@sema-agent/server
v7.56.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;单机场景另有文件持久化的local模式)。任意副本都能服务任意 run 的事件流;任务可以在一个副本上挂起、在另一个副本上恢复。 - 完整的服务端能力面(可在
GET /v1/capabilities发现): 异步 run + 可重放 SSE、持久化检查点 + 人工审批(HITL)、会话与长期记忆、 一份镜像服务多场景、任务级子智能体、确定性 workflow 编排,以及可插拔的沙箱执行通道 (host/local-docker/e2b/k8s/ssh/adb)。
它不是:
- 不是引擎本体。 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(npm 路径)+ 一个 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) 容器(零依赖,匿名可拉)
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>钉版)。 - 随包二进制:包内带两个
bin——run-local(单机本地 runner)与sema-up(部署引导脚本)。run-local在进程内启同一套引擎,把命令行给的目标跑完一次、打印结果、退出——没有 HTTP 服务, 也没有提交鉴权门。- 部署治理旋钮在这条腿上同样生效(7.5.0 起;此前这条腿自建任务时整条治理链缺席,旋钮静默失效):
AUTONOMY、runtime.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 点名是哪个旋钮产的这道门。
- 一键全栈部署(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。
配置
服务完全由环境变量配置。最核心的一批:
| 变量 | 默认 | 说明 |
|------|------|------|
| PORT | 8090 | HTTP 监听端口 |
| 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 | http://127.0.0.1:8000/v1 | OpenAI 兼容网关地址(不带 /chat/completions) |
| MODEL_ID | 必填 | 缺省模型 id ——3.0.0 起无出厂缺省。未设 = 启动即失败并指路该旋钮(旧的烤死缺省是内网模型名,外部部署必炸且炸在离根因最远处:网关 400 + 标题 hook 连环告警)。填你的网关真正提供的模型名,或改由配置控制面下发目录 |
| MODEL_API_KEY | — | 网关 key(可选) |
| 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 |
| REMOTE_EXEC | 未设 | 沙箱执行通道:host / local-docker / e2b / k8s / ssh / adb;未设 = 进程内 stub(CONFIG_PROVIDER=local 时缺省转 host)。点名了通道但必需 env 不全(如 e2b 缺 E2B_API_KEY)或值不在闭集内 ⇒ 启动即拒——不再静默降级到 host/进程内通道(fail-closed) |
| 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) | 每一只 hook 席位单次调用的时间上限(core Hooks.timeoutMs)。未设 = 用引擎自己的缺省(本服务不复制上游默认值)。0 按字面生效(每个席位立即到期)。非整数 / 负数 / 超 setTimeout 上限(2147483647)⇒ 启动即拒 |
| CONFIG_PROVIDER | 未设 | 配置来源:local(单机文件 config.d/)/ remote(registry 控制面) |
| DEFAULT_SCENARIO | code | 请求体未指定场景时的缺省场景 |
| SANDBOX_PKG_SOURCE | global | 沙箱内装包源:global(官方源)/ cn(国内镜像)/ custom / none |
| SENSITIVE_WRITE_PATTERNS | core 推荐集 | 敏感路径写拒集;逗号分隔值为整体替换,off 或留空关闭。在治理层无条件施加(与客户端权限模式/lane/settings 在场性无关),run-local 腿同样生效;编译不出守卫集的值(如 /)启动即拒 |
| MODEL_CONNECT_TIMEOUT_MS | 30000 | 网关连接超时 |
| MODEL_FIRST_TOKEN_TIMEOUT_MS | 120000 | 首 token 超时 |
| 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 里的「三道 $ 闸的分工」对照表。
HTTP API 概览
一行一个端点族(非全量):
| 端点族 | 服务什么 |
|--------|----------|
| GET /health · GET /metrics | 存活探针 + Prometheus 指标(/metrics/summary、/metrics/plan-cache) |
| GET /v1/capabilities | 部署能力发现 —— 本部署真正能做什么,客户端免 501 探测 |
| 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 | 自托管网页控制台 + registry/配置中心 + 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 约束。
