@sema-agent/server 7.99.0 → 7.100.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 +13 -0
- package/USAGE.md +75 -52
- package/dist/approval-ask-machine.d.ts +10 -0
- package/dist/approval-ask-machine.js +3 -0
- package/dist/approval-card.d.ts +74 -1
- package/dist/approval-card.js +41 -8
- package/dist/approval.d.ts +44 -20
- package/dist/approval.js +14 -6
- package/dist/boot/config-center.d.ts +16 -8
- package/dist/boot/config-center.js +39 -81
- package/dist/boot/execution-env.d.ts +1 -2
- package/dist/boot/execution-env.js +2 -2
- package/dist/boot/leader.js +12 -9
- package/dist/boot/memory-consolidation.d.ts +38 -0
- package/dist/boot/memory-consolidation.js +35 -0
- package/dist/boot/resolve-spec.d.ts +0 -1
- package/dist/boot/resolve-spec.js +4 -3
- package/dist/boot/runner-deps.d.ts +2 -2
- package/dist/boot/stage-05-execution-env.d.ts +1 -1
- package/dist/boot/stage-06-runners.d.ts +2 -2
- package/dist/boot/stage-06-runners.js +3 -3
- package/dist/boot/stage-07-capability-layer.d.ts +2 -3
- package/dist/boot/stage-07-capability-layer.js +6 -6
- package/dist/boot/stage-08-reapers.d.ts +3 -4
- package/dist/boot/stage-08-reapers.js +2 -2
- package/dist/boot/stage-09-leader.d.ts +2 -3
- package/dist/boot/stage-10-http-server.d.ts +2 -3
- package/dist/boot/stage-10-http-server.js +2 -2
- package/dist/capabilities/center-plugins.d.ts +14 -2
- package/dist/capabilities/center-plugins.js +13 -5
- package/dist/capabilities/hands-lane.js +2 -1
- package/dist/capabilities/scenarios.js +18 -5
- package/dist/capabilities/tool-defer.d.ts +2 -2
- package/dist/config-catalog.d.ts +2 -2
- package/dist/config-catalog.js +12 -13
- package/dist/config-center/apply-effective.d.ts +34 -39
- package/dist/config-center/apply-effective.js +100 -64
- package/dist/config-center/apply-ledger.d.ts +35 -16
- package/dist/config-center/apply-ledger.js +25 -18
- package/dist/config-center/facade.d.ts +11 -5
- package/dist/config-center/facade.js +1 -1
- package/dist/config-center/hot-keys-registry.d.ts +11 -4
- package/dist/config-center/hot-keys-registry.js +11 -7
- package/dist/config-center/restart-signal.d.ts +21 -14
- package/dist/config-center/restart-signal.js +16 -22
- package/dist/config-center/types.d.ts +3 -3
- package/dist/config-types.d.ts +22 -7
- package/dist/cross-session-settings.js +1 -1
- package/dist/host-lsp-manager.d.ts +29 -0
- package/dist/host-lsp-manager.js +14 -0
- package/dist/http/active-run-conflict.d.ts +2 -12
- package/dist/http/active-run-conflict.js +1 -6
- package/dist/http/admission.js +8 -0
- package/dist/http/resume-legs.d.ts +1 -1
- package/dist/http/resume-legs.js +14 -10
- package/dist/http/route-ctx.d.ts +2 -2
- package/dist/http/routes/approvals-assistant.d.ts +1 -1
- package/dist/http/routes/approvals-assistant.js +2 -2
- package/dist/http/routes/memory-compliance.js +5 -0
- package/dist/http/routes/memory-origin.js +5 -0
- package/dist/http/routes/sessions.js +6 -0
- package/dist/http/routes/tasks.js +7 -6
- package/dist/http/server.d.ts +6 -5
- package/dist/http/wire-types.d.ts +6 -3
- package/dist/leader/wire.d.ts +20 -12
- package/dist/leader/wire.js +7 -6
- package/dist/memory-layer-preflight.d.ts +46 -0
- package/dist/memory-layer-preflight.js +121 -0
- package/dist/memory-operator-faces.js +17 -1
- package/dist/observability/corrupt-read-seat.d.ts +21 -4
- package/dist/observability/corrupt-read-seat.js +31 -0
- package/dist/observability/fail-open.d.ts +8 -4
- package/dist/observability/fail-open.js +8 -4
- package/dist/observability/run-terminal.js +1 -0
- package/dist/observability/secret-env-scrub.d.ts +1 -0
- package/dist/observability/secret-env-scrub.js +1 -0
- package/dist/orchestration/workflow-completion-inbox.d.ts +31 -23
- package/dist/orchestration/workflow-completion-inbox.js +8 -3
- package/dist/plugins/approval-ask-store-file.d.ts +20 -2
- package/dist/plugins/approval-ask-store-file.js +21 -3
- package/dist/plugins/approval-ask-store-memory.d.ts +2 -0
- package/dist/plugins/approval-ask-store-memory.js +39 -13
- package/dist/plugins/approval-ask-store-sql.d.ts +24 -5
- package/dist/plugins/approval-ask-store-sql.js +27 -3
- package/dist/plugins/checkpoint-store-sql.d.ts +9 -3
- package/dist/plugins/checkpoint-store-sql.js +19 -2
- package/dist/plugins/local-checkpoint-store.js +2 -0
- package/dist/plugins/mailbox-store-sql.d.ts +7 -5
- package/dist/plugins/mailbox-store-sql.js +6 -4
- package/dist/plugins/permission-rule-store-file.js +3 -2
- package/dist/plugins/sql-json-column.d.ts +16 -3
- package/dist/plugins/sql-json-column.js +15 -4
- package/dist/plugins/web-search.d.ts +42 -22
- package/dist/plugins/web-search.js +141 -49
- package/dist/run-local.js +6 -5
- package/dist/runs.js +6 -5
- package/dist/runtime-governance.d.ts +50 -3
- package/dist/runtime-governance.js +5 -0
- package/dist/server-secret-env.d.ts +4 -2
- package/dist/task-settings.d.ts +1 -1
- package/dist/tool-approval.d.ts +107 -19
- package/dist/tool-approval.js +64 -15
- package/dist/trace/core-keyset-guard.d.ts +5 -5
- package/dist/trace/ledger-sink.js +2 -2
- package/dist/trace/project.d.ts +13 -0
- package/dist/trace/project.js +22 -5
- package/dist/trace/projection-drop.d.ts +2 -0
- package/dist/trace/projection-drop.js +6 -0
- package/dist/trace/sema-provenance.d.ts +4 -1
- package/dist/trace/sema-provenance.js +1 -1
- package/dist/trace/task-notification-facets.d.ts +65 -0
- package/dist/trace/task-notification-facets.js +31 -0
- package/dist/trace/wire-projection-faces.d.ts +3 -3
- package/dist/trace/wire-projection-faces.js +3 -3
- package/package.json +3 -3
package/dist/tool-approval.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { HostDecidedBy, HostSettledBy } from "./host-decision.js";
|
|
2
2
|
import type { IncomingMessage } from "node:http";
|
|
3
|
-
import { type AskRequest, type AskOutcome, type ReadRootGrantCandidate, type RuleOffer } from "@sema-agent/core";
|
|
3
|
+
import { type AskRequest, type AskOutcome, type CheckpointGate, type PendingAction, type ReadRootGrantCandidate, type RuleOffer } from "@sema-agent/core";
|
|
4
4
|
import { type CardRulePersisted, type RuleConsentLane } from "./rules-consent.js";
|
|
5
5
|
import { type DenialLimitFallback, type RuleOffersAbsence, type ApprovalRequestFrame, type ApprovalRevokeFrame, type RuleEvidenceProjection } from "./approval-card.js";
|
|
6
6
|
import { type ApprovalAskStore, type AskRow } from "./plugins/approval-ask-store-sql.js";
|
|
7
7
|
import type { ApprovalAskAuditSink } from "./approval-ask-audit-store.js";
|
|
8
8
|
import { type GovernanceAskMarks } from "./governance-ask-marks.js";
|
|
9
|
+
import { type GovernancePosture } from "./runtime-governance.js";
|
|
9
10
|
/** [ref]:审批 gate kind 闭集(core gateMatch 的 `human`/`irreversible_ask` ↔ outcome.gate "policy_ask")。
|
|
10
11
|
* 此前 7 份手写副本散在两只 checkpoint store 的数组/SQL 字面与 /decide 守卫——core 加审批味 kind 时
|
|
11
12
|
* 全部静默漂移。core 无导出词表(全大写导出面零命中,2026-08-09 亲验),属主落此;SQL IN 片段从
|
|
@@ -80,10 +81,11 @@ export type ParkedAskRedeem = (req: ParkedAskRedeemRequest) => Promise<{
|
|
|
80
81
|
* 一问身上与「站着的答案」有关的三个事实位 —— {@link standingAnswerMayRetire} 的全部入参。
|
|
81
82
|
*
|
|
82
83
|
* 🔴 **三格全必填布尔**,刻意不做 `?: true` 的「只记真」形:判据哪天多一位,每个读者都要当场编译红,
|
|
83
|
-
* 而不是漏传一格被静默读成 `false`(那是安全轴上的 fail-open)
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
* `
|
|
84
|
+
* 而不是漏传一格被静默读成 `false`(那是安全轴上的 fail-open)。读者各自从自己手里的形折成这三格,
|
|
85
|
+
* 然后交**同一只** {@link standingAnswerMayRetire}(判据只有一份,折法各归读者):
|
|
86
|
+
* · live 读侧取 `req` + 本地治理 peek;live 写侧取 pending 条目;
|
|
87
|
+
* · 耐久 `/decide` 腿(S-663 → NP-1,7.100.0)取 park 行,经 {@link parkRowStandingAnswerFacts}(三格全从行上读)。
|
|
88
|
+
* 本型**不绑** live 条目。
|
|
87
89
|
*/
|
|
88
90
|
export interface StandingAnswerFacts {
|
|
89
91
|
/** 本仓治理层(`AUTONOMY` / `commandPolicy` / shellGate / `SENSITIVE_WRITE_PATTERNS`)产的门。 */
|
|
@@ -94,20 +96,25 @@ export interface StandingAnswerFacts {
|
|
|
94
96
|
readonly mandated: boolean;
|
|
95
97
|
}
|
|
96
98
|
/**
|
|
97
|
-
* 🔴 **S-660 —— 会话级放行的唯一判据:站着的答案能不能退掉这一问。**
|
|
99
|
+
* 🔴 **S-660 —— 会话级放行的唯一判据:站着的答案能不能退掉这一问。** 纯谓词,三个读者:
|
|
98
100
|
* · **读侧**(`askBroadcast` 的会话授权短路):`true` 才可能由既有 grant 代答,否则往下走真出卡;
|
|
99
101
|
* · **写侧**(`finishRespond` 的 `grantable`):`true` 才可能把这张卡上的 `allow_session` 铸成 grant,
|
|
100
|
-
* 否则只放行这一次、`rememberApplied:false
|
|
102
|
+
* 否则只放行这一次、`rememberApplied:false`;
|
|
103
|
+
* · **耐久 `/decide` 腿**(NP-1,`http/resume-legs.ts` 的 remember 可记性):入参由 {@link parkRowStandingAnswerFacts}
|
|
104
|
+
* 从 park 行铸 —— `false` ⇒ 可记工具名 `null` ⇒ 放行本次、不落豁免、回执 `rememberApplied:false`。
|
|
101
105
|
* 两臂读同一份事实、说同一句话:一问若不许被记住的放行答掉,它的应答也不许变成一条记住的放行 —— 否则
|
|
102
106
|
* 同一只卡「重跑一遍」就被自己上一次的回答代答(test [ref] U1s-off 的真形)。
|
|
103
107
|
*
|
|
104
108
|
* **为什么三位是同一类**(「站着的答案退不掉的一问」):会话授权 = **上一次**应答记下的一揽子放行,不是对
|
|
105
109
|
* **这一次**调用的应答 —— 与持久 allow 规则同族,只是更短命(`askBroadcast` 短路处的注早已这么定性)。
|
|
106
|
-
* · `mandated`:core
|
|
107
|
-
* posture may retire it, only an answer to THIS call
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
110
|
+
* · `mandated`:core `PermissionResult` ask 臂 `mandated` 成员的文档。7.29.0 原句「no persisted allow rule and no standing
|
|
111
|
+
* posture may retire it, only an answer to THIS call」;**7.30.0 起 d.ts 已落 [ref] 澄清**(S-616 在 7.30.1 装树亲核):
|
|
112
|
+
* core `PermissionResult` ask 臂的 `mandated` 成员文档「no persisted allow rule and no STANDING ANSWER (a release remembered
|
|
113
|
+
* from an earlier call, at any scope, a session included) may retire it」,`AskRequest.mandated` 孪生句同义 ——
|
|
114
|
+
* 「从早先某次回答记住的放行,**任何 scope、会话级也算**」都是站着的答案。core `ruleClearanceOf` 的文档
|
|
115
|
+
* 「Allow rules silence the classifier's questions, never a mandated one」。它**不**绑
|
|
116
|
+
* 这一次调用的应答者(人、hook、部署的一揽子 `onAsk:"allow"` 席、mandate 表允许的活判定者 —— 同一句 d.ts 逐一点名)——
|
|
117
|
+
* 那一半本仓不动(见 `mandated` 帧键顶注)。本谓词行为对 7.29.0 零改(文档到货,判据本来就是这么读的)。
|
|
111
118
|
* · `requiresRealApproval`([ref]):更强的那条,连一揽子席也不得答,当然也不许记住的放行答。
|
|
112
119
|
* · `governanceForced`([ref]):运维治理层的门,客户端表态掀不掉;持久规则车道早已同判(`buildRuleLaneMaterial`)。
|
|
113
120
|
* 本谓词**不重推** core 的 `ruleClearanceOf` / `ruleMayClear`(core 刻意不导出:闸外重算拿不到同一份标记快照,
|
|
@@ -120,6 +127,37 @@ export interface StandingAnswerFacts {
|
|
|
120
127
|
* 存着落库那一刻的判定。何况行上本来就没有 `mandated`(耐久面不造孪生座)—— 读了也读不到。
|
|
121
128
|
*/
|
|
122
129
|
export declare function standingAnswerMayRetire(facts: StandingAnswerFacts): boolean;
|
|
130
|
+
/**
|
|
131
|
+
* 🔴 **S-663 → NP-1(7.100.0 合并复审 [ref] 交叉表 #2)—— 耐久 `/decide` 腿的 {@link StandingAnswerFacts}:从 park 行铸三位。**
|
|
132
|
+
* 纯投影,**不判**:判据是同一只 {@link standingAnswerMayRetire}(唯一读点 = `http/resume-legs.ts` 的 remember 可记性,
|
|
133
|
+
* `standingAnswerMayRetire(parkRowStandingAnswerFacts(…))`)。修前耐久腿自成一只谓词、只读 `ruleOffersAbsence` 一词,同一行上
|
|
134
|
+
* core 盖好的 `requiresRealApproval` 与治理出身都不读 ⇒ 那两类卡的 `remember:"session"` 照旧铸会话免询问,而 live 腿对同一张卡
|
|
135
|
+
* 答 `false`(两腿同一个问题、两份事实覆盖;两腿复审同报)。三格各自的来源(全在**这一条**已属主校验的载入行上,不另读):
|
|
136
|
+
* · `governanceForced` —— 行上的治理标:`gate.riskDescriptor.shellGateDoctrine` × 本部署治理姿态,经 **同一只**
|
|
137
|
+
* `governanceOriginOf`(`runtime-governance.ts`;运维队列 `projectPendingForWire` / 409 体同一个属主,不另判)。它在
|
|
138
|
+
* 本读者这里只**收窄**(失真两个方向的代价登记在 `governanceMandatesShellGateAlways` 顶注)。⚠️ 它**只覆盖 shell 门的
|
|
139
|
+
* `always` 档** —— live 腿的治理标来自进程内标记表(敏感写路径 / `commandPolicy` / `AUTONOMY` 内层策略 / shellGate 各档),
|
|
140
|
+
* park 行上唯一的取证格只有 `riskDescriptor.shellGateDoctrine`(见下方 🚧);
|
|
141
|
+
* · `requiresRealApproval` —— 行上 core 铸的那一位,经 `approval-card.ts` 的 {@link readRequiresRealApprovalSeat}(与运维
|
|
142
|
+
* 队列 `parkRowFacts` 同一只读法,`=== true`)。刻意**不**经 `parkRowFacts` 本身:那只展示投影顺手对 `ruleOffersAbsence`
|
|
143
|
+
* 的集外词计展示面 F 类 tag,而本读者对同一格是 fail-closed(S-663 codex r1 钉「权限面不计展示面 tag」);
|
|
144
|
+
* · `mandated` —— 行上**没有**这一位(core 7.30.1 `PendingAction` 无 `mandated`,#1079 候 7.31.0),只读得到强制的子集:
|
|
145
|
+
* `ruleOffersAbsence` 经三态窄读 {@link readRuleOffersAbsenceSeat},`"mandated"` **或读不出**(集外词 / 非串值,世代差)
|
|
146
|
+
* ⇒ `true`(fail-closed 不变:一个本仓不认识的新词可能正是一种强制因由)。
|
|
147
|
+
*
|
|
148
|
+
* 🚧 **剩余不对称两处**(耐久腿读得到的事实比 live 腿少,读不到的一律照旧可记):
|
|
149
|
+
* ① **`mandated` 孪生位(候 core #1079)**:一张强制卡若行上词为 `shadowed` / 缺席、又无 `requiresRealApproval` 与治理出身
|
|
150
|
+
* (非 Bash 工具 / 车道未武装 / 匿名部署上的规则强制 —— core 只在「车道武装 ∧ `Bash` ∧ 有 principal」时铸那一词,且
|
|
151
|
+
* `ruleClearanceOf` 的词序让 `persistedRuleShadowed` / `matchedAskRule` 先得 `"shadowed"`),本折法读不到它的强制。#1079 到货后
|
|
152
|
+
* 改的**只是 `mandated` 这一格**(改读行上那一位),谓词与调用点零改(`test/approval-exemption-http.test.ts` 的 🚧 格按 #1079
|
|
153
|
+
* 行形钉着);
|
|
154
|
+
* ② **非 shell 治理(候 S-707)**:治理位经 `governanceOriginOf` 只覆盖 shell 门 `always` 档;敏感写路径
|
|
155
|
+
* (`SENSITIVE_WRITE_PATTERNS`)、`commandPolicy`、`AUTONOMY` 内层策略产的门与 shellGate `classify` 档,park 行上没有取证格
|
|
156
|
+
* (live 腿靠进程内标记表,跨副本 / 重启后够不着),本折法读不到它们的治理出身。
|
|
157
|
+
*/
|
|
158
|
+
export declare function parkRowStandingAnswerFacts(pending: Extract<PendingAction, {
|
|
159
|
+
kind: "tool_approval";
|
|
160
|
+
}>, gate: CheckpointGate, governance: GovernancePosture | undefined): StandingAnswerFacts;
|
|
123
161
|
/** A live approval frame delivered to whoever tails this run's stream. `type` IS the SSE event name (named-event
|
|
124
162
|
* convention, same as question). The shell renders `tool_approval` as the CC three-choice card and dismisses on
|
|
125
163
|
* `tool_approval_complete`. */
|
|
@@ -186,6 +224,8 @@ export interface ToolApprovalFrame {
|
|
|
186
224
|
* 车道**有什么可给,而那条车道对它不说话的工具、**没接规则店的部署**(本仓的 live-only 形)、装不下规则的
|
|
187
225
|
* 任务都是结构性沉默 —— 它的缺席**不是**断言。本键是这一问**自己**的属性,凡强制皆在场。读错的代价 core
|
|
188
226
|
* 实测过:同一条根外读命令在 shell 工具上是强制问、在 monitor 工具上看起来是普通问。
|
|
227
|
+
* (唯一例外是**手里没有本键**的那条腿:耐久 `/decide` 腿只有 park 行,S-663 / NP-1 只读那一词的**在场**、从不读它的
|
|
228
|
+
* 缺席 —— 见 {@link parkRowStandingAnswerFacts},子集与剩余不对称写在那里。live 腿恒读本键。)
|
|
189
229
|
*
|
|
190
230
|
* 🔴 **它不是 `requiresRealApproval`**:强制只说「没有规则能清掉」,**不**说「没有应答者可以答」——
|
|
191
231
|
* 一个人、一只 hook、一张一揽子 `onAsk:"allow"` 席照常答得了强制卡。两键别互推。
|
|
@@ -684,6 +724,29 @@ export type RespondSettledBy = Extract<HostSettledBy, HostDecidedBy>;
|
|
|
684
724
|
* (`config.ts` 的解析腿,[ref] A 档)。
|
|
685
725
|
*/
|
|
686
726
|
export type UnattendedApprovalPolicy = "park" | "deny";
|
|
727
|
+
/**
|
|
728
|
+
* S-689 —— `deny` 政策下「无人可答」交给 core 的形:core `AskOutcome` 对象臂的**部署政策拒**
|
|
729
|
+
* (`settledBy:"policy"` ⇒ core 结算 `policy_refused`、`who.party:"none"`,模型读的是策略句)。
|
|
730
|
+
*
|
|
731
|
+
* 修前这里交**裸 `false`** —— 而在 core 的 onAsk 契约里裸 `false` 就是「一个人拒了」:结算记
|
|
732
|
+
* `human_refused` / `who.party:"person"`,模型被告知「用户不想继续,停下来等他」,run 以
|
|
733
|
+
* `haltedOnUserRejection` 收束。可这台部署自己声明了没有人会来 —— 拒的是它的政策。
|
|
734
|
+
*
|
|
735
|
+
* 型从 core 的 `AskOutcome` 对象臂**收窄**而不是另写一份(`settledBy` 取 core 那一格词表里的 `"policy"`:
|
|
736
|
+
* core 哪天退役这个词,这里编译期先红)。`reason` 必填:core 以 `policy note` 围栏把它交给模型,内容见
|
|
737
|
+
* {@link unattendedRefusalReason}。
|
|
738
|
+
*/
|
|
739
|
+
export type UnattendedPolicyRefusal = Extract<AskOutcome, {
|
|
740
|
+
allow: boolean;
|
|
741
|
+
}> & {
|
|
742
|
+
allow: false;
|
|
743
|
+
settledBy: Extract<HostSettledBy, "policy">;
|
|
744
|
+
reason: string;
|
|
745
|
+
};
|
|
746
|
+
/** 「无人可答」终局的**闭集** —— core `AskOutcome` 联合里只有这两臂由 {@link ToolApprovalCoordinator.unattendedOutcome}
|
|
747
|
+
* 铸:park 政策的路由答 `"unavailable"`,deny 政策的 {@link UnattendedPolicyRefusal}。没有布尔臂(S-689:裸 `false`
|
|
748
|
+
* 是人的拒绝,这个口从不替人说话)。 */
|
|
749
|
+
export type UnattendedAskOutcome = Extract<AskOutcome, "unavailable"> | UnattendedPolicyRefusal;
|
|
687
750
|
/**
|
|
688
751
|
* [ref] 车3 刀 3b —— 「流内审批协议到底上不上场」的**单一谓词**(设计稿 §2.3 注入 / §2.4 能力面 /
|
|
689
752
|
* §8.4 park 设施自检,三处同一份判据)。
|
|
@@ -1006,6 +1069,10 @@ export declare class ToolApprovalCoordinator {
|
|
|
1006
1069
|
/**
|
|
1007
1070
|
* [ref] R-13 C —— 「**无人可答**」这一类终局的**唯一**成形口(park 路由 vs deny 政策)。
|
|
1008
1071
|
*
|
|
1072
|
+
* 终局形(S-689):park ⇒ `"unavailable"`;deny ⇒ {@link UnattendedPolicyRefusal}
|
|
1073
|
+
* `{allow:false, settledBy:"policy", reason}`(core 记 `policy_refused`)。**从不**交裸 `false`:那在 core 的
|
|
1074
|
+
* onAsk 契约里是「一个人拒了」,而本口的全部臂都是「没有人能答」。
|
|
1075
|
+
*
|
|
1009
1076
|
* 五臂(设计稿 §1 的表)全部读它,`unattendedPolicy` 因此是一处施加、五处消费:
|
|
1010
1077
|
* (a) 有店窗到期 `expireAsk` 赢 CAS / (b) 无店窗到期(D1)/ (c) 有店但 `expireAsk` 报错
|
|
1011
1078
|
* —— 三条走 `windowRouteUnavailable` 标志,在 {@link shapeOutcome}(askBroadcast 内)成形;
|
|
@@ -1023,12 +1090,17 @@ export declare class ToolApprovalCoordinator {
|
|
|
1023
1090
|
* **身份不确定**的处置(与「有没有人」无关),且背后可能正躺着一条真行。于是 `deny` 部署上仍可能落
|
|
1024
1091
|
* 极少数 park(店抖动期),已知且有意的残余,成文在 config-types 的域注。
|
|
1025
1092
|
*
|
|
1026
|
-
*
|
|
1027
|
-
* 造一条原子 deny
|
|
1028
|
-
*
|
|
1029
|
-
*
|
|
1030
|
-
*
|
|
1031
|
-
*
|
|
1093
|
+
* 🔴 **`deny` 部署上政策结算当场落行**(NP-2,7.100.0 合并复审 [ref] 交叉表 #4;codex R1-F1 当年**不采纳**的那一半
|
|
1094
|
+
* 「给 deny 造一条原子 deny 终态转移」在这里收了):窗到期 / emit 全灭两臂在 deny 政策下的终局 claim 是
|
|
1095
|
+
* `refuse` 意图(见 {@link unattendedClaimIntent})—— STREAM_PENDING→DECIDED(deny) + `settled_by = "policy"`,**按 ask
|
|
1096
|
+
* 作用域**(不碰批、不连坐兄弟)。落的来源词与本口交给 core 的是**同一个常量**(`POLICY_REFUSAL_DECISION`),于是
|
|
1097
|
+
* 同 ask 重入 / 收敛后重入由 `outcomeOfDecidedRow` 读回同一个对象。当年「危害为零」的论证(PARKING 行绑不上、
|
|
1098
|
+
* 自行收敛成 DENIED/VOID)在 S-689 之后不再成立:首判交 `{allow:false, settledBy:"policy"}`,行停 PARKING 的回放
|
|
1099
|
+
* 却交裸 `false`(收敛后 DENIED 无来源)—— core 当成人拒、可停批,两次判决第一次可被观测地分家。
|
|
1100
|
+
* 仍按 PARKING 记账的只剩两形(都不是本进程这一次政策结算):别的写者(park 政策副本 / 切换政策之前)推进过的行,
|
|
1101
|
+
* 与崩溃后收敛器孤儿腿代打 expire 的行 —— 前者重入走本口(`replayed_parked`),后者登记在收车档的未闭环项。
|
|
1102
|
+
* deny 政策下批仍是**单 ask 批**(见 {@link batchIdFor}):`refuse` 本来就不碰批,单 ask 批让新行与存量整腿批行
|
|
1103
|
+
* 的差别只剩「批 id 是谁」,结算语义一致。
|
|
1032
1104
|
*/
|
|
1033
1105
|
private unattendedOutcome;
|
|
1034
1106
|
/** 政策**读**口(不是终局铸口)—— 回答「这台部署把无人可答翻成 park 吗」。
|
|
@@ -1037,6 +1109,22 @@ export declare class ToolApprovalCoordinator {
|
|
|
1037
1109
|
* 纯粹的**政策查询**(`unattendedOutcome() !== false`)会和同一只 ask 的真终局各记一条遥测 ——
|
|
1038
1110
|
* 「一只 ask 一条线」当场不成立。读口不落日志,铸口落;谁也不兼职。 */
|
|
1039
1111
|
private get unattendedRoutesToPark();
|
|
1112
|
+
/**
|
|
1113
|
+
* 一只 ask 落在**哪只批**里 —— 批作用域随政策(S-689 codex R1-F1,判据全文见 {@link deriveAskScopedBatchId})。
|
|
1114
|
+
* · park 路由 ⇒ 整腿一批(`deriveBatchId`):窗到期赢家整批转投递面、兄弟连坐,core 随后 park,腿就此结束;
|
|
1115
|
+
* · deny 政策 ⇒ 单 ask 批:没有 park 路由,腿在一次部署政策拒之后继续跑 —— 整腿一批会让首只到期把批关掉,
|
|
1116
|
+
* 同腿后续的卡人批不动(`decideAsk` batch_closed ⇒ 404),兄弟还被连坐成 VOID、以裸 `false` 交 core(人拒)。
|
|
1117
|
+
* 读的是政策**读**口(不落遥测)。
|
|
1118
|
+
*/
|
|
1119
|
+
private batchIdFor;
|
|
1120
|
+
/**
|
|
1121
|
+
* 窗到期 / emit 全灭两臂的**终局 claim 意图**(NP-2)—— 与 {@link batchIdFor} 读同一个政策读口:
|
|
1122
|
+
* · park 路由 ⇒ `expire`(行进投递面、批转 ROUTING_UNBOUND、兄弟连坐,core 随后 park);
|
|
1123
|
+
* · deny 政策 ⇒ `refuse`(按 ask 作用域当场落 DECIDED(deny) + `settled_by="policy"`,与 {@link unattendedOutcome}
|
|
1124
|
+
* 交给 core 的那一只同一个来源词 —— 回放 / 收敛后重入读回同一个对象;不碰批、不连坐兄弟,存量整腿批行同判)。
|
|
1125
|
+
* 两臂之外的终局 claim(取消臂 `cancel`)与政策无关,不读本口。
|
|
1126
|
+
*/
|
|
1127
|
+
private get unattendedClaimIntent();
|
|
1040
1128
|
/** {@link unattendedOutcome} 的**公开**口:`windowZero` 的 immediate-unavailable 闭包长在装配层
|
|
1041
1129
|
* (`http/routes/tasks.ts` 的 sync 腿),它必须与协调器内五臂读**同一个**旋钮值,而不是各算一遍。
|
|
1042
1130
|
* 出处随调用方给(那条腿知道自己是哪一只 ask)。 */
|
|
@@ -1044,7 +1132,7 @@ export declare class ToolApprovalCoordinator {
|
|
|
1044
1132
|
taskId?: string;
|
|
1045
1133
|
owner?: string | null;
|
|
1046
1134
|
toolName?: string;
|
|
1047
|
-
}):
|
|
1135
|
+
}): UnattendedAskOutcome;
|
|
1048
1136
|
/**
|
|
1049
1137
|
* [ref] 车3 刀 3b —— [ref] §3.3 / 设计稿 §0 X-2 的**写侧准入门**。
|
|
1050
1138
|
*
|
package/dist/tool-approval.js
CHANGED
|
@@ -7,10 +7,11 @@ import { hasBidiControls } from "./text-bidi.js";
|
|
|
7
7
|
import { approvalPayloadFingerprint } from "./plugins/approval-payload-fingerprint.js";
|
|
8
8
|
import { createLogger } from "./observability/logger.js";
|
|
9
9
|
import { recordFailOpen } from "./observability/fail-open.js";
|
|
10
|
-
import { deriveAskId, deriveBatchId, MAX_DECISION_NOTE_CHARS } from "./approval-ask-machine.js";
|
|
11
|
-
import { ApprovalCardEnvelopeSchema, MAX_RULE_OFFERS, buildApprovalCard, buildApprovalCardEnvelope, buildApprovalRequestFrame, buildRevokeFrame, readDenialLimitFallback, readProbeCause, readReadRootCandidate, readRuleEvidence, readRuleOffersAbsence, RuleOfferRawSchema, backfillLegacyBatchMemberKind, screenUncoveredDetailSeat, } from "./approval-card.js";
|
|
12
|
-
import { projectAskTerminalClaimTruth } from "./plugins/approval-ask-store-sql.js";
|
|
10
|
+
import { deriveAskId, deriveAskScopedBatchId, deriveBatchId, MAX_DECISION_NOTE_CHARS } from "./approval-ask-machine.js";
|
|
11
|
+
import { ApprovalCardEnvelopeSchema, MAX_RULE_OFFERS, buildApprovalCard, buildApprovalCardEnvelope, buildApprovalRequestFrame, buildRevokeFrame, readDenialLimitFallback, readProbeCause, readReadRootCandidate, readRuleEvidence, readRuleOffersAbsence, readRuleOffersAbsenceSeat, readRequiresRealApprovalSeat, RuleOfferRawSchema, backfillLegacyBatchMemberKind, screenUncoveredDetailSeat, } from "./approval-card.js";
|
|
12
|
+
import { POLICY_REFUSAL_DECISION, projectAskTerminalClaimTruth } from "./plugins/approval-ask-store-sql.js";
|
|
13
13
|
import { governanceAskMarksFor, runWithGovernanceAskScope } from "./governance-ask-marks.js";
|
|
14
|
+
import { governanceOriginOf } from "./runtime-governance.js";
|
|
14
15
|
const defaultLogger = createLogger();
|
|
15
16
|
export const APPROVAL_GATE_KINDS = ["human", "irreversible_ask"];
|
|
16
17
|
export function isApprovalGateKind(k) {
|
|
@@ -82,6 +83,24 @@ function sessionAllowKey(owner, sessionId, category) {
|
|
|
82
83
|
export function standingAnswerMayRetire(facts) {
|
|
83
84
|
return !facts.governanceForced && !facts.requiresRealApproval && !facts.mandated;
|
|
84
85
|
}
|
|
86
|
+
export function parkRowStandingAnswerFacts(pending, gate, governance) {
|
|
87
|
+
const riskDescriptor = "riskDescriptor" in gate ? gate.riskDescriptor : undefined;
|
|
88
|
+
return {
|
|
89
|
+
governanceForced: governanceOriginOf({ riskDescriptor }, governance) === true,
|
|
90
|
+
requiresRealApproval: readRequiresRealApprovalSeat(pending),
|
|
91
|
+
mandated: mandatedFromSeat(readRuleOffersAbsenceSeat(pending)),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function mandatedFromSeat(seat) {
|
|
95
|
+
switch (seat.state) {
|
|
96
|
+
case "word":
|
|
97
|
+
return seat.word === "mandated";
|
|
98
|
+
case "unreadable":
|
|
99
|
+
return true;
|
|
100
|
+
case "absent":
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
85
104
|
export const PERSIST_RULE_TEXT_ERROR = `persistRule.rule must be a non-empty string of at most ${MAX_RULE_TEXT_CHARS} characters`;
|
|
86
105
|
export const PERSIST_RULE_EDITED_FLAG_ERROR = "persistRule.edited must be a boolean when present";
|
|
87
106
|
export const PERSIST_RULE_BATCH_INDEX_ERROR = "persistRule.batchOfferIndex must be a non-negative integer when present";
|
|
@@ -152,6 +171,10 @@ export function parseToolApprovalResponse(body) {
|
|
|
152
171
|
}
|
|
153
172
|
return { ok: false, error: 'decision must be one of "allow" | "allow_session" | "deny"' };
|
|
154
173
|
}
|
|
174
|
+
function unattendedRefusalReason(arm) {
|
|
175
|
+
return ("UNATTENDED_APPROVAL_POLICY=deny: this deployment declares that no one attends its approvals, so an approval " +
|
|
176
|
+
`request no one can answer is refused here instead of being parked for a person (arm: ${arm}).`);
|
|
177
|
+
}
|
|
155
178
|
function isChildAsk(req) {
|
|
156
179
|
return req.fromSubagent === true;
|
|
157
180
|
}
|
|
@@ -321,11 +344,26 @@ export class ToolApprovalCoordinator {
|
|
|
321
344
|
this.askAudit = opts?.askAudit;
|
|
322
345
|
}
|
|
323
346
|
unattendedOutcome(site) {
|
|
324
|
-
|
|
347
|
+
let outcome;
|
|
348
|
+
let outcomeWord;
|
|
349
|
+
switch (this.unattendedPolicy) {
|
|
350
|
+
case "park":
|
|
351
|
+
outcome = "unavailable";
|
|
352
|
+
outcomeWord = "unavailable";
|
|
353
|
+
break;
|
|
354
|
+
case "deny":
|
|
355
|
+
outcome = { allow: false, settledBy: POLICY_REFUSAL_DECISION.settledBy, reason: unattendedRefusalReason(site.arm) };
|
|
356
|
+
outcomeWord = "deny";
|
|
357
|
+
break;
|
|
358
|
+
default: {
|
|
359
|
+
const unreachable = this.unattendedPolicy;
|
|
360
|
+
throw new Error(`unattendedOutcome: unknown UNATTENDED_APPROVAL_POLICY word ${String(unreachable)}`);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
325
363
|
defaultLogger.warn("approver_unavailable", {
|
|
326
364
|
arm: site.arm,
|
|
327
365
|
policy: this.unattendedPolicy,
|
|
328
|
-
outcome:
|
|
366
|
+
outcome: outcomeWord,
|
|
329
367
|
owner: site.owner ?? null,
|
|
330
368
|
taskId: site.taskId ?? null,
|
|
331
369
|
toolName: site.toolName ?? null,
|
|
@@ -336,6 +374,12 @@ export class ToolApprovalCoordinator {
|
|
|
336
374
|
get unattendedRoutesToPark() {
|
|
337
375
|
return this.unattendedPolicy !== "deny";
|
|
338
376
|
}
|
|
377
|
+
batchIdFor(askId, sourceTaskId, runId, legKey) {
|
|
378
|
+
return this.unattendedRoutesToPark ? deriveBatchId(sourceTaskId, runId, legKey) : deriveAskScopedBatchId(askId);
|
|
379
|
+
}
|
|
380
|
+
get unattendedClaimIntent() {
|
|
381
|
+
return this.unattendedRoutesToPark ? "expire" : "refuse";
|
|
382
|
+
}
|
|
339
383
|
unattendedAskOutcome(site) {
|
|
340
384
|
return this.unattendedOutcome({
|
|
341
385
|
arm: "window_zero",
|
|
@@ -917,7 +961,7 @@ export class ToolApprovalCoordinator {
|
|
|
917
961
|
const runId = origin.taskId;
|
|
918
962
|
const legKey = origin.legKey;
|
|
919
963
|
askId = deriveAskId(sourceTaskId, runId, req.toolCallId, legKey, req.delegation?.parentToolCallId);
|
|
920
|
-
batchId =
|
|
964
|
+
batchId = this.batchIdFor(askId, sourceTaskId, runId, legKey);
|
|
921
965
|
try {
|
|
922
966
|
const existingOrCreated = await this.withStoreDeadline(this.askStore.ensureAsk({
|
|
923
967
|
askId,
|
|
@@ -940,6 +984,7 @@ export class ToolApprovalCoordinator {
|
|
|
940
984
|
if (abandonedEnsure && lateEnsuredAskId !== undefined)
|
|
941
985
|
voidAbandonedRow(lateEnsuredAskId);
|
|
942
986
|
});
|
|
987
|
+
batchId = existingOrCreated.row.batchId;
|
|
943
988
|
if (existingOrCreated.row.state !== "STREAM_PENDING") {
|
|
944
989
|
releaseAdmission();
|
|
945
990
|
const replayed = replayTerminalAskRow(existingOrCreated.row);
|
|
@@ -1001,7 +1046,10 @@ export class ToolApprovalCoordinator {
|
|
|
1001
1046
|
let indeterminate = true;
|
|
1002
1047
|
for (let attempt = 0; attempt <= DURABLE_CONVERGE_BACKOFF_MS.length; attempt++) {
|
|
1003
1048
|
try {
|
|
1004
|
-
|
|
1049
|
+
const confirmedRow = await this.withStoreDeadline(this.askStore.getAsk(askId), "getAsk(ensureAsk-confirm)");
|
|
1050
|
+
confirmedRowExists = confirmedRow !== null;
|
|
1051
|
+
if (confirmedRow !== null)
|
|
1052
|
+
batchId = confirmedRow.batchId;
|
|
1005
1053
|
indeterminate = false;
|
|
1006
1054
|
break;
|
|
1007
1055
|
}
|
|
@@ -1044,7 +1092,7 @@ export class ToolApprovalCoordinator {
|
|
|
1044
1092
|
let selfEntry;
|
|
1045
1093
|
let hostSettled;
|
|
1046
1094
|
let denyReasonSettled;
|
|
1047
|
-
const shapeDeny = () => {
|
|
1095
|
+
const shapeDeny = (bare) => {
|
|
1048
1096
|
if (hostSettled !== undefined || (denyReasonSettled !== undefined && denyReasonSettled !== "")) {
|
|
1049
1097
|
return {
|
|
1050
1098
|
allow: false,
|
|
@@ -1052,18 +1100,17 @@ export class ToolApprovalCoordinator {
|
|
|
1052
1100
|
...(denyReasonSettled !== undefined && denyReasonSettled !== "" ? { reason: denyReasonSettled } : {}),
|
|
1053
1101
|
};
|
|
1054
1102
|
}
|
|
1055
|
-
return
|
|
1103
|
+
return bare;
|
|
1056
1104
|
};
|
|
1057
1105
|
const shapeOutcome = (settled) => {
|
|
1058
1106
|
if (windowRouteUnavailable) {
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
: "unavailable";
|
|
1107
|
+
const unattended = this.unattendedOutcome({ arm: "window_expired", taskId: origin.taskId, ...(origin.owner !== null ? { owner: origin.owner } : {}), toolName: req.toolName, reachability });
|
|
1108
|
+
return unattended === "unavailable" ? unattended : shapeDeny(unattended);
|
|
1062
1109
|
}
|
|
1063
1110
|
if (settled.allowed) {
|
|
1064
1111
|
return settled.updatedInput !== undefined ? { allow: true, updatedInput: settled.updatedInput } : true;
|
|
1065
1112
|
}
|
|
1066
|
-
return shapeDeny();
|
|
1113
|
+
return shapeDeny(false);
|
|
1067
1114
|
};
|
|
1068
1115
|
const settle = (allowed, outcome, updatedInput, hostSettledBy, denyReason) => {
|
|
1069
1116
|
if (done)
|
|
@@ -1268,10 +1315,11 @@ export class ToolApprovalCoordinator {
|
|
|
1268
1315
|
const store = this.askStore;
|
|
1269
1316
|
const pinnedAskId = askId;
|
|
1270
1317
|
const pinnedBatchId = batchId;
|
|
1318
|
+
const claimIntent = this.unattendedClaimIntent;
|
|
1271
1319
|
await resolveLocalOutcome({
|
|
1272
1320
|
intent: "expire",
|
|
1273
1321
|
storeLabel: "claimTerminal(window)",
|
|
1274
|
-
claim: (timeoutMs) => boundedClaim(() => store.claimTerminal(pinnedAskId, pinnedBatchId,
|
|
1322
|
+
claim: (timeoutMs) => boundedClaim(() => store.claimTerminal(pinnedAskId, pinnedBatchId, claimIntent), "claimTerminal(window)", timeoutMs, (late) => {
|
|
1275
1323
|
if (!late.claimed) {
|
|
1276
1324
|
lateClaimLossSettle(late.current, "expire");
|
|
1277
1325
|
return;
|
|
@@ -1450,6 +1498,7 @@ export class ToolApprovalCoordinator {
|
|
|
1450
1498
|
const store = this.askStore;
|
|
1451
1499
|
const pinnedAskId = askId;
|
|
1452
1500
|
const pinnedBatchId = batchId;
|
|
1501
|
+
const claimIntent = this.unattendedClaimIntent;
|
|
1453
1502
|
const settleUnreachable = () => {
|
|
1454
1503
|
if (done)
|
|
1455
1504
|
return;
|
|
@@ -1459,7 +1508,7 @@ export class ToolApprovalCoordinator {
|
|
|
1459
1508
|
await resolveLocalOutcome({
|
|
1460
1509
|
intent: "unreachable",
|
|
1461
1510
|
storeLabel: "claimTerminal(emit-failed)",
|
|
1462
|
-
claim: (timeoutMs) => boundedClaim(() => store.claimTerminal(pinnedAskId, pinnedBatchId,
|
|
1511
|
+
claim: (timeoutMs) => boundedClaim(() => store.claimTerminal(pinnedAskId, pinnedBatchId, claimIntent), "claimTerminal(emit-failed)", timeoutMs, (late) => {
|
|
1463
1512
|
if (!late.claimed) {
|
|
1464
1513
|
lateClaimLossSettle(late.current, "unreachable");
|
|
1465
1514
|
return;
|
|
@@ -25,7 +25,7 @@ import type { ToolApprovalFrame } from "../tool-approval.js";
|
|
|
25
25
|
* `type X<T extends never> = T`(抄一份就是第二个写者,两处哪天分岔谁都发现不了)。
|
|
26
26
|
* 本文件只有类型、不产 JS,所以被 `import type` 引用不新增任何运行期边。 */
|
|
27
27
|
export type AssertAllKeysHandled<T extends never> = T;
|
|
28
|
-
type NotificationProjected = "task_id" | "task_type" | "toolUseId" | "status" | "summary" | "result" | "output_file" | "usage" | "sessionId" | "seq" | "lines" | "stoppedBy" | "source" | "exitCode" | "partial" | "diagnostics" | "recentSteps" | "editedFiles" | "resumable" | "completionId" | "error" | "errorCode" | "apiFailure" | "agentMessage" | "_sema_provenance";
|
|
28
|
+
type NotificationProjected = "task_id" | "task_type" | "toolUseId" | "status" | "summary" | "result" | "output_file" | "usage" | "sessionId" | "seq" | "lines" | "stoppedBy" | "source" | "exitCode" | "partial" | "diagnostics" | "recentSteps" | "editedFiles" | "resumable" | "completionId" | "error" | "errorCode" | "apiFailure" | "agentMessage" | "_sema_provenance" | "spawnName" | "handback" | "compaction" | "resupplied" | "attempt";
|
|
29
29
|
type NotificationExcluded = (typeof import("./wire-projection-faces.js").WIRE_PROJECTION_FACES)["task_notification"]["excluded"][number];
|
|
30
30
|
type _GuardNotification = AssertAllKeysHandled<Exclude<keyof TaskNotificationPayload, NotificationProjected | NotificationExcluded>>;
|
|
31
31
|
type _GuardNotificationReverse = AssertAllKeysHandled<Exclude<NotificationProjected | NotificationExcluded, keyof TaskNotificationPayload>>;
|
|
@@ -59,8 +59,8 @@ type _GuardMailboxReverse = AssertAllKeysHandled<Exclude<MailboxProjected, keyof
|
|
|
59
59
|
type MailboxAppendProjected = "from" | "content" | "sentAt" | "hopChain" | "peerMeta";
|
|
60
60
|
type _GuardMailboxAppend = AssertAllKeysHandled<Exclude<keyof MailboxAppendMessage, MailboxAppendProjected>>;
|
|
61
61
|
type _GuardMailboxAppendReverse = AssertAllKeysHandled<Exclude<MailboxAppendProjected, keyof MailboxAppendMessage>>;
|
|
62
|
-
type WiringSectionProjected = "schemaVersion" | "leg" | "ask" | "question" | "interaction" | "elicit" | "parkLane" | "session" | "fleet" | "permissionRules" | "modelGate" | "autoMode" | "mcp" | "tools" | "hooks" | "lsp" | "writeProtection";
|
|
63
|
-
type WiringSectionExcluded = "governance" | "configFingerprint" | "autoConsolidation" | "readDeny";
|
|
62
|
+
type WiringSectionProjected = "schemaVersion" | "leg" | "ask" | "question" | "interaction" | "elicit" | "parkLane" | "session" | "fleet" | "permissionRules" | "modelGate" | "autoMode" | "mcp" | "tools" | "hooks" | "lsp" | "writeProtection" | "teamRole";
|
|
63
|
+
type WiringSectionExcluded = "governance" | "configFingerprint" | "autoConsolidation" | "readDeny" | "peerPresence";
|
|
64
64
|
type _GuardWiringSections = AssertAllKeysHandled<Exclude<keyof WiringManifest, WiringSectionProjected | WiringSectionExcluded>>;
|
|
65
65
|
type _GuardWiringSectionsReverse = AssertAllKeysHandled<Exclude<WiringSectionProjected | WiringSectionExcluded, keyof WiringManifest>>;
|
|
66
66
|
type WiringSection<K extends keyof WiringManifest> = NonNullable<WiringManifest[K]>;
|
|
@@ -135,10 +135,10 @@ type SummaryExcluded = "token" | "toolInput" | "toolName" | "toolCallId" | "prev
|
|
|
135
135
|
type _GuardInboxSummary = AssertAllKeysHandled<Exclude<keyof CheckpointSummary, SummaryProjected | SummaryExcluded>>;
|
|
136
136
|
type _GuardInboxSummaryReverse = AssertAllKeysHandled<Exclude<SummaryProjected | SummaryExcluded, keyof CheckpointSummary>>;
|
|
137
137
|
type TaskSpecWired = "objective" | "principal" | "images" | "sessionId" | "requireExistingSession" | "oneShot" | "clientContext" | "resumeAt" | "resumeAtMode" | "model" | "compactionModel" | "thinking" | "systemPrompt" | "appendSystemPrompt" | "promptProvider" | "memory" | "suggestNextPrompts" | "restoreFiles" | "acceptPartialRestore" | "rewindFilesTo" | "tools" | "excludeTools" | "deferTools" | "toolMaterializeStrategy" | "promptProfile" | "toolPolicy" | "onAsk" | "onQuestion" | "hooks" | "durableApproval" | "resourceSuspend" | "resilience" | "finalVerification" | "checkpointStore" | "handsReadOnly" | "memoryPersistenceCapable" | "additionalDirectories" | "additionalReadDirectories" | "enablePlanMode" | "interactiveTools" | "enableFork" | "shellGate" | "writeFace" | "mcp" | "a2a" | "skills" | "backgroundScope" | "envFacts" | "limits" | "configOverrides" | "forwardSubagentEvents" | "retainSubagentSessions" | "retainBackgroundProcesses" | "outputSchema" | "outputRetries" | "compaction" | "attachments" | "selfOrchestration" | "getApiKeyAndHeaders" | "interactionPosture" | "agents" | "approverPosture" | "taskId" | "signal" | "preemptSignal" | "modelRole" | "enableBlockedReport" | "maxSuspends" | "autoModeRequested" | "skillListingBudgetFraction" | "skillListingMaxDescChars" | "excludeAllTools";
|
|
138
|
-
type TaskSpecUnwired = "actor" | "roles" | "lspManager" | "tracer" | "readFace" | "readDenyPatterns" | "interactiveQuestionFallback" | "alwaysLoadTools" | "restoreGatedTools" | "deferSelfResolve" | "basePolicyForResumeEdit" | "lspDiagnostics" | "streamingToolExecution" | "toolResultThresholdChars";
|
|
138
|
+
type TaskSpecUnwired = "actor" | "roles" | "lspManager" | "tracer" | "readFace" | "readDenyPatterns" | "interactiveQuestionFallback" | "alwaysLoadTools" | "restoreGatedTools" | "deferSelfResolve" | "basePolicyForResumeEdit" | "lspDiagnostics" | "streamingToolExecution" | "toolResultThresholdChars" | "peerPresence";
|
|
139
139
|
type _GuardTaskSpec = AssertAllKeysHandled<Exclude<keyof TaskSpec, TaskSpecWired | TaskSpecUnwired>>;
|
|
140
140
|
type _GuardTaskSpecReverse = AssertAllKeysHandled<Exclude<TaskSpecWired | TaskSpecUnwired, keyof TaskSpec>>;
|
|
141
|
-
type TaskResultForwarded = "taskId" | "runId" | "sessionId" | "terminal" | "model" | "effectiveReasoning" | "result" | "salvagedOutput" | "remoteEnvFailures" | "apiFailure" | "retryAfterMs" | "degraded" | "structuredOutput" | "rewindNotes" | "haltedOnUserRejection" | "haltedByUser" | "strandedHumanAnswers" | "pendingApproval" | "approvalWaitedMs" | "effectiveReadFace" | "effectiveReadDenyPatterns" | "effectiveWriteFace" | "effectiveMemoryScopes" | "stats" | "editedFiles" | "responseModel";
|
|
141
|
+
type TaskResultForwarded = "taskId" | "runId" | "sessionId" | "terminal" | "model" | "effectiveReasoning" | "result" | "salvagedOutput" | "remoteEnvFailures" | "apiFailure" | "retryAfterMs" | "degraded" | "structuredOutput" | "rewindNotes" | "haltedOnUserRejection" | "haltedByUser" | "strandedHumanAnswers" | "pendingApproval" | "approvalWaitedMs" | "effectiveReadFace" | "effectiveReadDenyPatterns" | "effectiveWriteFace" | "effectiveMemoryScopes" | "stats" | "editedFiles" | "responseModel" | "compaction";
|
|
142
142
|
type TaskResultStripped = never;
|
|
143
143
|
type _GuardTaskResult = AssertAllKeysHandled<Exclude<keyof TaskResult, TaskResultForwarded | TaskResultStripped>>;
|
|
144
144
|
type _GuardTaskResultReverse = AssertAllKeysHandled<Exclude<TaskResultForwarded | TaskResultStripped, keyof TaskResult>>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {} from "@sema-agent/core";
|
|
2
2
|
import { outwardPlane } from "../terminal.js";
|
|
3
3
|
import { modelTextEventData, toolStartEventData, toolEndEventData, taskProgressEventData, taskNotificationEventData, compactedEventData, diagnosticsEventData, brainStatusEventData, steeringInjectedEventData, compactionOutcomeEventData, workspaceChangedEventData, wiringManifestEventData, toolRosterDeltaEventData, toolDisclosureEventData, humanInputEventData, turnEndEventData, contextUsageEventData } from "./project.js";
|
|
4
|
-
import { NotifiedKeys,
|
|
4
|
+
import { NotifiedKeys, taskNotificationStreamKeyOf } from "../orchestration/workflow-completion-inbox.js";
|
|
5
5
|
import { isParkLedgerEventType } from "./ledger-events.js";
|
|
6
6
|
import { isModelSegmentBoundary, reasoningDeltaBytes, reasoningSegmentEventId } from "./model-segment.js";
|
|
7
7
|
export function createSerialLedgerAppend(appendEvent, startSeq) {
|
|
@@ -119,7 +119,7 @@ export function createLedgerSink(opts) {
|
|
|
119
119
|
break;
|
|
120
120
|
case "task_notification": {
|
|
121
121
|
const tn = ev.notification;
|
|
122
|
-
const tnKey =
|
|
122
|
+
const tnKey = taskNotificationStreamKeyOf(tn);
|
|
123
123
|
const tnPrior = tnKey !== undefined ? keys.get(tnKey) : undefined;
|
|
124
124
|
if (tnPrior === undefined || !(await tnPrior)) {
|
|
125
125
|
const write = append("task_notification", taskNotificationEventData(ev));
|
package/dist/trace/project.d.ts
CHANGED
|
@@ -422,6 +422,17 @@ export declare function taskNotificationEventData(ev: {
|
|
|
422
422
|
* `kind` 过闭集(`trace/sema-provenance.ts` 单点,park 半场同一判据);`agentType` 本 mount 恒缺席(工具无
|
|
423
423
|
* agent-type 席),在场即透传(fleet spawn 帧按 taskId 可 join 时上游给)。 */
|
|
424
424
|
_sema_provenance?: SemaProvenanceInput;
|
|
425
|
+
/** core 7.30.0 [ref] S1 / #1034 / #1036(S-616):委派终态帧三枚 facet + 重供两键 —— 判据单点在
|
|
426
|
+
* `trace/task-notification-facets.ts`(与 park 半场同一只;入参按 `unknown` 收、判过形才成 typed)。 */
|
|
427
|
+
spawnName?: string;
|
|
428
|
+
handback?: string;
|
|
429
|
+
compaction?: {
|
|
430
|
+
passes: number;
|
|
431
|
+
breakerOpen: boolean;
|
|
432
|
+
kind?: string;
|
|
433
|
+
};
|
|
434
|
+
resupplied?: boolean;
|
|
435
|
+
attempt?: number;
|
|
425
436
|
};
|
|
426
437
|
eventId?: string;
|
|
427
438
|
parentToolCallId?: string;
|
|
@@ -840,6 +851,8 @@ export declare function compactedEventData(ev: {
|
|
|
840
851
|
* 的数、post 恒是结构和 + 固定提示词开销,两者的差混坐标,实测在普通 run 上是负数)。本仓的处置因此
|
|
841
852
|
* 是**三条都逐字透传、一条都不合成**:谁要画上下文表就读 `freedTokens`,读不到就渲染 unknown。 */
|
|
842
853
|
freedTokens?: number;
|
|
854
|
+
/** core 7.30.0 #1036(S-616):这一次压缩**摘要掉**了几条之前已交给模型的跨会话消息(在场 iff ≥1)。 */
|
|
855
|
+
summarizedCrossSessionMessages?: number;
|
|
843
856
|
durationMs?: number;
|
|
844
857
|
phaseDurations?: {
|
|
845
858
|
prepareMs?: number;
|
package/dist/trace/project.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { redactErrorMessage, redactModelText } from "../observability/run-terminal.js";
|
|
2
|
-
import { MCP_DELIVERY_VERDICTS, MCP_LIVENESS_STATES, screenGateOutcome, ToolRoster, ToolRosterDelta, WRITE_PROTECTION_TARGET_VIEWS } from "@sema-agent/core";
|
|
2
|
+
import { MCP_DELIVERY_VERDICTS, MCP_LIVENESS_STATES, screenGateOutcome, TEAM_ROLES, ToolRoster, ToolRosterDelta, WRITE_PROTECTION_TARGET_VIEWS } from "@sema-agent/core";
|
|
3
3
|
import { Value } from "typebox/value";
|
|
4
4
|
import { recordFailOpen } from "../observability/fail-open.js";
|
|
5
5
|
import { redactSecrets, redactDeep } from "./redact.js";
|
|
6
6
|
import { injectionTierOrAbsent } from "./injection-tier.js";
|
|
7
7
|
import { semaProvenanceOrAbsent } from "./sema-provenance.js";
|
|
8
|
+
import { resupplyFields, terminalFrameFacetFields } from "./task-notification-facets.js";
|
|
9
|
+
import { dropProjectedFace } from "./projection-drop.js";
|
|
8
10
|
export async function appendModelUsageDelta(append, modelUsage, taskId) {
|
|
9
11
|
const delta = modelUsage?.drain(taskId);
|
|
10
12
|
if (delta) {
|
|
@@ -229,10 +231,6 @@ export function toolEndEventData(ev) {
|
|
|
229
231
|
...identityFields(ev),
|
|
230
232
|
};
|
|
231
233
|
}
|
|
232
|
-
const dropProjectedFace = (what) => {
|
|
233
|
-
recordFailOpen("server.trace.projection-input-malformed", what);
|
|
234
|
-
return undefined;
|
|
235
|
-
};
|
|
236
234
|
export function toolProgressEventData(ev) {
|
|
237
235
|
const id = typeof ev.toolCallId === "string" && ev.toolCallId !== "" ? ev.toolCallId : undefined;
|
|
238
236
|
const name = typeof ev.toolName === "string" && ev.toolName !== "" ? ev.toolName : undefined;
|
|
@@ -326,6 +324,8 @@ export function taskNotificationEventData(ev) {
|
|
|
326
324
|
const p = semaProvenanceOrAbsent(n._sema_provenance);
|
|
327
325
|
return p !== undefined ? { _sema_provenance: p } : {};
|
|
328
326
|
})(),
|
|
327
|
+
...terminalFrameFacetFields(n),
|
|
328
|
+
...resupplyFields(n),
|
|
329
329
|
...(() => {
|
|
330
330
|
const tier = injectionTierOrAbsent(ev.priority);
|
|
331
331
|
return tier !== undefined ? { priority: tier } : {};
|
|
@@ -535,9 +535,17 @@ export function wiringManifestEventData(ev) {
|
|
|
535
535
|
return { targetView };
|
|
536
536
|
})();
|
|
537
537
|
const mcp = projectWiringManifestMcpRows(m.mcp);
|
|
538
|
+
const teamRole = (() => {
|
|
539
|
+
if (m.teamRole === undefined)
|
|
540
|
+
return undefined;
|
|
541
|
+
if (!TEAM_ROLES.includes(m.teamRole))
|
|
542
|
+
return dropProjectedFace("wiring_manifest.teamRole is outside core TEAM_ROLES");
|
|
543
|
+
return m.teamRole;
|
|
544
|
+
})();
|
|
538
545
|
return {
|
|
539
546
|
...(num(m.schemaVersion) !== undefined ? { schemaVersion: m.schemaVersion } : {}),
|
|
540
547
|
...(str(legIn.kind) !== undefined ? { leg: { kind: legIn.kind } } : {}),
|
|
548
|
+
...(teamRole !== undefined ? { teamRole } : {}),
|
|
541
549
|
...(ask !== undefined ? { ask } : {}),
|
|
542
550
|
...(question !== undefined ? { question } : {}),
|
|
543
551
|
...(str(interactionIn.posture) !== undefined ? { interaction: { posture: interactionIn.posture } } : {}),
|
|
@@ -676,6 +684,15 @@ export function compactedEventData(ev) {
|
|
|
676
684
|
...(num(ev.tokensAfter) !== undefined ? { tokensAfter: num(ev.tokensAfter) } : {}),
|
|
677
685
|
...(num(ev.triggerTokensBefore) !== undefined ? { triggerTokensBefore: num(ev.triggerTokensBefore) } : {}),
|
|
678
686
|
...(num(ev.freedTokens) !== undefined ? { freedTokens: num(ev.freedTokens) } : {}),
|
|
687
|
+
...(() => {
|
|
688
|
+
const v = ev.summarizedCrossSessionMessages;
|
|
689
|
+
if (v === undefined)
|
|
690
|
+
return {};
|
|
691
|
+
if (Number.isInteger(v) && v >= 1)
|
|
692
|
+
return { summarizedCrossSessionMessages: v };
|
|
693
|
+
dropProjectedFace("compacted.summarizedCrossSessionMessages is not an integer >= 1");
|
|
694
|
+
return {};
|
|
695
|
+
})(),
|
|
679
696
|
...(num(ev.durationMs) !== undefined ? { durationMs: num(ev.durationMs) } : {}),
|
|
680
697
|
...(phaseDurations !== undefined ? { phaseDurations } : {}),
|
|
681
698
|
};
|
|
@@ -26,8 +26,11 @@ export declare const SEMA_PROVENANCE_KINDS: readonly ["agent_message"];
|
|
|
26
26
|
* (core-keyset-guard.ts ① 的同名排除键)一同候 [ref] 表态。放进 EXCLUDED 而不是 PROJECTED,是**沿用**上一行的
|
|
27
27
|
* 裁定而不是新增特判:表态未出前放行一个 lane 词,等于替它预先声明一种 cli 渲染形。表态落定那天三处(本簿、
|
|
28
28
|
* 载体键、①-nested 的 `peerMeta`)同批翻。
|
|
29
|
+
* · `inbox_notice` —— core 7.30.0 #1036(S-616 提货;本闭集当拍真红出它)。**同一条车道的第三个载体**(收件箱通告,
|
|
30
|
+
* `crossSessionMessage` / `crossSessionNotice` 之后),同一个 session-box drain 铸;载体键 `inboxNotice` 在
|
|
31
|
+
* core-keyset-guard.ts ① 同批进 EXCLUDED。沿用上两行的裁定,不是新判据:[ref] 表态落定那天四处同批翻。
|
|
29
32
|
*/
|
|
30
|
-
export declare const SEMA_PROVENANCE_KINDS_EXCLUDED: readonly ["cross_session_message", "cross_session_notice"];
|
|
33
|
+
export declare const SEMA_PROVENANCE_KINDS_EXCLUDED: readonly ["cross_session_message", "cross_session_notice", "inbox_notice"];
|
|
31
34
|
/** 本仓两条腿入参的**形**(不是 core 类型:入参是运行期载荷,`kind` 先当 string 收、经闭集才成 typed)。 */
|
|
32
35
|
export interface SemaProvenanceInput {
|
|
33
36
|
kind: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export const SEMA_PROVENANCE_KINDS = ["agent_message"];
|
|
2
|
-
export const SEMA_PROVENANCE_KINDS_EXCLUDED = ["cross_session_message", "cross_session_notice"];
|
|
2
|
+
export const SEMA_PROVENANCE_KINDS_EXCLUDED = ["cross_session_message", "cross_session_notice", "inbox_notice"];
|
|
3
3
|
const _semaProvenanceExhaustive = true;
|
|
4
4
|
void _semaProvenanceExhaustive;
|
|
5
5
|
const _semaProvenanceNoDoubleBook = true;
|