@sema-agent/server
v7.145.0
Published
Sema Server — the server/API implementation layer for Sema, wiring core, registry, model providers, and cloud agent execution. Built on @sema-agent/core.
Readme
@sema-agent/server
Sema 技术栈的服务端/API 层 —— 装配引擎,服务舰队。
快速开始 · 配置 · HTTP API · 生态导航 · 许可协议
它是什么
@sema-agent/server 是 Sema 的服务端/API 实现层:把
@sema-agent/core 引擎、registry 配置、
模型网关与云端 agent 执行能力,装配到一套 HTTP/SSE 契约后面。
它是:
- 一个 HTTP/SSE 服务端 + 装配层。 请求体只带内容(
objective、sessionId、scenario等); 服务端按任务装配其余一切 —— 工具、子智能体角色册、提示词、skill、策略 —— 身份/会话/安全策略由服务端注入,不信 body。凭据只活在服务端闭包里, 不进请求体、不进模型、不进沙箱。 - 无状态设计。 副本是 cattle:
docker run即起一个,挂在负载均衡后想开多少开多少。 持久化状态 —— 会话、run、可重放事件日志、检查点、审批 —— 全在外部 SQL 存储 (任何 MySQL 协议数据库:MySQL/TiDB/MariaDB,或 PostgreSQL;每条池连接自钉会话隔离级(MySQL 协议腿REPEATABLE READ、PostgreSQLREAD COMMITTED)并回读复核,TiDB 上会话切到悲观事务模式、切不成或复核不符才拒启,见 docs/DEPLOY-PREREQS.md;单机场景另有文件持久化的local模式)。任意副本都能服务任意 run 的事件流;任务可以在一个副本上挂起、在另一个副本上恢复。 - 完整的服务端能力面(可在
GET /v1/capabilities发现): 异步 run + 可重放 SSE、持久化检查点 + 人工审批(HITL)、会话与长期记忆、 一份镜像服务多场景、任务级子智能体、确定性 workflow 编排,以及可插拔的沙箱执行通道 (host/local-docker/e2b/k8s/ssh/adb)。 - 中心提示层只有一种形。 中心下发(或本地
config.d)的中心层是{ schemaVersion: 2, artifact }(引擎铸的 artifact): 先过配置契约、再过引擎判官,由引擎采用;按场景挂段用when.binding(本服务把每个请求的场景名写进TaskSpec.promptBinding)。见 USAGE §9.5f。
它不是:
- 不是引擎本体。 agent 循环、工具 harness、记忆与检查点机制在
sema-core;本仓以 npm 依赖的方式消费它, 自己出装配、后端与服务契约。 - 不是 CLI。 终端智能体是
sema;它(以及网页端) 都是本服务的客户端。 - 不是部署工具。 一键自托管部署(Docker 单机或 Kubernetes)在
sema-deploy。 - 不是持久化中心。 真相在外部数据库里;服务进程随时可弃。
架构
HTTP / SSE API 面 装配层 执行通道
──────────────── ────── ────────
/v1/tasks (同步) ──┐ ┌─ 任务级 spec 装配 ─┐ ┌─ host (本机直跑)
/v1/runs (异步) ──┤ │ 场景 · skill │ ├─ local-docker (任务级容器)
/v1/sessions ──┼──▶│ 策略 · 审批门 │──▶├─ e2b (Firecracker VM)
/v1/approvals ──┤ │ registry 配置 │ ├─ k8s (Kata pod 沙箱)
/v1/workflows ──┘ │ 模型网关 │ └─ ssh / adb (真机 / 真设备)
└─ @sema-agent/core ─┘
│
持久化存储(MySQL/TiDB · PostgreSQL · 本地文件)
会话 · run · 事件日志 · 检查点 · 审批快速开始
环境要求:Node 20.19+ 或 22.12+(npm 路径;engines.node = ^20.19.0 || >=22.12.0)+ 一个 OpenAI 兼容模型网关。
关于安装时那条
glob@11弃用警告。npm install会为[email protected]打一条 deprecated 警告,它由e2b(E2B 沙箱 SDK)间接引入。这是安装期噪声,在这里没有任何运行时曝露面:glob在e2b里的 唯一加载点是它 template-build 打包路径里的一处dynamicImport,而本服务只使用 E2B 的沙箱运行时 接口。这一条是跑出来的、不是读代码推断的:importe2b、构造适配器、真调一次exec,全程glob从未进入模块缓存。我们是刻意不消它的。 唯一真能消掉的办法是把 e2b 整棵子树 bundle 进本包 (实测有效,警告确实消失),代价是解包体积 2.7 MB → 20.8 MB、npm ls会把依赖树标成invalid、 且你装到的e2b与 e2b 官方发布的那份脱钩 —— 为一条没有运行时影响的警告付这些,不划算。 顺带告诉你哪些做法没用(免得你去试):我们写的overrides(只在"被读的那份 package.json 正是 npm 本次调用的项目清单"时生效),以及随包发布的npm-shrinkwrap.json(本包作为依赖被安装时同样被 忽略)—— 两条都是实测。若这条警告碍事,把"overrides": { "glob": "^13" }加进你自己项目的 package.json(那份才是 npm 会读的;glob@13与 e2b 用到的 API 兼容,已验)。真正的修复在上游e2b。
# A) npm
npm install @sema-agent/server
MODEL_GATEWAY_BASEURL=https://api.deepseek.com MODEL_ID=deepseek-v4-flash \
MODEL_API_KEY=<你的-key> SERVICE_AUTH_TOKEN=<自定> \
node node_modules/@sema-agent/server/dist/main.js # → :8090
# B) 容器(零依赖;⚠️ 镜像不再发布,自建见下方「镜像不再发布」与 USAGE 9.13)
docker run -p 8090:8090 \
-e MODEL_GATEWAY_BASEURL=https://api.deepseek.com -e MODEL_ID=deepseek-v4-flash \
-e MODEL_API_KEY=<你的-key> -e SERVICE_AUTH_TOKEN=<自定> \
ghcr.io/sema-agent/sema-server:latest # 或 docker.io/claybobby/sema-server:latest
# 提交一个任务
curl -s localhost:8090/v1/tasks -H "Authorization: Bearer <SERVICE_AUTH_TOKEN>" \
-H 'content-type: application/json' -d '{"objective":"用一句话回答:1+1 等于几?"}'
# 带指定模型:body 加 "model":"<catalog id>";可用能力见 GET /v1/capabilities- 分发坐标:npm =
@sema-agent/server(npmjs 公开)· 镜像 =ghcr.io/sema-agent/sema-server+docker.io/claybobby/sema-server(均 public,:latest滚动 /:<sha>钉版)。 - 镜像不再发布:容器镜像自 7.128.0 起不再发布,npm 包是唯一发布件;自建镜像步骤见 USAGE 9.13。
- 作为库嵌入(包根导出,如
createHttpServer+ 自建StoreBackend):loadConfig()之后调composeExecutionLane(config, ctx)—— HTTP 服务与run-local都这么做。7.104.0 起执行车道的几条拒启(host 车道上开LEADER_ENABLED、多租户姿态落在共享车道、device 车道缺耐久店)判在这一步,不在loadConfig()里;assertExecutionLaneInvariants(config)是同一份判据,不做config.d/remote-exec.json覆写。createHttpServer的authorize席是必填:它是一次提交的根会话唯一的来源(server 把这只根盖进它执行的每一只 spec;resolveSpec不返回sessionId,要用根时读opts.execution.root)。单用户嵌入传createAuthorizer(config, runner.sessions)(包根导出);省掉即构造期拒。 7.145.0 起它还要deploymentMods:交给 Runner 当mods的同一只数组(没有 mod 传[])—— server 从它读这条腿上有没有 prompt 屏,有屏的腿只在引擎原样交付之后才存目标文本(有两处在此之外:verify形提交的续跑输入为验证器留着请求原文,那一份从不展示;leader 车道 durable worker 的子目标续跑输入不经这一座,屏前原文照旧落盘 —— 另票);省掉即构造期拒。 构建期工具(如目录编辑页)从包根取两张表、不手抄:RETIRED_ENVS(退役 env 墓碑)与 7.110.0 起的CATALOG_ENTRY_HEADER_LANES/CATALOG_ENTRY_HEADER_NAMES(+ 型CatalogEntryHeaderName)—— 模型目录条目headers的闭集白名单及读每个名字的线路。两者都冻结,就是服务端自己判据用的那一只。 壳要知道一台在跑的引擎服务的是哪张模型表、目录采纳了没有、起服路由判官怎么说,读GET /v1/models的modelPlane({ servedTable: "env" | "catalog", catalog: "absent" | "adopted" | "refused", refusalCode?, gap? })—— 问 server,不猜:判官的输入是服务进程的事实。 只在引擎起来之后可答,没有起服前的预判口。 起服自己的路由判官在目录应用之后判,不在loadConfig()里:自建装配在自己的配置源应用之后调一次包根的judgeServedModelRoute(config, { envTableIsPlaceholder })(与composeExecutionLane同形)。 - 随包二进制:包内带两个
bin——run-local(单机本地 runner)与sema-up(部署引导脚本)。run-local在进程内启同一套引擎,把命令行给的目标跑完一次、打印结果、退出——没有 HTTP 服务, 也没有提交鉴权门。- 部署治理旋钮在这条腿上同样生效(7.5.0 起;此前这条腿自建任务时整条治理链缺席,旋钮静默失效):
AUTONOMY、governance.commandPolicy(来自config.d/governance.json)与SENSITIVE_WRITE_PATTERNS与 HTTP 腿同样地 tighten-only 编译进本地任务,裁决锚在--workspace目录。 - 关闸通道:
SENSITIVE_WRITE_PATTERNS=off或留空(SENSITIVE_WRITE_PATTERNS=)都关掉守卫集;AUTONOMY不设(或设auto)= 不额外收紧。守卫集若给了编译不出来的值(例如/这种不含任何 路径段的模式),启动即拒并指名旋钮,而不是每个任务炸一次。 - 这条腿没有 durable 审批 park:一次性 CLI 没有
/v1/approvals/:id/decide可赎回。被门住的ask(例如AUTONOMY=ask,它把每条 shell 命令都送进审批链)当场结算:stdin 是 TTY 就y/N问人, 否则 fail-closed 拒绝并在 stderr 点名是哪个旋钮产的这道门。 - 三张审批名单在这条腿上同样执法(7.101.0 起;此前在本腿静默不生效):
APPROVAL_DENY当场拒;APPROVAL_REQUIRE/APPROVAL_NEVER_AUTO走上面那条当场结算(TTYy/N,否则拒并在 stderr 点名名单键);APPROVAL_AUTO_BUDGET让前 N 次APPROVAL_REQUIRE自动批(never-auto 工具恒问人)。与服务共用.env的 CI 脚本请给它单独一份.env,或在终端里跑。 y/N问句带上这次调用的完整参数(JSON、终端安全化;参数展示不出的调用不问、当场拒);一个终端一次只答 一问 —— 主任务与子代的并发询问依次排队。- 因拒答而停下的 run 退 1(7.101.0 起,
--json也一样;此前退 0):模型在拒答前写的文字照打 stdout, 非--json形 stderr 一行点名停因(task stopped (haltedOnUserRejection) …)。 - 没有人被问的拒记在部署政策名下,不记在你名下(7.110.0 起):无 TTY(或参数展示不出)时门记录是
policy_refused/who.party: "none",模型读引擎的策略句而不是「用户不想继续」,接着做不需要审批的部分; 那次调用没执行 ⇒ run 照样退 1,stderr 停因行task incomplete (approval unanswered) …。
- 一键全栈部署(DB + 对象存储 + registry 网站 + 沙箱池,docker/k8s 双路径):
sema-agent/sema-deploy。 - 沙箱装包源:缺省 = 官方源(pypi/npmjs/crates.io/…)。中国大陆部署配
SANDBOX_PKG_SOURCE=cn切国内镜像源(tuna/npmmirror/rsproxy/aliyun),自定义源用SANDBOX_PKG_SOURCE=custom+SEMA_*_MIRROR/INDEX/REGISTRY显式 URL。 这些 URL 会进沙箱环境(模型读得到):带user:pass@的地址起服即拒,凭据不要写进 URL。
配置
服务完全由环境变量配置。最核心的一批:
| 变量 | 默认 | 说明 |
|------|------|------|
| PORT | 8090 | HTTP 监听端口。0 = 让 OS 分一个:listening 日志行(stdout,info 级)与 /health.port 报实际绑到的口 |
| BIND_HOST(别名 HOST) | 见说明 | 监听地址。显式 BIND_HOST 恒生效。缺省:写面无鉴权时(ALLOW_UNAUTHED_WRITES=true 且未配任何 service token)= 127.0.0.1,否则全接口——配了 token 的部署不受影响。自 3.15.0 起 HOST 别名不再完全等效:shell 常把 HOST 设成机器名而 operator 并不知情,于是上述收窄条件成立时,收窄压过继承来的 HOST(告警事件 bind_host_from_HOST_env_overridden)。要暴露写面,显式设 BIND_HOST,或配一个 service token。 |
| MODEL_GATEWAY_BASEURL | 无缺省 | OpenAI 兼容网关地址(不带 /chat/completions)。无出厂缺省:每一条落 openai 兼容腿的路由都必须解析到显式端点 —— 目录条目自己的 baseUrl,或本键 —— 否则拒启,拒因点名模型并给出本机写法(MODEL_GATEWAY_BASEURL=http://127.0.0.1:8000/v1)。anthropic 单路由部署可不设。只设 MODEL_GATEWAY_FALLBACK_URLS 不设本键同拒 |
| MODEL_ID | 必填(目录给出缺省时可省) | 缺省模型 id ——3.0.0 起无出厂缺省。7.101.0 起判据挪到目录应用之后:MODEL_ID 或目录里一条可用的缺省(config.d/models.json / 配置控制面)任一在场即可;两者皆无 = 拒启(码 config.default_model_missing,指路二选一)。目录一旦被采纳就整张换掉 env 表,MODEL_ID 此时不服务:起服不拒(目录条目自带 baseUrl 时没有网关也能起),并说一行 config_env_set_but_ineffective 点名在服务的目录缺省(目录第一次被采纳的那一拍恰好说一次 —— 启动时,或目录晚到 / 刷新时才第一次采纳)。旧的烤死缺省是内网模型名,外部部署必炸且炸在离根因最远处:网关 400 + 标题 hook 连环告警 |
| MODEL_API_KEY | — | 网关 key(可选)。只与 MODEL_GATEWAY_BASEURL 配对:没设网关时不装载、不发往任何路由 |
| SERVICE_AUTH_TOKEN | — | 调用方需带 Authorization: Bearer <token> |
| DB_BACKEND | local* | SQL 引擎:mysql(任何 MySQL 协议库:MySQL/TiDB/MariaDB —— TiDB 走这个值,没有 tidb 别名,写它启动即拒)/ pg(PostgreSQL)/ local(免 DB 文件持久化)/ memory(显式纯内存)。显式设置 mysql/pg 时 session 自动转 durable。单租户裸 boot 缺省 local;REQUIRE_PRINCIPAL=true 的多租户裸 boot 缺省 memory(local 与多租户互斥) |
| SESSION_BACKEND | memory | memory / mysql(durable 会话中心)/ auto。*显式 DB_BACKEND=mysql/pg 时默认转 durable。(tidb 是退役公名,设了拒启;7.57.0 起 GET /v1/config/catalog 的回显也归一成公名 mysql,不再吐内部标签 tidb) |
| REMOTE_EXEC | 未设 | 沙箱执行通道:host / local-docker / e2b / k8s / ssh / adb;未设 = 进程内 stub(CONFIG_PROVIDER=local 时缺省转 host)。点名了通道但必需 env 不全(如 e2b 缺 E2B_API_KEY;未设、空串或只含空白一律按缺,所有通道、所有必需键同判)或值不在闭集内 ⇒ 启动即拒——不再静默降级到 host/进程内通道(fail-closed)。k8s 必需 K8S_SANDBOX_IMAGE 和 K8S_NAMESPACE —— 沙箱 pod 所在的命名空间没有内置缺省(部署自己声明;缺席、空串或只含空白 ⇒ 启动即拒;随包 chart 取 sandbox.namespace 显式设)。CONFIG_PROVIDER=local 下 config.d/remote-exec.json 压过本 env(刻意:单机形的真源是那份文件);7.57.0 起这次抢占响亮——remote_exec_lane_preempted_by_file 点名被抢占的 lane、最终生效的 lane,以及它是不是一次隔离降级(隔离 lane 被换成不隔离的);文件点了尚未接线的隔离 lane(e2b/k8s/ssh/adb)时 env 腿照旧生效并说明 |
| SSH_HOST_FINGERPRINT / SSH_KNOWN_HOSTS | 未设 | SSH 通道主机密钥校验(仅 REMOTE_EXEC=ssh)。前者 = 主机公钥的 SHA256 base64 指纹(SHA256: 前缀与 = 填充都可选);后者 = known_hosts 文件路径,按 host / [host]:port 逐字匹配行。任一在场 ⇒ 严格校验,不符即拒连(拒因带两半指纹 + ssh-keyscan 取指纹指路一行);两只同时在场 ⇒ 合取(都要过)。两只全缺席 ⇒ 每连接一条响亮 warn(ssh_host_key_unverified,中间人风险)后照常连 —— 批量部署通道的既定姿态,已登记为 P-DEBT fail-open(docs/FAIL-OPEN-CENSUS.md)。指纹拼错 / known_hosts 路径读不到 ⇒ 启动即拒。known_hosts 里刻意不支持:hashed(\|1\|…)行、通配符 pattern、@cert-authority —— 一律跳过,于是只有这些条目的主机会被拒连(@revoked 照常生效,且无论写在哪一行都优先于普通匹配行) |
| HOOKS_TIMEOUT_MS | 未设(600000) | 请求 settings.hooks 那张扩展注册每个 handler 的时间预算(一个事件跑一遍本请求的钩子条目)。未设 = 600000 ms —— 这是引擎对这张注册的 budgetMs(每个 handler 自己的时间:一个事件跑一遍本请求的钩子条目);预算到、或任务被取消,这个 handler 里还在跑的命令钩子会被叫停(SIGTERM → 短宽限 → SIGKILL),不再跑到自己的 timeout;不用引擎给扩展的缺省(10 s)。0 按字面生效(零预算)。本服务自己的两张观察注册(拒绝计量 / 工具追踪)不读它。非整数 / 负数 / 超 setTimeout 上限(2147483647)⇒ 启动即拒 |
| MODS_ROOT / MODS_PACKAGES | 未设 | 部署座装载的 mod 包。MODS_PACKAGES = JSON 数组,每项 { "name", "dir", "tier", "options"? }:name = 包自己的名(.claude-plugin/plugin.json 的 name,逐字同);dir 绝对路径,真实路径须严格落在 MODS_ROOT(绝对路径)的真实路径之下(按路径分量判 —— 符号链接出根、/mods-evil 这类前缀相似的兄弟目录、.. 遍历、根本身都拒启);tier 必填(prepend / user / append,宿主声明,包不自报);options 原样交包的 register。包里的文件只有引擎的读包者一只读者,本服务不读。每只声明的包起服装一次、整列交引擎准入:任一失败(声明坏、越根、读包者拒包、名不同、准入拒)⇒ 拒启,一行拒句点名哪一席或哪只包 —— 本服务自己写的句子不回显声明的值(路径、options);读包者 / 准入交回的话原样透传(凭据形换记号、剥控制字符),其中可能点名包目录。装上了 ⇒ 每包一行 mods_package_loaded 日志(带引擎读包者交回的 digest —— 装载件三件字节摘要,认得出装的是哪几份字节,非完整性凭据:模块自己再加载的代码不在其内)、/health.mods.deploymentPackages 与能力位 modsDeploymentPackages: true;未设(或 [])⇒ 两面与没有这两根旋钮时逐字节同。包是受信的部署代码 —— 在本进程里跑、可触全部租户与进程凭据,准入不是沙箱 —— 只从你控制的只读物料树装。包若在 PreToolUse 上答 allow(可带 updatedInput),引擎仍按最终参数裁决,运维旋钮要问或要拒的(APPROVAL_REQUIRE / APPROVAL_NEVER_AUTO / MANUAL_MODE_SHELL_GATE=always / governance.commandPolicy 的问档与拒档等)与引擎强制的问句不因它改变,但未被强制的缺省审批问句它能清掉 —— 装包就是把这一类问句的决定权交给包作者;要某类调用无论包怎么答都问人,用这些旋钮声明。改声明或换包要重启(没有自动重启信号)。配置目录对 MODS_PACKAGES 只回在场位与长度。options 不是凭据通道:本服务不替包扣凭据 —— MODS_PACKAGES 本身与包自己读的任何变量,在宿主车道 inheritEnv: "all" 下都会被模型的子进程继承(只有本服务声明的自有凭据被扣),包要的凭据请经宿主车道模型 shell 读不到的渠道交付 |
| CONFIG_PROVIDER | 未设 | 配置来源:local(单机文件 config.d/)/ remote(SEMA_WEB_ADMIN_URL 那只 registry 控制面 —— 写了 remote 而没设这个地址拒启)。未设 = 设了 SEMA_WEB_ADMIN_URL 即中心,否则纯 env。闭集、逐字比较(7.104.0 起):其余任何值(大小写不同、带首尾空白)拒启;空串 = 未设 |
| DEFAULT_SCENARIO | code | 请求体未指定场景时的缺省场景;必须是本部署在册的场景名,否则拒启 |
| SANDBOX_PKG_SOURCE | global | 沙箱内装包源:global(官方源)/ cn(国内镜像)/ custom / none |
| SENSITIVE_WRITE_PATTERNS | core 推荐集 | 敏感路径写拒集;逗号分隔值为整体替换,off 或留空关闭。在治理层无条件施加(与客户端权限模式/lane/settings 在场性无关),run-local 腿同样生效。射程:拒的是文件工具(Write / Edit / NotebookEdit,按路径);shell 命令写同一路径(重定向 / tee / cp …)不被这个集拒绝,是一条普通审批问,和别的 shell 写同一条出路(人答;auto 下交分类器);编译不出守卫集的值(如 /)启动即拒 |
| WRITE_PROTECTED_EXTRA | 未设(引擎缺省表) | 给 core 的写保护名表加行(字面名表:命中即把幸存的 allow 降级成 ask,作用于 Write/Edit/NotebookEdit)。逗号分隔裸名(裸名匹配任意路径段,含 / 的名匹配连续段)或 JSON 数组("name" 串 / {name, kind} 行,kind:basename | segment | segment-run)。值按 [...core 缺省表, …] 组合,丢不掉任何缺省行。未设 = 不铸座 = 引擎缺省表在岗(本仓从不复制那张表)。两形按内容判而不是猜首字符:值里出现 JSON 结构字符([ ] { } ")即按 JSON 解析,且顶层必须是数组(少写一对方括号 ⇒ 拒启,而不是被拆成垃圾裸名静默收下)。空值 / 坏值(通配符、未知 kind、kind 与名字段数矛盾)/ 与 WRITE_PROTECTED_TABLE_REPLACE 同时设置 ⇒ 启动即拒。读面:GET /v1/capabilities 的 writeProtection.{armed,rows,replaced};GET /v1/diagnostics/wiring 的 writeProtection.{rows,source,droppedDefaultRows}(operator-only) |
| WRITE_PROTECTED_TABLE_REPLACE | 未设(引擎缺省表) | 整表替换写保护名表(core 的座按契约就是整表)。只收 JSON 数组 —— 刻意不给逗号简写:一个手滑的裸串会把 51 行换成 1 行。[] = 显式「完全不要这张表」。替换时 boot 期发一条响亮日志逐名列出被丢的缺省行(write_protection_table_replaced;空表走 write_protection_table_disabled)—— 想「加两行」请用 WRITE_PROTECTED_EXTRA。拒启条件同姊妹键,外加:两根同写 = 一条语义面两个写者 ⇒ 拒启 |
| MODEL_FIRST_BYTE_TIMEOUT_MS | 未设(core 缺省) | fetch() → 响应头的等待,毫秒(7.103.0 起;取代退役的 MODEL_CONNECT_TIMEOUT_MS,设了旧键拒启 —— core 7.33.0 起建连(TCP + TLS)是传输层自己的钟)。未设 = 不传键,core 缺省当家(另加按请求体大小的上传宽限,到点 core 自有一次加宽重试)。0 = 该段不设引擎钟、传输层的响应头 / 响应体钟也关(TCP + TLS 建连仍归传输层自己的钟)。须为 [0, 2147483647] 内整数,其余拒启。配了 MODEL_GATEWAY_FALLBACK_URLS 时每条网关路由同样是首窗 + 一次加宽重试之后才切备(server 不铸 core firstByteRetries:调用方可按请求关 failover,那一次身后没有备)。failover 拓扑须显式设:未设时接了连接却不回头的主网关要等 core 的首字节 lane(缺省窗 + 加宽重试)走完才切备,预算更短的调用(code-review council 镜头 180 s)在备网关被尝试之前就被取消;这类部署起服时打一条 failover_first_byte_lane warn |
| MODEL_FIRST_TOKEN_TIMEOUT_MS | 600000 | 首 token 超时(开流不吐字的唯一看门狗;0 = 该段不设引擎钟、传输层响应体钟也关。7.71.0 起由 120000 提高 —— 自托管后端长 prefill 下首字合理地就要等几分钟;要旧姿态显式设 120000) |
| MODEL_IDLE_TIMEOUT_MS | 300000 | 流中 idle 超时(0 = 该段不设引擎钟、传输层响应体钟也关) |
| LOG_LEVEL | info | debug / info / warn / error(结构化 JSON 日志) |
布尔旋钮收 true/false/1/0/yes/no/on/off(大小写不敏感;词表自 7.16.0 起放宽)。
词表外的值会让进程直接拒启——报错信息点名该 env 名、收到的原始值、可接受词表,打错的开关在启动
那一刻就现形,而不是静默退回默认(旧的「config_env_invalid_using_default 警告 + 保留缺省值」这条臂
已随本次改动退役,不再覆盖布尔旋钮;该事件现在只用于其他种类的越界配置,如数值旋钮被夹取)。
缺省值无法从名字推出,所以服务在 LOG_LEVEL=debug 下每个旋钮打一行 config_knob_polarity:
名字 → 极性(opt-in=缺省关、opt-out=缺省开、posture=由 REQUIRE_PRINCIPAL 推导)→ 生效值 → 来源。
该表描述本配置下活着的旋钮——挂在未激活通道上的旋钮(如非 k8s 通道下的 K8S_INSECURE_TLS、
未设时的 E2B_ALLOW_NET)没有行,含义是「在这里不生效」,不是「关」。
完整配置面 —— 成本/配额上限、断路器与 failover、多模型角色、审批门、可观测
(Prometheus /metrics + 可选 OTLP)、registry 控制面、各沙箱通道细项 ——
见 USAGE.md。⚠️ 封顶花费的旋钮有三根,判的时刻和能停住什么各不相同
(单任务硬闸 / per-principal 进场门——不打断已在跑的 run / 部署级治理窗——会在 turn 边界停住它);
选之前请先读 USAGE.md 里的「三道 $ 闸的分工」对照表。
Web search(部署 env WEB_SEARCH_* 七键、per-request settings.webSearch、两车道优先级、工具层错误形)
见 USAGE.md §9.5。
安全与隐私提示
🔴 trace 脱敏 ≠ 出站控制。 trace 脱敏(你在账本 / SSE / turns / 审批预览里看到的
«redacted»标记)只作用于读面 / 展示面(账本 / SSE / turns / 审批预览 /GET /v1/sessions/:id);不碰引擎会话存档 (审计真源:store 里怎么写就怎么回、HTTP 读面才脱敏,之后每一次续轮按原文回送模型路由)与 session-sync 七口/v1/sessions/:id/sync/*(逐字 durable log 出入)——这两面是原形——发往「该 run 实际选中的模型路由」的请求体是工具结果原文。 这条路由不止MODEL_GATEWAY_BASEURL一根:还可能是备用网关列表(MODEL_GATEWAY_FALLBACK_URLS)、provider:"anthropic"模型的独立直连路由(缺省根https://api.anthropic.com,除非显式配ANTHROPIC_BASEURL)、或 web-admin 可对单个目录模型下发的 per-modelbaseUrl覆盖(见docs/ARCHITECTURE.md§10)。要让内容不出机器,靠读侧敏感路径门,并核对本部署会被选中的每一条 路由都指向自己控制的基础设施——只把默认网关 env 指到私有端点是不够的。验法见USAGE.md§9.6。
HTTP API 概览
一行一个端点族(非全量):
| 端点族 | 服务什么 |
|--------|----------|
| GET /health · GET /readyz · GET /metrics | 存活探针 + 就绪探针(/readyz:200 / 503,给只认状态码的探针,如 k8s readinessProbe)+ Prometheus 指标(/metrics/summary、/metrics/plan-cache) |
| GET /v1/capabilities | 部署能力发现 —— 本部署真正能做什么,客户端免 501 探测 |
| GET /v1/capabilities/mcp · POST /v1/capabilities/mcp/probe | 无需先跑一条 run 的逐台 MCP 状态:现连、列工具、关掉 —— 前者答本部署自己申报的服务器,后者答调用方自带的 .mcp.json。行就是引擎装配名册里的那一行,所以一次性命令与交互会话读到同一个判定。它会真拨号,所以按调用方限速 + 短窗复用 |
| GET /v1/models | 模型目录(仅名字,不含网关 URL/key) |
| POST /v1/tasks · /v1/tasks/stream | 同步任务执行;SSE 变体逐 token 流式输出类型化 TaskEvent |
| POST /v1/runs · GET /v1/runs/:id | 异步 run:立即 202,后台续跑,轮询状态/结果 |
| GET /v1/runs/:id/events | 可重放 SSE(Last-Event-ID 续订);任意副本可服务任意 run |
| POST /v1/runs/:id/cancel / steer / interrupt / compact · /v1/runs/:id/subagents/:target/steer / resume | run 控制动词:协作式取消、运行中转向、turn 级中断(切当前在飞 turn,run 继续)、上下文压缩、子智能体转向/恢复 |
| /v1/approvals(list · decide · stream) | 人工审批中心,底座是持久化检查点;任意副本都能批复 |
| /v1/sessions(list · get · fork · init · settings · wake) | 会话列表/检索、审计回溯、fork、启动包 |
| /v1/workflows(list · get · stream · agents/:label/steer) | 确定性 workflow 编排 run,带实时流与逐 agent 转向 |
| GET /v1/usage · GET /v1/policy | 累计花费(配置配额时)与生效策略只读面 |
生态导航
| 仓库 | 是什么 |
|------|--------|
| sema-agent/sema | sema CLI 门户 —— 属于你自己的 Claude Code 级智能体:终端、网页、你的云 |
| sema-agent/sema-core | 智能体引擎,以库的形式发布 —— @sema-agent/core |
| sema-agent/sema-sdk | 本服务的官方 TypeScript SDK(@sema-agent/sdk) |
| sema-agent/sema-deploy | 一键部署 —— docker compose 或 k8s(helm),单机到多机 HA |
| sema-agent/sema-web-admin | web-admin:自托管网页控制台、配置控制面与 orchestrator |
版本策略
1.x = 快速迭代期:BREAKING 变更可能落在 minor(记录于
MIGRATION.md)。生产部署请锁精确版本
(如 @sema-agent/[email protected]);GA 后切 2.0 起严格 semver。
许可协议
BUSL-1.1(Business Source License):
- 个人、教育、研究及非商业生产使用 免费。
- 商业生产使用需要商业授权。
- 2030-07-13 起自动转为 Apache-2.0。
≤ 1.180.1 的已发布副本仍受其发布时的 MIT 约束。
