@sema-agent/server 7.130.0 → 7.132.0
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/MIGRATION.md +396 -0
- package/README.md +13 -6
- package/README.zh-CN.md +9 -5
- package/USAGE.md +187 -50
- package/dist/approval-card.d.ts +3 -1
- package/dist/approval-card.js +2 -3
- package/dist/audit.d.ts +7 -10
- package/dist/audit.js +4 -1
- package/dist/auth-bridge.d.ts +4 -0
- package/dist/auth-bridge.js +10 -11
- package/dist/bench/s1/live-deps.js +2 -0
- package/dist/boot/deployment-mods.d.ts +31 -0
- package/dist/boot/deployment-mods.js +26 -0
- package/dist/boot/execution-env.d.ts +1 -1
- package/dist/boot/execution-env.js +19 -6
- package/dist/boot/memory-boundary.d.ts +2 -2
- package/dist/boot/read-deny-anchor-audit.d.ts +17 -0
- package/dist/boot/read-deny-anchor-audit.js +36 -0
- package/dist/boot/resolve-spec.d.ts +1 -5
- package/dist/boot/resolve-spec.js +56 -61
- package/dist/boot/runner-deps.d.ts +19 -8
- package/dist/boot/runner-deps.js +14 -2
- package/dist/boot/session-faces.d.ts +1 -7
- package/dist/boot/stage-02-web-admin-pull.js +9 -1
- package/dist/boot/stage-03-store-backend.d.ts +1 -1
- package/dist/boot/stage-03-store-backend.js +2 -2
- package/dist/boot/stage-04-stores.d.ts +1 -1
- package/dist/boot/stage-05-execution-env.d.ts +4 -4
- package/dist/boot/stage-05-execution-env.js +7 -10
- package/dist/boot/stage-06-runners.d.ts +2 -2
- package/dist/boot/stage-06-runners.js +5 -4
- package/dist/boot/stage-07-capability-layer.d.ts +2 -2
- package/dist/boot/stage-07-capability-layer.js +3 -3
- package/dist/boot/stage-08-reapers.d.ts +2 -2
- package/dist/boot/stage-09-leader.d.ts +3 -9
- package/dist/boot/stage-10-http-server.d.ts +3 -9
- package/dist/boot/stage-10-http-server.js +12 -10
- package/dist/boot/stores.d.ts +1 -1
- package/dist/boot/stores.js +5 -6
- package/dist/boot/web-admin.d.ts +0 -3
- package/dist/boot/web-admin.js +35 -35
- package/dist/brain.js +17 -22
- package/dist/budget.js +5 -4
- package/dist/caller-text-echo.d.ts +20 -0
- package/dist/caller-text-echo.js +24 -0
- package/dist/capabilities/brand-identity.d.ts +26 -0
- package/dist/capabilities/brand-identity.js +27 -0
- package/dist/capabilities/builtin-tools.js +2 -1
- package/dist/capabilities/center-plugins.js +1 -1
- package/dist/capabilities/center-prompts.d.ts +32 -59
- package/dist/capabilities/center-prompts.js +18 -32
- package/dist/capabilities/composite-members.d.ts +1 -0
- package/dist/capabilities/composite-members.js +1 -0
- package/dist/capabilities/engine-capabilities.js +2 -1
- package/dist/capabilities/hands-lane.d.ts +9 -6
- package/dist/capabilities/hands-lane.js +3 -3
- package/dist/capabilities/host-tool-names.d.ts +17 -0
- package/dist/capabilities/host-tool-names.js +15 -0
- package/dist/capabilities/mcp-probe.d.ts +14 -1
- package/dist/capabilities/mcp-probe.js +22 -133
- package/dist/capabilities/repo-tools.js +4 -3
- package/dist/capabilities/scenarios.d.ts +42 -47
- package/dist/capabilities/scenarios.js +19 -35
- package/dist/capabilities/select-environment-tool.js +2 -1
- package/dist/capabilities/send-user-file-tool.d.ts +0 -1
- package/dist/capabilities/send-user-file-tool.js +2 -2
- package/dist/capabilities/skills.d.ts +19 -4
- package/dist/capabilities/skills.js +30 -10
- package/dist/capabilities/tool-defer.js +2 -1
- package/dist/config-catalog.js +22 -11
- package/dist/config-invariants.js +2 -2
- package/dist/config-lkg.d.ts +9 -9
- package/dist/config-lkg.js +20 -4
- package/dist/config-provider.d.ts +3 -1
- package/dist/config-provider.js +14 -6
- package/dist/config-types.d.ts +13 -9
- package/dist/config.d.ts +2 -2
- package/dist/config.js +34 -20
- package/dist/device-ws-protocol.d.ts +1 -1
- package/dist/device-ws-protocol.js +1 -0
- package/dist/elicitation.d.ts +7 -0
- package/dist/elicitation.js +20 -5
- package/dist/env-name-allowlist-knobs.d.ts +12 -2
- package/dist/env-name-allowlist-knobs.js +5 -4
- package/dist/exec-bounds.d.ts +15 -3
- package/dist/exec-bounds.js +4 -0
- package/dist/execution-lane-caps.d.ts +9 -2
- package/dist/execution-lane-caps.js +11 -0
- package/dist/hooks/classic-stations.d.ts +86 -0
- package/dist/hooks/classic-stations.js +27 -0
- package/dist/hooks/hook-llm.d.ts +8 -5
- package/dist/hooks/hook-llm.js +80 -37
- package/dist/hooks/hook-runner.d.ts +273 -75
- package/dist/hooks/hook-runner.js +293 -317
- package/dist/http/admission.d.ts +8 -2
- package/dist/http/admission.js +103 -59
- package/dist/http/approval-sweeps.js +59 -18
- package/dist/http/checkpoint-ctx.d.ts +36 -18
- package/dist/http/checkpoint-ctx.js +14 -10
- package/dist/http/claimed-run.d.ts +13 -0
- package/dist/http/claimed-run.js +15 -0
- package/dist/http/device-placement.js +5 -10
- package/dist/http/dispatch.d.ts +0 -4
- package/dist/http/dispatch.js +6 -10
- package/dist/http/durable-run-leg.d.ts +2 -1
- package/dist/http/durable-run-leg.js +5 -3
- package/dist/http/health-self-report.d.ts +7 -5
- package/dist/http/health-self-report.js +4 -18
- package/dist/http/principal-gate.d.ts +23 -6
- package/dist/http/principal-gate.js +24 -5
- package/dist/http/refusal-body.d.ts +21 -0
- package/dist/http/refusal-body.js +4 -0
- package/dist/http/request-guards.d.ts +27 -0
- package/dist/http/request-guards.js +24 -3
- package/dist/http/resume-legs.d.ts +25 -0
- package/dist/http/resume-legs.js +48 -26
- package/dist/http/routes/approvals-assistant.js +1 -1
- package/dist/http/routes/capabilities.js +7 -17
- package/dist/http/routes/diagnostics.js +1 -1
- package/dist/http/routes/rules.js +2 -2
- package/dist/http/routes/runs.js +13 -17
- package/dist/http/routes/session-sync.js +4 -2
- package/dist/http/routes/sessions.js +23 -11
- package/dist/http/routes/shared-memory.js +2 -13
- package/dist/http/routes/side-query.js +2 -3
- package/dist/http/routes/tasks.js +34 -19
- package/dist/http/scenario-read-face.d.ts +14 -0
- package/dist/http/scenario-read-face.js +5 -0
- package/dist/http/send.d.ts +13 -1
- package/dist/http/send.js +12 -1
- package/dist/http/server.d.ts +37 -23
- package/dist/http/server.js +30 -4
- package/dist/http/stored-body-replay.d.ts +10 -3
- package/dist/http/stored-body-replay.js +27 -6
- package/dist/http/submit-ctx.d.ts +25 -0
- package/dist/http/submit-ctx.js +39 -0
- package/dist/http/wire-types.d.ts +18 -5
- package/dist/index.d.ts +3 -2
- package/dist/index.js +3 -2
- package/dist/lane-home-probe.d.ts +43 -0
- package/dist/lane-home-probe.js +35 -0
- package/dist/limit-refusal.d.ts +47 -0
- package/dist/limit-refusal.js +12 -0
- package/dist/main.js +1 -1
- package/dist/mcp-assertion-header.d.ts +3 -11
- package/dist/mcp-assertion-header.js +3 -9
- package/dist/mcp-tool-faces.d.ts +5 -0
- package/dist/mcp-tool-faces.js +5 -1
- package/dist/memory-scope.d.ts +1 -1
- package/dist/model-entry-refusal.d.ts +1 -7
- package/dist/model-provider.d.ts +39 -12
- package/dist/model-provider.js +19 -2
- package/dist/model-route-endpoint.d.ts +52 -12
- package/dist/model-route-endpoint.js +48 -26
- package/dist/model-route-gap.d.ts +5 -4
- package/dist/model-route-gap.js +1 -1
- package/dist/model-select.d.ts +58 -0
- package/dist/model-select.js +31 -0
- package/dist/namespaced-rule-name.d.ts +7 -4
- package/dist/namespaced-rule-name.js +4 -3
- package/dist/observability/cost-taxonomy.d.ts +7 -7
- package/dist/observability/fail-open.d.ts +53 -12
- package/dist/observability/fail-open.js +47 -7
- package/dist/observability/metrics.js +3 -1
- package/dist/observability/prompt-manifest.d.ts +47 -82
- package/dist/observability/prompt-manifest.js +119 -17
- package/dist/observability/run-terminal.js +14 -6
- package/dist/observability/secret-env-scrub.d.ts +13 -1
- package/dist/observability/secret-env-scrub.js +13 -1
- package/dist/observability/tool-trace.d.ts +16 -21
- package/dist/observability/tool-trace.js +51 -42
- package/dist/per-task-image.d.ts +7 -1
- package/dist/per-task-image.js +3 -3
- package/dist/plain-string-record.d.ts +25 -0
- package/dist/plain-string-record.js +32 -0
- package/dist/plugins/blob-backend.d.ts +68 -13
- package/dist/plugins/blob-backend.js +53 -10
- package/dist/plugins/checkpoint-store-sql.d.ts +14 -4
- package/dist/plugins/checkpoint-store-sql.js +39 -26
- package/dist/plugins/k8s-bg-scripts.d.ts +11 -0
- package/dist/plugins/k8s-bg-scripts.js +22 -0
- package/dist/plugins/local-checkpoint-store.js +5 -2
- package/dist/plugins/local-session-store.js +3 -3
- package/dist/plugins/one-time-migrations.d.ts +147 -91
- package/dist/plugins/one-time-migrations.js +372 -208
- package/dist/plugins/permission-rule-store-sql.d.ts +13 -7
- package/dist/plugins/permission-rule-store-sql.js +4 -18
- package/dist/plugins/pg-session-storage.d.ts +4 -5
- package/dist/plugins/pg-session-storage.js +7 -17
- package/dist/plugins/remote-env-adb.d.ts +6 -0
- package/dist/plugins/remote-env-adb.js +9 -4
- package/dist/plugins/remote-env-device.js +3 -0
- package/dist/plugins/remote-env-e2b.d.ts +1 -1
- package/dist/plugins/remote-env-e2b.js +21 -9
- package/dist/plugins/remote-env-host.d.ts +9 -9
- package/dist/plugins/remote-env-host.js +10 -32
- package/dist/plugins/remote-env-k8s.d.ts +95 -26
- package/dist/plugins/remote-env-k8s.js +265 -90
- package/dist/plugins/remote-env-local-docker.d.ts +20 -1
- package/dist/plugins/remote-env-local-docker.js +77 -9
- package/dist/plugins/remote-env-ssh.d.ts +15 -0
- package/dist/plugins/remote-env-ssh.js +109 -3
- package/dist/plugins/remote-shell.d.ts +0 -1
- package/dist/plugins/remote-shell.js +1 -2
- package/dist/plugins/retention-store-sql.js +6 -2
- package/dist/plugins/schema-consistency.d.ts +54 -0
- package/dist/plugins/schema-consistency.js +52 -0
- package/dist/plugins/session-epoch-anchor.d.ts +13 -0
- package/dist/plugins/session-epoch-anchor.js +23 -0
- package/dist/plugins/shared-memory-store-sql.d.ts +9 -3
- package/dist/plugins/shared-memory-store-sql.js +5 -16
- package/dist/plugins/sql-driver.d.ts +141 -0
- package/dist/plugins/sql-driver.js +115 -1
- package/dist/plugins/sql-errors.d.ts +41 -0
- package/dist/plugins/sql-errors.js +36 -0
- package/dist/plugins/store-backend.js +2 -1
- package/dist/plugins/tidb-session-storage.d.ts +7 -11
- package/dist/plugins/tidb-session-storage.js +6 -16
- package/dist/plugins/tidb-session-store.js +1 -1
- package/dist/prompts-domain-validate.d.ts +17 -61
- package/dist/prompts-domain-validate.js +9 -119
- package/dist/question.d.ts +18 -9
- package/dist/question.js +21 -13
- package/dist/request-key-closure.d.ts +4 -4
- package/dist/request-key-closure.js +18 -13
- package/dist/rule-entry-list.d.ts +134 -24
- package/dist/rule-entry-list.js +162 -30
- package/dist/run-local.d.ts +3 -3
- package/dist/run-local.js +26 -25
- package/dist/runs.d.ts +48 -2
- package/dist/runs.js +61 -2
- package/dist/server-secret-env.d.ts +44 -18
- package/dist/server-secret-env.js +49 -8
- package/dist/session-incarnation.d.ts +15 -5
- package/dist/session-incarnation.js +16 -9
- package/dist/session-titler.js +12 -2
- package/dist/spec-fields.d.ts +34 -18
- package/dist/spec-fields.js +46 -53
- package/dist/sql-engine-posture.d.ts +29 -4
- package/dist/sql-engine-posture.js +36 -1
- package/dist/stored-request-hooks-m20.d.ts +23 -0
- package/dist/stored-request-hooks-m20.js +124 -0
- package/dist/stored-request-tool-axes-m19.d.ts +20 -5
- package/dist/stored-request-tool-axes-m19.js +30 -2
- package/dist/task-a2a.d.ts +9 -1
- package/dist/task-a2a.js +73 -47
- package/dist/task-mcp.d.ts +54 -102
- package/dist/task-mcp.js +194 -92
- package/dist/task-settings.d.ts +47 -25
- package/dist/task-settings.js +46 -61
- package/dist/text-bidi.d.ts +3 -46
- package/dist/text-bidi.js +3 -3
- package/dist/tool-approval.d.ts +1 -1
- package/dist/trace/core-keyset-guard.d.ts +24 -4
- package/dist/trace/engine-notice-wire.d.ts +11 -3
- package/dist/trace/engine-notice-wire.js +8 -1
- package/dist/trace/ledger-events.d.ts +3 -1
- package/dist/trace/ledger-sink.d.ts +29 -0
- package/dist/trace/ledger-sink.js +15 -1
- package/dist/trace/model-segment.js +1 -1
- package/dist/trace/project.d.ts +25 -6
- package/dist/trace/project.js +68 -22
- package/dist/trace/wire-projection-faces.d.ts +80 -2
- package/dist/trace/wire-projection-faces.js +23 -1
- package/dist/user-authored-text.d.ts +7 -0
- package/dist/user-authored-text.js +3 -0
- package/dist/web-admin-client/apply-effective.js +10 -5
- package/dist/web-admin-client/candidate-gate.d.ts +6 -6
- package/dist/web-admin-client/candidate-gate.js +3 -3
- package/dist/web-admin-client/http-client.js +0 -6
- package/dist/web-admin-client/read-warnings.d.ts +13 -0
- package/dist/web-admin-client/read-warnings.js +10 -0
- package/dist/web-admin-client/skills-mcp.d.ts +3 -0
- package/dist/web-admin-client/skills-mcp.js +9 -6
- package/dist/web-admin-client/types.d.ts +3 -4
- package/dist/workspace-cache.d.ts +35 -0
- package/dist/workspace-cache.js +36 -0
- package/dist/workspace-space.d.ts +3 -2
- package/dist/workspace-space.js +2 -0
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +8 -1
- package/package.json +4 -4
- package/scripts/drain-check-local.mjs +37 -3
- package/scripts/drain-check.mysql.sql +30 -2
- package/scripts/drain-check.pg.sql +29 -2
- package/dist/capabilities/memory-notice.d.ts +0 -138
- package/dist/capabilities/memory-notice.js +0 -64
- package/dist/capabilities/prompt.d.ts +0 -17
- package/dist/capabilities/prompt.js +0 -6
- package/dist/mcp-content-origin.d.ts +0 -34
- package/dist/mcp-content-origin.js +0 -10
- package/dist/tool-axis-words.d.ts +0 -27
- package/dist/tool-axis-words.js +0 -9
- package/dist/wire-name-bound.d.ts +0 -14
- package/dist/wire-name-bound.js +0 -13
package/USAGE.md
CHANGED
|
@@ -102,12 +102,18 @@ MODEL_GATEWAY_BASEURL=http://gw-a:8000/v1 MODEL_GATEWAY_FALLBACK_URLS=http://gw
|
|
|
102
102
|
ANTHROPIC_API_KEY=sk-ant-… # 可选:ANTHROPIC_BASE_URL / ANTHROPIC_VERSION / ANTHROPIC_CACHE_BREAKPOINTS=true
|
|
103
103
|
```
|
|
104
104
|
- 两个变量都不设 = 和以前**逐字节一致**(单网关)。
|
|
105
|
-
- 🔴 **`MODEL_GATEWAY_BASEURL` 没有出厂缺省**(BREAKING)
|
|
105
|
+
- 🔴 **`MODEL_GATEWAY_BASEURL` 没有出厂缺省**(BREAKING):**将要服务的那张表**里每一条落 openai 兼容腿的路由(主模型 / cheap 槽 /
|
|
106
106
|
目录条目 / 降级目标 / titler 所选模型)都必须解析到显式端点 —— 条目自己的 `baseUrl`,或本键 —— 否则拒启,拒因
|
|
107
107
|
(码 `config.model_route_endpoint_missing`)点名解析不到的模型并给出本机写法 `MODEL_GATEWAY_BASEURL=http://127.0.0.1:8000/v1`。
|
|
108
|
-
|
|
108
|
+
**判哪张表**:判在目录应用之后(不在读 env 的那一拍)—— 一份目录被采纳(`config.d/models.json` 或中心的启用条目落了模型面)⇒ 判目录表,
|
|
109
|
+
拒因教的出路是「设网关,或在目录里给条目自己的 `baseUrl`」;目录缺席 / 被整拒 / 没有一条启用条目 ⇒ 服务的是 env 表(`MODEL_ID` / `MODEL_CHEAP_ID`),
|
|
110
|
+
判 env 表,拒因教的是 env 的三条出路:设 `MODEL_GATEWAY_BASEURL` / 挂 Anthropic 路由(`MODEL_PROVIDER=anthropic` + `ANTHROPIC_API_KEY` 或 `ANTHROPIC_AUTH_TOKEN`)/ 不设 `MODEL_ID` 让目录缺省服务
|
|
111
|
+
(env 行没有自己的 `baseUrl`,「给条目自己的 baseUrl」不是它的出路)。
|
|
112
|
+
只设 `MODEL_GATEWAY_FALLBACK_URLS` 不设主网关同拒(`config.gateway_fallback_without_primary`,与服务哪张表无关)。只走 Anthropic 路由的部署
|
|
109
113
|
不设网关合法;此时 `MODEL_API_KEY`(网关的凭据)不装载、不发往任何路由(启动通知 `model_gateway_key_unpaired`)。
|
|
110
114
|
中心 / config.d 下发的候选目录里有解析不到的条目 ⇒ 候选的模型面这一组被拒、上一代模型面继续服务(同候选其余组照落)。
|
|
115
|
+
- **目录与 `MODEL_ID` 并存**:目录一旦被采纳就整张换掉 env 表 —— 缺省模型取目录缺省,env 的 `MODEL_ID` 不服务。此时起服**不拒**(哪怕没设网关:目录条目自带 `baseUrl` 即可),
|
|
116
|
+
而是说一行 warn `config_env_set_but_ineffective`(`env: "MODEL_ID"`,点名目录缺省是谁),让你知道改 `MODEL_ID` 没有效果 —— 目录第一次被采纳的那一拍说,恰好一次(启动时就采纳、或目录晚到 / 刷新时才第一次采纳都一样)。`MODEL_ID` 仍是目录缺席时的兜底(目录迟到且无上一份 / 候选被整拒 / 没有启用条目时由它服务,届时按 env 表判)。
|
|
111
117
|
- **凭据什么时候生效**:网关 key `MODEL_API_KEY`(以及 `ANTHROPIC_API_KEY` / `ANTHROPIC_AUTH_TOKEN`)在启动时读一次,**换值 = 重启本服务**
|
|
112
118
|
—— 没有热应用通道(以前的版本同样如此:这几把 key 只来自启动时的环境变量;引擎 7.51.0 起模型路由的构造配置也只读一次)。
|
|
113
119
|
目录条目**自己的**凭据(`apiKeyEnv` 点名的变量、`sealedApiKey`)跟着中心 / config.d 的模型面热应用走,不用重启:新起的任务与调用
|
|
@@ -259,7 +265,8 @@ MODEL_DEGRADE_ON=rate_limit,breaker_open # 可选,反应式触发器子集;词
|
|
|
259
265
|
- **成本天花板要有价才咬得住**:`MAX_TASK_COST_USD` / `MAX_PRINCIPAL_COST_USD` 量的是 `costUsd`,未定价的模型算不出成本 ⇒ 这两道闸**永不触发**。目录里一只带价模型都没有却配了天花板时,boot 会打一条 `cost_ceiling_without_pricing` 告警(不拒启);token 轴的 `MAX_TASK_TOKENS` 不受影响。
|
|
260
266
|
- 成本计量**自动开**:从 config 的 `model.cost`(per-1M 绝对 USD)注入 `pricing`,core 算出权威的整数 `costMicroUsd`(避免浮点累计误差)。`/metrics` 新增:`model_cost_micro_usd_total{model}`(覆盖所有 brain 调用=主任务+异步+委派子任务的总花费)、`brain_first_token_ms`(网关 hang 早警)、`brain_call_latency_ms`、`tool_calls_total{name,ok}`、`budget_exceeded_total{code}`、`cost_quota_rejected_total`、`degraded_total{reason}`(1.40 降级)。
|
|
261
267
|
- **近预算降级 vs 硬闸**:降级(`MODEL_DEGRADE_TO`,到 `atCostFraction` 切便宜模型)是**撑长**预算、任务仍完成(出口质量下降、发 `task.degraded` 事件可告警);硬闸(`maxCostUsd` 全额)仍在,切了便宜模型还超全额 → `limits.max_cost_exceeded` 停。
|
|
262
|
-
- **`METRICS_TOKEN`**(可选,只读):设了它,`GET /metrics`+`/metrics/summary` 接受**它或** `SERVICE_AUTH_TOKEN
|
|
268
|
+
- **`METRICS_TOKEN`**(可选,只读):设了它,`GET /metrics`+`/metrics/summary` 接受**它或** `SERVICE_AUTH_TOKEN`。都没配时 `/metrics` 族只在 dev-open 部署上免凭据(见 §1 dev-open 那一段:
|
|
269
|
+
装了中心鉴权桥、配了 `TRACE_TOKEN` 或开了 `REQUIRE_PRINCIPAL` 的部署上匿名 `401` —— 7.132.0 起,此前前两形照开;`/metrics/plan-cache` 按主体分键,匿名可读 = 名册外泄)。**全 fleet 设同一个值** → 管理端(sema-web,规划名 sema-admin)用**一个** token 拉所有 worker 的指标,**无需持有各 worker 的全权 `SERVICE_AUTH_TOKEN`**(不破坏 secret 边界)。即使外泄也只暴露指标(只读)。
|
|
263
270
|
- **`GET /metrics/summary`**(token-gated,同 `/metrics`):`/metrics` 的**精炼 JSON**——`{model, runsActive, tasks{status}, tokensTotal, costUsd, costUsdByModel, taskDurationAvgSec, brainFirstTokenAvgMs, brainCallAvgMs, cacheHitRateAvg, rateLimited, costQuotaRejected, budgetExceeded, limitCeilingAfterAnswer, degraded, cascade, verifications, toolErrors, httpErrorsByClass, httpErrorsByRoute}`(**7.126.0 起没有 `councilRuns`** —— 它数的 code-review 多镜头评审团随引擎 7.49.0 删掉团队运行时一并删除,Prometheus 的 `council_runs_total` / `council_tokens` 同删;按 v1 形解析这张表的看板升级前先把这一键改成可缺)(`httpErrorsByClass` / `httpErrorsByRoute` 自 **7.87.0**,additive:窗内 HTTP **失败**请求按状态码类聚合(键只有 `4xx` / `5xx`,2xx/3xx 不进;⚠️ `4xx` 含本仓给「客户端提前断连」铸的 `499`,SSE 长连上是常态)+ 失败最多的前 10 条 route 标签(`routeLabel` 低基数形,id 折成 `:id`,未命中路由表的落 `other`)—— 这两格是**不装 Prometheus 的部署**看见一场 404 风暴的唯一地方;两键**恒在场**,零失败时是 `{}`,不用缺席表示零)(`limitCeilingAfterAnswer` 自 7.71.0,按 `origin` 分桶的「答后撞顶」计数;与 `budgetExceeded` **总体不同** —— 前者每条引擎 run 都过,后者只由 HTTP 提交腿递增 —— 不要无条件相加)。给**轻量 fleet 看板**用(管理端 sema-web 的 fleet 页按 worker 拉、渲染卡片、按轮询算速率;**不用 Prometheus/Grafana**)。counter 是累计值、histogram 报均值。
|
|
264
271
|
- 预算闸是 core 强制的:`maxCostUsd` pre-call 估算(没花钱就拒)+ 流中途取消 + turn 边界(`limits.max_cost_exceeded`);`maxTokens` 超 → `limits.max_tokens_exceeded`(core 5.8.0 起 `budget.*` 前缀退役)。**review 网关**建议设 `MAX_TASK_COST_USD` 防单任务烧掉共享云 key。
|
|
265
272
|
- 🔴 **三道 $ 闸的分工(别拿进场门当中途停机用)**:三根旋钮名字都带 cost,但**判的时刻**和**能不能打断正在烧的那张单**完全不同。按「谁触发 / 什么时刻判 / 拒或停长什么样」对表:
|
|
@@ -385,7 +392,7 @@ MODEL_ID=<your-model-name> MODEL_CHEAP_ID=<your-cheap-model-name>
|
|
|
385
392
|
存量中心配置里的 `roles.team` / `roles.synthesize` 由 settings-schema 的一次性迁移搬走,side query 带 `modelRole` 表外词(含 `advisor`)⇒ **400**
|
|
386
393
|
`request.field_invalid`(不再回落主模型;带了 `model` 也一样拒)。要给委派子代配模型就绑 `subagent`,主任务绑 `default`。
|
|
387
394
|
- 调用方可在 `objective` 里 `@<模型名>` 选模型,**只认已配置的名单**(`MODEL_ID` / `MODEL_CHEAP_ID`,或目录条目)——注入不了 `baseUrl`/`apiKey`;无 `@` → 默认模型;`@` 点中一条已发布但本部署不可用的目录条目 ⇒ 400 `request.model_unavailable`。
|
|
388
|
-
- **`GET /v1/models`**(带 Bearer)→ `{models:[{name,id,provider,reasoning,vision,…}],default,defaultModel,droppedEntries}`,只含名字/能力、**不含密钥** —— 消费方(如 OA)拿它做 `@` 自动补全下拉的数据源;`droppedEntries`(7.123.0 起恒在场,零条 = `[]`)是本代目录里被读腿逐条丢掉的条目(下标 + 闭集原因词 + 可披露身份),契约 §A.1d。 7.126.0 起另有**可选**顶层键 `candidateRejected: { domains, at, source }`:最近一次配置候选被候选判官整拒时在场(`domains` = 判形失败的配置域名,`source` = `local` 本机 `config.d` / `remote` 中心,`at` = 判下它的时刻)—— 在场就说明这份目录是回落的那一份(整份候选没收,候选里的模型一个都不在),真因域在 `domains` 里;后来的候选被判 clean 即缺席;dry-run 姿势(web-admin 腿 compare-only)恒缺席(拒判只走日志)。**缺席不等于配置一定干净**(也可能是更早的 server)。只含域名 / 时刻 / 源形态,拒因句与文件路径只在引擎日志 `config_candidate_rejected` 里,契约 §A.1d。
|
|
395
|
+
- **`GET /v1/models`**(带 Bearer)→ `{models:[{name,id,provider,reasoning,vision,…}],default,defaultModel,droppedEntries}`,只含名字/能力、**不含密钥** —— 消费方(如 OA)拿它做 `@` 自动补全下拉的数据源;`reasoning` / `vision` 两列是**三态**:声明了给布尔,**未声明 = 键缺席**(7.131.0 起;env 部署不设 `MODEL_REASONING` / `MODEL_VISION` 就是未声明,没有 `true` 缺省 —— 需要思考的模型显式写 `MODEL_REASONING=true`,纯文本模型写 `MODEL_VISION=false`;缺席时引擎对图收、对思考档不发),契约 §A.1d;`droppedEntries`(7.123.0 起恒在场,零条 = `[]`)是本代目录里被读腿逐条丢掉的条目(下标 + 闭集原因词 + 可披露身份),契约 §A.1d。 7.126.0 起另有**可选**顶层键 `candidateRejected: { domains, at, source }`:最近一次配置候选被候选判官整拒时在场(`domains` = 判形失败的配置域名,`source` = `local` 本机 `config.d` / `remote` 中心,`at` = 判下它的时刻)—— 在场就说明这份目录是回落的那一份(整份候选没收,候选里的模型一个都不在),真因域在 `domains` 里;后来的候选被判 clean 即缺席;dry-run 姿势(web-admin 腿 compare-only)恒缺席(拒判只走日志)。**缺席不等于配置一定干净**(也可能是更早的 server)。只含域名 / 时刻 / 源形态,拒因句与文件路径只在引擎日志 `config_candidate_rejected` 里,契约 §A.1d。
|
|
389
396
|
- 不设 `MODEL_CHEAP_ID` → 所有角色 = 主模型(行为不变)。
|
|
390
397
|
- `MODEL_CHEAP_ID` 写成与 `MODEL_ID` **同一个 id**(7.104.0 起)→ 那就是主模型本身:不铸 cheap 槽,所有角色 = 主模型,起服一行
|
|
391
398
|
`config_env_entry_cheap_same_as_main`(同时设的其余 `MODEL_CHEAP_*` 键一并不生效)。要给同一只上游 id 第二种形(另一个价 / 思考 /
|
|
@@ -487,9 +494,15 @@ MODEL_CASCADE_LADDER=deepseek-flash,deepseek-pro # 目录里的模型名,cheap
|
|
|
487
494
|
只调 `loadConfig()` 的装配对这几形照起。`ctx.configSource === "local"` 时它先读 `config.d/remote-exec.json` 覆写车道(`drivesFromFile`
|
|
488
495
|
= 你的装配驱动得了的文件车道),再判;不走文件覆写的装配直接调同一份判据 `assertExecutionLaneInvariants(config)`。
|
|
489
496
|
`ctx` 的型 `ExecutionLaneComposeCtx` 也从包根导出(自己的装配里要写它的签名 / 抽 helper 时直接 import,不必手抄一份形)。
|
|
497
|
+
读口场景门 `scenarioGate` 是 `createHttpServer` 的必填件(7.131.0+):用包根导出的 `createScenarioGate({ config, scenarios, principalCaps, logger }, "peek")` 铸(与任务提交腿同一个工厂,型 `ScenarioGate` / `ScenarioGateLeg` / `ScenarioGateSources` 一并导出),没递就是 tsc 红。
|
|
498
|
+
**模型路由端点的拒启同理判在目录应用之后**:`judgeServedModelRoute(config, { envTableIsPlaceholder })`(包根导出,HTTP 服务与 `run-local` 调的就是它)只判将要服务的那张表(目录表或 env 表,句子随视图);
|
|
499
|
+
只调 `loadConfig()` 的装配不再在读配置那一拍拿到路由拒启 —— 在**自己的**配置源应用之后调它一次,有判决就拒启(`reason` 是给运维的原句)。严格名册布防(env 表是占位)传 `envTableIsPlaceholder: true`,没有名册门的装配传 `false`。
|
|
490
500
|
- **库形嵌入的 caps `store` 位**(7.106.0 起;7.106.0 合并复审 X9 补一句):`createHttpServer` 的 `storePosture` dep **不传** ⇒ `GET /v1/capabilities` 的
|
|
491
|
-
`store` 取诚实下限 `{declared: <config.dbBackend>, backend: "memory", durable: false}`,且**没有 `store.sql`**(
|
|
501
|
+
`store` 取诚实下限 `{declared: <config.dbBackend>, backend: "memory", durable: false}`,且**没有 `store.sql`**(即使递了引擎读口 `sqlEngine`、真有 SQL 后端 ——
|
|
492
502
|
7.105.0 上这类嵌入方的顶层 `sql` 是有值的)。要 caps 说真话就把你装出来的后端事实经 `storePosture` 递进来(形 = `src/store-posture.ts` 的 `StorePosture`)。
|
|
503
|
+
- **`PORT=0` = 让 OS 分口,口由引擎自己报**:引擎自己绑内核分给它的口,`listening` 启动日志行(stdout,info 级;`LOG_LEVEL` 高于 info 会滤掉它)的 `port` 与 `/health.port` 报**实际绑定口**
|
|
504
|
+
(`PORT` 非 0 时两者与配置值相等)。要用 OS 分的口起引擎的宿主:子进程以 `PORT=0` 起,读 stdout 那一行 `listening` 的 `port`,再用 `/health` 的 `pid` / `dataRoot` 验答话的是自己起的那个进程;
|
|
505
|
+
**不要**先在外面挑一个空闲口、关掉、再交给子进程去绑 —— 关与子进程真正 `listen` 之间有窗,并行负载下别的进程能抢走这个号。`configHash` 仍按**配置值**铸(配置指纹不随 OS 分的口漂)。
|
|
493
506
|
- `/health` 身份字段承诺:`pid`(= 引擎进程)、`startedAt`(**7.67.0+**,= 引擎进程起点的 epoch ms,
|
|
494
507
|
一次铸)与 `dataRoot`(= 生效数据根,解析恒回退 `~/.ai-agent`,与 DB_BACKEND 无关)**恒在**——宿主用
|
|
495
508
|
它们验证「这个端口上的 /health 是不是我起的那个引擎」。`startedAt` 变了 = 这个端口后面换了一条命
|
|
@@ -693,7 +706,7 @@ SEND_USER_FILE_SANDBOX_PUT_ENDPOINT=… # 可选:沙箱直传 PUT 的端
|
|
|
693
706
|
# k8s 集群内 pod 可指内网 MinIO 省公网带宽)
|
|
694
707
|
```
|
|
695
708
|
- **词表优先级**:内网端点 `MINIO_ENDPOINT` 优先,`S3_ENDPOINT` 是外接 S3 兼容位(内网/公网同址场景可只给它,同时充当公网面);公网端点 `S3_PUBLIC_ENDPOINT` 优先,缺席回落 `S3_ENDPOINT`。空串一律按未设处理。
|
|
696
|
-
- **🔴 云形(`DB_BACKEND=mysql|pg`)快照 blob 强制对象存储(1.295+,clay 拍)**:缺 MinIO 三键 ⇒ **boot 拒启**——单行 SQL blob 写会撞 TiDB `txn-entry-size-limit`(默认 6MiB,真库实测矮墙)/ mysql 协议 `max_allowed_packet`,大字节归对象存储(与 D-1 附件面同裁定)。单机/测试台显式逃生:`SNAPSHOT_BLOB_ALLOW_SQL_BYTES=true`(SQL 店此时带 per-blob 帽,
|
|
709
|
+
- **🔴 云形(`DB_BACKEND=mysql|pg`)快照 blob 强制对象存储(1.295+,clay 拍)**:缺 MinIO 三键 ⇒ **boot 拒启**——单行 SQL blob 写会撞 TiDB `txn-entry-size-limit`(默认 6MiB,真库实测矮墙)/ mysql 协议 `max_allowed_packet`,大字节归对象存储(与 D-1 附件面同裁定)。单机/测试台显式逃生:`SNAPSHOT_BLOB_ALLOW_SQL_BYTES=true`(SQL 店此时带 per-blob 帽,MySQL 协议(InnoDB 与 TiDB)默认 = 两堵已知墙取最小:库报的单行上限减 1 KiB(blob 行自己的余量:哈希键 + 长度 + 时间戳;`GET /v1/diagnostics/wiring` 的 `sqlEngine.maxRowBytes`,TiDB 才有)与库报的包墙扣 1 KiB 语句余量后折半(⌊(`sqlEngine.maxPacketBytes` − 1 KiB) ÷ 2⌋:文本协议把 blob 写成十六进制,语句至少是它的 2 倍);任一读数读不出时按该库族文档缺省并留一行运维日志 `fail_open`(tag `server.sql.packet-cap-unread` / `server.sql.tidb-row-cap-unread`),超限 PUT 413 `blob_too_large_for_sql`,门限按请求读活事实(新连接初始化读到新值即换;调大后旧连接换代前有一段过渡窗口,见部署前置清单 DEPLOY-PREREQS(仓内)「数据库」条);帽可用 `SNAPSHOT_BLOB_SQL_MAX_BYTES` 按部署真实限值覆写,两方言生效;pg 默认无帽)。
|
|
697
710
|
- **per-file rewind 历史的边界上限**(与 workspace 浏览面同一个整树快照纪元退役批留下的保留条款):`FILE_HISTORY_RETENTION_KEEP` —— 每个 scope(会话)存活的**最新** boundary 数,**每次 boundary 提交后自剪**(最旧者先亡,刚提交者恒存活;失引用的版本行级联删,blob 字节走异步 grace 窗 GC;v1 基线永存)。未设=core 缺省 **100**(由 core 的 `resolveFileHistoryRetention` 兑现,server 不复制那个数);`unbounded` 是**唯一**的「不剪」拼法(整店自剪关闭,GC 归部署自排 `reap`);`0`/负数/小数/非数 ⇒ **boot 拒启**(码 `config.retention_policy_invalid`,与 core 内置后端同码同判——**省略这个键不等于不剪**,它选的是缺省 100)。三条车道(TiDB / PG / local 文件店)同旋钮同判。⚠️ 升级即生效:存量超 100 boundary 的 scope 在下一次提交时被剪到 100;要保全量先写 `unbounded`。被剪 entry 的键**已花掉**(再次 snapshot 同 entry 典型拒,不复铸)。排序=DB 分配的 per-scope 发布序号 `file_history_boundary.publish_seq`(不是墙钟):**自 7.50.x 有存量 `file_history_boundary` 的部署升级本版会在 boot 期被 `assertFileHistorySchema` 拒启并指明 `DROP TABLE file_history_boundary`**(本仓无 ALTER;丢的是 per-file rewind 便利态,会话与其他持久面不动)。
|
|
698
711
|
- **文件历史捕获总开关**(7.97.0 立,7.104.0 改语义):`FILE_HISTORY_CAPTURE`(缺省 `true`;布尔词表 true/false/1/0/yes/no/on/off,未知词 ⇒ boot 拒启;TiDB / PG / local 三条车道同义)。`false` ⇒ **只关捕获**:历史店照接,引擎拿到部署捕获位 `RunnerDeps.fileHistoryCapture: "off"`,改动文件的首次快照**一个都不捕获**、不铸回合边界(`wiring_manifest.fileHistory` 报 `"disabled"`);**已存历史照常可用** —— `resumeAt`+`restoreFiles` / `rewindFilesTo` 照常还原、2c session-sync 照常导出 / 导入。`GET /v1/capabilities` 的 `fileHistoryCapture` 报 `"off"`,而 `rewindFiles` / `restoreFiles` / `rewindFilesTo` / `sessionSync` 仍为 `true`(缺省部署报 `"on-optional"` = 捕获中且请求可按 run 关掉,见上一段)。🔴 **7.97.0–7.103.x 的旧语义**:`false` = 不把店交给引擎,连已存历史也读不了(还原走 `rewind.store_unconfigured`、sync 501)—— 把本旋钮当成「整个文件历史功能关掉」来用的部署,升级后已存历史**重新可以被还原 / 同步**。要让已存历史也不可用,今天的出路只有**逐会话** `DELETE /v1/sessions/:id`(擦除面不受本旋钮管)与 SQL 后端的留存清扫(`RETENTION_MODE=enforce` + `RETENTION_MAX_AGE_DAYS` + `RETENTION_SWEEP_INTERVAL_SEC`,按会话年龄删,local 车道没有留存车道);**没有**「整库历史一键不可用」的旋钮。⚠️ **关掉 ≠ 删掉**:翻旋钮不批量删除存量历史;local 车道上删会话走 `reap` —— 边界删光、v1 基线按 core 契约留存,既有残余。关着时 `FILE_HISTORY_RETENTION_KEEP` 没有效果(不再有边界提交,自剪不会触发),值仍照常校验。没有存储后端的部署(env-only worker)本来就没有历史店,旋钮在那里无事可关、不下发捕获位(引擎对「off 但没店」拒 prepare)。
|
|
699
712
|
- **🔴 公桶策略必须 GetObject-only**:`mc anonymous set download` 会**连带打开 ListBucket**——匿名 `GET /<bucket>/?list-type=2` 能枚举全部不可猜 key,能力链接设计即告失效。正确姿势=`mc anonymous set-json`,policy 只含 `Action:["s3:GetObject"]` on `arn:aws:s3:::<bucket>/*`(验证:对象 GET 200、桶 LIST 403)。
|
|
@@ -818,6 +831,9 @@ QUESTION_TTL_MS=300000
|
|
|
818
831
|
- 三个值都有出厂缺省(即上面写的值),**不设=行为不变**;越界值**启动期响亮拒**(不静默夹取)。
|
|
819
832
|
- 窗用尽 / 到期 **不是替人作答**:服务只报「此刻无人可答」,落点由引擎选——**durable 部署**(`DURABLE_APPROVAL=true` 且这条腿没有活的流)把问题 **park** 成待办,运维随后经审批面带答案补答;**无 durable 的部署**则让模型被告知"没人在"后按自己的判断继续(run 永不挂死)。
|
|
820
833
|
- 想让人有更长时间答就调大 `QUESTION_TTL_MS`;想让 agent 少打扰人就调小 `QUESTION_MAX_TOTAL_PER_RUN`。
|
|
834
|
+
- **问题卡随 run 账本回放**:`question` / `question_complete` 在每条腿都落进 run 账本(`/v1/tasks/stream` 腿在有 durable run 行时先落账、再写 SSE;`/v1/runs` 腿本来就只有账本)。
|
|
835
|
+
页面重载 / 重连后,经 `GET /v1/runs/:id/events` 取回仍在等的卡(待答 = 没有同 `questionId` 的 `question_complete` 且 `expiresAtMs` 未到)。
|
|
836
|
+
**答题口不变**:`POST /v1/questions/:id/respond` 只在受理这一问的副本内、窗(`QUESTION_TTL_MS`)内有效;没有「列出待答问题」的读口。无 durable run 行的部署没有账本,仍只有 live 帧。
|
|
821
837
|
- 🔴 **`/v1/tasks/stream` 的开帧投递失败是响亮的(逐腿,不是部署级)**:这条腿(**且仅这条腿**)向引擎
|
|
822
838
|
声明 `interactionPosture: "interactive"` —— 人就在这条 SSE 上,一次开帧投递失败(壳断连/流被撕裂)
|
|
823
839
|
不再合成「没有人可问,你自己判」的续跑卡,而是让那次工具调用返回 coded 失败
|
|
@@ -1076,6 +1092,9 @@ READ_DENY_PATTERNS='[{"pattern":"**/secrets/**"},{"pattern":".ssh","caseSensitiv
|
|
|
1076
1092
|
**路径段窗**匹配:pattern 按 `/` 分段,`*` 是唯一元字符(段内通配,不跨段),整段序列可命中路径**任意
|
|
1077
1093
|
位置**(`.ssh` 同时盖住 `~/.ssh/…` 和别处的 `.ssh`);默认 ASCII 大小写**不敏感**,单条 `caseSensitive:true`
|
|
1078
1094
|
退出。这些条目**叠在** core 内建 deny 集之上(内建先、追加后,重复折叠),不是替换。
|
|
1095
|
+
⚠️ **7.132.0(引擎 7.52.0)起 shell 递归读(`grep -r` 一类)只按命令点名的根判这张表**:既不以 `/` 起(根锚,如 `<工作区根>/secrets/**`)、也不以 `~` 起(家锚,如 `~/secrets/**`)的
|
|
1096
|
+
拼写行(`**/secrets/**`、`.ssh`、`id_rsa*`),护不住根下面被父目录递归读到的文件(点名那个目录 / 文件本身照拒)。要护住就把行写成根锚或家锚(MIGRATION 7.132.0 第 45 条);
|
|
1097
|
+
起服(server 与 `run-local`)与中心热发会为这类行打**一行** warn `read_deny_unanchored_rows`(点名行与改法;运维的 `READ_DENY_PATTERNS` 与中心 read-face 的行同判,一份值第一次装进 Runner 席时点名一次;只告知,不改放行 / 拒绝、不拒启)。
|
|
1079
1098
|
- **坏形拒启,不静默折默认**:坏 JSON / 非数组 / 缺 `pattern` / 编不过 core 的 `compileReadDeny`
|
|
1080
1099
|
一律启动期点名拒——一个手滑的 deny 集比没有 deny 集更糟(以为挡了其实没挡)。
|
|
1081
1100
|
- **缺席的语义按 posture 分两形(7.65.0 起)**:
|
|
@@ -1095,6 +1114,9 @@ READ_DENY_PATTERNS='[{"pattern":"**/secrets/**"},{"pattern":".ssh","caseSensitiv
|
|
|
1095
1114
|
(每种模式都拒、不出卡)。agent-config 的十五行改写成 `~/…`(`~/.claude/settings.json`、`~/.sema/settings.json` …)、只在执行环境的 home 正下方
|
|
1096
1115
|
命中 —— 工作区里的 `.claude/settings.json` 不再是内建行;🔴 `READ_DENY_BUILTIN_EXCLUDE` 里写旧行名(`.claude/settings.json`)的部署**起服拒**
|
|
1097
1116
|
(core 的拒句点名新行名),改写成 `~/.claude/settings.json`。
|
|
1117
|
+
🔴 **7.132.0(引擎 7.52.0)**:`credentials` 档的 `.npmrc` / `.pypirc` 两行同样改成家锚(`~/.npmrc` / `~/.pypirc`)—— 家目录那一对照旧拒,项目里自带的同名文件
|
|
1118
|
+
读得到(执行环境没声明家目录时仍拒);`READ_DENY_BUILTIN_EXCLUDE` 里写 `.npmrc` / `.pypirc` 的部署**起服拒**(拒句点名新行名):删掉这两个值(家目录那一对仍护着),
|
|
1119
|
+
确要读家目录那一只就改写成 `~/…`;要项目里那一对照旧拒,把 `.npmrc` / `.pypirc` 加进 `READ_DENY_PATTERNS`。
|
|
1098
1120
|
· 🔴 **命中这三张表的结局自 core 7.25.0 起是「拒」,不是「问」**(三只旋钮的名字 / 语义 / 缺席读法一字
|
|
1099
1121
|
未变,变的是结局词):一条命中拒表的读在**每张脸每个时刻**都被拒 —— 不出审批卡、持久 allow 规则
|
|
1100
1122
|
清不掉、值守的人点「同意」也放不掉。拒因在 `tool_end` 上:`errorCode` 与 `structured` 都是
|
|
@@ -1209,10 +1231,11 @@ TASK_WRITE_FACE_ESCALATION=allow # 词表 allow|refuse;坏词启动期响亮
|
|
|
1209
1231
|
|
|
1210
1232
|
1. **出厂技能 = `SKILLS_DIR` 这一个目录**(缺席 = 包内自带的 `skills/`,按模块位置解析,不是进程 cwd)。目录里每个 `<名>.md`(frontmatter `name` / `description` / `scenarios`)
|
|
1211
1233
|
或 `<名>/SKILL.md`(同目录的其余文件作附件)是一条。**设了 `SKILLS_DIR` 就整个替换包内出厂技能,不叠加** —— 想在出厂集上加几条,把包内 `skills/` 拷过去再加;
|
|
1212
|
-
目录不存在 = 零出厂技能(不报错)
|
|
1234
|
+
目录不存在 = 零出厂技能(不报错)。**frontmatter 读不了的技能不装**:文件第一行是围栏 `---`(行尾只许空白 / 制表)而块没有收尾 ⇒ 这一条被拒载(一行 warn `skill_refused`,点名技能与文件,`reason: frontmatter_unclosed`),
|
|
1235
|
+
不会降成每个场景都有的全局技能;第一行不是围栏的文件没有 frontmatter,仍是全局技能。兄弟技能照装。
|
|
1213
1236
|
2. **配置源的技能**:配了中心 = web-admin 的 skills 域;`CONFIG_PROVIDER=local` = `config.d/skills.json`(`{ "skills": [{ "name", "description", "content", "scenarios"?, "enabled"? }] }`,
|
|
1214
1237
|
正文写在 `content` 里)。**按名盖在出厂技能上**(同名 ⇒ 配置源这条赢),`enabled: false` 的不装;两种配置源同一条路径(7.128.0 起;此前本地形整域不生效)。
|
|
1215
|
-
起服每装上一条一行 `web_admin_skill`(`overrodeBuiltin` 说盖没盖出厂的);拿不到正文的一条一行 `web_admin_skill_failed`(`reason`:`body_absent` / `read_failed`),
|
|
1238
|
+
起服每装上一条一行 `web_admin_skill`(`overrodeBuiltin` 说盖没盖出厂的);拿不到正文的一条一行 `web_admin_skill_failed`(`reason`:`body_absent` / `read_failed`;**正文为空串视同缺席**:`content` 缺省或写成 `""` 的条目,本地与中心同判 `body_absent`),
|
|
1216
1239
|
这一条不装、同名出厂技能保留、起服照常。重启生效(与 MCP 同:改了之后 `/health` 的 `restart.reasons` 含 `skills`)。
|
|
1217
1240
|
3. **插件带的技能**(plugins 域):只补**没被占的名字**,撞名让位(起服行 `center_plugins_applied` 的 `letGo`)。
|
|
1218
1241
|
4. **请求体自带的技能**(`skills[]`):只补这一 run **没被占的名字** —— 与部署的技能同名的那条被丢(一行 `user_skills_dropped`),不覆盖;
|
|
@@ -1238,7 +1261,20 @@ TASK_WRITE_FACE_ESCALATION=allow # 词表 allow|refuse;坏词启动期响亮
|
|
|
1238
1261
|
的窗内(窗口见 `src/plugins/one-time-migrations.ts` 登记表)按升级前的读法重读一次(非对象含 `null` ⇒ 没声明;对象里过不了形的成员剔、好的留),产物仍过同一只判官 ⇒ server 照挂、
|
|
1239
1262
|
一行运维 warn `mcp_tool_axes_read_as_before_upgrade`(`server` / `migration` / `problem` / `note`);重读的产物仍判不过、或窗已关 ⇒ 这一条 server 整条不进,
|
|
1240
1263
|
运维 warn `mcp_injection_dropped`(`malformed_entry` / `field: toolAxes`)+ 用户面通告 `mcp.injection_dropped`(续跑家族同投);`POST /v1/capabilities/mcp/probe` 同拒同句,
|
|
1241
|
-
判官受理的声明与提交腿同读(只有空条目的工具 = 没声明,受理)
|
|
1264
|
+
判官受理的声明与提交腿同读(只有空条目的工具 = 没声明,受理)。
|
|
1265
|
+
- **请求体自带的 `a2aPeers[].toolAxes`**(键 = 对端的远端 skill id)读同一只判官(引擎根导出的 `readToolAxes`,A2A 一面;形同上):读不出 —— 出词表、`egress` 非布尔、
|
|
1266
|
+
**未知成员**、某只 skill 的值不是对象、`__proto__` 键、不是纯数据 —— ⇒ 那一条对端整条不挂、点名进运维 warn `a2a_injection_dropped`,任务照跑(与这条腿上其余字段坏形同一处置)。
|
|
1267
|
+
此前本服务对 A2A 一面用自己的读法、未知成员静默忽略;引擎的准备门对同一份声明本就整单拒,两层现在是同一只判官、同一个方向。
|
|
1268
|
+
续跑重放升级前存下的请求体时与 `mcpServers[].toolAxes` 同一只一次性迁移 M19:窗内判官判不过的那一格按 7.131.x 的 A2A 读法重读一次(未知成员剔、三轴留,产物再过同一只判官),
|
|
1269
|
+
对端照挂、一行运维 warn `a2a_tool_axes_read_as_before_upgrade`(`peer` / `migration` / `problem` / `note`);已知轴写坏(出词表、`egress` 非布尔、某只 skill 的值不是对象、
|
|
1270
|
+
整份不是对象)的对端 7.131.x 当时就整条丢了,重读照旧整条不挂(`a2a_injection_dropped` 点名);窗关之后回到上面的读法(整条不挂)。
|
|
1271
|
+
- **请求体自带的 `mcpServers[].transport.env` / `transport.headers`**(「名 → 串」记录,与 `a2aPeers[].headers` 同一只读法):名叫 `__proto__` 的成员、值不是串的成员、
|
|
1272
|
+
整只不是纯数据 ⇒ 新提交 `400 request.field_invalid` 点名第一处(`__proto__` 成员点名成员级路径 `…headers.__proto__`;值不是串 / 整只读不成点名那个键,原因句点名成员)。
|
|
1273
|
+
续跑重放存量请求体(JSON 文本铸出来的记录)时复现 7.131.x 的读法,唯一偏离是引擎拒的 `__proto__` 成员:记录里有值不是串的成员 ⇒ 整键不交(7.131.x 原跑就是这样挂的,不半程换身份);
|
|
1274
|
+
等价只对 JSON 存体成立 —— 直接递 `Map`、类实例、`process.env` 的嵌入方按上面的更严读法(7.131.x 对带自有串属性的类实例照收);
|
|
1275
|
+
只有 `__proto__` 名的成员坏 ⇒ 剔掉它、其余照交。server 照挂,运维 warn `mcp_transport_members_dropped`(`server` / `lost` / `lostTotal?` / `note`)点名没交出去的键 / 成员与整键没交的
|
|
1276
|
+
`transport.args` / `transport.principalHeader`。A2A 对端 `headers` 同读:值不是串 ⇒ 对端照旧不挂;只有 `__proto__` 成员坏 ⇒ 续跑照挂、剔掉它,一行 `a2a_peer_headers_members_dropped`
|
|
1277
|
+
(`peer` / `lost` / `note`);新提交上两形都整条不挂。
|
|
1242
1278
|
|
|
1243
1279
|
**可选 — MCP 入站表单(elicitation,E23):默认关**
|
|
1244
1280
|
|
|
@@ -1252,6 +1288,8 @@ MCP_ELICITATION_TTL_MS=300000 # 一张没人填的表单挂多久后释放(
|
|
|
1252
1288
|
- 四个节流钮都是 `numEnvBounded`:**越界启动期响亮拒,不静默夹取**(一个手滑的多小时 TTL 会让表单实际上永不过期)。
|
|
1253
1289
|
- 总开关关着时四个节流钮解析照跑但无消费者——不设=行为不变。帧格式见
|
|
1254
1290
|
[`docs/ASSISTANT-WIRE-CONTRACT.md` §4a-quater](docs/ASSISTANT-WIRE-CONTRACT.md)(`elicitation` / `elicitation_complete`)。
|
|
1291
|
+
- 两帧同样**随 run 账本回放**(与上面的问题卡同一条规则:`/v1/tasks/stream` 腿有 durable run 行时先落账再直写,`/v1/runs` 腿只有账本),重载后经 `GET /v1/runs/:id/events` 取回表单卡;
|
|
1292
|
+
`elicitation` 开帧带 `expiresInMs` / `expiresAtMs`,待答判法与问题卡同一把。**答题口不变**:`POST /v1/elicitations/:id/respond` 只在受理那一张表单的副本内、窗内有效。
|
|
1255
1293
|
|
|
1256
1294
|
**可选 — 把这台 worker 挂进别人的 A2A 拓扑(server-as-peer,DESIGN-269 车2):默认关**
|
|
1257
1295
|
|
|
@@ -1466,12 +1504,20 @@ invalid_using_default` 警告 + 退回缺省值」这条臂随词表放宽一并
|
|
|
1466
1504
|
|
|
1467
1505
|
| 键 | 缺省 | 写法 | 行为 |
|
|
1468
1506
|
|---|---|---|---|
|
|
1469
|
-
| `LSP_ENV_ALLOW` | 未设 = 空名单 = 全剥(7.100.0 行为) | 逗号分隔的**裸变量名**,如 `LSP_ENV_ALLOW=NPM_TOKEN,CARGO_REGISTRIES_MY_REG_TOKEN` | 点到的键从服务进程环境**原样**交给语言服务器(密钥形也照交 —— 点名即你显式承担把这个值交给仓里代码的后果);没点到的照旧剥,`SERVICE_AUTH_TOKENS` 这类不会因为别的键被放行而跟着进去。空串 = 未设。**形错拒启**:空段(`A,,B`、尾逗号)、非变量名形(`1BAD`、带空格、`NAME=value` 整段贴进来)⇒ 起服失败,拒句点名键与第几段,**不回显原值**。形对但本进程环境里**没有**这个名的段 ⇒ 不放行,起服一行 `config_env_entry_rejected` 只报第几段(常见成因是 `LSP_ENV_ALLOW=$NPM_TOKEN` 这种把**值**展开进来的手滑 —— `npm_` 令牌恰好是合法变量名形,所以名单原文在任何日志 / 配置目录回显里都不出现)。旋钮**原文**按凭据类对待:配置目录只回在场位,`LSP_ENV_ALLOW` 这个键本身不进语言服务器 / host shell / git 子进程(点名它自己,或点名两只沙箱名单 `E2B_SANDBOX_ENV` / `DOCKER_SANDBOX_ENV` ⇒ 拒启)
|
|
1507
|
+
| `LSP_ENV_ALLOW` | 未设 = 空名单 = 全剥(7.100.0 行为) | 逗号分隔的**裸变量名**,如 `LSP_ENV_ALLOW=NPM_TOKEN,CARGO_REGISTRIES_MY_REG_TOKEN` | 点到的键从服务进程环境**原样**交给语言服务器(密钥形也照交 —— 点名即你显式承担把这个值交给仓里代码的后果);没点到的照旧剥,`SERVICE_AUTH_TOKENS` 这类不会因为别的键被放行而跟着进去。空串 = 未设。**形错拒启**:空段(`A,,B`、尾逗号)、非变量名形(`1BAD`、带空格、`NAME=value` 整段贴进来)⇒ 起服失败,拒句点名键与第几段,**不回显原值**。形对但本进程环境里**没有**这个名的段 ⇒ 不放行,起服一行 `config_env_entry_rejected` 只报第几段(常见成因是 `LSP_ENV_ALLOW=$NPM_TOKEN` 这种把**值**展开进来的手滑 —— `npm_` 令牌恰好是合法变量名形,所以名单原文在任何日志 / 配置目录回显里都不出现)。旋钮**原文**按凭据类对待:配置目录只回在场位,`LSP_ENV_ALLOW` 这个键本身不进语言服务器 / host shell / git 子进程(点名它自己,或点名两只沙箱名单 `E2B_SANDBOX_ENV` / `DOCKER_SANDBOX_ENV` ⇒ 拒启)。**点名本服务自己的凭据名**(配置目录里的 secret 型变量,如 `SERVICE_AUTH_TOKEN` / `APPROVAL_HMAC_KEYS` / `MODEL_API_KEY`)⇒ 拒启(7.132.0 起):放回在剥除之上,点到它就把刚扣下的本服务凭据交回语言服务器;拒句带引擎拒白名单的同一句。放回本身经引擎:点到的变量值若是本服务凭据的副本(换了个名),同样扣下。语言服务器要凭据 ⇒ 给它一枚自己的(值与本服务的任何凭据都不同)。生效名单看起服那行的 `allowed`。`REQUIRE_PRINCIPAL=true`(多租户 / 托管)⇒ 忽略名单、仍全剥,起服一行 `config_env_set_but_ineffective`(host 腿语言服务器在这一姿态下本来就不起)。只作用于 host 腿;沙箱腿的语言服务器跑在沙箱里,环境由沙箱车道自己的旋钮决定 |
|
|
1470
1508
|
|
|
1471
1509
|
**「剥了什么」这一行**:起服(host 腿语言服务器管理器构造时)一行 `warn` `secret_env_scrubbed`,`site:"server.lsp.spawn-env"`,
|
|
1472
1510
|
字段 `keys`(这次剥掉的键名)· `allowed`(当前放行名单)· `hint`(出路句,点名 `LSP_ENV_ALLOW=NAME,NAME`)· `summary`;**值永不进日志**。
|
|
1473
1511
|
放回的键不算剥除(不在 `keys` 里、不进计数 `secret_env_scrubbed_total`);同一个键每进程只报一次;没有剥除 ⇒ 不发。
|
|
1474
|
-
|
|
1512
|
+
其余剥除现场(模型可驱动的 host shell `server.remote-env-host.spawn-env`、三条 git 腿、local-docker / adb 两条 CLI 腿、settings hooks 的命令腿)没有部署级放行旋钮,它们的同名行照旧是 `info`、不带 `allowed` / `hint`。
|
|
1513
|
+
现场按**腿**命名(`server.<模块>.<腿>`),不按继承词:7.131.x 及以前 host shell 那条腿叫 `server.remote-env-host.inherit-scrub`,7.132.0 起改名(计数器 `secret_env_scrubbed_total{site}` 与日志字段 `site` 同改,无别名)。
|
|
1514
|
+
|
|
1515
|
+
**每一条宿主子进程腿的 env 都经同一只组合(7.132.0 起射程写全)**:本服务在宿主上起的每一只子进程,env 都由引擎按这条腿的继承词组合,本服务自己的凭据(起服声明的名与值)任何词都不交。
|
|
1516
|
+
腿的继承词按「子进程里跑的是谁选的代码」定:模型命令(host shell:交任务自己的词,缺省形状剥)、仓里的钩子与凭据助手(project-memory / center-plugins / leader 三条 git 腿)、
|
|
1517
|
+
执行仓代码的语言服务器、bake-runner 的配方脚本 ⇒ 形状剥(语言服务器与 bake-runner 另有点名放回);请求带来的 settings hooks 命令 ⇒ 严格名单(`PATH` / `HOME` / `SHELL` /
|
|
1518
|
+
`USER` / `LOGNAME` / `TERM` / `TZ` / `LANG` / `LC_ALL` / `LC_CTYPE` / `LC_MESSAGES` / `TMPDIR`,外加请求自己的 `settings.env`);local-docker 车道的 `docker` CLI 与 adb 车道的 `adb` CLI
|
|
1519
|
+
(部署方装在宿主上的二进制,命令本身跑在容器 / 设备里)⇒ 整份环境**减**本服务凭据 —— CLI 与它拉起的凭据助手 / CLI 插件 / 常驻 adb server 要读的 `DOCKER_*` / `AWS_*` /
|
|
1520
|
+
`ADB_VENDOR_KEYS` 照交(形状剥会剥后两类)。7.131.x 及以前这两条 CLI 腿原样继承整份环境(本服务凭据在内)。
|
|
1475
1521
|
|
|
1476
1522
|
**🔴 模型可驱动的 host shell 没有点名放回旋钮(刻意,7.104.0 写明)**:凭据形变量不交给模型能驱动的 shell —— 这条腿恒走缺省剥除
|
|
1477
1523
|
(本服务不给它传点名名单),部署配置里没有任何键能改它的继承模式;`inheritEnv:[names]` 是**嵌入方**用本包构造执行环境时的选项
|
|
@@ -1496,8 +1542,8 @@ invalid_using_default` 警告 + 退回缺省值」这条臂随词表放宽一并
|
|
|
1496
1542
|
`CONTEXT_TOKENS`)与两个开关(`DB_FOREIGN_KEYS` `JSON_SORT_KEYS`)不再被剥,三条子进程腿同时生效(7.100.0 上这五个 7.30.1 误剥的名
|
|
1497
1543
|
`MAX_NEW_TOKENS` / `MAX_COMPLETION_TOKENS` / `MAX_BATCH_PREFILL_TOKENS` / `DB_FOREIGN_KEYS` / `JSON_SORT_KEYS` 需要点名放行,现在不用)。
|
|
1498
1544
|
**精确名,不是形**:`USERS_MAX_NEW_TOKENS`、`MAX_NEW_TOKENS_2` 这类装饰过的变体照剥。引擎自己的「剥了什么」通告码
|
|
1499
|
-
`config.secret_env_scrubbed`
|
|
1500
|
-
bake-runner)
|
|
1545
|
+
`config.secret_env_scrubbed` 只在引擎**自己**剥的子进程上发;本服务九条宿主腿(host shell / project-memory / center-plugins / leader 三条 git 腿 / 语言服务器 /
|
|
1546
|
+
bake-runner / local-docker 与 adb 两条 CLI 腿 / settings hooks 命令腿)都交本服务组合好的环境,所以运维面看的是上面这行
|
|
1501
1547
|
`secret_env_scrubbed`,不是那只通告码。这只通告码**每进程一次**、引擎里几处剥除共用一闩(工具 shell / 语言服务器 / 7.103.2 起还有 `runSpec` 的
|
|
1502
1548
|
oracle 门子进程,core 7.33.8):oracle 门若先于工具 shell 剥,通告只进 oracle 门那一处(`RunSpecOptions.onNotice`,没接就进 console),接在执行环境上的
|
|
1503
1549
|
结构化通告收不到。本服务不调 `runSpec`,不受影响;嵌入引擎、自接 `runSpec` 的宿主给它交同一只 `onNotice`。
|
|
@@ -1550,9 +1596,13 @@ bake-runner 要用 ⇒ `LSP_ENV_ALLOW` / `BAKE_ENV_ALLOW` 点名放回。
|
|
|
1550
1596
|
| `Authorization: Bearer <SERVICE_AUTH_TOKEN>` | 设了 `SERVICE_AUTH_TOKEN` 时,除 `/health` / `/readyz` 外的所有请求 | **谁有权调本服务**(OA 后端持有,服务到服务) |
|
|
1551
1597
|
| `x-agent-principal: user:42` | 设了 `REQUIRE_PRINCIPAL=true` 时 | **代表哪个终端用户**(决定 session 归属 + 记忆隔离;**绝不从 body 取**) |
|
|
1552
1598
|
|
|
1553
|
-
> **dev-open 部署的主体头是过滤 / 展示用,不是隔离。** 没配 `SERVICE_AUTH_TOKEN(S)
|
|
1554
|
-
>
|
|
1555
|
-
>
|
|
1599
|
+
> **dev-open 部署的主体头是过滤 / 展示用,不是隔离。** 没接任何身份来源(没配 `SERVICE_AUTH_TOKEN(S)`、没装中心鉴权桥、没开直连门 —— 即 `/health.auth.kinds` 为空)、
|
|
1600
|
+
> 也没配 `TRACE_TOKEN`、没开 `REQUIRE_PRINCIPAL` 的部署上,`x-agent-principal` 谁都能自报:
|
|
1601
|
+
> 会话列表与单会话的读写口(视图 / head / 事件流 / 改名置顶 / 记忆状态与抹除 / 后台任务 / MCP 重连 / fork / delete)都不按它钉人,带谁的头都读得到同一批会话;`/metrics` 族不要凭据(没配 `METRICS_TOKEN` 时)。
|
|
1602
|
+
> 它仍决定新会话记在谁名下、记忆按谁的 scope 走;规则口(`…/policy`)与 `…/notify` 用它选落哪一把属主键。要按用户隔离,给部署设上面几者之一(典型:service token + 写主体头的网关)。
|
|
1603
|
+
> **装了中心鉴权桥(`SEMA_WEB_ADMIN_URL` 在位即默认开,或 `AUTH_BRIDGE_ISSUER`)就不是 dev-open**(7.132.0 起;此前这一形被读成 dev-open):带登录令牌的调用方按令牌里的身份钉人,
|
|
1604
|
+
> 不带任何凭据的列表 `401 auth.unauthorized`、`/metrics` 族 `401`(要 `METRICS_TOKEN`)。仍成立的边界:没配 service token 的部署上,不带登录令牌的请求自报的主体头仍按身份读
|
|
1605
|
+
> (与 `REQUIRE_PRINCIPAL` 无 token 形同读)—— 要让「没令牌就没有身份」成立,配 `SERVICE_AUTH_TOKEN`(全局凭据门:每个请求要么带 service token、要么带登录令牌)。
|
|
1556
1606
|
|
|
1557
1607
|
| env 键 | 缺省 | 说明 |
|
|
1558
1608
|
|---|---|---|
|
|
@@ -1567,16 +1617,32 @@ bake-runner 要用 ⇒ `LSP_ENV_ALLOW` / `BAKE_ENV_ALLOW` 点名放回。
|
|
|
1567
1617
|
> 调用方身份,**不**叫你再去带 service token。逐字句子见 `docs/ASSISTANT-WIRE-CONTRACT.md` 附录 A.1 码表。壳(sema CLI)接 sema-up 引擎的
|
|
1568
1618
|
> 令牌交法见 `deploy/sema-up/README.md`「壳接入」。
|
|
1569
1619
|
|
|
1620
|
+
**整只请求体的上限**:8 MiB;**TiDB 部署更矮** —— 一份提交体要整只落进库的一行,上限 = 库的单行上限(TiDB `txn-entry-size-limit`,缺省 6 MiB)− 64 KiB,
|
|
1621
|
+
缺省约 5.94 MiB(6 225 920 字节,按体的 JSON 字节判)。超了 ⇒ `413 request.payload_too_large`,句子点名本部署的上限。服务连上库时从库读这个数(读数在
|
|
1622
|
+
`GET /v1/diagnostics/wiring` 的 `sqlEngine.maxRowBytes`);要收更大的体,运维抬 TiDB 的 `performance.txn-entry-size-limit`(或 TiDB 7.6+ 的 `tidb_txn_entry_size_limit`),
|
|
1623
|
+
并让库账号读得到它(`CONFIG` 权限,或设那只会话变量;读不到时按 TiDB 缺省判)。同时并入库的**语句**上限(`max_allowed_packet`,InnoDB 与 TiDB 都有;读数在 `sqlEngine.maxPacketBytes`)。两堵墙各量各的、量店真正发出去的东西:行墙腿量体的 JSON 字节 ≤ 单行上限 − 64 KiB(行里存原字节);
|
|
1624
|
+
包墙腿量**转义后的语句字节** ≤ 包墙 − 1 KiB(体经驱动以字符串字面进语句,`"` `'` `\` 与控制字符各多一个字节,引号 / 反斜杠密集的 JSON 比自己的字节数长,至多 2×),`null` 的墙不参与,句子点名真正拒绝的那一堵。
|
|
1625
|
+
PostgreSQL 只有 8 MiB 这一道;InnoDB 没有单行墙,缺省 16 MiB(MariaDB)包墙下引号密集的大体会在 8 MiB 之内就被包墙拒,缺省 64 MiB(MySQL 8)之下仍只有 8 MiB 这一道。
|
|
1626
|
+
连接池最近一次连接初始化被库拒(读不出库的事实;到下一条连接初始化成功为止,通常秒级)时,MySQL 协议部署按最保守的**假定**墙判(行墙 6 291 456 = TiDB 缺省、包墙 16 MiB,与 SQL 快照 blob 的缺省帽同一个读法),
|
|
1627
|
+
PostgreSQL 仍只有 8 MiB。这一窗的 413 句子说是假定(`the database's … limit was not read (engine facts not read yet, or the limit could not be read); refusing conservatively at … — retry shortly; if it persists, …`),不点名库的上限与旋钮;两形体上都带 `wallSource`,
|
|
1628
|
+
只看拒它的那堵墙的数字是不是库自己报的:`"reported"` = 库报的墙,缩小或请运维抬;`"assumed"` = 不是库报的 —— 事实没建立的窗口里稍后重试按库报的墙重判(InnoDB / MariaDB 上多半就过,TiDB 上同一份体多半仍超);
|
|
1629
|
+
事实在场、但这一堵墙读失败退了文档缺省(TiDB < 7.6 又无 `CONFIG` 权限读不到单行上限;`max_allowed_packet` 读不出)的不会自己变真,请运维让库账号读得到那个上限(`GET /v1/diagnostics/wiring` 的 `sqlEngine.wallSources` 逐堵说出处)。
|
|
1630
|
+
`PUT /v1/sessions/:id/sync/blobs/:hash` 超 SQL 快照 blob 帽的 `413 blob_too_large_for_sql` 同样带 `wallSource`,词多一个 `"operator"`(帽是你设的 `SNAPSHOT_BLOB_SQL_MAX_BYTES`),句子按三形分:旋钮 / 库报的墙 / 没读到的假定墙。
|
|
1631
|
+
受理口放行、写续跑输入那一笔被库以「一行装不下」拒时(开了 durable 审批的部署)答同一个 413,出路按拒它的那堵墙给(TiDB 单行墙 ⇒ 抬 `txn-entry-size-limit`;语句墙 ⇒ 抬 `max_allowed_packet`;
|
|
1632
|
+
PostgreSQL 硬上限 ⇒ 只有缩小),运维日志一行 `submit_ctx_row_too_large`(`wall` 点名那堵墙);刚认领的 run 当场撤掉,撤认领的库写自己也失败时一行 `submit_ctx_run_release_failed`(带步名)
|
|
1633
|
+
并计 `submit_ctx_run_release_failed_total{step}`,会话到 `REAP_RUN_STALE_SEC` 才放。
|
|
1634
|
+
|
|
1570
1635
|
**请求体字段(常用;受理**闭集**以 `docs/ASSISTANT-WIRE-CONTRACT.md` §1 为准 —— 本表不再重抄一份):**
|
|
1571
1636
|
| 字段 | 必填 | 说明 |
|
|
1572
1637
|
|---|---|---|
|
|
1573
1638
|
| `objective` | ✅ | 要做什么(自然语言)。**唯一必填。** |
|
|
1574
1639
|
| `sessionId` | — | 续聊:带上次返回的 `sessionId`,服务端自动 wake 历史。**只收 canonical uuid**(任意版本,小写;与会话口同一只形判):自选名 / 业务键 / 空串 ⇒ `400 request.id_invalid`,缺省请**省略这个键**(服务端现铸 uuid)。想要好记的名字,自己记 name → uuid 的映射 |
|
|
1575
|
-
| `images` | — | 图文输入 `[{data,mimeType}|{url}]`(模型需支持 vision) |
|
|
1640
|
+
| `images` | — | 图文输入 `[{data,mimeType}|{url}]`(模型需支持 vision)。**随提交的这条目标一次送达**:续跑 / 投递腿(审批 / 资源停车 / wake / plan_review 续跑、在宿主会话上新起的一跑)重建配置时不再带它(与 `userAttachments` 同律;图在首跑已是会话里的消息) |
|
|
1576
1641
|
| `attachmentIds` | — | D-1 通用文件上传(1.289+):先 `POST /v1/attachments?name=…`(raw body,content-type=mime)拿句柄,提交时引用 ≤16 个;文件物化到执行环境工作目录 `attachments/` 下,objective 尾部自动追加文件清单(内容不进会话流)。单文件缺省 ≤32 MiB(`ATTACHMENT_MAX_BYTES`);可配 mime 白名单(`ATTACHMENT_MIME_ALLOWLIST` CSV,缺省不限);上传后未引用的按 `ATTACHMENT_UNBOUND_TTL_MS`(缺省 24h)回收。**云形态(tidb/pg)字节本体存对象存储——MinIO 必配**(`MINIO_ENDPOINT/MINIO_ACCESS_KEY/MINIO_SECRET_KEY`,与快照 lane 同一组变量),未配则附件面 501;local 形走本地文件店。 |
|
|
1642
|
+
| `userAttachments` | — | 请求层附件(≤20 条),原样交给引擎、随**这条目标**送到模型:`{ path, lines? }` 读这次 run 的工作区 / `{ name, text, startLine? }` 宿主给的文本 / `{ name, image: { data, mimeType } }` 宿主给的图片(base64)。形判属主是引擎:坏形、带行号超 Read 上限(100 000 字符)的 text、过不了准入的图 ⇒ `400 config.user_attachment_invalid`(`error` 以字段路径起);`path` 只在有手场景(这次 run 有工作区)受理 —— 无手场景(`scan` / `code-review`、无手叠层、`provider: "in-process"` 的部署)上整条 `path` 条目同码 400,改发 text / image 条目;能力位 `supplies` 是席位能承载的供给,不按场景裁;读不到的文件不拒,它的消息里说明没附上,结局见流上目标那一帧 `human_input.attachments`。只随目标走:steer / interrupt 带它 400,续跑不重发。带附件的提交在第一次回复出来之前被切断(halt / interrupt)时,这次 run 不落回退锚 —— 拿它的 taskId 去 `resumeAt` ⇒ `404 resume_at.unknown_event`,请显式给 resumeAt。与 `attachmentIds` 分工:那条把文件放进工作区让模型按需去读(内容不进上下文),这条把内容直接送进上下文。能力位 `userAttachments` |
|
|
1577
1643
|
| `scenario` | — | 省略时取本部署的 `DEFAULT_SCENARIO`(工厂缺省场景名 = **`code`**——CC 编码 persona 蒸馏版,default 全量工具面,终验旋钮独立;`default` 场景**已非出厂缺省**,要用它须显式传 `scenario:"default"`,或部署方显式设 `DEFAULT_SCENARIO=default`)。可选内建名:`default`(通用/助理场景,域中性 persona,CC agent loop 全量工具面)/ `code-review`(见 §5)/ `scan`(同 §5 的 repo 只读工具但**中性无框架提示词**——objective+中心下发 skill 全权主导输出,OA 扫描类用;与 `code-review` 同属 clone-free 无执行环境场景,见 §5 末)/ **配置控制面可声明任意新场景**(`{name, toolset: none\|repo-readonly, prompt?}`,组合即配置、能力写死在部署;restart-to-apply;center 可覆盖内建名,boot 日志 `config_center_scenarios.shadowsBuiltin` 可审计)。**缺省与指派都必须是本部署在册的场景名,悬空不回落 `default`**:`DEFAULT_SCENARIO` 不在册 ⇒ **起服拒**(拒句点名那个名字与在册词表);中心按主体指派的场景名本部署没有 ⇒ 该主体的 run 答 **503 `state.scenario_assignment_unknown`**(体 `detail: { scenario, source: "ruling" }`,不带 `Retry-After`;修法 = 中心改指派,或把那个场景加回本部署,然后原样重试);请求体显式给的未知名仍是 400 `scenario_unknown` |
|
|
1578
1644
|
| `repo` | — | `code-review`/`scan` 必填,见 §5(7.126.0 起 `council` / `debate` / `lenses` / `rounds` / `team` / `businessContext` 是未知键 ⇒ 400:它们喂的评审团腿与 `discuss` 场景随引擎 7.49.0 删掉团队运行时一并删除) |
|
|
1579
|
-
| `systemPrompt` / `appendSystemPrompt` | — | 调用方自带的系统提示 / 追加段(各 ≤16384 字符,超限 400 `request.field_invalid`;`appendSystemPrompt` 必须非空串)—— 任务自带时优先于角色 / 全局缺省(见 §模型角色) |
|
|
1645
|
+
| `systemPrompt` / `appendSystemPrompt` | — | 调用方自带的系统提示 / 追加段(各 ≤16384 字符,超限 400 `request.field_invalid`;`appendSystemPrompt` 必须非空串)—— 任务自带时优先于角色 / 全局缺省(见 §模型角色)。`systemPrompt` 是**角色层**:它整替所选角色的基底(`code-review` 场景把自己的评审员文本放在它前面),宪法、行为段、记忆段由引擎组在它之后;追加段恒排在宪法之后。逐字含引擎提示段的提示(一份已组装的提示)⇒ 400 `prompt.assembled_role_refused`(7.132.0 起) |
|
|
1580
1646
|
| `outputStyle` / `settings.outputStyle` | — | 输出风格**两个座位、两件事**:风格的**正文**(指南全文)走 `settings.outputStyle`(折进系统提示的追加段);**每轮一句**走顶层 `outputStyle: { name, turnReminder? }`(7.121.0+,能力位 `outputStyle`)—— 原样交引擎,引擎每个回合用自己的标记帧说「`<name> output style is active. <turnReminder>`」(`turnReminder` 缺席用引擎缺省句),流上回声 `steering_injected` `source:"output_style"`。只在非缺省风格时声明顶层键;它的值形由引擎判(`name` 非空、≤256 字;`turnReminder` 在场即非空串;不许别的键),坏值这一轮终态 `failed`、码 `config.output_style_invalid` |
|
|
1581
1647
|
| `model` | — | 本次用哪个模型:只能点服务端**已配置目录**里的名字 / 档位词 / 模型 id(目录见 `GET /v1/models`;请求体带不进新模型)。未知 ⇒ 400 `request.unknown_reference`(带 `available` 列表);目录里有、但本部署服务不了 ⇒ 400 `request.model_unavailable`;空串 / 非字符串 ⇒ 400 `request.field_invalid` |
|
|
1582
1648
|
| ~~tools~~ | 🚫 | **不是受理键**(传了 ⇒ 400 `request.body_shape`,`unknownKeys` 点名)——工具面走场景装配;按请求只能**减**:`allowTools`(7.126.0 起;引擎的可用性选择器,只留列出的,原样透传)/ `excludeTools` / `settings.permissions` 的 deny · ask(`allow` 7.115.0 起是 allow 规则:给出「有人表态」,回答没人表态的服务器工具 / A2A 调用;不加工具、不放掉任何一层自己的问) |
|
|
@@ -1720,7 +1786,7 @@ curl -N http://<host>:8090/v1/tasks/stream -H 'content-type: application/json' \
|
|
|
1720
1786
|
| `POST /v1/approvals/<sessionId>/decide` `{"decision":"approve"|"deny","reason":"…"}` | 批/否并恢复挂起任务(CAS,重复决议 409);**仅 operator**(非 operator → 403)。5.0.0 起旧轮询腿 `POST /v1/approvals/<id>` 已退役 |
|
|
1721
1787
|
| `GET /v1/agents/roster` | 后台 agent **名册**(7.29 起,需 durable background-agent store,否则 501 `capability.background_agent_store_required`):调用方自己 scope 的 `a…` 行,新→旧。行只带 `handle`/`name`/`agentType`/`status`/`spawnedAt`/`updatedAt`/`settledAt`(content-free;子代产物正文走 `GET /v1/runs/<id>/subagents/<handle>/output`)。查询:`?limit=`(1..100,默认 20)、`?before=`(上一页的 `nextBefore` 游标)、`?status=`(running\|parked\|completed\|failed\|killed)、`?session=`(按会话树窄化)、`?scope=`(**仅** service-token/单用户形;带 principal 的调用方锁定自己)。回体 `{agents,total,nextBefore?,truncated?}`;`truncated:true` = 租户行数超过名册窗(500),`total` 此时是窗内数。非属主的行**不出现也不计数**(无存在性 oracle) |
|
|
1722
1788
|
| `GET /v1/capabilities/scenarios/<name>` | 单个场景的只读详情:工具面、提示词概览、**本部署现在跑不跑得动**(见下) |
|
|
1723
|
-
| `GET /v1/capabilities/mcp[?scenario=<场景名>]` | **无需先跑 run 的逐台 MCP 状态**(现连、列工具、关掉;按调用方限速 + 30 秒复用)。答的是**某个场景**会挂哪些中心声明的 MCP 服务器:不带参数 =
|
|
1789
|
+
| `GET /v1/capabilities/mcp[?scenario=<场景名>]` | **无需先跑 run 的逐台 MCP 状态**(现连、列工具、关掉;按调用方限速 + 30 秒复用)。答的是**某个场景**会挂哪些中心声明的 MCP 服务器:不带参数 = 这位主体 run 时的场景(**7.131.0+**:中心按主体指派的场景胜出,否则部署缺省场景;此前恒读部署缺省场景;指派悬空 ⇒ `503 state.scenario_assignment_unknown`,与提交任务时同一句;`GET /v1/sessions/:id/mcp` 与 `…/a2a` 两张会话面板同读这位主体 run 时的场景:a2a 面板悬空时同样整面 503,而 mcp 面板另有「这个会话上一次真挂上了什么」那一半(`lastLegMcp`),悬空时答 `200`、`lastLegMcp` 照答、`servers` 缺席、拒因在 `scenarioRefusal: { errorCode, error, detail }`(与状态面整面 503 的体是同一份成员,`detail` 是门拒的机读事实 `{ scenario, source }`;`servers` 缺席 = 场景这一半没答,`servers: []` = 该场景没配 MCP));`?scenario=<名>`(**7.130.0+**)= 点名场景,可见集与同场景任务 run 时是同一只解析、过同一只场景门 —— 不在册 `400 scenario_unknown`(附在册词表;空串 `?scenario=` 同此,与提交 `scenario: ""` 同答)、这位 principal 的场景白名单集外 `400 scenario_not_allowed`(附 allowlist),两者的体与提交任务时的拒逐字同形;重复给出参数 `400 request.field_invalid`(提交腿没有这一形)。场景门接缝 `scenarioGate` 是 `createHttpServer` 的必填件:自建 `ServiceDeps` 的嵌入方用包根导出的 `createScenarioGate` 铸它(`"peek"` 腿给读面),没递就是 tsc 红。老 server 忽略这个参数、回缺省场景那一份,按 `GET /v1/capabilities` 的 `version` 判。`REQUIRE_PRINCIPAL` 下无身份 `401`(先于场景门)。自带 `.mcp.json` 的探测口是 `POST /v1/capabilities/mcp/probe` |
|
|
1724
1790
|
| `POST /v1/admin/drain` `{"actionId":"…","worker":"…","deadlineAt":…}` | **排空口**(7.121.0 起体 = settings-schema `DrainRequest`;operator-only —— principal 须在 `OPERATOR_PRINCIPALS` 内,空名单 ⇒ 501)。体 `{ actionId, worker, deadlineAt, scope?, expectedGeneration?, instanceId?, term? }`:`actionId` 幂等键(人手形自取,如 `manual:<uuid>`)、`worker` 本引擎的 worker 名(`SEMA_WEB_ADMIN_WORKER`)、`deadlineAt` 到期自停的 epoch ms、`scope` 本引擎的租户 scope(`FLEET_SCOPE`;不带 = 缺省 scope `global`,与没设 `FLEET_SCOPE` 的引擎相符 —— 多租引擎要带它自己的)、`expectedGeneration` fleet 成员的代际(`FLEET_GENERATION`;非成员不带)、`instanceId` 本进程身份(`GET /health` 读;不带则不比)。身份逐字段比(`worker` / `expectedGeneration` 缺席对缺席),不符 ⇒ `409 conflict.fleet_identity`(什么都不变);首次 ⇒ `200 {actionId, since, deadlineAt, state:"draining"}` 并**进入排空**(拒新提交、本副本可抢占的在飞腿当拍让出、活的审批卡改路耐久停驻、在飞归零或到期限即停);再来 ⇒ `200 … state:"already_draining"` 回显第一次的 `since` / `deadlineAt`,不重置。体坏 ⇒ `400 request.field_invalid`;`deadlineAt` 离本引擎此刻超过 `FLEET_LEASE_OUTAGE_MAX_MS`(缺省 24 h,一台实例活着而不服务的最长时长;7.122.0 起)⇒ 同码 400(什么都不变;拒句点名字段与上界的值;只在这一发会进入排空时判 —— 已在排空或硬停已在进行时任何重发都回 `already_draining`),已过的期限照收(进入即到期);嵌入宿主(无收尾链)⇒ `501 capability.drain_state_required`。没有 worker 身份的引擎(没配 `SEMA_WEB_ADMIN_WORKER`)恒 409 —— 用 SIGTERM。经本口进的排空之后,平台随后发的第一发 SIGTERM 被吸收、不缩短期限(第二发判据见「排空期的第二发信号」)。7.120.x 的 `{"reason":"…"}` 声明形与 `/health.drainReason` 已退役。 |
|
|
1725
1791
|
| `GET /v1/config/catalog` | **配置目录自描述**(operator-only —— `explicitOperatorOk`,空名单=谁都不是)。逐 env 键一行:`{name, domain, type, semantics, writeLanes, effectiveLane, envHeld, envTiming, staticDefault?/derivedDefaultNote?, effectiveValue, valueClass, danger, center?{domain,path,precedence,timing,restartSlice?,managedNow,effectiveNow}}`(🔴 7.106.0 起 `center.domainExists` 删除:座位在加载期对契约 `DOMAIN_SCHEMAS` 核过域 + 路径,核不过即拒启 ⇒ 有 `center` 块 ⇔ 中心可写;readFace 四键 / `PERMISSIONS_DISABLE_AUTO_MODE` / `MODEL_DEGRADE_ON` / `_REACTIVE` 七行的座位随之删除);顶层带 `restartSlices`(重启片闭集)与 `centerDomains`(settings-schema 现行域表)。**两轴不混**:`writeLanes`=谁能写,`effectiveLane`=现在谁在生效(env-wins 族 env 占位 ⇒ center 腿 `effectiveNow:false`)。secret 类值**永不回传**(只回在场位;opaque 回在场位+长度;URL 剥 userinfo)。完备性由仓内 AST 双向对账门执法(分母=全 `src/` 生产 env 读取点)。旋钮 `CONFIG_CATALOG_ENABLED=false`(合规部署)⇒ 路径 404 + 能力位 `configCatalog:false`。响应 `Cache-Control: no-store`。**7.57.0 起**:`enum` 行的 `effectiveValue` **恒落在该行自己的 `enumValues` 闭集内**(仓内机器门执法)——此前 `SESSION_BACKEND` 回的是**内部标签** `tidb`(自 5.0.0 起是**退役公名**,写回去 boot 拒),现归一成公名 `mysql`;`MODEL_DEFAULT_THINKING` 补上一直被解析器接受、却漏在目录闭集外的 `xhigh`,并改为回**实算值**(`off`/未设 ⇒ `null`)而不是 env 原文。 |
|
|
1726
1792
|
| `POST /v1/admin/config/refresh` | **配置手动刷新**(operator-only,与上一行同门:空 `OPERATOR_PRINCIPALS` ⇒ 恒 403)。改完中心配置 / `config.d` 之后不想等 60s 轮询就调它:触发**一次既有**的 refresh 拍(在飞则汇入那一拍,绝不并发双拍),返回时该拍已落地。200 体 `{triggered:true,targetVersion,appliedVersion}` —— 两个世代号与 `/health` 的 `configTargetVersion`/`configAppliedVersion` 同源。候选被判官整拒(坏域 / 坏 prompts / 带事实的退役域 —— 后者 7.126.0 起)是这一拍的结论,不是失败:照样 200,`targetVersion ≠ appliedVersion`,拒因在 `config_candidate_rejected` 日志行;拍真的失败(配置源不可达 / 读不了 / 应用抛错)⇒ `502 internal.config_refresh_failed`。本部署没有配置管道(纯 env worker:既没配 `CONFIG_CENTER`、也不是 `CONFIG_PROVIDER=local`)⇒ 409 `config.refresh_unavailable` 指路,不会回一个「触发了但什么都没发生」的 200。 |
|
|
@@ -1898,16 +1964,17 @@ curl -N http://<host>:8090/v1/tasks/stream -H 'content-type: application/json' \
|
|
|
1898
1964
|
> **7.7.0(引擎 5.20.0)起 `TOOL_TRACE` 已退出射程。** 引擎 5.20.0 新增「这条 PreToolUse 面只观察、
|
|
1899
1965
|
> 不裁决」的声明口,本服务的诊断 tracer(`TOOL_TRACE=true` 装的那只,恒不出判词)已按实声明 ⇒ 它**不再
|
|
1900
1966
|
> 铸筛查席**,该部署的层数回到 1、赎回照常通。**开着 `TOOL_TRACE` 不再需要在「诊断」与「后台子代能不能
|
|
1901
|
-
> 赎回」之间二选一。**
|
|
1967
|
+
> 赎回」之间二选一。** 7.132.0(引擎 7.52.0)起扩展点换成 mods 注册,读法不变:追踪是部署座上的观察注册
|
|
1968
|
+
> `server.tool-trace`,观察者永不铸筛查席。
|
|
1902
1969
|
>
|
|
1903
1970
|
> 📎 连带的一处**日志**变化(不是回归):引擎那行「可写工具面没有 effect-aware 门」的启动告警,此前把
|
|
1904
1971
|
> 诊断 tracer 当成一道门而被抑制;声明之后不再抑制,所以「没配任何工具策略层 + 开着 `TOOL_TRACE`」的
|
|
1905
1972
|
> 部署升级后会多出那行告警。tracer 从来没有门住任何东西,原先的抑制本身才是问题。
|
|
1906
1973
|
>
|
|
1907
1974
|
> **仍在射程内的只剩一条**:调用方提交里带 `settings.hooks.PreToolUse`(未开 `REQUIRE_PRINCIPAL` 的部署
|
|
1908
|
-
> 对外开放此面)。那是**会真裁决**的面(出得来 deny/ask)
|
|
1909
|
-
>
|
|
1910
|
-
>
|
|
1975
|
+
> 对外开放此面)。那是**会真裁决**的面(出得来 deny/ask),不能当观察者挂 —— 那等于让引擎把调用方的判词
|
|
1976
|
+
> 静默丢弃,比拒绝本身坏得多。本服务的赎回腿只重建调用方 policy 一层,所以拒绝仍是本版的行为
|
|
1977
|
+
> (7.132.0 起这张注册可以从存下的请求体按原配置重铸,引擎也认那条路;接上是后续版本的事)。不带该字段的部署**完全不受影响**。
|
|
1911
1978
|
>
|
|
1912
1979
|
> **精确的兼容矩阵**(本服务恒供 1 层;引擎只比层数,所以下表就是全部情形。5.18.1 / 5.19.0 / 5.20.0 三个
|
|
1913
1980
|
> 引擎上都实测过):
|
|
@@ -1953,6 +2020,12 @@ curl -N http://<host>:8090/v1/tasks/stream -H 'content-type: application/json' \
|
|
|
1953
2020
|
> 射程内的调用真人问(bypass 也问,无审批面即拒),run 一条 `permission.rule_store_unavailable`。
|
|
1954
2021
|
> **`~/…` 形的行以执行环境的家目录为基**:host / 未设 `REMOTE_EXEC` = 本机本用户,e2b = `/home/user`,k8s / local-docker / ssh / adb / device 不猜 —— 除非 `REMOTE_EXEC_HOME_DIR`
|
|
1955
2022
|
> 声明。没声明家目录的车道上,一条 `~/…` 的 deny / ask 行判不出点的是哪里 ⇒ 该面文件工具的每个调用都成真人问(bypass 也问);要么声明 `REMOTE_EXEC_HOME_DIR`,要么把规则写成绝对路径。
|
|
2023
|
+
> 7.132.0 起(引擎 7.52.0):没声明家目录的车道上,引擎的家锚拒读行(`~/.npmrc` / `~/.sema/settings.json` …)放不下 ⇒ **每一次泄内容的递归读**(`grep -r` / `rg` / `git grep` /
|
|
2024
|
+
> `tar c` …)在全 shell 面真人问(allow / 模式 / bypass 都放不掉)、只读面直接拒 —— 无人值守任务检索不了代码;起服一行 warn `execution_lane_home_undeclared`(`provider` + `note`)说出这件事与出路。
|
|
2025
|
+
> **声明会被对证**:local-docker 与 ssh 车道在每只执行环境开起来那一拍问一次 `$HOME`(与命令同一条 shell、同一份 env),与 `REMOTE_EXEC_HOME_DIR` 不一致(去掉尾斜杠后逐字比)
|
|
2026
|
+
> 或问不出 ⇒ 那只执行环境不开,工具结果里的拒句点名两个值与改法(改声明,或让环境以声明的那个用户运行);环境答了的不一致记在那只环境上(此后每次回同一句,不再起容器 / 不再问),
|
|
2027
|
+
> 问不出的那一次不记、下一次重问。
|
|
2028
|
+
> k8s / e2b / host / adb / device 车道今天不对证(声明照单全收)。
|
|
1956
2029
|
>
|
|
1957
2030
|
> **同批顺带:场景旧名 `team` / 工具旧名 `run_team` 退役(BREAKING)。** 此前过渡窗的别名层
|
|
1958
2031
|
> (`SCENARIO_ALIASES`)整体撤销:请求体里显式传 `scenario:"team"` 从「静默归一到 `discuss`」变成
|
|
@@ -2073,7 +2146,11 @@ curl -N http://<host>:8090/v1/tasks/stream -H 'content-type: application/json' \
|
|
|
2073
2146
|
| HTTP `429` + `errorCode:"limit.cost_quota_exceeded"` | per-principal 累计成本配额越顶(`MAX_PRINCIPAL_COST_USD`;**进场门**,不打断在跑的 run) | 看 `Retry-After` / 体 `retryAfterSec` 退避(体 `windowResetsAt` = 当代窗滚过的时刻);窗滚过或调高上限后放行 |
|
|
2074
2147
|
| HTTP `400` + `errorCode:"request.id_invalid"` | 调用方给的 id 形不对。**会话 id 的形门只有一只** = 任意版本 canonical uuid(壳预设的 v4 也过门):会话口 `:id`(fork / 抹除 / 会话策略 / 2c 同步)与提交口(`POST /v1/tasks` / `/v1/tasks/stream` / `/v1/runs` 体里的 `sessionId`,A2A 的 `contextId` 同)同判,提交口的句子在句首之后点名「改用 uuid、自己记映射」;`GET /v1/sendfile-links?before=` 游标与 `body.taskId` 幂等键要求 uuidv7(时间序 / 幂等键契约) | 按 `errorCode` 分支;句子各自点名要求的形(`must be a canonical uuid` / `must be a uuidv7 …`),只作展示、别锚文案 |
|
|
2075
2148
|
| HTTP `400` + `errorCode:"request.field_invalid"`(`PATCH /v1/sessions/:id` / 2c 导入的 `title`) | 标题不合形:1–120 个 Unicode 字符、**首尾不得有空白**(服务端不代为 trim,先于 C0 判)、不得含 C0 控制字符;`title: null` 清回自动标题;空串是 `request.body_shape` | 客户端送出前自行 trim;按 `errorCode` 分支,句子只作展示 |
|
|
2076
|
-
| HTTP `400` + `errorCode:"
|
|
2149
|
+
| HTTP `400` + `errorCode:"request.field_invalid"` + `reason:"over_cap"` / `"too_long"` / `"bad_entry"`(7.132.0 起:工具名清单、子代定义、两张宿主路径清单;其余的帽仍只有句子) | 撞了帽:`field` = 撞帽那一处的体内坐标(`skills[1].allowedTools` · `agents[0].denyTools[3]` · `agents` · `additionalDirectories` …),`count` = 送来的条数(`over_cap`)或字符数(`too_long`),`cap` = 帽;`bad_entry` = 清单第 `index` 条坏了(`field` = 那张清单)。句子头一句恒为 `<field> has <count> entries\|characters — at most <cap> are accepted` | 按 `field` 改那一处(合并 / 拆小条目、缩短文字、修那一条路径);句子只作展示 |
|
|
2150
|
+
| HTTP `400` + `errorCode:"config.tool_face_control"`(7.126.0 起;流式 / 后台腿的引擎侧拒是 `failed` 终局带同码,受理口拒三条腿都是提交时 400) | 请求的 `allowTools` / `excludeTools` 里有一个**读成空**的条目:任何工具名都不可能有的拼法(空白、括号不配、空名)、`allowTools` 写了 `mcp__*`(引擎拒)、`excludeTools` 写了 `*`,或(7.131.0 起,受理口拒)**近似名**(大小写孪生 `BASH`;放行侧 `allowTools` 与限制侧 `excludeTools` 都拒 —— 想放的什么也没放 / 想禁的照用)与**限制侧的退役名**(`excludeTools: ["Task"]`)。放行侧 `allowTools` 的**内容形**(`Agent(Explore)`)与没有后继的退役名(`MultiEdit`)照 7.130.0 受理、交引擎既有通告(运维行 `runner_config_advisory`);**有后继的退役名**(`Task` · `bash`)7.132.0 起由引擎开跑前拒(`config.tool_face_control`,同步腿 400)。**真未知名**(拼写合法、这台部署没有工具叫它,懒挂载的合法形)7.129.0 起照跑:条目原样留在表里,运维行告知一次。选择器只取工具名那一段判名字(限制侧 `Bash(echo $HOME)` 不拒),`allowTools:["*"]` 与限制侧 `mcp__*` / `a2a__*`(整个协议)合法。清单超 1000 条 ⇒ 整只 `400 request.field_invalid`(`count` / `cap`),帽内拒句只点名前 5 条 + `; and K more`。拒时:主模型零调用、标题器零调用(7.127.0 起;7.126.x 上标题器仍会为这次提交调一次模型)。这次提交留下的会话无标题、零消息 | 改成句子里 `write` 后的现名(或删掉条目);只列这台部署挂得出的工具名 |
|
|
2151
|
+
| HTTP `400` + `errorCode:"config.agent.unknown_tool"`(7.131.0 起) | 请求 `agents[i].denyTools`(限制侧)里有读成空的条目:近似名(`BASH`)、退役名(`bash`)、任何工具名都不可能有的拼法、`*`;`agents[i].allowTools`(放行侧)里的**近似名**。开跑前拒、主模型零调用、一个 token 没烧,句子点名条目、原因词与现名。限制侧 `Tool(content)` 的内容不读(读成整只工具)、限制侧整个协议的拒 `mcp__*` / `a2a__*`、真未知名(`NotMounted`,照跑、告运维一次)不拒;放行侧的内容形(`Agent(Explore)`)与没有后继的退役名(`MultiEdit`)照 7.130.0 受理、交引擎既有通告,选择器清单里**有后继的退役名**(`Task` · `bash`)7.132.0 起由引擎开跑前拒;文法读不出的放行条目授不出去 = 收窄而不是放行:规则表(`permissions.allow` / 技能 `allowedTools`)上受理口不拒、引擎开跑时告运维;选择器清单(根 / 子代 `allowTools`)上受理口不拒、引擎开跑前自己拒(子代 ⇒ `config.agent.unknown_tool`、根 ⇒ `config.tool_face_control`,同步腿都是 `400`〔7.132.0 起;此前子代这一形答 HTTP 200 + failed 终局体〕;异步 / 活流腿 HTTP 2xx、同码落在终态 run 行) | 改成句子里 `write` 后的现名,或删掉条目 |
|
|
2152
|
+
| HTTP `400` + `errorCode:"prompt.assembled_role_refused"`(7.132.0 起;流式 / 后台腿是 `failed` 终局带同码) | 请求的 `systemPrompt` / `appendSystemPrompt`(含 `settings.outputStyle`)逐字含引擎提示里的一段锁定文本(宪法、安全段、`# Harness` 这样的标题行)—— 一份已组装的提示。开跑前拒、零调用,句子点名字段与命中段 | 只写角色层:删掉抄进来的引擎段(引擎自己组宪法与行为段;追加段恒排在宪法之后) |
|
|
2153
|
+
| HTTP `422`(`request settings cannot be applied as written: …`)/ HTTP `400` + `errorCode:"request.field_invalid"`(7.131.0 起的读成空) | 请求体 `settings.permissions.deny` / `ask` 里的孪生与退役名 ⇒ 422、句子点名带内容的现名(`BASH(*)` ⇒ 写 `Bash(*)`);`settings.permissions.allow` 与技能 `allowedTools` 里的**近似名**(`BASH`)⇒ 400(退役名 · 内容形 · 文法读不出(带空白 / 括号不配 / 规则内容文法不成立,如 `Bash(echo $HOME)`)· 对端段通配照 7.130.0 受理,引擎通告)—— 全部读**同一张名册**(引擎目录 ∪ 本服务自铸的工具名)。运维 `APPROVAL_REQUIRE` / `APPROVAL_DENY` / `APPROVAL_NEVER_AUTO` / `APPROVAL_GRANT` 里的孪生 **拒启**,中心下发的 `governance.approvalRequire` 里的孪生整组被拒、保前值。续跑:停驻在升级前的任务,超 1000 条的清单(任一方向)与限制方向的存量孪生 `409 resume_blocked_by_policy`,放行方向的存量近似名照旧续跑 + 一行 warn `stored_allow_list_inert_resumed` | 改成句子里 `write` 后的现名(或删掉条目);超帽的合并成更宽的条目 |
|
|
2077
2154
|
| HTTP `429` + `errorCode:"usage.window_exhausted"` | 部署级治理窗耗尽(`USAGE_WINDOWS`,token 或 $ 天花板先满者) | 看响应体 `retryAfterSec` 退避;窗滑动/桶到期后放行 |
|
|
2078
2155
|
| `terminal:{kind:"failed", code:"usage.window_exhausted"}` | 已受理的 run 在 **turn 边界**撞上治理窗且无法 durable 挂起 | 同上退避后重投;配好 checkpoint 基建则改为 `suspended` 等窗自动续跑 |
|
|
2079
2156
|
| HTTP `501`(`/v1/runs`) | 内存模式不支持异步 | 配持久存储(`DB_BACKEND=mysql` / `pg` + 坐标;7.106.0 起给了坐标必须点名 `DB_BACKEND`) |
|
|
@@ -2096,9 +2173,9 @@ tag 词表与每条的最坏后果见 `docs/FAIL-OPEN-CENSUS.md`。引擎装配
|
|
|
2096
2173
|
按 `code` / `classification` / `level` 打标;其中 `shell-gate-off` 在本 session 显式声明 `permissionMode:
|
|
2097
2174
|
"bypassPermissions"` 时是调用方要的姿态,降为 **info** 并标 `expected`——只有没表态落到引擎默认 off 的无壳直连
|
|
2098
2175
|
形才 warn。子代 `agents[].denyTools` / `allowTools` 的**名字**归引擎开跑前一只判(7.126.0 起与根 run 的 `allowTools` / `excludeTools` 是同一只工具选择器):
|
|
2099
|
-
7.129.0 起(引擎 7.51.0)
|
|
2100
|
-
|
|
2101
|
-
|
|
2176
|
+
7.129.0 起(引擎 7.51.0)没有任何工具答应、也不是某只已挂载工具另一种拼法的名字(**真未知名**)**引擎不再拒跑**:条目原样保留(今天什么都不拒 / 不准,之后挂上同名工具即生效),运维行 `runner_config_advisory` 每条告知一次(句子带该写的拼法;委派工具声明了逐次注入工具的名册,引擎列得出子代工具池);
|
|
2177
|
+
引擎开跑前拒(`config.agent.unknown_tool`)的是任何工具名都不可能有的拼法(空白、括号不配、空名)、非字符串条目,以及(引擎 7.52.0 起,两侧同判)写成**已挂载工具另一种拼法**的条目:大小写孪生(`BASH`)与有后继的退役名(`Task` ⇒ `Agent`、`bash` ⇒ `Bash`)。**7.131.0 起本服务把其中写错现名的在受理口前置拒:限制侧四类全拒、放行侧只拒近似名** —— `denyTools:["BASH"]` / `["bash"]` 以为禁了 `Bash`、子代照用(静默放行),`allowTools:["BASH"]` 想放 `Bash` 却什么都没放(静默收窄);
|
|
2178
|
+
提交 400 `config.agent.unknown_tool`(根 run 的清单是 `config.tool_face_control`),句子点名条目、原因词与现名;放行侧的**内容形**(`Agent(Explore)`)与没有后继的退役名(`MultiEdit`)仍照 7.130.0 受理、交引擎既有通告,选择器清单(根 / 子代 `allowTools`)里**有后继的退役名**(`Task` · `bash`)7.132.0 起由引擎开跑前拒,规则表里的退役名照旧受理、引擎开跑时告运维;文法读不出的放行条目授不出去 = 收窄而不是放行:规则表(`permissions.allow` / 技能 `allowedTools`)上受理口不拒、引擎开跑时告运维;选择器清单(根 / 子代 `allowTools`)上受理口不拒、引擎开跑前自己拒(子代 ⇒ `config.agent.unknown_tool`、根 ⇒ `config.tool_face_control`,同步腿都是 `400`〔7.132.0 起;此前子代这一形答 HTTP 200 + failed 终局体〕;异步 / 活流腿 HTTP 2xx、同码落在终态 run 行);存量体续跑见 MIGRATION 7.131.0 第 8 条。判官仍是引擎的条目读法。**真未知名**(没有近似也没有退役对应:懒挂载的合法形)照旧只告运维、不拒。名字按工具名原拼写 `Bash`。这两张表管子代可挂载的**全部**工具 —— 委派池、内建 hands(`Read` / `Edit` / `Write` / `NotebookEdit` / `Bash` / `Grep` /
|
|
2102
2179
|
`Glob` …)、引擎自己的工具(`Monitor` / `Artifact` / `Skill` / 记忆工具 …)与父的 MCP 挂载:`denyTools:["Write"]` ⇒ 子代没有 `Write`,`denyTools:["Monitor"]` ⇒ 子代没有
|
|
2103
2180
|
`Monitor`;`allowTools` 只列调用方工具 ⇒ 子代只剩那几只与它这条腿的协议工具(要什么就点名什么,`mcp__<srv>` 点整台服务器)。内建只读子代(Explore / Plan)没有
|
|
2104
2181
|
`Edit` / `Write` / `NotebookEdit`。要按路径 / 命令拦而保留工具,写调用方权限策略的 deny 规则。
|
|
@@ -2202,7 +2279,7 @@ k8s 车道每条 run 一只新 pod(pod 寿命 = 泄漏护栏,不跨 run 复用)
|
|
|
2202
2279
|
- **指针**:`space/latest`,体 = 最近一份 snapshotId。run 结束时先把 `/workspace` 打包上传(与挂起同一条车道:沙箱只拿到限时预签 URL,凭据留在 server),成功后**整体覆写** `latest`,再删 pod。下一条 run 第一次用到沙箱时读 `latest`:在 ⇒ 新 pod 上恢复那一份;不在(空间第一条 run)⇒ 空目录。
|
|
2203
2280
|
- **保留**:每个空间只留最近 `WORKSPACE_SNAPSHOT_KEEP` 份(缺省 3),写新快照后删最老的;`latest` 指向的那份恒留。没有另外的索引表 —— 桶里列出来的就是全部。
|
|
2204
2281
|
- **只盖 `/workspace`**:进程、内存态、`/tmp` 不跨轮(与挂起 / 续跑同一口径)。大小上界 = 快照时限 `WORKSPACE_SNAPSHOT_TIMEOUT_MS`(缺省 300000 = 5 分钟);超时 = 快照失败,不截断。
|
|
2205
|
-
- **排除表**(`WORKSPACE_SNAPSHOT_EXCLUDE`,7.126.0 起):逗号分隔的 tar 排除模式,相对工作区根(`build,.gradle,node_modules/.cache`),每项一个 `--exclude=./<项>`,落在**那一只**打包上传上 —— run 末快照与停驻挂起是同一张表(挂起后续跑也没有被排除的目录;构建产物、依赖缓存本就可再生)。沙箱镜像的 GNU tar 按工作区根锚定(`build` 只排除 `/workspace/build`,不排除 `/workspace/app/build`;要排子模块的就写 `app/build`,或写通配 `*/build`);镜像若换成 busybox / libarchive 的 tar,同一项会在任意深度生效。不读项目的 `.gitignore`(那是另一套文法、按项目变、与 tar 的匹配不等价);中心若要下发模式表,下发的就是这一个 env 的值。项形是闭的:相对路径段,不含 `..`、前导
|
|
2282
|
+
- **排除表**(`WORKSPACE_SNAPSHOT_EXCLUDE`,7.126.0 起):逗号分隔的 tar 排除模式,相对工作区根(`build,.gradle,node_modules/.cache`),每项一个 `--exclude=./<项>`,落在**那一只**打包上传上 —— run 末快照与停驻挂起是同一张表(挂起后续跑也没有被排除的目录;构建产物、依赖缓存本就可再生)。沙箱镜像的 GNU tar 按工作区根锚定(`build` 只排除 `/workspace/build`,不排除 `/workspace/app/build`;要排子模块的就写 `app/build`,或写通配 `*/build`);镜像若换成 busybox / libarchive 的 tar,同一项会在任意深度生效。不读项目的 `.gitignore`(那是另一套文法、按项目变、与 tar 的匹配不等价);中心若要下发模式表,下发的就是这一个 env 的值。项形是闭的:相对路径段,不含 `..`、前导 `/`、空白、引号,也不是整体通配(只由 `*` / `?` 组成的项 —— `*` 会让快照一个顶层项都不剩;`*.log`、`build-*` 这类带字面部分的仍是正常项)(坏项拒启,码 `config.workspace_snapshot_exclude_invalid`,点名第几项)。⚠️ 已知形:打包先落 pod 里的临时文件再上传(对象存储的预签 PUT 要 `Content-Length`,流式上传不行)⇒ 打包期间工作区占双倍盘;排除表把它缩小。
|
|
2206
2283
|
- **提交围栏(下一条 run 等上一条存完)**:「这个空间有提交在飞」是 run 店里的一行(表 `workspace_space_commit`;local 后端是数据根下 `space-commits/` 的一份记录),不在对象存储里。写点只有一个次序:run 的终态写入与释放会话占用**同一个事务**里落 `pending`(只在这条 run 碰过沙箱时)→ run 末保存开始时改成提交中 → 上传完、写 `latest` 之前再认领一次(改成发布中)→ 存完或失败都删行。**一行一个期限,写者写、所有人读**:每次写行都把行的期限定为「此刻 + 写它的那台副本的 `WORKSPACE_SNAPSHOT_TIMEOUT_MS`」;读的一方只看行里的期限,不拿自己副本的数判别人的提交 —— 所以滚动改这个数时,新旧副本互不误判。下一条 run 连沙箱前读这一行:有 ⇒ **等**,每 1 秒重读一次,直到行消失(再按新的 `latest` 恢复)或过了行里的期限。读到过了期限 = 上一条的 worker 死在终态与保存之间、死在上传里、或死在写 `latest` 时 —— 也可能写者正在这一刻续期,所以只读一眼不算数:下一条 run 在一个事务里锁住这一行、按锁下读到的库钟再判一次,仍是那条 run 的、仍过期限才删掉它(弃)。删成了 ⇒ 一行 `workspace_commit_abandoned`(`space` / `remainingMs`:≤ 0,过了期限多久 / `state`),照常恢复 `latest`(它仍指上一份**完整**快照);没删成(写者恰好续了期、行已换主或已删)⇒ 立刻重读、照常等。弃与续期在行锁上排队,被弃的写者再认领时找不到自己的行 ⇒ 不推进 `latest`。期限按存储自己的钟算(SQL 后端 = 数据库的钟),不拿两台副本的墙钟比。提交自己也守同一个期限:开始保存时它的行已过期限(下一条 run 可能已按「放弃」继续)⇒ 不上传、不推进 `latest`(`workspace_snapshot_failed`、`stage: fence`);上传完、写 `latest` 前那次认领发现行已过期限或已不是自己的 ⇒ 同样不推进(`stage: fence`)。所以引擎拆环境的 15 秒上界、存储慢都不会让下一条 run 恢复到旧的一份。终态帧上的 `workspaceSnapshot` 只承载本 run 在终态帧之前落定的结局:保存比终态帧晚落定时这条 run 的帧不带,那次结局只留运维行,也不会挂到同一会话下一条 run 的帧上。
|
|
2207
2284
|
- **仍余的一条残窗(如实)**:`latest` 指针写是单对象预签 PUT,这次 PUT 的时限 = 围栏剩余时长。PUT 自己到点没答、写者放弃它(一行 `workspace_snapshot_failed`,`stage: "pointer"`、`code: "connect_failed"`,`error` 点名指针写)之后,对象存储侧那次 PUT 仍可能迟到落地 ⇒ 一个已失围栏的写者的 `latest` 覆盖新写者刚发布的。围栏丢失是另一臂(`stage: "fence"`、`code: "timeout"`):那一臂不发 PUT,构造不出这扇窗。只在多副本、围栏到期、且存储侧延迟大于剩余时长时构造得出;本版不读 ETag、不做条件写,只在此披露。收法(下一版):存储支持 `If-Match` 时用 ETag 条件 PUT,不支持时 `latest` 改为带提交世代的指针对象、读者取有围栏记录的最高世代;两形由能力位如实披露。
|
|
2208
2285
|
- **指针 / 列举 / 删除由 server 直接请求 `MINIO_ENDPOINT`**(快照字节仍是 pod ↔ MinIO 直传)。server 进程必须够得着这个端点(会话快照 blob 卸载本来就从 server 进程请求同一个端点)。
|
|
@@ -2218,19 +2295,22 @@ k8s 车道每条 run 一只新 pod(pod 寿命 = 泄漏护栏,不跨 run 复用)
|
|
|
2218
2295
|
|
|
2219
2296
|
- **没配快照存储**(`MINIO_ENDPOINT` / `MINIO_ACCESS_KEY` / `MINIO_SECRET_KEY` 缺任一)⇒ 工作区每轮为空,`GET /v1/capabilities` 不带 `workspaceSync`;起服一行 `workspace_persist_unavailable`(`missing` 点名缺的键;缺省 `space` 也出,设 `WORKSPACE_PERSIST=off` 即不出)。
|
|
2220
2297
|
- **没有存储后端**(`DB_BACKEND=memory`;配了 SQL 的 `DB_BACKEND` 却显式 `SESSION_BACKEND=memory` 时库不开,同一形)× `space`(含缺省,且配了快照存储)⇒ **拒启**,拒句一行点名 `WORKSPACE_PERSIST=space`、缺的存储后端、会话店种类(与 `/health.sessionBackend` 同一读法)与可用的后端。出路:`DB_BACKEND=local`,或 SQL(`DB_BACKEND=mysql|pg`,`SESSION_BACKEND` 不设 `memory`),或设 `WORKSPACE_PERSIST=off`。`SESSION_BACKEND=memory` 配 `DB_BACKEND=local` 不在此列:被收编成 local 店,照起。拒启而不是降级:否则能力位报 `space`、每条 run 却一份都不存。
|
|
2221
|
-
- **读 `latest` 失败**(非 404 的 HTTP 错、网络错)、**读或弃提交围栏那一行失败**或**读会话住客失败**(
|
|
2298
|
+
- **读 `latest` 失败**(非 404 的 HTTP 错、网络错)、**读或弃提交围栏那一行失败**或**读会话住客失败**(会话店报错、答出的不是住客令牌,或没在 `rpcTimeoutMs`〔30 秒,与读围栏行、读 `latest` 同一只墙〕内答 —— 挂住的会话店不再让 run 的起步永挂)⇒ 这条 run 连沙箱失败(`connect_failed`,工具调用报沙箱不可用;停驻 run 续跑时的恢复同样失败),**不会**悄悄给一个空目录、也不猜「没有提交在飞」—— 「以为恢复了其实没有」比失败更坏。读住客失败时一只 pod 都不建,另有一行 `workspace_space_unreadable_occupant`(`sessionId` / `code`:会话店错误的码,不带正文;读超时的码是 `incarnation_read_timeout`),每条 run 至多一次。修好存储 / 数据库后重跑,或设 `WORKSPACE_PERSIST=off` 即恢复。
|
|
2222
2299
|
- **`latest` 指向的快照对象不在了**(被删 / 被只盖 `.tar.gz` 的生命周期规则清掉)⇒ 沙箱**照常起**:一行 `workspace_latest_dangling`(`space` / `key` / `deleted`),删掉悬空的 `latest`,这条 run 从空目录开始,它的 run 末快照成为新的 `latest`(数据已被运维规则清走:响亮、可继续)。指针删不掉 ⇒ 同一行 `deleted: false` + `error`,下一条 run 再说一次。
|
|
2223
|
-
- **`latest` 指向的快照在、却拿不回来**(桶答了却不是 200 / 解压失败 / 超过快照时限 / 传输中断)⇒ 这条 run **仍然连沙箱失败**(`connect_failed`)、**不**退到空目录 —— 用户的改动还在桶里,静默空目录 = 让人以为丢了。**一条 run
|
|
2300
|
+
- **`latest` 指向的快照在、却拿不回来**(桶答了却不是 200 / 解压失败 / 超过快照时限 / 传输中断)⇒ 这条 run **仍然连沙箱失败**(`connect_failed`)、**不**退到空目录 —— 用户的改动还在桶里,静默空目录 = 让人以为丢了。**一条 run 只恢复一次**(同一只执行环境上并发的连沙箱 —— 显式 `connect()` 与首个工具调用的懒连接 —— 共用同一次建连:一只 pod、一次恢复、一个终局,被拒也是同一个拒;恢复还没完成时才到的工具调用和 `reconnect` 也等这一次建连 —— pod 先于它的工作区存在,不在半恢复的 `/workspace` 上先跑):瞬时类(`timeout` 超过快照时限 / `transport` 传输中断:执行通道断了,或 pod 取包的 GET 没拿到完整应答 —— 连不上、被重置、传到一半被截)在恢复这一步里换一只新 pod 再试一次(约 1 秒后),再试成了 ⇒ 照常起、不出行;`store_busy`(桶答 `408` / `429` / `500` / `502` / `503` / `504` —— 「现在不行」,同一请求再发可能换答案)同属瞬时类;非瞬时类(`download` 桶答了、答的是其余非 200 —— 如 `401` / `403` / `501`;`untar` 包完整下来了却解不开)不重试。每次没成的尝试,新起的 pod 当场删掉(残缺目录既不给工具用,也不会在 run 末被快照回去覆盖 `latest`)。恢复终局是拒 ⇒ **恰一行** `workspace_restore_failed`(`space` / `snapshotId` / `class` = `store_busy` \| `download` \| `untar` \| `timeout` \| `transport` / `attempts` = 这次恢复的尝试次数(`1` 或 `2`)/ `boundMs` = 每次尝试的时限 / `error`,预签 URL 已脱敏),这条 run 之后的每次沙箱操作都答**同一句**拒(不再建 pod、不再读 `latest`、不再出行);建 pod 本身失败不是恢复的结局(不出这行,下一次操作重来)。拒句写明类别与尝试次数,点名两条出路:**调大 `WORKSPACE_SNAPSHOT_TIMEOUT_MS`**(大工作区撞上界),或 **`WORKSPACE_PERSIST=off` 跑一轮**(空目录起,不删任何快照;改回 `space` 后下一条 run 照常恢复那一份)。没有「删指针」的接口:丢弃这份快照 = 丢弃用户数据,要做就由运维在对象存储侧有意识地删 `<前缀>/<化身>/space/latest`(下一条 run 从空目录起)。与上一条「悬空」分开:那是对象**不在**(没东西可恢复 ⇒ 空目录 + 响亮),这是对象**在**而拿不回来(⇒ 拒)。
|
|
2224
2301
|
- **run 末提交围栏失守、上传失败或 `latest` 写失败** ⇒ 一行 `workspace_snapshot_failed`(`space` / `stage` = `fence` \| `upload` \| `pointer` / `code` / `error`,预签 URL 已脱敏),这条 run 在 `GET /v1/fleet/stream` 上的终态 task 帧带 `workspaceSnapshot: "failed"`;pod 照删;`latest` 不动 ⇒ 下一条 run 恢复的是**上一份**。
|
|
2302
|
+
- **run 末快照保存前一律先停 pod 里的进程并确认**(与那一刻有没有命令在飞无关)。命令「结束」(自己退出、被取消、超时)不等于它起的进程结束(断开 exec 套接字不会让 pod 里的进程停),在飞登记里已经没有命令也不能证明 pod 静了,所以保存前都先杀掉 pod 里除 init 与容器保活进程外的全部进程并确认;没连过沙箱的 run 没有可存的工作区,不走这一步。**run 结束时还有命令在跑**(取消 / 超时结束的 run 的命令没来得及停)⇒ 杀之前**先等**它们结束:最长一只 `rpcTimeoutMs` 墙(缺省 30 秒;等待算在这次提交的快照时限里,上传拿到的是剩下的);等不到的还要断开仍开着的 exec 套接字(那条命令的调用方读到 `aborted`),**照样保存**,并出一行 `workspace_snapshot_commands_cut`(`space` / `inFlight` / `waitedMs` / `killed`)。**没能确认进程停下**(杀进程那一步失败,或几次复查后仍有活进程;有没有命令在飞、等到与否都一样)⇒ **不保存**:一行 `workspace_snapshot_failed`(`stage: upload`、`code: command_in_flight`),`latest` 不动 —— 可能还在变的工作区不当 `latest`。**确认不了的四种形**(工作区不存,下一轮恢复的是上一份 —— 本轮的工作在下一轮看不到;7.131.x 在「run 结束时没有命令在飞」时照存):镜像里经 `sudo` / setuid 程序起的、以别的 uid 跑的进程(`kill -9` 没有权限,例如 `sudo -u postgres` 起的库进程)· 不可中断睡眠(D 态)的进程 · `podSpecPatch` 打开了 `shareProcessNamespace`(同 pod 别的容器的进程也在 `/proc` 里)· 镜像里没有 `tr`、而容器保活进程不是 1 号进程(pod 起动先跑包源钩子的那一形:认不出保活进程、把它杀掉,容器随之结束)。**出路**:k8s 车道镜像以一个非 root 用户跑、不经 sudo / setuid 起常驻进程,带 `tr`,不开 `shareProcessNamespace`;按 `workspace_snapshot_failed{stage: upload, code: command_in_flight}` 告警;不需要跨轮保留的部署设 `WORKSPACE_PERSIST=off`。杀进程脚本只在「该杀的都不活了」时退出 0(僵尸进程算死:容器保活进程不收尸)。从 destroy 开始起这只执行环境不再收新命令(工具调用报沙箱已销毁)。`command_in_flight` 的拒只留给停驻挂起(run 还活着,撕裂的归档才是真风险)。此前 run 结束时只要还有命令在飞,快照就整份被拒(`workspace_snapshot_failed`,`stage: upload`),`latest` 不动,下一轮恢复上一份 —— 取消 = 丢掉这一轮的工作。
|
|
2303
|
+
- **pod 被集群在准入时拒**(pod 建出来后、跑起来之前就到了 `Failed`:如 `K8S_SANDBOX_IPV6=disabled` 而 kubelet 没放开那两只 sysctl 时的 `SysctlForbidden`、节点亲和不符、节点放不下)⇒ 这只执行环境**记住这次拒**直到销毁:这条 run 的每次操作答同一句 `connect_failed`(沙箱不可用;句子点名 pod 的阶段与 kubelet 的原因),**不再每次操作重建 pod**(此前一条 run 里可建出几十只 `Failed` pod),与「恢复被拒」同一只记住的槽、同一个写口;一行 `sandbox_pod_refused`(`pod` / `phase` / `reason` / `detail`:kubelet 的原话,截断 / `sessionId`),每只执行环境至多一次。重跑这条 run 是一只新的执行环境,重新问集群。API 拒建 pod(HTTP 非 2xx:配额等)不在此列,仍是那一次尝试的失败。
|
|
2225
2304
|
- **删最老的失败** ⇒ 一行 `workspace_snapshot_prune_failed`,不影响本轮(空间里只是多留几份)。
|
|
2226
|
-
- **空间结束时回收快照对象失败**(列举失败、列举被截断〔分区里超过 1000 个对象〕、某个对象删失败)⇒ 会话照删,每个失败的分区 / 阶段一行 `workspace_space_reclaim_failed`(`space` 前缀 / `sessionId` / `lane` = `space` \| `park` / `stage` = `list` \| `delete` \| `budget` \| `seat_threw`(回收座违约抛了,响亮接住、不炸进程)/ `error`,预签 URL
|
|
2227
|
-
`budget` = 回收座这一次调用的绝对截止(= 快照时限;会话删除 = 一个空间,托管留存 sweep = 每个域每拍一次;卷回收也在内)到点,这个空间余下的列举与删除没做 —— 截止在轮到这个空间之前就过了 ⇒
|
|
2305
|
+
- **空间结束时回收快照对象失败**(列举失败、列举被截断〔分区里超过 1000 个对象〕、某个对象删失败)⇒ 会话照删,每个失败的分区 / 阶段一行 `workspace_space_reclaim_failed`(`space` 前缀 / `sessionId` / `lane` = `space` \| `park` / `stage` = `list` \| `delete` \| `budget` \| `seat_threw`(回收座违约抛了,响亮接住、不炸进程)/ `count` / `error`,预签 URL 不进行;**一次调用里同类(分区 × 阶段)的失败合成一行**:`count` = 撞上它的空间数,`space` / `sessionId` / `error` 是调用里排第一的那个 —— sweep 一拍几百个空间遇上同一个 RBAC 漂移只出一行;卷那一行 `workspace_cache_reclaim_failed` 同形)+ 计数 `server.workspace-space.reclaim-failed`(仍逐空间计);
|
|
2306
|
+
`budget` = 回收座这一次调用的绝对截止(= 快照时限;会话删除 = 一个空间,托管留存 sweep = 每个域每拍一次;卷回收也在内)到点,这个空间余下的列举与删除没做 —— 截止在轮到这个空间之前就过了 ⇒ 它一个请求都没发,同样记进 `budget` 那一类(配了缓存卷的,它的卷记进 `workspace_cache_reclaim_failed{reason: "budget"}` 那一类)—— `budget` 类行里的 `count` 就是被截止留下的空间数。截止之前的失败互不牵连(另一个分区、构建缓存卷照收)。对象留在桶里,按行里的空间前缀 / 会话 id 去桶里手清,或等桶的生命周期规则;到期会话已删、不会被下一拍重新列出;一拍最长 = 有结束空间的域数 × 快照时限,超过 sweep 间隔时中间的拍被跳过(防重入守卫照旧);**快照时限 ≥ 2 × sweep 间隔(= 租约 TTL)时,一个域内的回收可把本副本的租约耗过期 ⇒ 这一拍余下的域不跑、下一拍再起(一行 `retention_sweep_lease_lost`)—— 配法:快照时限要明显小于租约 TTL,即 `WORKSPACE_SNAPSHOT_TIMEOUT_MS`(毫秒)< 2 × `RETENTION_SWEEP_INTERVAL_SEC` × 1000 再留出该域 SQL 步骤的余量;缺省时限 300 000 ms 对 sweep 间隔 ≥ 300 s 的部署成立,间隔更短的部署调大间隔或调小时限(时限下限 30 000 ms)**。
|
|
2228
2307
|
- **提交围栏那一行删不掉**(数据库 / 数据根故障)⇒ 下一条 run 等到行里的期限过去,按 `workspace_commit_abandoned` 继续(有界、响亮)。
|
|
2229
2308
|
|
|
2230
2309
|
**能力位**:`GET /v1/capabilities.workspaceSync = { persist, keep, timeoutMs }`(`timeoutMs` 7.126.0 起 = 快照时限,壳据此告知用户「快照上界」;排除表不上 wire),只在 k8s 车道 ∧ 配了快照存储时在场;`persist` 如实报生效值(缺省 `"space"`);报 `"space"` 的部署,会话店一定读得出住客(读不出的组合起服即拒)。壳 / 中心只在 `persist:"space"` 时渲「工作文件跨轮保留」。
|
|
2231
2310
|
|
|
2232
2311
|
**须知**:把 `/workspace` 当一次性临时盘用的调用方,下一条 run 会看到上一条留下的文件;回到每轮为空 = `WORKSPACE_PERSIST=off`。存储增长 = 每个空间 `KEEP` 份 tar;**空间随会话结束而回收**:`DELETE /v1/sessions/:id` 的删除协调器与托管留存 sweep 删掉会话(树)之后,同一只回收座(见 9.3d;**不在删除应答路径里** —— `DELETE` 摘掉旧订阅即答,回收在应答前已起、不被等待,一次调用一份绝对截止 = 快照时限,卷回收也在内)删该空间 `<前缀>/<化身>/space/` 下的全部对象(快照与 `latest`)和该会话停驻车道 `<前缀>/<会话 id>/` 里名字带本住客归属记号的 `*.tar.gz`
|
|
2233
2312
|
(用 `MINIO_*` 同一组凭据对桶做列举与删除,修剪旧快照走的也是这条车道;停驻分区按会话 id 分区,会话 id 删后可被别人重新登记 ⇒ 只按快照名字里的归属记号判、不读任何钟,后来的住客写的带它自己的记号,不碰;升级前写的不带记号的旧形与无住客的 run 写的 `none` 不删);删后前一位住客的空间不再可达(新住客是新的化身)。回收失败不挡删除:一行 `workspace_space_reclaim_failed` + 计数 `server.workspace-space.reclaim-failed`,对象留着。
|
|
2313
|
+
**回收座是一只带并发上界的队列**:同一时刻最多 4 个空间在收(小常数,不是旋钮),托管留存 sweep 的空间与每一次会话删除的回收**共用这一只门** —— 一阵会话删除不会同时起一阵回收,排队的空间在它那次调用的截止之下等;一个慢的空间不再拖住排在它后面的空间。
|
|
2234
2314
|
**桶的生命周期规则只作兜底**(回收失败的对象、回收截止到点没删的对象、回收没跑完进程就退留下的对象、会话删除那一刻上一条 run 的提交恰好才落下的对象、本版之前已结束的空间留下的对象、不带归属记号的旧形停驻快照与 `none` 停驻快照,只有它能清):规则要对**整个 `<前缀>/`** 按龄过期(跨轮保留在 `<前缀>/<化身>/space/`、停驻快照在 `<前缀>/<会话 id>/`,都在它下面;指针与快照同一条规则);只对 `.tar.gz` 配会留下指向空处的 `latest` —— 那个空间的下一条 run 按上一条「悬空」处置从空目录起(一行 `workspace_latest_dangling`),旧文件已被规则清走。
|
|
2235
2315
|
|
|
2236
2316
|
### 9.3c k8s 车道:点名 env 转发(`K8S_SANDBOX_ENV`)
|
|
@@ -2267,6 +2347,7 @@ k8s 车道每条 run 一只新 pod(pod 寿命 = 泄漏护栏,不跨 run 复用)
|
|
|
2267
2347
|
- **卷拿不到 ⇒ 不拒这一轮**:卷建不成(Role 少动词 / API 拒 / 网络,`reason: claim_failed`)、卷在快照时限(`WORKSPACE_SNAPSHOT_TIMEOUT_MS`)内没绑定(集群没有缺省 StorageClass /
|
|
2268
2348
|
供给器不在,`claim_unbound`)、卷绑上了而挂着它的 pod 起不来(挂载失败 / 卷所在节点没了,`claim_unmountable`)—— 后两种把等它的那只 pod 删掉、换一只不挂卷的 —— 、没有这只会话(会话店答「没有」,`incarnation_unknown`)⇒ run **照常起**:不挂卷、不注入缓存 env,
|
|
2269
2349
|
计数 `server.workspace-cache.unavailable`(fail-open 登记表第 129 行)+ 一行 `workspace_cache_unavailable`(`space` / `claim` / `reason` / `error`),每条 run 至多一次。
|
|
2350
|
+
**没绑上 / 没挂上(`claim_unbound` / `claim_unmountable`)按空间记一个快照时限**:这个空间的后续 run 在窗内直接不挂卷 —— 不发 claim 请求、不起等卷的 pod(此前每条 run 都等满一个快照时限、删掉第一只 pod 再起第二只),照样计数 + 一行(`error` 点名「记着的」);窗过了再问一次(运维补上缺省 StorageClass 后,窗后第一条 run 就挂上)。记忆放在部署的 per-run 绑定里(进程内、不跨副本、不落盘)。
|
|
2270
2351
|
- **读住客失败 ⇒ 拒这一轮**:会话店报错(或答出的不是住客令牌)不是「没有空间」—— 与 9.3b 同一只 `connect_failed`(一只 pod 都不建,一行 `workspace_space_unreadable_occupant`,不计数);拒句点名开着的旋钮
|
|
2271
2352
|
(只开卷时是 `WORKSPACE_CACHE=off`)。重跑即重新读。
|
|
2272
2353
|
- **委派子代 / 后台代理不挂卷**(与不开空间同一条法:它们与父并发,不共享父的空间)—— 不计数、不出行。
|
|
@@ -2279,7 +2360,7 @@ k8s 车道每条 run 一只新 pod(pod 寿命 = 泄漏护栏,不跨 run 复用)
|
|
|
2279
2360
|
|---|---|---|
|
|
2280
2361
|
| `WORKSPACE_CACHE` | `off` | `volume` = 每个空间一只构建缓存卷;`off` = 不建卷(pod 与旧版逐字同)。词表外 ⇒ 拒启。前提:有存储后端(`DB_BACKEND=memory` × `volume` ⇒ 拒启,出路 `WORKSPACE_CACHE=off`)。只在 `REMOTE_EXEC=k8s` 时读 |
|
|
2281
2362
|
| `WORKSPACE_CACHE_SIZE` | `20Gi` | 卷的申请量(k8s quantity 形,如 `20Gi` / `500Mi`;形不合 ⇒ 拒启) |
|
|
2282
|
-
| `WORKSPACE_CACHE_MOUNT` | `/cache` | 卷在 pod 里的挂载点(绝对路径;与工作区挂载 `K8S_MOUNT_PATH` 相同 / 互相嵌套 ⇒
|
|
2363
|
+
| `WORKSPACE_CACHE_MOUNT` | `/cache` | 卷在 pod 里的挂载点(绝对路径;与工作区挂载 `K8S_MOUNT_PATH` 相同 / 互相嵌套 ⇒ 拒启;落在保留的镜像目录闭集 —— `/bin /boot /dev /etc /home/sandbox /lib /lib64 /opt/sema /proc /root /run /sbin /sys /tmp /usr /var` —— 上 / 之下 / 之上 ⇒ 拒启并点名那一项:卷挂在那里会遮住镜像在那条路径下放的东西) |
|
|
2283
2364
|
|
|
2284
2365
|
**RBAC**:沙箱 Role 要有 `persistentvolumeclaims` 的 `get` / `create` / `delete` / `deletecollection`(回收按标签删 = `deletecollection`;chart 与 cluster 静态清单 7.126.0 起已带)。
|
|
2285
2366
|
**能力位**:`GET /v1/capabilities.workspaceSync.cache = { mount, size }`,present-iff k8s 车道 ∧ `WORKSPACE_CACHE=volume`(与快照存储无关:没配存储而开了卷的部署,
|
|
@@ -2345,9 +2426,10 @@ e2b SDK 自己的建命令握手另有一界(缺省 60 s),比命令的界早时
|
|
|
2345
2426
|
**有显式超时时这两只旋钮不参与**:调大不会让一条带超时的 Bash 跑得更久,调小也不会更早切它 —— 要更早切就给命令更短的超时。
|
|
2346
2427
|
|
|
2347
2428
|
切断时报的是真正触发的那一界:活性切断的句子是 `no output for <N> s — cut off by the exec liveness bound (set K8S_LIVENESS_MS or give the command an explicit timeout)`
|
|
2348
|
-
(e2b 点名 `E2B_LIVENESS_MS`)
|
|
2349
|
-
|
|
2350
|
-
|
|
2429
|
+
(e2b 点名 `E2B_LIVENESS_MS`)。**错误码按触发的那一界**(7.132.0 起,引擎 7.52.0 的码表两种超界两个词):静默切断报 `liveness_no_output` 并带窗口秒数
|
|
2430
|
+
(Bash 工具结果是 `livenessNoOutput: true` / `noOutputSec: N`,模型读到「no output for N s」—— 不是「调大超时」的提示),墙钟到点报 `timeout`(`timedOut: true` /
|
|
2431
|
+
`timeoutSec: N`,「Command timed out after <N>s」)。7.129.1–7.131.x 两种切断同报 `timeout`、靠句子区分。e2b 上建命令卡住被那只 60 s 握手切掉、或沙箱中途死掉时,
|
|
2432
|
+
这一发仍以 `timeout` 码回来(那是供应商自己的界,不是本服务的两只界)。host 车道没有活性界(命令只受调用方的超时,缓冲 exec 不带超时时受 `HOST_COMMAND_TIMEOUT_MS`)。
|
|
2351
2433
|
ssh / adb / local-docker 三条车道的流式调用同读这一条律:没有车道活性界,只受自己说的静默界 `readTimeoutMs` 约束,到点的切断句与 host 同一句
|
|
2352
2434
|
(`no output for <N> s — cut off by the command's own idle bound (readTimeoutMs)`);`readTimeoutMs` 为 `0` / 负数 / 非数不算说了界。
|
|
2353
2435
|
|
|
@@ -2509,23 +2591,39 @@ WebSearch 工具的 `tool_result` 错误文本,回到模型的对话里,**不是
|
|
|
2509
2591
|
这纯粹是**客户端约定**,本仓不读取、不校验、也不感知任何这类客户端侧 env 命名(这条命名事实来自任务书,
|
|
2510
2592
|
本车未读 cli 源码核实,列入收车档「未闭环」)。
|
|
2511
2593
|
|
|
2512
|
-
### 9.5b `settings.hooks`
|
|
2594
|
+
### 9.5b `settings.hooks` 的 matcher:提交时判什么、拒什么(7.126.0 起良性设置的结局只取决于配置)
|
|
2513
2595
|
|
|
2514
2596
|
`PreToolUse` / `PostToolUse` / `PostToolUseFailure` 三个工具事件的 `matcher` 按调用派发到的工具的 **wire 名**匹配(不是别名)。**新提交**(`POST /v1/runs` · `/v1/tasks` · `/v1/tasks/stream`;续跑重放不判)
|
|
2515
|
-
对每只 matcher
|
|
2597
|
+
对每只 matcher 做判断,下面四种情形都答 **`400 request.field_invalid`**,体带 `field: "settings.hooks"` 与 `detail`,按 `detail.reason` 分形(闭集,穷举读):
|
|
2516
2598
|
|
|
2517
2599
|
| `detail.reason` | 触发 | `detail` 其余键 | 怎么改 |
|
|
2518
2600
|
|---|---|---|---|
|
|
2519
2601
|
| `dead_alias` | matcher 选中某个工具的别名、却选不中它的正名(钩子永不命中) | `event` · `alias` · `canonical` | 改成正名(`ListPeers` → `ListAgents`) |
|
|
2520
2602
|
| `over_budget` | 正则形 matcher 的一次求值在 `1 000 ms` 内没有结束(灾难回溯) | `event` · `groupIndex`(该事件下第几组,从 0 起)· `budgetMs` | 改成工具名列表(`A\|B`),或去掉嵌套重复的正则写法(如 `(.*)*`) |
|
|
2521
|
-
| `
|
|
2603
|
+
| `budget_exceeded`(7.132.0 起) | 这次提交里所有已完成的正则形求值的耗时之和超过受理总额度 `5 000 ms`(每只都在单次额度之内,但合起来太慢) | `event` · `groupIndex`(越线的那一组)· `totalMs` | 把慢的 matcher 改成工具名列表(`A\|B`)或简化正则;正则形 matcher 越少越好 |
|
|
2604
|
+
| `invalid_regex` | 正则形 matcher 编不过(如 `(`、`[Read`);**写在任一契约事件上都判**(7.132.0 起;此前只判三个工具事件) | `event`(任一契约事件)· `groupIndex` | 修正则,或改成工具名列表(`A\|B`);matcher 没有用处的事件(如 `Stop`)直接去掉这个字段 |
|
|
2522
2605
|
|
|
2523
|
-
|
|
2524
|
-
|
|
2606
|
+
`detail` 恒带坐标 `path`(7.132.0 起;matcher 四形 = `["hooks", <event>, <组下标>, "matcher"]`;串段与 `key` 过拒句回显口径:剥控制与双向字符、截到 64 字 + `…`)。**配置本身读不出**的拒(7.132.0 起同带 `field: "settings.hooks"` + `detail`,句子骨架不变):
|
|
2607
|
+
|
|
2608
|
+
| `detail.reason` | 触发 | `detail` 其余键 |
|
|
2609
|
+
|---|---|---|
|
|
2610
|
+
| 契约分类器的码(`guard-entry-invalid` 等十一词,连字符拼法) | 分类器整份拒(一块可能藏着守卫钩子)或要剔掉一块(提交面不剔、整份拒) | `path`(那一块)· `key`(那一块上让它坏的键,点得出时) |
|
|
2611
|
+
| `unsupported_entry_type` | 本服务不执行的条目类型(`mcp_tool`) | `path`(那一条的 `type`)· `type` |
|
|
2612
|
+
| `over_cap` / `too_long` | 服务侧上限:组数 16、一个事件的条目总数 32(`path` 指第一条超出的条目)、命令 / URL 8192 字、header 32 个 / 合计 8192 字、`allowedEnvVars` 32 个 | `path` · `count` · `cap` |
|
|
2613
|
+
| `unnamed_refusal` | 分类器说拒却一块都没点名(契约漂移,fail-closed) | `path` |
|
|
2614
|
+
|
|
2615
|
+
- **预算有两层**:① 每只 matcher、每次求值各一份(`1 000 ms`)—— 不共享、不随同一份设置里 matcher 的多少缩水,这一份不读钟;② 一次受理的总额度(`5 000 ms`,7.132.0 起)—— 所有已完成的正则形求值的耗时之和,
|
|
2616
|
+
超过它就拒(`budget_exceeded`)。字面形(`A|B`)与非工具事件不进求值、不占总额度。良性 matcher 的求值是微秒到毫秒级,两层都给了数个数量级的余量(一份最大的良性配置 —— 3 个工具事件 × 16 组 —— 总耗时在毫秒级),
|
|
2617
|
+
所以良性设置的结局只取决于设置本身:机器忙闲不会让它一次 400、一次 202;只有求值总耗时逼近 `5 000 ms` 的病态设置才可能落在边界两侧。灾难回溯(指数级)用任何预算都跑不完。
|
|
2618
|
+
多只 matcher 时按配置顺序(事件 → 组)遇到的第一只被拒的定结局。一次受理最坏占用事件循环 ≤ 总额度 + 一次求值的额度(此前没有总界)。
|
|
2525
2619
|
- **为什么超时是拒绝、不是放行**:运行期每次工具调用都用同一个函数匹配 matcher、没有预算;一只在提交时都求不完的 matcher 放进去,会让之后每次工具调用卡住。
|
|
2526
|
-
- 拒句点名是**哪一只** matcher(`settings.hooks.<event>[<groupIndex>].matcher`):`over_budget`
|
|
2620
|
+
- 拒句点名是**哪一只** matcher(`settings.hooks.<event>[<groupIndex>].matcher`):`over_budget` 一形带预算、`budget_exceeded` 一形带总额度、都不回显 matcher 原文;`invalid_regex` 一形回显 matcher 原文与编译错误句(各截 200 字符,`detail` 不带这两段)。
|
|
2527
2621
|
- **这一判只在 hooks 会被采纳的车道上执行正则**(单用户车道;多租户车道 `settings.hooks` 整只被忽略,只做不执行正则的字面判):多租户部署不会因此多出一个在提交线程上跑调用方正则的面。
|
|
2528
|
-
- 不变的:matcher 超 `8 192` 字符不读(照旧受理,运维侧记一笔 `server.hooks.matcher-unjudged`)
|
|
2622
|
+
- 不变的:matcher 超 `8 192` 字符不读(照旧受理,运维侧记一笔 `server.hooks.matcher-unjudged`)。
|
|
2623
|
+
- **编不过的正则与事件无关**(7.132.0 起):写在 33 个契约事件里的哪一个上都 `400`(上表第四行)—— `StopFailure` 的 `error` 词、`PreCompact` / `PostCompact` 的 `trigger` 词、`SessionStart` 等事件,以及 matcher 被忽略的 `Stop` / `UserPromptSubmit` / `PostToolBatch`。
|
|
2624
|
+
7.126.0–7.131.x 只判三个工具事件,别的事件上同一串被受理:读 matcher 的引擎事件(`StopFailure` / `PreCompact` / `PostCompact`)运行期该组静默不跑(只落 `hook_matcher_invalid` 日志),壳跑的事件处置归壳。
|
|
2625
|
+
「选中别名而选不中正名」(上表第一行)仍只属三个工具事件。
|
|
2626
|
+
续跑重放不判:存量里的坏 matcher 照旧采纳 —— 读 matcher 的引擎事件上那一组不跑(记 `hook_matcher_invalid`),**matcher 被忽略的 `Stop` / `UserPromptSubmit` / `PostToolBatch` 照旧跑条目**。多租户车道(`settings.hooks` 整只被忽略)不判。
|
|
2529
2627
|
|
|
2530
2628
|
### 9.5c `settings.hooks` 的 `http` 钩子:header 里的环境变量展开(7.126.0 起与壳同一只读法)
|
|
2531
2629
|
|
|
@@ -2537,6 +2635,16 @@ WebSearch 工具的 `tool_result` 错误文本,回到模型的对话里,**不是
|
|
|
2537
2635
|
- 置空(名单外 / 凭据名)时日志一行 `hook_http_header_env_blanked`(名字与原因,不带值)。
|
|
2538
2636
|
例:`"headers": { "Authorization": "Bearer ${HOOK_TOKEN}" }`、`"allowedEnvVars": ["HOOK_TOKEN"]`,并在请求 `settings.env` 里给 `HOOK_TOKEN`。7.125.x 及更早的读法不同(升级见 MIGRATION)。
|
|
2539
2637
|
|
|
2638
|
+
### 9.5c-bis `settings.hooks` 的执行模型与时限(7.132.0 起)
|
|
2639
|
+
|
|
2640
|
+
- 被采纳的 `settings.hooks`(单用户车道)在引擎里是**一张**扩展注册,名字 `settings.hooks`(`wiring_manifest.mods[]` 里看得到它;
|
|
2641
|
+
审批卡 `allowRuleShadowed` 的 `hook` 成员、钩子失败时模型读到的拒句都点名它)。本部署自己另挂两张只观察的注册:恒挂的拒绝计量
|
|
2642
|
+
`server.permission-denied-meter`,`TOOL_TRACE=true` 时的 `server.tool-trace`(品牌部署另有一张提示装配站上的 `server.brand-identity`,只答品牌行 overlay,不在工具门上)。观察者的判词不采纳,链里唯一的答者是请求的钩子。
|
|
2643
|
+
- 每个事件的语义与此前相同:`Stop` 条目在主任务结束与委派子代结束时都跑;`PermissionDenied` / `SubagentStop` / 两个 model-switch 事件属壳,服务端不跑。
|
|
2644
|
+
- **`HOOKS_TIMEOUT_MS`** = 这张注册每个 handler 的时间预算(一个事件跑一遍本请求的钩子条目);**未设 = 600000 ms**(单条命令超时上限即 600 s);
|
|
2645
|
+
`0` 按字面(零预算)。超预算:`PreToolUse` 上该调用被拒(fail-closed,拒句点名 `extension "settings.hooks"`)、`UserPromptSubmit` 上该提交被拒,其余事件跳过这一轮钩子。
|
|
2646
|
+
单条命令自己的超时(`timeout`,上限 600 s)与一个事件 120 s 的墙钟(到点不再起下一条)照旧。
|
|
2647
|
+
|
|
2540
2648
|
### 9.5d MCP 服务器 http 传输的身份头:`principalHeader` 与 `assertionHeader` 二选一(请求体与部署声明同一种读法)
|
|
2541
2649
|
|
|
2542
2650
|
`mcpServers[].transport`(`kind:"http"`)上有两个「用哪个头送身份」的可选键,**只能设一个**:`principalHeader`(runner 把该任务已认证的终端用户 principal 注入这个头)与 `assertionHeader`(托管连接器断言所用的头**名**)。
|
|
@@ -2544,6 +2652,32 @@ WebSearch 工具的 `tool_result` 错误文本,回到模型的对话里,**不是
|
|
|
2544
2652
|
- `assertionHeader` 的**值**是头名,本服务不铸、也不校验具体词(只判是字符串且与 `principalHeader` 互斥);头名由引擎(上游)定为 **`connector-assertion`**(无 `x-` 前缀;引擎发送座落地后本服务只认这一个值),条目填别的名 ⇒ 连接器侧 401。
|
|
2545
2653
|
- 本版只承载、不发送断言:声明了 `assertionHeader` 的 server 照常挂载,但不带断言头;每台这样的 server 一行 info `mcp_assertion_header_not_sent`(`server` / `note`)。探测口 `POST /v1/capabilities/mcp/probe` 对声明了该键的条目整条拒 `400 request.field_invalid`(探测不拨一份少了断言头的配置)。
|
|
2546
2654
|
|
|
2655
|
+
### 9.5e 请求体 `mcpServers` 的列表与条目键:写坏,整份新提交 400(7.131.0 起;列表级与词表外的键 7.132.0 起;`startupTimeoutMs` 的值形由引擎在拨号时判,见本节首段)
|
|
2656
|
+
|
|
2657
|
+
条目的受理键 = `name` · `transport` · `allowTools` · `toolAxes` · `toolFaces` · `contentOrigin` · `elicitation` · `source` · `startupTimeoutMs`(7.132.0 起)(`transport` 的子键:`kind` · `command` · `args` · `env`(stdio),`kind` · `url` · `headers` · `principalHeader` · `assertionHeader`(http))。**新提交上每个键只有一只判官;除 `startupTimeoutMs` 外,判官在受理口,写坏的答案只有一种**(下面第一条:400)。`startupTimeoutMs`(这一只 server 自己的启动界,毫秒整数)的判官只在引擎里(引擎包根没给读口),受理口不判它的值形、原样交给引擎:数字串 / 小数 / 越界 ⇒ 请求照常 **200**,引擎拨号时**只拒这一只 server**(`config.mcp_startup_timeout_invalid`,兄弟照挂)。下面各条说的「写坏 ⇒ 400」是对其余受理键:
|
|
2658
|
+
- **新提交**(`POST /v1/tasks` · `/v1/tasks/stream` · `/v1/runs`):键在场却判不出形 ⇒ `400 request.field_invalid`,拒句形如 `mcpServers[2].allowTools (server "crm") is not a usable declaration — must be an array of strings (omit the key to leave the server's tools unrestricted) — got a string of 4 characters. …`:点名 `mcpServers[i].<键路径>`、server 名与该键判官的原因句,**整份请求不收** —— 不挂一半、不丢声明、不默认。原因句不回显声明的值,有几处例外,回显只有一只口径(剥控制与双向字符、截到 64 字、超出加 `…`):server 名(含写坏的 `name` 值,另报送来的原长度)、`contentOrigin` 词表外的值、`toolFaces` 点名的工具名;`toolAxes` 点名的工具名在引擎写的原因句里,由引擎截长(80 字);`transport.url` 的值从不回显:它常带凭据。可选键**缺席**永远合法(真「没声明」),必填的 `name` / `transport` 缺席同样 400;在场的 `null` 不是缺席。与单用户 / 多租户无关。列表本身同一条律(7.132.0 起,先于条目判):`mcpServers` 在场却不是数组、超过 32 条(整份拒,不挂前 32 条)、某一条不是对象 ⇒ `400 request.field_invalid`,拒句点名 `mcpServers` 或 `mcpServers[i]` 与形的种类;条目层或 `transport` 层出现词表外的键 ⇒ `400 request.body_shape`,拒体带 `unknownKeys`(全路径、至多 20 条)。`mcpServers` 缺席或为 `null` = 没声明,照常受理。
|
|
2659
|
+
- **耐久 resume 重放存量请求**:不拒(拒会把升级前 park 的任务永久卡死)。写坏的 `name` · `transport` 的 `kind`/`command`/`url` · `allowTools` · `toolAxes` · `toolFaces` ⇒ 这一条 server 整条不进,运维 warn `mcp_injection_dropped`(`reason: malformed_entry`,`field` 点名)并投用户面通告 `mcp.injection_dropped`(其中 `toolAxes` 在一次性迁移 M19 的窗开着时先按升级前读法重读一次,过了就挂,见上文 `toolAxes` 一节);写坏的 `contentOrigin` · `elicitation` · `source` · `transport` 的 `args`/`principalHeader` 与词表外的键 ⇒ 丢掉那一个键、server 照挂;`transport` 的 `env`/`headers`(名 → 串记录)对 JSON 存体按 7.131.x 的读法交:有值不是串的成员 ⇒ 整键不交,只有 `__proto__` 名的成员坏 ⇒ 剔掉它、其余照交;server 照挂,一行运维 warn `mcp_transport_members_dropped` 点名(见 9.5c-bis 同段);条目不是对象 ⇒ 这一条不进(`malformed_entry`);超过 32 条 ⇒ 第 33 条起只记 `over_cap`;整只不是数组 ⇒ 整只忽略 + 运维 warn `mcp_injection_ignored`。
|
|
2660
|
+
- `POST /v1/capabilities/mcp/probe` 问的是新提交那**同一只判官**:上面每一形同码同句(含 `unknownKeys`),拒之前零拨号;判官受理的申报,探测口拨的就是一条任务提交会交给引擎的那一份(判官的合法归一照收)。它多出的两形:本口的体就是这份列表,`mcpServers` 缺席或为 `null` ⇒ `400 request.body_shape`(缺必需字段);声明了 `transport.assertionHeader` 的条目 ⇒ `400 request.field_invalid`(见 9.5d:本版承载、不发送,新提交照挂,探测不拨一份少了断言头的配置 —— 同一只谓词,后果按门分)。7.131.x 上本口另有一只判法(申报原文与读器产物逐字比),列表不是数组 / 条目不是对象答 `request.body_shape`。
|
|
2661
|
+
- 7.130.x 及更早:`allowTools` / `toolFaces` / `name` / `transport` 写坏 ⇒ 200 + 这条 server 不挂;`elicitation` / `source` / `transport` 的可选子键写坏 ⇒ 200 + 悄悄丢键。7.131.x 及更早:列表整只不是数组 ⇒ 200、整只忽略;条目不是对象 ⇒ 200 + 点名丢弃;超过 32 条 ⇒ 200、挂前 32 条;词表外的键 ⇒ 悄悄不读。升级后这些请求变 400:改对那个键(或删掉它)、把列表改成数组、删掉第 33 条起的条目。
|
|
2662
|
+
|
|
2663
|
+
### 9.5f 中心提示层:一种 wire 形、按场景挂段、品牌行与「无持久记忆」披露(7.132.0 起)
|
|
2664
|
+
|
|
2665
|
+
- **形**:中心层只有一种 —— 中心(web-admin)下发的 `prompts` 键与本地 `config.d/prompts.json` 读出的中心层都是 `{ schemaVersion: 2, artifact }`(`artifact` = 引擎 `buildPromptArtifact` 铸的发布形,
|
|
2666
|
+
`payload.schemaVersion: 3`)。判官一只:契约包 `EffectivePromptsWire` 先过,再交引擎 `verifyPromptArtifact`;任一不过 ⇒ **整份候选拒**(一个域都不应用,停在上一份好配置),
|
|
2667
|
+
`config_candidate_rejected` 点名 `prompts`,`errors` 是两处的原句。中心不带 `prompts` 键 = 不下发中心层(已采纳的撤下)。存储原文(`{ artifact }` / `{}` / 13.x 的 `{ bindings: [] }`)放上 wire 也整拒。
|
|
2668
|
+
- **本地 `config.d/prompts.json`**:`{ artifact?, workers? }`(`artifact` = 中心编辑器导出的 artifact 身份 `{ payload, artifactDigest }`);本地没有 worker 身份 ⇒ 恒用 `artifact`,
|
|
2669
|
+
`workers` 在场时起服与之后每次采纳一份变了的候选时各一行 `config_unread_key`(与 `config_unread_file` 同频;`key: "workers"`、`names` 点名条目;不判拒)—— 只写了 `workers` 的本地文件不下发中心层。
|
|
2670
|
+
带 `bindings` / `catalog` 的旧文件被契约包拒 ⇒ `npx @sema-agent/settings-schema migrate <config.d 目录>`。
|
|
2671
|
+
- **按场景挂段**:本服务把每个请求的场景名写进 `TaskSpec.promptBinding`;artifact 里按场景的段写 `when: { binding: { anyOf: ["code"] } }`(或 `noneOf`)。同一目标一条通用 `replace` 加一条
|
|
2672
|
+
场景 `replace` 时两条的条件必须互斥(通用那条 `noneOf: [场景]`),否则引擎拒整份 artifact。委派子代继承父任务的场景名。
|
|
2673
|
+
- **生效**:新会话(与顶层会话的每次压缩)采用中心源的当期候选,进行中的会话钉着它开始时那一份;采纳日志 `center_prompts_adopted { artifactDigest, sourceRevision }`。
|
|
2674
|
+
中心源启动恢复读到一份引擎拒的 / 读不出的副本 ⇒ 一行 `prompt_composition_warning`(`classification: "center-source-restore"`)。
|
|
2675
|
+
- **部署序**:web-admin 与本服务同一维护窗升级、先中心后服务;回滚同序(窗内两端互拒对方的形,停在 LKG)。
|
|
2676
|
+
- **品牌行**(`CONFIG_PROVIDER=local` 与 `run-local`):`default` / `code` 两场景的 role 层以 Sema 品牌行开头(部署座的一条 overlay,清单段 `sema/identity`);`code-review` / `scan` /
|
|
2677
|
+
中心声明的场景与委派子代不带。
|
|
2678
|
+
- **「本会话没有持久记忆」**:引擎判、引擎渲染(记忆面没挂 ∧ 名册不能持久 ∧ 不是委派子代)。本部署有引擎推断看不见的持久通道(MCP 记忆服务器、自定义写工具)⇒ `MEMORY_PERSISTENCE_CAPABLE=true`
|
|
2679
|
+
撤回这段披露;host 车道自动声明。
|
|
2680
|
+
|
|
2547
2681
|
### 9.6 trace 脱敏的射程:与出站请求体无关
|
|
2548
2682
|
|
|
2549
2683
|
🔴 **脱敏 ≠ 出站控制**:trace 脱敏(账本 / SSE / turns / 审批预览里的 `«redacted»` 标记)只作用于
|
|
@@ -2603,8 +2737,8 @@ docker 推送的鉴权走构建宿主上的 docker 凭据存储(`docker login`),
|
|
|
2603
2737
|
**`BAKE_ENV_ALLOW=NAME,NAME`。** 配方真要一枚密钥形 env(例如 build.sh 里自己做 registry 登录要 `REGISTRY_PASSWORD`,或
|
|
2604
2738
|
`git fetch` 的 askpass 读 `GIT_TOKEN`)⇒ 点名它,runner 把该键从本进程 env **原样**放回给每一只子进程组(部署方显式承担)。
|
|
2605
2739
|
与服务侧 `LSP_ENV_ALLOW` 同一只解析器、同一只放行谓词:
|
|
2606
|
-
- 形错(空段 / 尾逗号 / 非变量名形,如 `$NPM_TOKEN`、`a b`、`NAME=value` 整段贴入 / 点名任一只名单型旋钮)⇒ runner **拒启**,
|
|
2607
|
-
`bake_runner_fatal`
|
|
2740
|
+
- 形错(空段 / 尾逗号 / 非变量名形,如 `$NPM_TOKEN`、`a b`、`NAME=value` 整段贴入 / 点名任一只名单型旋钮 / 点名本服务自有凭据名,7.132.0 起)⇒ runner **拒启**,
|
|
2741
|
+
`bake_runner_fatal` 那一行点名旋钮与第几段,**不回显值**(自有凭据那一形带引擎拒白名单的同一句);
|
|
2608
2742
|
- 本进程环境里没有的名 ⇒ 起服一行 `config_env_entry_rejected`(只报序号)、不放行;
|
|
2609
2743
|
- 旋钮原文本身按凭据类对待,不进子进程;
|
|
2610
2744
|
- 生效名单(点到且环境里真有的名)见起服行 `bake_runner_start.envAllow`(只键名);
|
|
@@ -2968,7 +3102,8 @@ UPDATE session_policy_rev_mark SET rev = 0, gen = gen + 1 WHERE policy_key = '<w
|
|
|
2968
3102
|
|
|
2969
3103
|
一条什么都不拒的 deny 已经在库里时,会话属主自己删得掉(删它不算放宽)。
|
|
2970
3104
|
|
|
2971
|
-
**行自带文法戳。** 7.129.0 起每一行会话规则自带规则文法戳 `grammar`(
|
|
3105
|
+
**行自带文法戳。** 7.129.0 起每一行会话规则自带规则文法戳 `grammar`(写口判官盖引擎当前的文法:7.129.0–7.131.x 写下的行是 `1`,7.132.0 起写下的行是 `2`;
|
|
3106
|
+
早先写下的行保留自己的戳、引擎按它的戳读;店整只存、读回原样交出)—— `GET` / `PUT` 回包的 `rules` 与同步导出的
|
|
2972
3107
|
记录里多这一个键。客户端改规则时只写三只桶,不要把读回的 `rev` / `gen` / `grammar` 一起回传:带着 `rev` 却没有 `grammar` 的值引擎按存量行的文法(0)读,括号形 allow 条目答
|
|
2973
3108
|
`400 rules.inert_entry`(`reason: "earlier_grammar"`;出路在句子里);`grammar` 坏或比引擎新 ⇒ `400 rules.invalid_shape`(`field: "grammar"`)。
|
|
2974
3109
|
|
|
@@ -2977,11 +3112,13 @@ UPDATE session_policy_rev_mark SET rev = 0, gen = gen + 1 WHERE policy_key = '<w
|
|
|
2977
3112
|
`session_rule_row_retired_bucket`(`policyKey` / `sessionId` / `buckets`)。出路是在库里把那一行改写成上面的写法(`rev` / `gen` 不动),或删掉会话(删会话即删规则)。
|
|
2978
3113
|
同一次改名里每一行改写成当前文法的同一句话:没有戳的行是 7.128.x 写的,引擎按它存下时的文法读 —— 那种文法把 `toolAllow` 的条目当整串工具名比,`Bash(rm:*)` / `Edit(src/**)` / `Bash(*)`
|
|
2979
3114
|
这类条目匹配不到任何工具、不放行任何东西,7.129.0 读成规则;引擎读成「名了不存在的工具」的 `toolAllow` 条目删掉,名单保持在场(删到空 = 什么都不放行,与升级前同判),其余条目原样,
|
|
2980
|
-
|
|
2981
|
-
|
|
3115
|
+
每一行盖当前文法的戳(7.129.0–7.131.x 盖 `grammar: 1`,7.132.0 起盖 `2`),`rev` / `gen` 不动。`toolDeny` 里的条目一个字节不动、不点名(deny 规则在两种文法下同义;7.128.x 上不拒,升级后拒),**唯一的例外**(7.132.0 起):`toolDeny` 里有引擎读成「不是任何一条规则」的条目(空串、`-deploy`、非 ASCII 名 ……)的行整行不改写、不盖戳,改名那一次起服各一条 warn `session_rule_row_unreadable_deny`(`policyKey` / `sessionId` / `toolDenyUnreadable`);这样的会话引擎每一次工具调用都拒,出路是 operator 用 `PUT /v1/sessions/:id/policy` 写一份读得出的新值,或删会话;同一行还带退役命令桶的(warn 多一键 `retiredBuckets`)`PUT` 读不了,只能在库里按新文法改写那一行(`rev` / `gen` 不动)或删会话。`toolAllow` 里的 `*`
|
|
3116
|
+
与别的读不出的条目同一条判(7.132.0 起):引擎在旧文法里把它读成什么都不放行的一条、名单其余照放(与 7.128.x 同),所以删掉、盖戳。7.129.0–7.131.x 的引擎把带 `*` 的名单整张读成作废,
|
|
3117
|
+
那几版的改名对这类行不改写、只点名 —— 那样留下的无戳行,7.132.0 起照上面这条读(`*` 不放行、其余照放),要它按新文法生效就 `PUT` 写回。有被删条目的行改名那一次起服各一条 warn `session_rule_row_old_grammar_entries`
|
|
2982
3118
|
(`policyKey` / `sessionId` / `toolAllowDropped`),之后不再报;被删的条目要按新文法生效,升级后 `PUT` 写回。改写在它下面跑的那一拍列叫
|
|
2983
|
-
`rule_entries_old_grammar`,改完才改成 `rule_entries`:起服在改写中途或其后的任何一步(终名改名、扫描、后续迁移)失败 ⇒
|
|
2984
|
-
`one_time_migrations_interrupted`
|
|
3119
|
+
`rule_entries_old_grammar`,改完才改成 `rule_entries`:起服在改写中途或其后的任何一步(终名改名、扫描、后续迁移)失败 ⇒ 拒因带本次起服已提交的全部读数(7.132.0 起每一条一次性迁移
|
|
3120
|
+
同一只收据账:各步的计数、落定了的形读数、有被删条目的行与已删的规则行),起服日志先打 `one_time_migrations_interrupted`(读数键与 `one_time_migrations_applied` 同名)与逐行的那几种
|
|
3121
|
+
(`session_rule_row_old_grammar_entries` 等)再抛(这些收据只在改写发生的那一拍的起服日志里出现,请保存;下一次起服不再有;只盖戳的改写不记);
|
|
2985
3122
|
失败或被杀时列停在进行中的名,下一次起服续改;回滚时从那个名改回(`grammar` 对旧版是一个它不读的多余键)。
|
|
2986
3123
|
|
|
2987
3124
|
**升级与回滚。** 7.128.x 及以前的副本按整串工具名读规则,读不懂 `Bash(rm:*)` 这类条目。改名之后它们在这只库上找不到规则列:还在跑的旧副本读写规则的请求失败、会话任务起不来,
|