@sema-agent/client-core 0.18.0 → 0.20.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/README.md +1 -1
- package/dist/adapt/arms.js +53 -11
- package/dist/adapt/ids.d.ts +1 -1
- package/dist/adapt/ids.js +11 -2
- package/dist/adapt/textStream.js +2 -2
- package/dist/adapt/toolCards.js +1 -1
- package/dist/adapt.d.ts +1 -1
- package/dist/adapt.js +2 -0
- package/dist/adapter/downstream/eventToSdkMessage.js +58 -0
- package/dist/attachmentsWireCaps.d.ts +73 -10
- package/dist/attachmentsWireCaps.js +188 -14
- package/dist/controlRouter.d.ts +45 -8
- package/dist/controlRouter.js +53 -21
- package/dist/hitl/askGateWire.d.ts +1 -1
- package/dist/hitl/askGateWire.js +1 -1
- package/dist/hitl/frameRouter.js +3 -1
- package/dist/hitl/hitlBridge.d.ts +19 -2
- package/dist/hitl/hitlBridge.js +37 -0
- package/dist/hitl/hitlHostSurface.d.ts +27 -0
- package/dist/hitl/hitlHostSurface.js +50 -10
- package/dist/hitl/parkResolver.d.ts +8 -1
- package/dist/hitl/parkResolver.js +26 -1
- package/dist/hitl/toolApprovalWire.d.ts +41 -4
- package/dist/hitl/toolApprovalWire.js +67 -5
- package/dist/seam.d.ts +44 -1
- package/dist/seam.js +6 -0
- package/dist/seatContract.d.ts +68 -8
- package/dist/seatContract.js +57 -2
- package/package.json +1 -1
|
@@ -75,31 +75,71 @@ const CANCEL_DENY_WARN_TIMEOUT_MS = 10_000;
|
|
|
75
75
|
* [paired-mechanisms-must-share-premise]:只给「显示」不给「清」,端各写各的清法必然漂。
|
|
76
76
|
* 无口(print/headless 没屏可上)⇒ 静默,与壳原文 `if (!store) return` 同语义。 */
|
|
77
77
|
function surfaceCancelDenyWarn() {
|
|
78
|
+
surfaceSelfClearingWarn(CANCEL_DENY_WARN_KEY, CANCEL_DENY_WARN_TEXT, CANCEL_DENY_WARN_TIMEOUT_MS);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* 「上屏一行 warning + 到点自清(仅当仍是本 key)」的**唯一**实现(FIX① 收编:此前只有
|
|
82
|
+
* cancel-by-deny 一处,新增 remember-not-applied 时若各写一遍,两处的自清时序必然漂 ——
|
|
83
|
+
* [paired-mechanisms-must-share-premise];顺带保住 TIMER③ 的裸定时器创建点基线不上涨)。
|
|
84
|
+
* 无宿主口 ⇒ 静默(print/headless 没屏可上,与壳原文 `if (!store) return` 同语义)。
|
|
85
|
+
*/
|
|
86
|
+
function surfaceSelfClearingWarn(key, text, timeoutMs) {
|
|
78
87
|
try {
|
|
79
88
|
const s = surfaceForCurrentSession();
|
|
80
89
|
if (!s)
|
|
81
90
|
return;
|
|
82
|
-
s.showNotice({
|
|
83
|
-
key: CANCEL_DENY_WARN_KEY,
|
|
84
|
-
text: CANCEL_DENY_WARN_TEXT,
|
|
85
|
-
color: 'warning',
|
|
86
|
-
priority: 'immediate',
|
|
87
|
-
timeoutMs: CANCEL_DENY_WARN_TIMEOUT_MS,
|
|
88
|
-
});
|
|
91
|
+
s.showNotice({ key, text, color: 'warning', priority: 'immediate', timeoutMs });
|
|
89
92
|
const timer = setTimeout(() => {
|
|
90
93
|
try {
|
|
91
|
-
s.clearNoticeIfCurrent(
|
|
94
|
+
s.clearNoticeIfCurrent(key);
|
|
92
95
|
}
|
|
93
96
|
catch {
|
|
94
97
|
/* fail-soft */
|
|
95
98
|
}
|
|
96
|
-
},
|
|
99
|
+
}, timeoutMs);
|
|
97
100
|
unrefTimer(timer);
|
|
98
101
|
}
|
|
99
102
|
catch {
|
|
100
|
-
/* fail-soft
|
|
103
|
+
/* fail-soft:上屏失败绝不再伤害它所依附的那条流 */
|
|
101
104
|
}
|
|
102
105
|
}
|
|
106
|
+
// ── FIX① (2026-08-07) —— allow_session 的「记住了没有」诚实回执 ────────────────────────────────
|
|
107
|
+
/** 文案(测试锁字面)。措辞刻意描述**后果**而不是内部机制:用户要知道的是「下次还会问」。 */
|
|
108
|
+
export const REMEMBER_NOT_APPLIED_WARN_TEXT = 'this session-wide allow was not remembered by the worker — you will be asked again for this tool';
|
|
109
|
+
const REMEMBER_NOT_APPLIED_KEY = 'hitl-remember-not-applied';
|
|
110
|
+
const REMEMBER_NOT_APPLIED_TIMEOUT_MS = 10_000;
|
|
111
|
+
/** 文案(测试锁字面)。"original" 是判据词:用户必须读到「跑的是原来那份」。 */
|
|
112
|
+
export const EDIT_NOT_FORWARDED_WARN_TEXT = 'your edited tool input was NOT forwarded — the tool is running with the ORIGINAL input you saw before editing';
|
|
113
|
+
const EDIT_NOT_FORWARDED_KEY = 'hitl-edit-not-forwarded';
|
|
114
|
+
/** 比 remember 那条久:它说的是「正在跑的东西和你批的不是同一份」,值得多留一会儿。 */
|
|
115
|
+
const EDIT_NOT_FORWARDED_TIMEOUT_MS = 20_000;
|
|
116
|
+
/**
|
|
117
|
+
* `allow_session` 决断的 ack 回报 `rememberApplied:false`(server 1.239 起诚实回显 —— 典型成因
|
|
118
|
+
* 是这条 run 没有 sessionId,grant 无处可落)。
|
|
119
|
+
*
|
|
120
|
+
* 🔴 为什么这必须上屏而不是只记 debug:三选卡第 2 项在用户心里签的是「本会话这个工具不再问我」。
|
|
121
|
+
* 记没落店而界面照渲「全放行」,就是**把一个没有发生的授权渲成发生了** —— 下一次弹卡时用户会以为
|
|
122
|
+
* 是 bug,更坏的是他可能因此养成「一路回车」的习惯。缺席(旧 server 不出这个位)= 未知,
|
|
123
|
+
* 按 [honest-absence-not-fabricated-zero] 一律不发通知,绝不把未知渲成失败。
|
|
124
|
+
* 无宿主口(print/headless 没屏)⇒ 静默,与 {@link surfaceCancelDenyWarn} 同语义。
|
|
125
|
+
*/
|
|
126
|
+
export function surfaceRememberNotApplied() {
|
|
127
|
+
surfaceSelfClearingWarn(REMEMBER_NOT_APPLIED_KEY, REMEMBER_NOT_APPLIED_WARN_TEXT, REMEMBER_NOT_APPLIED_TIMEOUT_MS);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* 「编辑并批准」带了 `updatedInput`,而 ack 回报 `updatedInputForwarded:false`(server 1.241 起
|
|
131
|
+
* 诚实回显)—— 引擎拿到的是**原始**入参。
|
|
132
|
+
*
|
|
133
|
+
* 🔴 这一条比 remember 那条严重一个量级,它是本批 codex 复审判的 [high]:用户在卡上把
|
|
134
|
+
* `rm -rf /tmp/x` 改成 `rm -rf /tmp/x/build` 然后按了批准,而真正执行的是他改之前那条。
|
|
135
|
+
* **事后没有 fail-closed 的余地**(allow 已经送达,工具已经在跑),所以唯一诚实的处置就是立刻
|
|
136
|
+
* 响亮地说出来 —— 静默(此前只写 debug 日志)等于让用户以为自己的编辑生效了。
|
|
137
|
+
* 上游的正位是让 server 在「带了 updatedInput 却转发不了」时 fail-closed 拒批;那属跨仓,
|
|
138
|
+
* 已记进 docs/refactor/README.md 的宿主/上游工单表,本层不做旁路补偿(只做如实告知)。
|
|
139
|
+
*/
|
|
140
|
+
export function surfaceEditNotForwarded() {
|
|
141
|
+
surfaceSelfClearingWarn(EDIT_NOT_FORWARDED_KEY, EDIT_NOT_FORWARDED_WARN_TEXT, EDIT_NOT_FORWARDED_TIMEOUT_MS);
|
|
142
|
+
}
|
|
103
143
|
/**
|
|
104
144
|
* cancel-by-deny 的「良性 no_pending」判据。**结构化 `.code` 为主,`instanceof` 只作加强,绝不替代**:
|
|
105
145
|
* - `.code` 是 client-core 自家 `HitlSafetyError` 的契约属性(hitlBridge.ts,REF-CC-036 起是闭集
|
|
@@ -25,7 +25,14 @@ import { type AskGateWireDeps, type GatePark } from './frameRouter.js';
|
|
|
25
25
|
* 开集腐蚀这个新判别位)。消费点只认 `'no_pending'` 为「已解决」,其余码(binding_mismatch 等)
|
|
26
26
|
* 是真需要重新呈现给人的失败,不能走「继续读流」这条路。
|
|
27
27
|
*/
|
|
28
|
-
|
|
28
|
+
/**
|
|
29
|
+
* 白名单的**运行期真源**(FIX② 2026-08-07 由三处散落的 `===` 收成一份元组)。
|
|
30
|
+
* 🔴 与 `hitlBridge.HitlSafetyError.code` 的联合是**同一个闭集的两半**:下方 `_gateFailureCodePins`
|
|
31
|
+
* 双向钉住,任何一边加员而另一边不跟 ⇒ 编译红。此前两边靠人肉同步,而不同步的可观测后果是
|
|
32
|
+
* 「新码被 `isGateFailureCode` 降成 undefined 后静默走文案兜底臂」—— 门里长得跟正常一模一样。
|
|
33
|
+
*/
|
|
34
|
+
export declare const GATE_FAILURE_CODES: readonly ["no_pending", "binding_mismatch", "wrong_gate", "bad_plan_edit", "empty_answer"];
|
|
35
|
+
export type GateFailureCode = (typeof GATE_FAILURE_CODES)[number];
|
|
29
36
|
export type GateOutcome = {
|
|
30
37
|
kind: 'decided';
|
|
31
38
|
gatedCallId?: string | undefined;
|
|
@@ -6,8 +6,33 @@ import { observeCancelByDeny } from './hitlHostSurface.js';
|
|
|
6
6
|
import { isAskTool } from './frameRouter.js';
|
|
7
7
|
/** 一 turn 内最多循环这么多次 park(防御:引擎/模型病态连环提问时不无限 attach)。 */
|
|
8
8
|
const MAX_GATE_HOPS = 24;
|
|
9
|
+
/**
|
|
10
|
+
* REF-CC-033:`GateOutcome` 的 `failed` 分支闭集判别码。来源两处:①本文件自己的
|
|
11
|
+
* 「pending 行取不到」早退(`surfaceGateAndDecide` 里 `!pending` 那条);②`HitlBridge` 抛出的
|
|
12
|
+
* `HitlSafetyError.code`(hitlBridge.ts 契约:`binding_mismatch|no_pending|wrong_gate|bad_plan_edit`
|
|
13
|
+
* ——该属性今天仍是开集 `string`,TYPESHAPE-07/REF-CC-036 候后续车锁死;这里落地前用
|
|
14
|
+
* `isGateFailureCode` 按闭集白名单过滤,不认得的值一律降级成 `undefined`,退回文案兜底,不让
|
|
15
|
+
* 开集腐蚀这个新判别位)。消费点只认 `'no_pending'` 为「已解决」,其余码(binding_mismatch 等)
|
|
16
|
+
* 是真需要重新呈现给人的失败,不能走「继续读流」这条路。
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* 白名单的**运行期真源**(FIX② 2026-08-07 由三处散落的 `===` 收成一份元组)。
|
|
20
|
+
* 🔴 与 `hitlBridge.HitlSafetyError.code` 的联合是**同一个闭集的两半**:下方 `_gateFailureCodePins`
|
|
21
|
+
* 双向钉住,任何一边加员而另一边不跟 ⇒ 编译红。此前两边靠人肉同步,而不同步的可观测后果是
|
|
22
|
+
* 「新码被 `isGateFailureCode` 降成 undefined 后静默走文案兜底臂」—— 门里长得跟正常一模一样。
|
|
23
|
+
*/
|
|
24
|
+
export const GATE_FAILURE_CODES = [
|
|
25
|
+
'no_pending',
|
|
26
|
+
'binding_mismatch',
|
|
27
|
+
'wrong_gate',
|
|
28
|
+
'bad_plan_edit',
|
|
29
|
+
/** FIX②:空作答被本地拦下(空 answers[] / 空 selected[] / 空 header)。 */
|
|
30
|
+
'empty_answer',
|
|
31
|
+
];
|
|
32
|
+
const _gateFailureCodePins = [true, true];
|
|
33
|
+
void _gateFailureCodePins;
|
|
9
34
|
function isGateFailureCode(v) {
|
|
10
|
-
return
|
|
35
|
+
return typeof v === 'string' && GATE_FAILURE_CODES.includes(v);
|
|
11
36
|
}
|
|
12
37
|
/**
|
|
13
38
|
* decide 的 `failed` 原因是不是「这个 gate 早就被解决了」(#110 缺陷② c 的判据)。
|
|
@@ -62,6 +62,7 @@
|
|
|
62
62
|
* 🔴 UNTRUSTED:gate args 为模型作文(service 已 redact),只渲染绝不回喂;决断只带 decision 枚举。
|
|
63
63
|
*/
|
|
64
64
|
import { type HitlClientLike } from './hitlBridge.js';
|
|
65
|
+
import type { ToolApprovalRespondAck } from '@sema-agent/sdk';
|
|
65
66
|
/** fs 写权限 gate 判定:未来的一等 kind(tool_approval)或按 toolName(server 桥首批=fs 写三件,
|
|
66
67
|
* [820] 表)。AskUserQuestion 永不进这里(ask 桥先判)。 */
|
|
67
68
|
export declare function isFsApprovalGate(gate: {
|
|
@@ -201,11 +202,47 @@ export declare const TOOL_APPROVAL_FRAME_KEYS_MIRROR: readonly ["type", "approva
|
|
|
201
202
|
export declare function isFromSubagent(frame: ToolApprovalFrame): boolean;
|
|
202
203
|
/** 三选卡决断 → respond 端点的 wire 枚举(server parseToolApprovalDecision)。 */
|
|
203
204
|
export type ToolApprovalRespondDecision = 'allow' | 'allow_session' | 'deny';
|
|
204
|
-
/**
|
|
205
|
+
/**
|
|
206
|
+
* POST /v1/tool-approvals/:id/respond 的注入面。
|
|
207
|
+
*
|
|
208
|
+
* 🔴 FIX①(2026-08-07):**SDK 6.3.0 起这是一等资源** `client.toolApprovals.respond`,返回
|
|
209
|
+
* `ToolApprovalRespondAck`(`{approvalId, delivery:"applied", decision, rememberApplied?,
|
|
210
|
+
* updatedInputForwarded?}`)。此前本位钉死 `Promise<void>` —— 于是 ack 上那两个**诚实位**在类型层
|
|
211
|
+
* 就不可能被读到:
|
|
212
|
+
* · `rememberApplied:false`(server 1.239)= allow_session 的 grant **没落店**(典型:无 sessionId)
|
|
213
|
+
* ⇒ 壳照渲「本会话全放行」就是把一个没发生的授权渲成发生了;
|
|
214
|
+
* · `updatedInputForwarded`(server 1.241)= 编辑后的 args 是否真被透传给引擎(措辞诚实:
|
|
215
|
+
* forwarded ≠ applied)。
|
|
216
|
+
* 返回型放宽成 `ack | void` 而不是硬钉 ack:**注入面的实现方**(旧 liveClient / mock / 测试桩)
|
|
217
|
+
* 回 void 仍然合法(assignable),消费端按 {@link readToolApprovalRespondAck} 结构化读,缺席=未知。
|
|
218
|
+
*/
|
|
205
219
|
export type RespondToolApprovalFn = (approvalId: string, decision: ToolApprovalRespondDecision, opts?: {
|
|
206
220
|
signal?: AbortSignal;
|
|
207
221
|
updatedInput?: unknown;
|
|
208
|
-
}) => Promise<void>;
|
|
222
|
+
}) => Promise<ToolApprovalRespondAck | void>;
|
|
223
|
+
/**
|
|
224
|
+
* respond 回执的**结构化读口**(wire 是 JSON:注入面可能是旧 liveClient 的 raw fetch,也可能是
|
|
225
|
+
* 比本包新一版的 SDK)。坏形一律降 `undefined` —— 与 `controlRouter.errCodes` 同族纪律:
|
|
226
|
+
* 「拿到一个不好用的值」不如「诚实地什么都没有」。两个可选布尔位非布尔时**单独**降缺席
|
|
227
|
+
* (它们直接决定要不要渲「本会话全放行」,透传一个 `'yes'` 字符串会让 `!== false` 这类读法说反话)。
|
|
228
|
+
*
|
|
229
|
+
* 🔴 `decision` 判到 **wire 三词闭集**而不是「是不是串」(codex 复审二轮):ack 上那两个布尔位会
|
|
230
|
+
* 触发**高危安全声明**(「工具正在用原始入参跑」),所以一个 `decision:'garbage'` 的回执绝不许被
|
|
231
|
+
* 当成合规 ack 放行。**相关性**(「这个 ack 是不是**这一次**审批的回执」)不在本函数判 —— 本函数
|
|
232
|
+
* 只认形,对不对得上由 {@link surfaceToolApprovalFrameAndRespond} 拿着 frame 与刚发出的 decision 核。
|
|
233
|
+
*/
|
|
234
|
+
export declare function readToolApprovalRespondAck(v: unknown): ToolApprovalRespondAck | undefined;
|
|
235
|
+
/**
|
|
236
|
+
* 一张 `tool_approval` 帧消费完的产物(FIX①,2026-08-07 **BREAKING**:此前是裸的
|
|
237
|
+
* `ToolApprovalRespondDecision | 'unresolved'` 字符串)。
|
|
238
|
+
* 迁移判据一句话:`const out = await surfaceToolApprovalFrameAndRespond(…); out.decision === 'deny'`。
|
|
239
|
+
*/
|
|
240
|
+
export interface ToolApprovalFrameOutcome {
|
|
241
|
+
/** 用户(或 fail-closed)落定的决断;`'unresolved'` = respond 没送达(引擎按 TTL 自决)。 */
|
|
242
|
+
decision: ToolApprovalRespondDecision | 'unresolved';
|
|
243
|
+
/** server 的 200 ack。**缺席 = 未知**(注入面回 void / 旧 server / respond 失败),绝不当成 false。 */
|
|
244
|
+
ack?: ToolApprovalRespondAck;
|
|
245
|
+
}
|
|
209
246
|
/** 结构性识别流上的 tool_approval 帧(named SSE frame,payload.type === 帧名;非 AgentEvent arm)。 */
|
|
210
247
|
export declare function isToolApprovalFrame(ev: unknown): ev is ToolApprovalFrame;
|
|
211
248
|
/**
|
|
@@ -215,6 +252,6 @@ export declare function isToolApprovalFrame(ev: unknown): ev is ToolApprovalFram
|
|
|
215
252
|
* fail-closed:卡面不可用(print 模式无卡口/enqueue 失败)⇒ 立刻 respond deny,不让引擎
|
|
216
253
|
* 干等 TTL。respond 自身失败(404=已过期/settled)⇒ 'unresolved'(诚实放行后续帧,引擎已自决)。
|
|
217
254
|
*
|
|
218
|
-
* @returns
|
|
255
|
+
* @returns {@link ToolApprovalFrameOutcome} —— 决断 + server ack(ack 缺席 = 未知,不是 false)。
|
|
219
256
|
*/
|
|
220
|
-
export declare function surfaceToolApprovalFrameAndRespond(frame: ToolApprovalFrame, respond: RespondToolApprovalFn, streamArgs: unknown | undefined, signal?: AbortSignal): Promise<
|
|
257
|
+
export declare function surfaceToolApprovalFrameAndRespond(frame: ToolApprovalFrame, respond: RespondToolApprovalFn, streamArgs: unknown | undefined, signal?: AbortSignal): Promise<ToolApprovalFrameOutcome>;
|
|
@@ -65,7 +65,7 @@ import { HitlBridge, HitlSafetyError, findPendingForTask } from './hitlBridge.js
|
|
|
65
65
|
import { hostLog } from '../host.js';
|
|
66
66
|
import { createSessionSlot, DEFAULT_SESSION_KEY } from '../sessionSlot.js';
|
|
67
67
|
import { readEngineActiveBgTasks } from '../fleet/fleetLedger.js';
|
|
68
|
-
import { observeCancelByDeny } from './hitlHostSurface.js';
|
|
68
|
+
import { observeCancelByDeny, surfaceRememberNotApplied, surfaceEditNotForwarded } from './hitlHostSurface.js';
|
|
69
69
|
/** fs 写权限 gate 判定:未来的一等 kind(tool_approval)或按 toolName(server 桥首批=fs 写三件,
|
|
70
70
|
* [820] 表)。AskUserQuestion 永不进这里(ask 桥先判)。 */
|
|
71
71
|
export function isFsApprovalGate(gate) {
|
|
@@ -312,6 +312,42 @@ export function isFromSubagent(frame) {
|
|
|
312
312
|
return true;
|
|
313
313
|
return typeof frame.sourceTaskId === 'string' && frame.sourceTaskId.length > 0;
|
|
314
314
|
}
|
|
315
|
+
/** 上面那个闭集的运行期真源(ack 判形要用;词表与类型由下方 `Covers` 双向钉住)。 */
|
|
316
|
+
const RESPOND_DECISIONS = ['allow', 'allow_session', 'deny'];
|
|
317
|
+
const _respondDecisionPins = [true, true];
|
|
318
|
+
void _respondDecisionPins;
|
|
319
|
+
function isRespondDecision(v) {
|
|
320
|
+
return typeof v === 'string' && RESPOND_DECISIONS.includes(v);
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* respond 回执的**结构化读口**(wire 是 JSON:注入面可能是旧 liveClient 的 raw fetch,也可能是
|
|
324
|
+
* 比本包新一版的 SDK)。坏形一律降 `undefined` —— 与 `controlRouter.errCodes` 同族纪律:
|
|
325
|
+
* 「拿到一个不好用的值」不如「诚实地什么都没有」。两个可选布尔位非布尔时**单独**降缺席
|
|
326
|
+
* (它们直接决定要不要渲「本会话全放行」,透传一个 `'yes'` 字符串会让 `!== false` 这类读法说反话)。
|
|
327
|
+
*
|
|
328
|
+
* 🔴 `decision` 判到 **wire 三词闭集**而不是「是不是串」(codex 复审二轮):ack 上那两个布尔位会
|
|
329
|
+
* 触发**高危安全声明**(「工具正在用原始入参跑」),所以一个 `decision:'garbage'` 的回执绝不许被
|
|
330
|
+
* 当成合规 ack 放行。**相关性**(「这个 ack 是不是**这一次**审批的回执」)不在本函数判 —— 本函数
|
|
331
|
+
* 只认形,对不对得上由 {@link surfaceToolApprovalFrameAndRespond} 拿着 frame 与刚发出的 decision 核。
|
|
332
|
+
*/
|
|
333
|
+
export function readToolApprovalRespondAck(v) {
|
|
334
|
+
if (v === null || typeof v !== 'object')
|
|
335
|
+
return undefined;
|
|
336
|
+
const o = v;
|
|
337
|
+
if (o.delivery !== 'applied')
|
|
338
|
+
return undefined;
|
|
339
|
+
if (typeof o.approvalId !== 'string' || o.approvalId.length === 0)
|
|
340
|
+
return undefined;
|
|
341
|
+
if (!isRespondDecision(o.decision))
|
|
342
|
+
return undefined;
|
|
343
|
+
return {
|
|
344
|
+
approvalId: o.approvalId,
|
|
345
|
+
delivery: 'applied',
|
|
346
|
+
decision: o.decision,
|
|
347
|
+
...(typeof o.rememberApplied === 'boolean' ? { rememberApplied: o.rememberApplied } : {}),
|
|
348
|
+
...(typeof o.updatedInputForwarded === 'boolean' ? { updatedInputForwarded: o.updatedInputForwarded } : {}),
|
|
349
|
+
};
|
|
350
|
+
}
|
|
315
351
|
/** 结构性识别流上的 tool_approval 帧(named SSE frame,payload.type === 帧名;非 AgentEvent arm)。 */
|
|
316
352
|
export function isToolApprovalFrame(ev) {
|
|
317
353
|
const e = ev;
|
|
@@ -365,7 +401,7 @@ function subagentBadgeFor(frame) {
|
|
|
365
401
|
* fail-closed:卡面不可用(print 模式无卡口/enqueue 失败)⇒ 立刻 respond deny,不让引擎
|
|
366
402
|
* 干等 TTL。respond 自身失败(404=已过期/settled)⇒ 'unresolved'(诚实放行后续帧,引擎已自决)。
|
|
367
403
|
*
|
|
368
|
-
* @returns
|
|
404
|
+
* @returns {@link ToolApprovalFrameOutcome} —— 决断 + server ack(ack 缺席 = 未知,不是 false)。
|
|
369
405
|
*/
|
|
370
406
|
export async function surfaceToolApprovalFrameAndRespond(frame, respond, streamArgs, signal) {
|
|
371
407
|
const toolName = typeof frame.toolName === 'string' ? frame.toolName : 'Write';
|
|
@@ -404,14 +440,40 @@ export async function surfaceToolApprovalFrameAndRespond(frame, respond, streamA
|
|
|
404
440
|
}
|
|
405
441
|
try {
|
|
406
442
|
// abort 后的 deny 仍要送达(引擎侧同款 cancel-by-deny)——不带已 aborted 的 signal。
|
|
407
|
-
await respond(frame.approvalId, decision, {
|
|
443
|
+
const raw = await respond(frame.approvalId, decision, {
|
|
408
444
|
...(signal && !signal.aborted ? { signal } : {}),
|
|
409
445
|
...(card.kind === 'allow' && card.updatedInput !== undefined ? { updatedInput: card.updatedInput } : {}),
|
|
410
446
|
});
|
|
411
|
-
|
|
447
|
+
// 🔴 相关性门(codex 复审二轮):ack 必须是**这一次**审批的回执 —— id 与决断词都要对上。
|
|
448
|
+
// 对不上的 ack(注入面串了别人的响应 / 坏 mock / raw-fetch 包装器复用了连接)如果照样被
|
|
449
|
+
// 消费,一次普通审批就能弹出「你的编辑没生效、工具正在用原始入参跑」这种强安全声明。
|
|
450
|
+
// 不匹配 ⇒ 整个 ack 丢弃(降成「未知」)+ 响亮留痕,绝不据此触发任何用户告警。
|
|
451
|
+
const parsed = readToolApprovalRespondAck(raw);
|
|
452
|
+
let ack = parsed;
|
|
453
|
+
if (parsed !== undefined && (parsed.approvalId !== frame.approvalId || parsed.decision !== decision)) {
|
|
454
|
+
hostLog('error', `liveToolApprovalWire: DISCARDING respond ack for ${frame.approvalId} — it does not correlate ` +
|
|
455
|
+
`(ack.approvalId=${parsed.approvalId} ack.decision=${parsed.decision}, sent decision=${decision}); ` +
|
|
456
|
+
'treating as "no ack" (unknown) — never surfacing a safety notice off an unrelated receipt');
|
|
457
|
+
ack = undefined;
|
|
458
|
+
}
|
|
459
|
+
// 🔴 FIX①:三选卡第 2 项在用户心里签的是「本会话这个工具不再问我」。server 说没记住时,
|
|
460
|
+
// 界面必须收敛那个承诺 —— 这里只发一条诚实通知(渲不渲「全放行」徽标由宿主按 ack 决定,
|
|
461
|
+
// ack 也随本函数返回值一起交出去)。ack 缺席(旧 server / void 注入面)= 未知,不发。
|
|
462
|
+
if (decision === 'allow_session' && ack?.rememberApplied === false) {
|
|
463
|
+
hostLog('debug', `liveToolApprovalWire: ${frame.approvalId} allow_session ack rememberApplied=false — grant not stored, surfacing honest notice`);
|
|
464
|
+
surfaceRememberNotApplied();
|
|
465
|
+
}
|
|
466
|
+
// 🔴 [high] 同族但更重的一位:用户**编辑过**入参并批准,而 server 说编辑没转发 ⇒ 引擎按
|
|
467
|
+
// 原始入参跑。批的那份 ≠ 跑的那份,对 Write/Edit/Bash 就是破坏性操作的入口。
|
|
468
|
+
// allow 已送达,事后无法 fail-closed ⇒ 唯一诚实的处置是立刻响亮告知(不是 debug 日志)。
|
|
469
|
+
if (card.kind === 'allow' && card.updatedInput !== undefined && ack?.updatedInputForwarded === false) {
|
|
470
|
+
hostLog('debug', `liveToolApprovalWire: ${frame.approvalId} edited args were NOT forwarded (ack.updatedInputForwarded=false) — the tool runs on the ORIGINAL input`);
|
|
471
|
+
surfaceEditNotForwarded();
|
|
472
|
+
}
|
|
473
|
+
return ack !== undefined ? { decision, ack } : { decision };
|
|
412
474
|
}
|
|
413
475
|
catch (e) {
|
|
414
476
|
hostLog('debug', `liveToolApprovalWire: respond(${decision}) failed for ${frame.approvalId}: ${String(e)} — engine self-settles (TTL/abort)`);
|
|
415
|
-
return 'unresolved';
|
|
477
|
+
return { decision: 'unresolved' };
|
|
416
478
|
}
|
|
417
479
|
}
|
package/dist/seam.d.ts
CHANGED
|
@@ -375,7 +375,50 @@ export type ChromeEvent = {
|
|
|
375
375
|
kind: 'plan_review_park';
|
|
376
376
|
laneProof: LaneProof;
|
|
377
377
|
result: unknown;
|
|
378
|
-
}
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* FIX⑦(2026-08-07,黑板 [3017]/[3020];core 5.14.0 design/171 新 `TaskEvent` 臂,server 7.4.0
|
|
381
|
+
* 起真上 SSE)——「**谁把什么喂进了这条 run**」的生命周期账本帧:objective / 实时 steer /
|
|
382
|
+
* nextTurn / parked-steer 续跑 / wake 五个载体共用一个投影点。
|
|
383
|
+
*
|
|
384
|
+
* 🔴 **本帧不带正文**(core 的臂里就没有 text 字段)—— 所以它归 chrome 而不是 transcript,
|
|
385
|
+
* 而且宿主**不许**据此铸任何一行「用户说了…」的转录:那会是替引擎编一句它没说过的话。
|
|
386
|
+
* 宿主消费义务(全部可选,fail-soft):把它记进会话审计/时间线(「12:03 operator 通过 steer
|
|
387
|
+
* 注入了一条指令」),或在 HUD 上闪一下。什么都不做也是合法的 —— 本臂存在的第一价值是
|
|
388
|
+
* **不再落 `unknown_arm` 被丢弃**(账本帧丢了,壳就说不出「这条 run 被谁插过话」)。
|
|
389
|
+
* `actor.hostAsserted` 是消费端唯一能判「这个署名可信吗」的位:渲署名而不渲这个位 = 把一个
|
|
390
|
+
* 未经验证的名字渲成可信的(core 自己的 `[from …]` 渲染就是靠它决定加不加 `(unverified)`)。
|
|
391
|
+
*/
|
|
392
|
+
| HumanInputChromeEvent;
|
|
393
|
+
/**
|
|
394
|
+
* `human_input` 臂的署名(core `ActorAssertion` 的投影;server 已 redact 后上帧)。
|
|
395
|
+
* 🔴 `hostAsserted` 是消费端**唯一**能判「这个署名可信吗」的位 —— 渲 `id` 而不渲它,
|
|
396
|
+
* 等于把一个未经验证的名字渲成可信的。
|
|
397
|
+
*/
|
|
398
|
+
export interface HumanInputActor {
|
|
399
|
+
id?: string;
|
|
400
|
+
hostAsserted?: boolean;
|
|
401
|
+
issuer?: string;
|
|
402
|
+
}
|
|
403
|
+
/** {@link ChromeEvent} 的 `human_input` 臂(具名:本仓 typeshape 门对内联匿名形有棘轮)。 */
|
|
404
|
+
export interface HumanInputChromeEvent {
|
|
405
|
+
kind: 'human_input';
|
|
406
|
+
laneProof: LaneProof;
|
|
407
|
+
/** 载体:objective / steer / next_turn / parked_steer / wake …(core 开集,原样透传)。 */
|
|
408
|
+
carrier: string;
|
|
409
|
+
inputId?: string;
|
|
410
|
+
sessionSeq?: number;
|
|
411
|
+
/** 入口来源(oa / cc-mcp / portal …)。 */
|
|
412
|
+
source?: string;
|
|
413
|
+
delivery?: string;
|
|
414
|
+
/** 宿主从入口凭据派生的身份串(server 已 redact)。UNTRUSTED-for-display。 */
|
|
415
|
+
issuer?: string;
|
|
416
|
+
actor?: HumanInputActor;
|
|
417
|
+
entryId?: string;
|
|
418
|
+
/** 引擎铸的**稳定事件身份** —— durable 腿按 `Last-Event-ID` 续读会重放同一条账本帧,宿主
|
|
419
|
+
* 落审计/时间线时**按这个键幂等**(`inputId`/`entryId` 都是可选位,靠不住)。 */
|
|
420
|
+
eventId?: string;
|
|
421
|
+
}
|
|
379
422
|
/** `ChromeEvent` 的判别键(臂名)—— 覆盖率断言与宿主装配自检都锚在它上。 */
|
|
380
423
|
export type ChromeArmKind = ChromeEvent['kind'];
|
|
381
424
|
/**
|
package/dist/seam.js
CHANGED
|
@@ -35,6 +35,12 @@ const CHROME_ARM_TABLE = {
|
|
|
35
35
|
prompt_suggestions: { required: false, duty: '推 composer 上方 chips(绝不回喂模型)' },
|
|
36
36
|
last_turn_usage: { required: true, duty: '落最近一次 turn 真 usage(statusline 回落源)' },
|
|
37
37
|
plan_review_park: { required: true, duty: '弹 plan 审批卡(fail-soft,不挡后续终态帧)' },
|
|
38
|
+
// FIX⑦:账本帧,**不带正文** ⇒ 义务是可选的(记进审计/时间线即可);🔴 硬约束是**不许**据此
|
|
39
|
+
// 铸转录行,渲署名时必须带上 `actor.hostAsserted` 的可信度标注。
|
|
40
|
+
human_input: {
|
|
41
|
+
required: false,
|
|
42
|
+
duty: '可选:记进会话审计/时间线(谁把什么喂进了这条 run)。绝不铸 transcript 行(本帧不带正文);渲署名必须跟渲 actor.hostAsserted 的可信度标注',
|
|
43
|
+
},
|
|
38
44
|
};
|
|
39
45
|
/**
|
|
40
46
|
* chrome 臂**覆盖率断言出口**(§8-1 裁决的一半:client-core 定接口不定实现)。
|
package/dist/seatContract.d.ts
CHANGED
|
@@ -143,7 +143,24 @@ export interface LocalSessionRecord {
|
|
|
143
143
|
uuid: string;
|
|
144
144
|
text: string;
|
|
145
145
|
}>;
|
|
146
|
+
/** [C111] B1(clay 裁「加」,2026-08-08):**快照提示位** —— `true` = 写入方(session-host)当时
|
|
147
|
+
* 确知该会话停在人门上(enterPark/reparkIfStillPending 盖戳,settleTurn 清);缺席 = **未知**
|
|
148
|
+
* (旧账本/旧端写的记录),**不是** `false` 的断言。消费端(recents/会话列表)只在 `true` 渲
|
|
149
|
+
* 「等审批」徽标,缺席/false 不渲 —— 绝不把未知渲成安全。重启恢复端必须先按引擎 approvals
|
|
150
|
+
* registry 对账再回写:盘上的 `parked` 是过去的声明,不直接当现势渲。 */
|
|
151
|
+
parked?: boolean;
|
|
146
152
|
}
|
|
153
|
+
/**
|
|
154
|
+
* `ToolPermissionRequest.requestId` 的**域词表**(FIX⑥,2026-08-07)—— 三端唯一真源。
|
|
155
|
+
*
|
|
156
|
+
* 🔴 前缀不是装饰:它**就是**决断的路由依据(session-host 按它挑 wire 动词)。一个域外的 requestId
|
|
157
|
+
* 意味着「这条决断无处可去」,所以校验器对它 fail-loud 而不是放行(此前门只校「是不是串」,
|
|
158
|
+
* 于是 desktop 早就在用的 `plan:` 既不在枚举里、也不会被任何一处说出来)。
|
|
159
|
+
*/
|
|
160
|
+
export declare const TOOL_PERMISSION_REQUEST_ID_DOMAINS: readonly ["live:", "durable:", "question:", "elicit:", "plan:"];
|
|
161
|
+
export type ToolPermissionRequestIdDomain = (typeof TOOL_PERMISSION_REQUEST_ID_DOMAINS)[number];
|
|
162
|
+
/** 读口:requestId → 它的域。未登记前缀 / 非串 ⇒ `undefined`(诚实缺席,绝不猜一个域)。 */
|
|
163
|
+
export declare function toolPermissionRequestIdDomain(requestId: unknown): ToolPermissionRequestIdDomain | undefined;
|
|
147
164
|
/** design/80 D-1 的 TOCTOU 绑定**对**(REF-CC-070:此前是两个互不相干的 optional,半个 pair 照样过门)。
|
|
148
165
|
* 一位承载整对 ⇒「只有 callId 没有 inputHash」在类型层不可表达,门里也不用再补联合判据。 */
|
|
149
166
|
export interface ToctouBinding {
|
|
@@ -154,8 +171,9 @@ export declare const TOCTOU_BINDING_KEYS: readonly ["callId", "inputHash"];
|
|
|
154
171
|
/** HITL request row (CC's `request` position is schema-gated by `S1`; ours is this shape, projected
|
|
155
172
|
* from the sema wire's PendingCheckpoint — see session-host). */
|
|
156
173
|
export interface ToolPermissionRequest {
|
|
157
|
-
/** Stable request key — echo back on respondToToolPermission.
|
|
158
|
-
* (the prefix is what routes the decision back to the right wire verb — see session-host)
|
|
174
|
+
/** Stable request key — echo back on respondToToolPermission. FIVE id domains, prefix-tagged
|
|
175
|
+
* (the prefix is what routes the decision back to the right wire verb — see session-host);
|
|
176
|
+
* 词表真源 = {@link TOOL_PERMISSION_REQUEST_ID_DOMAINS},读口 = {@link toolPermissionRequestIdDomain}:
|
|
159
177
|
* `live:<approvalId>` = LIVE in-band tool-approval face (frame rides the token
|
|
160
178
|
* stream; unanswered → engine fail-CLOSED deny at its TTL);
|
|
161
179
|
* `durable:<engineSessionId>:<callId>` = the durable checkpoint class (approvals inbox);
|
|
@@ -164,8 +182,14 @@ export interface ToolPermissionRequest {
|
|
|
164
182
|
* headless default `{answers:[]}` at the 5-min TTL, which is
|
|
165
183
|
* why leaving this family unrendered is silent, [1947] 红④);
|
|
166
184
|
* `elicit:<elicitationId>` = LIVE inbound-MCP elicitation (a server asks the user for
|
|
167
|
-
* form input mid-tool-call)
|
|
168
|
-
*
|
|
185
|
+
* form input mid-tool-call);
|
|
186
|
+
* `plan:<checkpointId>` = plan-review park(FIX⑥ 2026-08-07 补登记)—— 决断路由到
|
|
187
|
+
* `assistant.planReview`,**不是** `/decide`(server 对走错
|
|
188
|
+
* 门的调用回 409 `gate_not_plan_review`)。desktop 的
|
|
189
|
+
* session-host 早已在铸这个前缀,而本枚举只写了四域:
|
|
190
|
+
* 域表说四个、现实跑五个,靠「域外的行长什么样」做判断的
|
|
191
|
+
* 消费端于是各猜各的。
|
|
192
|
+
* The LIVE domains are same-replica + non-durable: a late/duplicate decision 404s, which the
|
|
169
193
|
* host treats as "already released" (dismiss), never as a retryable error. */
|
|
170
194
|
requestId: string;
|
|
171
195
|
sessionId: string;
|
|
@@ -589,6 +613,12 @@ export interface LocalSessionsApi {
|
|
|
589
613
|
/** Read-only model catalog (engine `GET /v1/models`). Empty `models` = the deployment offers no
|
|
590
614
|
* catalog; the renderer must degrade honestly rather than fall back to a fixture list. */
|
|
591
615
|
listModels(): Promise<SeatModelCatalog>;
|
|
616
|
+
/** [C115]/[C117] 模型配置写 verb:把选定的 catalog 条目落成宿主配置(settings.json env 块)。
|
|
617
|
+
* 写盘语义归宿主实现(desktop main 复用 cli buildModelEnv 键映射+updateSettingsForSource 锁形+
|
|
618
|
+
* RETIRED_MODEL_ENV_TOMBSTONES 墓碑);契约只定形与诚实位。🔴 req.apiKey 是敏感位:validator
|
|
619
|
+
* 校形不校值,任何 throw/log/ack 绝不回显 req(错误消息只说哪个键缺/形错,不带值);
|
|
620
|
+
* requiresRestart 必须如实渲(改完不重启=假 affordance)。 */
|
|
621
|
+
applyModelConfig(req: ApplyModelConfigRequest): Promise<ApplyModelConfigResult>;
|
|
592
622
|
onEvent(cb: (ev: LocalSessionEvent) => void): () => void;
|
|
593
623
|
onToolPermissionRequest(cb: (req: ToolPermissionRequest) => void): () => void;
|
|
594
624
|
/** `$store$` reactive states (read + subscribe; writes go through the verbs above). */
|
|
@@ -600,18 +630,43 @@ export declare function isLocalSessionRecord(s: unknown): s is LocalSessionRecor
|
|
|
600
630
|
export declare function isToolPermissionRequest(r: unknown): r is ToolPermissionRequest;
|
|
601
631
|
export declare function isLocalSessionEvent(v: unknown): v is LocalSessionEvent;
|
|
602
632
|
export declare function isAttachmentUploadReceipt(v: unknown): v is AttachmentUploadReceipt;
|
|
633
|
+
/** 与 cli applyOnboard.CatalogEntry 逐键同形(真源对齐:cli 侧以 satisfies 断言钉住两形不漂——
|
|
634
|
+
* 包不反向依赖壳,故此处独立铸型)。api 闭集;apiKey 敏感位(校形不校值,零回显)。 */
|
|
635
|
+
export interface SeatCatalogEntry {
|
|
636
|
+
providerId: string;
|
|
637
|
+
providerName: string;
|
|
638
|
+
baseUrl: string;
|
|
639
|
+
api: "anthropic-messages" | "openai-completions";
|
|
640
|
+
apiKey?: string;
|
|
641
|
+
modelId: string;
|
|
642
|
+
contextWindow: number;
|
|
643
|
+
maxTokens: number;
|
|
644
|
+
cheapHint?: boolean;
|
|
645
|
+
}
|
|
646
|
+
export interface ApplyModelConfigRequest {
|
|
647
|
+
defaultModel: SeatCatalogEntry;
|
|
648
|
+
/** 缺席 = 与 default 同(宿主不写 MODEL_CHEAP_ID)。 */
|
|
649
|
+
cheapModel?: SeatCatalogEntry;
|
|
650
|
+
}
|
|
651
|
+
export interface ApplyModelConfigResult {
|
|
652
|
+
ok: boolean;
|
|
653
|
+
/** ok:false 时必在(GUI 要能渲原因);同样零敏感值回显。 */
|
|
654
|
+
reason?: string;
|
|
655
|
+
/** 必须如实渲(改完不重启=假 affordance,[C115] 预登记)。 */
|
|
656
|
+
requiresRestart: boolean;
|
|
657
|
+
}
|
|
603
658
|
export declare function isSeatModelCatalog(v: unknown): v is SeatModelCatalog;
|
|
604
659
|
export declare function isSendMessageAck(v: unknown): v is SendMessageAck;
|
|
605
660
|
export declare const LOCAL_SESSIONS_SPEC: EipcServiceSpec;
|
|
606
661
|
/** verb 名清单 = `LOCAL_SESSIONS_SPEC.methods` 应有的键集(逐元素相等,门里断言)。 */
|
|
607
|
-
export declare const SEAT_METHOD_NAMES: readonly ["start", "sendMessage", "interrupt", "stop", "respondToToolPermission", "cancelQueuedMessage", "reorderQueuedMessage", "promoteQueuedMessage", "setFocusedSession", "setModel", "getTranscript", "searchSessions", "uploadAttachment", "listModels", "onEvent", "onToolPermissionRequest"];
|
|
662
|
+
export declare const SEAT_METHOD_NAMES: readonly ["start", "sendMessage", "interrupt", "stop", "respondToToolPermission", "cancelQueuedMessage", "reorderQueuedMessage", "promoteQueuedMessage", "setFocusedSession", "setModel", "getTranscript", "searchSessions", "uploadAttachment", "listModels", "applyModelConfig", "onEvent", "onToolPermissionRequest"];
|
|
608
663
|
/** `$store$` 属性名清单;SPEC 的 store 键 + `"Store"` 必须逐条等于这里的名字(门里断言)。 */
|
|
609
664
|
export declare const SEAT_STORE_PROPS: readonly ["sessionsStateStore", "focusedSessionStateStore", "settingsStateStore"];
|
|
610
665
|
/** 事件式(main→renderer push)的 verb —— SPEC 里 `kind: "event"` 的那一撮,门里逐元素对账。 */
|
|
611
666
|
export declare const SEAT_EVENT_METHOD_NAMES: readonly ["onEvent", "onToolPermissionRequest"];
|
|
612
667
|
export declare const LOCAL_SESSION_EVENT_KEYS: readonly ["type", "sessionId", "message", "messages", "error", "errorCategory", "code", "request", "data", "sources", "permissionMode", "session", "userMessageUuid", "hasPreClearSession", "requestId", "outcome", "chrome"];
|
|
613
668
|
export declare const TOOL_PERMISSION_REQUEST_KEYS: readonly ["requestId", "sessionId", "toolName", "toolCallId", "input", "message", "toctouBinding", "createdAtMs"];
|
|
614
|
-
export declare const LOCAL_SESSION_RECORD_KEYS: readonly ["sessionId", "engineSessionId", "model", "title", "isRunning", "createdAt", "lastActivityAt", "queuedMessages"];
|
|
669
|
+
export declare const LOCAL_SESSION_RECORD_KEYS: readonly ["sessionId", "engineSessionId", "model", "title", "isRunning", "createdAt", "lastActivityAt", "queuedMessages", "parked"];
|
|
615
670
|
export declare const SEND_MESSAGE_REQUEST_KEYS: readonly ["sessionId", "text", "model", "userMessageUuid", "permissionMode", "attachmentIds", "reasoningEffort", "retainBackgroundProcesses", "settings"];
|
|
616
671
|
export declare const TOOL_PERMISSION_DECISION_KEYS: readonly ["sessionId", "requestId", "decision", "answer", "updatedInput", "remember"];
|
|
617
672
|
export declare const START_SESSION_OPTION_KEYS: readonly ["model", "title", "cwd", "excludeTools"];
|
|
@@ -642,7 +697,7 @@ export declare const SEAT_VALIDATOR_KEY_COVERAGE: {
|
|
|
642
697
|
readonly LocalSessionRecord: {
|
|
643
698
|
readonly guard: "isLocalSessionRecord";
|
|
644
699
|
readonly check: (s: unknown) => SeatValidation;
|
|
645
|
-
readonly validated: readonly ["sessionId", "engineSessionId", "model", "title", "isRunning", "createdAt", "lastActivityAt", "queuedMessages"];
|
|
700
|
+
readonly validated: readonly ["sessionId", "engineSessionId", "model", "title", "isRunning", "createdAt", "lastActivityAt", "queuedMessages", "parked"];
|
|
646
701
|
readonly unchecked: readonly [];
|
|
647
702
|
};
|
|
648
703
|
readonly ToolPermissionRequest: {
|
|
@@ -675,6 +730,11 @@ export declare const SEAT_VALIDATOR_KEY_COVERAGE: {
|
|
|
675
730
|
readonly validated: readonly ["models", "defaultId"];
|
|
676
731
|
readonly unchecked: readonly [];
|
|
677
732
|
};
|
|
733
|
+
readonly ApplyModelConfigResult: {
|
|
734
|
+
readonly check: (v: unknown) => SeatValidation;
|
|
735
|
+
readonly validated: readonly ["ok", "requiresRestart", "reason"];
|
|
736
|
+
readonly unchecked: readonly [];
|
|
737
|
+
};
|
|
678
738
|
readonly SendMessageAck: {
|
|
679
739
|
readonly guard: "isSendMessageAck";
|
|
680
740
|
readonly check: (v: unknown) => SeatValidation;
|
|
@@ -754,6 +814,6 @@ export declare const SEAT_VALIDATOR_COVERAGE_EXEMPT: readonly [{
|
|
|
754
814
|
}, {
|
|
755
815
|
readonly label: "LaneProof";
|
|
756
816
|
readonly check: (v: unknown) => SeatValidation;
|
|
757
|
-
readonly why:
|
|
817
|
+
readonly why: string;
|
|
758
818
|
}];
|
|
759
819
|
export {};
|