@sema-agent/client-core 0.59.2 → 0.60.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 +192 -0
- package/README.md +3 -2
- package/dist/adapt/toolCards.d.ts +2 -1
- package/dist/adapter/downstream/eventToSdkMessage.d.ts +24 -4
- package/dist/adapter/downstream/eventToSdkMessage.js +42 -70
- package/dist/adapter/downstream/terminalToSdkResult.d.ts +27 -22
- package/dist/adapter/downstream/terminalToSdkResult.js +47 -30
- package/dist/adapter/runStream.js +27 -11
- package/dist/engineCapsCache.d.ts +27 -0
- package/dist/engineCapsCache.js +29 -0
- package/dist/engineErrorCodes.d.ts +12 -0
- package/dist/engineErrorCodes.js +13 -0
- package/dist/gateOutcome.d.ts +157 -0
- package/dist/gateOutcome.js +181 -0
- package/dist/headlessReconnectWire.js +9 -2
- package/dist/hitl/askParkRowRouting.d.ts +2 -0
- package/dist/hitl/askParkRowRouting.js +17 -2
- package/dist/hitl/frameRouter.d.ts +2 -2
- package/dist/hitl/frameRouter.js +49 -35
- package/dist/hitl/hitlBridge.d.ts +49 -2
- package/dist/hitl/hitlBridge.js +22 -1
- package/dist/hitl/parkResolver.d.ts +3 -1
- package/dist/hitl/parkResolver.js +15 -5
- package/dist/hitl/planReviewWire.d.ts +8 -1
- package/dist/hitl/planReviewWire.js +18 -7
- package/dist/hitl/toolApprovalWire.d.ts +37 -3
- package/dist/hitl/toolApprovalWire.js +36 -9
- package/dist/index.d.ts +3 -0
- package/dist/index.js +7 -0
- package/dist/printToolResultFrame.d.ts +34 -49
- package/dist/resumeRefusalCopy.d.ts +12 -4
- package/dist/resumeRefusalCopy.js +15 -5
- package/dist/runTerminal.d.ts +194 -0
- package/dist/runTerminal.js +189 -0
- package/dist/sqlEngineCapability.d.ts +11 -1
- package/dist/sqlEngineCapability.js +13 -1
- package/dist/writeProtectionCapability.d.ts +142 -0
- package/dist/writeProtectionCapability.js +224 -0
- package/docs/INTEGRATION-CLIENTS.md +325 -11
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -49,6 +49,198 @@
|
|
|
49
49
|
> 挡住 ⇒ 本批把它机械化——④a0 对 `pending` 行**要求段头已是日期形**(`(未发布)` 直接红),阶段一
|
|
50
50
|
> commit 漏转在发布前就红,不再靠人记。
|
|
51
51
|
|
|
52
|
+
## 0.60.0(2026-09-08)
|
|
53
|
+
|
|
54
|
+
> 内容批(2026-09-08,隔离树交付):四件 —— ①`@sema-agent/sdk` **8.4.0 提货**(engine ≥7.64.0 的
|
|
55
|
+
> wire BREAKING 半场:`TaskResult.terminal` 四臂 / `tool_end.gate` / `McpFailure` 两词 /
|
|
56
|
+
> `writeProtection` 两键)、②**B-042** park 重开取件身份闸与行路由**同源**、③**B-037 候包两件**
|
|
57
|
+
> (无窗 `preflight_rejected` 第三句改自足措辞 / `FsApprovalOutcome.failed` 补 `errorCode`)、
|
|
58
|
+
> ④ `Capabilities` 93→**94** 逐键复核。**本段只记内容**(0.59.0 先例逐字):`package.json.version`
|
|
59
|
+
> 未动、README `Version` 行未动、`FROZEN` 未动 —— bump 与段头转日期形归**发包批**(阶段一义务见
|
|
60
|
+
> 本档头注;两阶段协议下 `pending` 行要求段头**已是日期形**,所以内容批插 `pending` 行必红)。
|
|
61
|
+
> peer 地板/devDep/README 地板句/门常量 `FLOOR` **四处必须同批**(`run-sdk-floor-test` ①c 互绑),
|
|
62
|
+
> 因此这一组抬版**在内容批里**,与 0.59.0 同形。
|
|
63
|
+
> 接入面详报见 `docs/INTEGRATION-CLIENTS.md` **§24**(每个新读器的签名/输入形/缺席语义 + 壳换装清单
|
|
64
|
+
> + 黑盒判据 + 门表)。
|
|
65
|
+
|
|
66
|
+
### 🔴 BREAKING(peer 地板 + 两个读面换判据 + 两条失败臂加必填位)
|
|
67
|
+
|
|
68
|
+
- **`@sema-agent/sdk` peer 地板 `>=8.3.0` → `>=8.4.0`**(devDep `^8.4.0` 同批;地板与 peer 声明由
|
|
69
|
+
`run-sdk-floor-test.mjs` **三位逐位等值**互绑)。四条硬理由逐条见该门的 `FLOOR` 注,摘要:
|
|
70
|
+
`TaskResult.terminal`(`TerminalCause` / `PausedCause`)/ `GateOutcome` 四型 /
|
|
71
|
+
`WriteProtectionCapability` / `McpDelivered`·`McpFailureKind` 在 <8.4.0 上都不存在。
|
|
72
|
+
🔴 **engine 7.63.0 及以前的 wire 不在本版支持窗内** —— 本批对退役的八个平面键与四个正交词
|
|
73
|
+
**不留兼容读**(理由见下一条:留下的那条读盘臂不是「旧引擎兼容」)。
|
|
74
|
+
- **终局读面换判据**:`done.result` / run row `result` 的终局不再从**八个平面键**(`status` /
|
|
75
|
+
`errorCode` / `errorMessage` / `blockedReason` / `checkpointToken` / `checkpointId` /
|
|
76
|
+
`checkpointGate` / `workspaceRestoreMode`)拼,改读**一条带标因由** `terminal`。包内单一读器
|
|
77
|
+
`readRunTerminal`(新公面),四个消费点(`doneToSdkResult` / `runStream` 可见性行 /
|
|
78
|
+
`frameRouter` 两条 park 臂 / `isPlanReviewPark`)全部换装。
|
|
79
|
+
🔴 **可观察行为变化(端要知道)**:因由形下「码属于失败」是**形状** ⇒ `-p` 投影里 park / blocked
|
|
80
|
+
终帧的 additive `errorCode` 位**恒缺席**(此前 `review.pending` 骑在 park 帧的平面 `errorCode` 上)。
|
|
81
|
+
扁平形回放的历史行仍带得动它。
|
|
82
|
+
- **两条决断腿的 `failed` 臂加必填 `stage`**(异源复审 ④,见下段):`FsApprovalOutcome.failed` 与
|
|
83
|
+
`parkResolver.GateOutcome.failed` 各多一个必填位;自己构造这两个形的宿主/测试要同批补。
|
|
84
|
+
- **`tool_end` 门记录换判据**:退役的 `settledBy` / `resolution` / `autoDenied` / `approver`
|
|
85
|
+
**四键全删无 alias**,继任者是一条记录 `gate: GateOutcome`。包内单一读器 `gateOutcomeOf`(新公面)
|
|
86
|
+
+ 四个判定谓词。内部臂 `tool_end_result` 上那四个键随之消失,新增 `gate` / `delivered` /
|
|
87
|
+
`gatedCallId` 三位。**端必须换装**(清单见 §24)。
|
|
88
|
+
|
|
89
|
+
### 件① sdk 8.4.0 提货 —— 终局因由与门记录两只新读器
|
|
90
|
+
|
|
91
|
+
- 🆕 **`src/runTerminal.ts`**:`readRunTerminal(result)` → 五臂读数(`completed` / `failed` /
|
|
92
|
+
`blocked` / `paused` / `unknown`)+ `plane`(`cause` | `flat`)。配套 `runTerminalCode` /
|
|
93
|
+
`runTerminalGateKind` / `runTerminalGateToolName` / `isReviewPark` / `REVIEW_PARK_GATE_KINDS`。
|
|
94
|
+
- 🔴 **两代字节一个读器,判别位 `"terminal" in result`**(上游钉的那一个)。第二代臂**不是**
|
|
95
|
+
「旧引擎兼容读」:它认的是同一台 ≥7.64.0 引擎真会送来的扁平字节,两个来源都有出处 ——
|
|
96
|
+
①**读盘面**(`GET /v1/runs/:id` 与 durable 账本回放对存储 blob **逐字透传、不补 `terminal`**,
|
|
97
|
+
所以跨 7.64.0 升级过的部署上升级前落盘的行仍是平面形);②**server 自己的 409 拒绝信封**
|
|
98
|
+
(它从来就是扁平的,这次形变没动它)。两源的投影处置完全相同,所以共用一个 `plane: 'flat'` 标。
|
|
99
|
+
- 🔴 **不认识的终态词绝不折成成功**:四臂之外的 `terminal.kind` / 平面形四词之外的 `status`
|
|
100
|
+
一律落 `unknown` 臂并**逐字带回那个词**([884]A1 / [909]B1 两次实锤事故的常驻结论)。整个读器
|
|
101
|
+
只有一条路返回 `null`:**连终态词都没有**(mock 车道 / 不带 status 的旧合成帧)—— 那一格维持
|
|
102
|
+
成功臂,与形变前逐字节同行为。
|
|
103
|
+
- 🔴 **不提供「因由 → 五词 status」的兼容投影**:同一个事实两个真源之后,消费端会分成两派,
|
|
104
|
+
而下一次形变时后者全部无声地错(sdk 顶注同规)。
|
|
105
|
+
- 🔴 `token` 席位永不上 wire(paused 因由与 `failed.nestedPause` 都不带恢复凭据),读器一个字节
|
|
106
|
+
都不碰它、也不给它留位。
|
|
107
|
+
- 🔴 **真机黑盒摸出的三条边界**(engine 7.64.0,test 三路独立构造 + server 回帖确认;每条在门里各带
|
|
108
|
+
一正控一负控)—— 「所有帧都带新键」那个假设在三处都不成立:
|
|
109
|
+
- **① park 短路帧上没有 `gate`**:审批窗走完(默认 300s)未决而走 park 路径时,`tool_end` 只有
|
|
110
|
+
`errorCode:"gate.parked"`。server 认定这是**契约设计**。⇒ 读器 tolerant(缺席不抛不猜),另出
|
|
111
|
+
第二形谓词 `isGateParkedToolEnd` + 单源常量 `GATE_PARKED_ERROR_CODE`;端判「这次调用没在这里
|
|
112
|
+
结算」必须**两形合读**,两形语义不同不许互相顶替(「窗走完拒了」vs「park 了还没人决」)。
|
|
113
|
+
- **② 同步提交腿的 park 体不是 `TaskResult`**:`POST /v1/tasks` 当场停在审批门上时,200 回体是
|
|
114
|
+
**server 自造**的 `{taskId, sessionId, status:"suspended"|"needs_review"}` —— 既没有退役的八个
|
|
115
|
+
平面键、也没有 `terminal`、**连门都不带**。⇒ 读器把那个 status 词原样带回
|
|
116
|
+
`RunTerminalPausedRead.flatStatus`,`isReviewPark` **两个来源合读**(门种 ∪ 扁平词);只读门种会让
|
|
117
|
+
整条同步 park 腿的 plan-review 卡不弹。`runStream` 那处对 `needs_review` 的读**保留**,它读的是
|
|
118
|
+
这只形、不是旧八键残留。缺席**绝不**折成 `completed`/`failed`;暂停中的 run 在 `GET /v1/runs/:id`
|
|
119
|
+
上连 `result` 都没有 ⇒ 读器答 `null`(端继续等,不报终局)。
|
|
120
|
+
- **③ `/decide` 体的 `settledBy` / `hostDecision` server 都不读**(结算方从认证主体算)。⇒ 包侧
|
|
121
|
+
decide 发送面**不许**带这两个键(带了是死字节),常驻门对三个 hitl 产物 grep 直证零命中;结算方
|
|
122
|
+
身份只从**响应/帧**的 `gate.settlement` 读。
|
|
123
|
+
- 🆕 **`src/gateOutcome.ts`**:`gateOutcomeOf(frame)` → `GateOutcomeView`
|
|
124
|
+
(`disposition` / `settlement?` / `origin?`)+ 谓词 `isDeniedGate` / `gateDeniedBy` /
|
|
125
|
+
`gateApprover` / `isApprovalWindowExpiredGate` / `isDenialLimitAutoDeniedGate` /
|
|
126
|
+
`isParkSlaExpiredGate` / `isHumanSettledGate`。
|
|
127
|
+
- 🔴 **判定归包**:「这次是不是审批窗自己走完的拒绝」旧形上是端各自拼的两键合取,而拼错的方式有
|
|
128
|
+
好几种且错法静默。三条窗词(`approval_window_expired` / `denial_limit_window_expired` /
|
|
129
|
+
`park_sla_expired`)**刻意不合并读** —— 旧形上它们共用一个 `settledBy:"timeout"`,合并读回去
|
|
130
|
+
等于把刚修好的判别力扔掉。
|
|
131
|
+
- 🔴 `disposition` 是**唯一承重座**(读不出 ⇒ 整只 `undefined`);`settlement` 的 `kind`/`who`
|
|
132
|
+
缺一即整只缺席(半只会被读成「结算过了只是没说是谁」)。三处词表一律**开集读**;
|
|
133
|
+
**不校上游的 I1–I4 四条不变量**(筛子属主是引擎,server 对坏记录整条不投)。
|
|
134
|
+
- ⚠️ **同名不同义**:本包 `hitl/parkResolver.ts` 另有一个导出型也叫 `GateOutcome`(决断腿结局),
|
|
135
|
+
与 sdk 的 `GateOutcome`(引擎的门记录)是两个语义面 ⇒ 本模块公面型一律带 `View` 后缀。
|
|
136
|
+
- **`wiring_manifest.mcp[]` 补 `delivered` / `httpStatus`**(S6-B):与既有五位同律 —— 逐键挑、
|
|
137
|
+
开集读、缺席不铸(`httpStatus` **缺席而不是 0**)。`errorCode` 的码族换代到 `McpFailureKind`
|
|
138
|
+
(退役的 `network` / `http_<status>` 两形作废),本包**照旧只判非空串**(词表属主在 core)。
|
|
139
|
+
`tool_end` 内部臂同批补 `delivered`。
|
|
140
|
+
- 🆕 **`src/writeProtectionCapability.ts`**(S-138):`Capabilities.writeProtection` 的**四态**窄读器
|
|
141
|
+
(`unobserved` / `not_reported` / `none` / `present`)+ caps tee + 换代失效口 + 唯一措辞铸点
|
|
142
|
+
`writeProtectionDoctorDetail`;operator 面 `diagnostics.wiring.writeProtection` 另有
|
|
143
|
+
`projectWriteProtectionPosture` / `writeProtectionPostureDetail`(带行内容)。与
|
|
144
|
+
`sqlEngineCapability` **同构同纪律**。
|
|
145
|
+
- 🔴 三位(`armed` / `rows` / `replaced`)**刻意不合成一个布尔**:合成之后「引擎缺省表在岗」与
|
|
146
|
+
「运维换了一张自己的表」同为 true。
|
|
147
|
+
- 🔴 `not_reported` **不是**「这台部署没有写保护表」—— 引擎侧**座位缺席时缺省表在岗**;四句话
|
|
148
|
+
互不相同也互不蕴含。
|
|
149
|
+
- 🔴 **最小披露**:逐行 name/kind 不上租户面(部署自定义行可能含内部路径名)。
|
|
150
|
+
- **`Capabilities` 93 → 94 逐键复核**:新增的唯一一位 `writeProtection` 登记为 `read`
|
|
151
|
+
(`run-engine-caps-ledger-test.mjs` 是逐元素等值门,上游加位当天红)。
|
|
152
|
+
|
|
153
|
+
### 件② B-042 —— park 重开取件的身份闸与行路由**同源**
|
|
154
|
+
|
|
155
|
+
- **病形** = [paired-mechanisms-must-share-premise]:三端把一行路由进工具门臂用的是
|
|
156
|
+
`askParkRowArm`(kind ∈ ask 门族 ∧ 不是 ask 工具 ⇒ `tool-gate`),而 `surfaceFsApprovalAndDecide`
|
|
157
|
+
取件时的**身份闸**是 `isToolApprovalGate`,只有两条腿(一等 `kind === 'tool_approval'`,或 fs 写 /
|
|
158
|
+
shell 的**名字腿**)。于是 `gateKind:"irreversible_ask"` + 工具名不在 fs 三件 + Bash 里的行
|
|
159
|
+
(**MCP 远端工具** / WebFetch / NotebookEdit / agent 工具 …)身份逐字命中却被族闸判出局 ⇒ 候选池
|
|
160
|
+
收紧到空 ⇒ `no_pending` ⇒ 卡永远重开不了。内建 fs/Bash 行只是**恰好**走了名字腿才没中招。
|
|
161
|
+
- **修** = 身份闸读**同一只**谓词:`askParkRowArm(row) === 'tool-gate'`。名字腿只留给 leg 2
|
|
162
|
+
「同族第一行」的 `matches`(那一腿本来就该按工具名挑)。外族门种(plan_review / resource_limit /
|
|
163
|
+
未来新词)由 `findPendingForTask` 上游的 `askParkForeignGateKind` 整族先滤,两道闸串联的语义与
|
|
164
|
+
修前逐字相同 —— 变的只是「工具臂认不认得非 fs/Bash 的工具名」。
|
|
165
|
+
- 门:`run-park-reopen-tool-identity-test.mjs`(新建)。
|
|
166
|
+
|
|
167
|
+
### 件③ B-037 候包两件
|
|
168
|
+
|
|
169
|
+
- **① 无窗 `preflight_rejected` 第三句改自足措辞**:此前写的是「The engine line **above** says
|
|
170
|
+
whether this token can still be redeemed」—— 它把答案外包给屏上另一行,而那一行只有 **turn 级**
|
|
171
|
+
报错路径才有;同一份文案在**决断路径**(审批卡 decide 的 409)上也照发,那条路上引擎原文按凭证
|
|
172
|
+
纪律根本不上屏 ⇒ 用户读到一句指向不存在的东西的指路话。改成只陈述本读面知道的事实:
|
|
173
|
+
`The engine supplied no wait, so this refusal does not say whether the token stays redeemable`。
|
|
174
|
+
🔴 判据锚在**性质**(每一句都自足)而不是「不等于那一个旧串」:门枚举了一族外包措辞
|
|
175
|
+
(`above` / `previous line` / …),新写的文案再引入一句外包话当场红。
|
|
176
|
+
- **② `FsApprovalOutcome.failed` 补 `errorCode`**(与 0.47.0 补 `currentPending` 同形):本类型把
|
|
177
|
+
typed 错**拍平成 `reason` 串**,于是只读 outcome 形的消费者对机读码全盲,要分辨拒绝族只能去正则
|
|
178
|
+
匹配那句拍平文案(里面嵌的是 `String(e)`)。新单源读口 `readWireErrorCode`(结构视图读,不
|
|
179
|
+
`instanceof`);ask 腿的 `GateOutcome.failed` **同批同形**改齐(同形存量清剿)。
|
|
180
|
+
🔴 与本包铸的 `code`(闭集取件判别位)是**两个命名空间,绝不合并**;🔴 **只搬码不搬正文**
|
|
181
|
+
(错误正文可能含凭据/内部路径,照旧只进 `reason` 的既有拍平位)。
|
|
182
|
+
|
|
183
|
+
### 🔴 异源对抗复审逼出的四条 —— 同批修根,各带正反控(红先绿后)
|
|
184
|
+
|
|
185
|
+
四条都是**复现出来的**反例,不是推演:
|
|
186
|
+
|
|
187
|
+
- **① 旧 caps 探测覆盖新写保护读数**(medium):`kickEngineCapsProbe` 的代际闸在 probe **返回之后**
|
|
188
|
+
才跑,而宿主的读面 tee 是在 probe **内部**落地的 ⇒ 一次慢的旧探测能在 `invalidateEngineCaps` +
|
|
189
|
+
新探测都走完之后把**上一台引擎**的读数写回来(屏上是一句肯定句)。修 = 两个 tee
|
|
190
|
+
(`noteEngineCapsForWriteProtection` / `noteEngineCapsForSqlEngine`,**同形存量一次改齐**)加
|
|
191
|
+
additive 第三参 `{ generation }` + 新公面读口 `engineCapsGeneration(baseUrl)`;不传 = 逐字节
|
|
192
|
+
同行为(additive 供给,不是强制门),端的换装行见 §24h 第 19 行。
|
|
193
|
+
- **② 因由座在场却读不出被洗成成功**(medium):`terminal: null` / `{}` / `[]` / `{kind:7}`(混合载体、
|
|
194
|
+
schema 漂移)此前返 `null`,消费点当成「连终态词都没有」而落**成功臂** —— 一条明确 park 着的 run
|
|
195
|
+
投影成空成功,正是 [884]A1 / [909]B1 两次事故的形状。修 = 这几形落 `unknown` 臂,
|
|
196
|
+
`RunTerminalRead.unknown.word` 改**可选**(缺席 = 那个词本身读不出,**不是**「没有终局」),
|
|
197
|
+
措辞说「读不出」而不编一个词。
|
|
198
|
+
- **③ ask 工具身份被门种压过**(medium):`gateKind:"irreversible_ask"` + `toolName:"AskUserQuestion"`
|
|
199
|
+
在门种早退里被判 tool-gate ⇒ 工具臂弹一张**没有问句**的卡、送出**不带 answer 的 approve**
|
|
200
|
+
(一次静默的错动作)。修 = `askParkRowArm` 把「toolName 明说是 ask 工具 ⇒ 问答臂」提到**最前**,
|
|
201
|
+
与 `frameRouter` 那条 park 分流同一个次序。**行为变化**:`tool_approval` / `irreversible_ask` 门下的
|
|
202
|
+
**ask 工具名**行从工具臂改到问答臂;非 ask 工具名一格未动(B-042 修根不受影响)。
|
|
203
|
+
- **④ 失败四类仍不结构可分**(medium):两条决断腿的 `failed` 把 typed 错拍平成一个 `reason` 串。
|
|
204
|
+
修 = `FsApprovalOutcome.failed` 与 `parkResolver.GateOutcome.failed` **同批**加**必填** `stage`
|
|
205
|
+
(`fetch` / `input` / `card` / `decide` / `orchestration`,单源 `HitlFailureStage`);fs 腿另加
|
|
206
|
+
`safetyCode`(本包安全停闭五词 `HitlSafetyCode`,ask 腿早有对应位)。
|
|
207
|
+
🔴 **只有 `stage === 'decide'` 代表「引擎那一头知道这次决断」**;三个码位是**三个命名空间**
|
|
208
|
+
(`code` 取件闭集 / `safetyCode` 本地安全停 / `errorCode` 引擎 wire 码),绝不合并。
|
|
209
|
+
|
|
210
|
+
### 新增公面导出
|
|
211
|
+
|
|
212
|
+
`readRunTerminal` · `runTerminalCode` · `runTerminalGateKind` · `runTerminalGateToolName` ·
|
|
213
|
+
`isReviewPark` · `REVIEW_PARK_GATE_KINDS` · 型 `RunTerminalRead` / `RunTerminalPause` /
|
|
214
|
+
`RunTerminalPausedRead` / `RunTerminalPlane` | `gateOutcomeOf` · `isDeniedGate` · `gateDeniedBy` · `gateApprover` ·
|
|
215
|
+
`isApprovalWindowExpiredGate` · `isDenialLimitAutoDeniedGate` · `isParkSlaExpiredGate` ·
|
|
216
|
+
`isHumanSettledGate` · `isGateParkedToolEnd` · `GATE_PARKED_ERROR_CODE` · 型 `GateOutcomeView` /
|
|
217
|
+
`GateDispositionView` / `SettlementView` / `SettlementWhoView` | `projectWriteProtectionCapability` · `noteEngineCapsForWriteProtection` ·
|
|
218
|
+
`observedWriteProtection` · `forgetWriteProtectionReading` · `writeProtectionDoctorDetail` ·
|
|
219
|
+
`projectWriteProtectionPosture` · `writeProtectionPostureDetail` ·
|
|
220
|
+
`__resetWriteProtectionReadingsForTests` · 型 `WriteProtectionReading` /
|
|
221
|
+
`WriteProtectionCapabilityView` / `WriteProtectionPostureView` / `WriteProtectedRowView` |
|
|
222
|
+
`readWireErrorCode` · `engineCapsGeneration` · 型 `HitlSafetyCode` / `HitlFailureStage`。
|
|
223
|
+
**零删除**(既有导出一个没动)。
|
|
224
|
+
|
|
225
|
+
### 已知局限(本版新增)
|
|
226
|
+
|
|
227
|
+
- **`hostDecision`(`/decide` 入参)零消费**:server 7.64.0 起 `/decide` 收
|
|
228
|
+
`hostDecision{decidedBy, approver?}` 而不再收 `settledBy`。sdk 8.4.0 的
|
|
229
|
+
`dist/resources/approvals.d.ts` **没有**声明这一位(与 8.3.0 逐字节相同),而本包对 decide 入参
|
|
230
|
+
**从来就零 stamp 那两个退役词** ⇒ 本批零受迫、也不自铸一个上游没定型的入参键。登记为上游候件。
|
|
231
|
+
- **`checkpointStore: "disabled"` / `engine_notice` cause `task_store_disabled`**:本包零消费点
|
|
232
|
+
(提交位与 notice 的 `detail` 都按开集原样透传),复核后**只登记不改码**。
|
|
233
|
+
⚠️ 真机确认:`TaskSpec.checkpointStore` 这个 **body 字段 server 未接线**(由部署侧配置决定)⇒
|
|
234
|
+
包侧只登记、**不投影发送**。
|
|
235
|
+
- **`LegacyPlaneTaskResult` 的 `x-legacy-replay-only` 标记**未被本包消费:判别位用的是
|
|
236
|
+
`"terminal" in result`(上游钉的那一个),不是那个标记。
|
|
237
|
+
- **决断链失败的第五类(卡口自己报失败 vs 没装卡口)仍在 `stage: 'card'` 里同形**:两者的出路不同
|
|
238
|
+
(前者是卡口实现的问题,后者是装配漏了),但本包对卡口只拿得到一个 `{kind:'failed', reason}`
|
|
239
|
+
——要分开得先给卡口端口一个结构化的失败形,那是端口契约的改动,不在本批射程。
|
|
240
|
+
- **旧 caps 探测覆盖新读数的兜底只到「供给」为止**:代际参数是 additive 的,端不传就仍有那条竞态。
|
|
241
|
+
做成必填会让每一个还没跟上的宿主当场把这一格读成空 —— 那比竞态更坏(竞态是罕见时序,必填是
|
|
242
|
+
确定性回归)。⇒ 端的换装行登记在 §24h 第 19 行,跟上之后这条限制自然消失。
|
|
243
|
+
|
|
52
244
|
## 0.59.2(2026-09-06)
|
|
53
245
|
|
|
54
246
|
- `sqlEngineDoctorDetail` 两句措辞订正(仅文案,四态与读数零变):`none` 不再断言「local file stores」这个因由 —— server 7.61.0 起 `sql:null` 同时覆盖「没配 SQL 后端」与「池初始化被拒」(wire 不可分),改为两种可能都点名并指向引擎日志(cli 1.0.102 异源复审 [medium]);`unobserved` 去掉「run /doctor inside the REPL」这句端命令(包不点名端命令;cli B-038 定位:REPL /doctor 是 skill 不渲此行)。三端消费该函数的 doctor 类面文案随包变,无需改码。
|
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.60.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
|
|
@@ -67,7 +67,7 @@ Renamed from **`@sema-agent/wire-cc-adapter`** (0.1.x, deprecated — see *Migra
|
|
|
67
67
|
against — the tables live upstream precisely so this package does not keep a second copy that can
|
|
68
68
|
fall behind. The browser bundle really bundles the SDK through (the portability guard would
|
|
69
69
|
exit 3 rather than quietly mark it external).
|
|
70
|
-
- The declared floor is `>=8.
|
|
70
|
+
- The declared floor is `>=8.4.0`, and it is *witnessed*: the guard checks that an actually
|
|
71
71
|
installed SDK at that line still exports every value-level symbol this package imports and still
|
|
72
72
|
declares `TaskStats.costMicroUsd` (the key `costOrNull` reads). A floor nobody ever ran is a
|
|
73
73
|
promise, not a contract.
|
|
@@ -236,6 +236,7 @@ public-surface guard checks that last one).
|
|
|
236
236
|
| `scripts/run-sdk-floor-test.mjs` | The SDK version floor — and, more to the point, that the *installed* type declarations still carry the keys this package reads |
|
|
237
237
|
| `scripts/run-engine-caps-ledger-test.mjs` | A per-key disposition ledger for `GET /v1/capabilities`. The SDK's `Capabilities` grew from 74 keys to 93 in one release and nothing on the board could see it: this package consumes that table through four synchronous readers, and *nineteen new positions arriving while the package does not move* is exactly the disease shape this repo keeps logging on other axes — the fact is already on the wire, the package boundary is the cell that swallows it, and no client can read it however they write their side. So the ledger is reconciled **element-wise against the SDK interface in both directions**: a key the SDK added with no ledger row is red (someone must classify it), and a row for a key the SDK removed is red too (a registration that no longer does anything). Each row then has to survive its own claim — a `read` row names the source file, and the **code** there (comments stripped) must really mention the key, because prose asserting an alignment is the classic way these guards go hollow; a `not_read` row must have **zero** read sites in the tree, so wiring one up while the ledger still says the package ignores it is red rather than invisible. The census behind those two directions recognises five call shapes, each of which really occurs here — a reader whose base argument carries its own parentheses, a direct `caps.<key>`, a narrowing cast, an own-property read helper, and a `*_CAP` constant — and proves it on fabricated samples first, since a census that recognises one shape reports "nothing here" for the other four. What the guard deliberately does **not** judge is whether a position *ought* to be read: that is a design call, and the ledger only pins that every capability was looked at once by a person and that what they wrote down does not contradict the code |
|
|
238
238
|
| `scripts/run-sql-engine-capability-test.mjs` | The SQL-posture read face and the four-state capability reader underneath it. One capability cell here carries **four different things**, and each one points an operator somewhere else: nothing has been observed yet in this process (a one-shot doctor run is always in that state), the response arrived but carries no such key (an older engine), the engine explicitly answered `null` — *this deployment has no SQL backend*, which is a **positive fact** rather than an absence — and a full reading. Fold any two together and the screen states something flatly, confidently, and wrongly, so every positive control here is paired with a control pointing the opposite way, and the four sentences the doctor row can print are checked to be pairwise distinct and non-implying. The reading itself is narrowed no tighter than the mint: `txnMode: null` is a **legal value** — two of the three engines always report it that way, and the upstream type note names reading it as "optimistic" as the error — so treating it as malformed would throw away the entire reading for ordinary deployments, which is the same disease this repo logged when a consumer's domain was narrower than the producer's. A response that cannot be parsed **clears** the cell rather than leaving the previous engine's answer in place, and a separate invalidation port exists for the case the generation latch cannot catch — a same-port respawn whose new probe never succeeded, where the stale reading would otherwise be answered as current fact. Untrusted values (the isolation string is read back from a database server variable) are sanitised and bounded before display, and the bound is applied **before** escaping so a visible escape never gets cut in half. Finally the export names are themselves a guard: the shell still carries a copy that is meant to go red on the package's same-named export and be swapped out, so renaming anything here would silently disarm that lock |
|
|
239
|
+
| `scripts/run-terminal-cause-projection-test.mjs` | The `7.64.0` wire reshape, projected. A run's ending stopped being eight parallel flat keys and became **one tagged cause** (`completed | failed | blocked | paused`), and a tool call's gate stopped being four orthogonal words and became **one record** (`disposition` / `settlement?` / `origin?`). Both are read in exactly one place in this package, and this guard pins them at **two levels**, because the dangerous seam is "the reader was updated, the consumer was not": each terminal arm is checked on the reader *and* on the `subtype` / `is_error` / `errors[]` the projector actually emits. Two properties carry most of the weight. First, a terminal word this reader does not know is **never** laundered into an empty success — it lands on an `unknown` arm carrying the word verbatim, while a payload with no terminal word at all (the mock lane) keeps the success arm exactly as before, which is the one and only case the reader answers `null`. Second, the three window words (`approval_window_expired`, `denial_limit_window_expired`, `park_sla_expired`) must each be told apart by a different predicate: the previous generation collapsed all three onto one `timeout`, and re-merging them would throw away the discrimination this reshape just restored. Two byte generations are read by one reader, keyed on the discriminator upstream nailed (`"terminal" in result`): the current cause form, and the **flat** form that a current engine still emits on two lanes — replayed persisted bytes, which the service passes through verbatim rather than back-filling, and the service's own rejection envelope. A cause-form payload that also carries stale flat keys must ignore them entirely: keeping one compatibility read is what gives a single fact two sources. The same file also pins the MCP delivery verdict and HTTP status riding the wiring manifest, the four-state write-protection reading (where three of the four states mean *cannot tell*, and none of them may be printed as "there is no table"), and the park-reopen fetch identity: that predicate is asserted through the **real entry point**, since the defect being fixed was precisely a call site wired to a different predicate than the one that routed the row there |
|
|
239
240
|
| `scripts/run-engine-vocab-floor-test.mjs` | Engine-mirrored vocabularies (structured card whitelist, self-reported tool face, control verbs, recogniser sets) against the *installed* `@sema-agent/core` |
|
|
240
241
|
| `scripts/run-limits-env-failloud-test.mjs` | `SEMA_HEADLESS_*` env-lane limits reject invalid values as loudly as the flag lane (no silent "no budget" runs) |
|
|
241
242
|
| `scripts/run-streamjson-timing-honesty-test.mjs` | Stream timing & terminal honesty ([2084]): held errored fs-write results release on model progress; a wall-clock stop maps to `error_during_execution` with a truthful salvage note; the synthetic API-error assistant row carries the `<synthetic>` in-message sentinel. Also ([2489], core 5.8.0): the run-limit `errorCode` -> CC subtype map is pinned code by code (`limits.max_{cost,turns,tokens,walltime}_exceeded`), token/wall-clock stops keep the text the engine already produced, and the `failed` event arm shares the one mapping point. The 5.7 dual-vocabulary legs retired with server 6.0.0 (which bundles core 5.8.0); four **retirement negative controls** stand in their place — the retired `status:'timeout'` and the retired codes must fall to the honest fallback subtype and must never drop back to an empty success, so putting any of them back turns the gate red |
|
|
@@ -37,7 +37,8 @@ export interface PendingToolUse {
|
|
|
37
37
|
*
|
|
38
38
|
* 🔴 本形**不是** `tool_end_result` 臂的镜像,是它的**关卡切片** —— 只收「铸这张 tool_result 卡真正
|
|
39
39
|
* 要读的位」。臂上另有若干**开集观察位**按设计**不进本形**:`errorCode`(core 5.9.0 W3)、
|
|
40
|
-
* `
|
|
40
|
+
* `gate`(整条门记录,engine ≥7.64.0 / sdk 8.4.0 —— 取代退役的四个正交词)、`delivered`
|
|
41
|
+
* (MCP 投递判词,core ≥7.6.0)、`gatedCallId`(core ≥5.55.0)。它们由
|
|
41
42
|
* `eventToSdkMessage` 的 `case 'tool_end'` 臂原样上臂、由**宿主/桥**直接从臂上读(壳 upstreamBridge、
|
|
42
43
|
* print 车道 {@link import('../printToolResultFrame.js').ToolEndResultArmLike}),卡台账一位都不消费。
|
|
43
44
|
* 往本形加一个没有落点的键 = 一句「关卡会用到它」的假话(声明与产物对不上,且没有任何门会响);
|
|
@@ -178,9 +178,14 @@ export interface WiringManifestAutoMode {
|
|
|
178
178
|
* 🔴 **`name` + `status` 是必需两座**(与 server 侧 `wiringManifestEventData` 的 `mcp` 臂同判据:
|
|
179
179
|
* `if (name === undefined || status === undefined) continue`)—— 一条既没有名字也没有状态的行
|
|
180
180
|
* 渲不出任何有用的话,而**坏一条只丢那一条**,绝不丢整张表(丢整表 = 用户以为「一台都没申报」)。
|
|
181
|
-
* 🔴 **`errorCode`
|
|
182
|
-
*
|
|
183
|
-
*
|
|
181
|
+
* 🔴 **`errorCode` 不是纯闭集**(core 7.6.0 换代:`MCP_FAILURE_CODES` 十词表退役,继任者是
|
|
182
|
+
* `McpFailureKind` 十词;**`network` 与 `http_<status>` 两种拼法一并作废** —— HTTP 状态从此走
|
|
183
|
+
* 结构位 {@link WiringManifestMcpEntry.httpStatus},不再编进码里)⇒ 本包**照旧既不枚举那十个词、
|
|
184
|
+
* 也不套形正则**(词的单一属主在 core;抄一份会把 core 加的新词吞成缺席),只判非空串。
|
|
185
|
+
* 消费端按具名词写的 `switch` **必须带 default 臂**。
|
|
186
|
+
* 🔴 **`delivered` 与 `errorCode` 合读才有判别力**(core 7.6.0 S6-B):同一个 `connection_closed`,
|
|
187
|
+
* `no` 可以直接重试(**可证**什么都没发出去)、`unknown` 必须先去查(请求**可能**已经执行了)。
|
|
188
|
+
* 这条判别力单看码拿不到,所以这一位非透传不可。
|
|
184
189
|
* 🔴 **`error` 自由文本上游就不投,本包更不铸**:它是这条面上唯一的**远端作者自由文本**,server
|
|
185
190
|
* 侧的裁定逐字是「进来会同时破本段『无自由文本 ⇒ 不脱敏』的段内不变量,和 core 把远端 MCP 错误
|
|
186
191
|
* 文本脱敏收敛成**一个**铸点的单铸律」。可操作的因由在 `errorCode`。
|
|
@@ -192,10 +197,25 @@ export interface WiringManifestMcpEntry {
|
|
|
192
197
|
status: string;
|
|
193
198
|
/** 声明方自述的层级标签(core 已 single-line + 长度封顶后逐字回显)。缺席 = 没报。 */
|
|
194
199
|
source?: string;
|
|
195
|
-
/** 失败因由的**机器码**(
|
|
200
|
+
/** 失败因由的**机器码**(core 7.6.0 `McpFailureKind` 十词,**按开集读**)。缺席 = 这条没失败,
|
|
201
|
+
* 或引擎没给码。 */
|
|
196
202
|
errorCode?: string;
|
|
197
203
|
/** 这台服务器挂上来的工具数(有限数)。缺席 = 没报,**不是** `0`。 */
|
|
198
204
|
toolCount?: number;
|
|
205
|
+
/**
|
|
206
|
+
* 请求**到没到**那台服务器(core 7.6.0 S6-B;`yes` / `no` / `unknown`,**按开集读**)。
|
|
207
|
+
* 🔴 与 {@link errorCode} **合读**(见投影函数顶注)。缺席 = 引擎没给这一位。
|
|
208
|
+
* ⚠️ `no` 说的是**调用方的工具调用**没发出去,**不**保证「那台服务器一个字节都没收到」。
|
|
209
|
+
*/
|
|
210
|
+
delivered?: string;
|
|
211
|
+
/**
|
|
212
|
+
* 端点答的那个 HTTP 状态(core 7.6.0 S6-B),**只**与 `errorCode === "http_status"` 同行
|
|
213
|
+
* (401/403 去重新授权、5xx 是那头挂了)。
|
|
214
|
+
* 🔴 **缺席而不是 0**:一个编出来的 `0` 会被读成「服务器答了状态码 0」这句不存在的话。
|
|
215
|
+
* ⚠️ 本层**不校**「只与 http_status 同行」那条配对:它是 core 的段内规矩,server 已按它铸;
|
|
216
|
+
* 包再校一遍只会在上游合法演进的当天把一个真读数判没(与 `errorCode` 的开集纪律同规)。
|
|
217
|
+
*/
|
|
218
|
+
httpStatus?: number;
|
|
199
219
|
}
|
|
200
220
|
/**
|
|
201
221
|
* CS-7 §2.7 — turn_end usage → CC `ModelUsage` (pinned name mapping;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { stamp, } from '../types.js';
|
|
2
2
|
import { turnUsageToModelUsage } from './turnUsageToModelUsage.js';
|
|
3
|
+
// 0.60.0(engine ≥7.64.0 / sdk 8.4.0):`tool_end.gate` 的三端共用窄读器(判定归包,端不许自拼)。
|
|
4
|
+
import { gateOutcomeOf } from '../../gateOutcome.js';
|
|
3
5
|
// #51: `stamp<T extends { uuid?: string; session_id?: string }>` — passing an
|
|
4
6
|
// arm-body object literal straight to `stamp` triggers a TS quirk: the
|
|
5
7
|
// literal gets excess-property-checked against the CONSTRAINT (which only
|
|
@@ -229,63 +231,33 @@ export function eventToSdkMessage(ev, ctx) {
|
|
|
229
231
|
// 绝不按识别表过滤(过滤 = 替引擎决定哪些原因配得上被看见)。判别用
|
|
230
232
|
// `engineErrorCodes.isInterruptedToolEndCode`,不要在消费点重新写字面比较。
|
|
231
233
|
const toolEndErrorCode = ev.errorCode;
|
|
232
|
-
// ──
|
|
233
|
-
//
|
|
234
|
-
//
|
|
235
|
-
//
|
|
236
|
-
//
|
|
237
|
-
//
|
|
238
|
-
//
|
|
239
|
-
//
|
|
240
|
-
//
|
|
241
|
-
//
|
|
242
|
-
//
|
|
243
|
-
//
|
|
244
|
-
//
|
|
245
|
-
|
|
246
|
-
//
|
|
247
|
-
//
|
|
248
|
-
//
|
|
249
|
-
//
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
//
|
|
253
|
-
|
|
254
|
-
//
|
|
255
|
-
//
|
|
256
|
-
//
|
|
257
|
-
//
|
|
258
|
-
|
|
259
|
-
// 是闭形白名单,`resolution` 在包边界被整段剥掉 ⇒ 消费端**缺一臂**,只能退到锚 core 散文
|
|
260
|
-
// (文案一改就漂)。[1947] `toolCallId` / [2942] `governanceForced` / #263 两键 / #324 机读位
|
|
261
|
-
// 之后的**同款病形第五例**。
|
|
262
|
-
// 🔴 **给消费端的判据是正面匹配**(异源复审 [medium] 采纳):
|
|
263
|
-
// `settledBy === 'timeout' && resolution === 'window_expired'`;**绝不**写
|
|
264
|
-
// `resolution !== 'approver_contract'` —— 那个不等式对**缺席**(旧引擎)与**任何未来新码**
|
|
265
|
-
// 都为真,会把「不知道是怎么拒的」折成「窗口自然结束」。
|
|
266
|
-
// 🔴 **开集防御读**(与上面三键同姿势):类型面虽是九词闭集,词表属主仍是引擎 —— 窄读成枚举
|
|
267
|
-
// 会在加员当天把一个合法值判没。非空串即原样透传,绝不按识别表过滤、绝不 trim/截断/改写。
|
|
268
|
-
// 🔴 **缺席不带语义,不许反推**(core 头注逐字):每一次真正执行了的调用、每一次 policy/hook
|
|
269
|
-
// 直拒、以及 durable/decide 腿的结算(它们带自己的 settledBy/reason)都**不带**这一位。
|
|
270
|
-
// 缺席 ≠「不是拒绝」也 ≠「人拒的」⇒ 缺席就不铸键(绝不折成 null / 空串)。
|
|
271
|
-
const toolEndResolution = ev.resolution;
|
|
272
|
-
// ── S-125⑧(0.59.0):`autoDenied` —— 这次 deny **是引擎的窗自己拒的**,不是人拒的 ──────
|
|
273
|
-
// 出处 = server ≥7.57.0 `trace/project.js` 的 `toolEndEventData`(条件 stamp
|
|
274
|
-
// `ev.autoDenied === true ? { autoDenied: true } : {}`),源头是 core 7.4.0 auto 模式
|
|
275
|
-
// 分类器的**限额回落窗**:那张必须真人批的卡(`tool_approval.denialLimitFallback` +
|
|
276
|
-
// `requiresRealApproval` 孪生键)在 `autoDenyAfterMs` 走完之后由**引擎**判 deny,同批盖
|
|
277
|
-
// `settledBy:"timeout"` / `resolution:"window_expired"` / 本位。
|
|
278
|
-
// 🔴 **为什么单靠既有两键判不出来**(这一位非补不可的理由):`settledBy:"timeout"` 覆盖的是
|
|
279
|
-
// **一切**审批窗到期(含普通 ask 的 TTL),`resolution:"window_expired"` 同理 —— 两者都
|
|
280
|
-
// 答不了「这一次到期是**自动拒**收的场,还是 park 了等人」。消费面要渲的那句话
|
|
281
|
-
// (「自动拒(限额回落)」vs「已转后台候批」)正卡在这一格上。
|
|
282
|
-
// 🔴 **严格 `true` 才上臂**(与 `_sema_collateral_abort` / `governanceForced` 同族纪律):
|
|
283
|
-
// 机读位是二值的,「在场但不是 true」没有语义,折成在场会让消费端把一个坏形当成肯定。
|
|
284
|
-
// 🔴 **缺席不带语义,不许反推**:缺席同时覆盖「不是自动拒」「老引擎(<7.57.0)不报」
|
|
285
|
-
// 「这次根本没走审批」三形 ⇒ 缺席**禁**读成「是人拒的」。
|
|
286
|
-
// 🔴 **不据它自铸第二只定时器/第二张资格表**:窗的执行全在引擎(上游 `denialLimitFallback`
|
|
287
|
-
// 顶注的同一条禁令),本位只是**事后**的判别位。
|
|
288
|
-
const toolEndAutoDenied = ev.autoDenied;
|
|
234
|
+
// ── 0.60.0(engine ≥7.64.0 / sdk 8.4.0):四个正交词 → 一条门记录 `tool_end.gate` ──────────
|
|
235
|
+
// 退役的 `settledBy` / `resolution` / `autoDenied` / `approver` **四键全删,无 alias**(上游
|
|
236
|
+
// 类型面 BREAKING)。继任者是一条记录:`disposition`(放行 / 被哪一**层**拒)+ `settlement?`
|
|
237
|
+
// (这次消费掉的等待怎么结束的)+ `origin?`(谁问的),后两位**同在同缺**。
|
|
238
|
+
// 🔴 **窄读单源在包里**(`gateOutcome.gateOutcomeOf`),本臂只负责把成形的那只**原样上臂** ——
|
|
239
|
+
// 此前四个词各自在这里做一次 `typeof === 'string'` 窄化,而端还要再自拼一个两键合取才能
|
|
240
|
+
// 回答「这次是不是审批窗自己走完的」。判定归包之后端调谓词,不再自拼(见 gateOutcome.ts)。
|
|
241
|
+
// 🔴 **不成形就不铸键**(绝不折成 null / 空对象):缺席在上游是**四种不可分辨的成因**
|
|
242
|
+
// (门没看见这次调用 / 延后重发 / reconcile 捡回的孤儿 / 记录过不了引擎的筛而 server
|
|
243
|
+
// 整条不投),一律退回 `isError` + 文案 —— 铸一个空壳会让端把「不知道」读成「放行过」。
|
|
244
|
+
// 🔴 **UNTRUSTED-for-display**:`settlement.who.approver` 与 `settlement.note` 是部署侧审批
|
|
245
|
+
// 通道自报/拒批人自写的自由文本(转录不是认证),只渲染,绝不回喂模型/工具入参,更不许
|
|
246
|
+
// 当鉴权判据。
|
|
247
|
+
const toolEndGate = gateOutcomeOf(ev);
|
|
248
|
+
// ── core ≥7.6.0(S6-B):这次 **MCP** 失败**到没到那台服务器** ─────────────────────────────
|
|
249
|
+
// 🔴 与 {@link errorCode} **合读**才有意义:同一个 `connection_closed`,`no` 可以直接重试
|
|
250
|
+
// (什么都没发出去)、`unknown` 必须先去查(请求可能已经执行了)。带写副作用的工具在
|
|
251
|
+
// `unknown` 上必须先核实再重试 —— 这条判别力单看码拿不到,所以这一位非透传不可。
|
|
252
|
+
// 🔴 **不在本层收窄成三词**:词表属主是引擎(与 `settledBy` 那一代的开集纪律逐字同规),
|
|
253
|
+
// 抄一份会把新词吞成缺席。非空串即原样透传。
|
|
254
|
+
// 🔴 **缺席不带语义**:每一次执行成功的调用、每一次非 MCP 失败都不带它。
|
|
255
|
+
const toolEndDelivered = ev.delivered;
|
|
256
|
+
// ── core ≥5.55.0(#333):耐久 park 正扣着**哪一个** tool call 的 id ────────────────────────
|
|
257
|
+
// 引擎从已提交 checkpoint 的 pendingAction 直读(**禁由工具自报**)。只挂在 park 污染帧上;
|
|
258
|
+
// tool-less park(resource_limit / plan_review / task_done)**整键缺席**,契约逐字
|
|
259
|
+
// "ABSENT, never guessed" —— 缺席不铸键、也不猜。
|
|
260
|
+
const toolEndGatedCallId = ev.gatedCallId;
|
|
289
261
|
// ── #324 半场(0.40.0):连坐 abort 机读位 `_sema_collateral_abort`([4907] 裁定)──
|
|
290
262
|
// 出处**不是引擎**,是本包自己的 HITL 桥:`gateLedger.flushHeld` 对「出身 = collateral」的
|
|
291
263
|
// 扣留帧 stamp(见 `SEMA_COLLATERAL_ABORT_KEY` 头注)。桥在本臂**上游**(宿主先用
|
|
@@ -315,19 +287,16 @@ export function eventToSdkMessage(ev, ctx) {
|
|
|
315
287
|
...(ev.output !== undefined ? { output: ev.output } : {}),
|
|
316
288
|
...(structured !== undefined ? { structured } : {}),
|
|
317
289
|
...(ev.truncated !== undefined ? { truncated: ev.truncated } : {}),
|
|
318
|
-
//
|
|
319
|
-
...(
|
|
320
|
-
|
|
290
|
+
// 0.60.0:整条门记录(不成形不铸键;顶部大段头注是判据本体)。
|
|
291
|
+
...(toolEndGate !== undefined ? { gate: toolEndGate } : {}),
|
|
292
|
+
// S6-B:MCP 投递判词(开集、缺席不铸、在场原样)。
|
|
293
|
+
...(typeof toolEndDelivered === 'string' && toolEndDelivered.length > 0
|
|
294
|
+
? { delivered: toolEndDelivered }
|
|
321
295
|
: {}),
|
|
322
|
-
|
|
323
|
-
|
|
296
|
+
// #333:耐久 park 正扣着哪个 call(缺席不铸,绝不猜)。
|
|
297
|
+
...(typeof toolEndGatedCallId === 'string' && toolEndGatedCallId.length > 0
|
|
298
|
+
? { gatedCallId: toolEndGatedCallId }
|
|
324
299
|
: {}),
|
|
325
|
-
// A-D2:拒绝臂分类(开集、缺席不铸、在场原样;判据本体是上方那段头注)。
|
|
326
|
-
...(typeof toolEndResolution === 'string' && toolEndResolution.length > 0
|
|
327
|
-
? { resolution: toolEndResolution }
|
|
328
|
-
: {}),
|
|
329
|
-
// S-125⑧:自动拒判别位(**严格 true** 才上臂;见上方头注)。
|
|
330
|
-
...(toolEndAutoDenied === true ? { autoDenied: true } : {}),
|
|
331
300
|
// #324:连坐 abort 机读位(严格 true 才上臂;见上方头注)。
|
|
332
301
|
...(collateralAbort === true ? { _sema_collateral_abort: true } : {}),
|
|
333
302
|
...(ev.eventId !== undefined ? { eventId: ev.eventId } : {}),
|
|
@@ -862,8 +831,8 @@ function textEndProjection(ev, ctx) {
|
|
|
862
831
|
* (「我读不出来」不是「我知道是零」)。这与下面「逐条独立」并不矛盾:只要**还有幸存者**,
|
|
863
832
|
* 半张表仍是真读数,坏行照旧只丢自己。
|
|
864
833
|
* 🔴 **逐条独立**:一条坏行只丢自己(与 server 侧 `continue` 同判据),绝不因为一条坏行丢整表。
|
|
865
|
-
* 🔴 **逐键挑,禁 spread**:core
|
|
866
|
-
* 一个像 `error` 那样的自由文本面。
|
|
834
|
+
* 🔴 **逐键挑,禁 spread**:core 往条目上加新键时必须由人显式处置 —— 而它下一个加的很可能又是
|
|
835
|
+
* 一个像 `error` 那样的自由文本面。(0.60.0 按此显式处置了 S6-B 的 `delivered` / `httpStatus`。)
|
|
867
836
|
* ⚠️ `toolCount` 按**有限数**判(`Number.isFinite`),不按真值判:`0` 是合法读数(连上了、零工具),
|
|
868
837
|
* 折成缺席会让「连上了但没工具」与「没报」在消费端同形。
|
|
869
838
|
*/
|
|
@@ -885,6 +854,9 @@ function projectMcpSection(raw) {
|
|
|
885
854
|
...(typeof r.source === 'string' && r.source.length > 0 ? { source: r.source } : {}),
|
|
886
855
|
...(typeof r.errorCode === 'string' && r.errorCode.length > 0 ? { errorCode: r.errorCode } : {}),
|
|
887
856
|
...(typeof r.toolCount === 'number' && Number.isFinite(r.toolCount) ? { toolCount: r.toolCount } : {}),
|
|
857
|
+
// S6-B(0.60.0):两位与既有五位同律 —— 逐键挑、开集读、缺席不铸。
|
|
858
|
+
...(typeof r.delivered === 'string' && r.delivered.length > 0 ? { delivered: r.delivered } : {}),
|
|
859
|
+
...(typeof r.httpStatus === 'number' && Number.isFinite(r.httpStatus) ? { httpStatus: r.httpStatus } : {}),
|
|
888
860
|
});
|
|
889
861
|
}
|
|
890
862
|
// 🔴 见顶注:`raw.length === 0` 是**正面事实**(照铸 `[]`);非空却零行幸存 = 读不出来 ⇒ 段缺席。
|
|
@@ -11,21 +11,21 @@
|
|
|
11
11
|
* flatten(TaskStats); modelUsage ⇐ stats.modelUsage (per-model split).
|
|
12
12
|
* DROP CC stop_reason / duration_api_ms / structured_output /
|
|
13
13
|
* fast_mode_state (contract 02 §2.10).
|
|
14
|
-
* Budget gate is a RESULT branch, not a throw: a `done` whose
|
|
15
|
-
*
|
|
16
|
-
* (08 CS-10) — surfaced via
|
|
14
|
+
* Budget gate is a RESULT branch, not a throw: a `done` whose terminal
|
|
15
|
+
* cause is a failure carrying a budget code still settles as a result
|
|
16
|
+
* (08 CS-10) — surfaced via `terminal.failed.code` upstream, not here.
|
|
17
17
|
* failed : flatten CC's 4 SDKResultError subtypes + errors[] into the single
|
|
18
|
-
* {
|
|
19
|
-
*
|
|
20
|
-
* park : done
|
|
18
|
+
* {code, message} pair. A user-cancelled run settles here with
|
|
19
|
+
* code:"cancelled" (08 CS-11).
|
|
20
|
+
* park : done 帧的 `terminal.kind === "paused"`(HITL/plan-review park)在无
|
|
21
21
|
* overlay 消费面(-p / 非 REPL)也走 SDKResultError 臂 —— 绝不投影成
|
|
22
22
|
* 空成功([884]A1,见下方分支注释)。
|
|
23
23
|
*
|
|
24
|
-
* ──
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
24
|
+
* ── 终态分流([909]B1,2026-07-16;core 5.8.0 词表迁移 [2489],2026-08-04;因由形 0.60.0)──────
|
|
25
|
+
* 🔴 **0.60.0(engine ≥7.64.0 / sdk 8.4.0)换判据**:终局不再是并列的八个平面键,而是一条**带标
|
|
26
|
+
* 因由** `result.terminal`(四臂)。本文件一个 `status` 字面都不再比较 —— 读法单源在
|
|
27
|
+
* `runTerminal.readRunTerminal`,它同时认**扁平形**的两个来源(升级前落盘、读盘面逐字回放的历史行;
|
|
28
|
+
* server 自己的 409 拒绝信封),并把四臂之外的词一律归到 `unknown` 臂。分流表因此按**因由臂**排。
|
|
29
29
|
*
|
|
30
30
|
* ✅ **单代读面**(退役批,2026-08-04):core 5.8.0 是 BREAKING 大车(`status:'timeout'` 退役、
|
|
31
31
|
* 四个到限码全部改名),交付时点壳的引擎还捆 core 5.7,故读面曾同时认新旧两代,每处钉一个可 grep
|
|
@@ -34,9 +34,9 @@
|
|
|
34
34
|
* (记号与登记门同批清空),读面与写面(limitsWire.ts)重新同为单一新形。旧形不再被认走这件事由
|
|
35
35
|
* `scripts/run-streamjson-timing-honesty-test.mjs` 的四条**退役负控**常驻看守(加回来就红)。
|
|
36
36
|
*
|
|
37
|
-
*
|
|
37
|
+
* terminal.kind code → subtype is_error
|
|
38
38
|
* ────────────────────────────────────────────────────────────────────────────────────────────
|
|
39
|
-
* completed —
|
|
39
|
+
* completed —(结构上写不出码) → 'success' false
|
|
40
40
|
* failed limits.max_cost_exceeded → 'error_max_budget_usd' true
|
|
41
41
|
* failed limits.max_turns_exceeded → 'error_max_turns' true
|
|
42
42
|
* failed limits.max_tokens_exceeded → 'error_during_execution' true
|
|
@@ -53,16 +53,21 @@
|
|
|
53
53
|
* 兜底词。真实语义靠 errors[] 文案 + errorCode 透传辨认,不变。)
|
|
54
54
|
* failed output.invalid → 'error_max_structured_output_retries' true
|
|
55
55
|
* failed 其余(含 cancelled/conflict…) → 'error_during_execution' true
|
|
56
|
-
* blocked —(engine 只给
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
* 非 completed
|
|
56
|
+
* blocked —(engine 只给 reason) → 'error_during_execution' true
|
|
57
|
+
* paused —(结构上写不出码;扁平形回放的历史 → 'error_during_execution' true([884]A1)
|
|
58
|
+
* 行仍可能带 review.pending) 措辞按门种分「复核 / 交互作答」两句
|
|
59
|
+
* unknown — → 'error_during_execution' true(防御:
|
|
60
|
+
* 非 completed 的终局一律≠空成功;errors[] 里如实报出那个词的字面。**因由座在场
|
|
61
|
+
* 却整个读不出**(坏形/混合载体)也落这一臂,措辞改说「读不出」而不是编一个词)
|
|
62
|
+
* 〈整个缺席〉 — → 'success' false
|
|
63
|
+
* (mock 车道 / 不带终态词的旧合成帧;读器返 null,零行为变化)
|
|
61
64
|
*
|
|
62
|
-
* errorCode
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
65
|
+
* errorCode 透传:引擎的码骑 additive seam 字段 `errorCode`(CC schema 无此字段——与 success 臂的
|
|
66
|
+
* `model` 同款超集姿势),集成面可精确分流(limits.max_tokens_exceeded vs cancelled …)。
|
|
67
|
+
* 🔴 因由形下「码属于失败」是**形状**:paused / blocked 上引擎写不出码 ⇒ 这两臂的 `errorCode`
|
|
68
|
+
* 从 0.60.0 起恒缺席(扁平形回放的历史行仍带得动它)。截断 salvage:写出窗兑现的 r.result(非空)
|
|
69
|
+
* 骑 additive `result` 字段——CC error 帧无 result,但把引擎已救回的最终文本静默丢弃对 -p 消费者
|
|
70
|
+
* 是净损失。
|
|
66
71
|
*
|
|
67
72
|
* 成本取数 = `TaskStats.costMicroUsd`(整数 micro-USD 单轨,SDK 1.0.0 / server 1.319.0 /
|
|
68
73
|
* core 2.0.0 起;legacy float `costUsd` 已删,见 costOrNull 头注)。零成本 is AMBIGUOUS
|