@sema-agent/client-core 0.38.1 → 0.40.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 +152 -0
- package/README.md +1 -1
- package/dist/adapter/downstream/eventToSdkMessage.js +16 -0
- package/dist/engineErrorCodes.d.ts +33 -3
- package/dist/engineErrorCodes.js +51 -17
- package/dist/hitl/askGateWire.d.ts +1 -0
- package/dist/hitl/askGateWire.js +6 -0
- package/dist/hitl/frameRouter.js +30 -3
- package/dist/hitl/gateLedger.d.ts +68 -3
- package/dist/hitl/gateLedger.js +102 -3
- package/dist/hitl/parkResolver.js +11 -0
- package/dist/hitl/toolApprovalWire.d.ts +42 -1
- package/dist/hitl/toolApprovalWire.js +34 -0
- package/dist/printToolResultFrame.d.ts +9 -0
- package/docs/INTEGRATION-CLIENTS.md +101 -7
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -28,6 +28,158 @@
|
|
|
28
28
|
> 不许悄悄漂:豁免登记的 `releasedAt` 与 `FROZEN` 账上 0.36.0 那一行逐字相等;本段(点名版本号
|
|
29
29
|
> `0.36.0` + 关键字「勘误」)必须还在这份头注里 —— 删掉本段而不同批把门侧豁免一起处理,门当场红。
|
|
30
30
|
|
|
31
|
+
## 0.40.0(2026-08-22)
|
|
32
|
+
|
|
33
|
+
**minor:连坐 abort 机读位 `_sema_collateral_abort`(#324 / [4907] 裁定)。**
|
|
34
|
+
|
|
35
|
+
- **🆕 连坐帧机读位 `_sema_collateral_abort`(#324)**:`gateLedger.flushHeld()` 对**已知不是 gate
|
|
36
|
+
主角**的 HOLD 帧 stamp additive 超集键 `_sema_collateral_abort: true`。`eventToSdkMessage` 的
|
|
37
|
+
`case 'tool_end'` 臂同批放行这一位到内部 `tool_end_result` 臂(严格 `true` 才铸,缺席不铸键)
|
|
38
|
+
——不放行就等于本包把**自己刚打上去**的事实在自己的包边界上剥掉,即该臂头注点名的
|
|
39
|
+
[1947] `toolCallId` / [2942] `governanceForced` / #263 两键同款病形的下一例。
|
|
40
|
+
病形:同 turn 多 call 在飞 + 一个撞 gate ⇒ 引擎对整批在飞 call 铸同一串 `Operation aborted`
|
|
41
|
+
⇒ HOLD 表按超集谓词全收 ⇒ 任一 flush 出口一次倾泻,端上满屏同文红行,而其中只有一条是用户
|
|
42
|
+
刚决断的那个 call。
|
|
43
|
+
🔴 **一帧不丢的不变量不变**:修的是「出口处分不清谁是谁」,不是丢帧 —— 丢帧的后果是永久
|
|
44
|
+
假排队(dim 圆点等不到结果行),比多渲一行更坏。
|
|
45
|
+
- **🔴 判别子在 `flushHeld` 当拍求值、且只认 park 供证(#324 换锚)**:出身**不**在入表当拍
|
|
46
|
+
(hold-poison 臂)冻结 —— durable park 腿的帧序是 `tool_start → tool_end(毒化) →
|
|
47
|
+
done{suspended}`,**gate 身份晚于毒化帧到达**,那一拍的任何判词都是猜的。按工具名猜双向都错:
|
|
48
|
+
一等 `kind==='tool_approval'` gate 的主角(名字腿认不得的 toolName)被判成连坐 = **假阳打在
|
|
49
|
+
主角上**;同族兄弟(两个 `Bash` 只有一个撞 gate)两个都被判成主角 = 连坐帧拿不到位。
|
|
50
|
+
🔴 判别子真正要回答的是「**这一批** abort 帧属于哪张 gate」,而 wire 上**没有任何位**做这个
|
|
51
|
+
关联。定谳:只有 **park** 具备结构性归属(`flushHeld` 的出口就长在那张 park 自己的决断/回退
|
|
52
|
+
路径上),所以判据**只从 park 取证** —— 同步 `tool_approval` 帧腿不供证、整条不标(已知局限二);
|
|
53
|
+
**pending 队列也不供证**(`durable checkpointGate` 不带 callId,`findPendingForTask` 取的是
|
|
54
|
+
「同 taskId + 谓词命中的第一行」,那是卡面渲染的宽口不是身份 —— 同族两行排队时它会给出旁观者,
|
|
55
|
+
拿它当主角就把真主角挤成「非主角」)。判据全部**批级**、一批一套:①本批恰一张 park(硬门;
|
|
56
|
+
durable 重放同一张不算新的一张,判据 = 自上次登记以来有没有**新 call** 进扣留表,且去重分支
|
|
57
|
+
一个字节都不写;ask park 臂同样要登记 —— 它是本批的第二张 park);②主角 = 本批(扣留帧 ∪ 已
|
|
58
|
+
出批帧)里**唯一**属该 park 族的 call,前置是每条扣留帧的 `tool_start` 本连接都见过。
|
|
59
|
+
🔴 出口方向 fail-safe:**判不出来 ⇒ 整表一个都不 stamp**(诚实缺席,字节零变),绝不按到达
|
|
60
|
+
顺序编判词。批级判据退休点两处:`flushHeld` drain 完、`dropHeld` 之后**无条件**检查扣留表为空
|
|
61
|
+
(写成「摘中了才查」则零毒化帧的 park 批永不退休,判据活到下一批派错判词)。
|
|
62
|
+
兜底腿读的是 tool_start 当拍写入的**单调集**,不是 `pendingFsCalls` —— 后者在 `routeToolEnd`
|
|
63
|
+
跑臂表之前就被 `dropFsCall` 摘掉了当前 callId,拿它做判据会退化成「除最后一张毒化帧外全判
|
|
64
|
+
连坐」的位置性裁决(主角被 stamp、真连坐豁免,方向恰好反)。
|
|
65
|
+
随之删除未发布窗内的 `HoldOrigin` 类型与 `hold()` 第三参、`heldOrigin()`(干净切,零已发布
|
|
66
|
+
消费者)。
|
|
67
|
+
异源对抗复审**四轮**逮到九条残留路径(八条是「假阳打回 gate 主角」,一条是判据自失效),
|
|
68
|
+
同批修 + 每条各配常驻反证:①兜底缺准入证(F8-S10);②身份 turn 级只增不删,多 hop 冒充已知
|
|
69
|
+
(F8-S11);③凭证在零 flush 路径滞留(F8-S12/S21);④ask park 不登记(F8-S13/S19/S25/S26);
|
|
70
|
+
⑤同批两个主角被「新 gate 清空身份」抹掉先到的那个(F8-S17);⑥durable 重放同一张 park 抹掉
|
|
71
|
+
刚登记的真身份(F8-S18);⑦历史主角在后一批变成连坐 call 时反向误标新主角(F8-S20);
|
|
72
|
+
⑧旧 server 同批双 gate 双主角(F8-S22);⑨同批混入两张真 park 时挑一个当主角(F8-S23);
|
|
73
|
+
⑩**零毒化帧的 park 批永不退休**(`dropHeld` 每次都落空 ⇒ 判据活到下一批,F8-S27);
|
|
74
|
+
⑪扣留帧的 `tool_start` 落在本连接之外时,兜底把**旁观者**当主角、反手给真主角打位(F8-S28);
|
|
75
|
+
⑫毒化帧与 park **一并重放**被当成第二张 park,本该带位的兄弟帧丢位(F8-S29,幂等性);
|
|
76
|
+
⑬去重的**反向**误判 —— 一张真的新 park 同样可以零毒化帧,它顺手刷新族属就把本批判据改成
|
|
77
|
+
另一族,兜底选中旁观者、反手误标真主角(F8-S30 ⇒ 去重分支一个字节都不写)。
|
|
78
|
+
⑭被去重掉的 park **借决断成功**把自己的 callId 登记为本批主角,把真主角挤成「非主角」
|
|
79
|
+
(F8-S31 ⇒ 采信答案经 `GatePark.parkAccepted` 一路带到决断腿)。
|
|
80
|
+
⑮`findPendingForTask` 的选行(谓词命中的**第一行**,不命中时退「任意行」)被当成身份 ⇒
|
|
81
|
+
别族 / 同族的旁观 call 被登记为主角、反手给真主角打位(F8-S32/S33 ⇒ **pending 队列一概不参与
|
|
82
|
+
判别**,决断结果只用于 gate 生命周期)。
|
|
83
|
+
十五条同源:**「本 turn 存在过一张 gate 的证据」不等于「这一批帧属于那张 gate」** —— 与 v1
|
|
84
|
+
名字锚同形(拿旁证冒充身份),故按同形存量宪法一并清,并补齐四条 park 臂的登记点。
|
|
85
|
+
门:`run-hitl-gate-honesty-test.mjs` F8 组 **S1–S33**(70→126 checks),每形态钉死判词全串
|
|
86
|
+
「谁带位谁不带」而不只是「有没有键」;**零已知假阳**是本批的验收硬线。
|
|
87
|
+
变异自证十六发全抓(逐发只由目标格抓红,cp 复原后逐字节 cmp 一致):废兜底唯一性⇒F7-①;
|
|
88
|
+
翻转 fail-safe⇒F8-S2;准入证恒放行⇒F8-S10;废「恰一张 park」硬门⇒F8-S23;废重放去重⇒F8-S18;
|
|
89
|
+
去重分支写族属⇒F8-S30;废 flush 侧退休⇒F8-S24;废摘空退休⇒F8-S16;退休改「摘中才查」⇒
|
|
90
|
+
F8-S27;废出批帧并集⇒F7-①;废 start 全覆盖前置⇒F8-S28;`hold` 覆盖也置位⇒F8-S29;
|
|
91
|
+
四条 park 臂逐臂不登记⇒F8-S25 / F7-① / F8-S26 / F8-S16。
|
|
92
|
+
|
|
93
|
+
**已知局限(本版新增)**:
|
|
94
|
+
|
|
95
|
+
- **端侧呈现半场不在本包**:本包只把机读位送到 `tool_end_result` 臂;「连坐簇怎么折叠」是各端
|
|
96
|
+
的呈现设计。壳(cli)的消费件在 1.0.90 窗跟车。
|
|
97
|
+
- **@core 对表位未闭**:core 5.51 `[DEFERRED]` / `gate.batch_halted`([4826]③)到货前,本键是
|
|
98
|
+
端能拿到的唯一机读判别子;到货后若 core 给出更强官方形,端侧换锚、本 additive 键保留兼容。
|
|
99
|
+
- **同族多兄弟 ⇒ 分不出主角**:两个 `Bash` 同时在飞、其中一个撞 gate 时,wire 上没有任何位能说
|
|
100
|
+
「哪个撞的」——`lastFsOrShellGatedCallId()` 给「最后一个」、pending 队列给「第一行」,都不是身份。
|
|
101
|
+
**决断成功也不例外**。此格按诚实缺席处置(整表不 stamp,端侧逐字节退回本键出现前)。
|
|
102
|
+
🔴 出路在 server:`durable checkpointGate` 带 `toolCallId`。常驻门 `F8-S3/S8/S33` 钉成「全
|
|
103
|
+
ABSENT」,server 补位后当场翻红,逼下一棒把新身份接进判据。
|
|
104
|
+
- **同步 `tool_approval` 帧腿整条不标(刻意为之)**:帧只证明「本 turn 出现过一张 gate」,证明
|
|
105
|
+
不了「这一批 abort 帧属于它」——那张 gate 可能早已正常收口(零毒化帧 ⇒ 零扣留表 ⇒ 一次 flush
|
|
106
|
+
都不跑),证却会活到下一批派判词。四轮复审里**全部**「假阳打在主角身上」的残留路径都出自帧腿
|
|
107
|
+
取证。取舍:**宁可少标,绝不误标主角**(误标主角=把用户真正该看的那条红行折叠掉,比多渲 N 行
|
|
108
|
+
更坏)。常驻门 `F8-S4/S5/S7/S11/S14/S17/S21/S22` 钉成「全 ABSENT」。🔴 出路同样在 server:
|
|
109
|
+
abort 批带 **gate 关联 id**,把归属从推断变成读数。
|
|
110
|
+
- **记案(存量,非本批根因):`dropHeld` 也在用不可信的 `gatedCallId`** —— 决断成功那一下按
|
|
111
|
+
pending 行的 callId 摘扣留帧,同族多行排队时可能摘掉**另一条** call 的帧,那一帧就再也不吐
|
|
112
|
+
(「一帧不丢」在这一格上不成立)。这条**早于本批**(与 4c42c8a 逐字相同),根因是「decide 结果
|
|
113
|
+
没有可核验的 park 身份」,与本批修的判别面是两件事;改它要动 #110 / REF-CC-034 的承重路径,
|
|
114
|
+
单独立案。server 补 `checkpointGate.toolCallId` 后两处一并收口。
|
|
115
|
+
- **缺席不是「这是主角」**:本键缺席同时覆盖「是主角」与「判别不出来」两种情况,端不得据此反推
|
|
116
|
+
主角身份(要断言主角,端自己按 `toolCallId` 与手上的审批卡对账)。已写进 §3z 缺席语义段。
|
|
117
|
+
|
|
118
|
+
## 0.39.0(2026-08-21)
|
|
119
|
+
|
|
120
|
+
**minor:tool_approval 帧窗三键过境 + 三新错误码消费件(0.38.0 已知局限「delegation.* 无机器可读载体」自本版解除)。**
|
|
121
|
+
|
|
122
|
+
- **🆕 tool_approval 帧窗三键过境([4851] cli 请托;[4845] 假死案的包层半场)**:`ToolApprovalFrame`
|
|
123
|
+
声明 + 键镜像表 + `ApprovalCardRequest` 三处补 `expiresInMs` / `expiresAtMs` / `serverNowMs`
|
|
124
|
+
(server ≥7.34 在 durable `tool_approval` 帧上 stamp;0.38.1 及更早的白名单投影把三键**丢在包
|
|
125
|
+
边界外** —— 正是「审批卡 TTL 到点转 park 后屏幕零反应像活的」的直接成因之一)。铸卡点按
|
|
126
|
+
**有限数才 stamp** 收(坏形降缺席,三键独立判不互相湮灭);对账门 `run-approval-frame-keys`
|
|
127
|
+
以 AHEAD_OF_ANCHOR 登记三条领先(sdk 7.2.0 锚尚无三键,SDK 追平当天登记自红逼删)。
|
|
128
|
+
- **🆕 三新错误码消费件(0.38.0 件④ 的下半场,载体已核实到货)**:core 5.50.0 兑现上游诉求 ——
|
|
129
|
+
`capRefusal` 铸 `{ error: code, code }` **孪生拼法**(`dist/agents/subagent.js`,node 直读实证),
|
|
130
|
+
抬升腿 `toolEndBodyFrom` 读 `details.code` 后 stamp 帧顶层 ⇒ `delegation.concurrency_cap` /
|
|
131
|
+
`delegation.session_cap` 自 core ≥5.50.0 起**真出现在 `tool_end.errorCode`**。本版接上判定半场:
|
|
132
|
+
① `delegationCapDispositionOf`:两码处置不对称的机器可读形(`wait-for-slot` /
|
|
133
|
+
`reuse-existing-or-await-reap`),未知 `delegation.*` 码 ⇒ `undefined`(开集纪律:不认得就不给
|
|
134
|
+
处置,不替引擎指路);文案归端。🔴 **勘误(异源对抗复审命中)**:0.38.0 段曾把累计帽写成
|
|
135
|
+
「等也没用,这条会话这辈子的配额用完了」——**错**。core 实现在计数前先把不在 stored/active 的
|
|
136
|
+
handle 从 ledger 剪掉,计数是 **retained-window 帐**,行被 retention 回收后配额**会回来**,core
|
|
137
|
+
文案的推荐出路即 "Continue an existing agent (SendMessage)"。以本版语义为准(0.38.0 段已冻结
|
|
138
|
+
不回改)。
|
|
139
|
+
② `MCP_SERVER_REVOKED`(`mcp.server_revoked`,core 5.50.0 `dist/core/mcp.js` 三铸点同码):
|
|
140
|
+
操作员 mid-session 吊销 MCP server 后的**工具面本地闸**(请求没发出去;不是故障;同 server
|
|
141
|
+
重试无意义直到重新批准)。🔴 **哪个 server 被吊销今天 wire 上拿不到**(异源复审命中):core
|
|
142
|
+
detail 的 `server` 键是进程内位,抬升腿只 lift `code`、该 detail 无 `type` 进不了 `structured`
|
|
143
|
+
⇒ 端只有码没有名;归因渲染候 core 补 typed detail / tool_end 字段(发布帖点名,表态制)。
|
|
144
|
+
③ print 车道读形 `ToolEndResultArmLike` 补 `errorCode?: unknown`(与 `settledBy`/`approver`
|
|
145
|
+
同款「臂带、卡不带」姿势;typeshape unknown 出境棘轮 252→253 同批登记)。
|
|
146
|
+
④ **载体门**:`run-engine-vocab-floor-test` 新增 G3 腿(+7 checks,门 73→80)锚 core dist 铸点
|
|
147
|
+
与抬升腿口径,devDep core ^5.43.0→^5.50.0(实装 5.52.0),CORE_FLOOR 5.43→5.50 —— 5.45.0 实装物
|
|
148
|
+
上 G3-a 实测红(红先绿后留证),孪生拼法哪天被 core 重构删掉本门当场红。
|
|
149
|
+
⑤ `engineErrorCodes.ts` 0.38.0 那条「载体如实登记」注按现势改写(旧注描述的是 5.50 修孪生前
|
|
150
|
+
的 core;旧引擎 5.48/5.49 上两码仍只在模型面文案里,消费点拿不到码就什么都别渲)。
|
|
151
|
+
- **跟修**:pure 套 B7 两处 `TOOL_APPROVAL_FRAME_KEYS_MIRROR` 计数钉 18→21(三键过境批漏跑 pure
|
|
152
|
+
套的存量红,本批认领);public-export 基线 764→766。
|
|
153
|
+
|
|
154
|
+
- **🔴 收敛式扫码+异源复审收编(两 P1 三 P2 修复,发包前置)**:
|
|
155
|
+
① **重放腿假倒计时(P1)**:durable 账本 tail 会把旧 `tool_approval` 行连冻结三键逐字重放,
|
|
156
|
+
此前铸卡点无条件 stamp ⇒ 早已过期的 ask 在屏上拿到精确但完全错误的倒计时(比 [4845]「卡挂着
|
|
157
|
+
像活的」更坏)。修 = `ToolApprovalFrameLaneOpts` 新增 `windowIsCurrent` 席位,三键**只在
|
|
158
|
+
`=== true`(live 流)时过境**;缺席 fail-closed 不 stamp(老宿主行为 = 0.38.1,零回归),
|
|
159
|
+
各端 live 腿随自家提货批接线 `true`。
|
|
160
|
+
② **stamp 零门看守(P1)**:变异实证删掉三行 stamp 全门照绿。修 = pure 套新增端到端卡口断言
|
|
161
|
+
七条(live 逐值过境 / 重放三形缺席 / 负数坏形闸 / 0 合法)。
|
|
162
|
+
③ **负数放行(P2)**:铸卡注承诺「负数=坏形降缺席」而实现是裸 `Number.isFinite`。修 =
|
|
163
|
+
`isNonNegativeFinite`(0 合法 = 窗恰好到点,SDK 契约 `max(0,…)` 可产 0)。
|
|
164
|
+
④ **缺本地收帧锚(P2)**:卡口串行阻塞下排队靠后的卡按「呈现那一刻」起算 = 窗被整段还回去。
|
|
165
|
+
修 = live 腿 stamp 任一窗键时同拍盖 `ApprovalCardRequest.receivedAtMs`(壳读器明文优先它)。
|
|
166
|
+
⑤ **G3 载体门判据收紧(P2)**:铸点判据改「每个含 `mcp.server_revoked` 的 details 对象都带
|
|
167
|
+
`code` 键」全称断言(顺序无关 —— 装饰性 key 重排不再误红,单铸点退化单键不再被计数下限漏过);
|
|
168
|
+
capRefusal 体内判据同步放宽到 shorthand 等价形;判别器全员合成样本正控。
|
|
169
|
+
|
|
170
|
+
### 已知局限(本版新增)
|
|
171
|
+
|
|
172
|
+
- **三新码的渲染半场在端**:本包只出判定(处置轴/常量),cli 壳的指路文案腿(Task 卡拒因 +
|
|
173
|
+
mcp 吊销卡)随壳 0.39.0 提货批做;web/desktop 同理。旧引擎(core <5.50.0)上 `tool_end.errorCode`
|
|
174
|
+
不带这三码 —— 缺席 ≠ 没拒过,端别按缺席反推。
|
|
175
|
+
- **窗三键的 live 腿要各端接线才点亮**:`windowIsCurrent` 缺席 = 三键不 stamp(fail-closed)——
|
|
176
|
+
cli 壳 live 腿随 1.0.88 提货补 `true`;web/desktop 接线前行为 = 0.38.1(卡无倒计时,无假窗)。
|
|
177
|
+
- **seatContract 的 `ToolPermissionRequest` 未跟窗三键**:desktop/web 座位 IPC 面上窗仍停在包内
|
|
178
|
+
这一格 —— 座位面倒计时随两端提货批与 IPC 契约(B18 单源)同窗补,不在本批贸然扩 IPC 键。
|
|
179
|
+
- **park(durable)腿仍无窗投影**:富行 `PendingCheckpoint.deadline` 是重放面读数,与
|
|
180
|
+
`windowIsCurrent` 同一条闸;投影候 7.40 park 转态帧带当下余量([4846] server 已认领),
|
|
181
|
+
未投影登记(`run-durable-card-display-keys-test.mjs`)理由已按本批换代。
|
|
182
|
+
|
|
31
183
|
## 0.38.1(2026-08-21)
|
|
32
184
|
|
|
33
185
|
**patch:纯出包卫生版,零 API/行为变化。**
|
package/README.md
CHANGED
|
@@ -35,7 +35,7 @@ Renamed from **`@sema-agent/wire-cc-adapter`** (0.1.x, deprecated — see *Migra
|
|
|
35
35
|
|
|
36
36
|
## Scope
|
|
37
37
|
|
|
38
|
-
**Version:** 0.
|
|
38
|
+
**Version:** 0.40.0
|
|
39
39
|
|
|
40
40
|
- **Today** — the adapter seam, the whole `adapt()` pipeline (all 14 A-layer arms plus the
|
|
41
41
|
B/D/E tool-card layers), the notification/caps/model families, the adapter kernel (stream driver
|
|
@@ -245,6 +245,20 @@ export function eventToSdkMessage(ev, ctx) {
|
|
|
245
245
|
// (core 不鉴别、不比对、不回读)—— 只渲染,绝不回喂模型/工具入参,更不许当鉴权判据。
|
|
246
246
|
const toolEndSettledBy = ev.settledBy;
|
|
247
247
|
const toolEndApprover = ev.approver;
|
|
248
|
+
// ── #324 半场(0.40.0):连坐 abort 机读位 `_sema_collateral_abort`([4907] 裁定)──
|
|
249
|
+
// 出处**不是引擎**,是本包自己的 HITL 桥:`gateLedger.flushHeld` 对「出身 = collateral」的
|
|
250
|
+
// 扣留帧 stamp(见 `SEMA_COLLATERAL_ABORT_KEY` 头注)。桥在本臂**上游**(宿主先用
|
|
251
|
+
// `bridgeAskUserQuestionGates` 包住事件流,再喂 `eventToSdkMessage`),所以这一位到本臂时
|
|
252
|
+
// 已经在帧上了。
|
|
253
|
+
// 🔴 不转发 = 本臂白名单把它整段剥掉 ⇒ 宿主无论怎么写都读不到一条**本包自己刚打上去**的事实,
|
|
254
|
+
// 正是上面那段头注点名的 [1947] `toolCallId` / [2942] `governanceForced` / #263 两键
|
|
255
|
+
// 同款病形的下一例。缺席不铸键(严格 `true` 才铸,别的值一律当没有 —— 机读位是二值的,
|
|
256
|
+
// 「在场但不是 true」没有语义,折成在场会让消费端把一个坏形当成肯定)。
|
|
257
|
+
// 🔴 **只上内部臂,不进转录卡**:本臂是壳内部侧信道(见文件头注),转录 `tool_result` block
|
|
258
|
+
// 会随 `/compact` 直发 provider —— 往 block 上加自铸键正是 0.5.0 `label` 那个真缺口的形状
|
|
259
|
+
// (provider 400)。要让这一位进呈现面,归宿主在臂上读(壳 upstreamBridge 的 tee 就是
|
|
260
|
+
// `errorCode` 指路行同款既有位),不是往卡体里塞。
|
|
261
|
+
const collateralAbort = ev._sema_collateral_abort;
|
|
248
262
|
return projected(stamp(ctx, armBody({
|
|
249
263
|
type: 'tool_end_result',
|
|
250
264
|
toolCallId: ev.toolCallId,
|
|
@@ -267,6 +281,8 @@ export function eventToSdkMessage(ev, ctx) {
|
|
|
267
281
|
...(typeof toolEndApprover === 'string' && toolEndApprover.length > 0
|
|
268
282
|
? { approver: toolEndApprover }
|
|
269
283
|
: {}),
|
|
284
|
+
// #324:连坐 abort 机读位(严格 true 才上臂;见上方头注)。
|
|
285
|
+
...(collateralAbort === true ? { _sema_collateral_abort: true } : {}),
|
|
270
286
|
...(ev.eventId !== undefined ? { eventId: ev.eventId } : {}),
|
|
271
287
|
...(ev.parentToolCallId !== undefined
|
|
272
288
|
? { parentToolCallId: ev.parentToolCallId }
|
|
@@ -76,14 +76,44 @@ export declare const CONFIG_REFUSAL_CODES: ReadonlySet<string>;
|
|
|
76
76
|
/** 并发帽:这棵树此刻活着的委派席位已达 `delegationEntryCaps.maxConcurrent`(CC 对齐缺省 20)。
|
|
77
77
|
* 🔴 处置 = **可等**(兄弟结束即有位),别渲成「配置要改」。 */
|
|
78
78
|
export declare const DELEGATION_CONCURRENCY_CAP = "delegation.concurrency_cap";
|
|
79
|
-
/**
|
|
80
|
-
*
|
|
79
|
+
/** 累计帽:这棵树在 **retained window** 内创建的委派席位已达 `maxCumulativePerSession`
|
|
80
|
+
* (CC 对齐缺省 200)。🔴 处置 = **复用既有 agent(SendMessage)或候 retention 回收**(行被
|
|
81
|
+
* reap 后配额恢复 —— core 计数前先剪 ledger,见族注),别渲成「换会话」或「改配置」。 */
|
|
81
82
|
export declare const DELEGATION_SESSION_CAP = "delegation.session_cap";
|
|
82
83
|
/** 委派席位到限码识别表(**开集**:core 可能再加第三根轴)。两员处置不对称,消费点禁合并分支。 */
|
|
83
84
|
export declare const DELEGATION_CAP_CODES: ReadonlySet<string>;
|
|
84
85
|
/** `delegation.` 前缀谓词 —— **开集**判别(与 {@link isConfigRefusalCode} 同款)。缺席/空串 ⇒ false。
|
|
85
|
-
* 🔴
|
|
86
|
+
* 🔴 它只回答「这是不是一条委派席位拒绝」;**该等新槽还是该复用既有 agent**必须按成员分
|
|
87
|
+
* ({@link delegationCapDispositionOf}),见两码各自的注释。 */
|
|
86
88
|
export declare function isDelegationCapCode(code: string | undefined): boolean;
|
|
89
|
+
/**
|
|
90
|
+
* 委派席位到限的**处置轴**(0.39.0 消费件:两员处置不对称的机器可读形)。单源在本包 ——
|
|
91
|
+
* 「哪个码该等、哪个码等也没用」是判定不是文案,端各自再抄一份就回到本文件要根除的散抄病。
|
|
92
|
+
*/
|
|
93
|
+
export type DelegationCapDisposition =
|
|
94
|
+
/** 可等:活着的兄弟结束就有位,同一条命令过一会儿照样成(别渲成「配置要改」)。 */
|
|
95
|
+
'wait-for-slot'
|
|
96
|
+
/** 复用而不是新开:retained-window 计数满了 —— 用 SendMessage 续既有 agent(core 文案的
|
|
97
|
+
* 推荐出路),或候 retention 回收行后配额恢复(别渲成「换会话」/「永久耗尽」)。 */
|
|
98
|
+
| 'reuse-existing-or-await-reap';
|
|
99
|
+
/** 两成员各归各格;未知 `delegation.*` 码(core 的第三根轴)⇒ `undefined` —— 开集纪律:不认得
|
|
100
|
+
* 就不给处置,消费点必须留「只报码不指路」的 default 臂,绝不塌进任何一格替引擎指路。 */
|
|
101
|
+
export declare function delegationCapDispositionOf(code: string | undefined): DelegationCapDisposition | undefined;
|
|
102
|
+
/**
|
|
103
|
+
* 已吊销 MCP server 上的调用被拒。core `dist/core/mcp.js` **三个铸点同码**(远端工具调用 /
|
|
104
|
+
* 资源读取 / 目录列举)。载体与 `delegation.*` 两码同批:`{ error, code }` 双键同值 ⇒
|
|
105
|
+
* `tool_end.errorCode`(core ≥5.50.0;载体门 = engine-vocab G3 腿)。
|
|
106
|
+
* 🔴 **哪个 server 被吊销,今天 wire 上拿不到**(异源对抗复审命中,如实登记):core 的
|
|
107
|
+
* detail 确有 `server` 键,但它是**进程内** result 体 —— 抬升腿只 lift `code`,且该 detail 无
|
|
108
|
+
* `type` 进不了 `structured` ⇒ 端只有码没有名。**别按 output 文案抠 server 名当机器判据**
|
|
109
|
+
* (文案是模型面散文,不是契约);归因渲染候上游补 typed detail / tool_end 字段(诉求已
|
|
110
|
+
* 随 0.39.0 发布帖点名 core,表态制)。
|
|
111
|
+
* 🔴 语义三条,一条都别渲错:
|
|
112
|
+
* · **请求没发出去**(core 文案原话 "The request was NOT sent")—— 是本地闸,不是远端失败;
|
|
113
|
+
* · 这不是故障也不是配置坏了,是**操作员的治理动作** —— 别渲成「服务器错误,稍后重试」;
|
|
114
|
+
* · 同 server 重试**无意义**,直到它被重新批准;工具表在下一 turn 更新(core 文案原话)。
|
|
115
|
+
*/
|
|
116
|
+
export declare const MCP_SERVER_REVOKED = "mcp.server_revoked";
|
|
87
117
|
/** `config.` 前缀谓词 —— **开集**判别:5.10.0 之后每一波「不许静默折叠」都会往这一族加词,
|
|
88
118
|
* 按前缀判的消费点不必跟车,按成员判的必须跟车。缺席/空串 ⇒ false。 */
|
|
89
119
|
export declare function isConfigRefusalCode(code: string | undefined): boolean;
|
package/dist/engineErrorCodes.js
CHANGED
|
@@ -89,27 +89,35 @@ export const CONFIG_REFUSAL_CODES = new Set([
|
|
|
89
89
|
]);
|
|
90
90
|
// ── 委派席位到限族(core 5.48.0 design/323,[4743] @cli 点名的「两新 coded 拒绝」)──────────────
|
|
91
91
|
//
|
|
92
|
-
//
|
|
93
|
-
// `config.delegation_entry_caps`)
|
|
92
|
+
// 语义:一次**新开委派**(Task 铸新席位)因为**席位帽**被拒 —— 不是配置坏了(那是上面的
|
|
93
|
+
// `config.delegation_entry_caps`),也不是失败了,而是「现在不行」。SendMessage **复活**走
|
|
94
|
+
// revive 短路:core 只对它查并发帽、**跳过**累计帽(dist/agents/subagent.js:累计检查包在
|
|
95
|
+
// `reviveRow === undefined` 里)—— 这正是累计帽处置指向「复用」的机器面依据。两码**处置不同,
|
|
96
|
+
// 禁合并**:
|
|
94
97
|
// · 并发帽 ⇒ **等**:活着的兄弟结束就有位,同一条命令过一会儿照样成;
|
|
95
|
-
// ·
|
|
96
|
-
//
|
|
98
|
+
// · 累计帽 ⇒ **复用而不是新开**:计数是 **retained-window 帐**(core 计数前先把不在
|
|
99
|
+
// stored/active 里的 handle 从 ledger 剪掉 —— 行被 retention 回收后配额**会回来**),core
|
|
100
|
+
// 文案原话即 "in its retained window … Continue an existing agent (SendMessage) instead of
|
|
101
|
+
// launching new ones"。渲成「这条会话这辈子的配额用完了」是**错的**(0.38.0 段曾这么写,
|
|
102
|
+
// 0.39.0 勘误;异源对抗复审命中):会把一个「换 SendMessage 姿势就能继续」的用户赶去换会话。
|
|
103
|
+
// 把两者渲成同一句「委派失败」会让第一种情形的用户去改配置,第二种情形的用户去白等新槽。
|
|
97
104
|
//
|
|
98
|
-
// 🔴
|
|
99
|
-
// Task 工具结果体的 `details.error
|
|
100
|
-
//
|
|
101
|
-
//
|
|
102
|
-
//
|
|
103
|
-
//
|
|
104
|
-
//
|
|
105
|
-
//
|
|
106
|
-
//
|
|
107
|
-
//
|
|
105
|
+
// 🔴 **载体现势(2026-08-21 二次亲验,core 5.50.0 dist node 直读)**:0.38.0 曾如实登记「这两码
|
|
106
|
+
// 只铸进 Task 工具结果体的 `details.error`,而 core 的 `errorCode` 抬升腿只读 `details.code` →
|
|
107
|
+
// `details.errorKind` 两个拼法 ⇒ wire 上拿不到」,故先立词、消费分支候载体(上游诉求随
|
|
108
|
+
// 0.38.0 发布登记)。core 5.50.0 已兑现:`capRefusal` 铸 `{ error: code, code }` **孪生拼法**
|
|
109
|
+
// (`dist/agents/subagent.js`),抬升腿(`dist/core/runner/runtask.js` `toolEndBodyFrom`)读
|
|
110
|
+
// `details.code` 后 stamp 帧顶层 ⇒ **两码自 core ≥5.50.0 起真出现在 `tool_end.errorCode`**。
|
|
111
|
+
// 消费分支 0.39.0 同批接上:**判定归本包**({@link delegationCapDispositionOf}),文案归端。
|
|
112
|
+
// 载体门 = `run-engine-vocab-floor-test.mjs` G3 腿(锚 dist 铸点与抬升腿口径,孪生消失当场红,
|
|
113
|
+
// 不许安静绿回去)。旧引擎(5.48/5.49)上两码仍只在模型面文案里 —— 消费点拿不到码就什么都
|
|
114
|
+
// 别渲,**绝不按文案反解**([cross-repo-fix-at-source-constitution] 依旧适用)。
|
|
108
115
|
/** 并发帽:这棵树此刻活着的委派席位已达 `delegationEntryCaps.maxConcurrent`(CC 对齐缺省 20)。
|
|
109
116
|
* 🔴 处置 = **可等**(兄弟结束即有位),别渲成「配置要改」。 */
|
|
110
117
|
export const DELEGATION_CONCURRENCY_CAP = 'delegation.concurrency_cap';
|
|
111
|
-
/**
|
|
112
|
-
*
|
|
118
|
+
/** 累计帽:这棵树在 **retained window** 内创建的委派席位已达 `maxCumulativePerSession`
|
|
119
|
+
* (CC 对齐缺省 200)。🔴 处置 = **复用既有 agent(SendMessage)或候 retention 回收**(行被
|
|
120
|
+
* reap 后配额恢复 —— core 计数前先剪 ledger,见族注),别渲成「换会话」或「改配置」。 */
|
|
113
121
|
export const DELEGATION_SESSION_CAP = 'delegation.session_cap';
|
|
114
122
|
/** 委派席位到限码识别表(**开集**:core 可能再加第三根轴)。两员处置不对称,消费点禁合并分支。 */
|
|
115
123
|
export const DELEGATION_CAP_CODES = new Set([
|
|
@@ -117,10 +125,36 @@ export const DELEGATION_CAP_CODES = new Set([
|
|
|
117
125
|
DELEGATION_SESSION_CAP,
|
|
118
126
|
]);
|
|
119
127
|
/** `delegation.` 前缀谓词 —— **开集**判别(与 {@link isConfigRefusalCode} 同款)。缺席/空串 ⇒ false。
|
|
120
|
-
* 🔴
|
|
128
|
+
* 🔴 它只回答「这是不是一条委派席位拒绝」;**该等新槽还是该复用既有 agent**必须按成员分
|
|
129
|
+
* ({@link delegationCapDispositionOf}),见两码各自的注释。 */
|
|
121
130
|
export function isDelegationCapCode(code) {
|
|
122
131
|
return typeof code === 'string' && code.startsWith('delegation.');
|
|
123
132
|
}
|
|
133
|
+
/** 两成员各归各格;未知 `delegation.*` 码(core 的第三根轴)⇒ `undefined` —— 开集纪律:不认得
|
|
134
|
+
* 就不给处置,消费点必须留「只报码不指路」的 default 臂,绝不塌进任何一格替引擎指路。 */
|
|
135
|
+
export function delegationCapDispositionOf(code) {
|
|
136
|
+
if (code === DELEGATION_CONCURRENCY_CAP)
|
|
137
|
+
return 'wait-for-slot';
|
|
138
|
+
if (code === DELEGATION_SESSION_CAP)
|
|
139
|
+
return 'reuse-existing-or-await-reap';
|
|
140
|
+
return undefined;
|
|
141
|
+
}
|
|
142
|
+
// ── MCP 吊销族(core 5.50.0;操作员 mid-session 吊销 server 后的工具面拒绝)────────────────────
|
|
143
|
+
/**
|
|
144
|
+
* 已吊销 MCP server 上的调用被拒。core `dist/core/mcp.js` **三个铸点同码**(远端工具调用 /
|
|
145
|
+
* 资源读取 / 目录列举)。载体与 `delegation.*` 两码同批:`{ error, code }` 双键同值 ⇒
|
|
146
|
+
* `tool_end.errorCode`(core ≥5.50.0;载体门 = engine-vocab G3 腿)。
|
|
147
|
+
* 🔴 **哪个 server 被吊销,今天 wire 上拿不到**(异源对抗复审命中,如实登记):core 的
|
|
148
|
+
* detail 确有 `server` 键,但它是**进程内** result 体 —— 抬升腿只 lift `code`,且该 detail 无
|
|
149
|
+
* `type` 进不了 `structured` ⇒ 端只有码没有名。**别按 output 文案抠 server 名当机器判据**
|
|
150
|
+
* (文案是模型面散文,不是契约);归因渲染候上游补 typed detail / tool_end 字段(诉求已
|
|
151
|
+
* 随 0.39.0 发布帖点名 core,表态制)。
|
|
152
|
+
* 🔴 语义三条,一条都别渲错:
|
|
153
|
+
* · **请求没发出去**(core 文案原话 "The request was NOT sent")—— 是本地闸,不是远端失败;
|
|
154
|
+
* · 这不是故障也不是配置坏了,是**操作员的治理动作** —— 别渲成「服务器错误,稍后重试」;
|
|
155
|
+
* · 同 server 重试**无意义**,直到它被重新批准;工具表在下一 turn 更新(core 文案原话)。
|
|
156
|
+
*/
|
|
157
|
+
export const MCP_SERVER_REVOKED = 'mcp.server_revoked';
|
|
124
158
|
/** `config.` 前缀谓词 —— **开集**判别:5.10.0 之后每一波「不许静默折叠」都会往这一族加词,
|
|
125
159
|
* 按前缀判的消费点不必跟车,按成员判的必须跟车。缺席/空串 ⇒ false。 */
|
|
126
160
|
export function isConfigRefusalCode(code) {
|
|
@@ -73,6 +73,7 @@ import { type AskGateWireDeps } from './frameRouter.js';
|
|
|
73
73
|
export { HITL_REJECT_MESSAGE, ENGINE_ABORT_TOOL_RESULT } from './frameRouter.js';
|
|
74
74
|
export type { AskGateWireDeps } from './frameRouter.js';
|
|
75
75
|
export type { AskAnsweredOutput } from './gateLedger.js';
|
|
76
|
+
export { SEMA_COLLATERAL_ABORT_KEY } from './gateLedger.js';
|
|
76
77
|
export { toAnsweredOutput, isAlreadyResolvedGateReason, GATE_FAILURE_CODES } from './parkResolver.js';
|
|
77
78
|
export type { GateOutcome, GateFailureCode } from './parkResolver.js';
|
|
78
79
|
/**
|
package/dist/hitl/askGateWire.js
CHANGED
|
@@ -19,6 +19,12 @@ import { resolvePark } from './parkResolver.js';
|
|
|
19
19
|
// `toAnsweredOutput` / 下方 `bridgeAskUserQuestionGates`)、类型四个。定义搬去了实现所在的
|
|
20
20
|
// 那一刀,本文件是它们对外的**唯一门牌**——下游 import 路径不变,public-export 基线不变。
|
|
21
21
|
export { HITL_REJECT_MESSAGE, ENGINE_ABORT_TOOL_RESULT } from './frameRouter.js';
|
|
22
|
+
// #324 / [4907]:连坐 abort 机读位的**单一真源**导出([C93] `toolEndOutputText` 同款理由 ——
|
|
23
|
+
// 三端各自手抄键名 = 漂移温床)。壳/web/desktop 认这个常量,不认文案。
|
|
24
|
+
export { SEMA_COLLATERAL_ABORT_KEY } from './gateLedger.js';
|
|
25
|
+
// 🔴 `HoldOrigin` 随 #324 换锚删除(2026-08-22):出身不再在入表当拍冻结成两值枚举,改在
|
|
26
|
+
// `flushHeld` 当拍按已登记的 gate 主角身份求值 —— 那个枚举没有对外语义了。干净切:它只在
|
|
27
|
+
// 未发布的 0.40.0 窗里存在过,零已发布消费者([clean-cut-no-legacy-compat])。
|
|
22
28
|
export { toAnsweredOutput, isAlreadyResolvedGateReason, GATE_FAILURE_CODES } from './parkResolver.js';
|
|
23
29
|
/**
|
|
24
30
|
* 包一层 AgentEvent 流:把 AskUserQuestion 的 suspended park 变成「对话框 → decide → 续流」闭环。
|
package/dist/hitl/frameRouter.js
CHANGED
|
@@ -76,6 +76,12 @@ function isGatedToolName(name) {
|
|
|
76
76
|
return false;
|
|
77
77
|
return toolNameIsFsWrite(name) || toolNameIsShellExec(name);
|
|
78
78
|
}
|
|
79
|
+
/** 这个 gate 的**主角属 fs 写 / shell 执行族**吗(`gateLedger.noteParkGate` 的准入判据)。
|
|
80
|
+
* 🔴 主语是 **gate 本体**的 toolName(park 的 `checkpointGate`/`gate`),不是某张 tool_end
|
|
81
|
+
* 帧的 —— 拿「本 turn 有哪些 gate-capable 工具」当准入证正是 v1 名字锚那条病的同形残留。 */
|
|
82
|
+
function isFsOrShellToolName(name) {
|
|
83
|
+
return typeof name === 'string' && (toolNameIsFsWrite(name) || toolNameIsShellExec(name));
|
|
84
|
+
}
|
|
79
85
|
/**
|
|
80
86
|
* 「这一帧 tool_end 归 gate 管」的判据 —— 上面那条**名字腿**加一条 kind 腿的替身([2393] hitl-F1,
|
|
81
87
|
* 2026-08-02)。
|
|
@@ -226,8 +232,12 @@ const TOOL_END_ARMS = [
|
|
|
226
232
|
// 6.0.0 wire:output 可为 content-block 数组形(见 toolEndOutputText 头注)—— 归一后仍做精确等值。
|
|
227
233
|
if (toolEndOutputText(ev.output) !== ENGINE_ABORT_TOOL_RESULT)
|
|
228
234
|
return undefined;
|
|
229
|
-
|
|
230
|
-
|
|
235
|
+
// #324 换锚(2026-08-22):这一拍**不判出身**。durable park 腿的帧序是
|
|
236
|
+
// `tool_start → tool_end(毒化) → done{suspended}` —— gate 身份晚于本帧到达,此刻任何判词
|
|
237
|
+
// 都是猜的(名字腿猜法被双向证伪:一等 kind gate 的主角判成连坐、同族兄弟两个都判成主角)。
|
|
238
|
+
// 出身改在 `flushHeld` 当拍按**已登记的主角身份**求值,判据供给见 `gateLedger.noteGateSubject`。
|
|
239
|
+
led.hold(callId, ev);
|
|
240
|
+
return { kind: 'skip' }; // park 毒化帧,先 HOLD(gate 定性前不渲 Error 卡)
|
|
231
241
|
},
|
|
232
242
|
},
|
|
233
243
|
{
|
|
@@ -266,6 +276,12 @@ async function routeToolApprovalFrame(ev, ctx) {
|
|
|
266
276
|
const { led, deps } = ctx;
|
|
267
277
|
if (ev.type === 'tool_approval_complete')
|
|
268
278
|
return { kind: 'skip' }; // 收口帧:卡已由决断路径撤下,吞掉
|
|
279
|
+
// 🔴 #324:本臂**刻意不给连坐判别子供证**(异源对抗复审四轮的收口,2026-08-22)。
|
|
280
|
+
// 帧只证明「本 turn 出现过一张 gate」,证明不了「**这一批** abort 帧属于它」—— 那张 gate
|
|
281
|
+
// 可能早已正常收口(零毒化帧 ⇒ 零扣留表 ⇒ 一次 flush 都不跑),证却会活到下一批派错判词。
|
|
282
|
+
// 三条实测假阳(旧 server 双主角 / 零 HOLD 审批证跨批 / 历史身份跨批)都出自帧腿取证。
|
|
283
|
+
// 判别子只认 park(归属可结构性证明,见 `gateLedger.noteParkGate` 头注);同步帧腿一律
|
|
284
|
+
// 不标 —— 诚实缺席,登记在 §3z 已知局限。
|
|
269
285
|
if (!deps.respondToolApproval) {
|
|
270
286
|
hostLog('debug', `liveHitlAskWire: tool_approval frame ${ev.approvalId} but no respond wire — engine self-settles (TTL deny)`);
|
|
271
287
|
return { kind: 'skip' };
|
|
@@ -345,11 +361,18 @@ function routeToolEnd(ev, callId, led) {
|
|
|
345
361
|
function routeSuspended(ev, ctx) {
|
|
346
362
|
// durable leg 的 park arm(续流中模型再次提问/再次撞写权限)。gate 只带 kind/toolName,
|
|
347
363
|
// payload 走 approvals。
|
|
348
|
-
|
|
364
|
+
// 🔴 两条 park 臂都要登记(判别子的归属证据只认 park)—— ask park 自己用不到兜底腿,
|
|
365
|
+
// 但它必须把**上一张** gate 的准入证清掉,否则旧证会让兜底把一个 Bash 连坐帧反认成主角、
|
|
366
|
+
// 再把真正的 ask 主角 stamp 掉(对抗复审实测 `ask-main=STAMP`)。
|
|
367
|
+
if (ev.gate && isAskToolLoose(ev.gate.toolName) && ctx.taskId.current) {
|
|
368
|
+
ctx.led.noteParkGate({ fsOrShellFamily: false });
|
|
349
369
|
return { kind: 'park', gate: 'ask' };
|
|
370
|
+
}
|
|
350
371
|
if (ev.gate &&
|
|
351
372
|
isToolApprovalGate(ev.gate) &&
|
|
352
373
|
ctx.taskId.current) {
|
|
374
|
+
// 准入证:park 的 gate 本体属 fs/shell 族(kind-only gate 的 toolName 在族外 ⇒ 不发证)。
|
|
375
|
+
ctx.led.noteParkGate({ fsOrShellFamily: isFsOrShellToolName(ev.gate.toolName) });
|
|
353
376
|
return { kind: 'park', gate: 'fs' };
|
|
354
377
|
}
|
|
355
378
|
// 其余 gate:透传。⚠️ ADAPTER-F8 注纠(2026-08-02):原文写「eventToSdkMessage 出 null」——
|
|
@@ -359,12 +382,16 @@ function routeSuspended(ev, ctx) {
|
|
|
359
382
|
}
|
|
360
383
|
function routeDone(ev, ctx) {
|
|
361
384
|
const { led } = ctx;
|
|
385
|
+
// 两条 park 臂都登记(理由同 routeSuspended)。
|
|
362
386
|
if (isAskGatePark(ev.result)) {
|
|
363
387
|
ctx.taskId.current = ctx.taskId.current ?? ev.result.taskId;
|
|
388
|
+
led.noteParkGate({ fsOrShellFamily: false });
|
|
364
389
|
return { kind: 'park', gate: 'ask', pendingDone: ev };
|
|
365
390
|
}
|
|
366
391
|
if (isFsApprovalPark(ev.result)) {
|
|
367
392
|
ctx.taskId.current = ctx.taskId.current ?? ev.result.taskId;
|
|
393
|
+
// 准入证:主语是 checkpointGate **本体**的 toolName,不是任何 tool_end 帧的。
|
|
394
|
+
led.noteParkGate({ fsOrShellFamily: isFsOrShellToolName(ev.result.checkpointGate?.toolName) });
|
|
368
395
|
return { kind: 'park', gate: 'fs', pendingDone: ev };
|
|
369
396
|
}
|
|
370
397
|
const events = [...led.flushHeld()]; // 真错(非 gate)的 Ask tool_end 此刻诚实渲染
|
|
@@ -19,6 +19,17 @@
|
|
|
19
19
|
* 台账要能自描述,值类型必须与台账同层或更低。`askGateWire.ts` 原样 re-export 它,对外类型面不变。
|
|
20
20
|
*/
|
|
21
21
|
import type { AgentEvent } from '@sema-agent/sdk';
|
|
22
|
+
/**
|
|
23
|
+
* 连坐 abort 帧的 additive 超集机读位(#324 / [4907] 裁定;登记见 `docs/type-superset.json`)。
|
|
24
|
+
*
|
|
25
|
+
* `flushHeld` 对**已知不是 gate 主角**的帧 stamp `true`,别的帧一个字节不改。消费方(壳 / web /
|
|
26
|
+
* desktop)据此把连坐簇按 repeated-error 族软化折叠,**不猜文案**。
|
|
27
|
+
*
|
|
28
|
+
* 🔴 刻意**不动** `isError` 与 `output`:core 5.51 的 `[DEFERRED]` / `gate.batch_halted` 词汇
|
|
29
|
+
* ([4826]③)尚未到货,那一面的定形归 core;本键只是机读位,到货后与官方形对表,
|
|
30
|
+
* additive 键保留兼容(裁定原文)。
|
|
31
|
+
*/
|
|
32
|
+
export declare const SEMA_COLLATERAL_ABORT_KEY = "_sema_collateral_abort";
|
|
22
33
|
/** CC AskUserQuestion outputSchema 形状(答过的问题卡):toolResult 的 `ask-user-question` arm
|
|
23
34
|
* 消费它渲真实答案卡(否则「诚实缺席」路径会把这张卡渲成结果不可用)。 */
|
|
24
35
|
export interface AskAnsweredOutput {
|
|
@@ -52,12 +63,44 @@ export interface GateLedger {
|
|
|
52
63
|
gatedStartArgs(): ReadonlyMap<string, unknown>;
|
|
53
64
|
isEnded(callId: string): boolean;
|
|
54
65
|
markEnded(callId: string): void;
|
|
55
|
-
/**
|
|
56
|
-
*
|
|
66
|
+
/**
|
|
67
|
+
* park 毒化的 gated tool_end(isError:true "Operation aborted")——HOLD 到 gate 定性
|
|
68
|
+
* (AskUserQuestion + [816] 放宽后的 fs 写工具 + [2150] Bash)。
|
|
69
|
+
*
|
|
70
|
+
* 🔴 **入表当拍不判出身**(#324 换锚,2026-08-22):durable park 腿的帧序是
|
|
71
|
+
* `tool_start → tool_end(毒化) → done{suspended}` —— gate 身份**晚于**毒化帧到达,入表那一拍
|
|
72
|
+
* 包层根本还不知道谁是主角。出身改在 {@link flushHeld} 当拍求值(五个 flush 出口全部晚于 park
|
|
73
|
+
* 被看见),判据见 {@link noteParkGate}。
|
|
74
|
+
*/
|
|
57
75
|
hold(callId: string, ev: AgentEvent): void;
|
|
58
76
|
dropHeld(callId: string): void;
|
|
59
77
|
heldCount(): number;
|
|
60
|
-
/**
|
|
78
|
+
/**
|
|
79
|
+
* drain:逐帧吐出并**同批记 ended**(fail-soft 回退路径与终帧路径共用的唯一出口)。
|
|
80
|
+
*
|
|
81
|
+
* 🔴 **一帧不丢**(frameRouter:185 的不变量,#324 车实测确证它是刻意的):HOLD 过的帧在这里
|
|
82
|
+
* 全部吐出去 —— 丢帧的后果是永久假排队(dim 圆点永远等不到结果行),比多渲一行红字更坏。
|
|
83
|
+
* 本出口做的唯一一件事是给**已知不是 gate 主角**的帧 stamp {@link SEMA_COLLATERAL_ABORT_KEY}
|
|
84
|
+
* 机读位(additive 超集键;`isError` / `output` / 帧序一律不动),让消费端能把连坐簇与主角帧
|
|
85
|
+
* 分开呈现。
|
|
86
|
+
*
|
|
87
|
+
* 🔴 判词方向(fail-safe):**判不出本批主角 ⇒ 一个都不 stamp**(诚实缺席,与本键出现之前
|
|
88
|
+
* 逐字节相同);判得出 ⇒ 主角走原路零改动、其余一律 stamp。绝不按到达顺序编判词。
|
|
89
|
+
*
|
|
90
|
+
* 主角怎么判(实现见 `resolveGateSubjects`,判据全部**批级**、一批一套):
|
|
91
|
+
* ① **硬门:本批恰好一张 park**({@link noteParkGate})。零张 = 归属无从证明(同步帧腿 /
|
|
92
|
+
* 纯取消批都落这里);两张以上 = 这批扣留帧混了两次 gate 的 abort,谁属谁无解。一律不标。
|
|
93
|
+
* ② **主角 = 本批(扣留帧 ∪ 本批已出批的帧)里唯一属该 park 族的 call**。并上「已出批的帧」
|
|
94
|
+
* 是因为决断成功那一下会把主角的毒化帧 `dropHeld` 掉,只看扣留帧的话主角就「不在这一批」,
|
|
95
|
+
* 整批判据当场失效。族外 park(kind-only / ask)不发准入证 ⇒ 整批不标。
|
|
96
|
+
* ③ 前置:**每一条扣留帧的 `tool_start` 本连接都得见过** —— 族成员判据取自 tool_start 当拍
|
|
97
|
+
* 记的集合,没见过 start 的 call 在「唯一」这件事上是隐形的;续流只消费 `runs.events` 的
|
|
98
|
+
* 一段,主角的 start 完全可能落在这次连接之外,那时表里剩下的唯一族成员是**旁观者**。
|
|
99
|
+
*
|
|
100
|
+
* 🔴 **pending 队列一概不参与判别**:`durable checkpointGate` 不带 callId,`findPendingForTask`
|
|
101
|
+
* 取的是「同 taskId + 谓词命中的第一行」(不命中时退「任意行」)—— 那是给**卡面渲染**用的宽口,
|
|
102
|
+
* **不是身份**。同族两行排队时它会给出旁观者,拿它当主角就把真主角挤成「非主角」而 stamp。
|
|
103
|
+
*/
|
|
61
104
|
flushHeld(): Generator<AgentEvent>;
|
|
62
105
|
/** 三选卡 deny 过的 call:重放 tool_end 的 render 面 stamp REJECT_MESSAGE(vendored
|
|
63
106
|
* renderToolUseRejectedMessage 渲 `User rejected <op> to <path>`,CC 逐字)。 */
|
|
@@ -81,6 +124,28 @@ export interface GateLedger {
|
|
|
81
124
|
* 时前进,天然把「这次 park 到底是哪个 call」的身份带过 decide→重放两轮。 */
|
|
82
125
|
noteFsOrShellGate(callId: string): void;
|
|
83
126
|
lastFsOrShellGatedCallId(): string | undefined;
|
|
127
|
+
/**
|
|
128
|
+
* 登记「**这一批**的 park」——判别子唯一认的归属证据。写者 = 四条 park 臂:`routeDone` 的
|
|
129
|
+
* ask/fs 两条、`routeSuspended` 的 ask/fs 两条。`fsOrShellFamily` = 这张 park 的 gate **本体**
|
|
130
|
+
* `toolName` 属 fs 写 / shell 执行族吗(唯一性兜底腿的准入证)。
|
|
131
|
+
*
|
|
132
|
+
* 🔴 **为什么只认 park、不认 `tool_approval` 帧**(异源对抗复审四轮的收口,2026-08-22):
|
|
133
|
+
* 判别子要回答的是「**这一批** abort 帧属于哪张 gate」,而 wire 上**没有**任何位做这个关联 ——
|
|
134
|
+
* 包层能算的都是推断。park 是唯一**归属可结构性证明**的证据:`flushHeld` 的出口就长在那张 park
|
|
135
|
+
* 自己的决断/回退路径上(`parkResolver` fail-soft / decide 成功后的续流放行 / 终帧),
|
|
136
|
+
* 「这一批是这张 park 的 abort 批」是结构事实,不是猜的。
|
|
137
|
+
* 审批帧腿不具备这个性质:帧只证明「本 turn 出现过一张 gate」,那张 gate 可能**早已正常收口**
|
|
138
|
+
* (零毒化帧 ⇒ 零扣留表 ⇒ 一次 flush 都不跑),它的证却会活到下一批去派判词。四轮实测里
|
|
139
|
+
* 三条「假阳打回主角」都出自帧腿证据(旧 server 双主角 / 零 HOLD 审批证跨批 / 历史身份跨批),
|
|
140
|
+
* 故本版**刻意**不从帧腿取证 —— 代价是同步帧腿整条不标(已知局限,见 §3z)。
|
|
141
|
+
*
|
|
142
|
+
* 🔴 **重放同一张 park 不算新的一张**:#110 成文「durable re-attach 必然把已决断的 park 再送
|
|
143
|
+
* 一遍」。判据 = 自上一次 park 登记以来**有没有新的帧进过扣留表**;没有就是同一张 park 被重放,
|
|
144
|
+
* 计数不动(否则本批会被自己的重放判成「多 park」而整批失效,真连坐帧拿不到位)。
|
|
145
|
+
*/
|
|
146
|
+
noteParkGate(evidence: {
|
|
147
|
+
fsOrShellFamily: boolean;
|
|
148
|
+
}): void;
|
|
84
149
|
/** 续流重放的解答 tool_end 无 output,不补就会渲成结果不可用;这里记下真实答案供该帧 stamp
|
|
85
150
|
* `structured` 让卡片渲真实选择。 */
|
|
86
151
|
rememberAnswer(callId: string, answered: AskAnsweredOutput): void;
|
package/dist/hitl/gateLedger.js
CHANGED
|
@@ -1,14 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 连坐 abort 帧的 additive 超集机读位(#324 / [4907] 裁定;登记见 `docs/type-superset.json`)。
|
|
3
|
+
*
|
|
4
|
+
* `flushHeld` 对**已知不是 gate 主角**的帧 stamp `true`,别的帧一个字节不改。消费方(壳 / web /
|
|
5
|
+
* desktop)据此把连坐簇按 repeated-error 族软化折叠,**不猜文案**。
|
|
6
|
+
*
|
|
7
|
+
* 🔴 刻意**不动** `isError` 与 `output`:core 5.51 的 `[DEFERRED]` / `gate.batch_halted` 词汇
|
|
8
|
+
* ([4826]③)尚未到货,那一面的定形归 core;本键只是机读位,到货后与官方形对表,
|
|
9
|
+
* additive 键保留兼容(裁定原文)。
|
|
10
|
+
*/
|
|
11
|
+
export const SEMA_COLLATERAL_ABORT_KEY = '_sema_collateral_abort';
|
|
1
12
|
/** 造一份 turn 级 gate 台账(**不是单例**,见文件头注)。 */
|
|
2
13
|
export function createGateLedger() {
|
|
3
14
|
const startedCalls = new Set();
|
|
4
15
|
const endedCalls = new Set();
|
|
16
|
+
/** 只存帧:出身不在入表当拍冻结(那一拍 gate 身份还没到),改在 `flushHeld` 当拍求值。 */
|
|
5
17
|
const heldAskEnds = new Map();
|
|
6
18
|
const gatedStartArgsByCall = new Map();
|
|
7
19
|
const deniedCalls = new Set();
|
|
8
20
|
const pendingFsCalls = [];
|
|
9
21
|
const resolvedAnswers = new Map();
|
|
10
22
|
const decidedGates = new Set();
|
|
23
|
+
// ── 批级判据(四样同生共死,退休点见 `retireBatchState` 的两处调用)────────────────────────
|
|
24
|
+
/** 本批 park 属 fs/shell 族的准入证(唯一性兜底的前置)。 */
|
|
25
|
+
let fsOrShellFamilyGate = false;
|
|
26
|
+
/** 本批里被 `dropHeld` 摘出扣留表的 call(decide 成功会把主角摘走,判据还得认它)。 */
|
|
27
|
+
const droppedFromBatch = new Set();
|
|
28
|
+
/** 本批登记过几张 park。≠1 ⇒ 归属无从证明 ⇒ 整表不标(硬门)。 */
|
|
29
|
+
let batchParkCount = 0;
|
|
30
|
+
/** 上一次 park 登记之后有没有新帧进过扣留表 —— 用来把「同一张 park 被 durable 重放」认出来。 */
|
|
31
|
+
let heldSinceLastPark = false;
|
|
32
|
+
/** 本 turn 见过的 fs 写 / shell 执行族 gated tool_start —— 只做**族成员**判据,不做主角判据。 */
|
|
33
|
+
const fsOrShellGatedCalls = new Set();
|
|
11
34
|
let lastFsOrShellGatedCall;
|
|
35
|
+
/**
|
|
36
|
+
* flush 当拍解析「谁是主角」:登记在案的优先;否则唯一性兜底(要准入证 + 扣留表内族成员唯一);
|
|
37
|
+
* 都拿不到 ⇒ `undefined` = 不知道,调用方一个都不 stamp。
|
|
38
|
+
*
|
|
39
|
+
* 🔴 返回 `undefined` 与返回空集合是**两件事**,别合并([honest-absence-not-fabricated-zero]):
|
|
40
|
+
* 空集合意味着「知道谁是主角,且一个都不是」。
|
|
41
|
+
* 🔴 兜底在**扣留表内**求唯一 —— 主角必在这一批被同一次 abort 连坐的 call 里;拿整个 turn 的
|
|
42
|
+
* 历史集求唯一会把「已经收口过的旧 call」算进来,又是一次「拿旁证冒充身份」。
|
|
43
|
+
*/
|
|
44
|
+
const resolveGateSubjects = () => {
|
|
45
|
+
// 🔴 硬门:归属可结构性证明 = 本批恰好一张 park。零张(同步帧腿 / 纯取消批)与多张(两次
|
|
46
|
+
// gate 的 abort 混进同一张扣留表)都无解 —— 诚实不标,绝不猜。
|
|
47
|
+
if (batchParkCount !== 1)
|
|
48
|
+
return undefined;
|
|
49
|
+
// 准入证:这张 park 的 gate **本体**属 fs 写 / shell 执行族 —— 主角必是该族的某个 call。
|
|
50
|
+
if (!fsOrShellFamilyGate)
|
|
51
|
+
return undefined;
|
|
52
|
+
// 前置:每一条扣留帧的 `tool_start` 都得是本连接亲眼见过的。族成员判据取自 tool_start 当拍
|
|
53
|
+
// 记的集合,没见过 start 的 call 在「唯一」这件事上是隐形的;而续流只消费 `runs.events` 的一段
|
|
54
|
+
// (re-attach 从 `lastEventId` 起),主角的 start 完全可能落在这次连接之外 —— 那时表里剩下的
|
|
55
|
+
// 唯一族成员是**旁观者**,会被当成主角、反手给真主角打上连坐位。信息不全就不许声称「唯一」。
|
|
56
|
+
for (const id of heldAskEnds.keys()) {
|
|
57
|
+
if (!startedCalls.has(id))
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
// 主角 = 本批(扣留帧 ∪ 已出批帧)里**唯一**属该族的 call。并上出批帧是因为决断成功那一下会
|
|
61
|
+
// 把主角的毒化帧 `dropHeld` 掉;不并上就等于主角「不在这一批」,整批判据当场失效。
|
|
62
|
+
const family = [...new Set([...heldAskEnds.keys(), ...droppedFromBatch])].filter((id) => fsOrShellGatedCalls.has(id));
|
|
63
|
+
return family.length === 1 ? new Set(family) : undefined;
|
|
64
|
+
};
|
|
65
|
+
/** 一批判完(或整批被摘空)⇒ 四样批级判据同批退休:下一批从零证起。 */
|
|
66
|
+
const retireBatchState = () => {
|
|
67
|
+
fsOrShellFamilyGate = false;
|
|
68
|
+
droppedFromBatch.clear();
|
|
69
|
+
batchParkCount = 0;
|
|
70
|
+
heldSinceLastPark = false;
|
|
71
|
+
};
|
|
12
72
|
let denyStampNextFsEnd = false;
|
|
13
73
|
let seq;
|
|
14
74
|
return {
|
|
@@ -41,20 +101,43 @@ export function createGateLedger() {
|
|
|
41
101
|
endedCalls.add(callId);
|
|
42
102
|
},
|
|
43
103
|
hold(callId, ev) {
|
|
104
|
+
// 🔴 只有**新** call 进批才算「批里来了新东西」:durable re-attach 会把仍被扣留的毒化帧
|
|
105
|
+
// 连同 park 一起重放,那一下若也置位,同一张 park 就会被当成第二张而触发硬门弃判
|
|
106
|
+
// (实测:重放后本该带位的兄弟帧变成 ABSENT)。覆盖同一 callId = 重放,不置位。
|
|
107
|
+
if (!heldAskEnds.has(callId))
|
|
108
|
+
heldSinceLastPark = true;
|
|
44
109
|
heldAskEnds.set(callId, ev);
|
|
45
110
|
},
|
|
46
111
|
dropHeld(callId) {
|
|
47
|
-
heldAskEnds.delete(callId)
|
|
112
|
+
if (heldAskEnds.delete(callId))
|
|
113
|
+
droppedFromBatch.add(callId);
|
|
114
|
+
// 🔴 扣留表空 = 这一批没有(或不再有)任何待判的帧,批级判据当场退休 —— 不能等下一次
|
|
115
|
+
// flush:「决断成功但本批压根没有毒化帧」的路径上 `flushHeld` 一次都不会跑,判据会就这么
|
|
116
|
+
// 活到下一批去把那一批的**真主角**判成连坐(实测 `new-main=STAMP`)。
|
|
117
|
+
// 🔴 「摘的那个不在表里」也要走这一步(不能早退):零 HOLD 批正是**每次** delete 都落空的
|
|
118
|
+
// 形状,早退就等于那种批永远不退休 —— 上一版的漏洞就在这里。
|
|
119
|
+
if (heldAskEnds.size === 0)
|
|
120
|
+
retireBatchState();
|
|
48
121
|
},
|
|
49
122
|
heldCount() {
|
|
50
123
|
return heldAskEnds.size;
|
|
51
124
|
},
|
|
52
125
|
*flushHeld() {
|
|
53
|
-
|
|
126
|
+
// 🔴 出身在**这一拍**求值(不是入表当拍):五个 flush 出口全部晚于 park 被看见,
|
|
127
|
+
// gate 身份此时已在手。`undefined` = 不知道谁是主角 ⇒ 整表一个字节不改。
|
|
128
|
+
const subjects = resolveGateSubjects();
|
|
129
|
+
for (const [callId, ev] of heldAskEnds) {
|
|
54
130
|
endedCalls.add(callId);
|
|
55
|
-
|
|
131
|
+
// 已知不是主角 ⇒ additive 机读位(帧的其余部分逐字节原样);主角与「不知道」走原路。
|
|
132
|
+
yield subjects !== undefined && !subjects.has(callId)
|
|
133
|
+
? { ...ev, [SEMA_COLLATERAL_ABORT_KEY]: true }
|
|
134
|
+
: ev;
|
|
56
135
|
}
|
|
57
136
|
heldAskEnds.clear();
|
|
137
|
+
// 🔴 判完即弃:这一批帧就是这张 gate 的 abort 批。不退休 ⇒ 判完之后又来一批**背后没有
|
|
138
|
+
// 任何 gate**的 abort 帧(例如整轮被取消)时,上一批的证会给它们派判词。
|
|
139
|
+
// 身份不在退休之列(turn 级事实),它靠上面的「∩ 本批」求交集来限定作用域。
|
|
140
|
+
retireBatchState();
|
|
58
141
|
},
|
|
59
142
|
markDenied(callId) {
|
|
60
143
|
deniedCalls.add(callId);
|
|
@@ -87,10 +170,26 @@ export function createGateLedger() {
|
|
|
87
170
|
},
|
|
88
171
|
noteFsOrShellGate(callId) {
|
|
89
172
|
lastFsOrShellGatedCall = callId;
|
|
173
|
+
fsOrShellGatedCalls.add(callId);
|
|
90
174
|
},
|
|
91
175
|
lastFsOrShellGatedCallId() {
|
|
92
176
|
return lastFsOrShellGatedCall;
|
|
93
177
|
},
|
|
178
|
+
noteParkGate(evidence) {
|
|
179
|
+
// 自上次登记以来没有**新 call** 进过扣留表 ⇒ 按 durable 重放同一张 park 处置:不计新的一张。
|
|
180
|
+
// 🔴 而且**一个字节都不写**。「没有新帧进批」证明得了「这一批的组成没变」,证明不了
|
|
181
|
+
// 「这张 park 就是上一张」—— 一张**真的新 park** 同样可以零毒化帧(例如上一张 park 走
|
|
182
|
+
// already-resolved 重放救回、续流紧接着来一张别的 gate 的 park)。此时若顺手刷新族属,
|
|
183
|
+
// 本批的判据就被一张与这批帧无关的 gate 改写:实测 `WebFetch` 主角 + `Bash` 旁观者的批
|
|
184
|
+
// 被一张零毒化 `Bash` park 改成 fs/shell 族,兜底选中旁观者、反手给真主角打位
|
|
185
|
+
// (`web-main=STAMP`)。真是重放时族属本就相同,不写零损失;是新 park 时不写才安全。
|
|
186
|
+
// (本批的帧全部早于第一张 park,归属本来就该按第一张算。)
|
|
187
|
+
if (batchParkCount > 0 && !heldSinceLastPark)
|
|
188
|
+
return;
|
|
189
|
+
batchParkCount += 1;
|
|
190
|
+
fsOrShellFamilyGate = evidence.fsOrShellFamily;
|
|
191
|
+
heldSinceLastPark = false;
|
|
192
|
+
},
|
|
94
193
|
rememberAnswer(callId, answered) {
|
|
95
194
|
resolvedAnswers.set(callId, answered);
|
|
96
195
|
},
|
|
@@ -289,6 +289,17 @@ export async function resolvePark(park, ctx) {
|
|
|
289
289
|
// decide 成功:丢弃该 call 的毒化 HOLD(续流重放会带 isError:false 的解答帧收口卡片),
|
|
290
290
|
// 并记下真实答案供该解答帧 stamp `structured`(否则卡片渲成结果不可用)。
|
|
291
291
|
if (outcome.gatedCallId) {
|
|
292
|
+
// 🔴 #324:**刻意不把 pending 行的 callId 当成连坐判别的主角身份**。durable `checkpointGate`
|
|
293
|
+
// 不带 callId,`findPendingForTask` 取的是「同 taskId + 谓词命中的**第一行**」(谓词不命中
|
|
294
|
+
// 时还退「任意行」)—— 那是给**卡面渲染**用的宽口,证明不了这一行就是这张 park 的主角:
|
|
295
|
+
// 同族两行排队时它可能给出旁观者,于是真主角被挤成「非主角」而 stamp(异源复审实测)。
|
|
296
|
+
// 连坐判别改由台账按「本批唯一的该族 call」自证(`gateLedger.flushHeld` 头注),
|
|
297
|
+
// 分不出来就整批不标。下面两行是 gate 生命周期(#110 / REF-CC-034),与判别无关,照旧。
|
|
298
|
+
// ⚠️ **记案(存量,非本批根因)**:`dropHeld` 用的也是这个不可信的 `gatedCallId` —— 同族
|
|
299
|
+
// 多行排队时它可能摘掉**另一条** call 的扣留帧,那一帧就再也不吐了(「一帧不丢」在这一格
|
|
300
|
+
// 上不成立)。这条早于本批(4c42c8a 逐字相同),根因在「decide 结果没有可核验的 park 身份」,
|
|
301
|
+
// 与本批修的判别面是两件事;改它要动 #110 的承重路径,单独立案。server 补
|
|
302
|
+
// `checkpointGate.toolCallId` 后两处一并收口。
|
|
292
303
|
led.dropHeld(outcome.gatedCallId);
|
|
293
304
|
led.markDecided(outcome.gatedCallId); // #110 缺陷② b / REF-CC-034:身份留痕,上方候选匹配消费
|
|
294
305
|
if ('answered' in outcome && outcome.answered)
|
|
@@ -296,6 +296,17 @@ export interface ApprovalCardRequest {
|
|
|
296
296
|
* **行为面**改动(会改到人已按下的决断的字节),按宪法三问单独立项,不在本过境批内。
|
|
297
297
|
*/
|
|
298
298
|
requiresRealApproval?: true;
|
|
299
|
+
/** [4851]:窗三键透传(server ≥7.34;壳 readAskDeadlineMs 消费渲倒计时)。只在
|
|
300
|
+
* `windowIsCurrent === true` 的 live 腿上过境(重放腿=旧余量,续窗即假倒计时);**全部**缺席
|
|
301
|
+
* =该帧无窗不渲,半套在场读器按「expiresAtMs 优先、expiresInMs 兜底」回落。 */
|
|
302
|
+
expiresInMs?: number;
|
|
303
|
+
/** 同门:窗绝对到点(server 时钟 epoch ms)。 */
|
|
304
|
+
expiresAtMs?: number;
|
|
305
|
+
/** 同门:server 出帧时刻(壳时钟校偏用)。 */
|
|
306
|
+
serverNowMs?: number;
|
|
307
|
+
/** 本地**收帧**时刻(`Date.now()`,与窗任一键同拍盖下)。壳读器明文优先这枚锚:卡口串行
|
|
308
|
+
* 阻塞下,排队靠后的卡若按「呈现那一刻」起算余量,等待的时间会被整段还给窗。 */
|
|
309
|
+
receivedAtMs?: number;
|
|
299
310
|
}
|
|
300
311
|
/**
|
|
301
312
|
* 🔴 **拆缝口** —— 弹「三选卡」并等人的决断。壳 = vendored CC `PermissionRequest`;
|
|
@@ -494,6 +505,26 @@ export interface ToolApprovalFrame {
|
|
|
494
505
|
* run-durable-card-display-keys-test.mjs ⑨ 段;上游补位后按 {@link probeCause} 的双源合流形跟批。
|
|
495
506
|
*/
|
|
496
507
|
requiresRealApproval?: true;
|
|
508
|
+
/**
|
|
509
|
+
* server ≥7.34.0(#288/[4429]② —— cli 自己请托的窗三键,**ADDITIVE**,`"tool_approval"` only;
|
|
510
|
+
* 来源锚 = sema-server src/tool-approval.ts 的三键声明+emit 前赋值,字段注逐字「新壳借此给旧族帧
|
|
511
|
+
* 补倒计时」)。这只 ask 的**决策窗**:到点后引擎按 `UNATTENDED_APPROVAL_POLICY`(缺省 park)
|
|
512
|
+
* 处置,卡上的按键此后 404 `tool_approval.not_pending`([4845] Postgres 直读实证)。
|
|
513
|
+
*
|
|
514
|
+
* 🔴 三键**信封级**(不进 card 语义):壳的倒计时读器(`readAskDeadlineMs`)以
|
|
515
|
+
* `expiresAtMs`(+`serverNowMs` 时钟校偏)优先、`expiresInMs` 兜底 —— **半套在场时按此
|
|
516
|
+
* 优先序回落消化**(异源对抗复审纠偏:早注「任一缺席整段不渲」与真实读器不符);**全部**
|
|
517
|
+
* 缺席 = 旧 server / 该帧无窗,才是不渲。0.38.1 及更早的白名单投影把三键丢在包边界外
|
|
518
|
+
* ([4851] 头号请托的实体)——帧到了、壳读器预埋了、中间这一格空转,[4845]「卡挂着像活的」
|
|
519
|
+
* 的直接成因。缺席 ≠ 「永不过期」。
|
|
520
|
+
* 🔴 过境有闸:三键只在 `ToolApprovalFrameLaneOpts.windowIsCurrent === true`(live 流)时上卡
|
|
521
|
+
* —— durable 账本重放的历史帧带的是铸帧时刻的旧余量,续窗 = 假倒计时(见 stamp 段注)。
|
|
522
|
+
*/
|
|
523
|
+
expiresInMs?: number;
|
|
524
|
+
/** 窗绝对到点时刻(server 时钟,epoch ms)。与 {@link expiresInMs} 同门在场。 */
|
|
525
|
+
expiresAtMs?: number;
|
|
526
|
+
/** server 出帧时刻(epoch ms)——壳用它对本地时钟校偏后再消费 expiresAtMs。 */
|
|
527
|
+
serverNowMs?: number;
|
|
497
528
|
}
|
|
498
529
|
/** {@link ToolApprovalFrame.delegation} 的形(命名形,不用内联匿名 —— typeshape 门 B4 棘轮口径)。 */
|
|
499
530
|
export interface ToolApprovalDelegation {
|
|
@@ -509,7 +540,7 @@ export interface ToolApprovalDelegation {
|
|
|
509
540
|
* `TOOL_APPROVAL_FRAME_KEYS` 比对——SDK additive 增键时对账当天红,不再人肉追平。
|
|
510
541
|
* 下面两个类型钉保证镜像与 interface 本身不可能漂移(少键/多键都是编译错)。
|
|
511
542
|
*/
|
|
512
|
-
export declare const TOOL_APPROVAL_FRAME_KEYS_MIRROR: readonly ["type", "approvalId", "toolCallId", "toolName", "sourceTaskId", "fromSubagent", "sourceAgentName", "message", "args", "argsOmitted", "governanceForced", "ruleSuggestions", "persistedRuleShadowed", "probeCause", "ruleEvidence", "requiresRealApproval", "delegation", "outcome"];
|
|
543
|
+
export declare const TOOL_APPROVAL_FRAME_KEYS_MIRROR: readonly ["type", "approvalId", "toolCallId", "toolName", "sourceTaskId", "fromSubagent", "sourceAgentName", "message", "args", "argsOmitted", "governanceForced", "ruleSuggestions", "persistedRuleShadowed", "probeCause", "ruleEvidence", "requiresRealApproval", "expiresInMs", "expiresAtMs", "serverNowMs", "delegation", "outcome"];
|
|
513
544
|
/**
|
|
514
545
|
* 子代帧判别:显式键 fromSubagent(core 1.378 RB-39②)优先;缺席退 sourceTaskId 在场性权宜式
|
|
515
546
|
* (server 1.258 [1549]①3,旧代际兼容)。
|
|
@@ -599,5 +630,15 @@ export interface ToolApprovalFrameLaneOpts {
|
|
|
599
630
|
* 缺席/false ⇒ 不发(fail-closed 到「不发」侧;决断本身照常送达,现状字节不变)。
|
|
600
631
|
*/
|
|
601
632
|
approvalDecisionNoteCapable?: boolean;
|
|
633
|
+
/**
|
|
634
|
+
* 这条帧是不是**当下**从 live 流上收到的(异源对抗复审 P1 采纳;壳孪生帧族同名闸的
|
|
635
|
+
* 本包席位 —— 壳 `approvalStreamWire` 头注逐字:「账本重放的历史帧带的是铸帧时刻的旧余量,
|
|
636
|
+
* 拿它算『本地 now + 余量』等于给一只早就过期的 ask 续一个新窗」)。
|
|
637
|
+
* 🔴 窗三键**只在本位 === true 时**过境到卡:durable 账本 tail 会把旧 `tool_approval` 行连
|
|
638
|
+
* 冻结三键逐字重放,重放腿不设防 = 过期 ask 在屏上拿到一个精确但完全错误的倒计时,比
|
|
639
|
+
* 「卡挂着没倒计时」更坏。缺席 = 不知道来路 ⇒ **不 stamp**(fail-closed:退回无窗渲染,
|
|
640
|
+
* 老宿主不传本位时行为 = 0.38.1,零回归)。live 腿的宿主接线随各端提货批补 `true`。
|
|
641
|
+
*/
|
|
642
|
+
windowIsCurrent?: boolean;
|
|
602
643
|
}
|
|
603
644
|
export declare function surfaceToolApprovalFrameAndRespond(frame: ToolApprovalFrame, respond: RespondToolApprovalFn, streamArgs: unknown | undefined, signal?: AbortSignal, lane?: ToolApprovalFrameLaneOpts): Promise<ToolApprovalFrameOutcome>;
|
|
@@ -389,6 +389,14 @@ export const TOOL_APPROVAL_FRAME_KEYS_MIRROR = [
|
|
|
389
389
|
// sdk 7.1.0 的运行期锚**尚无**本键(node 直读实证:锚 17 项)⇒ 这是一次**领先**,进对账门的
|
|
390
390
|
// AHEAD_OF_ANCHOR 带退出条件登记(SDK 追平当天那条登记自红逼删,回到逐元素相等)。
|
|
391
391
|
'requiresRealApproval',
|
|
392
|
+
// [4851] 头号请托(client-core 0.38.2):server 7.34.0 起真发窗三键(#288/[4429]② cli 自己请托,
|
|
393
|
+
// server src/tool-approval.ts 三键声明+条件 stamp)。⚠️ 与 requiresRealApproval 同形=**领先** SDK
|
|
394
|
+
// 运行期锚(sdk 7.2.0 锚 17 项,node 直读实证无三键)⇒ 进对账门 AHEAD_OF_ANCHOR 带退出条件登记
|
|
395
|
+
// (SDK 追平当天登记自红逼删)。0.38.1 把三键丢在包边界外 = [4845]「卡到期屏幕零反应」的直接成因
|
|
396
|
+
// (壳读器 readAskDeadlineMs 早已预埋,缺的一直是包边界这一格——#283 逐字同形第四例)。
|
|
397
|
+
'expiresInMs',
|
|
398
|
+
'expiresAtMs',
|
|
399
|
+
'serverNowMs',
|
|
392
400
|
'delegation',
|
|
393
401
|
'outcome',
|
|
394
402
|
];
|
|
@@ -532,6 +540,12 @@ function pathFromGateMessage(message) {
|
|
|
532
540
|
* 🔴 **一把判词服务多键**是设计而非省事:两条决断腿(活帧 / durable 行)× 多个开集记录键共用同一个
|
|
533
541
|
* 载体判据,判词绝不各写各的(各写一份 = 同一个问题有了两个属主,分叉那天没人发现)。
|
|
534
542
|
*/
|
|
543
|
+
/** 窗三键的坏形闸:三键定义域按 SDK 契约本就非负(`expiresInMs = max(0, …)`,0 合法=窗恰好
|
|
544
|
+
* 到点)。裸 `Number.isFinite` 会放行负数 —— 与铸卡注承诺的「负数=坏形降缺席」相反(同文件
|
|
545
|
+
* `delegation.depth` 曾同款教训,异源对抗复审第二次命中同形)。 */
|
|
546
|
+
function isNonNegativeFinite(v) {
|
|
547
|
+
return typeof v === 'number' && Number.isFinite(v) && v >= 0;
|
|
548
|
+
}
|
|
535
549
|
function isWireRecordCarrier(v) {
|
|
536
550
|
return typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
537
551
|
}
|
|
@@ -630,6 +644,26 @@ export async function surfaceToolApprovalFrameAndRespond(frame, respond, streamA
|
|
|
630
644
|
...(isFromSubagent(frame) ? { workerBadge: subagentBadgeFor(frame) } : {}),
|
|
631
645
|
...(wireNote !== undefined ? { wireNote } : {}),
|
|
632
646
|
...(frame.governanceForced === true ? { governanceForced: true } : {}),
|
|
647
|
+
// [4851]:窗三键透传,三闸合取(异源对抗复审 P1/P2 收编):
|
|
648
|
+
// ① `lane.windowIsCurrent === true` —— durable 账本重放的历史帧带的是铸帧时刻的旧余量,
|
|
649
|
+
// 给它续窗 = 过期 ask 渲出精确假倒计时(壳孪生族同名闸的本包席位,见 LaneOpts 注);
|
|
650
|
+
// ② **非负有限数**才 stamp —— `Number.isFinite` 单独放行负数,而三键定义域按 SDK 契约
|
|
651
|
+
// 本就非负(`expiresInMs = max(0, …)`;0 合法 = 窗恰好到点)。负数/NaN/Infinity =
|
|
652
|
+
// 坏形降缺席,绝不折 0 或猜(同文件 delegation.depth 曾同款教训);
|
|
653
|
+
// ③ 三键各自独立 stamp:server 承诺同门在场,但包边界不替上游把「半套在场」湮灭成全缺席
|
|
654
|
+
// —— 读器自己按「expiresAtMs 优先、expiresInMs 兜底」消化半套。
|
|
655
|
+
// 任一键 stamp 时同步盖 `receivedAtMs`(本地收帧锚):卡口串行阻塞下,排队靠后的卡若按
|
|
656
|
+
// 「呈现那一刻」起算余量,窗被整段还回去 —— 壳读器明文优先这枚锚。
|
|
657
|
+
...(lane?.windowIsCurrent === true
|
|
658
|
+
? {
|
|
659
|
+
...(isNonNegativeFinite(frame.expiresInMs) ? { expiresInMs: frame.expiresInMs } : {}),
|
|
660
|
+
...(isNonNegativeFinite(frame.expiresAtMs) ? { expiresAtMs: frame.expiresAtMs } : {}),
|
|
661
|
+
...(isNonNegativeFinite(frame.serverNowMs) ? { serverNowMs: frame.serverNowMs } : {}),
|
|
662
|
+
...(isNonNegativeFinite(frame.expiresInMs) || isNonNegativeFinite(frame.expiresAtMs)
|
|
663
|
+
? { receivedAtMs: Date.now() }
|
|
664
|
+
: {}),
|
|
665
|
+
}
|
|
666
|
+
: {}),
|
|
633
667
|
// 🔴 跨字段不变量(对抗复审命中):`delegation` 只在**子代 ask** 的门上在场(SDK 头注:
|
|
634
668
|
// "Present on the same door as fromSubagent (child asks only)")。只校对象形不校这一条 ⇒
|
|
635
669
|
// 一个**宿主自己**的破坏性工具审批也能带着 delegation 到卡口,被呈成「某层子代发起的」——
|
|
@@ -58,6 +58,15 @@ export interface ToolEndResultArmLike {
|
|
|
58
58
|
/** 引擎 CC-shaped details(core 1.199+ AgentToolResult.details;Bash 时带 exitCode)。 */
|
|
59
59
|
structured?: unknown;
|
|
60
60
|
truncated?: unknown;
|
|
61
|
+
/**
|
|
62
|
+
* 这次调用失败的**机器码**(开集;`eventToSdkMessage` 的 `case 'tool_end'` 臂原样上臂,宿主从
|
|
63
|
+
* 臂上直读 —— 与 {@link settledBy}/{@link approver} 同款「臂带、卡不带」姿势)。已知族:中断
|
|
64
|
+
* 合成收口两码(`interrupted_never_started` / `interrupted_outcome_unknown`,core 5.10.0)、
|
|
65
|
+
* 委派席位到限两码(`delegation.*`)与 `mcp.server_revoked`(两族 core ≥5.50.0 孪生拼法起才
|
|
66
|
+
* 真到达 —— 更旧引擎恒缺席,缺席≠没拒过)。词表与判定单源 `engineErrorCodes.ts`
|
|
67
|
+
* (`delegationCapDispositionOf` 等);宿主只渲已知码的指路文案,未知码原样报码**不编因**。
|
|
68
|
+
*/
|
|
69
|
+
errorCode?: unknown;
|
|
61
70
|
/**
|
|
62
71
|
* 这次调用**是怎么结算的**(core ≥5.18.1 #187;`human`/`timeout`/`aborted` + 开集读)与
|
|
63
72
|
* **是谁结算的**(core ≥5.35.0 design/252 G-7 / server ≥7.23.0 #263;审批通道自报的身份串,
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
| peer:wire 契约 | `@sema-agent/sdk` **>=7.2.0**(value-level,非 type-only) | `package.json` `peerDependencies` |
|
|
24
24
|
| peer:会话词汇表 | `@sema-agent/agent-types` **>=0.2.0**(type-only,零运行时) | 同上 |
|
|
25
25
|
| runtime dep | `diff` ^9.0.0(**唯一**一条;portability 门按**等值**钉死) | `package.json` `dependencies` |
|
|
26
|
-
| 公开导出面 | **
|
|
26
|
+
| 公开导出面 | **767** 个运行期符号(+ 39 个测试钩;= 未发 `0.40.0` 的值,npm `0.39.0` 是 **766**,`0.38.0` 是 **764**;`0.37.0` 是 **753**,见 `CHANGELOG.md`) | `scripts/public-export-baseline.json` 的 `count` / `testHookCount` —— **别手抄进别处,以该文件为准** |
|
|
27
27
|
| 常驻门 | 以 `scripts/gates-manifest.json` 的 `suites` 长度为准(**本档不抄这个数**) | `scripts/gates-manifest.json`;`npm test` 的名单等值门与它逐名对账 |
|
|
28
28
|
| 沿革档 | 0.29.0 起建 `CHANGELOG.md`;更早批次记账在 `src/index.ts` 文件头 + `docs/REFACTOR-LEDGER.md` | — |
|
|
29
29
|
|
|
@@ -101,7 +101,7 @@ SDK 核对「本包 import 的每个值级符号仍然导出」「`TaskStats.cos
|
|
|
101
101
|
|
|
102
102
|
## §2 公共导出面地图(按域)
|
|
103
103
|
|
|
104
|
-
> 全集真源 = `scripts/public-export-baseline.json` 的 `names`(**
|
|
104
|
+
> 全集真源 = `scripts/public-export-baseline.json` 的 `names`(**767** 项)。
|
|
105
105
|
> 本节**不逐名抄**,只给「域 → 承重导出 → 用途 → 实现锚」。承重导出 = 一个端为了让这个域干活
|
|
106
106
|
> **必须**直接调到的那几个符号;其余是它们的类型、变体与辅助位。
|
|
107
107
|
> 单一入口:`import { … } from '@sema-agent/client-core'`(`exports` 只有 `.` 一个;
|
|
@@ -111,7 +111,7 @@ SDK 核对「本包 import 的每个值级符号仍然导出」「`TaskStats.cos
|
|
|
111
111
|
|
|
112
112
|
`public-export-baseline.json` 由 **`dist/index.js` 的运行期导出**生成(生成口径自述见
|
|
113
113
|
`scripts/run-client-core-typeshape-test.mjs`,双向精确集合门在 `scripts/run-public-surface-test.mjs`)。
|
|
114
|
-
实测:
|
|
114
|
+
实测:767 项 **100% 是运行期导出,零 type-only**。
|
|
115
115
|
|
|
116
116
|
**推论(端必须知道)**:
|
|
117
117
|
- barrel 导出的**类型**面比 707 大得多,且**不被这道门看守** —— `AdapterContext` / `SeamEvent` /
|
|
@@ -120,18 +120,18 @@ SDK 核对「本包 import 的每个值级符号仍然导出」「`TaskStats.cos
|
|
|
120
120
|
端依赖这些类型是合法的,但**不要**拿基线 diff 当"类型面没变"的证据。
|
|
121
121
|
- `src/agentSession/contract.ts` 对基线贡献 **0** 项(纯类型模块,`export *` 在 dist 里是空转发)。
|
|
122
122
|
|
|
123
|
-
|
|
123
|
+
767 项的内部构成(帮助端估读表大小):**227** 项是 `SCREAMING_SNAKE` 常量数据表/词汇表
|
|
124
124
|
(矩阵、键集、env 名、锚串)而非可调用物;**5** 项是 PascalCase 运行期值
|
|
125
125
|
(`ControlRouter` / `ControlSafetyError` / `HitlBridge` / `HitlSafetyError` / `DecideTransportRetryExhaustedError`);
|
|
126
126
|
**39** 项是 `*For(sessionKey, …)` 的 per-session 变体(§6;其中 `engineNamespaceKeyFor` 是命名巧合 —— 参数是 baseUrl 不是 sessionKey,见域 14)。
|
|
127
127
|
|
|
128
|
-
### 2b. 域图(16 域,逐域计数之和 =
|
|
128
|
+
### 2b. 域图(16 域,逐域计数之和 = 767)
|
|
129
129
|
|
|
130
130
|
| # | 域 | 名数 | 承重导出 | 用途 | 实现锚 |
|
|
131
131
|
|---|---|---|---|---|---|
|
|
132
132
|
| 1 | **适配内核(下行主链)** | 33 | `adapt` · `createWireToCcAdapter` · `runStream` · `eventToSdkMessage` · `terminalToSdkResult` · `turnUsageToModelUsage` · `isRunStreamActive` · `ADAPTER_DIVERGENCES` | 引擎 SSE `AgentEvent` → 端要渲的**双面输出**:transcript(`SDKMessage`)+ chrome(瞬态 `ChromeEvent`)。**本包存在的理由** | `src/adapt.ts`、`src/adapt/{arms,wireShapes,panelTasks}.ts`(经 `adapt.ts` 再导出)、`src/adapter/runStream.ts`、`src/adapter/downstream/*`、`src/adapter/types.ts` |
|
|
133
133
|
| 2 | **seam 公共契约** | 2(其余为 type-only) | `CHROME_ARMS` · `deriveTranscriptId` | 公共词汇 + **id 确定性不变量**(同一条流重放 ⇒ 同一串 id)。`CHROME_ARMS` = 端「我要消费哪些 chrome 臂」的对照清单 | `src/seam.ts` |
|
|
134
|
-
| 3 | **HITL 决断卡链**(§4/§5 主战场) |
|
|
134
|
+
| 3 | **HITL 决断卡链**(§4/§5 主战场) | 121 | `makeHitlCanUseTool` · `HitlBridge` · `findPendingForTask` · `HitlSafetyError` · `bridgeAskUserQuestionGates` · `surfaceToolApprovalFrameAndRespond` / `surfaceFsApprovalAndDecide` · `readToolApprovalRespondAck` · `installApprovalCardPort(For)` · `installHitlHostSurface(For)` · `armPlanReviewApproval` · `reopenPlanReviewCard` · `decidePlanReview` · `startApprovalsFeed` · `pendingRowIsOwnedByThisSession` · `approvalCallKey`/`liveFrameCallKey`/`planReviewQuestionId` · `registerArmedGateFor`/`wasGateArmedFor`/`clearArmedGateFor` · `waitForGateArmed(For)`/`onGateArmed(For)`/`gateArmedWaitMs`(#244 F1 呈现回执事件源) · `planReviewArmedKey(For)`/`notePlanReviewAnswered(For)`/`notePlanReviewAnsweredIfDecisive(For)`(A-024.4 plan 呈现分代) · `toolEndOutputText` · `isAskTool` · `waitForParkRowBirth` · `classifyAskParkRows` / `askParkRowArm` / `classifyAskParkChainFailure` · `readDecisionNoteAudit` / `decisionNoteAuditLine` · `resumeRunningOptions` / `resumeChoiceFromLabels` · `persistedRulesLaneAvailable`/`persistedRulesGovernanceAvailable` · `classifyRulesFailure` · `listAllPersistedRules` · `classifySkippedReason` · `readRulePersistOutcome`(#244 F2:persist-ack 读口与 `readToolApprovalRespondAck` 合成一处) · `parseLocalAllowRule`(durable 腿本地落规则窄化骨架,谓词经 `LocalAllowRuleDeps` 注入) · `DecideTransportRetryExhaustedError`(Inkglow-1085 P0a:decide 出站瞬断重试耗尽的 typed 判别 —— HitlBridge 内建单次退避重试,耗尽走重呈臂不判死 turn;端一般只消费行为,不需要 instanceof) | suspended→decide→resume 环。🔴 **D-1 两元组 verbatim 回显**是字节级断言的安全不变量,端**不许重实现它的任何一段**。🔴 键空间边界(web [C1] d3 拦截):`gateIdentity` 四常量两函数只覆盖 HITL questionId/callKey 空间;seat 的 `TOOL_PERMISSION_REQUEST_ID_DOMAINS`(`plan:` 等)是另一键空间,**两者绝不合并**(合并=座位校验器静默拒全部 plan-review 卡) | `src/hitl/hitlBridge.ts`、`toolApprovalWire.ts`、`askGateWire.ts`、`planReviewWire.ts`、`hitlHostSurface.ts`、`gateIdentity.ts`、`armedGateRegistry.ts`、`parkOwnership.ts`、`parkResolver.ts`、`approvalsFeed.ts`、`frameRouter.ts`(**只挑名导出** `toolEndOutputText`/`ENGINE_ABORT_TOOL_RESULT`/`isAskTool`/`HITL_REJECT_MESSAGE`)、`parkRowBirthWait.ts`、`approvalDecisionNoteAudit.ts`、`askParkRowRouting.ts`、`resumeRunningCard.ts`(#265 上收的判定层)、`persistedRulesWire.ts`、`localAllowRule.ts`(#244 F2 规则侧) |
|
|
135
135
|
| 4 | **子代 wire + 面板侧信道台账** | 82 | `tailEngineSubagent` · `installSubagentActivitySink` · `installSubagentTailMetaSink`(#280 件2:tail meta 帧发布口,`contentFrames` 判别位载体)· `stopEngineTask` + `classifyTaskStopConflict` · `fetchEngineSubagentReport` · `steerEngineSubagent`(0.32.0 未发布 #280 件A:additive 第三参 `childTaskId` —— 端有行上下文时**应当**传,传了就走「台账优先 / 缺席即诚实缺席 + `noteBgOwnerAbsence` 留痕」的 Q3 口径,与 tail·taskOutput·subagentOutput 三腿同姿势、与孪生 resume 腿共用同一个 `resolveOwnerRunId` 判据;**不传**则逐字维持旧行为=回落在飞 run)· `resumeSettledSubagent` + `resolveSubagentResumeContext` + `resolveOwnerRunId` + `classifySubagentResumeFailure` + `subagentResumeAvailable`(#242 批 2 A-028.7:resume 判定半场上收,与 steer 孪生同居;取址三态 = 台账有行用行值 / 指名了行但台账缺席则**诚实缺席绝不回落在飞 run** / 没指名行才回落。出路文案归端)· `recordSubagentOwnerFromProgress` + `getBgParentRunOwner`(A-028.6:「子代 → 宿主 run」**单表**,宿主 run 必须由持 stream-local 值的调用方显式传入,包内绝不从 `activeEngineRunId()` 推断)· `noteBgOwnerAbsence`(#242 批 3 [4000] Q3=B:tail/taskOutput·taskStop/subagentOutput 三腿台账缺席即诚实缺席**绝不回落在飞 run**,缺席 warn 留痕每 (腿,taskId) 一条)· `clearBgTerminalFacts`(#242 批 3 扫码修:复活=新周期,旧周期终态事实作废——fleetLedger 复活两腿按尾段清账,factsAccepted 方向核不再拿上周期终态当先例)· `auditRetainWithoutWake`([4000] Q5:引擎宣示 `subagentResume` + 本端在付 `retainSubagentSessions` + 端未实现 `wakeSubagent` ⇒ 响亮一条;`CLIENT_VERBS.wakeSubagent` 维持 fail-soft)· `subscribeSubagentContent` · `subscribeEngineAgentPanel` · `publishQuestionFrame` / `respondToQuestion` | 驱动与观测委派子代;经 module 级台账喂活体 agent/task 面板。全部**能力位 gate**(§5b) | `src/subagent/*.ts`、`src/subagentContentStore.ts`、`src/engineAgentPanelStore.ts`、`src/engineInlineTaskStats.ts`、`src/engineToolLabelStore.ts`、`src/liveQuestionStore.ts` |
|
|
136
136
|
| 5 | **fleet 投影** | 46 | `createFleetLedger` · `projectTasks` · `projectWorkflows` · `projectFleetAgentRows` · `readEngineActiveBgTasks` · `FLEET_TASK_VIEW_KEYS` · `escapeDisplayControlChars`(不可见字符可见化,行标签/描述消毒的共享底座)· `wireCycleSeq` / `wireRetiredBy`(0.38.0 提货补投的 #261 §2 两位:代际号 = SendMessage 复活即 +1,**缺席 ≠ 第一代**;`retiredBy` 在场 = 这条终态是对账腿从 durable run 行投影出来的、**不是**发布方亲报 —— 幽灵行与正常收尾唯一的 wire 判据。两位都只在场才落键) | 老 `fleetClient` 那一刀的成品:**帧体归库、连接归端** —— 端持 SSE 连接,库做行投影 + 保留台账 | `src/fleet/fleetProjection.ts`、`src/fleet/fleetLedger.ts`、`src/fleetAgentPanelProjection.ts`、`src/fleetTaskDesc.ts` |
|
|
137
137
|
| 6 | **请求装配(上行唯一构造口)** | 8 | `buildTaskRequest` · `REQUEST_FIELD_MATRIX` · `unregisteredRequestKeys` · `applyLiveRequestDefaults` · `taskNotificationToPrintFrame` | 两条车道(`interactive`/`print`)出站请求的**唯一**构造器;`unregisteredRequestKeys` 是可执行门 —— 端偷带一个未登记键上 wire 就红 | `src/request/taskRequest.ts`、`src/request/printNotification.ts` |
|
|
@@ -144,7 +144,7 @@ SDK 核对「本包 import 的每个值级符号仍然导出」「`TaskStats.cos
|
|
|
144
144
|
| 13 | **座位 IPC 契约** | 33 | `LOCAL_SESSIONS_SPEC` · `SEAT_METHOD_NAMES` · `SEAT_EVENT_TYPES` · `isLocalSessionEvent` · `isToolPermissionRequest` · `toolPermissionRequestId` · `SEAT_VALIDATOR_KEY_COVERAGE` | desktop↔web 座位 IPC 契约的**单一真源**(此前两边各一份、名字零重合 ⇒ 编译器永远不会告诉你它们漂了)。🔴 加 verb 忘了加 `LOCAL_SESSIONS_SPEC` **不报错**:preload 不注册 channel、渲染端读到 `undefined` | `src/seatContract.ts`(**零 import**,纯类型 + 常量 + 纯谓词) |
|
|
145
145
|
| 14 | **宿主端口与会话槽** | 26 | `installHost` · `installHostFor` · `hostPortMisses(For)` · `DEFAULT_SESSION_KEY` · `hostEnv` · `unrefTimer` · `parseLocaleTag` / `pickUiLanguage`(#244 F4 族D A-028.20:locale tag 手术单源 + UI 语言判定;与 `resolveRegionHint` 双出口成文 —— 语言偏好域 en/zh ≠ 地址可达域 cn/intl/unknown,`zh-Hant` 前者 zh 后者 intl 是设计)· `engineNamespaceKeyFor` / `mergeSessionMapRecord` / `mergeEngineEntry`(A-028.12:会话 id 映射单一键形 + merge 判定;存储经 `SessionMapStorePort` 归端 —— cli 文件锁/原子写,web localStorage)| 进程/端级装配层(settings/fs/queue/timers/session/log/probe),与 per-turn 的 `AdapterContext` **分层**。头注的判定规则:**这个能力每 turn 都会变吗?** 会 ⇒ `ctx`;不会 ⇒ `installHost` | `src/host.ts`、`src/hostEnv.ts`、`src/sessionSlot.ts`、`src/unrefTimer.ts`、`src/env/{localeGeo,localeTag,uiLanguage}.ts`、`src/sessionMap.ts` |
|
|
146
146
|
| 15 | **控制面与传输** | 73 | `ControlRouter`(+ `ControlSafetyError`)· `makeEngineWireClient` + `resolveWireAuth` · `installEngineWireTarget` · `diagnoseSseIdleTear` / `isSseIdleError` · `attemptActiveRunSelfHeal` + `activeRunBusySignal` + `activeRunSelfHealRow` / `activeRunBusyHeadlessRow` · `kickEngineCapsProbe` / `engineCapTrue` / `invalidateEngineCaps(baseUrl, probe?)`(#307 S25:引擎温切后的 caps 生产失效口 —— kick 自带幂等闸,同 baseUrl 重启后不显式失效就永远读到旧引擎那一版能力位;调用方 = 壳的 respawn/restartEngine。🔴 **推荐两参形**:第二参给替代探测则「推进代际 + 注册新探测」在同一同步块内完成,失效与下一次 kick 之间那个「等待者读到未判」的窗按构造不存在;单参形保留给「只丢缓存、这一刻没有替代探测」的调用方,那种情形下读到未判是诚实结局) · `mapBrainStatusToRetry` · `waitForClaimRelease` + `CLAIM_RELEASED_STATES` / `CLAIM_HELD_STATES` · `atMostOnceFailureClass` / `readSteerDelivery` · `clearRunningChoiceOffer`(Inkglow-1085 P0b①:「Do nothing」登记的清口 —— 端的「重新打开操作菜单」入口;登记在场时 attemptActiveRunSelfHeal 不整卡重弹,not-parked 结局带 `alreadyOffered: true` 判别位,端据此降级渲一行)· `INTERACTIVE_WAY_OUT`(默认出路串单源)· `normalizeWirePrincipal`(A-028.10:principal 在场性 trim 原语 —— 全空白=缺席不发头,engineWireTarget 两臂/makeEngineWireClient/壳 livePrincipal 同尺)· `classifyTurnWireError` / `isWireTransportError` / `isPreStreamDrainingReject` / `isResumeAtRejection` / `drainingRetryDelayMs` / `scenarioDenyFromError` + `WIRE_NETWORK_ERROR_PATTERN`(A-028.11/.13:turn 错误分型判定半场,人话文案与渲染归端) | 上行通道的**监管**半场(submit / steer / kill / 队列命令定序)+ 传输构造、caps 探测、SSE 断流分诊、**409 active-run 自愈** | `src/controlRouter.ts`、`steering.ts`、`sseIdleTriage.ts`、`retryStatus.ts`、`diagnostics.ts`、`engineWireSdk.ts`、`engineWireTarget.ts`、`src/principalWire.ts`、`src/wireErrorTriage.ts`、`engineSessionParam.ts`、`engineCapsCache.ts`、`liveInitToolFace.ts`、`adapter/activeRunSelfHeal.ts` |
|
|
147
|
-
| 16 | **引擎词汇表与包自检** |
|
|
147
|
+
| 16 | **引擎词汇表与包自检** | 48 | `CONFIG_REFUSAL_CODES` / `isConfigRefusalCode` · `STOP_CONFLICT_CODES` · `isInterruptedToolEndCode` · `isRewindFamilyCode` · `CLIENT_VERBS` · `compensationSplitViolations` · `DELEGATION_CAP_CODES` / `isDelegationCapCode` / `DELEGATION_CONCURRENCY_CAP` / `DELEGATION_SESSION_CAP`(0.38.0 #318 件④:core 5.48.0 design/323 委派席位到限**两码,处置不对称禁合并** —— 并发帽=**可等**(兄弟结束即有位)/ 会话累计帽=**等也没用**(这条会话的配额用尽))· `CONFIG_DELEGATION_ENTRY_CAPS`(同批入 `CONFIG_REFUSAL_CODES` 识别表)· `delegationCapDispositionOf` / `MCP_SERVER_REVOKED`(0.39.0 载体到货消费件:core 5.50.0 补 `{ error: code, code }` 孪生拼法后两码真上 `tool_end.errorCode`,0.38.0「先立词不落消费分支」的已知局限自此解除;处置轴 `wait-for-slot` / `reuse-existing-or-await-reap` 机器可读(累计帽=retained-window 帐,行回收配额即回,处置=SendMessage 复用,**非**「换会话/永久耗尽」——0.38.0 段该句系勘误),未知 `delegation.*` 码 ⇒ `undefined`;`mcp.server_revoked` = 操作员 mid-session 吊销 server 后的工具面本地闸(被吊销的 server **名**今天不过 wire 境:detail.server 是进程内位,抬升腿只 lift code——归因渲染候 core 补 typed detail,已点名);载体门 = engine-vocab G3 腿锚 core dist 铸点) | 三端分臂共用的**去字面化** `errorCode` 词表(病根正是三端各抄一份字面);编译期 verb 闭合门;搬迁补偿登记表 | `src/engineErrorCodes.ts`(计数以 `scripts/public-export-baseline.json` 为准,别手抄;A-028.11/.13 补 `DRAINING_ERROR_CODE`/`SCENARIO_NOT_ALLOWED_ERROR_CODE`/`RESUME_AT_ERROR_CODE_PREFIX`;#318 件④ 补 `delegation.*` 族四位 + `config.delegation_entry_caps`;0.39.0 补三新码消费件三位)、`src/classifierVerdictWire.ts`、`src/compensations.ts`、`src/clientSlice.ts` |
|
|
148
148
|
|
|
149
149
|
🔴 **`engineErrorCodes` 的开集纪律**(该文件头注逐字):这些 `ReadonlySet` / 前缀谓词一律是**识别表**,
|
|
150
150
|
回答的是「我认不认得这个码」,**绝不是**「合法码只有这些」。消费点 `switch` **必须留 `default`**,
|
|
@@ -304,6 +304,100 @@ lane 归属改用 id 形状 / `workflowRunId` 启发式判(`src/adapt/arms.ts`)
|
|
|
304
304
|
7.38 到)。**对本包与端零影响** —— 正因为消费面按开集写,白名单是 server 的投递判定,不是消费判据。
|
|
305
305
|
已按接入文档宪法回报 server。
|
|
306
306
|
|
|
307
|
+
### 3z. 🆕 `_sema_collateral_abort` —— 连坐 abort 机读位(0.40.0,#324 / [4907])
|
|
308
|
+
|
|
309
|
+
**病形**:同 turn 多个 call 在飞 + 一个撞 gate ⇒ 引擎对**整批**在飞 call 铸同一串
|
|
310
|
+
`Operation aborted`。本包 HITL 桥的 HOLD 表按 `isGatedToolEnd`(名字腿 ∪ abort 标记腿)
|
|
311
|
+
把它们**全部**收进同一张表,任一 flush 出口一次倾泻 ⇒ 端上满屏同文红行,而其中只有一条是
|
|
312
|
+
用户刚决断的那个 call,其余是**连坐**的旁观 call。
|
|
313
|
+
|
|
314
|
+
**本版做的事**(additive,`isError` / `output` / 帧序 / 帧数一律不动):
|
|
315
|
+
|
|
316
|
+
| 位置 | 行为 |
|
|
317
|
+
|---|---|
|
|
318
|
+
| `gateLedger.noteParkGate(...)` / `noteGateSubject(callId)` | 登记「本批那张 park」与「它决断出的主角」。判据只收 **park** 与 wire **身份**,绝不收工具名、也不收 `tool_approval` 帧 |
|
|
319
|
+
| `gateLedger.flushHeld()` | 在**这一拍**求出身:已知不是主角的帧 stamp `_sema_collateral_abort: true`。**一帧不丢**的不变量不变 —— 丢帧的后果是永久假排队(dim 圆点等不到结果行),比多渲一行更坏 |
|
|
320
|
+
| `eventToSdkMessage` 的 `case 'tool_end'` | 严格 `true` 才原样上内部 `tool_end_result` 臂;缺席不铸键 |
|
|
321
|
+
|
|
322
|
+
**判别子为什么在 flush 当拍求值(而不是入表当拍)**:durable park 腿的帧序是
|
|
323
|
+
`tool_start → tool_end(毒化) → done{suspended}` —— **gate 身份晚于毒化帧到达**。入表那一拍包层
|
|
324
|
+
还不知道谁是主角,任何判词都是猜的。按工具名猜(「名字腿认得 = 可能是主角」)双向都错:一等
|
|
325
|
+
`kind==='tool_approval'` gate 的主角(名字腿认不得的 toolName,如 `WebFetch`)被判成连坐 ——
|
|
326
|
+
**假阳打在主角上**;同族兄弟(两个 `Bash` 只有一个撞 gate)两个都被判成主角 —— 连坐帧拿不到位。
|
|
327
|
+
五个 flush 出口**全部**晚于 park 被看见,所以判词搬到那一拍才有真判据。
|
|
328
|
+
|
|
329
|
+
**判别子只认 park 供证 —— 归属必须可结构性证明**。判别子真正要回答的是「**这一批** abort 帧
|
|
330
|
+
属于哪一张 gate」,而 wire 上**没有任何位**做这个关联,包层能算的都是推断。四轮异源对抗复审的
|
|
331
|
+
定谳:只有 **park** 具备结构性归属 —— `flushHeld` 的出口就长在那张 park 自己的决断/回退路径上
|
|
332
|
+
(`parkResolver` fail-soft / 决断成功后的续流放行 / 终帧),「这一批是这张 park 的 abort 批」是
|
|
333
|
+
结构事实,不是猜的。
|
|
334
|
+
|
|
335
|
+
判据构成(**全部批级**,一批一套):
|
|
336
|
+
1. **本批恰好一张 park**(硬门)。零张 ⇒ 归属无从证明;两张以上 ⇒ 两次 gate 的 abort 混进同一张
|
|
337
|
+
扣留表,谁属谁无解。两种情形一律**整批不标**。
|
|
338
|
+
· durable **重放同一张 park** 不算新的一张 —— 判据是「自上次登记以来有没有**新的 call** 进过
|
|
339
|
+
扣留表」(按 call 不按帧:re-attach 会把仍被扣留的毒化帧连同 park 一起重放)。
|
|
340
|
+
🔴 走这条去重分支时**一个字节都不写**:该判据证明得了「这一批的组成没变」,证明**不了**
|
|
341
|
+
「这张 park 就是上一张」—— 一张真的新 park 同样可以零毒化帧。顺手刷新族属就等于让一张与
|
|
342
|
+
这批帧无关的 gate 改写本批判据。真是重放时族属本就相同,不写零损失。
|
|
343
|
+
· ask park 臂同样要登记:它自己用不到兜底腿,但它是本批的第二张 park,漏登会让上一张 fs park
|
|
344
|
+
的判据被拿来给这一批派判词(连 ask 主角自己都会被 stamp)。
|
|
345
|
+
2. **主角 = 本批(扣留帧 ∪ 本批已出批的帧)里唯一属该族的 call**;该族 = 这张 park 的 gate
|
|
346
|
+
**本体** `toolName` 所属的 fs 写 / shell 执行族(准入证;族外 park 不发证 ⇒ 整批不标)。
|
|
347
|
+
· 并上「已出批的帧」是因为决断成功那一下会把主角的毒化帧 `dropHeld` 掉;不并上就等于主角
|
|
348
|
+
「不在这一批」,整批判据当场失效。
|
|
349
|
+
· 前置:**每一条扣留帧的 `tool_start` 都得是本连接亲眼见过的**。族成员判据取自 tool_start 当拍
|
|
350
|
+
记的集合,没见过 start 的 call 在「唯一」这件事上是隐形的;而续流只消费 `runs.events` 的一段
|
|
351
|
+
(re-attach 从 `lastEventId` 起),主角的 start 完全可能落在这次连接之外 —— 那时表里剩下的
|
|
352
|
+
唯一族成员是**旁观者**。信息不全就不许声称「唯一」。
|
|
353
|
+
· 🔴 **pending 队列一概不参与判别**:`durable checkpointGate` 不带 callId,
|
|
354
|
+
`findPendingForTask` 取的是「同 taskId + 谓词命中的**第一行**」(谓词不命中时还退「任意行」)
|
|
355
|
+
—— 那是给**卡面渲染**用的宽口,**不是身份**。同族两行排队时它可能给出旁观者,拿它当主角
|
|
356
|
+
就会把真主角挤成「非主角」而 stamp(异源复审实测)。所以决断结果只用于 gate 生命周期
|
|
357
|
+
(`markDecided`/`dropHeld`),judgment 一步都不碰它。
|
|
358
|
+
|
|
359
|
+
批级判据的**退休点两处**:`flushHeld` drain 完、以及 `dropHeld` 之后**扣留表为空**那一下。
|
|
360
|
+
后者必须写成「无条件检查表空」而不是「摘中了才检查」—— 「park 决断成功但本批压根没有毒化帧」
|
|
361
|
+
的批每次 delete 都落空,写成后者就等于那种批**永远不退休**,判据活到下一批派错判词。
|
|
362
|
+
drain 那条拦的是「判完之后又来一批背后没有 park 的 abort 帧」。
|
|
363
|
+
|
|
364
|
+
🔴 **缺席语义(端必须按这条读)**:`_sema_collateral_abort` 缺席 = **「不是已知的连坐帧」**,它同时
|
|
365
|
+
覆盖两种情况 —— (a) 这一帧是 gate 主角,(b) **本包判别不出来**(判据没到手)。**缺席不等于
|
|
366
|
+
「这是主角」**,更不能据此渲「这条才是你刚决断的那个」。要断言主角身份,端自己按 `toolCallId`
|
|
367
|
+
与手上的审批卡对账,别拿本键的缺席反推([honest-absence-not-fabricated-zero])。
|
|
368
|
+
|
|
369
|
+
🔴 **端怎么读(唯一正道)**:从 **`tool_end_result` 臂**上读(`errorCode` / `settledBy` /
|
|
370
|
+
`approver` 同款位置),按 `toolCallId` 归集,自己决定呈现(建议:连坐簇按 repeated-error 族
|
|
371
|
+
软化折叠,头卡留 + 计数尾)。**判别取机读位,不猜文案** —— `Operation aborted` 这串是
|
|
372
|
+
引擎词汇,会随 core 版本变。键常量从本包取:`import { SEMA_COLLATERAL_ABORT_KEY }`
|
|
373
|
+
(单一真源,三端别各自手抄)。
|
|
374
|
+
|
|
375
|
+
🔴 **这一位刻意不在转录 `tool_result` block 上,也不在转录消息顶层**(两向都有常驻断言钉着,
|
|
376
|
+
pure 门 062⑥/⑦):
|
|
377
|
+
- **block 上不行** —— 转录卡会随 `/compact` 直发 provider,往 block 上加自铸键正是 0.5.0
|
|
378
|
+
`label` 那个真缺口的形状(**provider 400**);
|
|
379
|
+
- **消息顶层不行** —— 壳的 `createUserMessage` 是闭形重建,顶层键在到达渲染层之前就没了
|
|
380
|
+
(`_sema_degraded` 至今壳侧零消费面,根因就是这个),放那儿等于假接线。
|
|
381
|
+
|
|
382
|
+
⚠️ **已知局限一(在册,不当已办)**:**同族多兄弟分不出主角**。两个 `Bash` 同时在飞、其中一个
|
|
383
|
+
撞 gate 时,wire 上没有任何位能说「这两个里哪个撞的」—— `lastFsOrShellGatedCallId()` 指向**最后
|
|
384
|
+
一个** tool_start,pending 队列给的是「第一行」,两者都不是身份。**决断成功也不例外**(见判据②
|
|
385
|
+
最后一条)。此格按诚实缺席处置:**整表一个都不 stamp**,端侧行为逐字节退回本键出现之前。
|
|
386
|
+
🔴 出路在 server:`durable checkpointGate` 带上 `toolCallId`。常驻门 `F8-S3/S8/S33` 把这一格钉成
|
|
387
|
+
「全 ABSENT」—— server 补位后这些条**当场翻红**,逼下一棒把新身份接进判据,而不是让局限长住。
|
|
388
|
+
|
|
389
|
+
⚠️ **已知局限二(刻意为之)**:**同步 `tool_approval` 帧腿整条不标**。帧只证明「本 turn 出现过
|
|
390
|
+
一张 gate」,证明不了「**这一批** abort 帧属于它」—— 那张 gate 完全可能早已正常收口(零毒化帧
|
|
391
|
+
⇒ 零扣留表 ⇒ 一次 flush 都不会跑),它的证却会活到下一批去派判词。异源对抗复审四轮里,**全部**
|
|
392
|
+
「假阳打在 gate 主角身上」的残留路径都出自帧腿取证(旧 server 同批双主角 / 零 HOLD 审批证跨批 /
|
|
393
|
+
历史身份跨批)。取舍是明确的:**宁可少标,绝不误标主角**(误标主角 = 把用户真正该看的那条红行
|
|
394
|
+
折叠掉,比多渲 N 行更坏)。常驻门 `F8-S4/S5/S7/S11/S14/S17/S21/S22` 把这一格钉成「全 ABSENT」。
|
|
395
|
+
🔴 出路同样在 server:abort 批带 **gate 关联 id**(不只是主角 `toolCallId`),把归属从推断变成读数。
|
|
396
|
+
|
|
397
|
+
⚠️ **@core 对表位(在册,不当已办)**:core 5.51 的 `[DEFERRED]` / `gate.batch_halted` 词汇
|
|
398
|
+
([4826]③)到货时与本键**对表**。若 core 给出更强的官方形(例如 `errorCode` 上的专码),
|
|
399
|
+
端侧换锚、本 additive 键**保留兼容**,不塌方。在那之前本键是端能拿到的唯一机读判别子。
|
|
400
|
+
|
|
307
401
|
---
|
|
308
402
|
|
|
309
403
|
## §4 回执消费义务(ack contract)—— 🔴 本档重点
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sema-agent/client-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.40.0",
|
|
4
4
|
"description": "Client-side session runtime shared by every sema human client (TUI / web / desktop): sema wire frames (AgentEvent) -> CC session vocabulary (SDKMessage) with dual-plane output (transcript/chrome), deterministic transcript ids, lane discipline as a type, and the notification/dedup ledgers. Every CC-skin shape is collected here so the wire itself stays neutral. Blackboard [1832] design axioms; [1651]/[1652]/[1653] signed seam design. Renamed from @sema-agent/wire-cc-adapter (0.1.x).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@sema-agent/agent-types": "^0.2.0",
|
|
38
|
-
"@sema-agent/core": "^5.
|
|
38
|
+
"@sema-agent/core": "^5.50.0",
|
|
39
39
|
"@sema-agent/sdk": "^7.2.0",
|
|
40
40
|
"esbuild": "^0.27.4",
|
|
41
41
|
"typescript": "^6.0.2"
|