@sema-agent/client-core 0.57.0 → 0.58.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 +174 -0
- package/README.md +7 -4
- package/dist/adapter/downstream/eventToSdkMessage.js +19 -0
- package/dist/engineErrorCodes.d.ts +15 -0
- package/dist/engineErrorCodes.js +15 -0
- package/dist/hitl/toolApprovalWire.d.ts +103 -91
- package/dist/hitl/toolApprovalWire.js +150 -14
- package/dist/index.d.ts +1 -0
- package/dist/index.js +5 -0
- package/dist/resumeRefusalCopy.d.ts +58 -0
- package/dist/resumeRefusalCopy.js +115 -0
- package/docs/INTEGRATION-CLIENTS.md +212 -14
- package/package.json +3 -3
|
@@ -78,7 +78,8 @@
|
|
|
78
78
|
* 🔴 方向纪律:reason/note 只做归因,绝不参与裁决;缺席 ⇒ 现状字节不变。
|
|
79
79
|
*/
|
|
80
80
|
import { type GateCurrentPending, type HitlClientLike } from './hitlBridge.js';
|
|
81
|
-
import
|
|
81
|
+
import { RULE_OFFER_MATCHES, RULE_OFFER_BATCH_MEMBER_KINDS, RULE_OFFER_UNCOVERED_REASONS } from '@sema-agent/sdk';
|
|
82
|
+
import type { RuleSuggestion, ToolApprovalRespondAck, PersistedRuleAnchor as SdkPersistedRuleAnchor, RuleOfferMatch as SdkRuleOfferMatch, RuleOfferBatchMember as SdkRuleOfferBatchMember, RuleOfferUncoveredDetail as SdkRuleOfferUncoveredDetail, RuleOfferUncoveredReason as SdkRuleOfferUncoveredReason } from '@sema-agent/sdk';
|
|
82
83
|
/** fs 写权限 gate 判定:未来的一等 kind(tool_approval)或按 toolName(server 桥首批=fs 写三件,
|
|
83
84
|
* [820] 表)。AskUserQuestion 永不进这里(ask 桥先判)。 */
|
|
84
85
|
export declare function isFsApprovalGate(gate: {
|
|
@@ -140,29 +141,68 @@ export interface FsApprovalWireDeps {
|
|
|
140
141
|
* 引用比较/JSON.stringify 串比较都会假报「编辑过」。 */
|
|
141
142
|
export declare function structurallyEqual(a: unknown, b: unknown): boolean;
|
|
142
143
|
/**
|
|
143
|
-
* 一条「不再询问」候选的匹配形(
|
|
144
|
+
* 一条「不再询问」候选的匹配形 —— **sdk 8.2.0 `RULE_OFFER_MATCHES` 派生**(四员闭词表:
|
|
145
|
+
* `exact` / `prefix` / `wildcard` / `subpath`)。
|
|
146
|
+
*
|
|
147
|
+
* 🔴 **B-025 的病形就在这一行**(0.43.0–0.57.0):本包按当时 server 的两员词表**手抄**
|
|
148
|
+
* `'exact' | 'prefix'`,而 core design/382 / #510 把词表扩到四员之后手抄的那份没跟 ⇒
|
|
149
|
+
* 一条合法的 `match:"wildcard"` single 会被 {@link readRuleTriple} 判成坏形**整条丢掉**,
|
|
150
|
+
* 卡上那一格「不再询问」凭空消失。词表属上游,消费端手抄一份就是给自己立第二个判官。
|
|
151
|
+
* 🔴 **比铸点更窄的消费型面就是一句谎**(sdk 8.2.0 头注逐字):server 的 wire 校验器
|
|
152
|
+
* `RuleMatchSchema = z.enum(PERSISTED_RULE_MATCHES)` 对这四个词一律放行 —— 更窄的型面
|
|
153
|
+
* 让 `switch` 在编译期自称穷尽,而运行期真会来第四个词。
|
|
154
|
+
* ⚠️ **端要跟的差分**:本类型从两员变四员是 0.58.0 唯一的非 additive 型面动作。在
|
|
155
|
+
* `RuleOfferMatch` 上写 `switch`/穷举的端会在 `wildcard`/`subpath` 两格上编译红 —— 那正是
|
|
156
|
+
* 要显形的东西(此前那两格在端上是**静默不可达**,因为本包在读器里就丢掉了)。
|
|
144
157
|
*/
|
|
145
|
-
export type RuleOfferMatch =
|
|
158
|
+
export type RuleOfferMatch = SdkRuleOfferMatch;
|
|
146
159
|
/**
|
|
147
|
-
* `batch` 臂的一个成员 ——
|
|
160
|
+
* `batch` 臂的一个成员 —— **sdk 8.2.0 `RuleOfferBatchMember` 判别联合**(core design/382 §2.3 B3):
|
|
161
|
+
* · `kind:'command'` —— 历史形:复合命令某一段的 Bash 规则(四座 + 判别位);
|
|
162
|
+
* · `kind:'directoryRead'` —— `cd <dir>` 段铸的**目录只读授权**(`rule` = 规范
|
|
163
|
+
* `Read(//dir/**)` 文本,`directory` = 词法规范绝对目录;本臂**没有** `match`/`command`)。
|
|
164
|
+
*
|
|
148
165
|
* `segment` = 这条成员是从哪一段折叠后的命令文本铸出来的:**渲染座,永不参与裁决**;
|
|
149
|
-
* 它与 `rule`/`command` 同属 **UNTRUSTED-for-display
|
|
150
|
-
*
|
|
166
|
+
* 它与 `rule`/`command`/`directory` 同属 **UNTRUSTED-for-display**。
|
|
167
|
+
*
|
|
168
|
+
* 🔴 **B-025 的第二半**:0.57.0 的成员形只认「三元组 + segment」、**没有** `directoryRead` 臂 ⇒
|
|
169
|
+
* 一只带 `directoryRead` 成员的合法 batch 被**整只丢掉**。本形改由 sdk 派生后该臂被认回。
|
|
170
|
+
* 🔴 **成员 `kind` 不识 ⇒ 丢整只 batch,绝不丢单个成员** —— 这是 core design/382 §2.3 的
|
|
171
|
+
* **规范性降级臂**(逐字:"drops the WHOLE batch offer — never the single member ... and never
|
|
172
|
+
* the whole card"),{@link readRuleOffers} 照此实现,判据钉在 run-rule-offers-reader 门里。
|
|
173
|
+
* ⚠️ **本包窄读器另收一条 pre-B3 兼容臂**:`kind` **缺席**的成员按 `kind:'command'` 归一
|
|
174
|
+
* (server ≥7.46.0 到 B3 落地之间铸的成员没有判别位;窄读域只许等于或宽于铸点域)。
|
|
175
|
+
* 归一形上 `kind` 恒在场 —— 端拿到的成员永远是判别联合,零分支差异。
|
|
151
176
|
*/
|
|
152
|
-
export
|
|
153
|
-
rule: string;
|
|
154
|
-
match: RuleOfferMatch;
|
|
155
|
-
command: string;
|
|
156
|
-
segment: string;
|
|
157
|
-
}
|
|
177
|
+
export type RuleOfferBatchMember = SdkRuleOfferBatchMember;
|
|
158
178
|
/**
|
|
159
|
-
*
|
|
179
|
+
* `uncoveredDetail` 的一行 —— **sdk 8.2.0 派生**(design/382 §3.5 additive 明细座)。
|
|
180
|
+
* `segment` = 折叠后的段原字节(UNTRUSTED-for-display,与成员 `segment` 同一条纪律),
|
|
181
|
+
* `reason` = 闭三词集 {@link RuleOfferUncoveredReason}。
|
|
182
|
+
*/
|
|
183
|
+
export type RuleOfferUncoveredDetail = SdkRuleOfferUncoveredDetail;
|
|
184
|
+
/** 「为什么这段仍未被覆盖」的闭三词集(server `UNCOVERED_SEGMENT_REASONS`,core 属主)。 */
|
|
185
|
+
export type RuleOfferUncoveredReason = SdkRuleOfferUncoveredReason;
|
|
186
|
+
/**
|
|
187
|
+
* 三张闭词表的**运行期**再导出(sdk 8.2.0 `as const` 单源)。
|
|
188
|
+
*
|
|
189
|
+
* 🔴 **端拿它做判定,别再手抄字面量** —— 本包自己的窄读器就读这两张表(B-025 的根因正是手抄);
|
|
190
|
+
* 再导出让三端与包**共用同一份数组对象**,词表加员时一处改、四处跟。
|
|
191
|
+
*/
|
|
192
|
+
export { RULE_OFFER_MATCHES, RULE_OFFER_BATCH_MEMBER_KINDS, RULE_OFFER_UNCOVERED_REASONS };
|
|
193
|
+
/**
|
|
194
|
+
* **wire 上的**一条 offer —— 与上游 sdk/core `RuleOffer` 逐字同形(**没有** `offerIndex`)。
|
|
160
195
|
*
|
|
161
196
|
* 🔴 为什么与归一形 {@link RuleOffer} 分开声明(异源对抗复审 [medium] 采纳):`offerIndex` 是
|
|
162
197
|
* **本包铸的座**(见 {@link RuleOffer} 顶注),把它写进 {@link ToolApprovalFrame.ruleOffers} 的
|
|
163
198
|
* 入参型 = 要求宿主为一个上游根本不发的字段负责 —— 真实 7.46.0 帧会**类型不合**,宿主只能强转,
|
|
164
199
|
* 或者自己伪造一个本该由窄读器按**当前这条腿**算出来的下标(而两条腿的下标语义还不一样)。
|
|
165
200
|
* ⇒ 入参面(帧/行)用本形,出参面(卡入参)用带下标的归一形,两者刻意不互相赋值。
|
|
201
|
+
*
|
|
202
|
+
* 🔴 **0.58.0(B-025)两处补形**,与 sdk 8.2.0 的 `RuleOffer` 逐字对齐:
|
|
203
|
+
* · batch 成员改用判别联合 {@link RuleOfferBatchMember}(`command` | `directoryRead`);
|
|
204
|
+
* · batch 臂补 **additive** `uncoveredDetail?`(缺席合法 —— server 对坏形的座**只丢座不丢批**,
|
|
205
|
+
* 所以缺席**不是**「没有未覆盖段」;真源恒是 `uncoveredSegments` 那个 count)。
|
|
166
206
|
*/
|
|
167
207
|
export type WireRuleOffer = {
|
|
168
208
|
kind: 'single';
|
|
@@ -173,19 +213,21 @@ export type WireRuleOffer = {
|
|
|
173
213
|
kind: 'batch';
|
|
174
214
|
rules: readonly RuleOfferBatchMember[];
|
|
175
215
|
uncoveredSegments: number;
|
|
216
|
+
uncoveredDetail?: readonly RuleOfferUncoveredDetail[];
|
|
176
217
|
};
|
|
177
218
|
/**
|
|
178
219
|
* 一张审批卡上的**一个**「不再询问」选项(core 5.58.0 design/375 §3.1 的判别联合,server ≥7.46.0
|
|
179
220
|
* 起在 `tool_approval` 帧 / `card_json` / durable park 行**三腿同形**发出)。
|
|
180
221
|
*
|
|
181
|
-
* ──
|
|
182
|
-
*
|
|
183
|
-
* `
|
|
184
|
-
*
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
* `@sema-agent/core
|
|
188
|
-
* `@sema-agent/server
|
|
222
|
+
* ── 为什么本包仍自铸这个形(记账,不是偷懒)──────────────────────────────────────────────
|
|
223
|
+
* **只为了多一位 `offerIndex`**。上游 wire 形的类型供给口 `@sema-agent/sdk` 自 **8.2.0** 起
|
|
224
|
+
* 已经把 `RuleOffer` / `RuleOfferMatch` / `RuleOfferBatchMember` / `RuleOfferUncoveredDetail`
|
|
225
|
+
* 一起补齐(S-134 锚②)⇒ 本形的**每一个成员类型**都已改由 sdk 派生(见上面四条),本联合
|
|
226
|
+
* 只在两臂上各加一位本包铸的座。0.43.0–0.57.0 那段「先追 server 不等 SDK」的自铸记账随
|
|
227
|
+
* `AHEAD_OF_ANCHOR` 的 `ruleOffers` 登记一起**在 0.58.0 退役**。
|
|
228
|
+
* 语义来源锚 = `@sema-agent/core` `dist/core/permission-rule-model.d.ts`(`RuleOffer` 逐字契约)+
|
|
229
|
+
* `@sema-agent/server` `dist/approval-card.d.ts`(两臂 zod 形与两条腿的下标语义)+
|
|
230
|
+
* sdk 8.2.0 `dist/resources/tool-approvals.d.ts`(同形的类型面锚)。
|
|
189
231
|
*
|
|
190
232
|
* ── `offerIndex` 是本包铸的座(上游形上没有这一位)──────────────────────────────────────
|
|
191
233
|
* core 的契约原话:消费端丢掉不认识的成员时**必须保住每个留下来成员的原始 wire 下标**,做不到就
|
|
@@ -193,6 +235,8 @@ export type WireRuleOffer = {
|
|
|
193
235
|
* 键就是**下标**(`persistRule.batchOfferIndex`)。本包的窄读器是**逐条丢坏的**(一条坏 offer 不该
|
|
194
236
|
* 让另一条真 offer 消失,与 server `boundedRuleOffers` 同向),压紧就会让下标前移 ⇒ 人点的第 k 个
|
|
195
237
|
* 与服务端兑的第 k 个指向两条不同规则。所以窄读时把**原始下标**显式记在这一位上,兑付时按它回报。
|
|
238
|
+
* ⚠️ **「逐条丢坏」是 offer 级的,不是成员级的**:一只 batch 里有一个 `kind` 不识的成员 ⇒ **整只
|
|
239
|
+
* batch 丢**(core design/382 §2.3 规范性降级臂,理由见 {@link RuleOfferBatchMember} 顶注)。
|
|
196
240
|
* 🔴 `offerIndex` 的定义域 = 「本包在**这条腿上**收到的那个数组里的下标」:
|
|
197
241
|
* · **活卡帧腿**(`ToolApprovalFrame.ruleOffers`):server 同步腿是纯前缀截、零逐条丢弃 ⇒ 它恒等于
|
|
198
242
|
* core 的 offer index,**是**合法选择键,`surfaceToolApprovalFrameAndRespond` 按它回兑;
|
|
@@ -214,12 +258,19 @@ export type RuleOffer = {
|
|
|
214
258
|
/** 见本联合顶注。**batch 臂的兑付就是按这个数**(文本不可抄:合取批没有单条文本)。 */
|
|
215
259
|
offerIndex: number;
|
|
216
260
|
/** 1..5 条逐段规则(段序,按规则文本去重)。勾这一项 = 对**全体成员**一次性说是,
|
|
217
|
-
* 合取批**没有成员级选中**(要更窄的答案就选 single 臂或只批这一次)。
|
|
261
|
+
* 合取批**没有成员级选中**(要更窄的答案就选 single 臂或只批这一次)。
|
|
262
|
+
* 🔴 成员是判别联合({@link RuleOfferBatchMember}):`command` 臂带 `match`/`command`,
|
|
263
|
+
* `directoryRead` 臂带 `directory` 且**没有**那两位 —— 端渲之前先读 `kind`。 */
|
|
218
264
|
rules: RuleOfferBatchMember[];
|
|
219
265
|
/** 铸卡时刻的诚实余量披露:这批兑完之后,按当时的覆盖快照仍未被任何规则放行的段数。
|
|
220
266
|
* 0 = 「兑完这批,这条复合命令在那份快照的口径下就全覆盖了」。它是**对铸卡快照的陈述**,
|
|
221
267
|
* 不是长期保证(并发删规则会让它过时)。 */
|
|
222
268
|
uncoveredSegments: number;
|
|
269
|
+
/** design/382 §3.5 **additive** 明细座(0.58.0 起透传)—— 逐段给闭三词集的因由。
|
|
270
|
+
* 🔴 **缺席 ≠ 「没有未覆盖段」**:server 对坏形的座**只丢座不丢批**,老引擎更是压根不铸;
|
|
271
|
+
* 真源恒是 {@link uncoveredSegments} 那个 count。在场时**行数不强制**等于 count
|
|
272
|
+
* (窄读器只丢坏行,不拿它反过来否决整只 batch —— additive 位绝不回头削弱既有位)。 */
|
|
273
|
+
uncoveredDetail?: readonly RuleOfferUncoveredDetail[];
|
|
223
274
|
};
|
|
224
275
|
/** 三选卡的原始决断(vendor 卡的三个选项 + abort + 表面失败)。allow_session=第 2 项
|
|
225
276
|
* (vendor 产出非空 permissionUpdates:setMode acceptEdits / cwd 外 addDirectories)。 */
|
|
@@ -627,8 +678,8 @@ export interface ToolApprovalFrame {
|
|
|
627
678
|
* 7.44 及更旧的引擎今天仍在场(pin 未抬的部署、混舰队)。新键在场时**本键整条不看**。
|
|
628
679
|
* 包内出口只有 {@link ApprovalCardRequest.ruleOffers} 一个,消费端不感知这次换键。
|
|
629
680
|
* 🔴 本键留在 interface 与 {@link TOOL_APPROVAL_FRAME_KEYS_MIRROR} 里**不是**遗留包袱:
|
|
630
|
-
* SDK
|
|
631
|
-
*
|
|
681
|
+
* SDK **8.2.0** 的运行期锚 `TOOL_APPROVAL_FRAME_KEYS` 仍含它(node 直读实证),删掉会让
|
|
682
|
+
* 对账门的「SDK 锚的每个键本仓都有」当场红 —— 退役登记要等 SDK 跟着 server 一起退。
|
|
632
683
|
*/
|
|
633
684
|
ruleSuggestions?: RuleSuggestion[];
|
|
634
685
|
/**
|
|
@@ -646,8 +697,10 @@ export interface ToolApprovalFrame {
|
|
|
646
697
|
* 🔴 文本由 ENGINE 铸,不由客户端拼:single 臂回决只能把 `rule` **原样**报回
|
|
647
698
|
* (`respond` 体 `persistRule.rule`,报表外文本 = server 拒 `rule_not_offered`);
|
|
648
699
|
* batch 臂没有单条文本可抄,回决报**下标**(`respond` 体 `persistRule.batchOfferIndex`)。
|
|
649
|
-
*
|
|
650
|
-
* `
|
|
700
|
+
* ✅ **锚已追平(0.58.0 / sdk 8.2.0 提货,S-134 锚②)**:sdk 8.2.0 的运行期锚
|
|
701
|
+
* `TOOL_APPROVAL_FRAME_KEYS` **已含本键**(node 直读 18 项实证),对账门
|
|
702
|
+
* (run-approval-frame-keys-test.mjs)的 `AHEAD_OF_ANCHOR` 登记按它自己的退出条件
|
|
703
|
+
* **随本批删除** —— 0.43.0–0.57.0 那条「先追 server 不等 SDK」的领先记账到此结清。
|
|
651
704
|
* 耐久路对偶 = `PendingCheckpoint.ruleOffers`(同契约、**下标语义不同**:那条腿 server 已逐条
|
|
652
705
|
* 丢弃压紧过,且无兑付口 ⇒ 下标只是展示座),由 {@link surfaceFsApprovalAndDecide} 消费。
|
|
653
706
|
*/
|
|
@@ -767,7 +820,7 @@ export interface ToolApprovalFrame {
|
|
|
767
820
|
* (帧 → {@link ApprovalCardRequest.inputHasBidi})。
|
|
768
821
|
* 🔴 判据**不看 `message`**(引擎/策略写的说明文本,不是待执行输入)——两个来源折进一个布尔会让
|
|
769
822
|
* 端无法判断该给哪一段加显形标记。
|
|
770
|
-
* 🔴 本键**领先** SDK 运行期锚一代(sdk
|
|
823
|
+
* 🔴 本键**领先** SDK 运行期锚一代(sdk 8.2.0 仍无)⇒ 对账门 AHEAD_OF_ANCHOR 带退出条件登记。
|
|
771
824
|
* 耐久路今天**无对偶**(server 7.46.0 的 `PendingCheckpoint`/`riskDescriptor` 均未声明本键;
|
|
772
825
|
* server 侧那份在**卡内**,不是行上的键)⇒ durable 行 → 卡那条腿不 stamp。
|
|
773
826
|
*/
|
|
@@ -914,78 +967,38 @@ export interface RespondToolApprovalOpts {
|
|
|
914
967
|
}
|
|
915
968
|
export type RespondToolApprovalFn = (approvalId: string, decision: ToolApprovalRespondDecision, opts?: RespondToolApprovalOpts) => Promise<ToolApprovalRespondAck | void>;
|
|
916
969
|
/**
|
|
917
|
-
* respond
|
|
970
|
+
* respond 回执的**包内视图**。
|
|
918
971
|
*
|
|
919
|
-
*
|
|
920
|
-
*
|
|
921
|
-
*
|
|
922
|
-
*
|
|
923
|
-
*
|
|
924
|
-
*
|
|
925
|
-
*
|
|
926
|
-
* 🔴
|
|
972
|
+
* 🔴 **0.58.0(sdk 8.2.0 提货)起本形已按它自己写下的退役条款回收 —— 现在它就是 sdk
|
|
973
|
+
* `ToolApprovalRespondAck` 本身**(别名保留只为源码兼容,端 import 的名字一个都不用改)。
|
|
974
|
+
* 0.43.0–0.57.0 它是一个 additive 超集,理由 = server ≤7.48.0 早已在回执上发的三位规范文本
|
|
975
|
+
* 回显(`persistedRule` / `persistedRules` / `persistedRuleAnchors`)当时**不在** sdk 声明里
|
|
976
|
+
* (与 `ruleOffers` 同一次锚滞后,§7d P-44 登记的那一族)。sdk 8.2.0 的 S-134 锚③把三位
|
|
977
|
+
* 一起补上(`dist/resources/tool-approvals.d.ts` 的 `ToolApprovalRespondAck` 逐字在场)⇒
|
|
978
|
+
* 退役条件满足,超集不再有存在理由(留着 = 两份会各自漂的同名形)。
|
|
979
|
+
* 🔴 **判形与窄读一个字节没改**:{@link readToolApprovalRespondAck} 的每一条纪律照旧 ——
|
|
980
|
+
* 三位规范文本回显**整只判形**(半份清单/半份归属表比没有更坏)、单复数**同场即互斥矛盾**、
|
|
981
|
+
* 回显在场而 `rulePersisted !== true` 即自相矛盾、锚与清单**逐位置同文本**。上游补的是**类型**,
|
|
982
|
+
* 不是判官:wire 是 JSON,sdk 的 optional 声明是 server 的承诺不是本层的前提。
|
|
983
|
+
* 🔴 **锚缺席时端的呈现口径**(0.44.0 立,退役后仍然成立,故留在此处):`persistedRuleAnchors`
|
|
984
|
+
* 缺席(≤7.47 引擎)时本包对 `persistedRules` 做到的相关性只有 **id + decision + 基数**
|
|
985
|
+
* ({@link surfaceToolApprovalFrameAndRespond} 的臂相关性门)—— 基数抓得到「少报/多报」,
|
|
986
|
+
* **抓不到**「条数对但内容是另一批规则」。⇒ 那种情形下端要把它渲成「**引擎报告**落盘的规则」,
|
|
987
|
+
* **不是**「你刚才选的那批规则」。锚在场时限制解除(`offerIndex` 已把清单钉在用户真选的那只 offer 上)。
|
|
927
988
|
*/
|
|
928
|
-
export
|
|
929
|
-
/**
|
|
930
|
-
* server ≥7.44(#340 编辑臂回显 `editedArmEcho`;7.46 沿用)——**编辑臂**兑付成功时,规则店里
|
|
931
|
-
* **真正落盘**的那条规范文本。
|
|
932
|
-
* 🔴 **界面要回显的是这一份,不是输入框里那一份**:core 会规范化人敲的拼写。
|
|
933
|
-
* 只在编辑臂 ∧ 兑付成功 ∧ 落的是 single 时在场;候选臂/批臂/失败/老 server ⇒ 缺席(≠ 空串)。
|
|
934
|
-
*/
|
|
935
|
-
persistedRule?: string;
|
|
936
|
-
/**
|
|
937
|
-
* server ≥7.46.0(design/377 批臂回执)——**批臂**兑付成功时落地的**全体**成员规范文本,
|
|
938
|
-
* **展示序**(= batch offer 的成员序,壳逐条回显)。「落地」含 persisted 与 deduped 两种
|
|
939
|
-
* (等价规则已在店 = 同意已生效)。
|
|
940
|
-
* 🔴 **复数是契约不是巧合**:合取批一次授权多条规则,把它折成一条(或只报第一条)会让人以为
|
|
941
|
-
* 自己只批了一条。非数组 / 含非串成员 / 空数组 ⇒ 整只降缺席(半份清单比没有清单更坏)。
|
|
942
|
-
* 非批臂 / 兑付失败 / 老 server ⇒ 字段省略;**缺席 ≠ 空**。
|
|
943
|
-
*
|
|
944
|
-
* ✅ **P-39 已到货**(server 7.48.0,client-core 本批):上游补的 additive 锚 =
|
|
945
|
-
* {@link ToolApprovalRespondAckView.persistedRuleAnchors}(每条带 `offerIndex` + `memberIndex`)。
|
|
946
|
-
* 本注按 `probeCause` 先例跟批收紧 —— 下面这段记的是**锚缺席时**(≤7.47 引擎)仍然成立的残余:
|
|
947
|
-
* 🔴 **锚缺席 ⇒ 逐条归属证不出**(异源对抗复审三轮 [medium] 登记的原始形)。那种情形下本包对这一位
|
|
948
|
-
* 做到的相关性只有 **id + decision + 基数**({@link surfaceToolApprovalFrameAndRespond} 的臂相关性
|
|
949
|
-
* 门):条数必须等于所选 batch 的成员数。基数抓得到「少报/多报」,**抓不到**「条数对但内容是
|
|
950
|
-
* 另一批规则」—— 因为回执上没有任何锚能把这 N 条与那只 offer 对上(文本等式在这一位上不成立:
|
|
951
|
-
* 落盘的是**规范化后**的文本,与 offer 上的文本按设计可以不同,拿文本去比就是装第二个判官)。
|
|
952
|
-
* 🔴 ⇒ **锚缺席时端的呈现口径**:把它渲成「**引擎报告**落盘的规则」,**不是**「你刚才选的那批规则」。
|
|
953
|
-
* 两句话在正常情形下指同一件事,但只有前一句是本包在无锚时能背书的。
|
|
954
|
-
* **锚在场时**这条限制解除:`offerIndex` 已经把这份清单钉在用户真选的那只 offer 上。
|
|
955
|
-
*/
|
|
956
|
-
persistedRules?: readonly string[];
|
|
957
|
-
/**
|
|
958
|
-
* server ≥7.48.0(P-39 正位解;#340/#334 批臂回执的**归属锚**)——批臂兑付成功时,每条落地规则
|
|
959
|
-
* 与它**出自哪只 offer 的哪个成员**的对应关系。
|
|
960
|
-
*
|
|
961
|
-
* 直证(engine 7.48.0 fixture `@sema-agent/server/dist/tool-approval.js`):park 迟到腿 `:1360` 与
|
|
962
|
-
* live 腿 `:1461` 两处逐字铸
|
|
963
|
-
* `persistedRuleAnchors: persisted.members.map(m => ({ offerIndex: persistRule.batchOfferIndex,
|
|
964
|
-
* memberIndex: m.memberIndex, rule: m.rule }))`。
|
|
965
|
-
* 🔴 **载体是 respond 的 200 体**(与 `rulePersisted`/`persistedRules` 同级),**不是帧** ——
|
|
966
|
-
* 所以它进的是本 ack 视图,不进 {@link TOOL_APPROVAL_FRAME_KEYS_MIRROR}。
|
|
967
|
-
* 🔴 **只在批臂 ∧ 兑付成功 ∧ server 交得出 `members` 时在场**;单臂/失败/老 server ⇒ 缺席
|
|
968
|
-
* (**缺席 ≠ 空数组**:空数组会被读成「一条都没落」)。
|
|
969
|
-
* 🔴 **整只判形**(与 `persistedRules` 同族):坏形一律整只降缺席 —— 半份归属表比没有更坏,
|
|
970
|
-
* 它驱动的断言是「这条规则出自**你选的那只批**」。判形见 {@link readPersistedRuleAnchors}。
|
|
971
|
-
* 🔴 它**不替代** `persistedRules`:后者是展示序的规范文本清单(端逐条回显的那一份),
|
|
972
|
-
* 本位是给**相关性门**用的归属证据。两位同场时条数必须一致,否则本位整只降缺席
|
|
973
|
-
* (additive 位绝不回头削弱既有位的现行为)。
|
|
974
|
-
*/
|
|
975
|
-
persistedRuleAnchors?: readonly PersistedRuleAnchor[];
|
|
976
|
-
}
|
|
989
|
+
export type ToolApprovalRespondAckView = ToolApprovalRespondAck;
|
|
977
990
|
/**
|
|
978
991
|
* {@link ToolApprovalRespondAckView.persistedRuleAnchors} 的成员形(server 7.48.0 逐字三键)。
|
|
979
992
|
*
|
|
993
|
+
* 🔴 **0.58.0 起直接是 sdk 8.2.0 的同名形**(S-134 锚③同批补;本包不再自铸)。此前本包自铸的
|
|
994
|
+
* 那份三键**逐字同形**,唯一差别是本包给三位钉了 `readonly` —— 别名化之后跟随 sdk 声明
|
|
995
|
+
* (读方源码兼容;本包自己的铸点仍只在 {@link readPersistedRuleAnchors} 一处,不外泄可写引用)。
|
|
996
|
+
*
|
|
980
997
|
* `offerIndex` = 兑付时发出去的 `persistRule.batchOfferIndex`(整表同值 —— server 的 map 闭包捕获的
|
|
981
998
|
* 就是那一个值);`memberIndex` = 该条在 batch offer 成员表里的下标;`rule` = **落盘后**的规范文本
|
|
982
999
|
* (与 `persistedRules` 的同序成员同值;规范化是引擎的活,本包不复判文本)。
|
|
983
1000
|
*/
|
|
984
|
-
export
|
|
985
|
-
readonly offerIndex: number;
|
|
986
|
-
readonly memberIndex: number;
|
|
987
|
-
readonly rule: string;
|
|
988
|
-
}
|
|
1001
|
+
export type PersistedRuleAnchor = SdkPersistedRuleAnchor;
|
|
989
1002
|
/**
|
|
990
1003
|
* respond 回执的**结构化读口**(wire 是 JSON:注入面可能是旧 liveClient 的 raw fetch,也可能是
|
|
991
1004
|
* 比本包新一版的 SDK)。坏形一律降 `undefined` —— 与 `controlRouter.errCodes` 同族纪律:
|
|
@@ -1198,4 +1211,3 @@ export interface ToolApprovalFrameLaneOpts {
|
|
|
1198
1211
|
windowIsCurrent?: boolean;
|
|
1199
1212
|
}
|
|
1200
1213
|
export declare function surfaceToolApprovalFrameAndRespond(frame: ToolApprovalFrame, respond: RespondToolApprovalFn, streamArgs: unknown | undefined, signal?: AbortSignal, lane?: ToolApprovalFrameLaneOpts): Promise<ToolApprovalFrameOutcome>;
|
|
1201
|
-
export {};
|
|
@@ -83,6 +83,14 @@ import { createSessionSlot, DEFAULT_SESSION_KEY } from '../sessionSlot.js';
|
|
|
83
83
|
import { readEngineActiveBgTasks } from '../fleet/fleetLedger.js';
|
|
84
84
|
import { observeCancelByDeny, surfaceRememberNotApplied, surfaceEditNotForwarded, surfaceRuleArmNotSent, surfaceRuleArmRejected } from './hitlHostSurface.js';
|
|
85
85
|
import { approvalCallKey, liveFrameCallKey } from './gateIdentity.js';
|
|
86
|
+
// ── sdk 8.2.0 单源闭词表(S-134 锚②;0.58.0 提货批 / B-025 修根)──────────────────────────────
|
|
87
|
+
// 🔴 **值级 import,不是 type-only**:三张 `as const` 数组是**运行期**判据(窄读器按它判 kind /
|
|
88
|
+
// match 是不是闭集成员)。本包此前把 `match` 的二词闭集**手抄**在读器里,而 core design/382 /
|
|
89
|
+
// #510 把词表扩到四员、batch 成员加了 `directoryRead` 臂 —— 手抄的那份没跟,合法候选被整条/
|
|
90
|
+
// 整只丢掉(B-025)。单源化之后「词表加员」这件事在**上游一处**发生,本包跟着走。
|
|
91
|
+
// 🔴 值级 import 的代价已记账:peer 地板随本批抬到 `>=8.2.0`(run-sdk-floor-test.mjs 的 ①c 把
|
|
92
|
+
// 声明与门常量逐位绑死),包总入口闭包的外部包集合仍恒等于 `{diff, @sema-agent/sdk}`(singleton 门)。
|
|
93
|
+
import { RULE_OFFER_MATCHES, RULE_OFFER_BATCH_MEMBER_KINDS, RULE_OFFER_UNCOVERED_REASONS } from '@sema-agent/sdk';
|
|
86
94
|
/** fs 写权限 gate 判定:未来的一等 kind(tool_approval)或按 toolName(server 桥首批=fs 写三件,
|
|
87
95
|
* [820] 表)。AskUserQuestion 永不进这里(ask 桥先判)。 */
|
|
88
96
|
export function isFsApprovalGate(gate) {
|
|
@@ -132,6 +140,13 @@ export function structurallyEqual(a, b) {
|
|
|
132
140
|
return false;
|
|
133
141
|
return ka.every(k => structurallyEqual(a[k], b[k]));
|
|
134
142
|
}
|
|
143
|
+
/**
|
|
144
|
+
* 三张闭词表的**运行期**再导出(sdk 8.2.0 `as const` 单源)。
|
|
145
|
+
*
|
|
146
|
+
* 🔴 **端拿它做判定,别再手抄字面量** —— 本包自己的窄读器就读这两张表(B-025 的根因正是手抄);
|
|
147
|
+
* 再导出让三端与包**共用同一份数组对象**,词表加员时一处改、四处跟。
|
|
148
|
+
*/
|
|
149
|
+
export { RULE_OFFER_MATCHES, RULE_OFFER_BATCH_MEMBER_KINDS, RULE_OFFER_UNCOVERED_REASONS };
|
|
135
150
|
// W1(design/161):sessionKey → 注册表;零参 API = DEFAULT_SESSION_KEY 兼容层(cli 装配不动)。
|
|
136
151
|
const cardPortByKey = createSessionSlot();
|
|
137
152
|
const cardPortMissesByKey = new Map();
|
|
@@ -424,16 +439,16 @@ export const TOOL_APPROVAL_FRAME_KEYS_MIRROR = [
|
|
|
424
439
|
'governanceForced',
|
|
425
440
|
// sdk 6.14.0 追平(#225 件1,client-core 0.26.0):server 7.12.0 起真发规则候选 —— 门
|
|
426
441
|
// (run-approval-frame-keys-test.mjs)在 bump SDK 当天恰红抓获本键缺席,本次补齐。
|
|
427
|
-
// ⚠️ **退役键**(server 7.46.0 起同文件 0 命中):留在镜像里是因为 sdk
|
|
442
|
+
// ⚠️ **退役键**(server 7.46.0 起同文件 0 命中):留在镜像里是因为 sdk 8.2.0 的运行期锚仍含它,
|
|
428
443
|
// 删了对账门的「SDK 锚的每个键本仓都有」当场红;本包对它只做归一读(见帧上同名键的 JSDoc)。
|
|
429
444
|
'ruleSuggestions',
|
|
430
445
|
// #334/[5223](client-core 0.43.0):server 7.46.0 起把规则候选整体换成判别联合 `ruleOffers`
|
|
431
446
|
// (core 5.58.0 design/375;engine 7.46.0 fixture 的 `@sema-agent/server/dist/tool-approval.d.ts`
|
|
432
|
-
// 直证,同文件旧键 0 命中)
|
|
433
|
-
//
|
|
447
|
+
// 直证,同文件旧键 0 命中)。✅ **sdk 8.2.0 锚已含本键**(S-134 锚②)⇒ 0.58.0 提货批按退出
|
|
448
|
+
// 条件删掉了对账门里那条 AHEAD_OF_ANCHOR 领先登记,本键回到「逐元素相等」的常态。
|
|
434
449
|
'ruleOffers',
|
|
435
450
|
// #341/[5214]③(client-core 0.43.0):server 7.46.0 起真发 `inputHasBidi`(E-14 Trojan Source 族;
|
|
436
|
-
// 7.44 fixture 同文件 0 命中)
|
|
451
|
+
// 7.44 fixture 同文件 0 命中)。仍**领先** sdk 8.2.0 锚(node 直读 18 项无本键)⇒ AHEAD_OF_ANCHOR 登记。
|
|
437
452
|
'inputHasBidi',
|
|
438
453
|
// 🔴 **同形族扫的产物**(client-core 0.43.0,[same-shape-residue-constitution]):本批的病形是
|
|
439
454
|
// 「镜像滞后于 server 实发键」。族扫 = 把 engine 7.46.0 fixture 的 `ToolApprovalFrame` 23 个声明键
|
|
@@ -463,7 +478,7 @@ export const TOOL_APPROVAL_FRAME_KEYS_MIRROR = [
|
|
|
463
478
|
'requiresRealApproval',
|
|
464
479
|
// [4851] 头号请托(client-core 0.38.2):server 7.34.0 起真发窗三键(#288/[4429]② cli 自己请托,
|
|
465
480
|
// server src/tool-approval.ts 三键声明+条件 stamp)。⚠️ 与 requiresRealApproval 同形=**领先** SDK
|
|
466
|
-
// 运行期锚(sdk
|
|
481
|
+
// 运行期锚(sdk 8.2.0 锚 18 项,node 直读实证无三键)⇒ 进对账门 AHEAD_OF_ANCHOR 带退出条件登记
|
|
467
482
|
// (SDK 追平当天登记自红逼删)。0.38.1 把三键丢在包边界外 = [4845]「卡到期屏幕零反应」的直接成因
|
|
468
483
|
// (壳读器 readAskDeadlineMs 早已预埋,缺的一直是包边界这一格——#283 逐字同形第四例)。
|
|
469
484
|
'expiresInMs',
|
|
@@ -816,8 +831,22 @@ function isWireRecordCarrier(v) {
|
|
|
816
831
|
return typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
817
832
|
}
|
|
818
833
|
/**
|
|
819
|
-
*
|
|
820
|
-
*
|
|
834
|
+
* `match` 是不是**闭词表成员** —— 表来自 sdk 8.2.0 `RULE_OFFER_MATCHES`(`exact` / `prefix` /
|
|
835
|
+
* `wildcard` / `subpath`),**本包不再手抄字面量**。
|
|
836
|
+
*
|
|
837
|
+
* 🔴 **B-025 的根因就是手抄**:0.43.0 铸这只读器时按当时 server 的两员词表写死
|
|
838
|
+
* `match !== 'exact' && match !== 'prefix'`,core design/382 / #510 扩到四员之后这里没跟 ⇒
|
|
839
|
+
* 一条合法的 `wildcard` / `subpath` 候选被判成坏形丢掉。读同一张 `as const` 数组之后,
|
|
840
|
+
* 「词表加员」在上游一处发生,本包自动跟上;门里另有**双向全等钉**(本包认的词集 ≡ sdk 数组
|
|
841
|
+
* 成员集,任一侧加员而另一侧没跟 ⇒ 当场红)。
|
|
842
|
+
*/
|
|
843
|
+
function isRuleOfferMatch(v) {
|
|
844
|
+
return typeof v === 'string' && RULE_OFFER_MATCHES.includes(v);
|
|
845
|
+
}
|
|
846
|
+
/**
|
|
847
|
+
* 一条 `single` offer / 一个 `command` 成员共用的三位窄化(`rule` 非空串 + `match` **四词闭集** +
|
|
848
|
+
* `command` 非空串)。任一不合形 ⇒ `undefined`(半条候选渲出来是一格没有正文、按下去必被 server
|
|
849
|
+
* 拒的选项)。
|
|
821
850
|
*/
|
|
822
851
|
function readRuleTriple(v) {
|
|
823
852
|
if (v === null || typeof v !== 'object')
|
|
@@ -825,13 +854,94 @@ function readRuleTriple(v) {
|
|
|
825
854
|
const o = v;
|
|
826
855
|
if (typeof o.rule !== 'string' || o.rule === '')
|
|
827
856
|
return undefined;
|
|
828
|
-
if (o.match
|
|
857
|
+
if (!isRuleOfferMatch(o.match))
|
|
829
858
|
return undefined;
|
|
830
859
|
// 上游形上 `command` 必填(渲染用的命令模式)——缺席/非串 ⇒ 整项不合形丢弃。
|
|
831
860
|
if (typeof o.command !== 'string' || o.command === '')
|
|
832
861
|
return undefined;
|
|
833
862
|
return { rule: o.rule, match: o.match, command: o.command };
|
|
834
863
|
}
|
|
864
|
+
/**
|
|
865
|
+
* 一个 `batch` 成员的窄化(sdk 8.2.0 判别联合 {@link RuleOfferBatchMember};B-025 修根)。
|
|
866
|
+
*
|
|
867
|
+
* 判别位 `kind` 读 sdk `RULE_OFFER_BATCH_MEMBER_KINDS`(`command` / `directoryRead`),外加一条
|
|
868
|
+
* **pre-B3 兼容臂**:`kind` **缺席**的成员按 `command` 归一(server ≥7.46.0 到 design/382 §2.3 B3
|
|
869
|
+
* 落地之间铸的成员没有判别位 —— 窄读域只许等于或宽于铸点域,绝不更窄)。
|
|
870
|
+
*
|
|
871
|
+
* 🔴 **不识的 `kind`(在场但不是表里的词)⇒ `undefined`,调用方据此丢掉整只 batch**,
|
|
872
|
+
* 绝不丢单个成员:core design/382 §2.3 规范性降级臂逐字 "drops the WHOLE batch offer —
|
|
873
|
+
* never the single member"(少一条成员的合取批把「对 N 条说 yes」渲成「对 N−1 条说 yes」,
|
|
874
|
+
* 比不渲更坏),旁边那条完整诚实的 `single` 照留。
|
|
875
|
+
* 🔴 `segment` 是每个臂都必带的渲染座(非空串);`directoryRead` 臂**没有** `match`/`command`,
|
|
876
|
+
* 拿三元组窄读器去读它正是 0.57.0 把整只 batch 判假的那一形。
|
|
877
|
+
*/
|
|
878
|
+
function readRuleOfferBatchMember(v) {
|
|
879
|
+
if (v === null || typeof v !== 'object')
|
|
880
|
+
return undefined;
|
|
881
|
+
const o = v;
|
|
882
|
+
const seg = o.segment;
|
|
883
|
+
if (typeof seg !== 'string' || seg === '')
|
|
884
|
+
return undefined;
|
|
885
|
+
// pre-B3 兼容臂:判别位**缺席** = 历史形的 `command` 成员(那一代 wire 上根本没有 `kind`)。
|
|
886
|
+
// 🔴 归一放在最前面,后面只有**一个**成员性判据 —— 缺席与在场两条路走同一道闸,不留第二个判官。
|
|
887
|
+
const kind = o.kind === undefined ? 'command' : o.kind;
|
|
888
|
+
// 🔴 **成员性判到 sdk 的闭词表,不手抄字面量**(异源对抗复审 r1 [medium] 逼出的同形残余):
|
|
889
|
+
// 本函数初稿把 `'directoryRead'` / `'command'` 两个词**手写**在分支条件里,导入的
|
|
890
|
+
// `RULE_OFFER_BATCH_MEMBER_KINDS` 只被再导出、运行期一次都没读 —— 那正是 B-025 本身的病形
|
|
891
|
+
// (`match` 手抄两员)在成员这一维上的**残余**,只是当天恰好抄对了。抄对的表明天也会过期。
|
|
892
|
+
if (typeof kind !== 'string')
|
|
893
|
+
return undefined;
|
|
894
|
+
if (!RULE_OFFER_BATCH_MEMBER_KINDS.includes(kind))
|
|
895
|
+
return undefined;
|
|
896
|
+
if (kind === 'directoryRead') {
|
|
897
|
+
const rule = o.rule;
|
|
898
|
+
const dir = o.directory;
|
|
899
|
+
if (typeof rule !== 'string' || rule === '')
|
|
900
|
+
return undefined;
|
|
901
|
+
if (typeof dir !== 'string' || dir === '')
|
|
902
|
+
return undefined;
|
|
903
|
+
return { kind: 'directoryRead', rule, directory: dir, segment: seg };
|
|
904
|
+
}
|
|
905
|
+
if (kind === 'command') {
|
|
906
|
+
const triple = readRuleTriple(v);
|
|
907
|
+
if (triple === undefined)
|
|
908
|
+
return undefined;
|
|
909
|
+
return { kind: 'command', ...triple, segment: seg };
|
|
910
|
+
}
|
|
911
|
+
// 🔴 **表内、但本包还没有读器的 kind** ⇒ 与表外同处置(丢 ⇒ 调用方丢整只 batch),绝不猜一个形。
|
|
912
|
+
// 上游往闭词表加员而本包没跟时走这条路:行为是 fail toward asking(合取批不渲,兄弟 single 照留),
|
|
913
|
+
// 而门 ⑨c 的「⊇ 成员 kind 在读器里走得通」那一腿会**当天红**,逼人补读器 —— 静默降级与显形二者兼得。
|
|
914
|
+
return undefined;
|
|
915
|
+
}
|
|
916
|
+
/**
|
|
917
|
+
* `uncoveredDetail`(design/382 §3.5 **additive** 明细座)的窄化。
|
|
918
|
+
*
|
|
919
|
+
* 🔴 **只丢坏行,绝不因为它否决整只 batch**:additive 位到货**不许回头削弱既有位的现行为** ——
|
|
920
|
+
* 老引擎压根不铸这一位,server 自己对坏形的座也是「只丢座不丢批」。整只读空 ⇒ 本位缺席
|
|
921
|
+
* (**不是**空数组:空数组会被端读成「已确认没有未覆盖段」,而真源恒是 `uncoveredSegments`)。
|
|
922
|
+
* 🔴 `reason` 判到 sdk 8.2.0 的闭三词集(`redirection` / `no_rule_form` / `cap_overflow`);
|
|
923
|
+
* 不识的 reason 只丢那一行 —— 它是**给人看的因由**,不驱动任何兑付动作。
|
|
924
|
+
*/
|
|
925
|
+
function readUncoveredDetail(v) {
|
|
926
|
+
if (!Array.isArray(v))
|
|
927
|
+
return undefined;
|
|
928
|
+
if (v.length === 0 || v.length > MAX_RULE_OFFER_UNCOVERED_DETAIL_TOLERATED)
|
|
929
|
+
return undefined;
|
|
930
|
+
const out = [];
|
|
931
|
+
for (const raw of v) {
|
|
932
|
+
if (raw === null || typeof raw !== 'object')
|
|
933
|
+
continue;
|
|
934
|
+
const o = raw;
|
|
935
|
+
if (typeof o.segment !== 'string' || o.segment === '')
|
|
936
|
+
continue;
|
|
937
|
+
if (typeof o.reason !== 'string')
|
|
938
|
+
continue;
|
|
939
|
+
if (!RULE_OFFER_UNCOVERED_REASONS.includes(o.reason))
|
|
940
|
+
continue;
|
|
941
|
+
out.push({ segment: o.segment, reason: o.reason });
|
|
942
|
+
}
|
|
943
|
+
return out.length > 0 ? out : undefined;
|
|
944
|
+
}
|
|
835
945
|
/** offer **条数**的坏形帽。server 侧执法帽是 `MAX_RULE_OFFERS`=4(core 契约本就 ≤2),本包留 8 ——
|
|
836
946
|
* [4050] 随批立的纪律:**窄读域只许等于或宽于铸点域,绝不更窄**;超帽 = 坏形/注入,整只降缺席
|
|
837
947
|
* (截了不留痕会掩盖注入)。 */
|
|
@@ -839,6 +949,23 @@ const MAX_RULE_OFFERS_TOLERATED = 8;
|
|
|
839
949
|
/** 一条 `batch` 的**成员**条数坏形帽(core 契约 1..5,server 容忍帽 8)。与上面那个刻意分家:
|
|
840
950
|
* 两者数的是不同的东西(几个选项 vs 一个选项里几条规则),混成一个数会让上游放宽任一维时误伤另一维。 */
|
|
841
951
|
const MAX_RULE_OFFER_BATCH_MEMBERS_TOLERATED = 8;
|
|
952
|
+
/**
|
|
953
|
+
* `uncoveredDetail` 的**行数**坏形帽(0.58.0)。
|
|
954
|
+
*
|
|
955
|
+
* 🔴 **锚在上游的铸点域上,不是按兄弟帽类比**(异源对抗复审 r1 [medium] 真病修):本位初稿写的是
|
|
956
|
+
* `8`,理由「与成员帽同源同量级」—— 那是**类比不是取证**,而且判错了源。真实铸点域:
|
|
957
|
+
* · server 的执法帽是 `MAX_UNCOVERED_DETAIL_ROWS = **32**`(`@sema-agent/server`
|
|
958
|
+
* `src/approval-card.ts`:zod `.max(32)` 与座级预筛 `screenUncoveredDetailSeat` 同用);
|
|
959
|
+
* · 未覆盖段数**根本不受成员帽约束** —— core 逐字 `uncoveredSegments: uncoveredDetail.length`
|
|
960
|
+
* (`permission-rule-model.ts`),一只**只有 1 个成员**的 batch 可以带 9 条明细(9 个带重定向
|
|
961
|
+
* 的段各自 mint 不出规则形,进不了 `rules[]` 却每段都要给一个「为什么还会问」)。
|
|
962
|
+
* ⇒ 帽 8 是**比铸点域更窄**的窄读域,正是 [4050] 那条纪律禁的形:一只合法的 9~32 行明细座被整座
|
|
963
|
+
* 静默丢掉,人失去「这几段为什么还会问」。边界钉在门 ⑨d(9 / 32 必收、33 才丢)。
|
|
964
|
+
* 🔴 **取等于而不是再加倍**:与 {@link MAX_RULE_OFFERS_TOLERATED}(server 执法帽 4,本包留 8)不同 ——
|
|
965
|
+
* 那一位没有可锚的上游常量,余量是纯容忍;本位有**具名铸点常量**,取等于就是「窄读域等于铸点域」,
|
|
966
|
+
* 再自行加倍反而是又一次凭感觉编数。上游哪天放宽,门 ⑨d 的 33 行负控会当天红,逼人跟着抬。
|
|
967
|
+
*/
|
|
968
|
+
const MAX_RULE_OFFER_UNCOVERED_DETAIL_TOLERATED = 32;
|
|
842
969
|
/**
|
|
843
970
|
* `ruleOffers`(server ≥7.46.0 的判别联合)的结构读。
|
|
844
971
|
*
|
|
@@ -893,19 +1020,28 @@ export function readRuleOffers(v) {
|
|
|
893
1020
|
const members = [];
|
|
894
1021
|
let memberShapeOk = true;
|
|
895
1022
|
for (const raw of o.rules) {
|
|
896
|
-
const triple = readRuleTriple(raw);
|
|
897
|
-
const seg = raw?.segment;
|
|
898
1023
|
// 🔴 batch 成员**不逐条丢**:合取批是「对全体成员一次说是」,少一条成员就是另一次授权 ——
|
|
899
|
-
// 渲一个缺了成员的批,人点的与引擎兑的不是同一批规则。任一成员不合形
|
|
900
|
-
|
|
1024
|
+
// 渲一个缺了成员的批,人点的与引擎兑的不是同一批规则。任一成员不合形(含 `kind` 不识)
|
|
1025
|
+
// ⇒ 整条 batch 丢。这是 core design/382 §2.3 的**规范性**降级臂,不是本包的保守选择:
|
|
1026
|
+
// 逐字 "drops the WHOLE batch offer — never the single member ... and never the whole card"。
|
|
1027
|
+
const member = readRuleOfferBatchMember(raw);
|
|
1028
|
+
if (member === undefined) {
|
|
901
1029
|
memberShapeOk = false;
|
|
902
1030
|
break;
|
|
903
1031
|
}
|
|
904
|
-
members.push(
|
|
1032
|
+
members.push(member);
|
|
905
1033
|
}
|
|
906
1034
|
if (!memberShapeOk)
|
|
907
1035
|
continue;
|
|
908
|
-
|
|
1036
|
+
// additive 明细座(0.58.0):只丢坏行、读空即缺席,**绝不**因为它否决整只 batch。
|
|
1037
|
+
const detail = readUncoveredDetail(item.uncoveredDetail);
|
|
1038
|
+
out.push({
|
|
1039
|
+
kind: 'batch',
|
|
1040
|
+
offerIndex: i,
|
|
1041
|
+
rules: members,
|
|
1042
|
+
uncoveredSegments: uncovered,
|
|
1043
|
+
...(detail !== undefined ? { uncoveredDetail: detail } : {}),
|
|
1044
|
+
});
|
|
909
1045
|
continue;
|
|
910
1046
|
}
|
|
911
1047
|
// 不认识的 kind(含 kind 缺席)⇒ 丢这一条,原始下标照旧不给后面的成员用。
|
package/dist/index.d.ts
CHANGED
|
@@ -215,6 +215,7 @@ export * from './engineSessionParam.js';
|
|
|
215
215
|
export * from './engineWireTarget.js';
|
|
216
216
|
export * from './principalWire.js';
|
|
217
217
|
export * from './wireErrorTriage.js';
|
|
218
|
+
export * from './resumeRefusalCopy.js';
|
|
218
219
|
export * from './sessionMap.js';
|
|
219
220
|
export * from './detachWire.js';
|
|
220
221
|
export * from './workflowMonitor.js';
|
package/dist/index.js
CHANGED
|
@@ -300,6 +300,11 @@ export * from './principalWire.js';
|
|
|
300
300
|
// · wireErrorTriage:turn 错误分型判定半场(A-028.11;文案/渲染归端)+ scenario 拒绝判型
|
|
301
301
|
// (A-028.13;web 逐字节同形过滤行的正主)。码字面引 engineErrorCodes。
|
|
302
302
|
export * from './wireErrorTriage.js';
|
|
303
|
+
// · resumeRefusalCopy:L-102 下半场(0.58.0)—— resume 拒绝的**人话铸点**三端单源。
|
|
304
|
+
// 与上面那口分工:`wireErrorTriage.resumeRetryLaterFromError` 答「能不能等」(事实读数),
|
|
305
|
+
// 本口答「该对人说什么」(文案),`preflight_rejected` 的窗与可等性**转调**前者不复制判定。
|
|
306
|
+
// 壳侧对位 = cli `src/sema/resumeRefusalCopy.ts`(1.0.101 起改薄成适配层)。
|
|
307
|
+
export * from './resumeRefusalCopy.js';
|
|
303
308
|
// · sessionMap:「客户端会话 id ↔ 引擎会话 id」映射单一键形 + merge 判定(A-028.12;存储经
|
|
304
309
|
// SessionMapStorePort 归端 —— cli 文件锁/原子写,web localStorage)。
|
|
305
310
|
export * from './sessionMap.js';
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 本模块认识的 resume 拒绝码(**闭集**)—— 「有人话可补」的那两个。
|
|
3
|
+
*
|
|
4
|
+
* 🔴 **冻结数组,不是 `ReadonlySet`**(与 {@link RESUME_RETRY_LATER_CODES} 同一条已定谳的病形):
|
|
5
|
+
* `ReadonlySet` 只在类型面只读,运行期是一只普通 `Set`,而判定查的就是这个实例 —— 公面上任何
|
|
6
|
+
* JS 消费者一次 `.add('resume.evicted')` 就能让一条「重开吧」的拒绝挂上「你的决定没被消费」
|
|
7
|
+
* 这句安全声明。冻结数组在运行期真的改不动(ESM 恒 strict:`push` / 下标赋值直接抛)。
|
|
8
|
+
* 🔴 新增成员必须**同批**补文案 + 判据,不许靠前缀放宽。
|
|
9
|
+
*/
|
|
10
|
+
export declare const RESUME_REFUSAL_CODES: readonly string[];
|
|
11
|
+
/** {@link resumeRefusalFromError} 的结构化读数。 */
|
|
12
|
+
export interface ResumeRefusalDetail {
|
|
13
|
+
/** 命中的那一个码({@link RESUME_REFUSAL_CODES} 的成员之一)。 */
|
|
14
|
+
code: string;
|
|
15
|
+
/**
|
|
16
|
+
* server 给的**等待秒数**(整数 ∧ ≥1;窄读域与 §21 同律,见模块顶注)。
|
|
17
|
+
* 🔴 **缺席 = 服务端没给窗**,不是 0、不是「立刻」——绝不渲一个编出来的倒计时
|
|
18
|
+
* ([honest-absence-not-fabricated-zero])。`resume.placement_mismatch` 上**恒缺席**
|
|
19
|
+
* (server 只在时间性二码上铸这一位);`resume.preflight_rejected` 上按 server 供给。
|
|
20
|
+
*/
|
|
21
|
+
retryAfterSec?: number;
|
|
22
|
+
/**
|
|
23
|
+
* **等一会儿再赎有没有用**(处置位;文案据它选第三句)。
|
|
24
|
+
*
|
|
25
|
+
* 🔴 **两个码上的 `false` 是两种「不」,别合并读**:
|
|
26
|
+
* · `resume.preflight_rejected` 的 `false` = **不可判**(转调 {@link resumeRetryLaterFromError}
|
|
27
|
+
* 的同名位:core 侧那条 `terminal` 臂与缺省 `retry_later` 臂的判别位只在 message 散文里,
|
|
28
|
+
* 本包不按文案分臂 ⇒ 只认「server 真给了窗」这条正向证据);
|
|
29
|
+
* · `resume.placement_mismatch` 的 `false` = **等没有用**(出路是换参数不是等时间,见该码顶注)。
|
|
30
|
+
* 两者在文案上落到**不同的第三句**,所以消费端不必自己再分。
|
|
31
|
+
*/
|
|
32
|
+
waitable: boolean;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 被 catch 的错误 → resume 拒绝读数;不是这两个码 ⇒ `null`(绝不误吃别的 4xx)。
|
|
36
|
+
*
|
|
37
|
+
* 🔴 **duck-typed 不 `instanceof`**:三端注入面可能是宿主的裸 fetch、desktop 的 IPC 转投、web 跨
|
|
38
|
+
* bundle 的 plain object(跨 bundle 同名类是两个类),这些形上 `instanceof` 一律为假而
|
|
39
|
+
* `errorCode` 恒在。键位**只认 `errorCode`**([2055] 死键纪律,退役 `code` 槽不做兼容)。
|
|
40
|
+
* 🔴 **判据只有 `errorCode`,不看 HTTP 数字**(与 §21 同口径):`resume.*` 那一族成员全是 409,
|
|
41
|
+
* 按数字分支等于把几种不同处置压成一种。
|
|
42
|
+
* 🔴 **`preflight_rejected` 的窗与可等性全部转调 §21 那一口**,本文件不复制判定。
|
|
43
|
+
*/
|
|
44
|
+
export declare function resumeRefusalFromError(err: unknown): ResumeRefusalDetail | null;
|
|
45
|
+
/**
|
|
46
|
+
* 结构化读数 → 人话补充行(`·` 分段,与端上 quota / scenario 两个兄弟同形)。
|
|
47
|
+
*
|
|
48
|
+
* 三句的分工固定:①**发生了什么**(用户看得懂的那句)· ②**这次拒绝有没有消费掉你的决定**
|
|
49
|
+
* (安全声明,两条臂都成立时才敢说)· ③**接下来怎么办 / 还能不能再决**。
|
|
50
|
+
*
|
|
51
|
+
* 🔴 第三句由 {@link ResumeRefusalDetail.waitable} 选,**不由 message 文本选**:按上游散文分支
|
|
52
|
+
* 正是「上游改一个词、壳的判定静默空转」的形(wire 锚契约门要挡的就是它)。
|
|
53
|
+
* 🔴 `preflight_rejected` 且 `waitable === false` 时说的是**两条臂都为真**的那句(cli 1.0.x 的现行
|
|
54
|
+
* 文案逐字),把「还能不能再赎」交给屏上那行引擎原文;`waitable === true` 时 server 真给了窗
|
|
55
|
+
* ——那是 `retry_later` 臂的**充分证据**(core 的 `terminal` 臂抛的 `CheckpointError` 一个
|
|
56
|
+
* detail 都不带,窗结构上到不了客户端)⇒ 可以放心说「障碍清掉之后这个 token 还能再赎」。
|
|
57
|
+
*/
|
|
58
|
+
export declare function resumeRefusalContent(detail: ResumeRefusalDetail): string;
|