@sema-agent/client-core 0.36.0 → 0.38.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 +313 -0
- package/README.md +2 -2
- package/dist/adapt/arms.js +43 -0
- package/dist/adapt.d.ts +1 -1
- package/dist/adapt.js +2 -0
- package/dist/adapter/activeRunSelfHeal.d.ts +35 -2
- package/dist/adapter/activeRunSelfHeal.js +157 -4
- package/dist/adapter/downstream/eventToSdkMessage.js +99 -0
- package/dist/adapter/runStream.d.ts +14 -1
- package/dist/adapter/runStream.js +4 -0
- package/dist/engineCapsCache.d.ts +81 -3
- package/dist/engineCapsCache.js +183 -15
- package/dist/engineErrorCodes.d.ts +20 -0
- package/dist/engineErrorCodes.js +44 -0
- package/dist/fleet/fleetProjection.d.ts +43 -1
- package/dist/fleet/fleetProjection.js +53 -3
- package/dist/fleetTaskDesc.d.ts +5 -1
- package/dist/fleetTaskDesc.js +39 -2
- package/dist/hitl/armedGateRegistry.js +11 -3
- package/dist/hitl/hitlBridge.d.ts +20 -0
- package/dist/hitl/hitlBridge.js +215 -12
- package/dist/hitl/parkResolver.d.ts +1 -0
- package/dist/hitl/parkResolver.js +22 -2
- package/dist/hitl/toolApprovalWire.d.ts +41 -6
- package/dist/hitl/toolApprovalWire.js +40 -6
- package/dist/index.d.ts +1 -0
- package/dist/index.js +4 -0
- package/dist/model/modelSupplyRules.d.ts +102 -0
- package/dist/model/modelSupplyRules.js +149 -0
- package/dist/model/providerPresets.js +68 -12
- package/dist/request/taskRequest.js +11 -11
- package/dist/retryStatus.d.ts +38 -3
- package/dist/retryStatus.js +15 -5
- package/dist/seam.d.ts +48 -1
- package/dist/seam.js +7 -0
- package/dist/subagent/engineSubagentResume.d.ts +18 -0
- package/dist/subagent/engineSubagentResume.js +7 -0
- package/dist/toolResult.d.ts +8 -0
- package/dist/toolResult.js +15 -0
- package/docs/INTEGRATION-CLIENTS.md +69 -20
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -15,6 +15,319 @@
|
|
|
15
15
|
>
|
|
16
16
|
> 🔴 **互链**(web [C166]⑦):各版「已知局限」段只记**该版新增**;接入面已知局限的完整台账在
|
|
17
17
|
> `docs/INTEGRATION-CLIENTS.md` §6e/§7 —— **只读其一会漏**,两处都过。
|
|
18
|
+
>
|
|
19
|
+
> 🔴 **勘误(#307 双扫,2026-08-19,永久记录 —— 见下方为什么不能退休)**:`## 0.36.0` 段标题的
|
|
20
|
+
> `(未发布)` 是发布批的操作失误 —— 0.36.0 **已经发布**(releasedAt=npm gitHead `b165f3f`,
|
|
21
|
+
> registry 在架),阶段二转正提交 `e56563c` 只补了 `FROZEN` 账(releasedAt/sha256、删
|
|
22
|
+
> pending),漏改标题。该段**已冻结**(`b165f3f` 上的字节被 ④a 逐字锁定,`FROZEN` 账不许改
|
|
23
|
+
> 既有行)⇒ 标题**不回改、且永远不会被改**(`b165f3f` 那个 commit 的字节是历史,任何未来提交
|
|
24
|
+
> 都改不到它)⇒ 这条勘误与门侧窄豁免(`run-integration-doc-freshness-test.mjs` ④b
|
|
25
|
+
> `KNOWN_HEADING_ERRATA`,登记 `version: '0.36.0', releasedAt: 'b165f3f'`)**都是永久的**,不是
|
|
26
|
+
> 「下一版删掉」的临时态(codex 复审 finding①:那样写会让豁免一删,门在**任何**后续版本上
|
|
27
|
+
> 都会重新对这个永久冻结的标题判红,退休条件不可能被满足)。门侧核验两件事把这条勘误钉死、
|
|
28
|
+
> 不许悄悄漂:豁免登记的 `releasedAt` 与 `FROZEN` 账上 0.36.0 那一行逐字相等;本段(点名版本号
|
|
29
|
+
> `0.36.0` + 关键字「勘误」)必须还在这份头注里 —— 删掉本段而不同批把门侧豁免一起处理,门当场红。
|
|
30
|
+
|
|
31
|
+
## 0.38.0(2026-08-21)
|
|
32
|
+
|
|
33
|
+
**#318 四件合批 + SDK 7.2.0 提货跟车。行为面五条**:一条新投影臂(additive)、一条超时预算收窄
|
|
34
|
+
(口径换代)、一条分层遮蔽真修(修前那条分支恒不可达)、两条**可分辨读口/分类**的加细。**
|
|
35
|
+
|
|
36
|
+
> 📌 **公面基线 753 → 764**(npm 上的 `0.37.0` 是 753)。11 个新导出全部 **additive**,零 BREAKING:
|
|
37
|
+
> `engineCapState`(+ 类型 `EngineCapState`)· `resolveEntryVision` / `computeDeleteBlockers` /
|
|
38
|
+
> `computeDeleteWarnings`(+ 四个具名类型)· `CONFIG_DELEGATION_ENTRY_CAPS` /
|
|
39
|
+
> `DELEGATION_CONCURRENCY_CAP` / `DELEGATION_SESSION_CAP` / `DELEGATION_CAP_CODES` /
|
|
40
|
+
> `isDelegationCapCode` · `wireCycleSeq` / `wireRetiredBy`。
|
|
41
|
+
> 🔴 **peer 地板抬到 `>=7.2.0`**(见下「SDK 7.2.0 提货」);装 <7.2.0 SDK 的端提货前先抬依赖。
|
|
42
|
+
|
|
43
|
+
- **🆕 件① `engine_notice` 投影臂(additive,server ≥7.36 / #310;黑板 [4679] 发布、[4682] cli 认领)**:
|
|
44
|
+
引擎的结构化通告里被 server 判为面向**本会话终端用户**的那一小撮,现在有了投影口 ——
|
|
45
|
+
`eventToSdkMessage` → 中性内部臂 `engine_notice` → `adapt()` → chrome 臂
|
|
46
|
+
`{ kind:'engine_notice', code, message, detail, sessionId?, ts?, eventId? }`。**不铸 transcript 行**
|
|
47
|
+
(通告是披露不是转录物,硬铸一行就是替引擎编一句它没说过的话)。
|
|
48
|
+
🔴 **开集是本件的承重设计,不是风格**:本层**一个码都不硬编** —— 没有识别表、没有 switch、
|
|
49
|
+
没有「已知才投」。server 的白名单会随 core 码册增长(起步三码 → core 5.47/5.48 的
|
|
50
|
+
`NOTICE_AUDIENCE` 到货后 hold 三码入册),任何在客户端复制一份白名单的实现都会在下一次
|
|
51
|
+
core 加码的当天开始静默丢帧。同理**不读能力位**:帧到了就投影(A-022「到帧即服务」),
|
|
52
|
+
拿一个探测位去 gate 一条**已经到手的事实**,只会在探测未判/失败时把真事实丢掉。
|
|
53
|
+
`detail` **整对象逐字透传**(禁挑键):逐码不同且开集,挑键 = 新码的事实在本层静默蒸发。
|
|
54
|
+
消费纪律五条(按 code+detail 渲 / message 仅 fallback / 未知码不许丢 / durable 重放幂等 /
|
|
55
|
+
`harvest_quarantined` 的 `moved` 与 `escalated` **不可相减**)写在 `seam.ts` 臂注释与
|
|
56
|
+
`docs/INTEGRATION-CLIENTS.md` §3f。**壳渲染半场不在本批**(cli 0.38.0 提货时做)。
|
|
57
|
+
🔴 **重放身份两个键(codex 对抗复审 [medium] 采纳,当窗修)**:首版只带 `eventId`,于是 body 不带
|
|
58
|
+
它时留给端的唯一去重口是 `code+ts` —— 而 `ts` 是 **server 观察时刻(ms)**,同毫秒同码的两条真通告
|
|
59
|
+
会被折成一条、跨重连的同一条又可能重复。而 SDK 的 SSE parser **本来就把 durable `id:`
|
|
60
|
+
(= `task_event.seq`)stamp 到 `ev.id` 上**(`dist/sse.js`),本包也早有规范访问口
|
|
61
|
+
(`adapter/types.eventSeq`)—— 有稳定序号却不带 = 本层自己把可靠性降级了。现补 `eventSeq` 位,
|
|
62
|
+
幂等序 = `eventId` > `eventSeq` > `code+ts`。🔴 **两键绝不合并**
|
|
63
|
+
([same-name-different-meaning-crosses-layers]:全局身份 vs per-task 序号)。
|
|
64
|
+
⚠️ **如实登记两条**(2026-08-21 亲验,接入文档宪法):① `engine_notice` **尚未进已发布 SDK 的
|
|
65
|
+
`AgentEvent` union** —— sdk 仓 `3d6aebc` 已写,但 npm `@sema-agent/sdk@7.2.0` 真 tarball 的 `dist/`
|
|
66
|
+
全树零命中(同批的 `FleetTaskRow.cycleSeq` 在场,证明抽检会说话)。故按 `workflow_complete` /
|
|
67
|
+
`human_input` 当年的先例走 **raw 预分派**,并留自退休钉:臂一进 union,`assertNeverArm` 编译期
|
|
68
|
+
真红,逼下一棒搬进 switch。② server 的 `ASSISTANT-WIRE-CONTRACT` 附录 D.3 仍写「起步白名单三码」,
|
|
69
|
+
而 server main 的 `ENGINE_NOTICE_WIRE_CODES` 已是六码 —— **对本包与端零影响**(正因为消费面按
|
|
70
|
+
开集写),已按宪法回报 server。
|
|
71
|
+
- **🔴 件② `decide` 超时重试总窗收窄:10 分钟 → 90 秒(口径换代,不是调参)**。
|
|
72
|
+
旧值按 [4664] 的**长调用**口径开:legacy 任务级 decide 在响应前同步跑整条 resume(模型往返无上限),
|
|
73
|
+
60s 帽结构性必炸,所以超时是**常态**。server #316([4687],随 7.37.0 发车)把 200 体从终局形改成
|
|
74
|
+
**受理回执**(受理点在 core `resumeStream` 解析后,一切会变成拒绝的判定仍同步发生;实测受理即回
|
|
75
|
+
≈23ms)⇒ **超时从常态变真异常**,总窗随之收窄。
|
|
76
|
+
🔴 **新值锚在「真正决定发数的量」上而不是拍一个整数**:SDK 的 per-attempt 帽(60s)本包不可配,
|
|
77
|
+
而每一发超时类失败本身就吃满一个帽 ⇒ 实际发数由「总窗 ÷ 帽」决定且量化很粗 —— 窗 ≤1 帽 = **零重试**
|
|
78
|
+
(重试环变死结构)、>2 帽 = 3 发起步一路回到分钟级、(1 帽, 2 帽] = **恰一次重试**。取
|
|
79
|
+
`60_000 × 1.5`(**写成「帽 × 系数」而不是裸 90000**,SDK 改帽时推导自动跟手),落在区间中部而不
|
|
80
|
+
贴边界。可预算最坏墙钟 ≈121s。**重试环结构一字未动**(超时臂仍走窗判),[4675] 的「绝不造第二层
|
|
81
|
+
节奏叠乘」照旧成立 —— 本批没有新增任何计时器/退避层。
|
|
82
|
+
🔴 **两条残余同步形如实登记**(收窄不等于长调用消失了,[4687] 逐字):终局形仍存在于 ①pre-7.37
|
|
83
|
+
的 server、②≥7.37 但没有 durable run 行可跟的部署。本包是三端共用件,故重试环保留、总窗不设 0;
|
|
84
|
+
这两形上窗尽的代价是**重呈臂**(同一张卡重交用户)而不是把 turn 判死。
|
|
85
|
+
🔴 **「至少重试一次」改由发数保证(codex 对抗复审 [medium] 采纳,当窗修)**:per-attempt 帽是
|
|
86
|
+
**宿主构造 client 时**定的(本桥吃注入 client,`HitlClientLike` 根本不暴露 `timeoutMs`)⇒
|
|
87
|
+
「总窗 ÷ 帽 = 发数」这条推导只在 SDK **缺省值**上成立,不能当本共用件的性质 —— 一个 120s client
|
|
88
|
+
的宿主在首发超时那一刻 elapsed 已 ≥ 窗,**一次重试都拿不到**,而上面那两条残余同步形恰恰最需要
|
|
89
|
+
它。故补第二个界 `DECIDE_TIMEOUT_MIN_ATTEMPTS = 2`,终止条件改为**合取**(发数达标 ∧ 窗尽)。
|
|
90
|
+
⚠️ 这**不是** [4675] 的「第二层节奏叠乘」:零新增定时器/退避层,退避仍是同一条 backoff 链,
|
|
91
|
+
只是同一个循环上的第二个终止条件。三种 client 配置都有界且都拿得到那次重试:120s ⇒ 2 发/~240s、
|
|
92
|
+
缺省 60s ⇒ 2 发/~121s、30s ⇒ 3 发/~92s。常驻套件同批加 F6-b4(窗=0 且每发都超时 ⇒ 必须恰在
|
|
93
|
+
第 2 发后耗尽),F6-b3 的期望值随行为改动同批更新并写明数字变化的来由。
|
|
94
|
+
- **🔴 件③(a)`inferFamily` 的 `vision` 分层遮蔽修 —— 一条恒不可达的分支**(cli [4752] 自领缺口1)。
|
|
95
|
+
病:`vision` 位只写在 `modelFamilies.json` 上,而那张表只有**第④层**读;可任何真实的 `deepseek-*`
|
|
96
|
+
id 在**第①层**(preset 大表精确)或**第③层**(家族主干包含)就已命中并 return,而这两层的构造器
|
|
97
|
+
`hitOf` 不带 vision 位 ⇒ 第④层结构性不可达 ⇒ `deepseek4` 行的 `vision: false` **永远读不出来**,
|
|
98
|
+
下游 `MODEL_VISION=false` stamp 恒不发生(两处注释自述的行为是死的)。
|
|
99
|
+
修的形 = 把 `vision` 从「第④层的一个字段」提成**与容量证据层正交的一次独立查表**:容量轴
|
|
100
|
+
(ctx/maxTokens/perModelCap)四层证据强者先赢,**一字不动**;vision 轴恒查 family 表,与哪一层命中
|
|
101
|
+
**无关**。理由:preset 大表根本没有 vision 列,主干匹配拿的是**别的模型**的行 —— 两者都不是
|
|
102
|
+
「这个 id 能不能看图」的证据。🔴 **诚实缺席不变**:表上没标 ⇒ 键不 stamp(`kimi`/`qwen` 仍缺席),
|
|
103
|
+
绝不顺手补成 `false` 去封死一个真能力。
|
|
104
|
+
⚠️ **新契约形(cli 侧套内已钉前提断言,提货时同批改)**:`inferFamily(id)?.vision` 现在对**任何**
|
|
105
|
+
证据层的命中都可能在场(此前只有第④层),`vision` 与 `perModelCap` 的在场性**互相独立**。
|
|
106
|
+
- **🆕 件③(b)`engineCapState(baseUrl, key)` —— 能力位的可分辨读口(additive)**(cli [4752] 自领缺口2)。
|
|
107
|
+
`engineCapTrue` 只回 true/false,`false` 同时承载「引擎明说没有」「还没探」「探测在飞」「探测失败」
|
|
108
|
+
四件事。对**放行判据**这个塌缩刻意且正确(fail-closed);对**自检/诊断面**(doctor)它是谎报 ——
|
|
109
|
+
这也是 doctor 此前无法复用共享缓存的直接原因。新读口给闭集五态:`true`/`false`(引擎明说)、
|
|
110
|
+
`unprobed`(没有已落地的 caps;四种成因**故意合并**,因为对调用方是同一个动作)、`absent`
|
|
111
|
+
(caps 已落地但没这个键)、`non_boolean`(键在但值不是布尔 —— 不并进 `absent`,那会是假话)。
|
|
112
|
+
🔴 **放行语义一字未变**:`engineCapTrue` 现在就是 `engineCapState(...) === 'true'` 的单源实现。
|
|
113
|
+
- **🆕 件③(c)Model Hub 供给面三纯函数上收(additive)**:`resolveEntryVision` /
|
|
114
|
+
`computeDeleteBlockers` / `computeDeleteWarnings` 从 cli `modelChannels.ts` 搬进
|
|
115
|
+
`model/modelSupplyRules.ts`(新模块,**零 IO**)。三端 Model Hub 要回答的是同样三个问题
|
|
116
|
+
(vision 生效值+来源 / 删了会不会断链 / 删了会不会悄悄改语义),各写一遍 = 三个 Hub 对
|
|
117
|
+
「同一条档能不能删」给出三个答案,而其中两个要等用户按下 y 之后才被发现。
|
|
118
|
+
读盘那半场留各端;`doc === null` 的两义(没读到 vs 读不出来)**在调用方分流** —— 读不出来时
|
|
119
|
+
调用方自产 `unreadable` 阻断,fail-closed 拒删比「猜没人指着」安全。
|
|
120
|
+
⚠️ **上收差分两条(行为零改动)**:`resolveEntryVision` 的返回型由内联匿名对象改为具名
|
|
121
|
+
`EntryVisionResolution`(本仓 typeshape 门 B4 棘轮),两个 compute 的入参同理具名 —— **结构逐字
|
|
122
|
+
相同**,cli 剪切 import 时零适配。🔴 与件③(a)**同批落地是刻意的**:修前
|
|
123
|
+
`inferFamily(deepseek-*)?.vision` 结构性恒 `undefined`,`source:'family'` 这一档对 deepseek 族
|
|
124
|
+
**从来没走到过** —— 只上收不修 = 把一条死分支原样搬进三端。
|
|
125
|
+
- **🆕 件④ 两族 coded 拒绝(additive;[4743] core 5.48.0 @cli 点名件的 client-core 半场)**:
|
|
126
|
+
① **委派席位到限两码** `delegation.concurrency_cap` / `delegation.session_cap`(core 5.48.0
|
|
127
|
+
design/323 的 `RunnerDeps.delegationEntryCaps`,CC 对齐缺省 20/200)入词表,配 `DELEGATION_CAP_CODES`
|
|
128
|
+
识别表 + `isDelegationCapCode` 开集前缀谓词。🔴 **两码处置不对称,禁合并**:并发帽 = **可等**
|
|
129
|
+
(兄弟结束就有位,同一条命令过一会儿照样成)/ 会话累计帽 = **等也没用**(这棵树这辈子的配额用完了)
|
|
130
|
+
—— 合并成一句「委派失败」会让一半用户去干等、另一半去改配置。
|
|
131
|
+
② `config.delegation_entry_caps`(坏旋钮响亮拒)入 `CONFIG_REFUSAL_CODES` 识别表(前缀谓词本来
|
|
132
|
+
就认它;识别表是**登记**,让提货 diff 里一眼看出这版加了哪个词)。
|
|
133
|
+
③ **SendMessage 复活裁决两格** `resume.row_recycling` → `row-contended`(行正在被裁决,
|
|
134
|
+
**窗口自清,过一会儿再发就成**)/ `resume.row_gone` → `row-gone`(行已被终态 GC 收走,
|
|
135
|
+
**等也没用,重开新 agent**)。此前两码双双落进开集兜底 `error`,core 明明给了**两个不同的下一步**,
|
|
136
|
+
到客户端只剩一句泛泛失败。判定归包、文案归端。
|
|
137
|
+
🔴 **载体缺口如实登记(2026-08-21 亲验,不在本包侧路补救)**:core 把
|
|
138
|
+
`delegation.concurrency_cap` / `delegation.session_cap` 铸进 Task 工具结果体的 `details.error`,
|
|
139
|
+
而 core 的 `errorCode` 抬升腿只读 `details.code` → `details.errorKind` **两个拼法**,
|
|
140
|
+
`structuredFrom` 又要求 `details.type` 落在 `CC_DETAIL_TYPES` 里(这条 detail 连 `type` 都没有)
|
|
141
|
+
⇒ **今天这两码在 wire 上既不在 `tool_end.errorCode` 也不在 `structured`**,只剩模型面文案。
|
|
142
|
+
故本批**先立词、不落消费分支** —— 按文案反解正是 `engineErrorCodes.ts` 存在的理由要根除的东西
|
|
143
|
+
([cross-repo-fix-at-source-constitution]:载体缺口在 core,下游不许侧路补救)。已列上游诉求。
|
|
144
|
+
- **🔴 SDK 提货 7.1.0 → 7.2.0(peer 地板同批抬齐)+ `FleetTaskRow` 两新 wire 键投影**:
|
|
145
|
+
sdk 7.2.0 给 `FleetTaskRow` 声明了 `cycleSeq` / `retiredBy`(#261 §2,**server ≥7.25.0 早已在 wire
|
|
146
|
+
上发**,只是 SDK 类型迟到 ⇒ 本层此前把两键整个丢弃)。抬地板不是「顺手跟版本」:
|
|
147
|
+
`FLEET_TASK_ROW_WIRE_KEY_TUPLE` 与 `keyof FleetTaskRow` 是**编译期双向等值**钉,补键之后在
|
|
148
|
+
<7.2.0 的实装物上整包编译不过。
|
|
149
|
+
两位现已投进 `FleetTaskView`:`cycleSeq` = 代际号(fresh spawn 就是 cycle 1,**SendMessage 复活即 +1**;
|
|
150
|
+
同 id 帧更大 ⇒ 复活、更小 ⇒ 前代迟到帧)、`retiredBy` = **非亲报终态的投影者**(在场 = 这条终态是
|
|
151
|
+
对账腿从 durable run 行读出来的,发布方死了 —— **幽灵行与正常收尾唯一的 wire 判据**;读侧开集)。
|
|
152
|
+
🔴 **两位都只在场才落键**:`cycleSeq` 缺席 = 「这条行**没有代际概念**」(同步委派子代 / workflow
|
|
153
|
+
agent / 顶层 run 行),**不是第一代** —— 读成 1 会把「首帧迟到」误判成「复活」;`retiredBy` 缺席 =
|
|
154
|
+
发布方亲报。任何一个补默认值都会把一个诚实缺席翻译成假话。壳渲染契约尚未声明这两键,已登记在
|
|
155
|
+
`scripts/run-fleet-view-keys-test.mjs` 的 `SHELL_UNDECLARED_LEDGER`(壳提货补声明,本表当天删两条)。
|
|
156
|
+
|
|
157
|
+
### 已知局限(本版新增)
|
|
158
|
+
|
|
159
|
+
- **`engine_notice` 只有投影半场,没有渲染半场** —— 端不接 chrome 臂 `engine_notice` 的话,
|
|
160
|
+
这类披露在该宿主上**看不见**(不是报错)。cli 渲染腿排在 0.38.0 提货批。
|
|
161
|
+
- **`delegation.*` 两码今天在 wire 上没有机器可读载体**(见件④ ③),词表已立但消费分支候 core 补
|
|
162
|
+
`details.code` 孪生拼法(或抬升腿兼读 `details.error`)后再接。
|
|
163
|
+
- **`engineCapState` 的 `unprobed` 不区分四种成因**(没 kick / 在飞 / 探测失败 / 刚失效)——
|
|
164
|
+
刻意合并,分开需要引擎没给的信息;要「探测到底跑没跑」得靠 `engineCapsSettled` 的时序而不是读口。
|
|
165
|
+
|
|
166
|
+
## 0.37.0(2026-08-19)
|
|
167
|
+
|
|
168
|
+
**#307 双扫台账余量四条(S43/S44/S47/S25)。行为面**四条**:三条是「上游给了本层没接」的补接
|
|
169
|
+
(两条 additive 词表/键表 + 一条 wire 形收窄),一条是新导出的生产失效口。**
|
|
170
|
+
|
|
171
|
+
> 📌 **本段的公面基线是 750,不是 0.36.0 发布时的 749**:`0.36.0` 发布(2026-08-18)之后、本段之前,
|
|
172
|
+
> #307 呈现面批已经落了一个**未发布**的 additive 导出 `escapeDisplayControlChars`(749→750,当时
|
|
173
|
+
> CHANGELOG 还没有未发段可记)。本段接着它记 750→**751**。⇒ npm 上的 `0.36.0` 是 **749**;
|
|
174
|
+
> 本段与那一批的两个新导出**都还没发布**,端按名 import 会在 ESM 实例化当场炸
|
|
175
|
+
> (同一条口径写进 `docs/INTEGRATION-CLIENTS.md` §0a 的版本锚)。
|
|
176
|
+
|
|
177
|
+
- **structured 白名单补 `read_path_denied`(S43)**:core 5.43.0 起 fs 安全层拒读铸
|
|
178
|
+
`{type:"read_path_denied", …}` 细节卡(`dist/tools/fs/safety.js`),而本包 `STRUCTURED_DETAIL_TYPES`
|
|
179
|
+
只有 41 项 ⇒ `structuredDetailType()` 对这张卡返 `undefined` ⇒ 该卡**退回正则解模型面文本**,
|
|
180
|
+
而任何一层都不会响。补词后 42 项,与实装 core 逐词等值。
|
|
181
|
+
🔴 **病根第三次是同一个:对账物没跟着抬**(5.10 前停 devDep 5.1、5.20 前停 5.10、本次停 5.20)。
|
|
182
|
+
同批把 devDep `@sema-agent/core` 升 `^5.43.0` 并把 `run-engine-vocab-floor-test.mjs` 的
|
|
183
|
+
`CORE_FLOOR` 提级 5.20 → 5.43,钉住「对账物不得回退」;`STRUCTURED_DETAIL_TYPES` 头注补
|
|
184
|
+
「core 提货窗必须跟车对表」的成文纪律。
|
|
185
|
+
- **`BrainStatusPayload` 补 `errClass`(S44,ADDITIVE)**:core 5.43.0 给 `BrainStatus` 加了
|
|
186
|
+
`errClass`(`BrainRetryErrClass` 闭集:`connect_refused`/`transport`/`rate_limit`/`server`/`http`/
|
|
187
|
+
`output_cap`)—— 与 `phase`(引擎正在**做什么**)互补,它说的是**为什么**在等。此前本包七键只接
|
|
188
|
+
六键 ⇒ 引擎真发的量在本层被剥掉,用户看得到「在等」看不到「为什么等」(与 #3004 那批修的
|
|
189
|
+
attempt/maxRetries/retryInMs 同一个形)。
|
|
190
|
+
接线三处:`BrainStatusPayload` + `BRAIN_STATUS_PAYLOAD_KEYS`(6→**7** 键,engine-vocab G2-c 对账)、
|
|
191
|
+
`RetryStatus` 的 `stalled`/`error` 两臂、两条投影臂(`adapt/arms.ts` 的 `retryStatusArm` 与
|
|
192
|
+
`adapter/downstream/eventToSdkMessage.ts` 的 `status` 臂 —— SDK 的 `status` 臂类型同样还没跟,
|
|
193
|
+
按 unknown 读 + 串窄化透传)。
|
|
194
|
+
🔴 **开集读 + 诚实缺席**:表外桶原样带过去(本层零分支);缺席/空串/非串一律**键不 stamp**,
|
|
195
|
+
绝不折成某个默认桶。`BrainRetryErrClass` 刻意**只出类型不出运行期值镜像** —— 本包对它零分支,
|
|
196
|
+
少一个成员没有行为后果,而 `phase` 有 switch 分支才需要那张表 + 等值门。
|
|
197
|
+
- **`ToolApprovalFrame.fromSubagent` 形收窄 `boolean` → `true`(S47)**:SDK 7.1.0/7.2.0
|
|
198
|
+
`dist/resources/tool-approvals.d.ts` 逐字是 `fromSubagent?: true`(与本 interface 上
|
|
199
|
+
`governanceForced?: true` / `requiresRealApproval?: true` 同族的**在场即真**键),本包此前写
|
|
200
|
+
`boolean` = 自铸了一个 wire 上不存在的第三态 `false`。
|
|
201
|
+
🔴 **`isFromSubagent` 的 `=== true` 判别与回落臂逐字节不变,并把理由写成头注**:显式 `false`
|
|
202
|
+
只能来自注入面/不合契约的实现,承载的是「这个载体不合契约」而不是「引擎判定不是子代」⇒ 与缺席
|
|
203
|
+
同档,落回 `sourceTaskId` 在场性那条独立证据。方向是刻意的 —— 本判据唯一消费面是**展示归属**
|
|
204
|
+
(`workerBadge`/`delegation`),多一枚徽章只是噪声、少一枚是把事实对用户藏起来;让不合契约的
|
|
205
|
+
`false` 否决一条独立成立的证据,等于给注入面一个「隐藏子代身份」的开关。
|
|
206
|
+
门侧:`run-approval-frame-keys-test.mjs` 此前只做**键名集合**比较(零类型判据 —— 一个键从
|
|
207
|
+
`?: true` 悄悄放宽成 `?: boolean` 键名一个字不变、门原样绿),本版补**形腿**:三个在场即真键
|
|
208
|
+
逐键 grep 源文件声明形 + 跨仓核 SDK 锚同形 + 一条反空转探针。
|
|
209
|
+
- **🔴 新导出 `invalidateEngineCaps(baseUrl)`(S25;公面 750→**751**)**:`engineCapsCache` 的
|
|
210
|
+
**生产失效口**。病:`kickEngineCapsProbe` 首行就是 `capsByBase.has(baseUrl) ⇒ return`,而模块头注
|
|
211
|
+
自述「随每次 `createLiveConversationClient` 构造重 kick(引擎温切重启后新构造自然重探)」——
|
|
212
|
+
**那句话不成立**:引擎温切(respawn/restartEngine)后 baseUrl 常与重启前一模一样,新构造被这条
|
|
213
|
+
幂等闸原样挡住,缓存里留的永远是**旧引擎**那一版 caps。后果不是报错,是安静地按旧能力位走:
|
|
214
|
+
新引擎新增的车道被判成「没有」(藏功能),旧引擎有而新引擎撤掉的车道被判成「有」(走死路)。
|
|
215
|
+
此前除测试钩 `__resetEngineCapsCacheForTests` 外**零生产失效路径**。同批订正那段过时自述。
|
|
216
|
+
语义:**推进 per-base 代际** + 清 `capsByBase` + `inFlight`;**不 abort** 在途探测,**不清**
|
|
217
|
+
`settleByBase`(`engineCapsSettled` 的语义是「等**当前这一次**探测落地」,抽走在途 promise 会让
|
|
218
|
+
await 方拿到假「已落地」);空串 ⇒ no-op,从没探过也没失效过的 base ⇒ **真 no-op 不留代际条目**;
|
|
219
|
+
绝不 throw。**per-base**,不连坐别的 base。
|
|
220
|
+
🔴 **代际计数 `genByBase`(codex 对抗复审 [high] 采纳,同批修)**:失效口清了 `inFlight` 之后同
|
|
221
|
+
base 立刻可以再 kick ⇒ **两次探测并发跑在同一份无版本共享态上**。没有代际时两个真后果,都发生在
|
|
222
|
+
「重启撞上一次慢 capabilities 请求」这个最该正确的时刻 —— ①旧引擎那次**后**落地会把 caps 覆盖回
|
|
223
|
+
旧引擎的位(失效等于没做);②旧探测的 `finally` 删掉的是**新 run** 的 `inFlight`/`settleByBase`
|
|
224
|
+
条目 ⇒ `engineCapsSettled` 提前 resolve(假「已落地」)+ 幂等闸被打开。修 = 每个 run 出生抓一份
|
|
225
|
+
代号,写缓存/归还在途位之前核对是否仍是当代;不是当代的 run **只许安静退场**。常驻回归腿按
|
|
226
|
+
落地**顺序**(新先旧后 / 旧先新后)与旧 run **结局**(resolve/reject)两轴全跑。
|
|
227
|
+
同批 `docs/refactor/p1-scan/singleton-manifest.json` 登记 `genByBase`(dupRisk high,与
|
|
228
|
+
capsByBase/inFlight/settleByBase 同族必须同一份)+ singleton 门 `HIGH_RISK_CEILING` 91→92。
|
|
229
|
+
🔴 **`engineCapsSettled` 跨代际接力(对抗复审第二轮 [medium] 采纳,同批修)**:代际闸挡住了
|
|
230
|
+
**写**,却没管**等** —— 调用方 W 抓的是旧代际探测 P0 的 promise,invalidate 推进代际并起 P1 之后,
|
|
231
|
+
P0 先落地就把 W 放走,而 P0 已被挡住不许写缓存 ⇒ **W 当场读到空缓存,把新引擎的能力位当成缺席**。
|
|
232
|
+
同一类假缺席,只是搬到了 settle 面。修 = 每等完一条就重新求值表里的当代条目,换上了更新代际的
|
|
233
|
+
那条就改等它(代际严格递增 ⇒ 必然终止;每轮真 await 一条 promise ⇒ 不忙等)。
|
|
234
|
+
🔴 **两参原子形 `invalidateEngineCaps(baseUrl, probe?)`(对抗复审第三轮 [medium] 采纳,同批修;
|
|
235
|
+
ADDITIVE 可选第二参,公面导出数不变)**:单参形与「下一次 kick」之间还有一个**真窗** —— 失效之后、
|
|
236
|
+
新探测注册之前,旧代际探测正好在这一拍落地时 `settleByBase` 里已无更新代际的条目 ⇒ 等待者被放走,
|
|
237
|
+
而缓存刚被清空 ⇒ 把**当代引擎**的能力位读成缺席。窗只在调用方于失效与 kick 之间 `await` 了什么时
|
|
238
|
+
张开(同步块里 JS 单线程,旧探测的续体插不进来),而引擎温切本身就是异步流程 ⇒ 可达。
|
|
239
|
+
修 = 第二参给替代探测时,「推进代际」与「注册替代探测」落在**同一个同步块**里 ⇒ 窗按构造不存在,
|
|
240
|
+
等待者被接力到新探测上。**壳的 respawn/restartEngine 应当用两参形**;单参形保留给「只想丢掉缓存、
|
|
241
|
+
这一刻没有替代探测」的调用方 —— 那种情形下等待者读到**未判**是诚实结局(判据永远是缓存位),
|
|
242
|
+
硬等一个可能永远不会来的 kick 才是错的。两条腿都有常驻回归钉(单参形的诚实结局也钉住)。
|
|
243
|
+
🔴 **代际变更信号(对抗复审第四轮 [high] 采纳,同批修)**:接力此前**无条件先 await 旧那条
|
|
244
|
+
promise**,而引擎重启恰恰是最容易把旧探测**吊死**的时刻(旧进程没了,那个 fetch 可能永远不返回)
|
|
245
|
+
⇒ 两参原子失效已经起了 P1、P1 也已经把新能力位写进缓存,而 invalidate 之前取件的等待者仍**永久**
|
|
246
|
+
卡在 P0 上:缓存里明明是对的,等待者却永远拿不到。修 = `settleByBase` 每条带一个 `superseded`
|
|
247
|
+
信号,`invalidateEngineCaps` 推进代际时 resolve 它,等待者 `Promise.race([探测, 代际信号])`
|
|
248
|
+
被叫醒后**照走接力循环重新求值**。
|
|
249
|
+
⚠️ **叫醒 ≠ 放行**(有专门负控钉):醒来时表里换上了新代际(两参原子形保证同拍就在)就接着等
|
|
250
|
+
新探测;没换才按诚实缺席返回。所以既不会漏掉新引擎的位,也不会硬等一个可能永远不来的 kick。
|
|
251
|
+
同批把既有那条「invalidate 不把在途 settle 抽走」的断言按修正后的语义**改判**(它编码的是修前
|
|
252
|
+
行为):判据从「等了多久」改锚「落地那一拍读到什么」—— 早落地不是病,落地时交出旧引擎的位或一个
|
|
253
|
+
假「新位已到」才是;另补一条「被顶掉的旧探测事后落地也不写缓存」。
|
|
254
|
+
🔴 **settle 位落位顺序(对抗复审第五轮 [medium] 采纳,同批修)**:`probe` 是**调用方给的闭包**,
|
|
255
|
+
它的同步段完全可以回头调 `invalidateEngineCaps(baseUrl, 替代探测)` —— 两参原子形正是为温切设计,
|
|
256
|
+
而温切逻辑就住在这种回调里。`kickEngineCapsProbe` 此前**先跑 IIFE(= 先跑调用方代码)、后
|
|
257
|
+
`settleByBase.set`** ⇒ 嵌套 kick 装好的**新代际**条目当场被外层那一行覆盖回旧条目,随后旧 run 的
|
|
258
|
+
finally 又把它删掉 ⇒ `engineCapsSettled` 在替代探测仍在途时返回,能力读口报 false/undefined。
|
|
259
|
+
修 = settle 位改用**手工兑现**的 promise 并在**调用方代码跑起来之前**落位;重入时外层没有任何机会
|
|
260
|
+
回头覆盖别人。`probe` 仍是同步调用(不改时序)。
|
|
261
|
+
⚠️ **消费方在壳、本版不接线**:cli 侧应在 respawn/restartEngine 成功后、重新构造
|
|
262
|
+
`createLiveConversationClient` **之前**调用;库这一层只看得到一个字符串 base,分辨不出对面是不是
|
|
263
|
+
同一个进程 —— 靠 TTL 或「每次构造清」去猜,是把一个确定事实换成一个定时器。
|
|
264
|
+
|
|
265
|
+
**Inkglow-1085 案 P0a/P0b 的包半场([4660] 立案、[4664] server 定谳对表,2026-08-19;两件都是
|
|
266
|
+
行为面。公面 751→**753**:新导出 `DecideTransportRetryExhaustedError` / `clearRunningChoiceOffer`,
|
|
267
|
+
测试钩 37→**39**)。**
|
|
268
|
+
|
|
269
|
+
- **🔴 P0a:decide 出站超时/瞬断不再判死 turn(分诊有界重试 + 重呈臂;[4664] 长调用口径)**。
|
|
270
|
+
病(测试员真实项目转录,案卷 `INKGLOW-1085-AUDIT.md` 车1 全链):`approvals.decide` 是非 submit
|
|
271
|
+
POST —— SDK transport 对它 `maxAttempts=1`,且每发带显式 `AbortSignal.timeout(timeoutMs)`(缺省
|
|
272
|
+
60s;per-call opts 只有 `signal`,与之合流**只能收短不能放长**;timeoutMs 是 client 构造级旋钮,
|
|
273
|
+
包对注入 client 不可配)⇒ 一次超时/网络断 = 单发即死 ⇒ `toolApprovalWire` 拼 `failed` ⇒
|
|
274
|
+
`parkResolver` 合成 `hitl_unanswered` 终帧 ⇒ ask 死局(零重试/零重呈/run 永挂)。
|
|
275
|
+
🔴 [4664] 定谳真因:legacy 任务级 decide 腿在响应前**同步跑整条 resume**(模型往返,无上限)——
|
|
276
|
+
60s 帽结构性必炸;server 立件 #316 改快速 ack,过渡期口径 = 壳把这条腿当**长调用**。修三段:
|
|
277
|
+
① `HitlBridge.decideRaw`(唯一 decide choke point,四条决断腿全过)分诊重试:**超时类**
|
|
278
|
+
(TimeoutError = 60s 帽掐断,server 多半仍在跑)带退避在**长调用总窗**(缺省 10 分钟,
|
|
279
|
+
`__setDecideTimeoutRetryBudgetForTests` 测试钩)内继续重试;**网络断类**(ECONNREFUSED/
|
|
280
|
+
fetch failed 等)重试**恰一次**(引擎真死尽快显形);**带 HTTP status 的语义答复一律零重试**。
|
|
281
|
+
重试安全两道背书:[4664] 原话「重复 decide 不双跑,server CAS 保证」+ D-1 绑定回显(第一发其实
|
|
282
|
+
送达时重发只能撞 4xx,绝不可能批掉另一件事;该 4xx 原样上抛,既有「已解决重放救回」判据照认)。
|
|
283
|
+
`HitlSafetyError` 与用户中止恒零重试;remember 回退臂对瞬断耗尽**不再**回退纯 approve(引擎够不着
|
|
284
|
+
时补发只烧第二轮超时还错标病因)。
|
|
285
|
+
② 重试耗尽(超时类窗尽 / 网络断类第二发仍断)⇒ 抛 typed `DecideTransportRetryExhaustedError`,
|
|
286
|
+
两条决断腿(fs 卡 / ask overlay)在 outcome 上 stamp **`retryExhausted: true`**
|
|
287
|
+
(`FsApprovalOutcome`/`GateOutcome` failed 臂的 additive 判别位,在场即真)。
|
|
288
|
+
③ `resolvePark` 对该位走**重呈臂**:reattach ⇒ durable 流对 suspended run 必然重放 park ⇒ **同一张
|
|
289
|
+
卡重新交给用户**(与 #110 已解决重放同一条机械路径,hop 预算照吃);不再合成 `hitl_unanswered` ——
|
|
290
|
+
判死是三条出路里唯一不可逆的,只配给引擎答了且拒了的语义失败。引擎真死时失败尽快显形:下一轮
|
|
291
|
+
approvals.list 当场失败走既有诚实红。门:`run-hitl-gate-honesty-test.mjs` 新 F6 组(红先绿后 +
|
|
292
|
+
四变异各自抓红);耗尽错 message 有负控钉「不落 isAlreadyResolvedGateReason 词表」。
|
|
293
|
+
⚠️ **请托 SDK 半场(候黑板)**:decide 的 per-call 面今天无 timeout 旋钮(只有 signal,合流只能
|
|
294
|
+
收短)—— 若 SDK 给 decide 开 per-call timeoutMs(或对 HITL 面单列长缺省),超时类重试环可整段
|
|
295
|
+
收敛成一发长等待;#316(快速 ack)落地后总窗亦可回收。
|
|
296
|
+
- **🔴 P0b:Session busy 幽灵 running 的三选卡半场(存活对账 + 已呈现登记)**。病(案卷车2):
|
|
297
|
+
`runningChoiceArm` 的判据 = 409 终帧 `activeTaskStatus`(best-effort 投影,claim/store 错时**每次**
|
|
298
|
+
回送同一个错的 `running`),无存活对账;且每次 409 无条件整卡重弹(用户选「Do nothing」后每条
|
|
299
|
+
消息再弹一张)。修两段:
|
|
300
|
+
① **出卡前存活对账**:wire 直供 `running` 时补一发 `runs.get`(4s 有界,session 逐次透传;status
|
|
301
|
+
本就是本层刚 get 来的则不打第二发)—— 读回非 running 的已知词 ⇒ 按真态走(park 词进对应重开臂);
|
|
302
|
+
**404 ⇒ 新结局 `running-not-found`**(幽灵 claim:三选卡不呈 —— 对不存在的 run 渲 steer/cancel 是
|
|
303
|
+
假 affordance;也不自动重发 —— 该 404 与 non-owner 同码刻意不可分辨,文案只说已证事实 + 「再发
|
|
304
|
+
一次」真出路);**get 网络失败/窗尽 ≠ 非 running,保守维持出卡**。
|
|
305
|
+
② **已呈现登记**:模块级 (sessionKey\0taskId,`\0` 为字面转义) 台账记「卡真呈现过且用户选了 wait」——
|
|
306
|
+
同键再撞 409 不再整卡重弹,`not-parked` 结局带 **`alreadyOffered: true`** 判别位(默认文案层给
|
|
307
|
+
降级行:仍被占用 + 已问过不再重复问 + cancel 端点与 wayOut 两条真出路;端可按该位自渲更轻的形)。
|
|
308
|
+
选 steer/cancel 清登记;呈卡腿抛错那次不登记(用户没看到卡);宿主「重新打开操作菜单」走新导出
|
|
309
|
+
**`clearRunningChoiceOffer(taskId, sessionId?)`**。门:`run-selfheal-reopen-test.mjs` 新 G10 组
|
|
310
|
+
(红先绿后 + 两变异抓红);G8⑤ 系列夹具的 `runs.get` 改相位形(首发答 running = 对账放行)。
|
|
311
|
+
③ **[4664] 对表补强**:`ActiveRunBusySignal` 补 additive 键 **`msSinceLastActivity`**(409 体内
|
|
312
|
+
唯一可消费的活性证据位;只认有限非负数,坏形键不 stamp,缺席 ≠「没有活动」;SDK 7.2.0 类型面
|
|
313
|
+
尚无此键 = probeCause 同款领先锚姿势)—— not-parked(running 形)默认行在位在场时追加
|
|
314
|
+
「last recorded activity … ago」一句,缺席一字不加。分诊上界如实登记:SQL 车道死 run 自愈上界
|
|
315
|
+
≈180s,**LOCAL(file)车道无周期腿 = 无上界**,故本包不做时间性假设,只做 runs.get 一手复核;
|
|
316
|
+
[4664] 四个洞(park 态不在 reapStale 射程 / updated_at 误杀窗 / 409 与 poll 口径短暂相左 /
|
|
317
|
+
LOCAL 无周期腿)在 `ActiveRunBusySignal.activeTaskStatus` 与存活对账腿的注释上逐条引用 ——
|
|
318
|
+
409 的 `running` 不是绝对真值。
|
|
319
|
+
④ **codex 对抗复审跟修(同批,真病三件)**:[high] 对账读回**终态词**(completed/failed/blocked/
|
|
320
|
+
timeout)不再落 not-parked(其默认文案对已终结的 run 说「wait for it to finish」= 永远等不到的
|
|
321
|
+
假话)—— 专属结局 **`running-settled`**(诚实说 claim 陈旧/释放中 + 重发指引);[medium] 对账
|
|
322
|
+
期间用户 Esc ⇒ 探测归来后零派臂/零出卡/零登记(零动作现状行收口);[medium 轻形] 登记表 FIFO
|
|
323
|
+
有界(cap 512,驱逐代价 = 卡重弹一次 = 修前行为)。驳回两件:allow_session remember 回退臂的
|
|
324
|
+
catch 宽度是 0.28.0 起的既有设计(本批已把瞬断耗尽从回退剥出 = 严格收窄;按语义收窄到「仅
|
|
325
|
+
unknown-key 400」登记为候件,行为面另立项);超时类总窗刻意只兜「起新发」不掐在飞发(给一发
|
|
326
|
+
可能已被受理的 decide 塞截止 signal 换不来安全,只制造送达未知;上冲 ≤ 一发 + 退避,注释成文)。
|
|
327
|
+
⚠️ **端半场(cli/web/desktop 候接)**:①消费 `alreadyOffered: true` 降级渲染(不接=默认降级行,
|
|
328
|
+
已可用);②「重新打开菜单」入口接 `clearRunningChoiceOffer`;③新结局 kind `running-not-found` /
|
|
329
|
+
`running-settled` 若端有自绘 rowFor 覆盖需补臂(默认文案已给);④`msSinceLastActivity` 判别位
|
|
330
|
+
可自渲「已 N 分钟无活动」(不接=默认行已带)。
|
|
18
331
|
|
|
19
332
|
## 0.36.0(未发布)
|
|
20
333
|
|
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.38.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
|
|
@@ -65,7 +65,7 @@ Renamed from **`@sema-agent/wire-cc-adapter`** (0.1.x, deprecated — see *Migra
|
|
|
65
65
|
`SseIdleError`, `probeHealth`, `APIError` and `TaskStopConflictError` are imported as values in
|
|
66
66
|
five modules, and the browser bundle really bundles the SDK through (the portability guard would
|
|
67
67
|
exit 3 rather than quietly mark it external).
|
|
68
|
-
- The declared floor is `>=7.
|
|
68
|
+
- The declared floor is `>=7.2.0`, and it is *witnessed*: the guard checks that an actually
|
|
69
69
|
installed SDK at that line still exports every value-level symbol this package imports and still
|
|
70
70
|
declares `TaskStats.costMicroUsd` (the key `costOrNull` reads). A floor nobody ever ran is a
|
|
71
71
|
promise, not a contract.
|
package/dist/adapt/arms.js
CHANGED
|
@@ -254,6 +254,45 @@ const humanInputArm = function* (m) {
|
|
|
254
254
|
...(str(m.eventId) !== undefined ? { eventId: str(m.eventId) } : {}),
|
|
255
255
|
});
|
|
256
256
|
};
|
|
257
|
+
/**
|
|
258
|
+
* #310 / #318 件① —— `engine_notice` 引擎结构化通告(server ≥7.36,契约 = ASSISTANT-WIRE-CONTRACT 附录 D)。
|
|
259
|
+
*
|
|
260
|
+
* 姿势抄同族的 `human_input`(引擎侧发生了一件事、壳记一笔的非持久帧,归 chrome;**不走 attachment**:
|
|
261
|
+
* 通告要带结构化事实与幂等键,折成一行文案会逼消费端反解 code)。
|
|
262
|
+
*
|
|
263
|
+
* 🔴 **开集:一个码都不判**。这里没有识别表、没有 switch、没有「已知才投」—— `code` 认不认得是
|
|
264
|
+
* **渲染面**的事,投影面只负责把事实原样送到。`detail` 同理**整对象透传**(禁挑键:逐码不同且开集,
|
|
265
|
+
* 挑键 = 新码的事实在本层静默蒸发)。
|
|
266
|
+
* 🔴 **不读能力位**:帧到了就投影(A-022「到帧即服务」)。拿探测位 gate 一条已经到手的事实,只会在
|
|
267
|
+
* 探测未判/失败时把真事实丢掉。
|
|
268
|
+
* 🔴 子流帧(带 `parentToolCallId`)同族让位:不上 leader 面。
|
|
269
|
+
* ⚠️ 第二道 `code` 在场判(投影层已判 malformed):同 `human_input` 的 carrier 二道判,防的是**非投影
|
|
270
|
+
* 口喂进来的帧**(宿主自建管线 / 重放存量转录),不是重复判据。
|
|
271
|
+
*/
|
|
272
|
+
const engineNoticeArm = function* (m) {
|
|
273
|
+
if (typeof m.parentToolCallId === 'string')
|
|
274
|
+
return;
|
|
275
|
+
const code = typeof m.code === 'string' ? m.code : '';
|
|
276
|
+
if (code.length === 0)
|
|
277
|
+
return;
|
|
278
|
+
const rawDetail = m.detail;
|
|
279
|
+
const detail = typeof rawDetail === 'object' && rawDetail !== null && !Array.isArray(rawDetail)
|
|
280
|
+
? rawDetail
|
|
281
|
+
: {};
|
|
282
|
+
yield chrome({
|
|
283
|
+
kind: 'engine_notice',
|
|
284
|
+
laneProof: MAIN,
|
|
285
|
+
code,
|
|
286
|
+
message: typeof m.message === 'string' ? m.message : '',
|
|
287
|
+
detail,
|
|
288
|
+
...(typeof m.sessionId === 'string' && m.sessionId.length > 0 ? { sessionId: m.sessionId } : {}),
|
|
289
|
+
...(typeof m.ts === 'number' && Number.isFinite(m.ts) ? { ts: m.ts } : {}),
|
|
290
|
+
...(typeof m.eventId === 'string' && m.eventId.length > 0 ? { eventId: m.eventId } : {}),
|
|
291
|
+
// durable 重放的第二层身份(SDK 从 SSE `id:` stamp 的 per-task 序号)—— 两个键两个命名空间,
|
|
292
|
+
// 见投影层同位的长注。消费端幂等序:eventId > eventSeq > (都缺才退) code+ts。
|
|
293
|
+
...(typeof m.eventSeq === 'string' && m.eventSeq.length > 0 ? { eventSeq: m.eventSeq } : {}),
|
|
294
|
+
});
|
|
295
|
+
};
|
|
257
296
|
const promptSuggestionsArm = function* (m) {
|
|
258
297
|
// T57 第五处断闸(#47 矩阵 #5 同族):子流(parentToolCallId 标)的建议绝不骑主 composer。
|
|
259
298
|
if (typeof m.parentToolCallId === 'string')
|
|
@@ -677,6 +716,9 @@ const retryStatusArm = function* (m, { ctx, flags }) {
|
|
|
677
716
|
...(typeof m.retryInMs === 'number' ? { retryInMs: m.retryInMs } : {}),
|
|
678
717
|
...(typeof m.attempt === 'number' ? { attempt: m.attempt } : {}),
|
|
679
718
|
...(typeof m.maxRetries === 'number' ? { maxRetries: m.maxRetries } : {}),
|
|
719
|
+
// 七键(#307 S44,2026-08-19):core 5.43.0 起 `BrainStatus` 带 `errClass`(等待原因分桶)。
|
|
720
|
+
// 剥掉它 = 用户看得到「在等」看不到「为什么等」,而供给方是发了的。
|
|
721
|
+
...(typeof m.errClass === 'string' ? { errClass: m.errClass } : {}),
|
|
680
722
|
}, ctx.now());
|
|
681
723
|
// `status === null` = 引擎直报 `recovered`(重试成功)。这一拍是**清除腿之一** —— 但间接腿
|
|
682
724
|
// (TurnFlags 的「主 lane 内容帧到达即清」)可能已经清过了:已安装 core 在内容流跑完的 finally
|
|
@@ -711,6 +753,7 @@ export const ARMS = new Map([
|
|
|
711
753
|
['steering_injected', steeringInjectedArm],
|
|
712
754
|
['workspace_changed', workspaceChangedArm],
|
|
713
755
|
['human_input', humanInputArm],
|
|
756
|
+
['engine_notice', engineNoticeArm],
|
|
714
757
|
['prompt_suggestions', promptSuggestionsArm],
|
|
715
758
|
['retry_status', retryStatusArm],
|
|
716
759
|
]);
|
package/dist/adapt.d.ts
CHANGED
|
@@ -50,7 +50,7 @@ export interface AdapterLedgerState {
|
|
|
50
50
|
/** 本批覆盖清单——差分守卫按它区分「已覆盖臂必须逐字段等价」与「已声明未覆盖臂」。 */
|
|
51
51
|
export declare const ADAPTER_COVERAGE: {
|
|
52
52
|
/** 已落码的帧臂。 */
|
|
53
|
-
readonly frames: readonly ["assistant", "user", "stream_event", "turn_usage", "result", "system", "task_notification", "workflow_complete", "diagnostics", "steering_injected", "workspace_changed", "human_input", "prompt_suggestions", "retry_status", "task_progress", "tool_end_result(label 补位 + 关卡 settle + response-id 复位 + 开卡台账出栈 + 经 cards.close 铸 tool_result)"];
|
|
53
|
+
readonly frames: readonly ["assistant", "user", "stream_event", "turn_usage", "result", "system", "task_notification", "workflow_complete", "diagnostics", "steering_injected", "workspace_changed", "human_input", "engine_notice", "prompt_suggestions", "retry_status", "task_progress", "tool_end_result(label 补位 + 关卡 settle + response-id 复位 + 开卡台账出栈 + 经 cards.close 铸 tool_result)"];
|
|
54
54
|
/** 已落码臂产出的 transcript 消息类目(差分守卫的比对域)。 */
|
|
55
55
|
readonly transcriptKinds: readonly ["assistant_text", "assistant_thinking", "assistant_tool_use", "user_tool_result_decision", "user_task_notification", "system_passthrough"];
|
|
56
56
|
/** B3(0.5.0)新落码的臂/半场 —— 从 todo 移过来的,别再在 todo 里留同名条目。 */
|
package/dist/adapt.js
CHANGED
|
@@ -33,6 +33,8 @@ export const ADAPTER_COVERAGE = {
|
|
|
33
33
|
'workspace_changed',
|
|
34
34
|
// FIX⑦(2026-08-07):`human_input` 账本帧 —— 投 chrome 记账,**不铸 transcript 行**(不带正文)。
|
|
35
35
|
'human_input',
|
|
36
|
+
// #318 件①(2026-08-21):`engine_notice` 引擎结构化通告 —— 投 chrome(开集,一个码都不判)。
|
|
37
|
+
'engine_notice',
|
|
36
38
|
'prompt_suggestions',
|
|
37
39
|
'retry_status',
|
|
38
40
|
'task_progress',
|
|
@@ -234,11 +234,38 @@ export type SelfHealOutcome =
|
|
|
234
234
|
decidePath: string | null;
|
|
235
235
|
}
|
|
236
236
|
/** 持锁的是**活着的** run(通常是背景化的那一轮),或 wire 指名了两张分诊表之外的 gate
|
|
237
|
-
* kind(结局④:不动 + 如实说)⇒ 不动它,如实告知。
|
|
237
|
+
* kind(结局④:不动 + 如实说)⇒ 不动它,如实告知。
|
|
238
|
+
* `alreadyOffered`(Inkglow-1085 P0b①,0.37.0,在场即真):同一 (sessionKey,taskId) 的三选卡
|
|
239
|
+
* **已呈现过且用户选了「Do nothing」** —— 本次不再整卡重弹,端据此把整卡降级渲成一行提示
|
|
240
|
+
* (默认文案层已给降级行;登记的清口见 {@link clearRunningChoiceOffer})。缺席 = 首撞或登记
|
|
241
|
+
* 已被 steer/cancel 选择清掉,现状行字节不变。 */
|
|
238
242
|
| {
|
|
239
243
|
kind: 'not-parked';
|
|
240
244
|
taskId: string;
|
|
241
245
|
status: string;
|
|
246
|
+
alreadyOffered?: true;
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* 存活对账腿(Inkglow-1085 P0b②,0.37.0):wire 409 终帧说这条 run `running` 占着会话,而出卡前
|
|
250
|
+
* 的 `runs.get` 真查撞 **404** —— claim 指着一条引擎已不认得的 run(幽灵 running)。三选卡不呈
|
|
251
|
+
* (对不存在的 run 渲 steer/cancel 是假 affordance),也**不自动重发**(该 404 与 non-owner 同码
|
|
252
|
+
* 刻意不可分辨,自动重发可能撞回一个仍锁着的会话)——如实说 + 「再发一次」是真出路。
|
|
253
|
+
*/
|
|
254
|
+
| {
|
|
255
|
+
kind: 'running-not-found';
|
|
256
|
+
taskId: string;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* 存活对账腿(codex 对抗复审 [high] 采纳,2026-08-19):wire 409 说这条 run `running`,而出卡前的
|
|
260
|
+
* `runs.get` 读回**终态词**({@link CLAIM_RELEASED_STATES})—— run 已终结,claim 是陈旧/释放中的
|
|
261
|
+
* 投影([4664] 洞③:409 与 poll 口径短暂相左)。三选卡不呈(steer/cancel 对已终结的 run 全是假
|
|
262
|
+
* affordance),也**不自动重发**(claim 可能尚未真正落地释放)—— 如实说 + 「再发一次」真出路。
|
|
263
|
+
* 修前这一形落 `not-parked`,默认文案对一条已终结的 run 说「wait for it to finish」= 永远等不到。
|
|
264
|
+
*/
|
|
265
|
+
| {
|
|
266
|
+
kind: 'running-settled';
|
|
267
|
+
taskId: string;
|
|
268
|
+
status: string;
|
|
242
269
|
}
|
|
243
270
|
/** 读不到状态(缺 verb / 404 / 传输错)⇒ 不做破坏性动作,如实告知。 */
|
|
244
271
|
| {
|
|
@@ -347,7 +374,8 @@ export type SelfHealSubmissionDisposition = 'held-for-decision' | 'resending' |
|
|
|
347
374
|
* 🔴 判据锚在「**有没有一张现在就能答、答了就放行的卡**」这个决定量上,不是锚在「是不是 park
|
|
348
375
|
* 态」这个前置条件上([anchor-on-the-deciding-quantity])。所以三张 reopen-failed / not-parked /
|
|
349
376
|
* state-unknown 全部落 `not-delivered`:它们同样是 park,但卡没能呈到用户面前,把注入件放回队列
|
|
350
|
-
* 只会在下一拍再撞一次同样的 409
|
|
377
|
+
* 只会在下一拍再撞一次同样的 409。`running-not-found`(幽灵 claim)同落 `not-delivered`:
|
|
378
|
+
* 「已解锁」证不出,自动重投可能撞回仍锁着的会话。
|
|
351
379
|
*/
|
|
352
380
|
export declare function selfHealSubmissionDisposition(outcome: SelfHealOutcome): SelfHealSubmissionDisposition;
|
|
353
381
|
/**
|
|
@@ -371,6 +399,11 @@ export declare function readSteerDelivery(receipt: unknown): string | null;
|
|
|
371
399
|
export declare function readSteerReceiptStatus(receipt: unknown): string | null;
|
|
372
400
|
/** cancel 之后**有界**等那条 run 交出会话的缺省窗(`POST …/cancel` 是 202 异步 —— 收下 ≠ 已停)。 */
|
|
373
401
|
export declare const CANCEL_RELEASE_WAIT_MS = 10000;
|
|
402
|
+
/** 清掉某条 run 的「Do nothing」登记 —— 宿主「重新打开操作菜单」入口(下一次 409 重新整卡呈现)。
|
|
403
|
+
* `sessionId` 与当时喂给 {@link ActiveRunSelfHealDeps.sessionId} 的值同源(缺席 = 默认键)。 */
|
|
404
|
+
export declare function clearRunningChoiceOffer(taskId: string, sessionId?: string): void;
|
|
405
|
+
/** 测试钩:清空整张登记表(套件各组之间隔离用)。 */
|
|
406
|
+
export declare function __resetRunningChoiceLedgerForTests(): void;
|
|
374
407
|
/** {@link waitForClaimRelease} 的收口:`released` = 那条 run 真交出了会话;`waitedMs` = **真等了
|
|
375
408
|
* 多久**;`aborted` = 收口原因是调用方中止(用户 Esc)而不是窗口到点。 */
|
|
376
409
|
export interface ClaimReleaseVerdict {
|