@sema-agent/client-core 0.28.0 → 0.30.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/CHANGELOG.md +400 -0
- package/README.md +19 -2
- package/dist/adapt/arms.js +24 -1
- package/dist/adapt/wireShapes.d.ts +7 -0
- package/dist/adapt/wireShapes.js +7 -0
- package/dist/adapter/activeRunSelfHeal.d.ts +407 -0
- package/dist/adapter/activeRunSelfHeal.js +771 -0
- package/dist/adapter/runStream.d.ts +23 -6
- package/dist/adapter/runStream.js +19 -5
- package/dist/engineWireSdk.d.ts +10 -2
- package/dist/engineWireSdk.js +7 -3
- package/dist/hitl/approvalDecisionNoteAudit.d.ts +58 -0
- package/dist/hitl/approvalDecisionNoteAudit.js +91 -0
- package/dist/hitl/armedGateRegistry.d.ts +19 -0
- package/dist/hitl/armedGateRegistry.js +92 -0
- package/dist/hitl/askParkRowRouting.d.ts +150 -0
- package/dist/hitl/askParkRowRouting.js +183 -0
- package/dist/hitl/frameRouter.d.ts +5 -1
- package/dist/hitl/frameRouter.js +1 -1
- package/dist/hitl/gateIdentity.d.ts +50 -0
- package/dist/hitl/gateIdentity.js +64 -0
- package/dist/hitl/hitlBridge.d.ts +7 -0
- package/dist/hitl/hitlBridge.js +11 -2
- package/dist/hitl/parkOwnership.d.ts +65 -0
- package/dist/hitl/parkOwnership.js +49 -0
- package/dist/hitl/parkResolver.js +3 -1
- package/dist/hitl/parkRowBirthWait.d.ts +63 -0
- package/dist/hitl/parkRowBirthWait.js +192 -0
- package/dist/hitl/planReviewWire.d.ts +51 -0
- package/dist/hitl/planReviewWire.js +172 -17
- package/dist/hitl/resumeRunningCard.d.ts +134 -0
- package/dist/hitl/resumeRunningCard.js +177 -0
- package/dist/hitl/toolApprovalWire.d.ts +69 -23
- package/dist/hitl/toolApprovalWire.js +60 -24
- package/dist/index.d.ts +9 -0
- package/dist/index.js +34 -0
- package/dist/liveQuestionStore.d.ts +11 -0
- package/dist/liveQuestionStore.js +13 -0
- package/dist/seatContract.d.ts +27 -0
- package/dist/seatContract.js +42 -0
- package/dist/subagent/engineSubagentTail.d.ts +0 -2
- package/dist/subagent/engineSubagentTail.js +7 -15
- package/dist/subagentContentStore.d.ts +58 -2
- package/dist/subagentContentStore.js +95 -6
- package/dist/toolResult.d.ts +26 -0
- package/dist/toolResult.js +38 -6
- package/dist/workflowClient.d.ts +6 -1
- package/docs/INTEGRATION-CLIENTS.md +844 -0
- package/docs/REFACTOR-LEDGER.md +392 -0
- package/package.json +7 -4
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* hitl/resumeRunningCard.ts — **resume 撞上「上一轮还在跑」**时那张三选卡的判定 / 选项集 / 文案
|
|
3
|
+
* (#265 上收件,2026-08-14;源形 = cli `src/sema/resumeRunningArm.ts` 的纯判定半场,编排腿留在端上)。
|
|
4
|
+
*
|
|
5
|
+
* ── 病与改形 ────────────────────────────────────────────────────────────────────────────────
|
|
6
|
+
* resume 时读到一条 `running` 的 run,旧形是**客户端自己**给它打一枪 cancel(动机 = 僵尸烧 token)。
|
|
7
|
+
* 矛盾:resume 时的 running run **不可判**是「用户要的在飞工作」还是「僵尸」—— 而实况里自动 cancel
|
|
8
|
+
* 恰好是错的方向(用户批准之后 run 该继续跑,resume 时 cancel = 把刚救活的 run 又杀了)。血统纪律:
|
|
9
|
+
* **破坏性动作恒不自动**。改形 = 把三条路交回用户:
|
|
10
|
+
* ① `Attach and watch` —— 接管为当前 turn 输出;
|
|
11
|
+
* ② `Cancel it` —— 那个动作降级为**用户按下**的选项;
|
|
12
|
+
* ③ `Leave it running in the background`(**默认焦点**)—— 零动作。
|
|
13
|
+
*
|
|
14
|
+
* ── §3.2a 活性证据的缺席纪律(不可削)──────────────────────────────────────────────────────
|
|
15
|
+
* 判活体的 `msSinceLastActivity`(相对毫秒)在场 ⇒ 卡上渲一行「last activity Ns ago」;
|
|
16
|
+
* **缺席 = 无法证明**(跨副本命中 / 副本重启后),不是「不活」—— 那一行**整行不渲**,绝不折成 0、
|
|
17
|
+
* 绝不写成「已死」。
|
|
18
|
+
*
|
|
19
|
+
* ── §3.2b 无 UI 臂:退役自动 cancel 之后不许留死墙 ──────────────────────────────────────────
|
|
20
|
+
* 「不自动 cancel + 没有卡可选」= 又一堵死墙。所以没有卡的形必须**显式定义臂**:恒不 cancel;
|
|
21
|
+
* 输出**机读三选指路**({@link resumeRunningNoUiGuidance},attach / cancel / 后台留着三条路各给
|
|
22
|
+
* 真实命令或 API 路径);headless 车道走**专码**退出({@link RESUME_RUNNING_NO_UI_EXIT_CODE});
|
|
23
|
+
* 绝不静默挂起、绝不谎报成功。
|
|
24
|
+
*
|
|
25
|
+
* ── 🔴 塌缩纪律 ─────────────────────────────────────────────────────────────────────────────
|
|
26
|
+
* Esc / 空答 / 认不出的自由文本 / 作答看门狗到点 / 呈卡失败 —— 一律收口成 ③(零动作)。
|
|
27
|
+
* 破坏性动作只认**逐字命中**的显式选择({@link resumeChoiceFromLabels})。
|
|
28
|
+
*
|
|
29
|
+
* ── 🔴 假 affordance 禁令(按供给渲)───────────────────────────────────────────────────────
|
|
30
|
+
* 一个按了没用的选项比没有这个选项更坏:durable `runs.events` 动词缺席**或**没有接管消费口 ⇒
|
|
31
|
+
* ① 整个不渲;`runs.cancel` 缺席 ⇒ ② 整个不渲;两条都缺 ⇒ 一张卡都不铸,走 §3.2b 臂。
|
|
32
|
+
*
|
|
33
|
+
* ── 归层 ────────────────────────────────────────────────────────────────────────────────────
|
|
34
|
+
* 本文件 = 纯判定 + 选项集 + 文案,**零 import**。呈卡口/动词切片/判活口/指路 sink/退出码应用口
|
|
35
|
+
* 全部由端在装配点注入;端只剩装配与呈现。
|
|
36
|
+
*/
|
|
37
|
+
// ── 逐字契约面(答案按 label 原样回声 —— 引擎的 `selected ⊆ options` 围栏,漂一个字节即失灵)──
|
|
38
|
+
/** ① 接管观看。 */
|
|
39
|
+
export const RESUME_CHOICE_ATTACH_LABEL = 'Attach and watch';
|
|
40
|
+
/** ② 用户显式取消(自动 cancel 那个动作的降级形)。 */
|
|
41
|
+
export const RESUME_CHOICE_CANCEL_LABEL = 'Cancel it';
|
|
42
|
+
/** ③ 后台留着 —— 🔴 **默认焦点**,所以它必须排在 options[0](见 {@link resumeRunningOptions})。 */
|
|
43
|
+
export const RESUME_CHOICE_BACKGROUND_LABEL = 'Leave it running in the background';
|
|
44
|
+
/** 卡的 header(答案按 header 归键;本卡只有一问)。与 409 三选卡的入口刻意不同词 —— 同一张卡的
|
|
45
|
+
* 两个入口,题面说的不是一件事。 */
|
|
46
|
+
export const RESUME_CHOICE_HEADER = 'Earlier run still in flight';
|
|
47
|
+
/**
|
|
48
|
+
* §3.2a 活性证据行。**缺席 ⇒ null(整行不渲)**;绝不渲 0、绝不渲「已死」。
|
|
49
|
+
* 负数 / 非有限值同样按缺席处理(wire 位 UNTRUSTED,类型说是 number 也要真判)。
|
|
50
|
+
*/
|
|
51
|
+
export function resumeRunningLivenessRow(msSinceLastActivity) {
|
|
52
|
+
const ms = msSinceLastActivity;
|
|
53
|
+
if (typeof ms !== 'number' || !Number.isFinite(ms) || ms < 0)
|
|
54
|
+
return null;
|
|
55
|
+
return `The engine last recorded activity on it ${String(Math.round(ms / 1000))}s ago.`;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* 卡的题面。第二行 = 活性证据(§3.2a 缺席时**整行消失**,不留占位、不留「unknown」字样 ——
|
|
59
|
+
* 一行「last activity: unknown」和一行 0 一样是在替引擎回答一个它没回答的问题)。
|
|
60
|
+
*/
|
|
61
|
+
export function resumeRunningQuestionText(i) {
|
|
62
|
+
const head = `This conversation was resumed while an earlier turn is still executing on the engine ` +
|
|
63
|
+
`(run ${i.taskId}, status ${i.status}). sema did not touch it. What should it do?`;
|
|
64
|
+
const liveness = resumeRunningLivenessRow(i.msSinceLastActivity);
|
|
65
|
+
return liveness === null ? head : `${head}\n${liveness}`;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* 选项集(同一张卡两个入口,选项集**按入口分形**)。
|
|
69
|
+
*
|
|
70
|
+
* 🔴 **顺序即默认焦点**:卡的渲染面 `focusedIndex` 初值恒 0,而 wire 的 `QuestionFrame` 里
|
|
71
|
+
* **没有**任何「默认焦点」位可传。所以「默认焦点 = ③ 后台留着」在结构上只有一个落法:把 ③ 排在
|
|
72
|
+
* options[0]。谁哪天为了「读起来顺」把 ①②③ 按序号排回去,默认焦点就漂到了 `Attach and watch`
|
|
73
|
+
* —— 一个手滑回车就把一条后台 run 接管到前台。常驻门逐位反钉这个顺序。
|
|
74
|
+
*/
|
|
75
|
+
export function resumeRunningOptions(i) {
|
|
76
|
+
const options = [
|
|
77
|
+
{
|
|
78
|
+
// 🔴 默认焦点 —— 三条路里唯一零副作用的一条,所以它是手滑回车的落点。
|
|
79
|
+
// 🔴 措辞:这一项**不许**承诺「它会留在某个任务面板里」—— 这张卡的前提恰恰是「那条 run 活得
|
|
80
|
+
// 比上一个客户端进程久」,新进程里没有任何腿会为它建行(③ 的处置本身也是显式零动作)。
|
|
81
|
+
// 默认焦点上的一句假 affordance 是最坏的一格:手滑回车的人拿到一条既看不见、也停不掉、
|
|
82
|
+
// 还占着会话锁的 run。换成两句**可证的**真话:本屏不会列出它;它还占着会话,所以下一条
|
|
83
|
+
// 消息会再撞上它(那时 409 三选卡会带着 steer/cancel 两条真出路出现)。
|
|
84
|
+
label: RESUME_CHOICE_BACKGROUND_LABEL,
|
|
85
|
+
description: 'Leaves the run alone. It keeps executing on the engine, but this screen will not show it and it will not be listed here — your next message runs into it again, and sema asks you then.',
|
|
86
|
+
},
|
|
87
|
+
];
|
|
88
|
+
if (i.canAttach) {
|
|
89
|
+
options.push({
|
|
90
|
+
label: RESUME_CHOICE_ATTACH_LABEL,
|
|
91
|
+
// 🔴 第二句是**知情同意**那一半(见 {@link resumeAttachReplayDisclosure}):resume 入口没有
|
|
92
|
+
// 事件锚可用,durable 尾只能从这条 run 的第一帧读起,所以崩溃前已经落盘并被 resume 还原到
|
|
93
|
+
// 屏上的那一段会再出现一次。用户按下之前就得看见这句 —— 一个会做出用户没预料到的事的
|
|
94
|
+
// 选项,和一个按了没用的选项同样是假 affordance。
|
|
95
|
+
description: 'Follows that run from here: sema replays it from the engine ledger and keeps streaming it into this conversation. ' +
|
|
96
|
+
'Anything from that turn already shown above will appear a second time — sema has no resume marker for it.',
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
if (i.canCancel) {
|
|
100
|
+
options.push({
|
|
101
|
+
label: RESUME_CHOICE_CANCEL_LABEL,
|
|
102
|
+
description: 'Stops that run on the engine (whatever it has been doing is discarded) and frees this session for a new turn.',
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
return options;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* 答案 → 决定。🔴 只认**逐字命中**的标签;空答(overlay 的 Esc/dismiss 形)、多选、认不出的
|
|
109
|
+
* 自由文本一律回落 ③ —— 破坏性动作只认显式选择(与 409 三选卡同律)。
|
|
110
|
+
*/
|
|
111
|
+
export function resumeChoiceFromLabels(selected) {
|
|
112
|
+
if (!Array.isArray(selected) || selected.length !== 1)
|
|
113
|
+
return 'background';
|
|
114
|
+
const label = selected[0];
|
|
115
|
+
if (label === RESUME_CHOICE_ATTACH_LABEL)
|
|
116
|
+
return 'attach';
|
|
117
|
+
if (label === RESUME_CHOICE_CANCEL_LABEL)
|
|
118
|
+
return 'cancel';
|
|
119
|
+
return 'background';
|
|
120
|
+
}
|
|
121
|
+
// ── §3.2b 无 UI 臂 ───────────────────────────────────────────────────────────────────────────
|
|
122
|
+
/**
|
|
123
|
+
* headless 车道撞 resume-running 的**专码**退出码。
|
|
124
|
+
*
|
|
125
|
+
* 为什么非 0:这一趟 resume **没有**把会话交到一个可用状态 —— 那条 run 还占着会话,脚本接下来
|
|
126
|
+
* 提交什么都会撞 409。静默 0 = 谎报成功。
|
|
127
|
+
* 为什么是 75:sysexits.h 的 `EX_TEMPFAIL`(「暂时性失败,请稍后重试」)语义正对 —— run 跑完
|
|
128
|
+
* 或被取消之后同一条命令就能过;与 cli 既用的 0/1/2/129/143 零撞(脚本消费者据此可以把「会话被
|
|
129
|
+
* 在飞 run 占住」与「真失败(1)」「用法错(2)」分臂)。
|
|
130
|
+
*/
|
|
131
|
+
export const RESUME_RUNNING_NO_UI_EXIT_CODE = 75;
|
|
132
|
+
/** 机读指路的行首标识 —— 脚本按它 grep;UI 改版不许动它。 */
|
|
133
|
+
export const RESUME_RUNNING_GUIDANCE_TAG = 'sema: resume-running:';
|
|
134
|
+
/**
|
|
135
|
+
* §3.2b 的**机读三选指路**。三条路各给真实命令或 API 路径,一条都不许省 ——
|
|
136
|
+
* 少写一条 = 那条路在这个车道上被客户端单方面关掉了。
|
|
137
|
+
*
|
|
138
|
+
* 🔴 `attach=` 那一行只有在**真知道 session id** 时才给具体命令:不知道还硬拼一条
|
|
139
|
+
* `sema --resume <sessionId>` 字面量,就是印一条按了没用的命令(假 affordance 的文本形)。
|
|
140
|
+
*/
|
|
141
|
+
export function resumeRunningNoUiGuidance(i) {
|
|
142
|
+
const sid = typeof i.sessionId === 'string' && i.sessionId.length > 0 ? i.sessionId : null;
|
|
143
|
+
const attach = sid === null ? 'sema --resume (pick this session from the list)' : `sema --resume ${sid}`;
|
|
144
|
+
const T = RESUME_RUNNING_GUIDANCE_TAG;
|
|
145
|
+
return [
|
|
146
|
+
`${T} run ${i.taskId} from an earlier turn is still executing on the engine, and this lane has no card to ask you on. sema did NOT cancel it and did NOT attach to it.`,
|
|
147
|
+
`${T} attach=${attach}`,
|
|
148
|
+
`${T} cancel=POST /v1/runs/${i.taskId}/cancel`,
|
|
149
|
+
// 🔴 这条车道连 REPL 都不挂载,更没有任何本地面板可看。给的是引擎侧真读面。
|
|
150
|
+
`${T} background=do nothing — run ${i.taskId} keeps executing on the engine; this client does not list it (read it with GET /v1/runs/${i.taskId})`,
|
|
151
|
+
].join('\n');
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* ① 接管之前的**显式披露**。
|
|
155
|
+
*
|
|
156
|
+
* resume 入口没有 `lastEventId` 可用(端今天不持久化引擎事件锚),所以 durable 尾从这条 run 的
|
|
157
|
+
* 第一帧读起 —— 崩溃前已落盘、已被 resume 还原到屏上的那一段会再渲一遍。续听腿那道「无锚 × 已上屏
|
|
158
|
+
* ⇒ 不许从头续读」的门在这一格判不出来(它数的是**本条流**吐过几帧,resume 入口恒 0),所以不能
|
|
159
|
+
* 拿它当安全证明。处置 = 说在前面:静默复读会让用户以为模型把同一段活干了两遍。
|
|
160
|
+
*
|
|
161
|
+
* 🔴 **账目面同源**:同一次重放也会把这条 run 已经执行过的每一个 `turn_end` 再喂一次成本累计器。
|
|
162
|
+
* 客户端这一端证明不了哪一枚已经在恢复出来的总额里(那需要一本按 turn 落盘的账 —— 与缺席的
|
|
163
|
+
* 事件锚是同一件移交残件),所以接管腿声明**不计账**。既然不计,就必须在**同一行**说清楚:
|
|
164
|
+
* 只披露视觉复读、不披露账目缺口,用户拿成本面跟引擎账本对不上时只会怀疑客户端算错了。
|
|
165
|
+
*/
|
|
166
|
+
export function resumeAttachReplayDisclosure(taskId) {
|
|
167
|
+
return (`sema: attaching to run ${taskId} — sema is replaying it from the engine's ledger, so anything from that ` +
|
|
168
|
+
`turn already shown above will appear again below. There is no resume marker for a run that outlived its shell. ` +
|
|
169
|
+
`The replayed turns are not billed into this session's cost again either — the engine's own record ` +
|
|
170
|
+
`(GET /v1/runs/${taskId}) is the authority on what that run really spent.`);
|
|
171
|
+
}
|
|
172
|
+
/** ② 打完 cancel 但引擎没确认落地时的如实一行(绝不谎报「已停止」)。 */
|
|
173
|
+
export function resumeRunningCancelUnconfirmedRow(taskId) {
|
|
174
|
+
return (`sema: the cancel for run ${taskId} did not come back confirmed, so that run may still be executing. ` +
|
|
175
|
+
`This screen does not list it — read its real state on the engine (GET /v1/runs/${taskId}) before ` +
|
|
176
|
+
`assuming this session is free.`);
|
|
177
|
+
}
|
|
@@ -69,10 +69,13 @@
|
|
|
69
69
|
* 规则逐字节相同、更不是它的 id;下游「删除/撤销规则」面拿它当身份用 = 删错或删不掉。
|
|
70
70
|
* ② **deny 归因通道**({@link ApprovalCardDenyDecision.reason}):两腿不同形 ——
|
|
71
71
|
* durable `/decide` **有** reason 位 ⇒ 原文上 wire(包内按 server 4096 上限截断);
|
|
72
|
-
* live 帧腿 `/v1/tool-approvals/:id/respond
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
72
|
+
* live 帧腿 `/v1/tool-approvals/:id/respond`:✅ **#229 已兑现**(0.29.0 respond-note 批,
|
|
73
|
+
* server ≥7.15.0)—— 端点收 **`note`**(不是 reason;与 durable `AskDecisionBody.note`
|
|
74
|
+
* 同词同源同一列 `decision_note`),deny reason 经 {@link RespondToolApprovalOpts.note} 上 wire。
|
|
75
|
+
* 发送前置两道门:能力位 `approvalDecisionNote`(SDK 6.16 成文「位缺席就别发」)+ 2048 上限
|
|
76
|
+
* (server 超限响亮 400 且**连决断一起拒**,所以超限 ⇒ 整条不发 + 留痕,诚实缺席优先于
|
|
77
|
+
* 静默截断);真落行与否看 ack 的 `noteRecorded`(缺席 ≠ false)。
|
|
78
|
+
* 🔴 方向纪律:reason/note 只做归因,绝不参与裁决;缺席 ⇒ 现状字节不变。
|
|
76
79
|
*/
|
|
77
80
|
import { type HitlClientLike } from './hitlBridge.js';
|
|
78
81
|
import type { RuleSuggestion, ToolApprovalRespondAck } from '@sema-agent/sdk';
|
|
@@ -139,8 +142,14 @@ export interface ApprovalCardDenyDecision {
|
|
|
139
142
|
* 这次决断仍是 deny(两条腿上的 `decision` 位逐字节不动)。
|
|
140
143
|
* 🔴 **两腿不同形**(见 {@link surfaceFsApprovalAndDecide} / {@link surfaceToolApprovalFrameAndRespond}):
|
|
141
144
|
* · durable park 腿(`/decide`)wire **有** reason 位 ⇒ 原文上 wire(包内按 server 上限截断);
|
|
142
|
-
* · live 帧腿(`/v1/tool-approvals/:id/respond`)
|
|
143
|
-
*
|
|
145
|
+
* · live 帧腿(`/v1/tool-approvals/:id/respond`)的 `decision` 仍是三词闭集,归因走**另一个键
|
|
146
|
+
* `note`**(与 durable `AskDecisionBody.note` 同词同源同一列 `decision_note`)—— 本位的原文经
|
|
147
|
+
* 两道门后落到 `RespondToolApprovalOpts.note` 上 wire:能力位
|
|
148
|
+
* `approvalDecisionNoteCapable === true`,且长度不超 `MAX_RESPOND_NOTE_CHARS`;任一不满足则
|
|
149
|
+
* 只留痕不发(绝不自造侧信道)。发了还要看 ack 的 `noteRecorded` 才算落行。
|
|
150
|
+
* ⚠️ 本段 0.28.0 原文写的是「wire 无 reason 位、只留痕不发,候 server 补位」—— server 7.15.0
|
|
151
|
+
* 已到货、0.29.0 #229 已兑现,那句话从此不成立(2026-08-13 类型/wire 超集台账普查时发现该
|
|
152
|
+
* JSDoc 已陈旧;实现坐标见 {@link surfaceToolApprovalFrameAndRespond} 里的 note 两道门)。
|
|
144
153
|
* 与 `{kind:'failed'}` 的 `reason` **不同义**:那一位是「卡面本身不可用」的诊断,不是人的拒因,
|
|
145
154
|
* 两者绝不互相顶替。
|
|
146
155
|
*/
|
|
@@ -158,7 +167,17 @@ export interface ApprovalCardRequest {
|
|
|
158
167
|
args: object;
|
|
159
168
|
callKey: string;
|
|
160
169
|
signal?: AbortSignal;
|
|
161
|
-
/**
|
|
170
|
+
/**
|
|
171
|
+
* 后台子代 ask 的归属徽章(卡头 `· @name`;宿主 ask 恒缺席)。
|
|
172
|
+
* ⚠️ **出身声明订正**(0.30.0 发包扫描,2026-08-14):本段 0.28.0 原文写的是「CC swarm workerBadge
|
|
173
|
+
* **原生位**」。类型/wire 超集台账普查逐份直证的结果与那句话相反 —— CC 语料九份
|
|
174
|
+
* (cli220/221/222/223 + pretty218/219/220/221/223)`workerBadge` **全 0 命中**(正控:同一把探针在
|
|
175
|
+
* 同目录对 `permissionMode` 有命中,证明它会说话),`@sema-agent/agent-types` 0.2.0 镜像的 TS AST
|
|
176
|
+
* 声明名集合(1651 个名字)里也没有这个名字。⇒ 这一位按现有证据是 **sema 自铸**,不是 CC 原生位;
|
|
177
|
+
* 终判(让位/改名/登记为超集)候台账 `docs/type-superset.json` 的 `_covenant`「未建工作」条清账。
|
|
178
|
+
* 🔴 三端读到的 `.d.ts` 注释随 dist 出包,所以订正必须落在这里 —— 只在不进 tarball 的台账里留话,
|
|
179
|
+
* 消费端读到的仍是那句错误出身断言。
|
|
180
|
+
*/
|
|
162
181
|
workerBadge?: {
|
|
163
182
|
name: string;
|
|
164
183
|
color: string;
|
|
@@ -167,10 +186,19 @@ export interface ApprovalCardRequest {
|
|
|
167
186
|
* 不可注入 args 的提示走这里([1543]③ 记账的 note 位,2026-07-23 落位)。 */
|
|
168
187
|
wireNote?: string;
|
|
169
188
|
/**
|
|
170
|
-
* 治理强制位(server ≥7.5.0,2026-08-08 补透传)
|
|
171
|
-
*
|
|
172
|
-
*
|
|
173
|
-
*
|
|
189
|
+
* 治理强制位(server ≥7.5.0,2026-08-08 补透传)。**缺席 ≠ false**:只在为真时在场,缺席 = 无治理
|
|
190
|
+
* 来源的证据。壳应据此把门呈成**表态掀不掉**(而不是引导用户去改 `permissionMode`);呈现形是壳
|
|
191
|
+
* 半场,本包只保证这一位到得了卡口 —— 此前它在帧类型上就不存在,于是宿主无论怎么写都读不到。
|
|
192
|
+
*
|
|
193
|
+
* 🔴 **本位是双源合流**(0.30.0 发包扫描订正,2026-08-14;本段原文只写「原样来自
|
|
194
|
+
* {@link ToolApprovalFrame.governanceForced}」,而 [C170] 那一批起 durable 腿也往这一位灌):
|
|
195
|
+
* · **活卡帧腿**:`ToolApprovalFrame.governanceForced`(进程内治理标记表);
|
|
196
|
+
* · **durable park 行腿**:`PendingCheckpoint.governanceForced`(`surfaceFsApprovalAndDecide` 的
|
|
197
|
+
* 行 → 卡重铸处 stamp,条件同样只认 `=== true`)。
|
|
198
|
+
* ⚠️ 上游对这两位的关系有逐字声明(sdk 6.17.2 `PendingCheckpoint` JSDoc):判据属主是
|
|
199
|
+
* `governanceOriginOf`(行上取证格 ∧ 部署姿态合取),与活卡帧那位**语义同族、判据不同源**,
|
|
200
|
+
* 「同一只 ask 两条腿的在场性可以不一致」。⇒ 宿主**不许**把本位读成「活卡帧的治理标记」:
|
|
201
|
+
* 帧腿缺席不等于 durable 腿缺席,反之亦然;要区分来源就看你拿到的是哪条腿的卡。
|
|
174
202
|
*/
|
|
175
203
|
governanceForced?: true;
|
|
176
204
|
/** 委派出处链(core 5.9.0 W1)——原样来自 {@link ToolApprovalFrame.delegation};只读展示增强,
|
|
@@ -183,6 +211,17 @@ export interface ApprovalCardRequest {
|
|
|
183
211
|
* 出身裁剪(MANDATED ask 不提供本档)候 core 5.25.0 出身键 wire 过境,见 #144/[3438]/[3442]。
|
|
184
212
|
*/
|
|
185
213
|
ruleSuggestions?: RuleSuggestion[];
|
|
214
|
+
/**
|
|
215
|
+
* 持久规则候选的**只读**对偶([C170] 答问②半场,0.29.0)——原样来自 durable 队列行
|
|
216
|
+
* `PendingCheckpoint.ruleSuggestions`(server 7.16.0 [3684]② 补齐的供给)的合形项。
|
|
217
|
+
* 🔴 与 {@link ruleSuggestions} **刻意分键不合流**:那一位的契约是「卡渲可选中的『不再询问』档
|
|
218
|
+
* → 决断带 {@link ApprovalCardAllowDecision.persistRule} 回兑」,兑付口=同副本活卡腿
|
|
219
|
+
* `respond.persistRule`;而 durable 腿的 `/decide` 体**无规则位**(SDK 6.17.2 PendingCheckpoint
|
|
220
|
+
* JSDoc 逐字:display/triage-only)——把行上候选落进那一位,就是一个按下去规则不落地的假
|
|
221
|
+
* affordance。卡口对本键只许**只读渲染**(chips/说明行),绝不渲成可选中项、决断绝不因它带
|
|
222
|
+
* `persistRule`。缺席 = 无候选/老行/坏形(三者同形,不猜);既有卡口不读本键 ⇒ 卡形字节不变。
|
|
223
|
+
*/
|
|
224
|
+
ruleSuggestionsReadOnly?: RuleSuggestion[];
|
|
186
225
|
/**
|
|
187
226
|
* 被越级的持久 allow 规则**原文**(#144,原样来自 {@link ToolApprovalFrame.persistedRuleShadowed}
|
|
188
227
|
* 的合形值)——壳据此渲「你的规则仍在,只是这次调用被要求逐次确认」;缺席 = 卡形与 0.27.0
|
|
@@ -305,8 +344,9 @@ export interface ToolApprovalFrame {
|
|
|
305
344
|
* {@link ApprovalCardRequest.persistedRuleShadowed} 的同名警示(下游删除规则面不许拿它当规则身份)。
|
|
306
345
|
*
|
|
307
346
|
* 耐久路(park 行)的对偶是 `gate.riskDescriptor.shadowedRule`(server 对 riskDescriptor 整体透传);
|
|
308
|
-
*
|
|
309
|
-
*
|
|
347
|
+
* durable 腿自 0.29.0 起 stamp 行上的 governanceForced/ruleSuggestionsReadOnly 两个展示键
|
|
348
|
+
* ([C170] 答问②半场,见 {@link surfaceFsApprovalAndDecide} 的卡入参),但 shadowedRule 的
|
|
349
|
+
* 耐久对偶仍未消费——那一路是独立的一件,不在本键的施工面内。
|
|
310
350
|
*/
|
|
311
351
|
persistedRuleShadowed?: string;
|
|
312
352
|
}
|
|
@@ -350,6 +390,11 @@ export interface RespondToolApprovalOpts {
|
|
|
350
390
|
updatedInput?: unknown;
|
|
351
391
|
/** #225 件1:兑付键 —— 帧候选之一的**原文**(编排层已做表内核对与 deny 剥除)。 */
|
|
352
392
|
persistRule?: string;
|
|
393
|
+
/** #229(server ≥7.15.0):回决备注 —— 与 durable 腿 `AskDecisionBody.note` **同词同源同一列**
|
|
394
|
+
* (`decision_note`,≤2048)。任何 decision 都可带(deny 的「为什么拒」正是审计面上最值钱的
|
|
395
|
+
* 一条);真落行与否看 ack 的 {@link surfaceToolApprovalFrameAndRespond} 消费的 `noteRecorded`。
|
|
396
|
+
* 🔴 编排层(本文件)只在能力位确认 + 上限内才填本位 —— 注入面原样透传,别自己再判。 */
|
|
397
|
+
note?: string;
|
|
353
398
|
}
|
|
354
399
|
export type RespondToolApprovalFn = (approvalId: string, decision: ToolApprovalRespondDecision, opts?: RespondToolApprovalOpts) => Promise<ToolApprovalRespondAck | void>;
|
|
355
400
|
/**
|
|
@@ -380,13 +425,14 @@ export interface ToolApprovalFrameOutcome {
|
|
|
380
425
|
* `AgentEvent` 的臂了(durable 腿也回放),所以结构识别与 union 收窄两条路都成立;本函数仍按
|
|
381
426
|
* 结构读(不依赖类型收窄),因为它同时服务 raw SSE 与 durable 回放两条入口。 */
|
|
382
427
|
export declare function isToolApprovalFrame(ev: unknown): ev is ToolApprovalFrame;
|
|
383
|
-
/**
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
428
|
+
/** 帧腿的宿主车道参数(#229 respond-note 批,0.29.0)。 */
|
|
429
|
+
export interface ToolApprovalFrameLaneOpts {
|
|
430
|
+
/**
|
|
431
|
+
* server 能力位 `capabilities.approvalDecisionNote` 的读数(宿主从自己的 caps 缓存供给)。
|
|
432
|
+
* 🔴 SDK 6.16 成文:**位缺席就别发 `note`** —— 老 server 对未知请求键静默忽略且照回 200,
|
|
433
|
+
* 「这台不认识 note」与「记上了」在响应上不可分,发了只造「已留档」的错觉。
|
|
434
|
+
* 缺席/false ⇒ 不发(fail-closed 到「不发」侧;决断本身照常送达,现状字节不变)。
|
|
435
|
+
*/
|
|
436
|
+
approvalDecisionNoteCapable?: boolean;
|
|
437
|
+
}
|
|
438
|
+
export declare function surfaceToolApprovalFrameAndRespond(frame: ToolApprovalFrame, respond: RespondToolApprovalFn, streamArgs: unknown | undefined, signal?: AbortSignal, lane?: ToolApprovalFrameLaneOpts): Promise<ToolApprovalFrameOutcome>;
|
|
@@ -69,16 +69,20 @@
|
|
|
69
69
|
* 规则逐字节相同、更不是它的 id;下游「删除/撤销规则」面拿它当身份用 = 删错或删不掉。
|
|
70
70
|
* ② **deny 归因通道**({@link ApprovalCardDenyDecision.reason}):两腿不同形 ——
|
|
71
71
|
* durable `/decide` **有** reason 位 ⇒ 原文上 wire(包内按 server 4096 上限截断);
|
|
72
|
-
* live 帧腿 `/v1/tool-approvals/:id/respond
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
72
|
+
* live 帧腿 `/v1/tool-approvals/:id/respond`:✅ **#229 已兑现**(0.29.0 respond-note 批,
|
|
73
|
+
* server ≥7.15.0)—— 端点收 **`note`**(不是 reason;与 durable `AskDecisionBody.note`
|
|
74
|
+
* 同词同源同一列 `decision_note`),deny reason 经 {@link RespondToolApprovalOpts.note} 上 wire。
|
|
75
|
+
* 发送前置两道门:能力位 `approvalDecisionNote`(SDK 6.16 成文「位缺席就别发」)+ 2048 上限
|
|
76
|
+
* (server 超限响亮 400 且**连决断一起拒**,所以超限 ⇒ 整条不发 + 留痕,诚实缺席优先于
|
|
77
|
+
* 静默截断);真落行与否看 ack 的 `noteRecorded`(缺席 ≠ false)。
|
|
78
|
+
* 🔴 方向纪律:reason/note 只做归因,绝不参与裁决;缺席 ⇒ 现状字节不变。
|
|
76
79
|
*/
|
|
77
80
|
import { DEFAULT_DENY_REASON, HitlBridge, HitlSafetyError, denyReasonForWire, findPendingForTask, } from './hitlBridge.js';
|
|
78
81
|
import { hostLog } from '../host.js';
|
|
79
82
|
import { createSessionSlot, DEFAULT_SESSION_KEY } from '../sessionSlot.js';
|
|
80
83
|
import { readEngineActiveBgTasks } from '../fleet/fleetLedger.js';
|
|
81
84
|
import { observeCancelByDeny, surfaceRememberNotApplied, surfaceEditNotForwarded } from './hitlHostSurface.js';
|
|
85
|
+
import { approvalCallKey, liveFrameCallKey } from './gateIdentity.js';
|
|
82
86
|
/** fs 写权限 gate 判定:未来的一等 kind(tool_approval)或按 toolName(server 桥首批=fs 写三件,
|
|
83
87
|
* [820] 表)。AskUserQuestion 永不进这里(ask 桥先判)。 */
|
|
84
88
|
export function isFsApprovalGate(gate) {
|
|
@@ -242,12 +246,22 @@ export async function surfaceFsApprovalAndDecide(deps, taskId, argsByCall, signa
|
|
|
242
246
|
return { kind: 'failed', gatedCallId, reason: 'gate has no tool input payload' };
|
|
243
247
|
}
|
|
244
248
|
const bridge = new HitlBridge(deps.client, taskId);
|
|
245
|
-
|
|
249
|
+
// A-028.3:卡身份键经 gateIdentity 唯一铸口(呈现台账/壳侧重开腿同源,字面不再各铸各的)。
|
|
250
|
+
const callKey = approvalCallKey(gatedCallId, taskId);
|
|
251
|
+
// [C170] 答问②半场(0.29.0):durable 富行的两个展示键随卡透传 —— 修前这里是四位闭集,
|
|
252
|
+
// server 7.16.0 起行上就有的 ruleSuggestions/governanceForced 在「行 → 卡」重铸处整段丢失
|
|
253
|
+
// (feed 行原样透传零丢失,丢的只有这处)。governanceForced 条件 stamp 只认 === true(缺席
|
|
254
|
+
// 纪律与活卡腿同款:缺席=无治理来源证据,绝不写 false);候选走 readRuleSuggestions 同一把
|
|
255
|
+
// 合形窄化,落**只读键**(红线见 ApprovalCardRequest.ruleSuggestionsReadOnly 顶注:/decide
|
|
256
|
+
// 无规则位,落可兑付位=假 affordance)。
|
|
257
|
+
const ruleSuggestionsReadOnly = readRuleSuggestions(pending.ruleSuggestions);
|
|
246
258
|
const card = await surfaceApprovalCard({
|
|
247
259
|
toolName,
|
|
248
260
|
args,
|
|
249
261
|
callKey,
|
|
250
262
|
...(signal ? { signal } : {}),
|
|
263
|
+
...(pending.governanceForced === true ? { governanceForced: true } : {}),
|
|
264
|
+
...(ruleSuggestionsReadOnly !== undefined ? { ruleSuggestionsReadOnly } : {}),
|
|
251
265
|
});
|
|
252
266
|
switch (card.kind) {
|
|
253
267
|
case 'failed':
|
|
@@ -408,6 +422,9 @@ export function readToolApprovalRespondAck(v) {
|
|
|
408
422
|
...(typeof o.ruleRefusal === 'string' && o.ruleRefusal !== ''
|
|
409
423
|
? { ruleRefusal: o.ruleRefusal }
|
|
410
424
|
: {}),
|
|
425
|
+
// #229(sdk 6.16.0):这次回决的 note 有没有**真落进持久行**。缺席 ≠ false(未带 note 的回决/
|
|
426
|
+
// 老 server 字段省略);非布尔降缺席 —— 它决定「审计理由记没记上」的诚实告知。
|
|
427
|
+
...(typeof o.noteRecorded === 'boolean' ? { noteRecorded: o.noteRecorded } : {}),
|
|
411
428
|
};
|
|
412
429
|
}
|
|
413
430
|
/** 结构性识别流上的 tool_approval 帧(named SSE frame,payload.type === 帧名)。
|
|
@@ -497,7 +514,10 @@ function subagentBadgeFor(frame) {
|
|
|
497
514
|
*
|
|
498
515
|
* @returns {@link ToolApprovalFrameOutcome} —— 决断 + server ack(ack 缺席 = 未知,不是 false)。
|
|
499
516
|
*/
|
|
500
|
-
|
|
517
|
+
/** respond `note` 位的 server 上限(server `MAX_DECISION_NOTE_CHARS` = 2048,与 durable
|
|
518
|
+
* `AskDecisionBody.note` 同一列;超限 server **响亮 400 且连决断一起拒**,所以本包发送前有界)。 */
|
|
519
|
+
const MAX_RESPOND_NOTE_CHARS = 2048;
|
|
520
|
+
export async function surfaceToolApprovalFrameAndRespond(frame, respond, streamArgs, signal, lane) {
|
|
501
521
|
const toolName = typeof frame.toolName === 'string' ? frame.toolName : 'Write';
|
|
502
522
|
// 工具入参:流上 tool_start.args(完整一手源)> 帧 args(redacted+16KiB 帽)> message 兜 path。
|
|
503
523
|
let args = streamArgs !== undefined && streamArgs !== null
|
|
@@ -527,7 +547,8 @@ export async function surfaceToolApprovalFrameAndRespond(frame, respond, streamA
|
|
|
527
547
|
const card = await surfaceApprovalCard({
|
|
528
548
|
toolName,
|
|
529
549
|
args: args,
|
|
530
|
-
|
|
550
|
+
// A-028.3:live 帧腿的卡身份键经 gateIdentity 唯一铸口(帧上无 gatedCallId,以 approvalId 铸)。
|
|
551
|
+
callKey: liveFrameCallKey(frame.approvalId),
|
|
531
552
|
...(signal ? { signal } : {}),
|
|
532
553
|
...(isFromSubagent(frame) ? { workerBadge: subagentBadgeFor(frame) } : {}),
|
|
533
554
|
...(wireNote !== undefined ? { wireNote } : {}),
|
|
@@ -554,24 +575,31 @@ export async function surfaceToolApprovalFrameAndRespond(frame, respond, streamA
|
|
|
554
575
|
if (card.kind === 'failed') {
|
|
555
576
|
hostLog('debug', `liveToolApprovalWire: approval card unavailable (${card.reason}) — fail-closed deny for ${frame.approvalId}`);
|
|
556
577
|
}
|
|
557
|
-
// #
|
|
558
|
-
// (
|
|
559
|
-
//
|
|
560
|
-
//
|
|
561
|
-
//
|
|
562
|
-
//
|
|
563
|
-
//
|
|
564
|
-
//
|
|
565
|
-
//
|
|
566
|
-
//
|
|
567
|
-
|
|
568
|
-
// 0.28.0 发版扫描 F4:本腿留痕**不借** denyReasonForWire —— 那个窄化器的超限日志讲的是
|
|
569
|
-
// 「413 会丢掉决断」,对 respond 端点是假话(它根本不收 reason,无 413 可言);且截断后 len
|
|
570
|
-
// 恒 4096,掩盖真实丢弃量。本地判空白+报**原始**长度,只说这条腿真实发生的事:归因整条没发。
|
|
578
|
+
// #229 兑现(0.29.0 respond-note 批;此前 0.28.0 记账「候 server」,server 7.15.0 已到货):
|
|
579
|
+
// respond 端点收 **`note`**(不是 reason —— 与 durable `AskDecisionBody.note` 同词同源同一列
|
|
580
|
+
// `decision_note`),任何 decision 都可带。deny reason 经它上 wire,发送前置两道门:
|
|
581
|
+
// · 能力位(`lane.approvalDecisionNoteCapable === true`)—— SDK 6.16 成文「位缺席就别发」:
|
|
582
|
+
// 老 server 静默忽略未知键照回 200,「没听懂」与「记上了」不可分,发了只造「已留档」错觉;
|
|
583
|
+
// · 上限(≤{@link MAX_RESPOND_NOTE_CHARS}=2048)—— server 超限**响亮 400 且连决断一起拒**,
|
|
584
|
+
// 而备注是决断的补充面,绝不许它把决断本身打失败。超限 ⇒ **整条不发** + 留痕
|
|
585
|
+
// (诚实缺席优先于静默截断 —— 「一条被悄悄砍半的审计理由比没有理由更坏」,server 同款立场)。
|
|
586
|
+
// 🔴 留痕纪律不变:只写**元数据**(在场 + 长度 + 没发的原因),绝不把正文拷进日志 ——
|
|
587
|
+
// 正文是宿主自己卡口返回的自由文本,回喂宿主 sink 零诊断增量,还是外溢/注入面。
|
|
588
|
+
let note;
|
|
571
589
|
if (card.kind === 'deny' && typeof card.reason === 'string' && card.reason.trim() !== '') {
|
|
572
|
-
|
|
573
|
-
'
|
|
574
|
-
|
|
590
|
+
if (lane?.approvalDecisionNoteCapable !== true) {
|
|
591
|
+
hostLog('debug', `liveToolApprovalWire: ${frame.approvalId} card supplied a deny reason (len=${card.reason.length}) but the ` +
|
|
592
|
+
'approvalDecisionNote capability is not confirmed for this engine — note not sent (an unknown key would be ' +
|
|
593
|
+
'silently swallowed by an older server while still acking 200)');
|
|
594
|
+
}
|
|
595
|
+
else if (card.reason.length > MAX_RESPOND_NOTE_CHARS) {
|
|
596
|
+
hostLog('debug', `liveToolApprovalWire: ${frame.approvalId} deny reason exceeds the decision_note cap ` +
|
|
597
|
+
`(len=${card.reason.length} > ${MAX_RESPOND_NOTE_CHARS}) — note not sent at all (the server rejects the WHOLE ` +
|
|
598
|
+
'respond with 400 over an oversize note, and a silently halved audit reason is worse than none)');
|
|
599
|
+
}
|
|
600
|
+
else {
|
|
601
|
+
note = card.reason;
|
|
602
|
+
}
|
|
575
603
|
}
|
|
576
604
|
try {
|
|
577
605
|
// abort 后的 deny 仍要送达(引擎侧同款 cancel-by-deny)——不带已 aborted 的 signal。
|
|
@@ -592,6 +620,7 @@ export async function surfaceToolApprovalFrameAndRespond(frame, respond, streamA
|
|
|
592
620
|
...(signal && !signal.aborted ? { signal } : {}),
|
|
593
621
|
...(card.kind === 'allow' && card.updatedInput !== undefined ? { updatedInput: card.updatedInput } : {}),
|
|
594
622
|
...(persistRule !== undefined ? { persistRule } : {}),
|
|
623
|
+
...(note !== undefined ? { note } : {}),
|
|
595
624
|
});
|
|
596
625
|
// 🔴 相关性门(对抗复审二轮):ack 必须是**这一次**审批的回执 —— id 与决断词都要对上。
|
|
597
626
|
// 对不上的 ack(注入面串了别人的响应 / 坏 mock / raw-fetch 包装器复用了连接)如果照样被
|
|
@@ -619,6 +648,13 @@ export async function surfaceToolApprovalFrameAndRespond(frame, respond, streamA
|
|
|
619
648
|
hostLog('debug', `liveToolApprovalWire: ${frame.approvalId} edited args were NOT forwarded (ack.updatedInputForwarded=false) — the tool runs on the ORIGINAL input`);
|
|
620
649
|
surfaceEditNotForwarded();
|
|
621
650
|
}
|
|
651
|
+
// #229:note 发了而 ack 说没落行(noteRecorded=false:纯活卡无行可落 / 店抖但裁决照常生效 /
|
|
652
|
+
// 并发同决议先落行)或位缺席(异常形:能力位为真却没回执)—— 审计面事实,decision 本身不受
|
|
653
|
+
// 影响,debug 留痕即可(不惊动用户:决断没丢,丢的只是理由的持久档)。
|
|
654
|
+
if (note !== undefined && ack !== undefined && ack.noteRecorded !== true) {
|
|
655
|
+
hostLog('debug', `liveToolApprovalWire: ${frame.approvalId} decision note was sent but not persisted ` +
|
|
656
|
+
`(ack.noteRecorded=${String(ack.noteRecorded)}) — decision stood; the audit note did not land on the ask row`);
|
|
657
|
+
}
|
|
622
658
|
return ack !== undefined ? { decision, ack } : { decision };
|
|
623
659
|
}
|
|
624
660
|
catch (e) {
|
package/dist/index.d.ts
CHANGED
|
@@ -182,6 +182,7 @@ export * from './adapter/downstream/turnUsageToModelUsage.js';
|
|
|
182
182
|
export * from './adapter/downstream/eventToSdkMessage.js';
|
|
183
183
|
export * from './adapter/downstream/terminalToSdkResult.js';
|
|
184
184
|
export * from './adapter/runStream.js';
|
|
185
|
+
export * from './adapter/activeRunSelfHeal.js';
|
|
185
186
|
export * from './request/taskRequest.js';
|
|
186
187
|
export * from './clientSlice.js';
|
|
187
188
|
export * from './host.js';
|
|
@@ -220,6 +221,13 @@ export * from './hitl/hitlHostSurface.js';
|
|
|
220
221
|
export * from './hitl/toolApprovalWire.js';
|
|
221
222
|
export * from './hitl/askGateWire.js';
|
|
222
223
|
export * from './hitl/planReviewWire.js';
|
|
224
|
+
export * from './hitl/gateIdentity.js';
|
|
225
|
+
export * from './hitl/armedGateRegistry.js';
|
|
226
|
+
export * from './hitl/parkOwnership.js';
|
|
227
|
+
export * from './hitl/parkRowBirthWait.js';
|
|
228
|
+
export * from './hitl/approvalDecisionNoteAudit.js';
|
|
229
|
+
export * from './hitl/askParkRowRouting.js';
|
|
230
|
+
export * from './hitl/resumeRunningCard.js';
|
|
223
231
|
export * from './hitl/approvalsFeed.js';
|
|
224
232
|
export * from './compensations.js';
|
|
225
233
|
export * from './request/printNotification.js';
|
|
@@ -231,3 +239,4 @@ export * from './model/catalogLoader.js';
|
|
|
231
239
|
export * from './model/providerAuth.js';
|
|
232
240
|
export * from './websearch/searchProviderPresets.js';
|
|
233
241
|
export * from './env/localeGeo.js';
|
|
242
|
+
export type { PendingCheckpoint, RuleSuggestion } from '@sema-agent/sdk';
|
package/dist/index.js
CHANGED
|
@@ -208,6 +208,14 @@ export * from './adapter/downstream/turnUsageToModelUsage.js';
|
|
|
208
208
|
export * from './adapter/downstream/eventToSdkMessage.js';
|
|
209
209
|
export * from './adapter/downstream/terminalToSdkResult.js';
|
|
210
210
|
export * from './adapter/runStream.js';
|
|
211
|
+
// ── A-028.1(#244 族A,2026-08-12):409 active-run 自愈的分诊树 + 结局文案层 ————————————
|
|
212
|
+
// 判别半场(activeRunBusySignal)在 runStream.js 早已出面;本件是它的消费侧:四路分诊
|
|
213
|
+
// (pendingGate.kind 优先 / status 表回退)+ 八种结局的可覆盖默认文案。归通用半场的理由:
|
|
214
|
+
// 三端面对同一把会话锁 —— cli 交互/headless 两车道换包导入删本地抄件(提货批);desktop
|
|
215
|
+
// session-host 已自写同族「parked run 不能 cancel」分诊,收敛到此;web 读 activeTaskId 的
|
|
216
|
+
// busy 面同源。文案默认串 = cli 产品面逐字,端经 ActiveRunSelfHealCopy 覆盖出路句。
|
|
217
|
+
// 🔴 零值级 import 纯函数叶(类型 type-only 借 runStream),不进内核/A 层闭包。
|
|
218
|
+
export * from './adapter/activeRunSelfHeal.js';
|
|
211
219
|
// ── B4 批:A 层帧分派收官 + 请求面合一 + 构造点收编(2026-07-27)────────────────────────────────
|
|
212
220
|
// 请求面:三个构造器(seamQuery.toTaskRequest / seamQueryEngine / liveClient.toLiveRequest)
|
|
213
221
|
// 的**字段集与合并语义**收成一份;车道差异做成 REQUEST_FIELD_MATRIX 数据表(gap:true = 判为漏)。
|
|
@@ -306,6 +314,32 @@ export * from './hitl/hitlHostSurface.js';
|
|
|
306
314
|
export * from './hitl/toolApprovalWire.js';
|
|
307
315
|
export * from './hitl/askGateWire.js';
|
|
308
316
|
export * from './hitl/planReviewWire.js';
|
|
317
|
+
// ── A-028.2/.3(#244 族A,2026-08-12):决断卡链的键词汇/呈现台账/归属判据三件 ————————————
|
|
318
|
+
// · gateIdentity:三条身份键字面(hitl-ask:/callKey/plan-review:,外加 hitl-frame: 同族)的唯一
|
|
319
|
+
// 铸口 —— 包内三处铸口与呈现台账的键推导同源;壳侧 armedGateRegistry/askParkReopen 的手抄字面
|
|
320
|
+
// 换 import 删本地(提货批);desktop session-host 的 plan:/durable: 前缀族收敛候后续对齐。
|
|
321
|
+
// · armedGateRegistry:per-session 呈现台账(firstSight 文案分形的唯一判据);sessionSlot 键支持
|
|
322
|
+
// 多会话宿主(desktop session-host 多引擎会话),cli 走 DEFAULT_SESSION_KEY 零参兼容层。
|
|
323
|
+
// · parkOwnership:ask park 重开腿的纯判据三件(fail-closed 归属证明/questions 结构判定/
|
|
324
|
+
// HitlSafetyError duck 判型)—— cli 换包导入删抄件;desktop refreshPendingApprovals 的自写
|
|
325
|
+
// 归属判定收敛到同一判据。approvals.list 编排与 stderr 留各端。
|
|
326
|
+
export * from './hitl/gateIdentity.js';
|
|
327
|
+
export * from './hitl/armedGateRegistry.js';
|
|
328
|
+
export * from './hitl/parkOwnership.js';
|
|
329
|
+
// ── #265(2026-08-14):C1-C5「决策卡死墙」病族的三端公共判定层上收(源形 = cli 五模块的判据半场;
|
|
330
|
+
// 呈现/编排留端)。四件都是纯判定,零宿主端口:
|
|
331
|
+
// · parkRowBirthWait:「待决行还没出生」这个第三态的有界可中断重查环 —— 把「行不在 pending 表」
|
|
332
|
+
// 从单义的「已决」拆成 row/unborn/settled 三态,`settled` 必须由正面证据得出。
|
|
333
|
+
// · approvalDecisionNoteAudit:回决备注(decisionNote/noteRecorded)三态读面 + 人话行,
|
|
334
|
+
// `unknown ⇒ 整行不渲`(缺席 ≠ false)。
|
|
335
|
+
// · askParkRowRouting:ask park 重开链的四问(队列三态分类 / 行身份 / 问答臂 vs 工具门臂 /
|
|
336
|
+
// 「行已消失」两义分臂)+ 行级单活闸工厂(一个待决项至多一张卡)。
|
|
337
|
+
// · resumeRunningCard:resume 撞上在飞 run 的三选卡(默认焦点 = 零动作那一项 / 活性证据缺席整行
|
|
338
|
+
// 不渲 / 无 UI 臂的机读三选指路与专码退出)。
|
|
339
|
+
export * from './hitl/parkRowBirthWait.js';
|
|
340
|
+
export * from './hitl/approvalDecisionNoteAudit.js';
|
|
341
|
+
export * from './hitl/askParkRowRouting.js';
|
|
342
|
+
export * from './hitl/resumeRunningCard.js';
|
|
309
343
|
// B7 ③(census G20,**行为改动**不是搬迁):pending-approvals 推送 feed(stream 优先 / 断流回落
|
|
310
344
|
// 轮询 / 定期再试)。🔴 它**不替换** D-1 的取件 —— 那三处必须继续走权威 `list()`(见文件头)。
|
|
311
345
|
export * from './hitl/approvalsFeed.js';
|
|
@@ -68,6 +68,17 @@ type RespondFn = (id: string, answer: QuestionAnswer, opts?: {
|
|
|
68
68
|
/** Register a one-shot local responder for a SYNTHETIC question frame (e.g. `plan-review:<taskId>`).
|
|
69
69
|
* Returns an unregister fn (dialog dismissed without answering ⇒ caller cleans up). */
|
|
70
70
|
export declare function registerLocalQuestionResponder(id: string, fn: RespondFn): () => void;
|
|
71
|
+
/**
|
|
72
|
+
* Unregister a local responder **by id**(A-028.4 复审二轮收紧,2026-08-12)。
|
|
73
|
+
*
|
|
74
|
+
* 为什么需要按 id 注销:`registerLocalQuestionResponder` 的注销钩只回到注册方手里,而重开腿
|
|
75
|
+
* (`planReviewWire.reopenPlanReviewCard`)要退役的是**别的注册方**(arm 臂)登记的 canonical
|
|
76
|
+
* responder —— 只发 `question_complete` 撤帧撤不掉表里的 responder,一个在途的迟到作答仍能经
|
|
77
|
+
* 它投递决断,与新卡的投递构成同一 gate 的双决断面。返回是否真删了一条(调用方留痕用)。
|
|
78
|
+
* 🔴 只删表项,不通知原注册方 —— 原注册方的自愈臂(如 arm 的陈旧武装态分支)按
|
|
79
|
+
* `hasLocalQuestionResponder` 探询真相,不依赖回调。
|
|
80
|
+
*/
|
|
81
|
+
export declare function unregisterLocalQuestionResponder(id: string): boolean;
|
|
71
82
|
/**
|
|
72
83
|
* Is a local responder for this synthetic questionId still bound?([2393] hitl-F3,2026-08-02)
|
|
73
84
|
*
|
|
@@ -20,6 +20,19 @@ export function registerLocalQuestionResponder(id, fn) {
|
|
|
20
20
|
localResponders.delete(id);
|
|
21
21
|
};
|
|
22
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Unregister a local responder **by id**(A-028.4 复审二轮收紧,2026-08-12)。
|
|
25
|
+
*
|
|
26
|
+
* 为什么需要按 id 注销:`registerLocalQuestionResponder` 的注销钩只回到注册方手里,而重开腿
|
|
27
|
+
* (`planReviewWire.reopenPlanReviewCard`)要退役的是**别的注册方**(arm 臂)登记的 canonical
|
|
28
|
+
* responder —— 只发 `question_complete` 撤帧撤不掉表里的 responder,一个在途的迟到作答仍能经
|
|
29
|
+
* 它投递决断,与新卡的投递构成同一 gate 的双决断面。返回是否真删了一条(调用方留痕用)。
|
|
30
|
+
* 🔴 只删表项,不通知原注册方 —— 原注册方的自愈臂(如 arm 的陈旧武装态分支)按
|
|
31
|
+
* `hasLocalQuestionResponder` 探询真相,不依赖回调。
|
|
32
|
+
*/
|
|
33
|
+
export function unregisterLocalQuestionResponder(id) {
|
|
34
|
+
return localResponders.delete(id);
|
|
35
|
+
}
|
|
23
36
|
/**
|
|
24
37
|
* Is a local responder for this synthetic questionId still bound?([2393] hitl-F3,2026-08-02)
|
|
25
38
|
*
|