@sema-agent/server 7.117.0 → 7.118.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 +97 -0
- package/USAGE.md +37 -18
- package/dist/approval-card.d.ts +40 -10
- package/dist/approval-card.js +11 -1
- package/dist/approval.d.ts +4 -12
- package/dist/approval.js +4 -26
- package/dist/boot/parked-revive-gate.d.ts +1 -7
- package/dist/boot/parked-revive-gate.js +2 -12
- package/dist/boot/resolve-spec.js +8 -13
- package/dist/boot/runner-deps.js +2 -2
- package/dist/boot/stage-07-capability-layer.js +2 -2
- package/dist/capabilities/hands-lane.d.ts +25 -0
- package/dist/capabilities/hands-lane.js +1 -1
- package/dist/capabilities/mcp-probe.d.ts +2 -2
- package/dist/config.d.ts +14 -18
- package/dist/config.js +13 -24
- package/dist/deployment-governance.d.ts +2 -7
- package/dist/deployment-governance.js +3 -5
- package/dist/host-decision.d.ts +83 -25
- package/dist/host-decision.js +31 -1
- package/dist/http/admission.js +7 -1
- package/dist/http/approval-sweeps.js +1 -1
- package/dist/http/mcp-dial-deadline.d.ts +35 -0
- package/dist/http/mcp-dial-deadline.js +21 -0
- package/dist/http/memory-compliance-failure-reply.d.ts +11 -5
- package/dist/http/memory-compliance-failure-reply.js +17 -8
- package/dist/http/memory-store-refusal-reply.d.ts +14 -11
- package/dist/http/memory-store-refusal-reply.js +16 -5
- package/dist/http/resume-legs.js +7 -3
- package/dist/http/routes/approvals-assistant.js +21 -24
- package/dist/http/routes/capabilities.js +2 -0
- package/dist/http/routes/mcp-reconnect.d.ts +17 -0
- package/dist/http/routes/mcp-reconnect.js +6 -1
- package/dist/http/routes/memory-bundle.js +1 -1
- package/dist/http/routes/memory-compliance.js +1 -1
- package/dist/http/routes/memory-origin.js +1 -1
- package/dist/http/routes/runs.js +41 -33
- package/dist/http/routes/sessions.d.ts +1 -1
- package/dist/http/routes/sessions.js +3 -6
- package/dist/http/routes/workflows.js +2 -0
- package/dist/http/wire-types.d.ts +6 -1
- package/dist/memory-store-refusal.d.ts +42 -17
- package/dist/memory-store-refusal.js +25 -6
- package/dist/model-unreachable-notice.d.ts +1 -1
- package/dist/namespaced-rule-name.d.ts +45 -41
- package/dist/namespaced-rule-name.js +36 -22
- package/dist/observability/corrupt-read-seat.d.ts +4 -0
- package/dist/observability/corrupt-read-seat.js +1 -0
- package/dist/observability/fail-open.d.ts +14 -2
- package/dist/observability/fail-open.js +14 -2
- package/dist/operator-ask.d.ts +4 -1
- package/dist/orchestration/workflow-agent-session-index.d.ts +82 -59
- package/dist/orchestration/workflow-agent-session-index.js +80 -14
- package/dist/orchestration/workflow-completion-inbox.d.ts +5 -0
- package/dist/orchestration/workflow-completion-inbox.js +39 -17
- package/dist/orchestration/workflow-notify-journal.d.ts +1 -1
- package/dist/orchestration/workflow-notify-journal.js +7 -2
- package/dist/outbound-dispatcher.d.ts +29 -20
- package/dist/outbound-dispatcher.js +105 -16
- package/dist/parked-decide.d.ts +43 -48
- package/dist/parked-decide.js +54 -16
- package/dist/permission-rule-vocab.d.ts +4 -3
- package/dist/permission-rule-vocab.js +1 -1
- package/dist/plugins/approval-ask-store-sql.d.ts +17 -20
- package/dist/plugins/approval-ask-store-sql.js +0 -3
- package/dist/plugins/one-time-migrations.d.ts +5 -0
- package/dist/plugins/one-time-migrations.js +110 -4
- package/dist/plugins/pg-pool.js +1 -1
- package/dist/plugins/tidb-pool.js +1 -1
- package/dist/plugins/web-search.d.ts +20 -1
- package/dist/plugins/web-search.js +39 -10
- package/dist/plugins/workflow-run-store-sql.d.ts +7 -6
- package/dist/plugins/workflow-run-store-sql.js +5 -7
- package/dist/request-key-closure.js +1 -1
- package/dist/request-value-closure.d.ts +1 -1
- package/dist/rule-entry-list.d.ts +35 -46
- package/dist/rule-entry-list.js +17 -25
- package/dist/rules-consent.js +3 -0
- package/dist/run-local.js +1 -0
- package/dist/runs.d.ts +1 -1
- package/dist/session-policy-wire.d.ts +13 -12
- package/dist/session-policy-wire.js +11 -6
- package/dist/spec-fields.d.ts +7 -9
- package/dist/spec-fields.js +4 -7
- package/dist/standing-answer-grant.d.ts +14 -2
- package/dist/standing-answer-grant.js +8 -1
- package/dist/task-settings.js +8 -4
- package/dist/tool-approval.d.ts +53 -112
- package/dist/tool-approval.js +75 -55
- package/dist/trace/core-keyset-guard.d.ts +5 -5
- package/dist/trace/self-minted-wire.d.ts +16 -2
- package/dist/trace/self-minted-wire.js +7 -0
- package/dist/user-input-ledger.d.ts +24 -12
- package/dist/user-input-ledger.js +33 -14
- package/package.json +2 -2
- package/scripts/drain-check-local.mjs +74 -3
- package/scripts/drain-check.mysql.sql +43 -17
- package/scripts/drain-check.pg.sql +46 -20
package/MIGRATION.md
CHANGED
|
@@ -7,6 +7,103 @@
|
|
|
7
7
|
> ⚠️ 完整清单在仓库根 `CHANGELOG.md`——它**不随 npm tarball 出包**(本文件随包)。看完整迁移窗的
|
|
8
8
|
> 权威姿势是源码 tag diff:`git diff v<旧>..v<新>`(每版都推 `v<版本>` tag);npm 包页也镜像 CHANGELOG。
|
|
9
9
|
|
|
10
|
+
## 7.118.0 —— 审批决定体的出处位 `decidedBy`(取代 `settledBy`)· 能力位 `approvalDecidedBy` · 有审批名单却无检查点店的装配,任务提交一律 501
|
|
11
|
+
|
|
12
|
+
**审批决定体用一只键说「谁做的这个决定」**:`decidedBy?: "person" | "policy"`(缺席 = `"person"`)。三条工具审批决定口 ——
|
|
13
|
+
`POST /v1/tool-approvals/:approvalId/respond`、`POST /v1/tasks/:taskId/asks/:askId/decision`、`POST /v1/approvals/:sessionId/decide` ——
|
|
14
|
+
同一只读法收它;`"policy"` 让引擎把这次决定记在策略名下(`tool_end.gate.settlement.kind` = `policy_allowed` / `policy_refused`,
|
|
15
|
+
`who.party:"policy"`),**放行与拒两向都可以**(此前一次规则代答的放行只能记成 `human_allowed`)。
|
|
16
|
+
|
|
17
|
+
**要动的(发过 `settledBy` 的调用方)**
|
|
18
|
+
|
|
19
|
+
1. **`settledBy` 退役,改发 `decidedBy`**。7.93.3–7.117.x 的决定体上有一格 `settledBy?: "policy"`(只配 deny);它与 `decidedBy` 是同一个
|
|
20
|
+
事实,本版删掉,零别名。送它:三条决定口都 `400 request.body_shape`,拒在裁决之前、卡不动(live `/respond` 的句子点名 `decidedBy`)。
|
|
21
|
+
迁移 = 一处装配:`settledBy:"policy"` → `decidedBy:"policy"`;放行一向现在也可以带它。
|
|
22
|
+
2. **见位才发**:`GET /v1/capabilities` 的 `approvalDecidedBy`(恒 `true` 的版本位)在场才发 `decidedBy`。老 server 上耐久两口与
|
|
23
|
+
`/v1/assistant/tasks/:id/plan_review` 对它 400,live `/respond` 静默丢 + 200 —— 位缺席就照老形发。
|
|
24
|
+
3. **直连门部署**:耐久两口上带 `decidedBy`(不论值)⇒ `400 decided_by_not_in_proof`(它不在决策证明的签名载荷里);错误码
|
|
25
|
+
`settled_by_not_in_proof` 随退役键一起删。live `/respond` 照收。
|
|
26
|
+
4. **回滚到 7.117.x**:本版 live `/respond` 与耐久 ask 账口上 `decidedBy:"policy"` 的放行,落成 ask 账里一条「`decision = approve` + 来源位 `settled_by = policy`」的行;
|
|
27
|
+
7.117.x 的读法对放行行不读来源位,同一只 ask 回滚后被重入(故障切换 / 重启后重放)时把它读成**人**放行 —— 审计归属错,不多放权(放行本来就生效)。
|
|
28
|
+
要审计准确:回滚前让在途的审批都结掉 —— 流内的卡清零、停驻的审批卡决掉或取消(做法:回滚前停收新任务、等在跑的 run 全部结束;流内卡数 = `SELECT COUNT(*) FROM approval_ask WHERE state = 'STREAM_PENDING'`,停驻的 workflow 子代卡照下面「7.118.0 线」第 10 条数),没有还会被重入的 ask,就没有被读错的行。
|
|
29
|
+
|
|
30
|
+
**新的拒(按需处置)**
|
|
31
|
+
|
|
32
|
+
- 闭集外(含 `"sla_timeout"` —— 「等待到点、没人答」只有服务端自己的截止扫说得出;含旧词 `human` / `timeout` / 结算词 / 空串 / 非串)⇒ 400,
|
|
33
|
+
句子点名闭集:live `/respond` = `request.body_shape`,耐久两口 = `request.field_invalid`。拒在裁决之前,卡不动。
|
|
34
|
+
- 一张**要人**的卡(帧顶层 `requiresRealApproval` / 卡面 `risk.requiresRealApproval`)上 `decidedBy:"policy"` 的放行:live `/respond` =
|
|
35
|
+
`400 request.body_shape`,ask 决定口 = `400 request.field_conflict`(拒在裁决之前,卡不动);`/decide` = 引擎在 CAS 之前拒,
|
|
36
|
+
`409 resume_outcome_invalid` + `field:"hostDecision"`(卡留 pending)。改成人答,或以策略的名义拒。
|
|
37
|
+
- `plan_review` 不收 `decidedBy`(引擎的计划审阅结局没有决定者位)⇒ `400 request.body_shape`,落 `unsupportedKeys`。
|
|
38
|
+
- **有审批名单(`APPROVAL_REQUIRE` / `APPROVAL_NEVER_AUTO` / `APPROVAL_DENY` 任一非空)或显式 `DURABLE_APPROVAL=true`、而装配里没有检查点店** ⇒ 每个任务提交(含续跑腿)`501 capability.checkpoint_store_required`,
|
|
39
|
+
拒在一切副作用之前;句子点名缺的是耐久席位、怎么配。**只有自己装配 `resolveSpec` 的嵌入方会撞到**:`sema-server` 起服对同一形早就拒启(`DURABLE_APPROVAL=false` / `DB_BACKEND=memory`),到不了任务提交。
|
|
40
|
+
7.117.0 上这一形的装配读到的是静默放行(审批基线铸成 `undefined`,请求的 `settings.permissions.allow` 清掉普通问后任务零卡落盘)。出路:给装配一只检查点店(`DURABLE_APPROVAL=true` + 带检查点面的后端),或去掉名单;
|
|
41
|
+
单用户 turnkey(没有名单、没有显式旗)的 allow-all 基线不变。
|
|
42
|
+
|
|
43
|
+
**已知边界(老版本,升级决策知悉)**:≤7.115.x 的 `DB_BACKEND=local` 后端没有文件历史店 —— 会话同步的文件历史 blob 两口(`PUT …/sync/blobs/:hash` 恒 501、`GET …/sync/history/blobs/:hash` 对清单引用的 blob 恒 404 `not_found.blob`),而那一代的能力位 `sessionSync` 仍为真。7.116.0 起拆成独立位 `sessionSyncFileHistory`(local 为假):消费方以这一位为唯一读法,位缺席 / 为假 ⇒ 按「这台不搬文件历史」处置,不要照旧尝试。SQL 后端(两只文件历史店在场)自 7.52 起 blob 面可用,不受此条影响。
|
|
44
|
+
|
|
45
|
+
**订正 7.117.0 节的一行配方**:排空判据 `skill-deny-inert` 逐行精确核的 `node -e` 一行此前写成裸子路径 `import("@sema-agent/server/dist/rule-entry-list.js")`,而本包不导出 `./dist/*` 子路径(`ERR_PACKAGE_PATH_NOT_EXPORTED`);已改成按文件路径 import(7.117.0 节与仓内部署前提文档同步改)。 正确的一行(7.117.0 节正文保持发布时原样,照这里的跑):
|
|
46
|
+
`node -e 'import(process.argv[1]).then(m => console.log(m.skillDenyInertEntryOf(JSON.parse(require("fs").readFileSync(process.argv[2], "utf8")).body) ?? "ok"))' "$(node -p 'require.resolve("@sema-agent/server/package.json").replace(/package\\.json$/, "dist/rule-entry-list.js")')" ctx.json`(包不导出 `./dist/*` 子路径,所以按文件路径 import,`ctx.json` 作第二个实参),
|
|
47
|
+
|
|
48
|
+
**部署前提(拉配置中心的部署,升级决策知悉)**:7.114.0 起引擎按 `@sema-agent/settings-schema` ≥ 7 的形读中心下发的 `workers` 配置;中心仍发 6.x 形时**整份中心配置被拒**,起服回落 env 并 `ready:false`,之后每次刷新照拒(响亮,不静默套用旧形;本仓不为 6.x 形留第二种读法)。**先把中心升到 settings-schema ≥ 7(web-admin SS8 / 8.0.0 + M-R2),再把拉它配置的引擎升到 ≥ 7.114.0**;顺序反了就是上面那一形。7.114.0 节当时没写这一句,在此补。
|
|
49
|
+
|
|
50
|
+
### 7.118.0 线 —— `@sema-agent/core` 7.42.1 → 7.44.0:规则名只认引擎判官 · allow 侧名字层交引擎 · 技能规则拼法 `Skill(<名>)` · 请求键 `approvalReach` · 崩溃告知按车道分族 · 重放拒体带 `detail.differs`
|
|
51
|
+
|
|
52
|
+
**升级前必读**
|
|
53
|
+
|
|
54
|
+
1. **嵌入方 import 了引擎的旧名**:`USER_STEER_UNDRAINED_CAUSES` / `UserSteerUndrainedCause` 已改名 `USER_INPUT_UNDRAINED_CAUSES` / `UserInputUndrainedCause`(引擎 7.44.0,零别名;TS 编译红、JS 读到 `undefined`)。换新名,成员不变。
|
|
55
|
+
2. **规则里的工具名只认引擎的判官**。协议名的服务器段引擎铸不出 / 为空(`mcp__github.com__*`、`mcp__*`、`mcp__`):
|
|
56
|
+
- 运维名表(`APPROVAL_REQUIRE` / `APPROVAL_DENY` / `APPROVAL_NEVER_AUTO`、中心下发)与请求 `settings.permissions.ask` / `deny` 照旧拒,**句子换成引擎的**(带它铸出的写法);按旧句子匹配的脚本要改。
|
|
57
|
+
- 会话规则写口(`PUT /v1/sessions/:id/policy`、同步导入的 `policy` 面)对这一族的码由 `400 request.field_invalid` 改为 `400 rules.legacy_tool_name`(体顶层 `verdict: "unmintable_segment"`、`currentName` = 该写的名字(带通配的协议名上它是摘要名,见本节末「已知边界」),与 `field` / `name` 同层,不在 `detail` 里;第 6 条 steer 重放拒的 `detail.differs` 才是嵌套的)。库里已存的这种死 deny,属主自己的写现在删得掉。
|
|
58
|
+
- 工具段为空的协议名(`mcp__srv__`)照旧在每张表上拒,会话写口仍是 `request.field_invalid`。
|
|
59
|
+
3. **allow 侧的名字交引擎**:请求 `settings.permissions.allow` 与请求自带技能的 `allowedTools` 里写退役名 / 无前缀短名 / 铸不出的协议名(`bash`、`figma__x`、`mcp__*`)不再 422 / 400,
|
|
60
|
+
而是受理、开跑时收通告 `permission.allowed_tool_not_granted`(`reason: "tool_name"`,带 `currentName`)—— 这些条目从来什么都不授予,现在只是不在提交时拦。依赖「写错名字当场被拒」的调用方改读那条通告。
|
|
61
|
+
技能 `disallowedTools` 里的同一族仍是 400(判据换成引擎的条目读法,原因词 `tool_name`);`APPROVAL_GRANT` 里的同一族仍拒启。
|
|
62
|
+
**存量停驻体**里技能 `disallowedTools` 写了这一族(7.116.x 受理过的)⇒ 续跑认领之前 `409 resume_blocked_by_policy`(`blockedBy: request.field_invalid`)——
|
|
63
|
+
引擎 7.43 起这一类拒侧条目同样让那只技能不激活;随包排空判据 `skill-deny-inert` 同数它们,升级前照 7.117.0 节的做法排空。
|
|
64
|
+
4. **技能规则只有一种拼法**:`settings.permissions.ask` / `deny` 里 `Skill(<名>)`(精确)/ `Skill(<前缀>:*)`(名字前缀,无词界)现在受理并生效(此前 422);参数面拼法 `Skill(skill:<名>)` 现在 422。先改写再升。
|
|
65
|
+
持久规则(`/v1/rules`、导入)的 `match` 多两个词 `name` / `name_prefix`;回滚到 7.117.x 的副本读到这种行会把它当坏行。
|
|
66
|
+
5. **崩溃丢掉的 `priority:"later"` steer 报在 follow-up 一族**:进程崩溃后下一条 run 首拍的告知,`later` 档那几条现在是 `task.user_followup_undrained{followUp, cause:"crashed"}`(其余仍是 `task.user_steer_undrained`);
|
|
67
|
+
`GET /v1/sessions/:id` 的 `userInputUndrained[].kind` 多一个词 `"follow_up"`。按 `code` 写死只认 steer 一族、或按 `kind === "steer"` 过滤的消费方两码同读。回滚到 7.117.x:那几条 `follow_up` 行旧版本读不懂、不告知。
|
|
68
|
+
6. **`steering.duplicate_input_id` 的 409 体多一格 `detail.differs`**(`text` / `trusted` / `priority` / `actor` 的非空子集):含 `"text"` ⇒ 换键;不含 ⇒ 别换键重发(会排两次),用原值重放。句子是引擎的,已改。
|
|
69
|
+
7. **新请求键 `approvalReach`**(唯一一词 `"none"`;能力位 `approvalReach`):声明这条 run 上没有人能答审批 —— 有停驻设施的部署上第一次门控调用就停驻(`paused`),要「拒了接着跑」用 `permissionMode:"dontAsk"`。不发它的调用方零变化。
|
|
70
|
+
|
|
71
|
+
8. **升级那一刻还停驻着的 workflow 子代审批卡**:决定口答 `409 decide.workflow_parks_unreadable`(句子说成因是更早的引擎版本),卡仍 pending、什么都不投递。
|
|
72
|
+
出路:续跑体里 `runId` 那条 workflow run,它走到那张卡时写下自己的持有者位,之后再决即可。
|
|
73
|
+
引擎 7.17 之前写下、记录上根本没有 `parks` 的那一代:没有条目、持有不了任何东西 —— 同一张卡上有新引擎写下的持有者时照常交给它;只有它点名这张卡时答
|
|
74
|
+
`409 conflict.resume_context_unavailable`(体里不带 `runId`;出路同上,续跑发起它的那条 workflow run)。想省掉这一步:**升级前在旧版本的数据上**跑随包排空判据 `workflow-park-holder`
|
|
75
|
+
(SQL:`node_modules/@sema-agent/server/scripts/drain-check.mysql.sql` / `drain-check.pg.sql` 的那一段,期望 `hit_rows = 0`;local:`node node_modules/@sema-agent/server/scripts/drain-check-local.mjs`,
|
|
76
|
+
期望 `WORKFLOW-PARK-HOLDER rows=0`;命中行点名 workflow run),把这些卡先决掉。
|
|
77
|
+
9. **新码 `409 decide.workflow_park_forked`**(体带 `runIds`):同一条 workflow run 先后被续跑两次、两支都停在同一张卡上(判得出的前提是 park 指针索引齐;一枚竞争指针没写上时决定投给指针在的那一支;指针**写失败**那一形运维计数 `server.workflow-park-index.sync-failed`,**写记录与写指针之间崩溃**那一形不计数 —— 计数为 0 不等于分叉门完好)。重试不会好:续跑 `runIds` 里的一条再决。把未知 409 一律当「稍后重试」的客户端要加这一支。
|
|
78
|
+
`GET /v1/workflows/:id` 的 `parks[]` 条目多两位 `parkedBy` / `generation`(在场才有);钉过条目精确键集的探针要放宽。
|
|
79
|
+
10. **SQL 后端**:`workflow_agent_session` 主键改成 `(session_id, run_id)`,启动期自动改形(暂存表复制 + 原子换名,任何一步被打断下一次起服从暂存表续上、旧行不丢;启动日志 `one_time_migrations_applied` 的 `workflowParkIndexKey: "reshaped"` 记一次)。
|
|
80
|
+
按旧主键写过外部查询的运维:同一个 `session_id` 现在可以有多行。
|
|
81
|
+
**SQL 多副本整队一次切,不混跑**:先停光 7.117.x,再起 7.118.0。改形之后 7.117.x 副本对这张表 ——
|
|
82
|
+
PostgreSQL:**每一次写都失败**(它的 upsert 冲突目标是 `(session_id)`,新主键下没有这只唯一约束;新键本来就允许一个子会话多行,这只约束保不住)⇒ 经它停驻的 workflow 子代卡没有指针,决定口决不掉,要人续跑那条 workflow run;
|
|
83
|
+
TiDB / MySQL:写照常落(`REPLACE INTO` 按新主键落行,不再覆盖同一子会话别的 run 的行),读一个子会话时多行里取哪一行不定 ⇒ 续跑链 / 分叉上的卡经它可能决不掉。
|
|
84
|
+
两方言都有一瞬:整表复制到换名之间旧副本写进旧表的指针随旧表删掉。
|
|
85
|
+
**回滚到 7.117.x**:先排空 workflow 子代的待批卡 —— 在 7.118.0 的数据上跑随包排空判据 `workflow-park-holder`(SQL 两份文件的那一段,期望 `hit_rows = 0`;此时数出的就是全部待批的 workflow 子代卡,逐张决掉或取消发起它的任务);
|
|
86
|
+
停掉全部 7.118.0 副本后再跑一次确认仍为 0;然后 `DROP TABLE workflow_agent_session`(派生投影,7.117.x 起服按它自己的建表语句重建旧形);再起 7.117.x。不删这张表,PostgreSQL 上 7.117.x 对它的写全部失败。
|
|
87
|
+
11. **出网代理拒隧道约 2 s 终局**:代理有时拒隧道、几十秒内又恢复的部署,以前靠长阶梯熬过的 run 现在失败、要重提;没有恢复长阶梯的旋钮,升级前稳住代理。终局句以
|
|
88
|
+
`proxy authentication required (HTTP 407)` / `proxy forbids this destination (HTTP 403)` / `proxy refused the tunnel (HTTP <n>)` 开头(按 `[network] fetch failed (` 开头匹配的脚本改成在句内搜)。
|
|
89
|
+
12. **记忆作用域家必须是真目录**:软链(哪怕指向真目录)或文件形的家在每条碰到它的记忆路由上答 `409 memory.scope_home_not_directory`(此前平铺布局是 500 `internal.memory_control_plane_corrupt`)。
|
|
90
|
+
升级前 `find <记忆目录> -maxdepth 1 -mindepth 1 ! -type d` 核一眼;要换盘就挂载整个记忆目录。记忆的 409 句子不再带宿主路径(`memory.target_outside_store` 同):路径在运维 warn `memory_store_form_refused { code, path, form? }`。
|
|
91
|
+
|
|
92
|
+
13. **`ask` 规则卡上的「本会话放行」不再落记录**:`APPROVAL_REQUIRE`、`APPROVAL_NEVER_AUTO`、请求的 `settings.permissions.ask` 或存下的 ask 行铸的卡带 `rememberRefused: true`;
|
|
93
|
+
`allow_session` / `remember: "session"` 只批这一次(`rememberApplied: false`)。**升级前已落的「本会话放行」对 `APPROVAL_REQUIRE` 的卡失效**:每次照问(旧行还在豁免列表里、按名撤得掉,
|
|
94
|
+
只是不再压住名单门的问)。工具不该被问就从名单里拿掉;要自动批用 `APPROVAL_AUTO_BUDGET`。
|
|
95
|
+
14. **没有类集的卡不记**:引擎 7.37 之前写的停驻卡(server ≤ 7.108)没有类集,`remember: "session"` 在它们上面只批这一次。
|
|
96
|
+
15. **技能卡**带 `boundGrantDigest` 时,live「本会话放行」按同技能同清单记住;耐久 `remember: "session"` 仍不记技能卡 —— 停驻的技能卡在运维队列行 / 推送帧上带 `rememberRefused: true`,`/decide` 回执 `rememberApplied: false`;
|
|
97
|
+
活卡停驻之后(`tool_approval_complete` 带 `parked: true`)对它的迟到应答同样不记。`rememberRefused` 按应答路读:活的面与停驻的面各说自己那条路(契约「缺席的读法」表)。
|
|
98
|
+
|
|
99
|
+
**已知边界(升级决策知悉)**
|
|
100
|
+
|
|
101
|
+
- workflow 子代的审批卡,只要点名它的记录里有一条的 `parks` **条目坏形**(或这一位在场却不是列表),决定口对这张卡恒答 `409 decide.workflow_parks_unreadable`,
|
|
102
|
+
直到运维把那条记录(体里的 `runId`)的 JSON 修好;续跑解不开 —— 那条记录的指针不随任何后继记录消失。体里另带 `readableHolderRunId` 时,工作可以从那条记录续上。
|
|
103
|
+
引擎从不写坏形,这一形只来自存储层改写或手改。
|
|
104
|
+
- 规则里写了带通配的协议名(`mcp__*`、`mcp__git*__x`)时,拒句里引擎的改法指引说「its tools are named mcp__<一串摘要>__<tool>」—— 那串摘要不是任何服务器的名字,照写不生效;
|
|
105
|
+
会话规则写口拒体顶层的 `currentName` 在这一形上也是那个摘要名(本服务的拒句不再在句尾追加它)。写具体的服务器名即可(`mcp__<server>__*` / `mcp__<server>`)。指引句在后续引擎版本修正。
|
|
106
|
+
|
|
10
107
|
## 7.117.0 —— 2026-10-06
|
|
11
108
|
|
|
12
109
|
### 7.117.0 线 —— `@sema-agent/core` 7.41.2 → 7.42.1:「这个调用不用问」只有一个去处(引擎的 allow 层)· 升级前排空带 `settings.permissions.allow` 的停驻行 · `APPROVAL_GRANT` 语义变宽 · 卡面披露键改名 `allowRuleShadowed` · 部署 hook 回 `allow` 现在清问 · 能力位 `settings.permissions.allowLayer` · 通告码改名 · 新错误码 `config.image_invalid`
|
package/USAGE.md
CHANGED
|
@@ -172,7 +172,7 @@ WEB_SEARCH_PROBE_ON_BOOT=true # boot 期一次性真出网探活,
|
|
|
172
172
|
| env 键 | 类型 | 默认 | 缺席行为 | 坏值行为 |
|
|
173
173
|
|---|---|---|---|---|
|
|
174
174
|
| `WEB_SEARCH_PROVIDER` | 闭集(`brave`\|`tavily`\|`searxng`) | 无 | WebSearch 工具整体不装配(功能缺席,无 warn) | 三词之外的任何值 = 同缺席处理,不装配、不 warn(`webSearchConfigFromEnv` 的词表守卫 `isWebSearchProvider`)。**读面(S-382 起)**:`GET /v1/capabilities` 的 `webSearch.backend` 把这一格的生效值广告成闭集词(缺席/坏值都报 `"none"` —— 两者行为本就相同);端点/密钥/配额**不上 wire**,那些仍只在 operator 面 `GET /v1/config/catalog` |
|
|
175
|
-
| `WEB_SEARCH_API_KEY` | secret string | 无 | brave/tavily:后端仍会装配(装配只看 `PROVIDER`),**首次真实工具调用**时抛 `WEB_SEARCH_API_KEY is required for the <provider> provider`(`braveSearch` / `tavilySearch` 的首行守卫);searxng:本键无消费点 | 空串 /
|
|
175
|
+
| `WEB_SEARCH_API_KEY` | secret string | 无 | brave/tavily:后端仍会装配(装配只看 `PROVIDER`),**首次真实工具调用**时抛 `WEB_SEARCH_API_KEY is required for the <provider> provider`(`braveSearch` / `tavilySearch` 的首行守卫);searxng:本键无消费点 | 空串 / 纯空白同缺席。内容只有一条形律:**能当 HTTP 请求头值**(brave 放 `X-Subscription-Token`,tavily 放 `Authorization: Bearer <key>`;判的是实际发出去的那一串)。含换行 / NUL / 其它控制字符 / U+007F / U+00FF 以上字符等头不能携带的字符 ⇒ **拒启**(`config.web_search_invalid`,句 `env WEB_SEARCH_API_KEY must be usable as an HTTP header value (it contains a character an HTTP header cannot carry, such as a line break)`,**不回显值** —— 7.118.0 起;改前采纳,首次搜索时运行时抛的错误句带着整串明文)。判据就是运行时构造并发出请求头的那条流水线(Node 自带的两步:`Headers` 构造的归一化 + 发送层的字符表;不是另一张字符表):首尾空白(含换行)归一化后不剩,所以从密钥文件带出的尾随换行照收;searxng 不发鉴权头,但这一键照判(按裸 key)。出路:修好值,或不用这一键时 unset 它 |
|
|
176
176
|
| `WEB_SEARCH_ENDPOINT` | url string(brave 下 = 完整搜索 URL,可指向 Brave 兼容网关如 Nólë) | brave/tavily → 各自官方 API;searxng → 无默认 | brave/tavily:落官方 endpoint;searxng:**首次真实工具调用**时抛 `WEB_SEARCH_ENDPOINT (the SearXNG instance URL) is required for the searxng provider`(`searxngSearch` 的首行守卫) | 空串同缺席(compose 模板 `${WEB_SEARCH_ENDPOINT:-}` 铸的就是空串)。**不是 `scheme://host[:port][/path]` 形的绝对 URL ⇒ 拒启**(`searx.internal`、`localhost:8888` 这类少了 `scheme://` 的形都算;判据与模型路由 base URL 拒启同一只)。**带 userinfo ⇒ 拒启**(7.101.0 起,S-716:`https://user:pw@host/…`、只带用户名的 `https://user@host/…` 都算;判据 = WHATWG 解析后用户名或口令任一非空,与运行时 fetch 拒收含凭据 URL 的约束同一条,所以修前这一形起得来、每次搜索必抛;brave / tavily 的凭据走 `WEB_SEARCH_API_KEY`,searxng 腿没有凭据通道,带鉴权的实例需在前面放一层注入鉴权的反代)。拒启句带键名与机读码 `config.web_search_invalid`,**不回显值**(这一格可能带凭据) |
|
|
177
177
|
| `WEB_SEARCH_MAX_RESULTS` | number | `10` | 用默认 10 | 空串同缺席;**非数字或 < 1 ⇒ 拒启**(`config.web_search_invalid`;改前静默落默认 10);是数则向下取整,再夹到 `[1,20]`(设 999 被夹到 20 —— 夹紧不是形错) |
|
|
178
178
|
| `WEB_SEARCH_TIMEOUT_MS` | number(ms) | `10000` | 用默认 10000 | 空串同缺席;**非数字(`"30s"` 这类带单位的也算)或 < 1 ⇒ 拒启**(`config.web_search_invalid`;改前静默落默认 10000 —— 写了 30s 的运维实际拿到 10s);是数则向下取整,再抬到 ≥ 1000ms |
|
|
@@ -860,10 +860,10 @@ UNATTENDED_APPROVAL_POLICY=park
|
|
|
860
860
|
**「本会话不再询问」对引擎的问也生效(7.106.0 起)**
|
|
861
861
|
|
|
862
862
|
- 审批面 `POST /v1/approvals/:sessionId/decide {decision:"approve", remember:"session"}` 与活卡的 `allow_session` 记下的放行,两处兑现:
|
|
863
|
-
|
|
863
|
+
本服务自己的 `ordinary` 类问(`run_workflow` 问句、acceptEdits 的域外写)在它们自己的层上不再问;**引擎自己的问**(`default`
|
|
864
864
|
模式下的每一次写、证不了只读的 shell 命令)由服务的**审批席**(工具审批协调器)在下一次到达时代答。后一半要审批席在场:
|
|
865
865
|
`TOOL_APPROVAL_ENABLED` 开(多租户缺省关);不想要活卡(纯 park 部署)再配 `STREAM_ASK_WINDOW_MS=0`。
|
|
866
|
-
- 代答不到的:`APPROVAL_DENY` / 敏感路径守卫(是拒,不是问);`APPROVAL_NEVER_AUTO` 与耐久预算耗尽的问(「恒问人」,回执 `rememberApplied:false`);
|
|
866
|
+
- 代答不到的:`APPROVAL_DENY` / 敏感路径守卫(是拒,不是问);`APPROVAL_REQUIRE` 名单的问(`ask_rule` 类 —— 引擎的类表说 allow 层清不掉它,站着的答案同读;每次照问,回执 `rememberApplied:false`;要免问就把工具移出名单或开自动批额度);`APPROVAL_NEVER_AUTO` 与耐久预算耗尽的问(「恒问人」,回执 `rememberApplied:false`);
|
|
867
867
|
委派子代经父链继承到祖先席上的引擎问(引擎盖强制位,席依约不代答)。
|
|
868
868
|
|
|
869
869
|
**无人值守腿:`default` 模式 + 按类作答的审批席(7.109.0 起;S-934 / S-906)—— 没有旋钮**
|
|
@@ -893,8 +893,9 @@ APPROVAL_GRANT='mcp__figma__*,a2a__planner__*,Bash(git:*)' # 逗号分隔的 a
|
|
|
893
893
|
leader 没有请求体 —— 运维为自己接的服务器、自家信得过的命令,在这里写一次。
|
|
894
894
|
- **值形(与引擎的文法相同)**:工具名、`mcp__<server>__*` 或两段形 `mcp__<server>`、`a2a__<peer>__*`、`Bash(<命令>)` / `Bash(<前缀>:*)` 命令规则、
|
|
895
895
|
`Read(//<dir>/**)` 读目录。`auto` 模式下交出任意代码的条目(整只 shell、解释器 / 启动器前缀)交分类器判(引擎的剔除表)。
|
|
896
|
-
坏值 ⇒ **启动拒**(句子点名那一条、引擎给的原因词、怎么写):引擎读成空的条目(`*`、`mcp__*`、写路径形 `Edit(src/**)
|
|
897
|
-
|
|
896
|
+
坏值 ⇒ **启动拒**(句子点名那一条、引擎给的原因词、怎么写):引擎读成空的条目(`*`、`mcp__*`、写路径形 `Edit(src/**)`、域名形、带空白的名字;
|
|
897
|
+
7.118.0 起条目名也过引擎的判官 —— 退役名 / 无前缀短名 / 协议名服务器段铸不出读成 `tool_name`,句子带现名)、工具段为空的协议名(`mcp__srv__`)。
|
|
898
|
+
内容形里带逗号的规则写不进(这张表的分隔符就是逗号)。
|
|
898
899
|
- **永远清不掉的**:任何一层的 deny(`APPROVAL_DENY`、请求 / 会话规则的 deny、命令策略拒档、敏感写路径)、ask 规则(`APPROVAL_REQUIRE`、请求的 ask)、
|
|
899
900
|
`APPROVAL_NEVER_AUTO`、`MANUAL_MODE_SHELL_GATE=always`、写保护路径、治理、PreToolUse hook 的问、plan 模式。命中而清不掉时卡上带
|
|
900
901
|
`allowRuleShadowed: [{ member: "deployment", entries: [...] }]`。同一工具既在本键又在 `APPROVAL_REQUIRE` / `APPROVAL_DENY` ⇒ ask / deny 赢。
|
|
@@ -2055,7 +2056,7 @@ TOC 本地形)时被**采纳**;`REQUIRE_PRINCIPAL=true`(多租户)上一段**形
|
|
|
2055
2056
|
| 键 | 类型 | 必填 | 默认 | 形错(⇒ 400) |
|
|
2056
2057
|
|---|---|---|---|---|
|
|
2057
2058
|
| `provider` | `"brave"|"tavily"|"searxng"` | **是** | 无 | 缺席、不是字符串、或不是三词之一(大小写 / 首尾空白照旧归一)——一段 `settings.webSearch` 就是在点名目的地,认不出就 400 点名 `settings.webSearch.provider`(括号里只说哪一形:`it is missing` / `it is not a string` / `it is not one of them`,**不回显**收到的串 —— 7.101.0 起,S-716),**不**静默换成部署 env 的 backend(改前:整段丢弃、回落 env backend、不报错)。词表守卫与 env 腿**同一只** `isWebSearchProvider`;env 腿词表外是「不装配」(部署自己的缺席) |
|
|
2058
|
-
| `apiKey` | string(明文) | brave/tavily 建议带(缺了首次调用才报错,见下表);searxng 不读 | 无(不继承 env 的 `WEB_SEARCH_API_KEY`);空串同缺席 |
|
|
2059
|
+
| `apiKey` | string(明文) | brave/tavily 建议带(缺了首次调用才报错,见下表);searxng 不读 | 无(不继承 env 的 `WEB_SEARCH_API_KEY`);空串同缺席 | 不是字符串,或不能当 HTTP 请求头值(含换行 / NUL / 其它控制字符 / U+007F / U+00FF 以上字符等;判据 = 运行时构造并发出请求头的那条流水线,与 env `WEB_SEARCH_API_KEY` 同一只;7.118.0 起,句 `settings.webSearch.apiKey must be usable as an HTTP header value (it contains a character an HTTP header cannot carry, such as a line break)`,**不回显值**;改前采纳、首次搜索时运行时抛的错误句带着整串明文)。首尾空白(含换行)运行时会剥掉 ⇒ 照收 |
|
|
2059
2060
|
| `endpoint` | string | searxng 必需(缺了首次调用才报错);brave/tavily 可选覆盖 | 无(不继承 env 的 `WEB_SEARCH_ENDPOINT`);空串同缺席 | 不是字符串,或不是 `scheme://host[:port][/path]` 形的绝对 URL(`localhost:8888` 这类少了 `scheme://` 的也算),或带 userinfo(`user:pw@` / 只带 `user@`;7.101.0 起,S-716,句 `settings.webSearch.endpoint must not carry userinfo (user or user:password before the host)`,不回显值) |
|
|
2060
2061
|
| `searxngParams` | `Record<string,string>`(对象)或 `"name=value;name=value"`(字符串) | 否 | 无;空串 / 空对象同缺席 | 与 env `WEB_SEARCH_SEARXNG_PARAMS` 同一套文法:数组、数字、一段不是 `name=value`、名不是参数名(字母 / 数字 / `_` / `-` / `.`)、值为空或不是字符串、同名两次(句里只报第几项 `entry #N`,不回显名或值 —— 7.101.0 起,S-716)。⚠️ **未列入已发布的 `@sema-agent/sdk` 8.8.0 `SettingsWebSearch` 类型**(该接口只有 `provider`/`apiKey`/`endpoint`/`maxResults` 四键、无开放下标)——server 侧代码认这个键,但当前发布的 TS 类型接不到它;手写 JSON 请求体仍可以发,server 会照常解析(源码头注自述:字段和消费点先落地,配置录入面尚未跟上,是一笔尚未还清的既有债务) |
|
|
2061
2062
|
| `maxResults` | number | 否 | 10(与 env 同一 clamp,`[1,20]`,小数向下取整;999 夹到 20 不是形错) | 不是数,或 < 1(`"10"` 这种字符串也算) |
|
|
@@ -2086,8 +2087,8 @@ WebSearch 工具的 `tool_result` 错误文本,回到模型的对话里,**不是
|
|
|
2086
2087
|
工具在场 ⇔ 调用方的 per-request 配置被采纳(单用户车道)或调用方根本没带(用部署默认)。
|
|
2087
2088
|
|
|
2088
2089
|
**`apiKey` 明文与 env 槽边界**:server 收到的 `settings.webSearch.apiKey` 是**明文字符串**,没有任何服务端
|
|
2089
|
-
密钥槽位/引用间接——收到什么字符串就直接进 backend 闭包(判官 `judgeRequestWebSearch`
|
|
2090
|
-
见 `src/plugins/web-search.ts` 的 `WebSearchBackendConfig.apiKey` 字段注)
|
|
2090
|
+
密钥槽位/引用间接——收到什么字符串就直接进 backend 闭包(判官 `judgeRequestWebSearch` 只判「是不是字符串」与「能不能当 HTTP 请求头值」——后者见上表 `apiKey` 行,与 `WEB_SEARCH_API_KEY` 同一只判官、同一条消费路径,
|
|
2091
|
+
见 `src/plugins/web-search.ts` 的 `WebSearchBackendConfig.apiKey` 字段注)。明文字段的形状维持原样(不是引用、不是槽位名)。调用方(壳)如何在
|
|
2091
2092
|
自己机器上管理这份明文是调用方的事——例如 cli 壳侧的约定是在**调用方自己的环境**里按
|
|
2092
2093
|
`SEMA_WEBSEARCH_KEY_<PROVIDER>` 这样的命名空间存放每个 provider 的 key,由壳在本地读出后把明文塞进请求体;
|
|
2093
2094
|
这纯粹是**客户端约定**,本仓不读取、不校验、也不感知任何这类客户端侧 env 命名(这条命名事实来自任务书,
|
|
@@ -2175,8 +2176,8 @@ server 进程(HTTP 服务与 `run-local`)**所有走 undici 的出网跳**都认
|
|
|
2175
2176
|
范围按 undici 划:目标 `http:` **且**代理 URL 也是 `http:` 才走绝对 URL 形;`https://` 代理 + http 目标仍是 `CONNECT`。
|
|
2176
2177
|
🔴 **要知道的三件**:① **明文过代理**:http 目标的请求行与头(含发给网关的凭据头)以明文经过代理,代理看得到完整 URL 与头;要对代理保密,网关用 https(隧道里是密文)。
|
|
2177
2178
|
② 代理按 `CONNECT` 记账 / 鉴权、且不转发绝对 URL 形请求的部署(罕见):把该网关改成 https,或把它写进 `NO_PROXY`。
|
|
2178
|
-
③ **代理拒绝的读法**:`CONNECT` 腿上代理回非 200 ⇒
|
|
2179
|
-
**407(要求代理认证)
|
|
2179
|
+
③ **代理拒绝的读法**:`CONNECT` 腿上代理回非 200 ⇒ 下面「代理答了拒」那一条(短阶梯 + 按状态选的句子);绝对 URL 形里代理的回话是**普通 HTTP 响应**,分两种 ——
|
|
2180
|
+
**407(要求代理认证)同样读成代理答了拒**,根因 `proxy answered the request with HTTP 407`(407 按协议只可能来自代理,两条腿同一种终局;一个自己回 407 的源站是违约,也会被读作代理);
|
|
2180
2181
|
**403 等其余状态不是代理拒**:它与网关自己回的 403 在 HTTP 层原理上分不开(没有通用判别式),调用方读到一条普通 403 响应(「网关回了 403」),代理的 ACL 拒绝请对着代理自己的日志查。网关自己回的 401 / 403 照原样交给调用方,不会被读成代理拒。
|
|
2181
2182
|
- **`NO_PROXY` 语法 = undici 的**:逗号或空白分隔;`host` 精确匹配**且含其子域**;`.host` / `*.host` 后缀;`host:port` 限端口;整串 `*` = 全直连;
|
|
2182
2183
|
IPv6 写方括号形 `[fd00::1]`。**不支持 CIDR / IP 段**(`10.0.0.0/8`、`10.*` 都不生效):按 IP 访问的目标逐个列(可带 `:port`)。
|
|
@@ -2189,22 +2190,38 @@ server 进程(HTTP 服务与 `run-local`)**所有走 undici 的出网跳**都认
|
|
|
2189
2190
|
行为一致,只多回环直连。不设它也一样生效。
|
|
2190
2191
|
- **代理那一跳失败时怎么读**(Node 运行时):连代理的每一次拨号 —— 拒连、解析不了、超时、`https://` 代理自身的 TLS、收下连接就关、CONNECT 回
|
|
2191
2192
|
非 200 —— 失败时,引擎的终局句(与 `run_failed` 日志行)形如
|
|
2192
|
-
`fetch failed (via outbound proxy (from HTTPS_PROXY) ←
|
|
2193
|
-
租户可见的失败原因:**包装句**(`via outbound proxy (from <变量>)`)点明「经代理 +
|
|
2194
|
-
|
|
2193
|
+
`fetch failed (via outbound proxy (from HTTPS_PROXY) ← ECONNREFUSED)` / `… ← proxy answered CONNECT with HTTP 403)` —— 这句会进
|
|
2194
|
+
租户可见的失败原因:**包装句**(`via outbound proxy (from <变量>)`)点明「经代理 + 哪只变量」,`←` 之后**只有码**(`ECONNREFUSED` / `ENOTFOUND` /
|
|
2195
|
+
`UND_ERR_SOCKET` / `ERR_TLS_…` 等)或本服务自己写的无地址句子(`proxy answered … with HTTP <状态码>` / `proxy did not answer CONNECT within …`)—— **整句没有代理的
|
|
2196
|
+
host:port、没有 userinfo**:上游错误原文(`connect ECONNREFUSED 10.0.0.9:3128` 这类点名代理地址的句子)在代理那一跳上被收成码,不上 wire、不进 `String(err)`。
|
|
2197
|
+
**要地址去运维面**:运维日志 `outbound_connect_failed` 的 `proxyHop`(原句,含代理 host:port)与启动日志 `outbound_proxy` 行(display-safe 代理值);诊断面
|
|
2198
|
+
`GET /v1/diagnostics/wiring` 与用户通告仍只报变量名。直连失败不在此列(目标的地址本来就是失败原因的一部分)。代理拨号有一只
|
|
2195
2199
|
**从拨号起计的绝对期限** 10 s(= undici 连接阶段的缺省时限;连代理的 TCP / TLS 与 CONNECT 交换都算在内,代理中途吐字节也不续命)—— 到点
|
|
2196
2200
|
CONNECT 还没回完 ⇒ 根因 `proxy did not answer CONNECT within 10000 ms`、那条连接随之关掉;调用方先取消时请求当场结束,挂着的那次拨号同样
|
|
2197
|
-
|
|
2201
|
+
在期限内收口、不留连接。**一次拨号**失败当场收口、dispatcher 不在原地重连(代理收下连接就关也一样)—— 这说的是传输层的那一次请求;
|
|
2202
|
+
**run 层**还会按引擎的重试阶梯重发这次模型调用,阶梯长短由失败的形决定(见下一条)。隧道建好之后的失败(目标的 TLS、
|
|
2198
2203
|
目标的响应)不带这段前缀 —— 那是目标本身的事。**http 目标(绝对 URL 形)那一腿**:拨号失败(拒连 / 解析不了 / 超时 / 代理 TLS)同一个包装句、同一个 `proxyInUse`;
|
|
2199
2204
|
10 s 拨号期限与「CONNECT 回非 200」只属于 `CONNECT` 腿 —— 绝对 URL 形的请求发出之后就是普通请求,代理收下连接就关、中途断流、回 4xx(407 除外,见上一条③)都与目标自己的失败同形,不冠这段前缀。
|
|
2205
|
+
- **代理答了拒 = 确定的答案,短阶梯(7.118.0 起;Node 运行时)**:代理**回了话**而且是拒绝 —— `CONNECT` 回非 200(403 / 407 / 502 …),或绝对 URL 形那一腿回 407 ——
|
|
2206
|
+
代理那一跳的错误带引擎的确定性连接码 `ERR_PROXY_TUNNEL_REFUSED` 与代理说的状态码 ⇒ 引擎不再走长阶梯:缺省重试 2 次(≤1 s 退避,约 2 s 内终局),
|
|
2207
|
+
等待帧写 `proxy refused the tunnel, retrying briefly`,终局句以按状态选的一句开头 —— 407 `proxy authentication required (HTTP 407)`、
|
|
2208
|
+
403 `proxy forbids this destination (HTTP 403)`、其余 `proxy refused the tunnel (HTTP <n>)` —— 之后 ` — ` 接原来的失败链,形如
|
|
2209
|
+
`[network] proxy forbids this destination (HTTP 403) — fetch failed (ERR_PROXY_TUNNEL_REFUSED: via outbound proxy (from HTTPS_PROXY) ← proxy answered CONNECT with HTTP 403)`
|
|
2210
|
+
(整句仍无代理地址与凭据)。7.117.x 及以前这一形读不出,走满长阶梯(缺省 10 次重试、约 3 分钟)才终局,等待帧一直说「connection lost, reconnecting」。
|
|
2211
|
+
代理的状态码**不**当作模型服务商的状态发布(`terminal.detail` / `apiFailure.status` 不带它 —— 那些位说的是服务商回了什么)。
|
|
2212
|
+
**拨号失败**(拒连 / 解析不了 / 收下就关 / 静默到 10 s 期限 / 代理 TLS)不带这枚码,阶梯照旧由下面那枚码决定:拒连 / 解析不了确定、收下就关 / 静默 / TLS 不确定(长阶梯)。
|
|
2213
|
+
🔴 **谁受伤**:代理**短暂**拒隧道、几十秒后恢复(凭据轮换、策略推送中)的部署,以前靠长阶梯熬过去,现在约 2 s 就失败、要重跑。
|
|
2214
|
+
**补偿**:本版没有恢复长阶梯的旋钮 —— 引擎恢复它的座位(`deterministicConnectRetries` ≥ 重试上限)本服务没有接出来,`GATEWAY_MAX_RETRIES` 调小只会更早终局;
|
|
2215
|
+
出路是修好代理的策略 / 凭据后重跑。按 407 / 403 分支的消费方今天读句子里的 `(HTTP n)`;结构化的状态位引擎本版没有。
|
|
2200
2216
|
- **启动日志**:恰一行 `outbound_proxy`,`{httpProxy, httpsProxy, noProxy, loopbackDirect, runtime}`(代理值 display-safe;`httpsProxy` 是 https
|
|
2201
2217
|
目标**实际**走的那只,含回落)。配置目录 `GET /v1/config/catalog` 有 `HTTP_PROXY` / `HTTPS_PROXY` / `NO_PROXY` 三行(`limitsHttp` 组,回显同一份
|
|
2202
2218
|
display-safe 投影)。`/health` 与 fleet 公告**不**带代理信息。
|
|
2203
2219
|
- **建连失败时怎么读(7.108.0 / S-925;Node 运行时)**:任何一条出网请求在**建连时**就失败(码闭集:`UND_ERR_CONNECT_TIMEOUT` —— TCP + TLS 没在
|
|
2204
2220
|
传输层的建连时限内完成 / `ECONNREFUSED` / `ENOTFOUND` / `EAI_AGAIN` / `EHOSTUNREACH` / `ENETUNREACH`;可能出现在已建立连接上的
|
|
2205
2221
|
`ECONNRESET` / `ETIMEDOUT` 刻意不算)⇒ 三件,同一份事实:
|
|
2206
|
-
① **运维日志** 一行 `outbound_connect_failed { targetHost, code, proxyInUse, proxyReadAtMs, sinceBootMs, hint }` —— `proxyInUse` = 这一跳走的代理
|
|
2207
|
-
**变量名**(`HTTP_PROXY` / `HTTPS_PROXY`,不打值;直连 ⇒ `null`),`
|
|
2222
|
+
① **运维日志** 一行 `outbound_connect_failed { targetHost, code, proxyInUse, proxyHop?, proxyReadAtMs, sinceBootMs, hint }` —— `proxyInUse` = 这一跳走的代理
|
|
2223
|
+
**变量名**(`HTTP_PROXY` / `HTTPS_PROXY`,不打值;直连 ⇒ `null`),`proxyHop` = 只在这一跳走了代理时在场的**原句**(上游错误原文,含代理 host:port,凭据位已脱敏;
|
|
2224
|
+
这是代理地址在运行时失败里唯一的去处,wire 上没有),`proxyReadAtMs` = 代理变量被读进来的时刻(= 起服那一拍),`sinceBootMs` = 进程已跑多久
|
|
2208
2225
|
—— 两者一对照就知道「起服之后 VPN / 代理是不是换过」;全进程的出网都算(模型、中心、工具 …),每条失败的请求一行(重试各算一次)。
|
|
2209
2226
|
② **诊断面** `GET /v1/diagnostics/wiring` 的 `outbound` 段:`{ proxy: { http, https }, noProxy, loopbackDirect, proxyReadAtMs, lastConnectFailure }` ——
|
|
2210
2227
|
代理只报**名字**(哪只变量供的;`https` 在 `HTTPS_PROXY` 缺席时回落 `HTTP_PROXY`)、`NO_PROXY` 只报在不在,地址一个字节都不上本段;
|
|
@@ -2255,7 +2272,7 @@ server 进程(HTTP 服务与 `run-local`)**所有走 undici 的出网跳**都认
|
|
|
2255
2272
|
引用)。脚本不读 `~/.npmrc`:每条 npm 调用带临时 `--userconfig`,临时 npmrc 只写 `${NPM_TOKEN}` 引用、不写值;开头封口,`npm ci` 的安装脚本 /
|
|
2256
2273
|
构建 / pack-hygiene 测试拿不到任何凭据,只有 `npm publish` 那一个进程拿到 `NPM_TOKEN`(且带 `--ignore-scripts`)。令牌从不打印。
|
|
2257
2274
|
- **门 4 不再等 CI**(同一裁定):`scripts/post-publish-gates.sh` 的门 4 = 一个 45 min 的 npm 窗(公开 packument 上 `versions[<v>]` 在且
|
|
2258
|
-
`dist-tags.latest` 追平)。判决行 `GATES456 v=… rc4=… rc5=… rc6=… shasum=… elapsed=… ciTag=… ciMain=… tagRun=… mainRun=… why4
|
|
2275
|
+
`dist-tags.latest` 追平)。判决行 `GATES456 v=… rc4=… rc5=… rc6=… shasum=… elapsed=… ciTag=… ciMain=… tagRun=… mainRun=… why4=… chain=…`:既有十一键形状不变,末尾追加第十二键 `chain=<本轮标识>`(见下一条起链启动器);
|
|
2259
2276
|
CI 两腿(`ciTag` / `ciMain` / `tagRun` / `mainRun`)是**信息格**,不进 rc4、不进 why4;`why4` 只剩 `propagation_timeout`(rc4 非零)与 `-`(绿)。
|
|
2260
2277
|
自此门 4 常态首拍即绿,CI 两腿多半还在跑 ⇒ 常落 `unchecked:still-running`,如实。7.105.0 起(S-882 ③)CI 信息格见包后**读一次、不轮询**
|
|
2261
2278
|
(此前的有界轮询几乎恒白等 10 min 再落同一个 still-running):落了终态记 conclusion;还在跑 ⇒ `unchecked:still-running` + 一句 `gh run view <id>`
|
|
@@ -2353,7 +2370,9 @@ server 进程(HTTP 服务与 `run-local`)**所有走 undici 的出网跳**都认
|
|
|
2353
2370
|
**从表派生** —— 一门要一个新名字就登记进表,
|
|
2354
2371
|
启动器自动透传(7.104.0 手抄名单漏了 `DEEPSEEK_API_KEY` ⇒ 门 2.4 停链)。起链 shell 里表外的变量(含 core 名形黑名单不认的
|
|
2355
2372
|
`*_PASS` / `*_PWD` / `*_COOKIE`)一条都进不去;值经管道进 `env -i` 起的子 shell,不进任何 argv。远端三条 `GATE_*_TEST_URL` 由它显式传
|
|
2356
|
-
共享库(k3s8 NodePort)
|
|
2373
|
+
共享库(k3s8 NodePort)。链日志按版本追加:门 2 / 门 3.5 的行(`GATE2` / `PUBLISH`)只认起链之后新落的行;**判决行只认本轮标识** —— 启动器起链时铸 `<pid>-<epoch>`,经 `release.sh` 的第一个参数交给它起的 `post-publish-gates.sh`
|
|
2374
|
+
(第二个参数),判决行末键 `chain=` 带回,等待方只读 `chain=` 等于本轮标识的那一行。同版本重起链时,上一轮留下的 `post-publish-gates.sh` 迟到追加的判决行(落在起链偏移之后,按偏移认不出)、
|
|
2375
|
+
十一键老形、手跑的 `chain=-` 行都不是本轮的 —— 没等到本轮的行 ⇒ 退出码 1 并说没出现,不转述别轮的读数。手跑 `release.sh` / `post-publish-gates.sh` 不给标识 = `chain=-`。之后转述门 3.5 的 `PUBLISH` 行;release.sh 红而 tag 已在 ⇒ 立即收尾并指路 `publish-local.sh` + `post-publish-gates.sh`;
|
|
2357
2376
|
绿 ⇒ 等 `GATES456`(窗 = `GATE4_WINDOW_SEC` + 20 min)后转述 `GATE2` / `PUBLISH` / 判决行。退出码见脚本头注(0 = 全绿)。
|
|
2358
2377
|
- **wire 变更机器清单**(S-129 ③,7.105.0 起):`node scripts/wire-changes-server.mjs <version>` 生成 `wire-changes/server@<version>.json`
|
|
2359
2378
|
(形照 core 的 `wire-changes/core@<ver>.json`:`added` / `removed` / `changed` / `narrowed` + `closedSetMembers` + `breaking`)。源 = 契约附录
|
package/dist/approval-card.d.ts
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* 没有方法、没有捕获的行为。
|
|
22
22
|
*/
|
|
23
23
|
import { z } from "zod";
|
|
24
|
-
import { ALLOW_RULE_MEMBERS, READ_ROOT_CANDIDATE_DIR_MAX, type AskClass, type AskEvidenceAbsence, type AskRequest as CoreAskRequest, type PendingAction as CorePendingAction, type ReadRootGrantCandidate, type RuleOffer } from "@sema-agent/core";
|
|
24
|
+
import { ALLOW_RULE_MEMBERS, READ_ROOT_CANDIDATE_DIR_MAX, type AskClass, type AskEvidenceAbsence, type AskRequest as CoreAskRequest, type PendingAction as CorePendingAction, type ReadRootGrantCandidate, type RuleOffer, type SteerReplayFacet } from "@sema-agent/core";
|
|
25
25
|
import type { AskRow } from "./plugins/approval-ask-store-sql.js";
|
|
26
26
|
/** 模型自由文本(`sourceAgentName` / `delegation.agentName`)的限长(设计稿 §6.2)。设计 §3.1 把
|
|
27
27
|
* 「限长 + 脱敏」写成 **server 新增责任**(引擎无此层):spawning model 挑的名字是自由文本,
|
|
@@ -81,11 +81,13 @@ export declare const RuleOfferSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
81
81
|
kind: z.ZodLiteral<"single">;
|
|
82
82
|
rule: z.ZodString;
|
|
83
83
|
match: z.ZodEnum<{
|
|
84
|
+
name: "name";
|
|
84
85
|
path: "path";
|
|
85
86
|
exact: "exact";
|
|
86
87
|
prefix: "prefix";
|
|
87
88
|
wildcard: "wildcard";
|
|
88
89
|
subpath: "subpath";
|
|
90
|
+
name_prefix: "name_prefix";
|
|
89
91
|
}>;
|
|
90
92
|
command: z.ZodString;
|
|
91
93
|
}, z.core.$strict>, z.ZodObject<{
|
|
@@ -94,11 +96,13 @@ export declare const RuleOfferSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
94
96
|
kind: z.ZodLiteral<"command">;
|
|
95
97
|
rule: z.ZodString;
|
|
96
98
|
match: z.ZodEnum<{
|
|
99
|
+
name: "name";
|
|
97
100
|
path: "path";
|
|
98
101
|
exact: "exact";
|
|
99
102
|
prefix: "prefix";
|
|
100
103
|
wildcard: "wildcard";
|
|
101
104
|
subpath: "subpath";
|
|
105
|
+
name_prefix: "name_prefix";
|
|
102
106
|
}>;
|
|
103
107
|
command: z.ZodString;
|
|
104
108
|
segment: z.ZodString;
|
|
@@ -158,11 +162,13 @@ export declare const RuleOfferRawSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
158
162
|
kind: z.ZodLiteral<"single">;
|
|
159
163
|
rule: z.ZodString;
|
|
160
164
|
match: z.ZodEnum<{
|
|
165
|
+
name: "name";
|
|
161
166
|
path: "path";
|
|
162
167
|
exact: "exact";
|
|
163
168
|
prefix: "prefix";
|
|
164
169
|
wildcard: "wildcard";
|
|
165
170
|
subpath: "subpath";
|
|
171
|
+
name_prefix: "name_prefix";
|
|
166
172
|
}>;
|
|
167
173
|
command: z.ZodString;
|
|
168
174
|
}, z.core.$strip>, z.ZodObject<{
|
|
@@ -171,11 +177,13 @@ export declare const RuleOfferRawSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
171
177
|
kind: z.ZodLiteral<"command">;
|
|
172
178
|
rule: z.ZodString;
|
|
173
179
|
match: z.ZodEnum<{
|
|
180
|
+
name: "name";
|
|
174
181
|
path: "path";
|
|
175
182
|
exact: "exact";
|
|
176
183
|
prefix: "prefix";
|
|
177
184
|
wildcard: "wildcard";
|
|
178
185
|
subpath: "subpath";
|
|
186
|
+
name_prefix: "name_prefix";
|
|
179
187
|
}>;
|
|
180
188
|
command: z.ZodString;
|
|
181
189
|
segment: z.ZodString;
|
|
@@ -437,7 +445,7 @@ type ToolApprovalPark = Extract<CorePendingAction, {
|
|
|
437
445
|
kind: "tool_approval";
|
|
438
446
|
}>;
|
|
439
447
|
/**
|
|
440
|
-
* 🔴 **闭集词座的唯一窄读**(S-721 起 `mandate`;S-755 起 `origin`)——
|
|
448
|
+
* 🔴 **闭集词座的唯一窄读**(S-721 起 `mandate`;S-755 起 `origin`;S-1170 起 `classifierNoRuling` / `differs`)—— 一座一只成员筛,**名字是参数**(与
|
|
441
449
|
* {@link readParkRowTrueSeat} 同一条:一处解析,不是两只各写一遍的函数)。
|
|
442
450
|
* · `mandate`(core 7.32.0 #1092)—— 一问**站在哪一个 mandate 词上**(`mandated` 说「站在强制上」,本座说是 core
|
|
443
451
|
* `PERSISTED_RULE_MANDATES` 六词里的哪一个;core 只在强制位的**整因**是那一个词时铸 —— 治理 / hook / 祖先,或不止一个理由
|
|
@@ -446,6 +454,11 @@ type ToolApprovalPark = Extract<CorePendingAction, {
|
|
|
446
454
|
* · `origin`(core 7.5.0 [ref] 的 park 孪生座;S-755)—— **谁提的这一问**,core `ASK_ORIGINS` 闭集一词。读者:运维队列行读寄存行
|
|
447
455
|
* 孪生座 `PendingAction.tool_approval.origin`({@link parkRowFacts})。活卡帧**不经**本函数:它读引擎在门上刚盖好的
|
|
448
456
|
* `AskRequest.origin`(盖章点即 core 的筛点),照旧只过「非空串」形门(`tool-approval.ts` 帧键 `origin` 顶注)。
|
|
457
|
+
* · `classifierNoRuling`(core 7.43.0 #1353)—— 分类器没给判词的成因词,core `AUTO_MODE_FALLBACK_CAUSES` 闭集一词(筛 = `isAutoModeFallbackCause`)。
|
|
458
|
+
* 读者:活卡帧读 `AskRequest.classifierNoRuling`(`tool-approval.ts`);inbox 行读 core `CheckpointSummary` 已筛过的同名位、直投不经本函数。
|
|
459
|
+
* · `differs`(core 7.44.0 #1374)—— **载体是引擎拒 steer 重放那只错的 `detail`**(不是 ask 的三个载体之一),值是 core `STEER_REPLAY_FACETS` 的**非空子集**
|
|
460
|
+
* (core:「恒非空」;筛 = 本文件 {@link isSteerReplayDiffers},成员表取 core 常量)。读者:`runs.ts` 的 409 `steering.duplicate_input_id` 体(`detail.differs`)。
|
|
461
|
+
* 集外成员 / 空数组 / 非数组 ⇒ 按缺席(不铸 `detail`,码仍是契约)+ 计一次;detail 只报形名(`differs=<array>` —— 数组从不展开成员,见 {@link outOfSetDetail})。
|
|
449
462
|
*
|
|
450
463
|
* 什么时候经本函数 —— 一句话:**筛点在 core;server 只在「读的是持久层原字节、中间没有 core 投影」的地方亲手调 core 的那一只筛**。
|
|
451
464
|
* inbox 行读 core `CheckpointSummary.{mandate,origin}`(core `summarizeCheckpoint` 已用同一只 `isPersistedRuleMandate` / `isAskOrigin`
|
|
@@ -459,10 +472,12 @@ type ToolApprovalPark = Extract<CorePendingAction, {
|
|
|
459
472
|
* 只读值不调用值)。
|
|
460
473
|
*/
|
|
461
474
|
export declare function readClosedWordSeat<S extends ClosedWordSeat>(carrier: object, seat: S): ClosedWordOf<S> | undefined;
|
|
462
|
-
/**
|
|
463
|
-
type
|
|
464
|
-
/**
|
|
465
|
-
type
|
|
475
|
+
/** ask 载体上的闭集词座名:三个 core 载体上**同名**(`AskRequest` / 寄存行 `tool_approval` 臂 / `CheckpointSummary`)—— 任一处改名 / 退役 ⇒ 下面的围栏编译红。 */
|
|
476
|
+
type AskClosedWordSeat = "mandate" | "origin" | "classifierNoRuling";
|
|
477
|
+
/** 闭集词座的名 = ask 载体上的三座 + 引擎拒 steer 重放那只错的 `detail.differs`(载体不同、读法同一只)。 */
|
|
478
|
+
type ClosedWordSeat = AskClosedWordSeat | "differs";
|
|
479
|
+
/** 一座的值型:ask 三座 = core 寄存行上那一座的型(去掉可选位的 `undefined`);`differs` = core 闭集 `SteerReplayFacet` 的数组(core `detail.differs` 的型)。 */
|
|
480
|
+
type ClosedWordOf<S extends ClosedWordSeat> = S extends AskClosedWordSeat ? NonNullable<ToolApprovalPark[S]> : readonly SteerReplayFacet[];
|
|
466
481
|
/**
|
|
467
482
|
* 🔴 **S-934 ②(core 7.37.0 #1214)—— ask 类对的唯一窄读**:`askClass`(一问的类 = `classes` 的首员)与 `classes`(这一问属于的全部类,core
|
|
468
483
|
* `ASK_CLASSES` 序)。三个载体上同名:`AskRequest`(活卡帧 / 呈卡帧的卡读它)、寄存行 `PendingAction.tool_approval`(运维队列行经
|
|
@@ -600,11 +615,13 @@ export declare const ApprovalCardSchema: z.ZodObject<{
|
|
|
600
615
|
kind: z.ZodLiteral<"single">;
|
|
601
616
|
rule: z.ZodString;
|
|
602
617
|
match: z.ZodEnum<{
|
|
618
|
+
name: "name";
|
|
603
619
|
path: "path";
|
|
604
620
|
exact: "exact";
|
|
605
621
|
prefix: "prefix";
|
|
606
622
|
wildcard: "wildcard";
|
|
607
623
|
subpath: "subpath";
|
|
624
|
+
name_prefix: "name_prefix";
|
|
608
625
|
}>;
|
|
609
626
|
command: z.ZodString;
|
|
610
627
|
}, z.core.$strict>, z.ZodObject<{
|
|
@@ -613,11 +630,13 @@ export declare const ApprovalCardSchema: z.ZodObject<{
|
|
|
613
630
|
kind: z.ZodLiteral<"command">;
|
|
614
631
|
rule: z.ZodString;
|
|
615
632
|
match: z.ZodEnum<{
|
|
633
|
+
name: "name";
|
|
616
634
|
path: "path";
|
|
617
635
|
exact: "exact";
|
|
618
636
|
prefix: "prefix";
|
|
619
637
|
wildcard: "wildcard";
|
|
620
638
|
subpath: "subpath";
|
|
639
|
+
name_prefix: "name_prefix";
|
|
621
640
|
}>;
|
|
622
641
|
command: z.ZodString;
|
|
623
642
|
segment: z.ZodString;
|
|
@@ -676,8 +695,8 @@ export declare const ApprovalCardSchema: z.ZodObject<{
|
|
|
676
695
|
}, z.core.$strict>>>;
|
|
677
696
|
personalRuleDotsAbsent: z.ZodOptional<z.ZodCustom<AskEvidenceAbsence, AskEvidenceAbsence>>;
|
|
678
697
|
}, z.core.$strict>>;
|
|
679
|
-
askClass: z.ZodOptional<z.ZodCustom<"mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary", "mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary">>;
|
|
680
|
-
classes: z.ZodOptional<z.ZodArray<z.ZodCustom<"mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary", "mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary">>>;
|
|
698
|
+
askClass: z.ZodOptional<z.ZodCustom<"mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary", "mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary">>;
|
|
699
|
+
classes: z.ZodOptional<z.ZodArray<z.ZodCustom<"mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary", "mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary">>>;
|
|
681
700
|
fromSubagent: z.ZodOptional<z.ZodLiteral<true>>;
|
|
682
701
|
sourceTaskId: z.ZodOptional<z.ZodString>;
|
|
683
702
|
sourceAgentName: z.ZodOptional<z.ZodString>;
|
|
@@ -726,11 +745,13 @@ export declare const ApprovalCardEnvelopeSchema: z.ZodObject<{
|
|
|
726
745
|
kind: z.ZodLiteral<"single">;
|
|
727
746
|
rule: z.ZodString;
|
|
728
747
|
match: z.ZodEnum<{
|
|
748
|
+
name: "name";
|
|
729
749
|
path: "path";
|
|
730
750
|
exact: "exact";
|
|
731
751
|
prefix: "prefix";
|
|
732
752
|
wildcard: "wildcard";
|
|
733
753
|
subpath: "subpath";
|
|
754
|
+
name_prefix: "name_prefix";
|
|
734
755
|
}>;
|
|
735
756
|
command: z.ZodString;
|
|
736
757
|
}, z.core.$strict>, z.ZodObject<{
|
|
@@ -739,11 +760,13 @@ export declare const ApprovalCardEnvelopeSchema: z.ZodObject<{
|
|
|
739
760
|
kind: z.ZodLiteral<"command">;
|
|
740
761
|
rule: z.ZodString;
|
|
741
762
|
match: z.ZodEnum<{
|
|
763
|
+
name: "name";
|
|
742
764
|
path: "path";
|
|
743
765
|
exact: "exact";
|
|
744
766
|
prefix: "prefix";
|
|
745
767
|
wildcard: "wildcard";
|
|
746
768
|
subpath: "subpath";
|
|
769
|
+
name_prefix: "name_prefix";
|
|
747
770
|
}>;
|
|
748
771
|
command: z.ZodString;
|
|
749
772
|
segment: z.ZodString;
|
|
@@ -802,8 +825,8 @@ export declare const ApprovalCardEnvelopeSchema: z.ZodObject<{
|
|
|
802
825
|
}, z.core.$strict>>>;
|
|
803
826
|
personalRuleDotsAbsent: z.ZodOptional<z.ZodCustom<AskEvidenceAbsence, AskEvidenceAbsence>>;
|
|
804
827
|
}, z.core.$strict>>;
|
|
805
|
-
askClass: z.ZodOptional<z.ZodCustom<"mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary", "mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary">>;
|
|
806
|
-
classes: z.ZodOptional<z.ZodArray<z.ZodCustom<"mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary", "mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary">>>;
|
|
828
|
+
askClass: z.ZodOptional<z.ZodCustom<"mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary", "mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary">>;
|
|
829
|
+
classes: z.ZodOptional<z.ZodArray<z.ZodCustom<"mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary", "mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary">>>;
|
|
807
830
|
fromSubagent: z.ZodOptional<z.ZodLiteral<true>>;
|
|
808
831
|
sourceTaskId: z.ZodOptional<z.ZodString>;
|
|
809
832
|
sourceAgentName: z.ZodOptional<z.ZodString>;
|
|
@@ -976,6 +999,13 @@ export declare function buildRevokeFrame(batchId: string, askIds: readonly strin
|
|
|
976
999
|
* 竞争者;收敛是车2 的窗到期竞争者与车5 恢复扫描的职责)。
|
|
977
1000
|
*/
|
|
978
1001
|
export declare function buildReplayFrame(row: AskRow, nowMs: number): ApprovalRequestFrame | undefined;
|
|
1002
|
+
/**
|
|
1003
|
+
* S-1154 —— 持久行上那张卡**要不要人**:卡面 `risk.requiresRealApproval`(铸卡时取自引擎在 `AskRequest` 上盖的同一位,
|
|
1004
|
+
* {@link buildApprovalCard} 第三参)。读者 = 耐久 ask 回决口在裁决之前判「策略的放行」(`host-decision.ts` 的 `policyCannotAllow`)。
|
|
1005
|
+
* 🔴 读不出卡(`card_json` 形不合)⇒ **按要人读**(fail-closed):这一位只用来**拒**策略的放行,读坏的行上拒一次可以改成人答 / 策略拒
|
|
1006
|
+
* 再来;反方向(读坏当不要人)会让一次引擎终将拒掉的放行先落成一条宣称 approve 的行。
|
|
1007
|
+
*/
|
|
1008
|
+
export declare function storedCardDemandsAPerson(cardJson: unknown): boolean;
|
|
979
1009
|
/** {@link buildApprovalPreamble} 的返回形——帧 + 两个**计数**(调用方按自己的 logger 记 warn;本模块
|
|
980
1010
|
* 保持纯函数,不吃 logger:那会让一个 `build*` 捕获行为)。 */
|
|
981
1011
|
export interface ApprovalPreamble {
|
package/dist/approval-card.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { ALLOW_RULE_MEMBERS, ASK_EVIDENCE_ABSENCE_VALUES, MAX_RULE_TEXT_CHARS, READ_ROOT_CANDIDATE_DIR_MAX, isAskClass, isAskOrigin, isPersistedRuleMandate, screenAskClassMembers } from "@sema-agent/core";
|
|
2
|
+
import { ALLOW_RULE_MEMBERS, ASK_EVIDENCE_ABSENCE_VALUES, MAX_RULE_TEXT_CHARS, READ_ROOT_CANDIDATE_DIR_MAX, STEER_REPLAY_FACETS, isAskClass, isAskOrigin, isAutoModeFallbackCause, isPersistedRuleMandate, screenAskClassMembers } from "@sema-agent/core";
|
|
3
3
|
import { redactSecrets } from "./trace/redact.js";
|
|
4
4
|
import { recordFailOpen } from "./observability/fail-open.js";
|
|
5
5
|
import { PERSISTED_RULE_MATCHES, UNCOVERED_SEGMENT_REASONS } from "./permission-rule-vocab.js";
|
|
@@ -314,9 +314,15 @@ export function readClosedWordSeat(carrier, seat) {
|
|
|
314
314
|
recordFailOpen("server.approval-card.closed-word-out-of-set", `${seat}=${outOfSetDetail(raw)}`);
|
|
315
315
|
return undefined;
|
|
316
316
|
}
|
|
317
|
+
function isSteerReplayDiffers(v) {
|
|
318
|
+
const facets = STEER_REPLAY_FACETS;
|
|
319
|
+
return Array.isArray(v) && v.length > 0 && v.every((f) => facets.includes(f));
|
|
320
|
+
}
|
|
317
321
|
const CLOSED_WORD_SEAT_GUARDS = {
|
|
318
322
|
mandate: isPersistedRuleMandate,
|
|
319
323
|
origin: isAskOrigin,
|
|
324
|
+
classifierNoRuling: isAutoModeFallbackCause,
|
|
325
|
+
differs: isSteerReplayDiffers,
|
|
320
326
|
};
|
|
321
327
|
export function readAskClassPair(carrier) {
|
|
322
328
|
const askClass = "askClass" in carrier ? carrier.askClass : undefined;
|
|
@@ -520,6 +526,10 @@ export function buildReplayFrame(row, nowMs) {
|
|
|
520
526
|
approvalId: parsed.data.approvalId,
|
|
521
527
|
};
|
|
522
528
|
}
|
|
529
|
+
export function storedCardDemandsAPerson(cardJson) {
|
|
530
|
+
const parsed = ApprovalCardEnvelopeSchema.safeParse(cardJson);
|
|
531
|
+
return !parsed.success || parsed.data.card.risk.requiresRealApproval;
|
|
532
|
+
}
|
|
523
533
|
export function buildApprovalPreamble(rows, nowMs, replayMax) {
|
|
524
534
|
const frames = [];
|
|
525
535
|
let skipped = 0;
|
package/dist/approval.d.ts
CHANGED
|
@@ -52,7 +52,7 @@ export declare function singleUserAutoAcceptBaselineApplies(config: GateIntentVi
|
|
|
52
52
|
readonly requirePrincipal: boolean;
|
|
53
53
|
}): boolean;
|
|
54
54
|
/**
|
|
55
|
-
* 门意图**不可服务**的判据 —— 返回拒因(可服务 ⇒ `undefined`)
|
|
55
|
+
* 门意图**不可服务**的判据 —— 返回拒因(可服务 ⇒ `undefined`)。**全仓唯一一份**,三处调用、处置不同:
|
|
56
56
|
* · **boot**(`boot/stage-07-capability-layer.ts`):对装配完的整份 config 判,拒因 ⇒ **拒启**(全窗复审 D3-F1,
|
|
57
57
|
* HIGH;与 env 墓碑族同谱系)。v4.3.0 的轮询门形(APPROVAL_REQUIRE + DB backend + DURABLE_APPROVAL 未设)在
|
|
58
58
|
* 5.0.0 只剩 core 每任务 warn——**原先拦、现在放**(方向反转)。「留 undefined 让 core warn」对新配置是
|
|
@@ -60,6 +60,9 @@ export declare function singleUserAutoAcceptBaselineApplies(config: GateIntentVi
|
|
|
60
60
|
* · **热路径**(S-668 波 2 ④,`config-center/apply-effective.ts` 的审批组 stage):对**候选视图**
|
|
61
61
|
* (活配置 + 候选名单)判,拒因 ⇒ 审批组**整组拒**、活配置零变化、世代账停旧代。进程在跑,拒启不是选项;
|
|
62
62
|
* 而放行一份「没有 checkpoint 店可停车」的名单 = 单用户 auto-accept 基线仍在、名单静默不生效。
|
|
63
|
+
* · **每个任务的装配**(S-1144,`boot/resolve-spec.ts` 的 `resolveSpec` 头一道):对**活配置**判,拒因 ⇒ 请求 501
|
|
64
|
+
* `capability.checkpoint_store_required`。部署形到不了(boot 已拒启);可达的是嵌入方装配 / 直调 `resolveSpec`(自己递 ctx、没经 stage-07)。
|
|
65
|
+
* 修前这一形把审批基线静默铸成 `undefined`,请求的 allow 清「普通问」后任务零卡落盘 —— 同一条规则在起服层拒、在装配层静默 = 一事两读。
|
|
63
66
|
* `checkpointStorePresent` 是**部署事实**(本进程建没建出 checkpoint 店),不在 `ServiceConfig` 里 ⇒ 调用方显式递。
|
|
64
67
|
* 放这文件与 hasOperatorGateIntent/inv#2 同源(意图判据再漂要同时改两段)。
|
|
65
68
|
*/
|
|
@@ -134,17 +137,6 @@ export interface DurableAskOptions {
|
|
|
134
137
|
deny?: string[];
|
|
135
138
|
autoBudget?: number;
|
|
136
139
|
neverAuto?: string[];
|
|
137
|
-
/** Per-session approval-exemption probe ("本会话不再询问"): consulted ONLY for require-listed
|
|
138
|
-
* tools, AFTER deny/neverAuto (both always win) and BEFORE the budget path. Canonical-space toolName.
|
|
139
|
-
* A rejected promise is treated as NOT exempt (fail-closed → ask) at the call site below.
|
|
140
|
-
* 🔴 S-877 候裁 16:会话授权**两个读位、一只店、按问句的作者分**(收车档 ⑩ 16):本探针兑现**本仓自己的问**(名单门)
|
|
141
|
-
* —— 在它自己的层上「不问」,于是委派子代经父约束链继承到的同一问也不问;引擎自装的问(模式写门 / 形状层)由审批席
|
|
142
|
-
* (`ToolApprovalCoordinator.standingGrantSettles`)兑现。本探针**不能**退役:子代的继承问到达祖先审批席时 core 盖
|
|
143
|
-
* `mandated`(`ruleClearanceOf` 的 inheritedUnresolved / ancestorResolved 门),席的判据依约不退役它 —— 只有本层的
|
|
144
|
-
* 「不问」够得着继承链(钉 test/parked-decide-leg.test.ts「[候裁② 修]remember 全链行为」)。 */
|
|
145
|
-
exempt?: (canonicalToolName: string) => Promise<boolean>;
|
|
146
|
-
/** Audit hook — fired when an exemption short-circuits the ask (the `approval_exempted` log line). */
|
|
147
|
-
onExempted?: (canonicalToolName: string, rawToolName: string) => void;
|
|
148
140
|
}
|
|
149
141
|
export declare function createDurableAskPolicy(opts: DurableAskOptions): ToolPolicy;
|
|
150
142
|
//# sourceMappingURL=approval.d.ts.map
|