@sema-agent/client-core 0.64.1 → 0.65.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 +226 -0
- package/README.md +15 -7
- package/dist/adapt/arms.js +125 -7
- package/dist/adapt/ids.d.ts +22 -0
- package/dist/adapt/ids.js +29 -0
- package/dist/adapt/panelTasks.d.ts +22 -0
- package/dist/adapt/panelTasks.js +45 -0
- package/dist/adapt/textStream.js +6 -3
- package/dist/adapt.d.ts +1 -1
- package/dist/adapt.js +3 -0
- package/dist/adapter/downstream/eventToSdkMessage.d.ts +0 -10
- package/dist/adapter/downstream/eventToSdkMessage.js +207 -65
- package/dist/adapter/downstream/terminalToSdkResult.d.ts +4 -4
- package/dist/adapter/downstream/terminalToSdkResult.js +43 -12
- package/dist/adapter/downstream/turnUsageToModelUsage.d.ts +23 -2
- package/dist/adapter/downstream/turnUsageToModelUsage.js +7 -1
- package/dist/adapter/runStream.js +39 -2
- package/dist/adapter/types.d.ts +12 -0
- package/dist/autoModeUnavailable.d.ts +48 -79
- package/dist/autoModeUnavailable.js +70 -99
- package/dist/classifierStatus.d.ts +25 -71
- package/dist/classifierStatus.js +110 -105
- package/dist/cloudConfigWireCaps.js +16 -0
- package/dist/decideReceipt.d.ts +117 -0
- package/dist/decideReceipt.js +142 -0
- package/dist/engineErrorCodes.d.ts +32 -0
- package/dist/engineErrorCodes.js +42 -0
- package/dist/fleet/fleetProjection.d.ts +24 -1
- package/dist/fleet/fleetProjection.js +26 -1
- package/dist/fleetAgentPanelProjection.js +6 -1
- package/dist/gateVocabulary.d.ts +9 -1
- package/dist/gateVocabulary.js +46 -4
- package/dist/hitl/askGateWire.js +22 -1
- package/dist/hitl/gateLedger.d.ts +24 -0
- package/dist/hitl/gateLedger.js +8 -0
- package/dist/hitl/hitlBridge.js +14 -2
- package/dist/hitl/parkResolver.d.ts +23 -2
- package/dist/hitl/parkResolver.js +34 -6
- package/dist/hitl/toolApprovalWire.d.ts +94 -6
- package/dist/hitl/toolApprovalWire.js +127 -7
- package/dist/index.d.ts +1 -0
- package/dist/index.js +16 -6
- package/dist/mcpWireCaps.d.ts +31 -0
- package/dist/mcpWireCaps.js +12 -0
- package/dist/notifications.js +11 -2
- package/dist/runTerminal.d.ts +48 -0
- package/dist/runTerminal.js +59 -0
- package/dist/seam.d.ts +131 -1
- package/dist/seam.js +22 -0
- package/docs/INTEGRATION-CLIENTS.md +934 -61
- package/package.json +2 -2
package/dist/adapt/arms.js
CHANGED
|
@@ -7,7 +7,9 @@ import { recordEngineToolLabel } from '../engineToolLabelStore.js';
|
|
|
7
7
|
import { registerSubagentAlias, registerSubagentContentAlias } from '../subagentContentStore.js';
|
|
8
8
|
import { readAsyncLaunchedAgentReceipt } from '../toolResult.js';
|
|
9
9
|
import { isWorkflowAgentTaskId, recordWorkflowAgentTaskId } from '../workflow.js';
|
|
10
|
-
|
|
10
|
+
// L-215+(0.65.0;core [6908]):终局状态词的单铸谓词(三处同形一次改齐)。
|
|
11
|
+
import { isTerminalStatus } from '../runTerminal.js';
|
|
12
|
+
import { chrome, MAIN, transcript, messageIdentityOf } from './ids.js';
|
|
11
13
|
import { CANCEL_MESSAGE, decisionOf, flattenWireOutput, REJECT_MESSAGE, sanitizeToolUseBlock, shortTaskLabel, TASK_TOOL_NAMES, WORKFLOW_TOOL_NAMES, } from './wireShapes.js';
|
|
12
14
|
// ══ M2/M1 —— assistant(tool_use 半场 + durable 文本/思考半场)══════════════════════════════════
|
|
13
15
|
const assistantArm = function* (m, { ctx, idOf, text, cards, inst }) {
|
|
@@ -60,11 +62,21 @@ const assistantArm = function* (m, { ctx, idOf, text, cards, inst }) {
|
|
|
60
62
|
// 0.62.0:卡之前的散文已经落账,卡**之后**的散文属于下一条 assistant 消息 —— 划界。
|
|
61
63
|
// (终帧 `result` 在引擎侧只取**最后一条** assistant 消息的文本,补差判据的两边必须是同一种东西。)
|
|
62
64
|
text.beginAssistantMessage();
|
|
65
|
+
// L-215③:身份位取一次(下面只用 `model` —— `id` 是 per-RESPONSE 分组键,见块内注)。
|
|
66
|
+
const cardIdentity = messageIdentityOf(m, ctx);
|
|
63
67
|
yield transcript({
|
|
64
68
|
type: 'assistant',
|
|
65
69
|
// S1:per-RESPONSE 铸 id —— CC 的 grouped-agent 渲染按 `${message.id}:${toolName}`
|
|
66
70
|
// 分组;id-less 帧会把整个 session 的 Agent 卡塌成一张。tool_use 帧才盖章。
|
|
67
|
-
|
|
71
|
+
// 🔴 L-215③:这条臂**只接 `model`,不接上游那个 `id`** —— 两个 `id` 是**两种身份**
|
|
72
|
+
// (上游铸的是 per-EVENT 引擎身份,这里要的是 per-RESPONSE 分组键);换掉会把一张
|
|
73
|
+
// Agent 卡拆成 N 张。`model` 没有这层冲突,照接(不接就在重建时原地丢掉)。
|
|
74
|
+
message: {
|
|
75
|
+
id: cards.mintResponseId(m),
|
|
76
|
+
role: 'assistant',
|
|
77
|
+
content: renderBlocks,
|
|
78
|
+
...(cardIdentity.model !== undefined ? { model: cardIdentity.model } : {}),
|
|
79
|
+
},
|
|
68
80
|
uuid: idOf(m),
|
|
69
81
|
session_id: ctx.sessionId,
|
|
70
82
|
parent_tool_use_id: null,
|
|
@@ -134,7 +146,8 @@ const assistantArm = function* (m, { ctx, idOf, text, cards, inst }) {
|
|
|
134
146
|
yield* text.takeThinking();
|
|
135
147
|
yield transcript({
|
|
136
148
|
type: 'assistant',
|
|
137
|
-
|
|
149
|
+
// L-215③ 族扫:durable 内容腿也是**重建**点,身份位在这里接力(见 ids.ts messageIdentityOf)。
|
|
150
|
+
message: { role: 'assistant', content: [{ type: 'text', text: textBlock.text }], ...messageIdentityOf(m, ctx) },
|
|
138
151
|
uuid: idOf(m),
|
|
139
152
|
session_id: ctx.sessionId,
|
|
140
153
|
parent_tool_use_id: null,
|
|
@@ -146,7 +159,8 @@ const assistantArm = function* (m, { ctx, idOf, text, cards, inst }) {
|
|
|
146
159
|
if (thinkingBlock && typeof thinkingBlock.thinking === 'string') {
|
|
147
160
|
yield transcript({
|
|
148
161
|
type: 'assistant',
|
|
149
|
-
|
|
162
|
+
// L-215③ 族扫:同上(durable 思考块)。
|
|
163
|
+
message: { role: 'assistant', content: [thinkingBlock], ...messageIdentityOf(m, ctx) },
|
|
150
164
|
uuid: idOf(m, 'durable-thinking'),
|
|
151
165
|
session_id: ctx.sessionId,
|
|
152
166
|
parent_tool_use_id: null,
|
|
@@ -262,6 +276,35 @@ const humanInputArm = function* (m) {
|
|
|
262
276
|
...(str(m.eventId) !== undefined ? { eventId: str(m.eventId) } : {}),
|
|
263
277
|
});
|
|
264
278
|
};
|
|
279
|
+
/**
|
|
280
|
+
* B-072 ④(0.65.0)—— `message_committed` **定位账本帧**。
|
|
281
|
+
*
|
|
282
|
+
* 姿势逐条抄同族的 `human_input`(引擎侧发生了一件事、壳记一笔的非持久帧,归 chrome;**不走
|
|
283
|
+
* attachment / 不铸 transcript**:本帧不带正文,铸一行就是替引擎编一句它没说过的话)。
|
|
284
|
+
* 它与 `human_input` 的唯一差别是**用途**:那一条是审计,这一条是**定位** —— 端拿它自建
|
|
285
|
+
* `entryId → 已渲消息` 的映射表,压缩分割线(`compact_metadata._sema_preserved_segment`)
|
|
286
|
+
* 就是靠这张表落到「保留尾段的第一条消息之前」。
|
|
287
|
+
*
|
|
288
|
+
* 子流帧(带 parentToolCallId)同族让位:不上 leader 面(子代的条目属子代那条流)。
|
|
289
|
+
* 两个必填位的**形**已由投影层判过(读不出即 malformed 留痕);这里是第二道,读不出就不发。
|
|
290
|
+
*/
|
|
291
|
+
const messageCommittedArm = function* (m) {
|
|
292
|
+
if (typeof m.parentToolCallId === 'string')
|
|
293
|
+
return;
|
|
294
|
+
const entryId = typeof m.entryId === 'string' && m.entryId.length > 0 ? m.entryId : undefined;
|
|
295
|
+
const role = typeof m.role === 'string' && m.role.length > 0 ? m.role : undefined;
|
|
296
|
+
if (entryId === undefined || role === undefined)
|
|
297
|
+
return;
|
|
298
|
+
yield chrome({
|
|
299
|
+
kind: 'message_committed',
|
|
300
|
+
laneProof: MAIN,
|
|
301
|
+
entryId,
|
|
302
|
+
role,
|
|
303
|
+
...(typeof m.toolCallId === 'string' && m.toolCallId.length > 0 ? { toolCallId: m.toolCallId } : {}),
|
|
304
|
+
// 宿主幂等落表的键(同 human_input):durable 续读会重放同一条账本帧。
|
|
305
|
+
...(typeof m.eventId === 'string' && m.eventId.length > 0 ? { eventId: m.eventId } : {}),
|
|
306
|
+
});
|
|
307
|
+
};
|
|
265
308
|
/**
|
|
266
309
|
* #310 / #318 件① —— `engine_notice` 引擎结构化通告(server ≥7.36,契约 = ASSISTANT-WIRE-CONTRACT 附录 D)。
|
|
267
310
|
*
|
|
@@ -338,6 +381,31 @@ const wiringManifestArm = function* (m) {
|
|
|
338
381
|
...(typeof m.eventId === 'string' && m.eventId.length > 0 ? { eventId: m.eventId } : {}),
|
|
339
382
|
});
|
|
340
383
|
};
|
|
384
|
+
/**
|
|
385
|
+
* `approval_request` / `approval_revoke` 内部臂 → 同名 chrome 臂(B-078 / L-208,0.65.0;design/172)。
|
|
386
|
+
*
|
|
387
|
+
* 契约本体在 `seam.ts` 的 {@link import('../seam.js').ApprovalRequestChromeEvent} /
|
|
388
|
+
* {@link import('../seam.js').ApprovalRevokeChromeEvent} 头注(那是宿主要读的那一份)。
|
|
389
|
+
* 本臂只做两件:
|
|
390
|
+
* 🔴 **一个字节都不加工**:`frame` 原样转发(信封纪律 —— 窄化到 v1 是宿主拿 sdk 谓词做的动作,
|
|
391
|
+
* 在这里替它窄化会让一条 `schemaVersion: 2` 的合法帧冒充 v1;见投影层头注)。
|
|
392
|
+
* 🔴 **第二道信封判**:投影层已经判过 `schemaVersion` 是有限数,这里再确认一次 —— 防的是
|
|
393
|
+
* **非投影口**喂进来的帧(宿主自建管线 / 重放存量转录),不是重复判据(与 `wiringManifestArm`
|
|
394
|
+
* 的第二道成形判同因)。
|
|
395
|
+
* 🔴 **刻意没有子流断闸**(与 `engine_notice` / `text_segment_end` 那三条相反,这是有理由的差别):
|
|
396
|
+
* 那几条断闸挡的是「把子代腿的东西渲到 leader 面上」;而审批卡**必须**上到人面前——一张属于
|
|
397
|
+
* 子代调用的卡也要人来点,断掉它等于把那条 run 挂死在没人看得见的地方。归属过滤由宿主按
|
|
398
|
+
* 帧上的 `taskId` 做(撤卡臂的纪律①),那是**过滤**不是**丢弃**。
|
|
399
|
+
*/
|
|
400
|
+
const approvalFrameArm = (kind) => function* (m) {
|
|
401
|
+
const schemaVersion = m.schemaVersion;
|
|
402
|
+
if (typeof schemaVersion !== 'number' || !Number.isFinite(schemaVersion))
|
|
403
|
+
return;
|
|
404
|
+
const frame = m.frame;
|
|
405
|
+
if (typeof frame !== 'object' || frame === null)
|
|
406
|
+
return;
|
|
407
|
+
yield chrome({ kind, laneProof: MAIN, frame, schemaVersion });
|
|
408
|
+
};
|
|
341
409
|
/**
|
|
342
410
|
* `text_end` 内部臂 → chrome `text_segment_end`(#323 / core #447)。
|
|
343
411
|
*
|
|
@@ -386,7 +454,9 @@ const promptSuggestionsArm = function* (m) {
|
|
|
386
454
|
// ══ M2 —— tool_end_result(关卡 + B/D/E 层卡本体 + 两个侧产物)══════════════════════════════════
|
|
387
455
|
const toolEndResultArm = function* (m, { ctx, idOf, cards, panel }) {
|
|
388
456
|
// B4 起本臂做三件:① P0-2 label 补位(只有 tool_end 带 label 的场景;台账自身幂等不覆盖)
|
|
389
|
-
// ② MF-10 **关卡 settle**(
|
|
457
|
+
// ② MF-10 **关卡 settle**(父卡的 tool_end 是完成信号;⚠️ 0.65.0/B-074 订正:「子代从不发
|
|
458
|
+
// 终态 tick」这句旧前提已被 core 7.x 推翻 —— 终态 tick 现在会发,由 taskProgressArm 的
|
|
459
|
+
// `TERMINAL_TICK_STATUSES` 分支落行,两条腿共用 `endedPanelTasks` 判重;卡的 output
|
|
390
460
|
// 文本 = 子代最终报告,串到行 end 事件上)③ 卡台账出栈 + response-id 复位(S1)。
|
|
391
461
|
// 🆕 B5:④ **B/D/E 层** —— 铸 `tool_result` 卡本体 + 三个侧产物
|
|
392
462
|
// (Remember→memory_saved / task 族 structured 台账 / #117a+#158 bg Bash+Monitor 桥)。
|
|
@@ -466,6 +536,16 @@ const toolEndResultArm = function* (m, { ctx, idOf, cards, panel }) {
|
|
|
466
536
|
});
|
|
467
537
|
}
|
|
468
538
|
};
|
|
539
|
+
/**
|
|
540
|
+
* B-074(0.65.0)—— core 明写的**终态那一拍**的两个词。
|
|
541
|
+
*
|
|
542
|
+
* 🔴 **闭二词,而 `status` 本身按开集读** —— 这两件事不矛盾,分工是:投影层原样透传任何词
|
|
543
|
+
* (词表属主在 core),本表只回答「哪些词**是**终态」。一个包不认识的新词(比如上游哪天加
|
|
544
|
+
* `cancelled`)走 **running 那条路**,而不是被猜成终态:猜错的代价是把一条还在跑的行提前
|
|
545
|
+
* 结掉,而「多渲一拍 running」只是慢一点。core 的臂注也只承诺这两个词
|
|
546
|
+
* (`timeout/blocked fold to failed`,即上游自己已经折过了)。
|
|
547
|
+
*/
|
|
548
|
+
const TERMINAL_TICK_STATUSES = new Set(['completed', 'failed']);
|
|
469
549
|
// ══ M3 —— task_progress(引擎侧子代的累计 usage tick)══════════════════════════════════════════
|
|
470
550
|
const taskProgressArm = function* (m, { ctx, cards, panel, inst }) {
|
|
471
551
|
// ── B4 A 层最后一臂(MF-10)—— 引擎侧子代的累计 usage tick。
|
|
@@ -599,6 +679,28 @@ const taskProgressArm = function* (m, { ctx, cards, panel, inst }) {
|
|
|
599
679
|
totalTokens: typeof usage.totalTokens === 'number' ? usage.totalTokens : 0,
|
|
600
680
|
},
|
|
601
681
|
});
|
|
682
|
+
// ── B-074(0.65.0)终态那一拍 ────────────────────────────────────────────────────────────
|
|
683
|
+
// 修前本臂的头注写着「**子代从不发终态 tick**,父卡的 tool_end 就是完成信号」—— 那句话在
|
|
684
|
+
// core 7.x 上已经是假的(`task_progress.status` 的臂注逐字:`ONE final tick fires at the
|
|
685
|
+
// sub-run's settle with the terminal face`,理由也写死了:`so a uuid-lane consumer sees the
|
|
686
|
+
// row finish instead of a bare removal after the last running beat`)。
|
|
687
|
+
//
|
|
688
|
+
// 🔴 **为什么落在臂尾、而不是一进来就早退**(异源对抗复审实抓的两条真回归,别按「先判终态再
|
|
689
|
+
// 干活」重排):终态那一拍带的是子代的**最终**累计数字。早退会让
|
|
690
|
+
// ① 面板行与 inline 群组行**冻在倒数第二拍**(实测 3 次工具 /150 tokens 被冻成 2 次 /100);
|
|
691
|
+
// ② 后到的关卡 settle 撞 `endedPanelTasks` 判重而整条让位 ⇒ 子代的**最终报告**(委派卡的
|
|
692
|
+
// output,只有关卡那条腿带得动)从此到不了面板行。
|
|
693
|
+
// 所以这一拍**照常走完上面的 tick 半场**(数字先落地),只在最后多一件事:落终态。
|
|
694
|
+
//
|
|
695
|
+
// 🔴 **只落「关卡腿不会来收」的那些行**(`!panel.isLiveBound`):绑在本 turn 还开着的卡上的行
|
|
696
|
+
// 由 `panel.settle(cardId, isError, report)` 收 —— 那条腿带着最终报告,在这里抢先落行就是
|
|
697
|
+
// 把报告挤掉(上面 ②)。未绑 / inert 绑定(跨 turn bg 子代)= session 常驻行,关卡腿不碰它,
|
|
698
|
+
// 它今天只认通知帧 —— 那正是 core 说的 uuid lane,也正是本件要救的那一条。
|
|
699
|
+
// 🔴 **开集第四词不当终态**:词表属主在 core(`TERMINAL_TICK_STATUSES` 头注)。
|
|
700
|
+
if (typeof m.status === 'string' && TERMINAL_TICK_STATUSES.has(m.status) && !panel.isLiveBound(taskId)) {
|
|
701
|
+
ctx.probe?.('tick', JSON.stringify({ t: ctx.now(), taskId, lane: 'foreground', settle: m.status }));
|
|
702
|
+
yield* panel.settleFromTerminalTick(taskId, m.status === 'failed');
|
|
703
|
+
}
|
|
602
704
|
};
|
|
603
705
|
// ══ M1 / M6a —— stream_event / turn_usage ══════════════════════════════════════════════════════
|
|
604
706
|
const streamEventArm = function* (m, { text }) {
|
|
@@ -655,10 +757,19 @@ const resultArm = function* (m, { ctx, idOf, text, cards, panel, flags }) {
|
|
|
655
757
|
// 🔴 比较对象 = 引擎「最后一条 assistant 消息」在屏上那段(0.63.2):卡后零散文时回退到卡前那条
|
|
656
758
|
// (provider 一条消息 = [text, tool_use];空串是任何终帧的前缀 ⇒ 拿空串比会把整段终帧再渲一遍)。
|
|
657
759
|
const committed = text.lastCommittedAnswerText;
|
|
760
|
+
// L-215③:同上,身份位取一次(终帧补差腿**只接 `model`**,理由见块内注)。
|
|
761
|
+
const terminalIdentity = messageIdentityOf(m, ctx);
|
|
658
762
|
const emitTerminal = function* (body, tag) {
|
|
659
763
|
yield transcript({
|
|
660
764
|
type: 'assistant',
|
|
661
|
-
|
|
765
|
+
// L-215③ 族扫:终帧补差腿。🔴 这条消息的**正文是终帧的 `result`**,不是某条内容帧 ——
|
|
766
|
+
// 所以只接 `model`(那是整条流的事实),**不接 `id`**:把终帧的 eventId 当成一条
|
|
767
|
+
// assistant 消息的身份,会让宿主把「补差出来的那一段」与终帧本身当成同一条东西。
|
|
768
|
+
message: {
|
|
769
|
+
role: 'assistant',
|
|
770
|
+
content: [{ type: 'text', text: body }],
|
|
771
|
+
...(terminalIdentity.model !== undefined ? { model: terminalIdentity.model } : {}),
|
|
772
|
+
},
|
|
662
773
|
uuid: idOf(m, tag),
|
|
663
774
|
session_id: ctx.sessionId,
|
|
664
775
|
parent_tool_use_id: null,
|
|
@@ -718,7 +829,9 @@ const taskNotificationArm = function* (m, { ctx, idOf, panel, inst }) {
|
|
|
718
829
|
return; // 空/缺 task_id:RB-75 同族,丢弃
|
|
719
830
|
const taskId = fields.taskId;
|
|
720
831
|
const rawStatus = fields.status;
|
|
721
|
-
|
|
832
|
+
// L-215② 族扫(0.65.0):终局判据走单铸谓词 —— 修前手抄三词,core [6908] 的 `blocked`
|
|
833
|
+
// 漏在外面 ⇒ 一条自报走不下去的后台行**永远不 settle**(面板上挂着一条不会再动的「在跑」)。
|
|
834
|
+
const terminal = isTerminalStatus(rawStatus);
|
|
722
835
|
// #117a settle 半场 —— **故意在渲染去重之前**:settle 幂等,重放帧仍须 settle 一条
|
|
723
836
|
// 首投之后才注册的行。#47 矩阵 #7:只有 bash/monitor 行(或老引擎无 task_type)能被 settle
|
|
724
837
|
// (#158:monitor 行注册进面板后,它的终局通知也得能关行;事件帧 status="event" 非终态,
|
|
@@ -933,9 +1046,14 @@ export const ARMS = new Map([
|
|
|
933
1046
|
['steering_injected', steeringInjectedArm],
|
|
934
1047
|
['workspace_changed', workspaceChangedArm],
|
|
935
1048
|
['human_input', humanInputArm],
|
|
1049
|
+
['message_committed', messageCommittedArm],
|
|
936
1050
|
['engine_notice', engineNoticeArm],
|
|
937
1051
|
['text_end', textSegmentEndArm],
|
|
938
1052
|
['wiring_manifest', wiringManifestArm],
|
|
1053
|
+
// B-078 / L-208(0.65.0):design/172 流内审批两帧 —— 修前它们在投影层就 `dropped`,
|
|
1054
|
+
// 壳自己另接一份 ⇒ desktop/web 拿不到卡集与撤卡(归层违例)。
|
|
1055
|
+
['approval_request', approvalFrameArm('approval_request')],
|
|
1056
|
+
['approval_revoke', approvalFrameArm('approval_revoke')],
|
|
939
1057
|
['prompt_suggestions', promptSuggestionsArm],
|
|
940
1058
|
['retry_status', retryStatusArm],
|
|
941
1059
|
]);
|
package/dist/adapt/ids.d.ts
CHANGED
|
@@ -5,6 +5,28 @@ export type Frame = Record<string, unknown>;
|
|
|
5
5
|
export declare const MAIN: LaneProof;
|
|
6
6
|
/** 帧 → 稳定转录 id(`suffix` = 同一帧派生多条消息时的去撞位)。 */
|
|
7
7
|
export type IdOf = (frame: Frame, suffix?: string) => string;
|
|
8
|
+
/**
|
|
9
|
+
* L-215③(0.65.0)—— 一条 assistant 转录消息的**身份键**(`message.id` / `message.model`)。
|
|
10
|
+
*
|
|
11
|
+
* 🔴 **本层不是第二个铸点,是接力点**:上游投影器(`adapter/downstream/eventToSdkMessage.ts` 的
|
|
12
|
+
* `assistantArm`)已经把这两位铸在 durable 内容帧的 `message` 上;而本层的三个构造点
|
|
13
|
+
* (tool_use 卡臂 / 散文段 / 思考块)都是**重建** `{role, content}` 的 —— 重建就把上游铸好的
|
|
14
|
+
* 两位原地丢掉了(异源对抗复审实抓:「新增 assistant id/model 到达不了最终转录」)。本函数把
|
|
15
|
+
* 它们接过来,规矩只有两条:
|
|
16
|
+
* · **帧优先、ctx 兜底**(`model`):durable 内容帧上有,live 分段腿的 `stream_event` 锚上没有
|
|
17
|
+
* —— 那时回落到宿主开流时钉的 {@link AdapterContext.model};
|
|
18
|
+
* · **`id` 只认帧**:它是引擎铸的**事件身份**,ctx 上没有、也不该有一个「整条流通用的消息 id」。
|
|
19
|
+
* 🔴 **两位都缺席即键不铸**(不是 `undefined` 在场)。
|
|
20
|
+
* ⚠️ tool_use 卡臂**不**用这里的 `id`:那条臂刻意铸 per-RESPONSE id(CC 的 grouped-agent 渲染按
|
|
21
|
+
* `${message.id}:${toolName}` 分组,换成 per-event id 会把一张 Agent 卡拆成 N 张)——
|
|
22
|
+
* 两个 `id` 是**两种身份**,那条臂只取 `model`。
|
|
23
|
+
*/
|
|
24
|
+
export declare function messageIdentityOf(frame: Frame, ctx: {
|
|
25
|
+
model?: string;
|
|
26
|
+
}): {
|
|
27
|
+
id?: string;
|
|
28
|
+
model?: string;
|
|
29
|
+
};
|
|
8
30
|
export declare const chrome: (event: ChromeEvent) => AdapterOutput;
|
|
9
31
|
/**
|
|
10
32
|
* 🔴 入参从裸 `unknown` 收窄成 `Frame`(拆分同批的真收窄,不是搬运):调用点全是「按 CC 词汇
|
package/dist/adapt/ids.js
CHANGED
|
@@ -1,6 +1,35 @@
|
|
|
1
1
|
import { deriveTranscriptId } from '../seam.js';
|
|
2
2
|
/** 主车道证明——本批实现的臂全在 leader lane(子代/workflow lane 的 tick 面留 #52b)。 */
|
|
3
3
|
export const MAIN = { lane: 'main' };
|
|
4
|
+
/**
|
|
5
|
+
* L-215③(0.65.0)—— 一条 assistant 转录消息的**身份键**(`message.id` / `message.model`)。
|
|
6
|
+
*
|
|
7
|
+
* 🔴 **本层不是第二个铸点,是接力点**:上游投影器(`adapter/downstream/eventToSdkMessage.ts` 的
|
|
8
|
+
* `assistantArm`)已经把这两位铸在 durable 内容帧的 `message` 上;而本层的三个构造点
|
|
9
|
+
* (tool_use 卡臂 / 散文段 / 思考块)都是**重建** `{role, content}` 的 —— 重建就把上游铸好的
|
|
10
|
+
* 两位原地丢掉了(异源对抗复审实抓:「新增 assistant id/model 到达不了最终转录」)。本函数把
|
|
11
|
+
* 它们接过来,规矩只有两条:
|
|
12
|
+
* · **帧优先、ctx 兜底**(`model`):durable 内容帧上有,live 分段腿的 `stream_event` 锚上没有
|
|
13
|
+
* —— 那时回落到宿主开流时钉的 {@link AdapterContext.model};
|
|
14
|
+
* · **`id` 只认帧**:它是引擎铸的**事件身份**,ctx 上没有、也不该有一个「整条流通用的消息 id」。
|
|
15
|
+
* 🔴 **两位都缺席即键不铸**(不是 `undefined` 在场)。
|
|
16
|
+
* ⚠️ tool_use 卡臂**不**用这里的 `id`:那条臂刻意铸 per-RESPONSE id(CC 的 grouped-agent 渲染按
|
|
17
|
+
* `${message.id}:${toolName}` 分组,换成 per-event id 会把一张 Agent 卡拆成 N 张)——
|
|
18
|
+
* 两个 `id` 是**两种身份**,那条臂只取 `model`。
|
|
19
|
+
*/
|
|
20
|
+
export function messageIdentityOf(frame, ctx) {
|
|
21
|
+
const msg = frame.message;
|
|
22
|
+
const inner = typeof msg === 'object' && msg !== null && !Array.isArray(msg)
|
|
23
|
+
? msg
|
|
24
|
+
: undefined;
|
|
25
|
+
const id = typeof inner?.id === 'string' && inner.id.length > 0 ? inner.id : undefined;
|
|
26
|
+
const frameModel = typeof inner?.model === 'string' && inner.model.length > 0 ? inner.model : undefined;
|
|
27
|
+
const model = frameModel ?? (typeof ctx.model === 'string' && ctx.model.length > 0 ? ctx.model : undefined);
|
|
28
|
+
return {
|
|
29
|
+
...(id !== undefined ? { id } : {}),
|
|
30
|
+
...(model !== undefined ? { model } : {}),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
4
33
|
export const chrome = (event) => ({ plane: 'chrome', event });
|
|
5
34
|
/**
|
|
6
35
|
* 🔴 入参从裸 `unknown` 收窄成 `Frame`(拆分同批的真收窄,不是搬运):调用点全是「按 CC 词汇
|
|
@@ -43,6 +43,17 @@ export interface PanelTaskLedger {
|
|
|
43
43
|
/** 这条行已经绑过卡了吗(含糊回落的前置判位;别拿 `laneOf(...) === MAIN` 代替 —— 那是
|
|
44
44
|
* 按引用相等在推断,判据锚在会决定结果的量上才对)。 */
|
|
45
45
|
isBound(taskId: string): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* B-074 —— 这条行绑在一张**本 turn 还开着**的卡上吗(`liveBound`,#6 的 live/inert 判位)。
|
|
48
|
+
*
|
|
49
|
+
* 它回答的是「**谁来收这条行的终态**」:
|
|
50
|
+
* · `true` ⇒ 关卡那条腿({@link settle})会收,而且它带着**子代的最终报告**(委派卡的 output);
|
|
51
|
+
* · `false` ⇒ 未绑 / inert 绑定(跨 turn bg 子代的典型形)= **session 常驻行**,关卡腿不碰它,
|
|
52
|
+
* 它的终态今天只认通知帧 —— 这正是 core 的终态 tick 要救的那条 uuid lane。
|
|
53
|
+
* 🔴 判别力承重:终态 tick 在 `true` 的行上**不许**抢着落终态 —— 抢了会让后到的关卡 settle 撞
|
|
54
|
+
* `endedPanelTasks` 判重而整条让位,子代的最终报告从此到不了面板行(异源对抗复审实抓)。
|
|
55
|
+
*/
|
|
56
|
+
isLiveBound(taskId: string): boolean;
|
|
46
57
|
/** 本 turn 发布过面板行了吗(首 tick 判别 = 子代在壳侧可观测的起点)。 */
|
|
47
58
|
isLive(taskId: string): boolean;
|
|
48
59
|
/** 登记「本 turn 发布过面板行」。 */
|
|
@@ -55,5 +66,16 @@ export interface PanelTaskLedger {
|
|
|
55
66
|
settle(cardId: string | null, isError: boolean, report?: string): Generator<AdapterOutput>;
|
|
56
67
|
/** #6 通知-settle 边(推送半场):真终态在此落行,session 常驻行不再被 turn sweep 假结。 */
|
|
57
68
|
settleFromNotification(taskId: string, isError: boolean): Generator<AdapterOutput>;
|
|
69
|
+
/**
|
|
70
|
+
* B-074(0.65.0)**终态 tick 边** —— core 明写的那一拍(`task_progress.status` = `completed`/
|
|
71
|
+
* `failed`)按 taskId 直接落行。
|
|
72
|
+
*
|
|
73
|
+
* 为什么不复用 {@link settleFromNotification}:那一条是**通知帧**那半场,它按 `MAIN` 车道发
|
|
74
|
+
* end(bg 子代行本来就是 unbound 的),而终态 tick 的行**可能绑着一张前台委派卡** ⇒ 车道证明
|
|
75
|
+
* 必须走 {@link laneOf},否则一条 subagent lane 的行会拿 main lane 的证明去落终态(帧×lane
|
|
76
|
+
* 矩阵那一族的病)。也不复用 {@link settle}:那一条按**卡 id** 收(关卡/防御 sweep 的语义),
|
|
77
|
+
* 而这里的权威键是 taskId —— 引擎说的是「这个子代结束了」,不是「这张卡关了」。
|
|
78
|
+
*/
|
|
79
|
+
settleFromTerminalTick(taskId: string, isError: boolean): Generator<AdapterOutput>;
|
|
58
80
|
}
|
|
59
81
|
export declare function createPanelTaskLedger(ctx: AdapterContext, cards: OpenCardView, inst: AdapterInstanceLedger): PanelTaskLedger;
|
package/dist/adapt/panelTasks.js
CHANGED
|
@@ -25,6 +25,7 @@ export function createPanelTaskLedger(ctx, cards, inst) {
|
|
|
25
25
|
return {
|
|
26
26
|
laneOf,
|
|
27
27
|
isBound: (taskId) => taskCardBinding.has(taskId),
|
|
28
|
+
isLiveBound: (taskId) => liveBoundPanelTasks.has(taskId),
|
|
28
29
|
/**
|
|
29
30
|
* T32 行绑定。**typed 双键在场恒赢**(B6 定案):wire 点名了 `parentToolCallId` 时,下面的
|
|
30
31
|
* FIFO 臂**一次都不会被考虑** —— 连「点名的卡不合格」那一支也是直接返回 unbound,而不是
|
|
@@ -189,5 +190,49 @@ export function createPanelTaskLedger(ctx, cards, inst) {
|
|
|
189
190
|
}
|
|
190
191
|
}
|
|
191
192
|
},
|
|
193
|
+
/**
|
|
194
|
+
* B-074(0.65.0)**终态 tick 边**(契约见端口声明)。
|
|
195
|
+
*
|
|
196
|
+
* 🔴 **幂等在最前面**:同一条行可能被三条腿同时收到终态(终态 tick / 关卡 tool_end /
|
|
197
|
+
* task_notification),`endedPanelTasks` 是它们共用的那本账 —— 判重放在**唯一的 yield 之前**
|
|
198
|
+
* (与 `start()` 同一条零残余窗纪律),否则一条 end 会在面板上重复出现。
|
|
199
|
+
* 🔴 **inline 群组行孪生同拍冻结**:绑了卡的行要把 tick 终值冻住,否则转录里那条
|
|
200
|
+
* "Running N agents…" 会被后到的 `settle_all` 把真实工具数重置回 0(clay dogfood 那一例)。
|
|
201
|
+
* 🔴 **常驻账要清**:终态 tick 是**权威**终点 ⇒ 这条行不再是「等通知帧收尸」的常驻行。
|
|
202
|
+
*/
|
|
203
|
+
*settleFromTerminalTick(taskId, isError) {
|
|
204
|
+
if (endedPanelTasks.has(taskId))
|
|
205
|
+
return;
|
|
206
|
+
endedPanelTasks.add(taskId);
|
|
207
|
+
clearEnginePanelTaskResident(taskId);
|
|
208
|
+
const lane = laneOf(taskId);
|
|
209
|
+
const card = taskCardBinding.get(taskId);
|
|
210
|
+
if (card !== undefined) {
|
|
211
|
+
yield chrome({
|
|
212
|
+
kind: 'inline_task_stats',
|
|
213
|
+
laneProof: { lane: 'subagent', parentToolCallId: card },
|
|
214
|
+
op: 'settle',
|
|
215
|
+
cardId: card,
|
|
216
|
+
isError,
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
// SubagentStop 只对**真 fire 过 Start** 的子代(同 settleFromNotification 的 if-started 门)。
|
|
220
|
+
if (inst.hasFiredSubagentStart(taskId)) {
|
|
221
|
+
const agentType = subagentTypeById.get(taskId);
|
|
222
|
+
yield chrome({
|
|
223
|
+
kind: 'subagent_lifecycle',
|
|
224
|
+
laneProof: lane,
|
|
225
|
+
phase: 'stop',
|
|
226
|
+
taskId,
|
|
227
|
+
...(agentType !== undefined ? { agentType } : {}),
|
|
228
|
+
guard: 'if-started',
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
yield chrome({
|
|
232
|
+
kind: 'panel_task',
|
|
233
|
+
laneProof: lane,
|
|
234
|
+
event: { kind: 'end', taskId, isError },
|
|
235
|
+
});
|
|
236
|
+
},
|
|
192
237
|
};
|
|
193
238
|
}
|
package/dist/adapt/textStream.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { chrome, MAIN, transcript } from './ids.js';
|
|
1
|
+
import { chrome, MAIN, transcript, messageIdentityOf } from './ids.js';
|
|
2
2
|
import { estimateCjkTokens, FLUSH_INTERVAL_MS } from './wireShapes.js';
|
|
3
3
|
/**
|
|
4
4
|
* 件 A(#323 症状①)判据 (b) 的句末字符集 —— 中英文各一套,**闭集**(开集匹配会把「代码里的点」
|
|
@@ -76,7 +76,9 @@ export function createTextStream(ctx, idOf) {
|
|
|
76
76
|
const anchor = thinkingAnchor ?? {};
|
|
77
77
|
const msg = {
|
|
78
78
|
type: 'assistant',
|
|
79
|
-
|
|
79
|
+
// L-215③:上游投影器铸在 durable 内容帧上的两个身份位在这里**接力**,不是重铸
|
|
80
|
+
// (本构造点是重建 `{role,content}` 的,不接就原地丢掉;见 `ids.ts` 的 messageIdentityOf)。
|
|
81
|
+
message: { role: 'assistant', content: [{ type: 'thinking', thinking }], ...messageIdentityOf(anchor, ctx) },
|
|
80
82
|
uuid: idOf(anchor, 'thinking'),
|
|
81
83
|
session_id: ctx.sessionId,
|
|
82
84
|
parent_tool_use_id: null,
|
|
@@ -96,7 +98,8 @@ export function createTextStream(ctx, idOf) {
|
|
|
96
98
|
const anchor = segmentAnchor ?? {};
|
|
97
99
|
const msg = {
|
|
98
100
|
type: 'assistant',
|
|
99
|
-
|
|
101
|
+
// L-215③:同 takeThinking —— 身份位接力(帧优先、ctx 兜底;两位都读不出就一个都不铸)。
|
|
102
|
+
message: { role: 'assistant', content: [{ type: 'text', text: answerSegment }], ...messageIdentityOf(anchor, ctx) },
|
|
100
103
|
uuid: idOf(anchor, 'text'),
|
|
101
104
|
session_id: ctx.sessionId,
|
|
102
105
|
parent_tool_use_id: null,
|
package/dist/adapt.d.ts
CHANGED
|
@@ -50,7 +50,7 @@ export interface AdapterLedgerState {
|
|
|
50
50
|
/** 本批覆盖清单——差分守卫按它区分「已覆盖臂必须逐字段等价」与「已声明未覆盖臂」。 */
|
|
51
51
|
export declare const ADAPTER_COVERAGE: {
|
|
52
52
|
/** 已落码的帧臂。 */
|
|
53
|
-
readonly frames: readonly ["assistant", "user", "stream_event", "turn_usage", "result", "system", "task_notification", "workflow_complete", "diagnostics", "steering_injected", "workspace_changed", "human_input", "engine_notice", "text_end", "prompt_suggestions", "retry_status", "task_progress", "tool_end_result(label 补位 + 关卡 settle + response-id 复位 + 开卡台账出栈 + 经 cards.close 铸 tool_result)"];
|
|
53
|
+
readonly frames: readonly ["assistant", "user", "stream_event", "turn_usage", "result", "system", "task_notification", "workflow_complete", "diagnostics", "steering_injected", "workspace_changed", "human_input", "message_committed", "engine_notice", "text_end", "prompt_suggestions", "retry_status", "task_progress", "tool_end_result(label 补位 + 关卡 settle + response-id 复位 + 开卡台账出栈 + 经 cards.close 铸 tool_result)"];
|
|
54
54
|
/** 已落码臂产出的 transcript 消息类目(差分守卫的比对域)。 */
|
|
55
55
|
readonly transcriptKinds: readonly ["assistant_text", "assistant_thinking", "assistant_tool_use", "user_tool_result_decision", "user_task_notification", "system_passthrough"];
|
|
56
56
|
/** B3(0.5.0)新落码的臂/半场 —— 从 todo 移过来的,别再在 todo 里留同名条目。 */
|
package/dist/adapt.js
CHANGED
|
@@ -33,6 +33,9 @@ export const ADAPTER_COVERAGE = {
|
|
|
33
33
|
'workspace_changed',
|
|
34
34
|
// FIX⑦(2026-08-07):`human_input` 账本帧 —— 投 chrome 记账,**不铸 transcript 行**(不带正文)。
|
|
35
35
|
'human_input',
|
|
36
|
+
// B-072 ④(0.65.0):`message_committed` 定位账本帧 —— 同 human_input 归 chrome(不带正文,
|
|
37
|
+
// 绝不铸 transcript 行);端拿它自建 entryId→已渲消息 映射,解析压缩分割线的保留段锚。
|
|
38
|
+
'message_committed',
|
|
36
39
|
// #318 件①(2026-08-21):`engine_notice` 引擎结构化通告 —— 投 chrome(开集,一个码都不判)。
|
|
37
40
|
'engine_notice',
|
|
38
41
|
// #323 / core #447:assistant 散文段边界 → chrome text_segment_end(子流断闸;本批**不**动文本缓冲)。
|
|
@@ -35,7 +35,6 @@
|
|
|
35
35
|
*/
|
|
36
36
|
import type { AgentEvent, CheckpointGate } from '@sema-agent/sdk';
|
|
37
37
|
import { type SDKMessage, type EmitContext, type ModelUsage } from '../types.js';
|
|
38
|
-
import { type ClassifierBreakerView } from '../../autoModeUnavailable.js';
|
|
39
38
|
/**
|
|
40
39
|
* 本适配器铸出的**内部臂** `type` 全集(A-004.4 上游半场,2026-08-08)——「内部臂」= 桥面
|
|
41
40
|
* (bridge-facing)消息,**不是** CC SDK stdout 联合体里的帧形(那些是 assistant/stream_event/
|
|
@@ -170,15 +169,6 @@ export interface WiringManifestAutoMode {
|
|
|
170
169
|
armed: boolean;
|
|
171
170
|
/** core **六词逐字透传**。🔴 不映射 `/v1/capabilities.permissionModeAuto.reason` —— 见投影函数头注。 */
|
|
172
171
|
reason: string;
|
|
173
|
-
/**
|
|
174
|
-
* 这个**会话**上最近一次熔断闩合上的记录(core 7.10.0 `AutoModeBreakerTrip`;
|
|
175
|
-
* **server ≥7.69.0 才投** ⇒ 缺席 = 老引擎,**不是**「没熔断过」)。
|
|
176
|
-
* 🔴 与 {@link armed} / {@link reason} 之间**没有**互证关系:闩合上之后被闩住的那条腿不再把
|
|
177
|
-
* auto 意图传给后续腿,于是后续腿读作 `no_intent` 而不是 `latch_open` ——
|
|
178
|
-
* `{armed:false, reason:"no_intent", breaker:{…}}` 是最常见的合法形。理由与三态优先序写在
|
|
179
|
-
* `src/classifierStatus.ts` 的模块顶注。
|
|
180
|
-
*/
|
|
181
|
-
breaker?: ClassifierBreakerView;
|
|
182
172
|
}
|
|
183
173
|
/**
|
|
184
174
|
* {@link wiringManifestSupersetBody} 的 `mcp[]` 一条目(S-124 / core 7.5.0,server ≥7.60.0 的形)。
|