@sema-agent/client-core 0.42.0 → 0.43.1
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 +125 -0
- package/README.md +1 -1
- package/dist/adapt/textStream.d.ts +11 -1
- package/dist/adapt/textStream.js +68 -2
- package/dist/adapt/wireShapes.d.ts +8 -0
- package/dist/adapt/wireShapes.js +8 -0
- package/dist/adapt.js +13 -2
- package/dist/hitl/askGateWire.d.ts +1 -0
- package/dist/hitl/askGateWire.js +15 -4
- package/dist/hitl/frameRouter.d.ts +59 -1
- package/dist/hitl/frameRouter.js +107 -3
- package/dist/hitl/gateLedger.d.ts +9 -0
- package/dist/hitl/gateLedger.js +3 -0
- package/dist/hitl/hitlHostSurface.d.ts +50 -0
- package/dist/hitl/hitlHostSurface.js +59 -0
- package/dist/hitl/parkResolver.js +14 -2
- package/dist/hitl/persistedRulesWire.d.ts +15 -0
- package/dist/hitl/persistedRulesWire.js +31 -0
- package/dist/hitl/toolApprovalWire.d.ts +320 -25
- package/dist/hitl/toolApprovalWire.js +307 -21
- package/docs/INTEGRATION-CLIENTS.md +216 -16
- package/package.json +1 -1
|
@@ -87,6 +87,56 @@ export declare function surfaceRememberNotApplied(): void;
|
|
|
87
87
|
* 已记进 docs/refactor/README.md 的宿主/上游工单表,本层不做旁路补偿(只做如实告知)。
|
|
88
88
|
*/
|
|
89
89
|
export declare function surfaceEditNotForwarded(): void;
|
|
90
|
+
/**
|
|
91
|
+
* 文案(测试锁字面)。措辞刻意描述**后果**,并且**只说证得出的话**(异源对抗复审四轮 [medium] 修):
|
|
92
|
+
* · 不写「这台引擎不支持」——能力位缺席有三种同形成因(宿主没接这个字段 / 探测还没回来 / 探测失败),
|
|
93
|
+
* 其中只有明确的 `false` 才勉强算「引擎说了不」。写成断言就是替引擎宣布一件没证据的事
|
|
94
|
+
* ([honest-absence-not-fabricated-zero]);改成 `could not be confirmed` 的未知口径。
|
|
95
|
+
* · 「审批本身过了」这句**只在 respond 真成功之后**才成立 —— 所以本通知的**发出时机**被移到
|
|
96
|
+
* `await respond(...)` 成功之后(见 `toolApprovalWire` 的调用点顶注),而不是丢键那一刻。
|
|
97
|
+
*/
|
|
98
|
+
export declare const RULE_NOT_SENT_WARN_TEXT = "your \"don't ask again\" choice was NOT sent to this engine \u2014 support for that rule form could not be confirmed. The approval itself went through, but you will be asked again";
|
|
99
|
+
/**
|
|
100
|
+
* 卡上选中了「不再询问」(编辑臂的自由文本 / 批臂的合取批),而**这台引擎的能力位没有确认**
|
|
101
|
+
* 那条兑付通道 ⇒ 编排层把持久臂整条丢掉、只送决断。
|
|
102
|
+
*
|
|
103
|
+
* 🔴 为什么这必须上屏而不是只记 debug(异源对抗复审三轮 [high] 采纳,0.43.0):它与
|
|
104
|
+
* {@link surfaceRememberNotApplied} 是**同一个病**——用户按下了一个明确的意图,系统把它静默
|
|
105
|
+
* 丢掉,然后下一次照旧弹卡。用户能得出的唯一结论是「这个功能坏了」或「我按错了」。卡上那一格
|
|
106
|
+
* 是**真 affordance**(offer 确实在场、确实可以走本地落规则那条路),被丢的只是**这条 wire
|
|
107
|
+
* 兑付通道** —— 所以正解不是把选项藏起来,是**如实说出来**。
|
|
108
|
+
* 🔴 **一条通知服务两条臂**(同形清剿):编辑臂(`respondFreeFormRules` 位缺席)与批臂
|
|
109
|
+
* (`respondBatchRuleOffers` 位缺席)此前都只写 debug —— 同一个病形两处存量,同批一起改。
|
|
110
|
+
* 🔴 决断本身**不受影响**(照常送达),所以文案第二句说清「审批过了,只是规则没存」——
|
|
111
|
+
* ⚠️ 正因为文案里有那句话,**调用时机必须在 `respond` 真成功之后**(异源对抗复审四轮 [medium]:
|
|
112
|
+
* 丢键那一刻就发,而随后 respond 抛错 ⇒ 决断其实**没有**落定,用户却已经读到「审批过了」,
|
|
113
|
+
* 可能按「工具已经在跑」继续操作)。调用点的时序契约见 `toolApprovalWire` 那一处。
|
|
114
|
+
* 🔴 文案**不说「引擎不支持」**:能力位缺席三种同形成因(宿主没接字段 / 探测未回 / 探测失败),
|
|
115
|
+
* 断言引擎的能力是没有证据的话 —— 用 `could not be confirmed` 的未知口径。
|
|
116
|
+
* 无宿主口(print/headless 没屏)⇒ 静默,与本文件其余 surface 同语义。
|
|
117
|
+
*/
|
|
118
|
+
export declare function surfaceRuleArmNotSent(): void;
|
|
119
|
+
/**
|
|
120
|
+
* 文案(测试锁字面)。与 {@link RULE_NOT_SENT_WARN_TEXT} **刻意分两条**:两者对用户的下一步建议不同 ——
|
|
121
|
+
* 那条说「这台引擎能不能收还不知道」(换台引擎/等探测就好了),本条说「你这次的选择**本身**没过
|
|
122
|
+
* 客户端那道核对」(卡口实现有问题或同时给了两个互斥选择,换台引擎也不会变)。折成一条会让任一方
|
|
123
|
+
* 谎报原因。措辞同样只说证得出的话:不猜是哪一种坏法,把两种都摆出来。
|
|
124
|
+
*/
|
|
125
|
+
export declare const RULE_NOT_SENT_REJECTED_WARN_TEXT = "your \"don't ask again\" choice was NOT sent \u2014 it did not pass the client-side check (the card returned a rule the engine never offered, an index that is not a batch offer, or two conflicting choices at once). The approval itself went through, but you will be asked again";
|
|
126
|
+
/**
|
|
127
|
+
* 卡上选中了「不再询问」,而那次选择**没过包内那道表核 / 互斥核**(报了引擎没 offer 过的文本、
|
|
128
|
+
* 下标不指向 batch offer、或文本臂与批臂同场)⇒ 编排层把持久臂整条丢掉、只送决断。
|
|
129
|
+
*
|
|
130
|
+
* 🔴 为什么这也必须上屏(异源对抗复审十轮 [medium] 采纳,0.43.0):它与
|
|
131
|
+
* {@link surfaceRuleArmNotSent} 是**同一个诚实性问题**,只是原因换了一个 —— 用户按下的明确意图
|
|
132
|
+
* 被系统丢掉,审批照常成功,下次照旧弹卡。此前这三条丢键路径**只写 `hostLog('error')`**:
|
|
133
|
+
* 那是给开发者看的诊断,**不是**给按下按钮的那个人的答复。
|
|
134
|
+
* 🔴 **时序契约与那条一致**:文案里有「审批本身过了」⇒ 只在 `await respond(...)` 真成功之后发。
|
|
135
|
+
* 🔴 **成因通常是卡口实现的 bug**(表外文本/坏下标/两臂同场都是宿主侧构造出来的),所以 `hostLog`
|
|
136
|
+
* 的那条 `error` 留痕**照旧保留** —— 两个受众,两条通道,谁都不顶替谁。
|
|
137
|
+
* 无宿主口(print/headless 没屏)⇒ 静默,与本文件其余 surface 同语义。
|
|
138
|
+
*/
|
|
139
|
+
export declare function surfaceRuleArmRejected(): void;
|
|
90
140
|
/**
|
|
91
141
|
* 中断 deny 的有界观察(壳侧单测 `hitlCancelDeny.test.ts` 的被测面;REF-CC-023 起两条决断腿共用)。
|
|
92
142
|
*
|
|
@@ -163,6 +163,65 @@ export function surfaceRememberNotApplied() {
|
|
|
163
163
|
export function surfaceEditNotForwarded() {
|
|
164
164
|
surfaceSelfClearingWarn(EDIT_NOT_FORWARDED_KEY, EDIT_NOT_FORWARDED_WARN_TEXT, EDIT_NOT_FORWARDED_TIMEOUT_MS);
|
|
165
165
|
}
|
|
166
|
+
/**
|
|
167
|
+
* 文案(测试锁字面)。措辞刻意描述**后果**,并且**只说证得出的话**(异源对抗复审四轮 [medium] 修):
|
|
168
|
+
* · 不写「这台引擎不支持」——能力位缺席有三种同形成因(宿主没接这个字段 / 探测还没回来 / 探测失败),
|
|
169
|
+
* 其中只有明确的 `false` 才勉强算「引擎说了不」。写成断言就是替引擎宣布一件没证据的事
|
|
170
|
+
* ([honest-absence-not-fabricated-zero]);改成 `could not be confirmed` 的未知口径。
|
|
171
|
+
* · 「审批本身过了」这句**只在 respond 真成功之后**才成立 —— 所以本通知的**发出时机**被移到
|
|
172
|
+
* `await respond(...)` 成功之后(见 `toolApprovalWire` 的调用点顶注),而不是丢键那一刻。
|
|
173
|
+
*/
|
|
174
|
+
export const RULE_NOT_SENT_WARN_TEXT = 'your "don\'t ask again" choice was NOT sent to this engine — support for that rule form could not be confirmed. The approval itself went through, but you will be asked again';
|
|
175
|
+
const RULE_NOT_SENT_KEY = 'hitl-rule-arm-not-sent';
|
|
176
|
+
/** 与 remember 那条同量级(都是「你以为记住了、其实没有」),取同一个时长。 */
|
|
177
|
+
const RULE_NOT_SENT_TIMEOUT_MS = 10_000;
|
|
178
|
+
/**
|
|
179
|
+
* 卡上选中了「不再询问」(编辑臂的自由文本 / 批臂的合取批),而**这台引擎的能力位没有确认**
|
|
180
|
+
* 那条兑付通道 ⇒ 编排层把持久臂整条丢掉、只送决断。
|
|
181
|
+
*
|
|
182
|
+
* 🔴 为什么这必须上屏而不是只记 debug(异源对抗复审三轮 [high] 采纳,0.43.0):它与
|
|
183
|
+
* {@link surfaceRememberNotApplied} 是**同一个病**——用户按下了一个明确的意图,系统把它静默
|
|
184
|
+
* 丢掉,然后下一次照旧弹卡。用户能得出的唯一结论是「这个功能坏了」或「我按错了」。卡上那一格
|
|
185
|
+
* 是**真 affordance**(offer 确实在场、确实可以走本地落规则那条路),被丢的只是**这条 wire
|
|
186
|
+
* 兑付通道** —— 所以正解不是把选项藏起来,是**如实说出来**。
|
|
187
|
+
* 🔴 **一条通知服务两条臂**(同形清剿):编辑臂(`respondFreeFormRules` 位缺席)与批臂
|
|
188
|
+
* (`respondBatchRuleOffers` 位缺席)此前都只写 debug —— 同一个病形两处存量,同批一起改。
|
|
189
|
+
* 🔴 决断本身**不受影响**(照常送达),所以文案第二句说清「审批过了,只是规则没存」——
|
|
190
|
+
* ⚠️ 正因为文案里有那句话,**调用时机必须在 `respond` 真成功之后**(异源对抗复审四轮 [medium]:
|
|
191
|
+
* 丢键那一刻就发,而随后 respond 抛错 ⇒ 决断其实**没有**落定,用户却已经读到「审批过了」,
|
|
192
|
+
* 可能按「工具已经在跑」继续操作)。调用点的时序契约见 `toolApprovalWire` 那一处。
|
|
193
|
+
* 🔴 文案**不说「引擎不支持」**:能力位缺席三种同形成因(宿主没接字段 / 探测未回 / 探测失败),
|
|
194
|
+
* 断言引擎的能力是没有证据的话 —— 用 `could not be confirmed` 的未知口径。
|
|
195
|
+
* 无宿主口(print/headless 没屏)⇒ 静默,与本文件其余 surface 同语义。
|
|
196
|
+
*/
|
|
197
|
+
export function surfaceRuleArmNotSent() {
|
|
198
|
+
surfaceSelfClearingWarn(RULE_NOT_SENT_KEY, RULE_NOT_SENT_WARN_TEXT, RULE_NOT_SENT_TIMEOUT_MS);
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* 文案(测试锁字面)。与 {@link RULE_NOT_SENT_WARN_TEXT} **刻意分两条**:两者对用户的下一步建议不同 ——
|
|
202
|
+
* 那条说「这台引擎能不能收还不知道」(换台引擎/等探测就好了),本条说「你这次的选择**本身**没过
|
|
203
|
+
* 客户端那道核对」(卡口实现有问题或同时给了两个互斥选择,换台引擎也不会变)。折成一条会让任一方
|
|
204
|
+
* 谎报原因。措辞同样只说证得出的话:不猜是哪一种坏法,把两种都摆出来。
|
|
205
|
+
*/
|
|
206
|
+
export const RULE_NOT_SENT_REJECTED_WARN_TEXT = 'your "don\'t ask again" choice was NOT sent — it did not pass the client-side check (the card returned a rule the engine never offered, an index that is not a batch offer, or two conflicting choices at once). The approval itself went through, but you will be asked again';
|
|
207
|
+
const RULE_NOT_SENT_REJECTED_KEY = 'hitl-rule-arm-rejected';
|
|
208
|
+
const RULE_NOT_SENT_REJECTED_TIMEOUT_MS = 10_000;
|
|
209
|
+
/**
|
|
210
|
+
* 卡上选中了「不再询问」,而那次选择**没过包内那道表核 / 互斥核**(报了引擎没 offer 过的文本、
|
|
211
|
+
* 下标不指向 batch offer、或文本臂与批臂同场)⇒ 编排层把持久臂整条丢掉、只送决断。
|
|
212
|
+
*
|
|
213
|
+
* 🔴 为什么这也必须上屏(异源对抗复审十轮 [medium] 采纳,0.43.0):它与
|
|
214
|
+
* {@link surfaceRuleArmNotSent} 是**同一个诚实性问题**,只是原因换了一个 —— 用户按下的明确意图
|
|
215
|
+
* 被系统丢掉,审批照常成功,下次照旧弹卡。此前这三条丢键路径**只写 `hostLog('error')`**:
|
|
216
|
+
* 那是给开发者看的诊断,**不是**给按下按钮的那个人的答复。
|
|
217
|
+
* 🔴 **时序契约与那条一致**:文案里有「审批本身过了」⇒ 只在 `await respond(...)` 真成功之后发。
|
|
218
|
+
* 🔴 **成因通常是卡口实现的 bug**(表外文本/坏下标/两臂同场都是宿主侧构造出来的),所以 `hostLog`
|
|
219
|
+
* 的那条 `error` 留痕**照旧保留** —— 两个受众,两条通道,谁都不顶替谁。
|
|
220
|
+
* 无宿主口(print/headless 没屏)⇒ 静默,与本文件其余 surface 同语义。
|
|
221
|
+
*/
|
|
222
|
+
export function surfaceRuleArmRejected() {
|
|
223
|
+
surfaceSelfClearingWarn(RULE_NOT_SENT_REJECTED_KEY, RULE_NOT_SENT_REJECTED_WARN_TEXT, RULE_NOT_SENT_REJECTED_TIMEOUT_MS);
|
|
224
|
+
}
|
|
166
225
|
/**
|
|
167
226
|
* cancel-by-deny 的「良性 no_pending」判据。**结构化 `.code` 为主,`instanceof` 只作加强,绝不替代**:
|
|
168
227
|
* - `.code` 是 client-core 自家 `HitlSafetyError` 的契约属性(hitlBridge.ts,REF-CC-036 起是闭集
|
|
@@ -3,7 +3,7 @@ import { publishQuestionFrame, registerLocalQuestionResponder, hasQuestionOverla
|
|
|
3
3
|
import { hostLog } from '../host.js';
|
|
4
4
|
import { surfaceFsApprovalAndDecide } from './toolApprovalWire.js';
|
|
5
5
|
import { observeCancelByDeny } from './hitlHostSurface.js';
|
|
6
|
-
import { isAskTool } from './frameRouter.js';
|
|
6
|
+
import { flushHeldWithInterruptRewrite, isAskTool } from './frameRouter.js';
|
|
7
7
|
import { approvalCallKey, askGateQuestionId } from './gateIdentity.js';
|
|
8
8
|
/** 一 turn 内最多循环这么多次 park(防御:引擎/模型病态连环提问时不无限 attach)。 */
|
|
9
9
|
const MAX_GATE_HOPS = 24;
|
|
@@ -286,7 +286,19 @@ export async function resolvePark(park, ctx) {
|
|
|
286
286
|
}
|
|
287
287
|
if (outcome.kind !== 'decided') {
|
|
288
288
|
hostLog('debug', `liveHitlAskWire: gate not decided (${outcome.kind}${'reason' in outcome ? `: ${outcome.reason}` : ''}) — fail-soft to suspended terminal`);
|
|
289
|
-
|
|
289
|
+
// 回退:毒化帧照旧渲染(= 修复前的诚实红)。
|
|
290
|
+
// 件 B(异源复审 finding 采纳):**五个排水出口一律走同一个中断感知出口** —— 本出口今天恒是
|
|
291
|
+
// park 批(走到这里的前提就是有一张 park),零-park 硬门必挡,所以是**语义等价的 no-op**;
|
|
292
|
+
// 写成统一形是为了「新开一个出口就绕过改写」这条病形从此在结构上不成立(常驻门:hitl F13-h
|
|
293
|
+
// 钉住 src 下 `flushHeld()` 的调用点恰好一处)。
|
|
294
|
+
const events = [
|
|
295
|
+
...flushHeldWithInterruptRewrite(led, {
|
|
296
|
+
terminal: park.pendingDone,
|
|
297
|
+
signal: ctx.signal,
|
|
298
|
+
// 模 B:`aborted` = 用户在门卡上按了 Esc(该 outcome 在包内的语义就是逐字这一条)。
|
|
299
|
+
gateAbortedByUser: outcome.kind === 'aborted',
|
|
300
|
+
}),
|
|
301
|
+
];
|
|
290
302
|
if (park.pendingDone) {
|
|
291
303
|
events.push(park.pendingDone);
|
|
292
304
|
}
|
|
@@ -56,6 +56,21 @@ export declare function persistedRulesLaneAvailable(baseUrl: string | undefined)
|
|
|
56
56
|
* 只查前者会在「7.11.0 且规则店在」的 worker 上渲出一个恒 404 的治理入口。
|
|
57
57
|
*/
|
|
58
58
|
export declare function persistedRulesGovernanceAvailable(baseUrl: string | undefined): boolean;
|
|
59
|
+
/** {@link readCcImportRedeemCounts} 的判决体:200 体上真读出来的落库/去重计数。 */
|
|
60
|
+
export interface CcImportRedeemCounts {
|
|
61
|
+
persisted: number;
|
|
62
|
+
deduped: number;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* cc-import redeem 200 体的兑付计数**双代归一读口**(server 7.46 未声明 BREAKING 的消费半场):
|
|
66
|
+
* · **新形**(server 7.46+):`result.members[]` 判别联合,member.status ∈ {'persisted','deduped'}
|
|
67
|
+
* (refused 不上 200 体 —— server 侧折进 404/503,见头注「404 禁按成因分支」);
|
|
68
|
+
* · **旧形**(≤7.45;SDK 7.2.0 `rules.d.ts` 仍此形):`result.persisted[]` / `result.deduped[]` 桶。
|
|
69
|
+
* · 纪律与 0.43.0 ruleOffers 窄读器同款:**新键(members)在场就按新键读** —— 即使全 0 也绝不
|
|
70
|
+
* 回落旧键;两形都缺 ⇒ `null`(诚实缺席,调用方渲 unknown,绝不渲 0/成功)。
|
|
71
|
+
* 入参吃 200 体的 `result` 字段(`unknown`:SDK 声明形已与真 wire 脱节,边界必须结构窄化)。
|
|
72
|
+
*/
|
|
73
|
+
export declare function readCcImportRedeemCounts(result: unknown): CcImportRedeemCounts | null;
|
|
59
74
|
/**
|
|
60
75
|
* 规则口失败的**处置分类**(不是成因分类)。SDK 的 typed 错误族按 `status` + `errorCode` 读,
|
|
61
76
|
* 结构读法(不 instanceof)—— 注入面可能是假件,bundling 下 instanceof 也不该是承重判据。
|
|
@@ -15,6 +15,37 @@ export function persistedRulesLaneAvailable(baseUrl) {
|
|
|
15
15
|
export function persistedRulesGovernanceAvailable(baseUrl) {
|
|
16
16
|
return engineCapTrue(baseUrl, 'permissionRulesRevoke') && engineCapTrue(baseUrl, 'permissionRules');
|
|
17
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* cc-import redeem 200 体的兑付计数**双代归一读口**(server 7.46 未声明 BREAKING 的消费半场):
|
|
20
|
+
* · **新形**(server 7.46+):`result.members[]` 判别联合,member.status ∈ {'persisted','deduped'}
|
|
21
|
+
* (refused 不上 200 体 —— server 侧折进 404/503,见头注「404 禁按成因分支」);
|
|
22
|
+
* · **旧形**(≤7.45;SDK 7.2.0 `rules.d.ts` 仍此形):`result.persisted[]` / `result.deduped[]` 桶。
|
|
23
|
+
* · 纪律与 0.43.0 ruleOffers 窄读器同款:**新键(members)在场就按新键读** —— 即使全 0 也绝不
|
|
24
|
+
* 回落旧键;两形都缺 ⇒ `null`(诚实缺席,调用方渲 unknown,绝不渲 0/成功)。
|
|
25
|
+
* 入参吃 200 体的 `result` 字段(`unknown`:SDK 声明形已与真 wire 脱节,边界必须结构窄化)。
|
|
26
|
+
*/
|
|
27
|
+
export function readCcImportRedeemCounts(result) {
|
|
28
|
+
const o = (result ?? {});
|
|
29
|
+
if (Array.isArray(o.members)) {
|
|
30
|
+
let persisted = 0;
|
|
31
|
+
let deduped = 0;
|
|
32
|
+
for (const m of o.members) {
|
|
33
|
+
const status = m?.status;
|
|
34
|
+
if (status === 'persisted')
|
|
35
|
+
persisted += 1;
|
|
36
|
+
else if (status === 'deduped')
|
|
37
|
+
deduped += 1;
|
|
38
|
+
}
|
|
39
|
+
return { persisted, deduped };
|
|
40
|
+
}
|
|
41
|
+
if (Array.isArray(o.persisted) || Array.isArray(o.deduped)) {
|
|
42
|
+
return {
|
|
43
|
+
persisted: Array.isArray(o.persisted) ? o.persisted.length : 0,
|
|
44
|
+
deduped: Array.isArray(o.deduped) ? o.deduped.length : 0,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
18
49
|
function errShape(e) {
|
|
19
50
|
const o = (e ?? {});
|
|
20
51
|
return {
|