@sema-agent/client-core 0.51.0 → 0.53.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 +115 -0
- package/README.md +1 -1
- package/dist/adapter/activeRunSelfHeal.d.ts +99 -2
- package/dist/adapter/activeRunSelfHeal.js +381 -104
- package/dist/classifierVerdictWire.d.ts +39 -0
- package/dist/classifierVerdictWire.js +111 -0
- package/dist/hitl/frameRouter.js +32 -3
- package/dist/hitl/gateLedger.d.ts +54 -0
- package/dist/hitl/gateLedger.js +54 -0
- package/dist/hitl/hitlHostSurface.d.ts +29 -2
- package/dist/hooksWireCaps.js +66 -2
- package/docs/INTEGRATION-CLIENTS.md +286 -8
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -40,6 +40,121 @@
|
|
|
40
40
|
> 门侧窄豁免同批登记(`KNOWN_HEADING_ERRATA` `version: '0.48.0', releasedAt: '4fae01b'`),
|
|
41
41
|
> 与本段互钉,均为永久记录。
|
|
42
42
|
|
|
43
|
+
## 0.53.0(未发布)
|
|
44
|
+
|
|
45
|
+
### hitl 自愈:陈旧 park —— 「待决行确已不在」给真出路(L-93;现网 sema-bug7)
|
|
46
|
+
|
|
47
|
+
- **病**:审批卡 park 住一条 run 之后过了很久(实测 27.5h),用户退出 TUI 再 `--resume`;重开链去引擎
|
|
48
|
+
读待决行时**读面答了**、而属主待决行**恰 0**(引擎重启后 `process_local` 会话店丢行 / 审批被引擎
|
|
49
|
+
reap),run 却仍 `suspended` 并占着会话 claim。修前本包对这一形只有 `ask-reopen-failed` 一个结局
|
|
50
|
+
⇒ 端渲「Your message was NOT sent … 换个新会话」:卡不可能重开(没有行了),run 不会自己结束
|
|
51
|
+
(park 态不在时间型 reap 射程),用户只剩丢掉整段上下文这一条路。
|
|
52
|
+
- **改**(全部 additive):
|
|
53
|
+
- `ReopenCardVerdict` 的 `reopened:false` 臂加 **`pendingRowGone?: true`** —— 宿主的**正面证据**位:
|
|
54
|
+
读面在有界窗内**答了**且属主过滤后待决行数**恰 0**。读口缺席 / 网络失败 / 抛错 / 窗尽 / 中止 /
|
|
55
|
+
「找不到能用的那一行」一律**不置**(fail-closed);判据只认严格 `true`。
|
|
56
|
+
- 新臂 `staleParkArm`:该位在场(且非 `decidedWithoutCard`)⇒ 用 `runs.get` **一手复核**真态,分五路
|
|
57
|
+
—— 404 ⇒ 新 kind **`ask-run-not-found`**(幽灵 claim 的 park 半场,不盲发);`running` ⇒ 交既有三选卡臂
|
|
58
|
+
(不打第二发 get);`needs_review` ⇒ 交既有 plan 重开臂(cancel 它 = 替用户丢掉整个 plan,禁区);
|
|
59
|
+
`suspended` ⇒ 新宿主钩子 **`offerStaleParkChoice`**(两选卡:停掉它 / 什么都不做);读不出、表外新词、
|
|
60
|
+
中止 ⇒ 一律退回既有 `ask-reopen-failed`。
|
|
61
|
+
- 四个新结局:**`stale-park-cancelled`**(处置 `resending`,与 `running-cancelled` 同一条重发腿、同一个
|
|
62
|
+
「释放已确认」前提)/ **`stale-park-cancel-timeout`** / **`stale-park-cancel-failed`** / **`stale-park-wait`**
|
|
63
|
+
(带 `alreadyOffered?` 登记降级位,清口同 `clearRunningChoiceOffer`)。
|
|
64
|
+
- cancel 那条腿**抽成共享叶 `cancelAndConfirmRelease`**(三选卡与两选卡同源):失败分类
|
|
65
|
+
(`atMostOnceFailureClass`)与释放判据(`CLAIM_RELEASED_STATES`)不许有第二份实现。
|
|
66
|
+
- 🔴 **边界写在判定上,不写在文案上**:退役的自动 cancel 臂的循环病根 =「**待决项仍在**时 cancel = 替用户
|
|
67
|
+
deny ⇒ 模型重试 ⇒ 再 park」。本臂的前提恰是那个待决项**已经不存在**,那条循环在结构上不成立。所以
|
|
68
|
+
`pendingRowGone` 缺席/含糊值一律进不了新臂(负控写进常驻门),且进臂后仍要一手复核 + 用户显式选择,
|
|
69
|
+
本包任何路径都不自动 cancel。
|
|
70
|
+
- 🔴 **卡后复证 run 真态**(对抗复审 R3 [high] 采纳):卡前那一发 `runs.get` 打在**呈卡之前**,而卡可以
|
|
71
|
+
停留任意久 —— 这中间 run 可能恢复运行。所以用户选 cancel 之后**再打一发**,状态仍是审批 park 词才
|
|
72
|
+
继续;变 running / 终态 / 换门 / 读不出 ⇒ fail-closed 退回旧结局(绝不沿用旧卡的授权去停一条正在
|
|
73
|
+
干活的 run),404 ⇒ `ask-run-not-found`。
|
|
74
|
+
- 🔴 **开枪前再证一次前提**(对抗复审 R1 [high] 采纳):`pendingRowGone` 是宿主**读那一刻**的事实,
|
|
75
|
+
而两选卡是人在看、可以看任意久 —— 中间待决行可能重新出现,宿主也可能误报。所以在离 `runs.cancel`
|
|
76
|
+
最近的那一刻用 `deps.listOwnedPendingApprovals`(既有键,带归属过滤)再问一次属主待决行数,**恰 0
|
|
77
|
+
才开枪**;非 0 / 抛错 / 窗尽 / 中止一律不开枪。该读口因此成为两选卡的**供给前提**:宿主不注入
|
|
78
|
+
⇒ 卡整个不呈(fail-closed)。复证走共享叶 `readOwnedPendingCount`(与假死锁防御同一只)。
|
|
79
|
+
- 🔴 **老宿主零行为差**:不传 `pendingRowGone`、不传 `offerStaleParkChoice` ⇒ 逐字节维持今天的结局与文案
|
|
80
|
+
(web / desktop 无需动作)。cli 半场(置位 + 两选卡 UI + live 证据)是另一批。
|
|
81
|
+
⚠️ 「零行为差」说的是**运行期**:`SelfHealOutcome` 多了五个 kind,对它做穷尽 switch + assertNever 的
|
|
82
|
+
消费方编译期要补臂(与 0.37.0 起历次加 kind 同形);`default` 分支的消费方零改动。
|
|
83
|
+
- 🔴 **文案不越过证据**(同批 [medium] 采纳):`ask-run-not-found` 不断言「那条 run 不存在」(404 分不出
|
|
84
|
+
「不存在」与「这个会话读不到」),`stale-park-cancelled` 明说那条 run 已终结、那一轮不会恢复
|
|
85
|
+
(SDK `CancelAck`:受理回 `cancelling`,随后 settle 成 `failed` + `errorCode: "cancelled"`)。
|
|
86
|
+
- 🔴 **两条在册边界(第二轮对抗复审如实登记,不假装不存在)**:
|
|
87
|
+
- **P-44** —— 开枪前复证是「查了再做」,**不是原子条件取消**:复证与那一枪之间仍有毫秒级窗口,
|
|
88
|
+
待决行恰在此间恢复的话那一枪照样落下。客户端关不死,正位解是**引擎侧条件取消**(带审批快照
|
|
89
|
+
版本 / checkpoint 标识,条件变了回 409 且不取消)。判据只钉可判的那半:调用序必须是
|
|
90
|
+
呈卡 → 卡后 get 复证 → 待决行复证 → cancel,两发复证都紧跟在用户那句授权之后。
|
|
91
|
+
- **P-45**(存量族)——「run 读到终态」不等于「claim 已落地释放」:`running-cancelled`(0.37.0 起)
|
|
92
|
+
与本批 `stale-park-cancelled` 共用同一把尺(`CLAIM_RELEASED_STATES`),重发撞回 409 是**已知可能**,
|
|
93
|
+
自愈树当拍再分诊。刻意**不**单修新那一条 —— 同一判据两份实现必漂;正位解要引擎给 claim 读面。
|
|
94
|
+
本批的 `stale-park-cancelled` 文案已按这条边界写(只说「引擎报它已终结」+「可能要再发一次」);
|
|
95
|
+
0.37.0 的 `running-cancelled` 行仍是旧说法,登记为同形存量待属主批(§7b P-45)。
|
|
96
|
+
- 接入形见 `docs/INTEGRATION-CLIENTS.md` §16(缺口登记见 §7b P-44/P-45)。常驻门:
|
|
97
|
+
`scripts/run-selfheal-reopen-test.mjs` G11 段 + `scripts/run-terminal-identity-copy-test.mjs` G2 段。
|
|
98
|
+
|
|
99
|
+
## 0.52.0(2026-09-04)
|
|
100
|
+
|
|
101
|
+
### hitl:分类器拒绝行带 `ctx`(toolCallId + tool_start args)(L-69⑨;DEBTS-cli)
|
|
102
|
+
|
|
103
|
+
- **病**:`frameRouter` 的 `classifier-deny` 臂只把 `toolName` 交给宿主 ⇒ 端的 /permissions Recent Denials
|
|
104
|
+
三行同名(三条被拒的 `Bash` 长一个样),retry 粒度只能落到「整个工具」。拿不到 args 的根因在台账:
|
|
105
|
+
`gateLedger` **只在 gated tool_start** 留 args(`gatedStartArgsByCall`),而分类器拒绝的工具通常
|
|
106
|
+
**没被 gate**(引擎侧分类器直接 block,一张 `tool_approval` 帧都不出)⇒ 拒绝当拍 args 已不可得。
|
|
107
|
+
- **改**:
|
|
108
|
+
- `GateLedger` 加三个动词 `noteStart` / `startArgs` / `dropStartArgs`:**每一张** `tool_start` 都留一份
|
|
109
|
+
args 快照,**有界 FIFO**(`START_ARGS_MAX_ENTRIES = 256`,超容量丢最早),`tool_end` 收口当拍释放。
|
|
110
|
+
🔴 与 `gatedStartArgs` **刻意分两张表**:「被 gate 过」是另一个集合,不许拿「表里有 args」当身份位;
|
|
111
|
+
两表的生命周期与容量纪律也不同(gated 表整个 turn 不删、条目数天然受限)。
|
|
112
|
+
- `HitlHostSurface.surfaceClassifierDeny(toolName, verdict, ctx?)` 加 **additive 可选**第三参
|
|
113
|
+
`ClassifierDenyContext { toolCallId: string; args?: unknown }`;deny 臂传 `{toolCallId: callId, args}`。
|
|
114
|
+
老宿主(两参实现)**零改动照跑**;台账缺席 ⇒ `args` 键不铸(诚实缺席,不是 `args: undefined`)。
|
|
115
|
+
- 新导出纯函数 `classifierDenyDisplay(toolName, args)`(三端同形的**行文案**判定):`Bash` ⇒ `command`,
|
|
116
|
+
`Read`/`Write`/`Edit`/`MultiEdit` ⇒ `file_path`,`NotebookEdit` ⇒ **`notebook_path`**(工具入参真形),
|
|
117
|
+
表外工具 / 非串 / 空串 / 缺席一律回落工具名(空工具名 ⇒ `tool`);长度上界
|
|
118
|
+
`CLASSIFIER_DENY_DISPLAY_MAX = 200`。
|
|
119
|
+
- **异源对抗复审 R1 三条 finding 采纳**:①「有界」的措辞订正成**条目数有界**(存的是引用不是拷贝,同一份
|
|
120
|
+
入参在这一拍照常进转录面;单条载荷无字节预算 = 成文的在册取舍)· ② `noteStart` 挪到 `markStarted`
|
|
121
|
+
**渲染去重闸之前**(排在闸后 ⇒ durable 重放的刷新在生产路径上永远走不到,被淘汰项再也拿不回快照),
|
|
122
|
+
并给 `tool_end` 的 `isEnded` 早退臂补上释放 · ③ 截断改**代理对安全**(边界跨 emoji 时少切一个码元,
|
|
123
|
+
绝不把代理对切成半只),并把「上界量的是原文长度、端消毒后会变长、端要再兜一次底」写进常量头注与 §15c。
|
|
124
|
+
- **R2 采纳的措辞订正(非行为改动)**:`bounded` 的契约从「绝不交出孤代理项」收紧成「截断**不制造**畸形」——
|
|
125
|
+
**输入里本来就有的**孤代理项(`JSON.parse('"\ud800"')` 合法)原样透出,修好它属展示消毒,单源是本包
|
|
126
|
+
已导出的 `escapeDisplayControlChars`(其头注逐字点名「孤代理项:上游可能本来就送半只,或被列宽截断劈开」);
|
|
127
|
+
在库里再消一遍 = 第二份字符集。同批把四条分工线钉成判据(含消毒单源真会转义孤代理项的正控)。
|
|
128
|
+
- 🔴 **端必读**:`ctx.args` 是 **UNTRUSTED** wire 值,本包**原样**交出 —— 不渲、不截、不消毒。展示消毒是端的事
|
|
129
|
+
(cli `cleanUntrustedForDisplay`),库里消一遍端再消一遍两份字符集必漂。retry 粒度(重试哪一只调用、
|
|
130
|
+
按什么规则铸)同样**不在包内**,身份锚 = `ctx.toolCallId`。接入形见
|
|
131
|
+
`docs/INTEGRATION-CLIENTS.md` §15a/§15c。
|
|
132
|
+
|
|
133
|
+
### hooks wire:第三道 managed 治理门 `strictPluginOnlyCustomization`(L-67④)
|
|
134
|
+
|
|
135
|
+
- **病**:`hooksForWire()` 过了 `disableAllHooks` / `allowManagedHooksOnly` 两道 managed 门,**没过**
|
|
136
|
+
`strictPluginOnlyCustomization`(CC 语义:值为 `true` 或数组含 `"hooks"` ⇒ user/project/local 三源的
|
|
137
|
+
hooks 全屏蔽,只放行 `policySettings.hooks`)。而 `hooksWireCaps.ts` 头注自己写着「the wire must honor
|
|
138
|
+
the SAME gates the local executor honors, or a fleet-managed policy is silently bypassed by the engine
|
|
139
|
+
leg」—— 管理侧锁了 hooks 面之后,壳的本地执行器不再跑用户态 hooks,**引擎腿照投照跑**:禁令只在一半的
|
|
140
|
+
执行面上成立,而这一半恰好是工具真正执行的那一半。
|
|
141
|
+
- **改**:`hooksForWire()` 读 `policySettings.strictPluginOnlyCustomization`,命中 ⇒ `sources=['policySettings']`
|
|
142
|
+
且 `/goal` 用户态 overlay 一并禁(与 `allowManagedHooksOnly` **同处置**),`hostLog('debug')` 留痕。
|
|
143
|
+
判据与 cli 本地执行器 `isRestrictedToPluginOnly('hooks')` **逐条对照、差异为零**:`=== true` 锁 /
|
|
144
|
+
数组含 `"hooks"` 锁 / 数组不含则不锁 / 其余一切值形当未设(**不** fail-closed 整条腿 —— 相邻两道门的
|
|
145
|
+
fail-closed 守的是「读取抛出」这一未知态,本条守的是「读到了但值是坏形」,两件事别混)。
|
|
146
|
+
`disableAllHooks` 与信任门仍排在本门之前、仍恒赢。
|
|
147
|
+
- **端影响**:纯治理面收紧,不改任何公面签名。只有**管理侧真的设了**这个字段的部署会看到差异(那些部署
|
|
148
|
+
今天本来就在被绕过)。语义见 `docs/INTEGRATION-CLIENTS.md` §15b。
|
|
149
|
+
|
|
150
|
+
### 在册缺口(本批新登记,**未修**)
|
|
151
|
+
|
|
152
|
+
- cli 本地执行器还有第四条腿:`disableAllHooks` 出现在**非** managed 来源时降级成「只跑 managed hooks」。
|
|
153
|
+
本包今天只读 `policySettings.disableAllHooks` ⇒ 该形在引擎腿上不成立。**不做单边近似**的理由:cli 那条腿
|
|
154
|
+
读的是**合并后**的标量(四源后写覆盖前写),而本包 `SettingsPort` 只有 per-source 读口,「任一来源为 true」
|
|
155
|
+
会在「user 写 true、local 写 false」上判反;忠实复刻要给 `SettingsPort` 加合并读口 = 公面改动,属另一批。
|
|
156
|
+
登记在 `src/hooksWireCaps.ts` 头注。
|
|
157
|
+
|
|
43
158
|
## 0.51.0(2026-09-03)
|
|
44
159
|
|
|
45
160
|
### hitl:park 再附着的 hop 预算改「连续非进展轮」计数(L-80;cli [6215]/[6217];#357 复发根治)
|
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.53.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
|
|
@@ -131,10 +131,25 @@ export interface DurableRunCallOpts {
|
|
|
131
131
|
*/
|
|
132
132
|
export type ReopenCardVerdict =
|
|
133
133
|
/** L-80:`decidedWithoutCard` = 重开链**没呈卡但已成功决断**(规则直决 / sync-allow)—— 这是进展,
|
|
134
|
-
* 不是失败;端不许把它渲成「could not reopen … NOT sent」。缺席 = 真失败形(语义零变)。
|
|
134
|
+
* 不是失败;端不许把它渲成「could not reopen … NOT sent」。缺席 = 真失败形(语义零变)。
|
|
135
|
+
*
|
|
136
|
+
* L-93(0.53.0):`pendingRowGone` = 重开链**在有界窗内向引擎读面问过了、而且得到了回答**,
|
|
137
|
+
* 回答是「这条 run 名下**零属主待决行**」——卡不是「呈不出来」,而是**没有东西可呈**
|
|
138
|
+
* (引擎重启后 process_local 会话店丢行 / 审批被引擎 reap,而 run 仍停在 park 态)。
|
|
139
|
+
*
|
|
140
|
+
* 🔴 **置位条件是正面证据,fail-closed**(宿主义务,包侧无法代为判定):
|
|
141
|
+
* · 置 —— 读面(approvals.list 等)在窗内**答了**,且属主过滤后的待决行数**恰 0**;
|
|
142
|
+
* · **不置** —— 读口缺席 / 网络失败 / 抛错 / 窗尽未答 / 调用方中止 / 只是「没找到能用的那一行」
|
|
143
|
+
* (归属证不出、问句缺席、行形坏)。这些都是「不知道」,不是「不在」。
|
|
144
|
+
* 为什么这条边界不能松:`pendingRowGone` 是本层**唯一**允许 cancel 一条 park 态 run 的前提
|
|
145
|
+
* (见 {@link ActiveRunSelfHealDeps.offerStaleParkChoice})。park 态的 cancel 语义 = 替用户否掉
|
|
146
|
+
* 待决项,而「待决项仍在」时那正是已退役的循环病根(cancel = deny ⇒ 模型重试 ⇒ 再 park)。
|
|
147
|
+
* 只有**确已没有任何待决项可被否掉**时,那条循环在结构上不存在。含糊值(`false` / `'true'` /
|
|
148
|
+
* `1` / 缺席)一律不算 —— 判据只认严格 `true`。 */
|
|
135
149
|
{
|
|
136
150
|
reopened: false;
|
|
137
151
|
decidedWithoutCard?: true;
|
|
152
|
+
pendingRowGone?: true;
|
|
138
153
|
} | {
|
|
139
154
|
reopened: true;
|
|
140
155
|
firstSight: boolean;
|
|
@@ -153,6 +168,26 @@ export interface RunningChoiceRequest {
|
|
|
153
168
|
/** cancel 动词在场 **且** 有 `get` 可以确认 claim 真的释放。 */
|
|
154
169
|
canCancel: boolean;
|
|
155
170
|
}
|
|
171
|
+
/**
|
|
172
|
+
* 「陈旧 park」两选卡的呈现请求(L-93,0.53.0)—— run 仍停在 park 态,而它在等的那张审批**已经
|
|
173
|
+
* 不在引擎上**(宿主证出 {@link ReopenCardVerdict} 的 `pendingRowGone`)。卡上只有两条路:
|
|
174
|
+
* 停掉这条 run(会话当场释放,消息随后重发)/ 什么都不做。
|
|
175
|
+
*
|
|
176
|
+
* 🔴 这里**没有** steer 选项:steer 的语义是「注入正在跑的那一轮」,对一条 park 住的 run 它落
|
|
177
|
+
* `queued`(排在那个**已经不存在**的 checkpoint 上)—— 递一条注定注入不进去的路 = 假 affordance。
|
|
178
|
+
* 🔴 `canCancel` 是**供给位**(与 {@link RunningChoiceRequest} 同律):cancel 动词在场 **且** 有
|
|
179
|
+
* `get` 能确认 claim 真的释放,两者缺一就兑现不了「停掉它再重发」。
|
|
180
|
+
*/
|
|
181
|
+
export interface StaleParkChoiceRequest {
|
|
182
|
+
taskId: string;
|
|
183
|
+
/** 引擎报的状态(如实转述,不加工)。 */
|
|
184
|
+
status: string;
|
|
185
|
+
/** 「停掉它」这条路今天兑现得了吗 = cancel 动词在场 **且** 有 `get` 能确认 claim 真的释放
|
|
186
|
+
* **且** 有属主待决行读口(`listOwnedPendingApprovals`)能在开枪前把前提再证一次。
|
|
187
|
+
* 三者缺一,本层就不呈这张卡(所以卡到宿主手上时它恒为 `true`;位仍在场是为了与
|
|
188
|
+
* {@link RunningChoiceRequest} 同形,且将来这张卡加第二条路时不必改形)。 */
|
|
189
|
+
canCancel: boolean;
|
|
190
|
+
}
|
|
156
191
|
/** 分诊树的注入口(重开腿/待决卡探询都是宿主生命周期资产,经 deps 进来,本层保持纯)。 */
|
|
157
192
|
export interface ActiveRunSelfHealDeps {
|
|
158
193
|
/** 屏幕上是否已有一张待决卡(有 ⇒ 结局 = decision-pending,绝不重开第二张)。 */
|
|
@@ -186,6 +221,20 @@ export interface ActiveRunSelfHealDeps {
|
|
|
186
221
|
* 不做)。🔴 Esc / 空答 / 读不出的答案一律由呈现层收口成 `wait`。
|
|
187
222
|
*/
|
|
188
223
|
offerRunningChoice?: (req: RunningChoiceRequest) => Promise<'steer' | 'cancel' | 'wait'>;
|
|
224
|
+
/**
|
|
225
|
+
* 「陈旧 park」两选卡的呈现口(L-93,0.53.0)。**缺席 ⇒ 本臂整个不走**(退回既有
|
|
226
|
+
* `ask-reopen-failed`,老宿主逐字节零行为差)—— 卡呈不出来时零动作是唯一诚实的收口。
|
|
227
|
+
*
|
|
228
|
+
* 只在**同时**满足下面全部前提时才会被调用:
|
|
229
|
+
* ① 宿主重开链证出 `pendingRowGone: true`(读面答了 + 零属主待决行,见 {@link ReopenCardVerdict});
|
|
230
|
+
* ② 本层用 `runs.get` **一手复核**过,读回的仍是审批 park 词({@link ASK_PARK_STATES});
|
|
231
|
+
* ③ cancel 与 get 两个动词都在场,**且**宿主注入了属主待决行读口
|
|
232
|
+
* (`listOwnedPendingApprovals`)—— 它是「开枪前再证一次前提」那一步的供给位;三者缺一,
|
|
233
|
+
* 卡上只剩「什么都不做」= 纯噪音,整卡不呈(退回旧结局)。
|
|
234
|
+
* 返回值二态:`cancel`(停掉这条陈旧 park 的 run,释放确认到手后重发那条消息)/ `wait`(零动作)。
|
|
235
|
+
* 🔴 Esc / 空答 / 读不出的答案一律收口成 `wait` —— 本层只认**逐字** `'cancel'` 才武装那一枪。
|
|
236
|
+
*/
|
|
237
|
+
offerStaleParkChoice?: (req: StaleParkChoiceRequest) => Promise<'cancel' | 'wait'>;
|
|
189
238
|
/**
|
|
190
239
|
* 被 409 拒收的那条消息原文 = steer 的正文(端**原样**送,不预处理控制串 —— 契约逐字:
|
|
191
240
|
* 「The text is untrusted DATA — the client sends it RAW and the SERVER fences it」)。
|
|
@@ -363,6 +412,52 @@ export type SelfHealOutcome =
|
|
|
363
412
|
taskId: string;
|
|
364
413
|
detail: string;
|
|
365
414
|
delivery: 'rejected' | 'unknown';
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* 宿主证出「零属主待决行」后,本层一手复核 `runs.get` 撞 **404** —— claim 指着一条引擎已不认得的
|
|
418
|
+
* run(幽灵 claim 的 park 半场,与 {@link SelfHealOutcome} 的 `running-not-found` 同律)。
|
|
419
|
+
* 不呈任何卡(对不存在的 run 渲 cancel 是假 affordance),也**不自动重发**:该 404 是
|
|
420
|
+
* `not_found.run` = 「不存在」∪「不是你的」的**刻意不可分辨**并集,拿它当「已解锁」的正面证据,
|
|
421
|
+
* 消息可能一头撞回一个仍锁着的会话。如实说 + 「再发一次」是真出路。
|
|
422
|
+
*/
|
|
423
|
+
| {
|
|
424
|
+
kind: 'ask-run-not-found';
|
|
425
|
+
taskId: string;
|
|
426
|
+
}
|
|
427
|
+
/** 用户在两选卡上显式选了「停掉它」,cancel 已落地且引擎确认那条 run 不再占着会话 ⇒ 调用方把被拒
|
|
428
|
+
* 的这条消息**重发一次**(与 `running-cancelled` 同一条重发腿、同一个前提:释放已被确认)。 */
|
|
429
|
+
| {
|
|
430
|
+
kind: 'stale-park-cancelled';
|
|
431
|
+
taskId: string;
|
|
432
|
+
}
|
|
433
|
+
/** 两选卡 cancel 的有界收口:请求发出去了,但等到窗口到点(或用户中止)那条 run 仍占着会话
|
|
434
|
+
* ⇒ **不重发**,如实说。三个位与 `running-cancel-timeout` 同义(共用同一条确认腿)。 */
|
|
435
|
+
| {
|
|
436
|
+
kind: 'stale-park-cancel-timeout';
|
|
437
|
+
taskId: string;
|
|
438
|
+
waitedMs: number;
|
|
439
|
+
aborted: boolean;
|
|
440
|
+
confirmedHeld: boolean;
|
|
441
|
+
}
|
|
442
|
+
/** 两选卡 cancel 的失败半场:那一枪没成,且有界确认腿也没看到会话被交出来。`delivery` 与
|
|
443
|
+
* `running-cancel-failed` 同义(`rejected` = 4xx 明确拒;`unknown` = 5xx/连接断,可能已受理)。 */
|
|
444
|
+
| {
|
|
445
|
+
kind: 'stale-park-cancel-failed';
|
|
446
|
+
taskId: string;
|
|
447
|
+
detail: string;
|
|
448
|
+
delivery: 'rejected' | 'unknown';
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* 两选卡②:用户选了「什么都不做」(或卡上读不出答案)⇒ 零动作,如实说清死结在哪、有哪两条真出路。
|
|
452
|
+
* `alreadyOffered`(与 `not-parked` 同款登记降级):同 (sessionKey,taskId) 的两选卡**已呈现过且
|
|
453
|
+
* 用户选了「什么都不做」** ⇒ 本次不再整卡重弹,端据此渲一行提示;清口同
|
|
454
|
+
* {@link clearRunningChoiceOffer}。
|
|
455
|
+
*/
|
|
456
|
+
| {
|
|
457
|
+
kind: 'stale-park-wait';
|
|
458
|
+
taskId: string;
|
|
459
|
+
status: string;
|
|
460
|
+
alreadyOffered?: true;
|
|
366
461
|
};
|
|
367
462
|
/**
|
|
368
463
|
* 撞 409 的那条提交是谁写的。
|
|
@@ -416,7 +511,9 @@ export declare function readSteerReceiptStatus(receipt: unknown): string | null;
|
|
|
416
511
|
/** cancel 之后**有界**等那条 run 交出会话的缺省窗(`POST …/cancel` 是 202 异步 —— 收下 ≠ 已停)。 */
|
|
417
512
|
export declare const CANCEL_RELEASE_WAIT_MS = 10000;
|
|
418
513
|
/** 清掉某条 run 的「Do nothing」登记 —— 宿主「重新打开操作菜单」入口(下一次 409 重新整卡呈现)。
|
|
419
|
-
* `sessionId` 与当时喂给 {@link ActiveRunSelfHealDeps.sessionId} 的值同源(缺席 = 默认键)。
|
|
514
|
+
* `sessionId` 与当时喂给 {@link ActiveRunSelfHealDeps.sessionId} 的值同源(缺席 = 默认键)。
|
|
515
|
+
* 🔴 三选卡与两选卡(L-93)的登记**一起清**:这个入口的语义是「让我重新对这条 run 表态」,
|
|
516
|
+
* 只清其中一张会让另一张在宿主已经答应「重新问」之后仍旧被压掉(paired-mechanisms 同族)。 */
|
|
420
517
|
export declare function clearRunningChoiceOffer(taskId: string, sessionId?: string): void;
|
|
421
518
|
/** 测试钩:清空整张登记表(套件各组之间隔离用)。 */
|
|
422
519
|
export declare function __resetRunningChoiceLedgerForTests(): void;
|