@sema-agent/server 4.3.0 → 5.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/USAGE.md +16 -16
- package/dist/approval-hmac.js +1 -1
- package/dist/approval.d.ts +17 -37
- package/dist/approval.js +26 -112
- package/dist/auth-bridge.d.ts +0 -1
- package/dist/auth-bridge.js +0 -1
- package/dist/auth-keys.d.ts +1 -1
- package/dist/auth-keys.js +1 -1
- package/dist/bench/s1/run-firm.js +1 -1
- package/dist/boot/config-center.d.ts +1 -1
- package/dist/boot/config-center.js +4 -3
- package/dist/boot/reapers.d.ts +1 -2
- package/dist/boot/reapers.js +4 -5
- package/dist/boot/resolve-spec.d.ts +1 -3
- package/dist/boot/resolve-spec.js +21 -35
- package/dist/boot/stores.js +1 -1
- package/dist/brain.js +3 -1
- package/dist/capabilities/center-prompts.d.ts +2 -3
- package/dist/capabilities/center-prompts.js +2 -3
- package/dist/capabilities/sandbox-file-send.d.ts +0 -2
- package/dist/capabilities/sandbox-file-send.js +2 -5
- package/dist/capabilities/scenarios.d.ts +2 -13
- package/dist/capabilities/scenarios.js +3 -22
- package/dist/capabilities/send-user-file-tool.js +3 -3
- package/dist/config-center/apply-effective.js +51 -13
- package/dist/config-center/types.d.ts +10 -3
- package/dist/config-provider.d.ts +1 -1
- package/dist/config-provider.js +6 -11
- package/dist/config-types.d.ts +15 -29
- package/dist/config.d.ts +28 -0
- package/dist/config.js +122 -68
- package/dist/fleet/fleet-bus.d.ts +1 -1
- package/dist/fleet/fleet-bus.js +25 -33
- package/dist/fleet-client.js +1 -1
- package/dist/http/active-run-conflict.d.ts +2 -0
- package/dist/http/active-run-conflict.js +1 -0
- package/dist/http/routes/approvals-assistant.d.ts +2 -1
- package/dist/http/routes/approvals-assistant.js +10 -96
- package/dist/http/routes/capabilities.js +6 -5
- package/dist/http/routes/fleet.js +7 -2
- package/dist/http/routes/images.js +10 -4
- package/dist/http/routes/runs.js +42 -65
- package/dist/http/routes/session-sync.d.ts +1 -1
- package/dist/http/routes/session-sync.js +2 -1
- package/dist/http/routes/tasks.js +7 -7
- package/dist/http/routes/trace-usage.js +1 -1
- package/dist/http/routes/workflows.js +3 -1
- package/dist/http/server.d.ts +1 -6
- package/dist/http/server.js +15 -10
- package/dist/http/verify-rounds.d.ts +2 -2
- package/dist/http/wire-types.d.ts +1 -1
- package/dist/images/bake-validate.d.ts +0 -22
- package/dist/images/bake-validate.js +0 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +2 -5
- package/dist/main.js +9 -10
- package/dist/memory-scope.d.ts +1 -2
- package/dist/memory-scope.js +8 -4
- package/dist/orchestration/workflow-completion-inbox.d.ts +6 -4
- package/dist/orchestration/workflow-completion-inbox.js +6 -4
- package/dist/plugins/breaker-state-sql.d.ts +2 -3
- package/dist/plugins/file-run-store.d.ts +1 -1
- package/dist/plugins/file-run-store.js +1 -1
- package/dist/plugins/image-index-sql.d.ts +0 -1
- package/dist/plugins/image-index-sql.js +0 -1
- package/dist/plugins/local-checkpoint-store.d.ts +1 -1
- package/dist/plugins/local-checkpoint-store.js +1 -1
- package/dist/plugins/memory-engine-pg.js +2 -1
- package/dist/plugins/memory-engine-tidb.js +1 -1
- package/dist/plugins/memory-engine-vector-util.d.ts +2 -3
- package/dist/plugins/memory-engine-vector-util.js +2 -3
- package/dist/plugins/memory-run-store.d.ts +2 -2
- package/dist/plugins/memory-run-store.js +1 -1
- package/dist/plugins/memory-session-policy-store.d.ts +1 -1
- package/dist/plugins/memory-session-policy-store.js +1 -1
- package/dist/plugins/memory-sync-store-pg.js +1 -1
- package/dist/plugins/pg-pool.js +8 -10
- package/dist/plugins/pg-rate-limiter.d.ts +1 -4
- package/dist/plugins/pg-rate-limiter.js +0 -1
- package/dist/plugins/roster-store-sql.d.ts +1 -3
- package/dist/plugins/roster-store-sql.js +3 -5
- package/dist/plugins/store-backend.d.ts +7 -17
- package/dist/plugins/store-backend.js +14 -30
- package/dist/plugins/tidb-pool.js +6 -30
- package/dist/plugins/workflow-journal-store-sql.d.ts +1 -1
- package/dist/plugins/workflow-journal-store-sql.js +1 -1
- package/dist/principal-jwt.js +2 -2
- package/dist/prompts-domain-validate.d.ts +4 -3
- package/dist/prompts-domain-validate.js +7 -8
- package/dist/router/route-orchestration.js +3 -3
- package/dist/run-local.js +13 -10
- package/dist/runs.js +8 -6
- package/dist/runtime-caps-resolver.d.ts +3 -2
- package/dist/runtime-caps-resolver.js +4 -4
- package/dist/runtime-governance.d.ts +4 -7
- package/dist/runtime-governance.js +12 -17
- package/dist/sealed-key.d.ts +1 -1
- package/dist/sealed-key.js +1 -1
- package/dist/security.d.ts +0 -5
- package/dist/security.js +8 -12
- package/dist/session-sync.d.ts +0 -2
- package/dist/session-sync.js +10 -17
- package/dist/spec-fields.js +6 -6
- package/dist/task-settings.d.ts +0 -27
- package/dist/task-settings.js +42 -11
- package/dist/tool-approval.d.ts +3 -3
- package/dist/tool-approval.js +10 -10
- package/dist/trace/artifacts.d.ts +11 -0
- package/dist/trace/artifacts.js +8 -19
- package/dist/trace/ledger-sink.js +7 -1
- package/dist/trace/project.d.ts +17 -0
- package/dist/trace/project.js +58 -5
- package/package.json +3 -3
- package/dist/capabilities/oa-tools.d.ts +0 -15
- package/dist/capabilities/oa-tools.js +0 -54
- package/dist/plugins/approval-store-sql.d.ts +0 -116
- package/dist/plugins/approval-store-sql.js +0 -150
- package/dist/plugins/file-workflow-journal-store.d.ts +0 -12
- package/dist/plugins/file-workflow-journal-store.js +0 -12
- package/dist/plugins/pg-approval-store.d.ts +0 -9
- package/dist/plugins/pg-approval-store.js +0 -9
- package/dist/plugins/pg-breaker-state.d.ts +0 -8
- package/dist/plugins/pg-breaker-state.js +0 -8
- package/dist/plugins/pg-checkpoint-store.d.ts +0 -10
- package/dist/plugins/pg-checkpoint-store.js +0 -10
- package/dist/plugins/pg-file-snapshot-store.d.ts +0 -8
- package/dist/plugins/pg-file-snapshot-store.js +0 -8
- package/dist/plugins/pg-image-bake.d.ts +0 -12
- package/dist/plugins/pg-image-bake.js +0 -11
- package/dist/plugins/pg-image-index.d.ts +0 -12
- package/dist/plugins/pg-image-index.js +0 -11
- package/dist/plugins/pg-outcome-ledger.d.ts +0 -12
- package/dist/plugins/pg-outcome-ledger.js +0 -11
- package/dist/plugins/pg-resume-anchor-store.d.ts +0 -7
- package/dist/plugins/pg-resume-anchor-store.js +0 -7
- package/dist/plugins/pg-run-store.d.ts +0 -9
- package/dist/plugins/pg-run-store.js +0 -9
- package/dist/plugins/pg-session-policy-store.d.ts +0 -7
- package/dist/plugins/pg-session-policy-store.js +0 -7
- package/dist/plugins/pg-session-store.d.ts +0 -12
- package/dist/plugins/pg-session-store.js +0 -12
- package/dist/plugins/pg-tool-result-store.d.ts +0 -9
- package/dist/plugins/pg-tool-result-store.js +0 -9
- package/dist/plugins/pg-workflow-journal-store.d.ts +0 -9
- package/dist/plugins/pg-workflow-journal-store.js +0 -9
- package/dist/plugins/pg-workflow-run-store.d.ts +0 -9
- package/dist/plugins/pg-workflow-run-store.js +0 -9
- package/dist/plugins/tidb-approval-store.d.ts +0 -8
- package/dist/plugins/tidb-approval-store.js +0 -8
- package/dist/plugins/tidb-breaker-state.d.ts +0 -7
- package/dist/plugins/tidb-breaker-state.js +0 -7
- package/dist/plugins/tidb-checkpoint-store.d.ts +0 -9
- package/dist/plugins/tidb-checkpoint-store.js +0 -9
- package/dist/plugins/tidb-file-snapshot-store.d.ts +0 -8
- package/dist/plugins/tidb-file-snapshot-store.js +0 -8
- package/dist/plugins/tidb-image-bake.d.ts +0 -12
- package/dist/plugins/tidb-image-bake.js +0 -11
- package/dist/plugins/tidb-image-index.d.ts +0 -12
- package/dist/plugins/tidb-image-index.js +0 -11
- package/dist/plugins/tidb-outcome-ledger.d.ts +0 -12
- package/dist/plugins/tidb-outcome-ledger.js +0 -12
- package/dist/plugins/tidb-resume-anchor-store.d.ts +0 -7
- package/dist/plugins/tidb-resume-anchor-store.js +0 -7
- package/dist/plugins/tidb-run-store.d.ts +0 -10
- package/dist/plugins/tidb-run-store.js +0 -9
- package/dist/plugins/tidb-session-policy-store.d.ts +0 -7
- package/dist/plugins/tidb-session-policy-store.js +0 -7
- package/dist/plugins/tidb-tool-result-store.d.ts +0 -8
- package/dist/plugins/tidb-tool-result-store.js +0 -10
- package/dist/plugins/tidb-workflow-journal-store.d.ts +0 -9
- package/dist/plugins/tidb-workflow-journal-store.js +0 -9
- package/dist/plugins/tidb-workflow-run-store.d.ts +0 -10
- package/dist/plugins/tidb-workflow-run-store.js +0 -10
- package/dist/plugins/workflow-journal-limits.d.ts +0 -12
- package/dist/plugins/workflow-journal-limits.js +0 -12
package/README.md
CHANGED
|
@@ -173,7 +173,7 @@ One row per endpoint family (not exhaustive):
|
|
|
173
173
|
| `POST /v1/runs` · `GET /v1/runs/:id` | Asynchronous runs: immediate `202`, background execution, poll for status/result |
|
|
174
174
|
| `GET /v1/runs/:id/events` | Replayable SSE (`Last-Event-ID` resume); any replica can serve any run |
|
|
175
175
|
| `POST /v1/runs/:id/cancel` / `steer` / `compact` · `/v1/runs/:id/subagents/:target/steer` / `resume` | Run control verbs: cooperative cancel, mid-run steering, context compaction, sub-agent steering/resume |
|
|
176
|
-
| `/v1/approvals` (list ·
|
|
176
|
+
| `/v1/approvals` (list · decide · stream) | Human-in-the-loop approval center backed by durable checkpoints; decisions from any replica |
|
|
177
177
|
| `/v1/sessions` (list · get · fork · init · settings · wake) | Session listing/search, audit inspection, fork, startup bundle |
|
|
178
178
|
| `/v1/workflows` (list · get · stream · agents/:label/steer) | Deterministic workflow orchestration runs with live streams and per-agent steering |
|
|
179
179
|
| `GET /v1/usage` · `GET /v1/policy` | Cumulative spend (when quotas are configured) and effective policy read surface |
|
package/README.zh-CN.md
CHANGED
|
@@ -164,7 +164,7 @@ curl -s localhost:8090/v1/tasks -H "Authorization: Bearer <SERVICE_AUTH_TOKEN>"
|
|
|
164
164
|
| `POST /v1/runs` · `GET /v1/runs/:id` | 异步 run:立即 `202`,后台续跑,轮询状态/结果 |
|
|
165
165
|
| `GET /v1/runs/:id/events` | 可重放 SSE(`Last-Event-ID` 续订);任意副本可服务任意 run |
|
|
166
166
|
| `POST /v1/runs/:id/cancel` / `steer` / `compact` · `/v1/runs/:id/subagents/:target/steer` / `resume` | run 控制动词:协作式取消、运行中转向、上下文压缩、子智能体转向/恢复 |
|
|
167
|
-
| `/v1/approvals`(list ·
|
|
167
|
+
| `/v1/approvals`(list · decide · stream) | 人工审批中心,底座是持久化检查点;任意副本都能批复 |
|
|
168
168
|
| `/v1/sessions`(list · get · fork · init · settings · wake) | 会话列表/检索、审计回溯、fork、启动包 |
|
|
169
169
|
| `/v1/workflows`(list · get · stream · agents/:label/steer) | 确定性 workflow 编排 run,带实时流与逐 agent 转向 |
|
|
170
170
|
| `GET /v1/usage` · `GET /v1/policy` | 累计花费(配置配额时)与生效策略只读面 |
|
package/USAGE.md
CHANGED
|
@@ -44,11 +44,11 @@ docker compose up --build --scale service=4 # 4 个无状态 worker,nginx
|
|
|
44
44
|
# ① 同协议冗余:主网关挂(连不上/上游开始前就失败)→ 按序切到备网关(同一 model id)
|
|
45
45
|
MODEL_GATEWAY_BASEURL=http://gw-a:8000/v1 MODEL_GATEWAY_FALLBACK_URLS=http://gw-b:8000/v1,http://gw-c:8000/v1
|
|
46
46
|
# ② 云 Anthropic 路由:provider="anthropic" 的模型走云 /v1/messages(带 prompt 缓存断点),其余走本地网关
|
|
47
|
-
ANTHROPIC_API_KEY=sk-ant-… # 可选:
|
|
47
|
+
ANTHROPIC_API_KEY=sk-ant-… # 可选:ANTHROPIC_BASE_URL / ANTHROPIC_VERSION / ANTHROPIC_CACHE_BREAKPOINTS=true
|
|
48
48
|
```
|
|
49
49
|
- 两个变量都不设 = 和以前**逐字节一致**(单网关)。
|
|
50
50
|
- **failover ≠ Anthropic↔vLLM**:failover 给所有 brain 发**同一个 model**(同协议同 id 的冗余);云↔本地是**按 `model.provider` 路由**的选择,不是故障转移(两者 model id/参数不同,不能透明互切)。设 `MODEL_PROVIDER=anthropic` + `MODEL_ID=claude-…` 让整个服务走 Anthropic。
|
|
51
|
-
- **缺省推断**:`MODEL_PROVIDER` **未设**、但显式配了 Anthropic 协议 base URL(`ANTHROPIC_BASE_URL`
|
|
51
|
+
- **缺省推断**:`MODEL_PROVIDER` **未设**、但显式配了 Anthropic 协议 base URL(`ANTHROPIC_BASE_URL`)**和**对应凭证(`ANTHROPIC_API_KEY` / `ANTHROPIC_AUTH_TOKEN`)时,缺省自动判 `anthropic` 并打一行启动 warn(`model_provider_inferred`)——纯净机直连 Anthropic 兼容上游不再需要显式第七个键。显式 `MODEL_PROVIDER` 恒赢;只给 base URL 或只给凭证不推断;两者皆无 = `gateway`,与以前逐字节一致。
|
|
52
52
|
- 启动日志的 `brain` 字段会回显当前组合(`failover` / `anthropicRoute` / `anthropicCacheBreakpoints`)。详见 `design/15`。
|
|
53
53
|
|
|
54
54
|
**可选 — 韧性栈:分级超时 + 断路器(core 1.38,叠在 failover 之下)**
|
|
@@ -66,7 +66,7 @@ ANTHROPIC_MAX_RETRIES=10 # 云 Anthropic 腿
|
|
|
66
66
|
- **全部默认关**(超时=0、断路器=false)→ 不设就和以前**逐字节一致**。
|
|
67
67
|
- 断路器**只在配了 `MODEL_GATEWAY_FALLBACK_URLS`(≥2 路)时才有意义**——它的价值是"开路即快速失败 → failover 立刻切备";单网关下它是 no-op(启动日志 `circuitBreakerNoop` 会提示)。只 `network/server/rate_limit` 计入连败,`auth`/`invalid_request` 不计(坏 key 熔断整网关无意义)。备用网关(最后一路)不套断路器。
|
|
68
68
|
- **重试上限**(2026-07-31):两个键**不设就不传给引擎** —— 引擎默认当家。以前这里是 server 侧硬编码 `2`(openai 腿甚至零配置出口),而**显式传参压过引擎默认**,于是引擎抬默认对 server 部署毫无效果;第三方限流 provider 下"重试两次就放弃"正是由此而来。现在:不设=继承引擎默认(抬默认那天自动跟上),设了=按设的走。钉在 `test/brain.test.ts` 的「网关腿重试次数」两条上。
|
|
69
|
-
- 断路器状态:配了 `SESSION_BACKEND=
|
|
69
|
+
- 断路器状态:配了 `SESSION_BACKEND=mysql` 时自动用**跨副本共享态**(SQL `circuit_breaker` 表,写穿+刷新最终一致),否则进程内 Map。启动日志 `breakerState` 字段回显 `shared(mysql)`/`in-process`/`off`。详见 `design/27`。
|
|
70
70
|
|
|
71
71
|
**可选 — WebSearch 后端(core 只留注入口,不自带任何 provider)**
|
|
72
72
|
```bash
|
|
@@ -97,7 +97,10 @@ MAX_PRINCIPAL_COST_USD=5.00 COST_QUOTA_WINDOW_SEC=86400 # 0/不设 = 不限;
|
|
|
97
97
|
MODEL_DEGRADE_TO=deepseek-v4-flash
|
|
98
98
|
MODEL_DEGRADE_AT_COST_FRACTION=0.7 # ① 近预算(1.40):累计成本到 0.7×maxCostUsd 切(需任务有 cost ceiling)
|
|
99
99
|
MODEL_DEGRADE_REACTIVE=true # ② 反应式(1.39):主模型 rate_limit/breaker-open 时切(brain 级,最外层)
|
|
100
|
-
MODEL_DEGRADE_ON=rate_limit,breaker_open #
|
|
100
|
+
MODEL_DEGRADE_ON=rate_limit,breaker_open # 可选,反应式触发器子集;词表=breaker_open|rate_limit|budget|server_error|last_resort
|
|
101
|
+
# ⚠️ core 5.1.0 起,不设 MODEL_DEGRADE_ON 时引擎默认全集**含 server_error 与 last_resort**
|
|
102
|
+
# (主模型 5xx、以及兜底的一般 http 错误类也切便宜模型)。
|
|
103
|
+
# 不想要这两类触发就显式设回 rate_limit,breaker_open。拼错词 boot 拒启(不静默忽略)。
|
|
101
104
|
```
|
|
102
105
|
- 反应式降级 brain 包在**最外层**(core council #8);fallback brain 用自己的凭据(decorator 清掉主模型的 per-call key 防泄漏给别的 provider)。**坑**:`MODEL_DEGRADE_TO` 最好别和被限流的是同一网关/账号,否则反应式切过去照样撞同一个 rate_limit。
|
|
103
106
|
- **定价怎么设**:`model.cost` 来自 `MODEL_COST_INPUT/OUTPUT/CACHE_READ/CACHE_WRITE`(**USD per 1M tokens**,默认 0 = `costUsd` 读 0)。云模型(如 review-gw 的 deepseek-v4-pro)必须设,否则 spend 恒为 $0;本地自托管(qwen)留 0 即对(无 per-token 外部花费)。字段名是 `costUsd`,**非美元计价的网关要先折算**(如 DeepSeek 官方 CNY ÷ 汇率)。配置控制面管的模型走 `CenterModel.cost`(中心存价、不存 secret)。
|
|
@@ -106,8 +109,8 @@ MODEL_DEGRADE_ON=rate_limit,breaker_open # 可选,反应式触发器子集;默
|
|
|
106
109
|
- **`METRICS_TOKEN`**(可选,只读):设了它,`GET /metrics`+`/metrics/summary` 接受**它或** `SERVICE_AUTH_TOKEN`。**全 fleet 设同一个值** → 管理端(sema-web,规划名 sema-admin)用**一个** token 拉所有 worker 的指标,**无需持有各 worker 的全权 `SERVICE_AUTH_TOKEN`**(不破坏 secret 边界)。即使泄露也只暴露指标(只读)。
|
|
107
110
|
- **`GET /metrics/summary`**(token-gated,同 `/metrics`):`/metrics` 的**精炼 JSON**——`{model, runsActive, tasks{status}, tokensTotal, costUsd, costUsdByModel, taskDurationAvgSec, brainFirstTokenAvgMs, brainCallAvgMs, cacheHitRateAvg, rateLimited, costQuotaRejected, budgetExceeded, degraded, cascade, verifications, councilRuns, toolErrors}`。给**轻量 fleet 看板**用(管理端 sema-web 的 fleet 页按 worker 拉、渲染卡片、按轮询算速率;**不用 Prometheus/Grafana**)。counter 是累计值、histogram 报均值。
|
|
108
111
|
- 预算闸是 core 强制的:`maxCostUsd` pre-call 估算(`budget.precall`,没花钱就拒)+ 流中途取消 + turn 边界(`budget.exceeded`);`maxTokens` 超 → `budget.exceeded`。**review 网关**建议设 `MAX_TASK_COST_USD` 防单任务烧掉共享云 key。
|
|
109
|
-
- **per-principal 累计配额**:用 `AsyncLocalStorage` 把 principal 透传到 cost tracer,所以**council/team 子任务的花费也算到发起人头上**。**配了 `SESSION_BACKEND=
|
|
110
|
-
- **`RATE_LIMIT_RPM` 请求限流同样自动跨副本**(`SESSION_BACKEND=
|
|
112
|
+
- **per-principal 累计配额**:用 `AsyncLocalStorage` 把 principal 透传到 cost tracer,所以**council/team 子任务的花费也算到发起人头上**。**配了 `SESSION_BACKEND=mysql` 时自动跨副本共享**(`cost_quota` 表,写后聚合的**原子自增** `micro=micro+delta`,对齐固定窗,最终一致——多副本花费 SUM 到一起、不丢增量);否则 in-memory per-replica 滚动窗(单副本兜底)。启动日志 `costQuota` 字段回显 `shared(mysql)`/`in-process`/`off`。跨副本是最终一致(flush 间隔内峰值可能略超,由**硬 per-task `maxCostUsd` 兜底**)。
|
|
113
|
+
- **`RATE_LIMIT_RPM` 请求限流同样自动跨副本**(`SESSION_BACKEND=mysql` 时,`rate_limit` 表,与配额共用 `WriteBehindCounter`;启动日志 `rateLimit` 回显)。注意:写后聚合 = **软限流**(边界上短暂略超 OK,适合公平/热调用方防护);要**硬合规上限**得另走 CAS/原子计数,不靠写后聚合——和断路器跨副本同款权衡。
|
|
111
114
|
|
|
112
115
|
**可选 — 生成调参透传 + 退化打捞(core 1.59/1.60)**
|
|
113
116
|
```bash
|
|
@@ -170,14 +173,11 @@ MODEL_CASCADE_LADDER=deepseek-flash,deepseek-pro # 目录里的模型名,cheap
|
|
|
170
173
|
|
|
171
174
|
**监听绑址(1.306+,[1934])—— 桌面/单机形请注意**
|
|
172
175
|
- `BIND_HOST` = 监听地址;显式设置**恒生效**(要在无鉴权下对外暴露,显式写 `BIND_HOST=0.0.0.0` 即可)。
|
|
173
|
-
- `HOST`
|
|
174
|
-
|
|
175
|
-
把无鉴权写面静默扩到 LAN。被压过时 boot 日志打 `bind_host_from_HOST_env_overridden`,点名被忽略的
|
|
176
|
-
值与两条逃生口(显式 `BIND_HOST`,或给写面配 token)。收窄条件不成立时 `HOST` 与从前完全一样。
|
|
176
|
+
- `HOST` 不再被读取(曾经的兼容别名已撤——zsh 默认把 `HOST` 设成机器名的暗通道风险已消除):
|
|
177
|
+
绑址唯一口 = `BIND_HOST`,设或不设都与 `HOST` 环境变量的值无关。
|
|
177
178
|
- **缺省自动收窄**:当写面无鉴权时(`ALLOW_UNAUTHED_WRITES=true` 且**完全没有**
|
|
178
179
|
`SERVICE_AUTH_TOKEN`/TOKENS 名录)⇒ 自动绑 `127.0.0.1`,boot 日志点名原因。理由:该形常配
|
|
179
|
-
`REMOTE_EXEC=host`(用户真机、非沙箱)
|
|
180
|
-
`HOST` env **零消费**、恒绑所有接口——沉默陷阱,已修)。
|
|
180
|
+
`REMOTE_EXEC=host`(用户真机、非沙箱),绑全接口=同网段任何人可无鉴权提交任务并执行。
|
|
181
181
|
- 配了凭证的部署(云形/k8s/compose)缺省**不变**(全接口),既有部署零影响。
|
|
182
182
|
|
|
183
183
|
**workspace 浏览面(1.299+,#3)—— 任务产出的浏览/预览/打包下载**
|
|
@@ -211,7 +211,7 @@ SEND_USER_FILE_SANDBOX_PUT_ENDPOINT=… # 可选:沙箱直传 PUT 的端
|
|
|
211
211
|
|
|
212
212
|
**可选 — 接配置控制面(中心化模型/角色/团队配置)**
|
|
213
213
|
```bash
|
|
214
|
-
# 新名(orchestrator 现注入);旧名 CONFIG_CENTER_*
|
|
214
|
+
# 新名(orchestrator 现注入);旧名 CONFIG_CENTER_* 在场即 boot 拒启,只认 SEMA_REGISTRY_*
|
|
215
215
|
SEMA_REGISTRY_URL=http://<config-center-host>:3100 # 启动拉 GET /api/config/effective(Bearer+ETag),覆盖 env 兜底
|
|
216
216
|
SEMA_REGISTRY_TOKEN=<SERVICE_PULL_TOKEN 的值> # 取自配置控制面主机 .env;只读拉取令牌
|
|
217
217
|
SEMA_REGISTRY_DRY_RUN=true # 安全灰度:只 LOG 中心配置 vs env 推导的差异,不 apply
|
|
@@ -373,8 +373,8 @@ curl -N http://<host>:8090/v1/tasks/stream -H 'content-type: application/json' \
|
|
|
373
373
|
| 端点 | 用途 |
|
|
374
374
|
|---|---|
|
|
375
375
|
| `GET /v1/sessions/<id>` | 审计回溯:当前上下文 + 摘要(owner 校验) |
|
|
376
|
-
| `GET /v1/approvals?owner=user:42` |
|
|
377
|
-
| `POST /v1/approvals/<
|
|
376
|
+
| `GET /v1/approvals?owner=user:42` | 高危写审批(durable,需 `DURABLE_APPROVAL=true`):**operator** 看待办队列(可按 owner 过滤);非 operator 只看自己的 |
|
|
377
|
+
| `POST /v1/approvals/<sessionId>/decide` `{"decision":"approve"|"deny","reason":"…"}` | 批/否并恢复挂起任务(CAS,重复决议 409);**仅 operator**(非 operator → 403)。5.0.0 起旧轮询腿 `POST /v1/approvals/<id>` 已退役 |
|
|
378
378
|
| `GET /health` | 健康(无需鉴权) |
|
|
379
379
|
| `GET /metrics` | Prometheus 指标(有 token 时需带) |
|
|
380
380
|
|
|
@@ -412,7 +412,7 @@ curl -N http://<host>:8090/v1/tasks/stream -H 'content-type: application/json' \
|
|
|
412
412
|
| HTTP `403` / `404`(session/run) | 不是该 principal 的资源 | 用正确身份 |
|
|
413
413
|
| HTTP `409`(`/v1/runs`) | 同 session 已有活跃 run | 等它完成 / 用返回的 `activeTaskId` |
|
|
414
414
|
| HTTP `429` | 限流 | 看 `Retry-After` 退避 |
|
|
415
|
-
| HTTP `501`(`/v1/runs`) | 内存模式不支持异步 | 配
|
|
415
|
+
| HTTP `501`(`/v1/runs`) | 内存模式不支持异步 | 配 MySQL 协议存储(`SESSION_BACKEND=mysql`) |
|
|
416
416
|
|
|
417
417
|
**机器码**:每个 4xx/5xx 响应体都带一个 `errorCode`(与人类文案 `error` 并列),这是**唯一**该拿来做
|
|
418
418
|
程序分支的字段——**别锚 `error` 文案**。前缀族固定:`auth.` / `request.` / `not_found.` / `conflict.` /
|
package/dist/approval-hmac.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* design/80 D-G: approval-envelope HMAC (INTEGRITY, not identity). Split out of `security.ts` (design/158
|
|
3
|
-
* A13
|
|
3
|
+
* A13; consumers import from HERE — [2354] cleared the security.ts compat re-exports; verifyDirectDoorProof in
|
|
4
4
|
* ./principal-jwt.ts imports {@link verifyApprovalHmac} from here for the combined proof).
|
|
5
5
|
*
|
|
6
6
|
* ✅ WIRED into the resolve path (was "🔴 SCAFFOLD — NOT YET WIRED" — that claim went STALE; a 2026-07-25 doc-rot
|
package/dist/approval.d.ts
CHANGED
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* Built on core's `createApprovalPolicy` (which routes requireApproval/deny and races the wait against
|
|
6
|
-
* the task's AbortSignal). Our `approve` records a pending row and polls it for a decision; it also
|
|
7
|
-
* honors the signal directly (marks the request expired and releases) so a never-answered approval is
|
|
8
|
-
* dropped at the task deadline instead of holding the worker — design/06 F4 self-protection.
|
|
2
|
+
* Human-in-the-loop approval gate (F4) — durable-only since 5.0.0 ([2354]/[2356] A-5:OA 轮询车道
|
|
3
|
+
* (createOaApprovalPolicy + ApprovalStore pending 行轮询)整体退役;唯一门形 = durable checkpoint
|
|
4
|
+
* suspend/resume,见 createDurableAskPolicy 与 /v1/approvals 的 checkpointStore 腿)。
|
|
9
5
|
*/
|
|
10
6
|
import { type ToolPolicy } from "@sema-agent/core";
|
|
11
|
-
import type { ApprovalStore } from "./plugins/store-backend.js";
|
|
12
7
|
/**
|
|
13
8
|
* 运维**是否表达了门意图** —— boot 的单用户 allow-all 基线只在"零门意图"时才允许铺开,
|
|
14
9
|
* 所以这个谓词漏一格 = 那一格的意图被 allow-all 静默吞掉。
|
|
@@ -29,11 +24,24 @@ export declare function hasOperatorGateIntent(config: {
|
|
|
29
24
|
approvalNeverAuto: readonly string[];
|
|
30
25
|
durableApproval: boolean;
|
|
31
26
|
}): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* 门意图不可服务=boot 拒启(全窗复审 D3-F1,HIGH;与 env 墓碑族同谱系)。
|
|
29
|
+
* v4.3.0 的轮询门形(APPROVAL_REQUIRE + DB backend + DURABLE_APPROVAL 未设)在 5.0.0 只剩 core 每任务
|
|
30
|
+
* warn——**原先拦、现在放**(方向反转)。「留 undefined 让 core warn」对新配置是曝露误配,对升级存量是
|
|
31
|
+
* 门静默消失,后者必须响亮。放这文件与 hasOperatorGateIntent/inv#2 同源(意图判据再漂要同时改两段)。
|
|
32
|
+
*/
|
|
33
|
+
export declare function assertGateIntentServiceable(config: {
|
|
34
|
+
approvalRequire: readonly string[];
|
|
35
|
+
approvalDeny: readonly string[];
|
|
36
|
+
approvalNeverAuto: readonly string[];
|
|
37
|
+
durableApproval: boolean;
|
|
38
|
+
}, checkpointStorePresent: boolean): void;
|
|
32
39
|
/**
|
|
33
40
|
* Durable approval policy (core 1.67 / design/45): returns three-state **`ask`** for gated tools instead of
|
|
34
41
|
* polling. With `TaskSpec.durableApproval` set + a `checkpointStore` on the Runner, core turns that `ask` into
|
|
35
42
|
* a **suspend** (persists a checkpoint, ends `status:"suspended"`) — no held connection, resumable on any
|
|
36
|
-
* replica. (
|
|
43
|
+
* replica. (The former poll-lane
|
|
44
|
+
* twin, createOaApprovalPolicy, was retired in 5.0.0 — durable is the only gate.)
|
|
37
45
|
*/
|
|
38
46
|
export interface DurableAskOptions {
|
|
39
47
|
requireApproval: string[];
|
|
@@ -48,32 +56,4 @@ export interface DurableAskOptions {
|
|
|
48
56
|
onExempted?: (canonicalToolName: string, rawToolName: string) => void;
|
|
49
57
|
}
|
|
50
58
|
export declare function createDurableAskPolicy(opts: DurableAskOptions): ToolPolicy;
|
|
51
|
-
export interface OaApprovalOptions {
|
|
52
|
-
store: ApprovalStore;
|
|
53
|
-
/** Tool names that require an operator decision before they run. */
|
|
54
|
-
requireApproval: string[];
|
|
55
|
-
/** Safety tools that must ALWAYS reach a human — checked BEFORE the exemption probe (workflow audit
|
|
56
|
-
* 2026-07-13: the OA leg consumed exemptions without the neverAuto guard, so a grant made in durable mode
|
|
57
|
-
* could silently auto-approve a NEVER_AUTO tool after an ops switch back to the poll gate). */
|
|
58
|
-
neverAuto?: string[];
|
|
59
|
-
/** Session exemption probe — same contract as createDurableAskPolicy.exempt (fail-closed). */
|
|
60
|
-
exempt?: (sessionId: string, canonicalToolName: string) => Promise<boolean>;
|
|
61
|
-
/** Audit hook for an exemption short-circuit. */
|
|
62
|
-
onExempted?: (sessionId: string, canonicalToolName: string) => void;
|
|
63
|
-
/** Per-run context captured for the approval row (operator UI shows session/tool/args). */
|
|
64
|
-
context: () => {
|
|
65
|
-
taskId?: string | null;
|
|
66
|
-
sessionId?: string | null;
|
|
67
|
-
owner?: string | null;
|
|
68
|
-
};
|
|
69
|
-
/** Always-denied tools. */
|
|
70
|
-
deny?: string[];
|
|
71
|
-
/** Poll interval for the decision. Default 1500ms. */
|
|
72
|
-
pollMs?: number;
|
|
73
|
-
}
|
|
74
|
-
export declare function createOaApprovalPolicy(opts: OaApprovalOptions): ToolPolicy;
|
|
75
|
-
/** Poll the approval row until decided, or release (deny) when the task aborts. Exported for unit tests.
|
|
76
|
-
* `scope` is the run's tenant identity (owner-sourced) — carried on every read/decide so a run only ever
|
|
77
|
-
* observes/aborts its OWN pending row (single-DB fleet read guard; defense-in-depth). */
|
|
78
|
-
export declare function waitForDecision(store: ApprovalStore, id: string, scope: string | null, signal: AbortSignal | undefined, pollMs: number): Promise<boolean>;
|
|
79
59
|
//# sourceMappingURL=approval.d.ts.map
|
package/dist/approval.js
CHANGED
|
@@ -1,15 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* Built on core's `createApprovalPolicy` (which routes requireApproval/deny and races the wait against
|
|
6
|
-
* the task's AbortSignal). Our `approve` records a pending row and polls it for a decision; it also
|
|
7
|
-
* honors the signal directly (marks the request expired and releases) so a never-answered approval is
|
|
8
|
-
* dropped at the task deadline instead of holding the worker — design/06 F4 self-protection.
|
|
2
|
+
* Human-in-the-loop approval gate (F4) — durable-only since 5.0.0 ([2354]/[2356] A-5:OA 轮询车道
|
|
3
|
+
* (createOaApprovalPolicy + ApprovalStore pending 行轮询)整体退役;唯一门形 = durable checkpoint
|
|
4
|
+
* suspend/resume,见 createDurableAskPolicy 与 /v1/approvals 的 checkpointStore 腿)。
|
|
9
5
|
*/
|
|
10
|
-
import {
|
|
11
|
-
import { createLogger } from "./observability/logger.js";
|
|
12
|
-
const logger = createLogger();
|
|
6
|
+
import {} from "@sema-agent/core";
|
|
13
7
|
/**
|
|
14
8
|
* 运维**是否表达了门意图** —— boot 的单用户 allow-all 基线只在"零门意图"时才允许铺开,
|
|
15
9
|
* 所以这个谓词漏一格 = 那一格的意图被 allow-all 静默吞掉。
|
|
@@ -30,15 +24,28 @@ export function hasOperatorGateIntent(config) {
|
|
|
30
24
|
config.approvalNeverAuto.length > 0 || // ← 漏了这格,见上面的由来
|
|
31
25
|
config.durableApproval);
|
|
32
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* 门意图不可服务=boot 拒启(全窗复审 D3-F1,HIGH;与 env 墓碑族同谱系)。
|
|
29
|
+
* v4.3.0 的轮询门形(APPROVAL_REQUIRE + DB backend + DURABLE_APPROVAL 未设)在 5.0.0 只剩 core 每任务
|
|
30
|
+
* warn——**原先拦、现在放**(方向反转)。「留 undefined 让 core warn」对新配置是曝露误配,对升级存量是
|
|
31
|
+
* 门静默消失,后者必须响亮。放这文件与 hasOperatorGateIntent/inv#2 同源(意图判据再漂要同时改两段)。
|
|
32
|
+
*/
|
|
33
|
+
export function assertGateIntentServiceable(config, checkpointStorePresent) {
|
|
34
|
+
if (!hasOperatorGateIntent(config) || checkpointStorePresent)
|
|
35
|
+
return;
|
|
36
|
+
if (!config.durableApproval) {
|
|
37
|
+
throw new Error("APPROVAL_REQUIRE/APPROVAL_DENY/APPROVAL_NEVER_AUTO are set but the durable gate is off — since 5.0.0 the poll lane is retired and durable is the ONLY gate. Set DURABLE_APPROVAL=true (with a DB/file backend that has a checkpoint face), or remove the APPROVAL_* lists to run ungated on purpose.");
|
|
38
|
+
}
|
|
39
|
+
throw new Error("DURABLE_APPROVAL=true but no checkpoint store is available — the configured DB backend has no checkpoint face (or no backend is configured). Wire a MySQL-protocol/PostgreSQL/file backend, or unset DURABLE_APPROVAL.");
|
|
40
|
+
}
|
|
33
41
|
export function createDurableAskPolicy(opts) {
|
|
34
|
-
// 🔒
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
//
|
|
38
|
-
|
|
39
|
-
const
|
|
40
|
-
const
|
|
41
|
-
const neverAuto = new Set((opts.neverAuto ?? []).map(canonicalToolName));
|
|
42
|
+
// 🔒 RAW-name matching(core 5.0.0 RB-476:canonicalToolName 折叠面整体退役)。安全前提没有变松,
|
|
43
|
+
// 只是换了执行者:live 请求名恒为 CC canonical(旧名在 core roster 层响亮 miss,永远到不了本 policy);
|
|
44
|
+
// 配置侧写了退役名 = core prepare 硬失败 `config.legacy_tool_name`(+ 本仓 config 装配墓碑先一步拒启)。
|
|
45
|
+
// 旧的双侧归一防的「旧名滑过新名规则」在 5.0.0 下无成立路径——折叠臂留着才是静默兼容层。
|
|
46
|
+
const require = new Set(opts.requireApproval);
|
|
47
|
+
const deny = new Set(opts.deny ?? []);
|
|
48
|
+
const neverAuto = new Set(opts.neverAuto ?? []);
|
|
42
49
|
const budget = Math.max(0, Math.floor(opts.autoBudget ?? 0));
|
|
43
50
|
// design/80 D-E (upgrade-budget): a per-run-leg counter of NORMAL gated calls auto-approved so far. The policy
|
|
44
51
|
// is rebuilt per resolveSpec call (= per submit AND per resume — server.ts), so this closure is per-leg —
|
|
@@ -47,7 +54,7 @@ export function createDurableAskPolicy(opts) {
|
|
|
47
54
|
let autoApproved = 0;
|
|
48
55
|
return {
|
|
49
56
|
check: (req) => {
|
|
50
|
-
const toolName =
|
|
57
|
+
const toolName = req.toolName; // RAW(5.0.0):live 名恒 canonical,折叠面已随 core RB-476 退役
|
|
51
58
|
if (deny.has(toolName))
|
|
52
59
|
return { action: "deny", message: `tool "${req.toolName}" is denied by policy` };
|
|
53
60
|
// inv#2: a never-auto (irreversible / safety) tool ALWAYS asks a human — UNCONDITIONALLY, even if it was not
|
|
@@ -120,97 +127,4 @@ export function createDurableAskPolicy(opts) {
|
|
|
120
127
|
return { action: "ask", message: `approval required to run "${req.toolName}"` };
|
|
121
128
|
}
|
|
122
129
|
}
|
|
123
|
-
export function createOaApprovalPolicy(opts) {
|
|
124
|
-
const pollMs = opts.pollMs ?? 1500;
|
|
125
|
-
const neverAuto = new Set((opts.neverAuto ?? []).map(canonicalToolName));
|
|
126
|
-
return createApprovalPolicy({
|
|
127
|
-
requireApproval: opts.requireApproval,
|
|
128
|
-
deny: opts.deny,
|
|
129
|
-
approve: async (req, signal) => {
|
|
130
|
-
const ctx = opts.context();
|
|
131
|
-
// Session exemption — core already routed deny (deny wins before approve is ever called);
|
|
132
|
-
// a remembered (sessionId, toolName) auto-approves without a pending row. Fail-closed on a store error.
|
|
133
|
-
// neverAuto ALWAYS wins the exemption (same ordering lock as the durable policy — the OA leg previously
|
|
134
|
-
// lacked this guard, workflow audit 2026-07-13).
|
|
135
|
-
if (opts.exempt && ctx.sessionId) {
|
|
136
|
-
const toolName = canonicalToolName(req.toolName);
|
|
137
|
-
if (toolName !== "AskUserQuestion" && !neverAuto.has(toolName)) {
|
|
138
|
-
let exempted = false;
|
|
139
|
-
try {
|
|
140
|
-
exempted = (await opts.exempt(ctx.sessionId, toolName)) === true; // strict boolean, same as the durable twin
|
|
141
|
-
}
|
|
142
|
-
catch {
|
|
143
|
-
exempted = false;
|
|
144
|
-
}
|
|
145
|
-
if (exempted) {
|
|
146
|
-
opts.onExempted?.(ctx.sessionId, toolName);
|
|
147
|
-
return true;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
const id = uuidv7();
|
|
152
|
-
// scope = the run's tenant identity, owner-sourced (single-DB fleet read guard; defense-in-depth). The
|
|
153
|
-
// poll/abort paths below carry the SAME scope so this run only ever reads/aborts its own pending row.
|
|
154
|
-
const scope = ctx.owner ?? null;
|
|
155
|
-
await opts.store.createPending(id, scope, { ...ctx, toolName: req.toolName, args: req.args });
|
|
156
|
-
return waitForDecision(opts.store, id, scope, signal, pollMs);
|
|
157
|
-
},
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
/** Consecutive poll errors tolerated before giving up (a persistent outage still fail-closes to deny). */
|
|
161
|
-
const MAX_POLL_ERRORS = 5;
|
|
162
|
-
/** Poll the approval row until decided, or release (deny) when the task aborts. Exported for unit tests.
|
|
163
|
-
* `scope` is the run's tenant identity (owner-sourced) — carried on every read/decide so a run only ever
|
|
164
|
-
* observes/aborts its OWN pending row (single-DB fleet read guard; defense-in-depth). */
|
|
165
|
-
export async function waitForDecision(store, id, scope, signal, pollMs) {
|
|
166
|
-
let consecutiveErrors = 0;
|
|
167
|
-
for (;;) {
|
|
168
|
-
if (signal?.aborted) {
|
|
169
|
-
// C1(failloud):最小对症=失败留痕,不必重试——这是最后一次尝试把行标 expired,任务本身已经在
|
|
170
|
-
// abort 路径上收尾,重试没有下一个时机。裸吞会让一次真实的店写故障(TiDB blip)在观测面上
|
|
171
|
-
// 与"成功标了 expired"毫无区别;补 error 留痕,行为(deny)不变。
|
|
172
|
-
await store.decide(id, scope, "expired", "task aborted before decision", null).catch((e) => {
|
|
173
|
-
logger.error("approval_expire_write_failed", { id, scope, err: e instanceof Error ? e.message : String(e) });
|
|
174
|
-
});
|
|
175
|
-
return false;
|
|
176
|
-
}
|
|
177
|
-
let s;
|
|
178
|
-
try {
|
|
179
|
-
s = await store.getStatus(id, scope);
|
|
180
|
-
consecutiveErrors = 0;
|
|
181
|
-
}
|
|
182
|
-
catch (e) {
|
|
183
|
-
// A single transient TiDB blip must NOT throw out of the poll loop — core fail-closes a thrown
|
|
184
|
-
// approval policy to DENY, so one hiccup would deny an already-approved high-risk call after the
|
|
185
|
-
// operator clicked approve. Tolerate a few consecutive errors (keep polling); only give up (re-throw →
|
|
186
|
-
// deny) on a persistent outage.
|
|
187
|
-
if (++consecutiveErrors >= MAX_POLL_ERRORS)
|
|
188
|
-
throw e;
|
|
189
|
-
await sleepAbortable(pollMs, signal);
|
|
190
|
-
continue;
|
|
191
|
-
}
|
|
192
|
-
if (s?.status === "approved")
|
|
193
|
-
return true;
|
|
194
|
-
if (s?.status === "denied" || s?.status === "expired")
|
|
195
|
-
return false;
|
|
196
|
-
await sleepAbortable(pollMs, signal);
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
function sleepAbortable(ms, signal) {
|
|
200
|
-
return new Promise((resolve) => {
|
|
201
|
-
if (signal?.aborted) {
|
|
202
|
-
resolve();
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
const onAbort = () => {
|
|
206
|
-
clearTimeout(timer);
|
|
207
|
-
resolve();
|
|
208
|
-
};
|
|
209
|
-
const timer = setTimeout(() => {
|
|
210
|
-
signal?.removeEventListener("abort", onAbort);
|
|
211
|
-
resolve();
|
|
212
|
-
}, ms);
|
|
213
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
214
|
-
});
|
|
215
|
-
}
|
|
216
130
|
//# sourceMappingURL=approval.js.map
|
package/dist/auth-bridge.d.ts
CHANGED
|
@@ -2,7 +2,6 @@ import { type AuthBridgeErrorCode, type VerifiedIdentity } from "@sema-agent/reg
|
|
|
2
2
|
import type { Logger } from "./observability/logger.js";
|
|
3
3
|
import type { Metrics } from "./observability/metrics.js";
|
|
4
4
|
export type { VerifiedIdentity } from "@sema-agent/registry-core/api/auth-bridge";
|
|
5
|
-
export { looksLikeJwt } from "@sema-agent/registry-core/api/auth-bridge";
|
|
6
5
|
export interface RegistryJwtVerifierOptions {
|
|
7
6
|
/** R4 — 期望 iss(registry 的 SSO_ISSUER;默认=SEMA_REGISTRY_URL,双侧去尾斜杠比较)。 */
|
|
8
7
|
issuer: string;
|
package/dist/auth-bridge.js
CHANGED
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { createPublicKey, verify as cryptoVerify } from "node:crypto";
|
|
13
13
|
import { AUTH_BRIDGE_ALGS, DEFAULT_CLOCK_SKEW_SEC, DEFAULT_JWKS_REFRESH_MIN_INTERVAL_SEC, DEFAULT_OFFLINE_GRACE_SEC, REGISTRY_JWKS_PATH, RegistryJwks, classifyTimeClaims, jwksWithinOfflineGrace, shouldForceJwksRefresh, toVerifiedIdentity, } from "@sema-agent/registry-core/api/auth-bridge";
|
|
14
|
-
export { looksLikeJwt } from "@sema-agent/registry-core/api/auth-bridge";
|
|
15
14
|
const DEFAULT_JWKS_TTL_SEC = 15 * 60;
|
|
16
15
|
/** JWKS 响应体字节上限(一个配错或超大响应的端点不应让 worker 无界缓冲;正常 JWKS 千字节级)。 */
|
|
17
16
|
const MAX_JWKS_BYTES = 256 * 1024;
|
package/dist/auth-keys.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* IDENTITY). config.ts consumes ONLY these two functions + their row types at env-load time, and importing them from
|
|
6
6
|
* security.ts made the base config layer value-depend on the whole 55KiB auth module (lens2 §F). This file is a pure
|
|
7
7
|
* leaf (JSON.parse + shape filters, zero repo imports); the VERIFIERS that consume the parsed key-sets
|
|
8
|
-
* (verifyApprovalHmac / verifyPrincipalJwt) stay in
|
|
8
|
+
* (verifyApprovalHmac / verifyPrincipalJwt) stay in ./approval-hmac.ts and ./principal-jwt.ts; consumers import these four names from HERE ([2354] 兼容面全清).
|
|
9
9
|
*/
|
|
10
10
|
/** One key in the rotating HMAC key-set. `kid` lets the verifier pick the signing key (or fall back to trying the
|
|
11
11
|
* whole set); `status` lets sema-registry rotate without breaking in-flight approvals: `active` = sign + verify,
|
package/dist/auth-keys.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* IDENTITY). config.ts consumes ONLY these two functions + their row types at env-load time, and importing them from
|
|
6
6
|
* security.ts made the base config layer value-depend on the whole 55KiB auth module (lens2 §F). This file is a pure
|
|
7
7
|
* leaf (JSON.parse + shape filters, zero repo imports); the VERIFIERS that consume the parsed key-sets
|
|
8
|
-
* (verifyApprovalHmac / verifyPrincipalJwt) stay in
|
|
8
|
+
* (verifyApprovalHmac / verifyPrincipalJwt) stay in ./approval-hmac.ts and ./principal-jwt.ts; consumers import these four names from HERE ([2354] 兼容面全清).
|
|
9
9
|
*/
|
|
10
10
|
/** Parse APPROVAL_HMAC_KEYS — a sema-registry-managed, rotating key-SET, as a JSON array of {kid,key,status}.
|
|
11
11
|
* Empty / unset / unparseable ⇒ `[]` ⇒ HMAC verification is OFF (D-G inactive; back-compat, BFF-only door). */
|
|
@@ -278,7 +278,7 @@ function dryRunMockFactory() {
|
|
|
278
278
|
sessionId: `dry-${String(seed)}`,
|
|
279
279
|
status: "completed",
|
|
280
280
|
result: "DONE",
|
|
281
|
-
stats: { turns: 3, tokens: 1200, costMicroUsd: 50_000,
|
|
281
|
+
stats: { turns: 3, tokens: 1200, costMicroUsd: 50_000, nested: { tokens: 0, turns: 0, tasks: 0, costMicroUsd: 0 }, ...stats },
|
|
282
282
|
verification: { verdict: green ? "PASS" : "FAIL", rounds: 1, findings: [] },
|
|
283
283
|
};
|
|
284
284
|
const deps = {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CenterPromptSource } from "@sema-agent/core";
|
|
2
2
|
import { buildPricing } from "../budget.js";
|
|
3
|
-
import { type PromptsDomainFaces } from "../
|
|
3
|
+
import { type PromptsDomainFaces } from "../prompts-domain-validate.js";
|
|
4
4
|
import { type Scenario, type ScenarioDeps, type ScenarioDetail } from "../capabilities/scenarios.js";
|
|
5
5
|
import type { LoadedSkill } from "../capabilities/skills.js";
|
|
6
6
|
import { type ServiceConfig } from "../config.js";
|
|
@@ -38,7 +38,8 @@ import { skillContentHash } from "@sema-agent/registry-core";
|
|
|
38
38
|
import { CenterPromptSource, FilePromptArtifactStore, FilePromptSourceStateStore, MemoryPromptArtifactStore, MemoryPromptSourceStateStore, } from "@sema-agent/core";
|
|
39
39
|
import { buildPricing } from "../budget.js";
|
|
40
40
|
import { applyCenterPlugins } from "../capabilities/center-plugins.js";
|
|
41
|
-
import {
|
|
41
|
+
import { applyCatalogToSource, withPromptArtifactBackfill } from "../capabilities/center-prompts.js";
|
|
42
|
+
import { validatePromptsDomain, CORE_ENGINE_VERSION } from "../prompts-domain-validate.js";
|
|
42
43
|
import { centerScenarios, centerScenarioDetails } from "../capabilities/scenarios.js";
|
|
43
44
|
import { configLkgEnabled } from "../config.js";
|
|
44
45
|
import { defaultLkgPath, defaultSkillCacheDir, saveLkg, loadLkg } from "../config-lkg.js";
|
|
@@ -87,7 +88,7 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
87
88
|
let pendingRestart;
|
|
88
89
|
// DUAL-MODE-DESIGN §4: the config SOURCE is a backend-selectable seam — remote (config-center HTTP, the fleet
|
|
89
90
|
// default) | local (.env + config.d via @sema-agent/registry-core FileConfigStore, the single-machine/TOC source).
|
|
90
|
-
// The provider exists when SEMA_REGISTRY_URL (legacy CONFIG_CENTER_URL) is set OR CONFIG_PROVIDER=local is explicit; neither = pure-env
|
|
91
|
+
// The provider exists when SEMA_REGISTRY_URL (legacy CONFIG_CENTER_URL now boot-rejects, no dual-read) is set OR CONFIG_PROVIDER=local is explicit; neither = pure-env
|
|
91
92
|
// (byte-identical to before). The remote provider DELEGATES verbatim to fetchEffective, so the fleet path is
|
|
92
93
|
// unchanged; applyEffective consumes either source's EffectiveConfig identically (one resolver → no drift).
|
|
93
94
|
const cc = config.configCenter;
|
|
@@ -104,7 +105,7 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
104
105
|
sealedKeys = await ensureSealedKeyStore(join(config.localDataRoot ?? localRoot, "sealed-key"), logger);
|
|
105
106
|
void reportExecutionPublicKey({
|
|
106
107
|
baseUrl: cc?.baseUrl,
|
|
107
|
-
adminToken: process.env.SEMA_REGISTRY_ADMIN_TOKEN
|
|
108
|
+
adminToken: process.env.SEMA_REGISTRY_ADMIN_TOKEN, // [2373]B-1:REGISTRY_ADMIN_TOKEN 双读已墓碑(在场即拒启)
|
|
108
109
|
key: sealedKeys.latest,
|
|
109
110
|
...(cc?.worker ? { notes: `worker ${cc.worker}` } : {}),
|
|
110
111
|
logger,
|
package/dist/boot/reapers.d.ts
CHANGED
|
@@ -20,7 +20,7 @@ import type { Logger } from "../observability/logger.js";
|
|
|
20
20
|
import type { Metrics } from "../observability/metrics.js";
|
|
21
21
|
import type { WorkflowNotifyGate, WorkflowNotifyJournalStore } from "../orchestration/workflow-notify-journal.js";
|
|
22
22
|
import type { TaskAttachmentStore } from "../plugins/task-attachment-store.js";
|
|
23
|
-
import type {
|
|
23
|
+
import type { CheckpointStoreFull, CostQuotaStore, ImageBake, RateLimiterStore, ServiceWorkflowJournalStore, StoreBackend, ToolResultStoreFull } from "../plugins/store-backend.js";
|
|
24
24
|
export interface ReapersCtx {
|
|
25
25
|
config: ServiceConfig;
|
|
26
26
|
logger: Logger;
|
|
@@ -30,7 +30,6 @@ export interface ReapersCtx {
|
|
|
30
30
|
subRunner: Runner;
|
|
31
31
|
runStore: ReturnType<StoreBackend["run"]> | undefined;
|
|
32
32
|
checkpointStore: CheckpointStoreFull | undefined;
|
|
33
|
-
approvalStore: ApprovalStore | undefined;
|
|
34
33
|
rateLimiter: RateLimiter | RateLimiterStore | undefined;
|
|
35
34
|
costQuota: CostQuota | CostQuotaStore | undefined;
|
|
36
35
|
toolResultStore: ToolResultStoreFull | undefined;
|
package/dist/boot/reapers.js
CHANGED
|
@@ -17,7 +17,7 @@ import { sweepStaleScratchpads } from "../env-facts.js";
|
|
|
17
17
|
import { CostQuota } from "../observability/cost-quota.js";
|
|
18
18
|
/** 起后台维护 tick,返回定时器 handle(收尾段 clearInterval 用)。 */
|
|
19
19
|
export function startReapers(ctx) {
|
|
20
|
-
const { config, logger, metrics, localRoot, backend, subRunner, runStore, checkpointStore,
|
|
20
|
+
const { config, logger, metrics, localRoot, backend, subRunner, runStore, checkpointStore, rateLimiter, costQuota, toolResultStore, fileSnapshotStore, taskAttachmentStore, imageBakes, worktreeReap, workflowNotifyGate, workflowJournalStore, sqlWorkflowRunStore, workflowNotifyJournal, rosterStore, backgroundAgentStore, mailboxStore, getRunDenySweep, } = ctx;
|
|
21
21
|
// S7 (SILENT-FALLBACK P0-d): the sweeps' return counts were discarded — an instance death that batch-fails
|
|
22
22
|
// N orphans was indistinguishable from organic failures. Count + log ONLY when a sweep flipped rows (>0),
|
|
23
23
|
// so healthy ticks stay silent. Tolerant of void-returning stores (typeof guard).
|
|
@@ -137,11 +137,10 @@ export function startReapers(ctx) {
|
|
|
137
137
|
// continues with the denial), vs the abort reapExpired gives the other kinds. Bounded per tick.
|
|
138
138
|
void getRunDenySweep()?.(Date.now()).catch(() => undefined); // A10 搬运改写:晚绑取值(原 `runDenySweep?.`)
|
|
139
139
|
}
|
|
140
|
-
// The finer, OPT-IN
|
|
141
|
-
//
|
|
142
|
-
//
|
|
140
|
+
// The finer, OPT-IN time-based suspended-run reaper (APPROVAL_TIMEOUT_SEC). Stays gated — reapSuspended
|
|
141
|
+
// with a 0 TTL would nuke ALL suspended rows (cutoff = now). The absolute backstop above is the safety
|
|
142
|
+
// floor; this is the operator-chosen deadline. ([2354] A-5:F4 轮询店的 expireStale 腿随车道退役。)
|
|
143
143
|
if (config.approvalTimeoutSec > 0) {
|
|
144
|
-
void approvalStore?.expireStale(config.approvalTimeoutSec * 1000).catch(() => undefined);
|
|
145
144
|
void runStore?.reapSuspended(config.approvalTimeoutSec * 1000).then(reapCount("runs_reaped_total", { kind: "suspended" })).catch(() => undefined);
|
|
146
145
|
}
|
|
147
146
|
// GC checkpoint_ctx rows whose checkpoint is gone (bound to the checkpoint lifecycle).
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type MemoryBackend, type RunnerDeps } from "@sema-agent/core";
|
|
2
|
-
import {
|
|
2
|
+
import type { PromptsDomainFaces } from "../prompts-domain-validate.js";
|
|
3
3
|
import { SessionEnvironmentSelection, selectEnvironmentTool } from "../capabilities/select-environment-tool.js";
|
|
4
4
|
import { sendUserFileTool } from "../capabilities/send-user-file-tool.js";
|
|
5
5
|
import { selectScenario } from "../capabilities/scenarios.js";
|
|
@@ -56,8 +56,6 @@ export interface ResolveSpecCtx {
|
|
|
56
56
|
} | undefined;
|
|
57
57
|
durableEnabled: boolean;
|
|
58
58
|
approvalExemptionStore: ReturnType<StoreBackend["approvalExemption"]> | undefined;
|
|
59
|
-
approvalEnabled: boolean | undefined;
|
|
60
|
-
approvalStore: ReturnType<NonNullable<StoreBackend["approval"]>> | undefined;
|
|
61
59
|
singleUserAutoAcceptBaseline: boolean;
|
|
62
60
|
checkpointStore: ReturnType<NonNullable<StoreBackend["checkpoint"]>> | undefined;
|
|
63
61
|
deploymentHooks: NonNullable<RunnerDeps["hooks"]>;
|