@zhushanwen/subagent-engine-sdk 0.2.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.
Files changed (139) hide show
  1. package/dist/best-effort.cjs +88 -0
  2. package/dist/best-effort.d.cts +14 -0
  3. package/dist/best-effort.d.ts +14 -0
  4. package/dist/best-effort.js +8 -0
  5. package/dist/chunk-2DIMPZCQ.js +0 -0
  6. package/dist/chunk-365AUV6N.js +67 -0
  7. package/dist/chunk-3K2P2CM2.js +127 -0
  8. package/dist/chunk-75QEMUGV.js +58 -0
  9. package/dist/chunk-7I4XGL5J.js +95 -0
  10. package/dist/chunk-A75XDJIC.js +227 -0
  11. package/dist/chunk-DSQ7JQKM.js +39 -0
  12. package/dist/chunk-EJMF63R5.js +19 -0
  13. package/dist/chunk-GT6YLLN4.js +46 -0
  14. package/dist/chunk-HYES77BR.js +109 -0
  15. package/dist/chunk-JSBRDJBE.js +30 -0
  16. package/dist/chunk-LEOBWKRM.js +128 -0
  17. package/dist/chunk-N3RL6OVM.js +38 -0
  18. package/dist/chunk-OPMY4G4M.js +27 -0
  19. package/dist/chunk-PPEPBVCC.js +120 -0
  20. package/dist/chunk-PYO3YR7W.js +16 -0
  21. package/dist/chunk-RDH3ZOV6.js +46 -0
  22. package/dist/chunk-RULLX6C6.js +11 -0
  23. package/dist/chunk-X24SFZYW.js +6646 -0
  24. package/dist/chunk-YFSN3D5N.js +216 -0
  25. package/dist/chunk-ZOFFJNJD.js +136 -0
  26. package/dist/chunk-ZXEAW25V.js +132 -0
  27. package/dist/cli-entry.cjs +119 -0
  28. package/dist/cli-entry.d.cts +24 -0
  29. package/dist/cli-entry.d.ts +24 -0
  30. package/dist/cli-entry.js +8 -0
  31. package/dist/contract-types-sSlgppBC.d.cts +352 -0
  32. package/dist/contract-types-sSlgppBC.d.ts +352 -0
  33. package/dist/data-dir.cjs +117 -0
  34. package/dist/data-dir.d.cts +20 -0
  35. package/dist/data-dir.d.ts +20 -0
  36. package/dist/data-dir.js +12 -0
  37. package/dist/env.cjs +205 -0
  38. package/dist/env.d.cts +73 -0
  39. package/dist/env.d.ts +73 -0
  40. package/dist/env.js +16 -0
  41. package/dist/error-codes-DHco5-i_.d.cts +118 -0
  42. package/dist/error-codes-Dhss2Kmk.d.ts +118 -0
  43. package/dist/error-message.cjs +40 -0
  44. package/dist/error-message.d.cts +3 -0
  45. package/dist/error-message.d.ts +3 -0
  46. package/dist/error-message.js +7 -0
  47. package/dist/index.cjs +8375 -0
  48. package/dist/index.d.cts +23 -0
  49. package/dist/index.d.ts +23 -0
  50. package/dist/index.js +268 -0
  51. package/dist/journal-io.cjs +70 -0
  52. package/dist/journal-io.d.cts +12 -0
  53. package/dist/journal-io.d.ts +12 -0
  54. package/dist/journal-io.js +7 -0
  55. package/dist/journal-replay.cjs +256 -0
  56. package/dist/journal-replay.d.cts +45 -0
  57. package/dist/journal-replay.d.ts +45 -0
  58. package/dist/journal-replay.js +17 -0
  59. package/dist/kill-chain.cjs +221 -0
  60. package/dist/kill-chain.d.cts +74 -0
  61. package/dist/kill-chain.d.ts +74 -0
  62. package/dist/kill-chain.js +23 -0
  63. package/dist/logger.cjs +84 -0
  64. package/dist/logger.d.cts +24 -0
  65. package/dist/logger.d.ts +24 -0
  66. package/dist/logger.js +11 -0
  67. package/dist/logs/stderr-rotation.cjs +151 -0
  68. package/dist/logs/stderr-rotation.d.cts +37 -0
  69. package/dist/logs/stderr-rotation.d.ts +37 -0
  70. package/dist/logs/stderr-rotation.js +23 -0
  71. package/dist/nesting-guard.cjs +95 -0
  72. package/dist/nesting-guard.d.cts +65 -0
  73. package/dist/nesting-guard.d.ts +65 -0
  74. package/dist/nesting-guard.js +15 -0
  75. package/dist/node-executor.cjs +180 -0
  76. package/dist/node-executor.d.cts +63 -0
  77. package/dist/node-executor.d.ts +63 -0
  78. package/dist/node-executor.js +16 -0
  79. package/dist/paths.cjs +55 -0
  80. package/dist/paths.d.cts +8 -0
  81. package/dist/paths.d.ts +8 -0
  82. package/dist/paths.js +15 -0
  83. package/dist/port-contract.cjs +35 -0
  84. package/dist/port-contract.d.cts +88 -0
  85. package/dist/port-contract.d.ts +88 -0
  86. package/dist/port-contract.js +7 -0
  87. package/dist/protocol/index.cjs +400 -0
  88. package/dist/protocol/index.d.cts +685 -0
  89. package/dist/protocol/index.d.ts +685 -0
  90. package/dist/protocol/index.js +89 -0
  91. package/dist/relay-env.cjs +71 -0
  92. package/dist/relay-env.d.cts +37 -0
  93. package/dist/relay-env.d.ts +37 -0
  94. package/dist/relay-env.js +23 -0
  95. package/dist/schema-emulation.cjs +6680 -0
  96. package/dist/schema-emulation.d.cts +39 -0
  97. package/dist/schema-emulation.d.ts +39 -0
  98. package/dist/schema-emulation.js +11 -0
  99. package/dist/spawn.cjs +200 -0
  100. package/dist/spawn.d.cts +80 -0
  101. package/dist/spawn.d.ts +80 -0
  102. package/dist/spawn.js +16 -0
  103. package/dist/ui-channels.cjs +120 -0
  104. package/dist/ui-channels.d.cts +60 -0
  105. package/dist/ui-channels.d.ts +60 -0
  106. package/dist/ui-channels.js +9 -0
  107. package/dist/ui-types.cjs +18 -0
  108. package/dist/ui-types.d.cts +62 -0
  109. package/dist/ui-types.d.ts +62 -0
  110. package/dist/ui-types.js +1 -0
  111. package/package.json +58 -0
  112. package/src/best-effort.ts +37 -0
  113. package/src/cli-entry.ts +77 -0
  114. package/src/data-dir.ts +88 -0
  115. package/src/env.ts +265 -0
  116. package/src/error-message.ts +22 -0
  117. package/src/index.ts +63 -0
  118. package/src/journal-io.ts +82 -0
  119. package/src/journal-replay.ts +432 -0
  120. package/src/kill-chain.ts +265 -0
  121. package/src/logger.ts +105 -0
  122. package/src/logs/stderr-rotation.ts +166 -0
  123. package/src/nesting-guard.ts +140 -0
  124. package/src/node-executor.ts +272 -0
  125. package/src/paths.ts +48 -0
  126. package/src/port-contract.ts +117 -0
  127. package/src/protocol/contract-types.ts +378 -0
  128. package/src/protocol/engine-protocol.ts +81 -0
  129. package/src/protocol/error-codes.ts +179 -0
  130. package/src/protocol/frames.ts +145 -0
  131. package/src/protocol/index.ts +12 -0
  132. package/src/protocol/methods.ts +229 -0
  133. package/src/protocol/reverse-channels.ts +274 -0
  134. package/src/protocol/schema.ts +154 -0
  135. package/src/relay-env.ts +60 -0
  136. package/src/schema-emulation.ts +192 -0
  137. package/src/spawn.ts +246 -0
  138. package/src/ui-channels.ts +219 -0
  139. package/src/ui-types.ts +84 -0
package/src/paths.ts ADDED
@@ -0,0 +1,48 @@
1
+ import { join } from 'node:path';
2
+
3
+ /**
4
+ * 引擎数据目录布局 SSOT(引擎侧原语,自 core execution/engine/paths.ts 移入
5
+ * @zhushanwen/subagent-engine-sdk,实现体逐字等价)。
6
+ * 迁移处置(impl-plan §2.1 paths 行):纯 `node:path` 模块 → **移入 SDK**(引擎侧需
7
+ * 自算池/journal 路径);core 侧引用切换已完成(core execution/engine/paths.ts 为
8
+ * re-export shim,子入口 ./engine/paths 解析路径不变)。
9
+ *
10
+ * 设计权威源:subagent-engine-abstraction.md D5/D6。
11
+ *
12
+ * 为什么独立成模块:extension 写侧(journal 落盘 / preparer 池目录)与
13
+ * runtime 校验侧(subagent-extractor 前缀白名单)必须同源推导——
14
+ * 双方 import 同一份纯函数,禁止各自拼字符串漂移。
15
+ *
16
+ * 布局:`<dataDir>/engines/<engineId>/<pool-key>/journal-<taskId>.jsonl`
17
+ * 隔离池跨任务保留复用;journal 生命周期跟随 record,不随池删除(D5)。
18
+ */
19
+
20
+ /** 路径段安全编码后的最大字符数(防超长段击穿文件名长度上限;runtime 校验侧同源)。 */
21
+ const MAX_SEG_CHARS = 80;
22
+
23
+ /** 路径段进入文件系统前的安全编码:路径穿越、分隔符、空白、超长全部归一。 */
24
+ export function sanitizeSeg(input: string): string {
25
+ const s = input.replace(/[^A-Za-z0-9-]+/g, '-').replace(/^-+|-+$/g, '');
26
+ return s.length > 0 ? s.slice(0, MAX_SEG_CHARS) : 'default';
27
+ }
28
+
29
+ export function resolveEnginesRoot(dataDir: string): string {
30
+ return join(dataDir, 'engines');
31
+ }
32
+
33
+ export function resolveEngineDir(dataDir: string, engineId: string): string {
34
+ return join(resolveEnginesRoot(dataDir), sanitizeSeg(engineId));
35
+ }
36
+
37
+ export function resolvePoolDir(dataDir: string, engineId: string, poolKey: string): string {
38
+ return join(resolveEngineDir(dataDir, sanitizeSeg(engineId)), sanitizeSeg(poolKey));
39
+ }
40
+
41
+ export function resolveJournalPath(
42
+ dataDir: string,
43
+ engineId: string,
44
+ poolKey: string,
45
+ taskId: string,
46
+ ): string {
47
+ return join(resolvePoolDir(dataDir, engineId, poolKey), `journal-${sanitizeSeg(taskId)}.jsonl`);
48
+ }
@@ -0,0 +1,117 @@
1
+ // src/port-contract.ts
2
+ //
3
+ // 引擎进程内契约面七符号 + parseCtxModel 单源(S4 簇 1 收编:pi/zcode 两包
4
+ // port-types.ts 的逐字等价本地镜像收编——两包原地改 re-export shim,18 个 import
5
+ // 点零改写;server.ts 的 parseCtxModel 模块级纯函数同批收编,实现以 pi 版为基线
6
+ // 逐字迁移)。
7
+ //
8
+ // 为什么现在能收(W5/W7 双轨沉淀后的收编,不翻「SDK 类型闭包只收跨进程协议面」
9
+ // 的原始裁决):两包过渡期镜像经 W10 conformance 套件验证字段逐字等价、双轨已
10
+ // 稳定,收编即消除克隆而非改变边界语义。RunContext 含 AbortSignal/回调/EngineStream
11
+ // 等非序列化成员,跨进程面经各包 server.ts 帧映射——故收主 barrel,不进 protocol/
12
+ // 子入口(protocol/ 是 semver 收窄的跨进程可序列化面)。
13
+ //
14
+ // 命名:全量任务声明在 SDK 侧名 EngineAgentCallOpts(主 barrel 已有 protocol 的
15
+ // AgentCallOpts 引擎面子集——16 字段协议 run.params.task 形态,两者是子集/全量
16
+ // 关系,不可同名共存;两包 shim 转名 re-export 保本包消费面 AgentCallOpts 不变)。
17
+ //
18
+ // onChildSpawned 统一采窄载荷形态(host/childSpawned 载荷形态;ChildProcess 句柄
19
+ // 不跨协议面)——zcode 侧生产零调用(D6),形态统一无行为影响。
20
+ //
21
+ // 第三份镜像登记:core execution/engine/port.ts 的 RunContext 是宿主侧独立契约
22
+ // (onChildSpawned 全 ChildProcess 句柄,概念域 = 宿主进程内),不收编、不 import
23
+ // 本模块;漂移面由 W10 conformance 套件继续覆盖。
24
+
25
+ import type {
26
+ AgentCallOpts as SdkAgentCallOpts,
27
+ AgentEvent,
28
+ AgentOutcome,
29
+ EngineCapabilities,
30
+ EngineHandleData,
31
+ InteractAction,
32
+ InteractResult,
33
+ ProbeReport,
34
+ ResumeAnchor,
35
+ SessionView,
36
+ } from "./protocol/contract-types.ts";
37
+
38
+ /**
39
+ * 引擎进程内全量任务声明 = SDK AgentCallOpts 引擎面子集 + 协议 ctx 还原字段(model/
40
+ * cwd/schemaEnv——SDK 契约把它们从 task 移到 run.params.ctx,进程内接口合回单对象;
41
+ * server.ts 做 ctx→task 还原,与 core RemoteEngine.toSdkTaskSubset 镜像)。
42
+ */
43
+ export type EngineAgentCallOpts = SdkAgentCallOpts & {
44
+ model?: string;
45
+ cwd?: string;
46
+ schemaEnv?: string;
47
+ };
48
+
49
+ /**
50
+ * 引擎进程内的 ctxModel 形态(core ModelInfo 的结构等价镜像——仅 id/provider 被引擎
51
+ * 消费,name/reasoning 等字段透传保留防测试/未来消费面漂移)。
52
+ */
53
+ export interface EngineCtxModel {
54
+ id: string;
55
+ provider: string;
56
+ name?: string;
57
+ reasoning?: boolean;
58
+ thinkingLevelMap?: Record<string, unknown>;
59
+ contextWindow?: number;
60
+ }
61
+
62
+ /** text_delta streaming 出口(协议 host/streamDelta 的本地承载)。 */
63
+ export interface EngineStream {
64
+ onDelta(delta: string): void;
65
+ }
66
+
67
+ /** run 的运行期上下文(core RunContext 结构等价镜像;chat? = 会话形态参数,缺省一次性任务)。 */
68
+ export interface RunContext {
69
+ taskId: string;
70
+ poolKey: string;
71
+ signal?: AbortSignal;
72
+ onEvent?: (event: AgentEvent) => void;
73
+ ctxModel?: EngineCtxModel;
74
+ stream?: EngineStream;
75
+ schemaEnv?: string;
76
+ engineFallback?: { from: string; reason: string };
77
+ onPoolResolved?: (poolKey: string) => void;
78
+ onHandleReady?: (partial: Pick<EngineHandleData, "sessionRef" | "poolKey">) => void;
79
+ /** 一次性子进程 pid 上报(host/childSpawned 载荷形态;ChildProcess 句柄不跨协议面)。 */
80
+ onChildSpawned?: (child: { pid: number | undefined; killed: boolean }) => void;
81
+ /**
82
+ * [v1.x] chat 会话形态参数(协议 run.params.chat 的进程内还原;缺省 = 一次性任务
83
+ * 形态)。recordId = chat 轮次关联键与 interact 定位键;resume 锚点存在 = 冷续
84
+ * (--session 续写原文件),不存在 = 首轮新建。
85
+ */
86
+ chat?: { recordId: string; resume?: ResumeAnchor };
87
+ }
88
+
89
+ export interface EngineHandle {
90
+ readonly data: EngineHandleData;
91
+ }
92
+
93
+ export interface EngineRunResult {
94
+ handle: EngineHandle;
95
+ outcome: AgentOutcome;
96
+ }
97
+
98
+ /** 引擎进程内的引擎契约点(core EnginePort 的结构等价镜像)。 */
99
+ export interface EnginePort {
100
+ readonly id: string;
101
+ capabilities(): EngineCapabilities;
102
+ probe(opts?: { force?: boolean }): Promise<ProbeReport>;
103
+ run(task: EngineAgentCallOpts, ctx: RunContext): Promise<EngineRunResult>;
104
+ interact(handle: EngineHandle, action: InteractAction): Promise<InteractResult>;
105
+ read(handle: EngineHandle): Promise<SessionView>;
106
+ listModels?(): Array<{ id: string; name?: string }> | null;
107
+ validateModel?(modelRef: string | undefined): { canonicalRef: string };
108
+ dispose?(): Promise<void>;
109
+ }
110
+
111
+ /** ctx.ctxModel("provider/id" canonical 词形)→ EngineCtxModel。 */
112
+ export function parseCtxModel(ref: string | undefined): EngineCtxModel | undefined {
113
+ if (ref === undefined || ref.trim() === "") return undefined;
114
+ const slash = ref.indexOf("/");
115
+ if (slash <= 0 || slash === ref.length - 1) return undefined;
116
+ return { provider: ref.slice(0, slash), id: ref.slice(slash + 1) };
117
+ }
@@ -0,0 +1,378 @@
1
+ // src/protocol/contract-types.ts
2
+ //
3
+ // 引擎面契约类型 SSOT(协议两侧不许各写一份;core 反向 re-export 保上层消费面)。
4
+ // 设计权威源:docs/design/subagent-engine-protocolization.md §3.5.1 D7 类型闭包表 +
5
+ // impl-plan §2.1「类型闭包处置」。
6
+ //
7
+ // 搬运口径(逐字对照,结构等价、零 core import):
8
+ // - AgentEvent / AgentUsage / AgentUsageTotal / ToolCallResult / ToolCall /
9
+ // InternalToolCall / Turn ← core execution/types.ts(2026-09-09 实测 :164-:313)
10
+ // - ReplayedTurn / SessionView / EngineHandleData / EngineCapabilities / ProbeReport /
11
+ // InteractAction / InteractResult / AgentOutcome ← core execution/engine/types.ts
12
+ // - AgentFailureKind / AgentOutcomeUsage(core 名 AgentUsage,orchestration 版)/
13
+ // ToolCallEntry / AgentCallOpts 子集 ← core orchestration/models/types.ts
14
+ // - WorktreeHandle ← core execution/types.ts:349(SDK 结构等价副本——设计 §3.5.1
15
+ // 点名「AgentCallOpts.worktree 的 WorktreeHandle 即这类副本」)
16
+ //
17
+ // core 域类型(ExecutionRecord / Turn 的宿主内部态消费)留 core;SDK 侧一切类型为
18
+ // 结构等价形态,漂移由双向可赋值断言(AssertMutuallyAssignable)在 typecheck 期抓出
19
+ // ——core 侧断言挂靠归 W2(本文件导出该类型助手供其复用),SDK 侧样板见
20
+ // src/__tests__/contract-closure.test.ts。
21
+
22
+ // ============================================================
23
+ // 断言助手(W2 core 侧双向可赋值断言复用)
24
+ // ============================================================
25
+
26
+ /**
27
+ * 双向可赋值断言:`type _A = AssertMutuallyAssignable<CoreX, SdkX>` 结果必须为 true。
28
+ * 任一方向不可赋值(字段缺失 / 可选性漂移 / 联合分支不齐)结果为 never → 编译失败。
29
+ * 用法(core 侧 W2 挂靠):
30
+ * import type { AssertMutuallyAssignable } from "@zhushanwen/subagent-engine-sdk";
31
+ * type _CoreSdkAgentEvent = AssertMutuallyAssignable<CoreAgentEvent, SdkAgentEvent>;
32
+ * const _assert: _CoreSdkAgentEvent = true;
33
+ */
34
+ export type AssertMutuallyAssignable<A, B> = [A] extends [B]
35
+ ? [B] extends [A]
36
+ ? true
37
+ : never
38
+ : never;
39
+
40
+ // ============================================================
41
+ // 事件面(AgentEvent 及其字段型)
42
+ // ============================================================
43
+
44
+ /** token 用量(message_end 单条消息增量)。← core execution/types.ts AgentUsage。 */
45
+ export interface AgentUsage {
46
+ input: number;
47
+ output: number;
48
+ cacheRead: number;
49
+ cacheWrite: number;
50
+ /** 本 message 的成本(USD)。无成本数据时缺省。 */
51
+ cost?: number;
52
+ }
53
+
54
+ export interface AgentUsageTotal extends AgentUsage {
55
+ /** 四项之和。投影时不再手工求和。 */
56
+ total: number;
57
+ /** 累计成本(USD)。无成本数据时为 0。 */
58
+ cost: number;
59
+ }
60
+
61
+ /** tool 调用结果(tool_end 携带,含 structured-output 的 details)。 */
62
+ export interface ToolCallResult {
63
+ content?: unknown[];
64
+ details?: unknown;
65
+ }
66
+
67
+ /** tool 调用(导出的纯净数据形状,不含内部状态机)。 */
68
+ export interface ToolCall {
69
+ toolName: string;
70
+ args?: unknown;
71
+ result?: ToolCallResult;
72
+ isError?: boolean;
73
+ }
74
+
75
+ /** 内部 ToolCall:追加 _status 进行中标记与 startedTs(reducer 内部态,跨边界导出前 strip)。 */
76
+ export interface InternalToolCall extends ToolCall {
77
+ _status: "running" | "done" | "failed";
78
+ /** tool_start 到达时的墙钟时间戳(Date.now(),ms)。 */
79
+ startedTs: number;
80
+ }
81
+
82
+ /** 一个 turn 的完整内容(reducer turns[] 的元素)。 */
83
+ export interface Turn {
84
+ /** 本 turn assistant 正文(text_delta 流式累积,完整)。 */
85
+ text: string;
86
+ /** 本 turn 推理(thinking_delta 流式累积,完整)。 */
87
+ thinking: string;
88
+ /** 本 turn 工具调用(InternalToolCall:含完整 result + _status 进行中标记)。 */
89
+ toolCalls: InternalToolCall[];
90
+ /** 本 turn message_end 的 token 增量(聚合得 usage 总量)。 */
91
+ usageDelta?: AgentUsage;
92
+ /** turn_end 是否已到达。false=正在进行;true=已闭合。 */
93
+ closed: boolean;
94
+ /** turn_end 到达时的墙钟时间戳(Date.now(),ms)。 */
95
+ closedTs?: number;
96
+ }
97
+
98
+ /**
99
+ * 引擎事件(8 种,协议 event.params.event 逐字序列化——「事件与 handle 序列化逐字
100
+ * 兼容」不变量 3 的类型面)。语义锚点 = pi(ACP 词汇对照见 core execution/types.ts 注释)。
101
+ */
102
+ export type AgentEvent =
103
+ | { type: "tool_start"; toolName: string; args?: unknown }
104
+ | { type: "tool_end"; toolName: string; args?: unknown; result?: ToolCallResult; isError?: boolean }
105
+ | { type: "text_delta"; delta: string }
106
+ | { type: "thinking_delta"; delta: string }
107
+ | { type: "turn_end"; summary?: string }
108
+ | { type: "message_end"; usage?: AgentUsage; error?: string }
109
+ | { type: "compaction" }
110
+ | { type: "error"; message: string };
111
+
112
+ // ============================================================
113
+ // handle / read 视图
114
+ // ============================================================
115
+
116
+ /**
117
+ * EngineHandle 的持久化形态(JSON v1)。协议 run 终态应答 / interact / read 的
118
+ * handle 载荷(引擎不持有宿主运行时引用,data 即全部)。
119
+ */
120
+ export interface EngineHandleData {
121
+ v: 1;
122
+ /** 引擎 id('pi' | 'zcode' | ...)。 */
123
+ engineId: string;
124
+ /** 引擎自定义定位键值。pi = { recordId?, sessionFile? };zcode = { sessionId, dbPath }。 */
125
+ sessionRef: Record<string, string>;
126
+ /** 隔离池定位。pi 无池化恒 'shared'。 */
127
+ poolKey: string;
128
+ /** journal 绝对路径(read 第②级数据源;宿主读前校验前缀白名单)。缺省 = 无 journal。 */
129
+ journalPath?: string;
130
+ /** probe 实测版本(漂移排查锚点)。 */
131
+ engineVersion?: string;
132
+ /** 适配器版本(golden 样本对齐排查)。 */
133
+ adapterVersion: string;
134
+ }
135
+
136
+ /**
137
+ * [v1.x] 冷续 resume 锚点——EngineHandleData 定位键的投影子集(诊断字段
138
+ * v/engineVersion/adapterVersion 不属锚点语义,不随锚点走)。两处消费:
139
+ * - run.params.chat.resume(宿主 → 引擎:冷续重开已 idle 的 session,pi 消费
140
+ * sessionRef.sessionFile —— 对照 core SpawnResumeOpts.sessionFile 的锚点面);
141
+ * - host/roundLifecycle 载荷 anchor(引擎 → 宿主:轮次终态时回填当前锚点,
142
+ * 宿主据此刷新冷续依据——pi 定位键形态同 EngineHandleData.sessionRef 注释)。
143
+ * 类型层与 EngineHandleData 定位形态的对照由测试断言(Pick 可赋值闭包)锁定。
144
+ */
145
+ export interface ResumeAnchor {
146
+ /** 引擎定位键(pi = { recordId?, sessionFile? };zcode = { sessionId, dbPath })。 */
147
+ sessionRef: Record<string, string>;
148
+ /** 隔离池定位(锚点补全 handle 重建所需;pi 无池化恒 'shared')。 */
149
+ poolKey: string;
150
+ /** journal 绝对路径(read 降级链第②级数据源;无 journal 缺省)。 */
151
+ journalPath?: string;
152
+ }
153
+
154
+ /** Turn → ReplayedTurn:剥离内部态(closed 恒 true——重放物无进行时语义)。 */
155
+ export interface ReplayedTurn {
156
+ text: string;
157
+ thinking: string;
158
+ /** 导出的纯净形状(ToolCall,无 _status/startedTs)。 */
159
+ toolCalls: ToolCall[];
160
+ closed: true;
161
+ }
162
+
163
+ /**
164
+ * session 历史的引擎中立视图(协议 read 应答)。降级链三级:①引擎原生读取 →
165
+ * ②宿主 event journal 重放 → ③outcome-only。source 字段是 GUI 降级标记数据源。
166
+ */
167
+ export interface SessionView {
168
+ engineId: string;
169
+ sessionId?: string;
170
+ /** turns[] 派生数据(重放/重建产物)。 */
171
+ turns: ReplayedTurn[];
172
+ /** 各 turn usageDelta 聚合。 */
173
+ usage?: AgentUsageTotal;
174
+ source: "native" | "journal" | "outcome-only";
175
+ }
176
+
177
+ // ============================================================
178
+ // 能力 / 探针 / 交互
179
+ // ============================================================
180
+
181
+ /**
182
+ * 引擎能力声明(11 位)。三级:native / emulated / unsupported。
183
+ * 声明的是本仓 subagent 链路实际接通的能力,不是引擎 RPC 层的理论能力。
184
+ * 同步权威 = manifest(注册期直读);握手应答仅诊断(§3.3「同步成员清单」)。
185
+ */
186
+ export interface EngineCapabilities {
187
+ /** native: --json-schema/--output-schema/env 注入。 */
188
+ schemaEnforcement: "native" | "emulated";
189
+ /** 注意区分「引擎 RPC 层有此能力」与「subagent 链路已接通」。 */
190
+ steer: "native" | "emulated" | "unsupported";
191
+ /** interact 控制面(message/close/cancel + idle)。 */
192
+ conversation: "native" | "unsupported";
193
+ /** 决定 persona 路由策略(file/flag/prompt 通道)。 */
194
+ personaInjection: "file" | "flag" | "prompt";
195
+ /** 粗粒度引擎:GUI 显示降级为阶段态。 */
196
+ eventGranularity: "stream" | "coarse";
197
+ /** emulated = worktree 隔离(无 OS sandbox 的引擎用文件写维度隔离补齐)。 */
198
+ sandbox: "native" | "emulated" | "none";
199
+ /** 重建历史的能力(read 降级链第①级保真度上限)。 */
200
+ sessionRead: "full" | "partial" | "outcome-only";
201
+ resume: "native" | "cold" | "unsupported";
202
+ /** 优雅中断 or 只能杀进程(公共杀链兜底)。 */
203
+ interrupt: "native" | "kill-only";
204
+ /** kimi headless 固定 auto = ignored;GUI 据此隐藏/提示。 */
205
+ permissionMode: "native" | "fixed" | "ignored";
206
+ /** maxTurns 轮数上限执行能力位(pi=true / zcode=false)。 */
207
+ maxTurns: boolean;
208
+ }
209
+
210
+ /** 引擎探针报告(probe 应答)。ok=false 时 error 必填(恢复指引)。 */
211
+ export interface ProbeReport {
212
+ ok: boolean;
213
+ /** 实测版本(探测不到时为空串)。 */
214
+ engineVersion: string;
215
+ /** 二进制存在/版本解析/干跑回归逐项。 */
216
+ checks: Array<{ name: string; ok: boolean; detail?: string }>;
217
+ /** engine_probe_failed 的恢复指引(ok=false 时必填)。 */
218
+ error?: { code: string; recovery: string };
219
+ }
220
+
221
+ /**
222
+ * interact 的 action(交互控制面)。interrupt: true = steer(抢占)/ false|缺省 =
223
+ * followUp(排队);不支持抢占的引擎忽略。
224
+ */
225
+ export type InteractAction =
226
+ | { kind: "message"; payload: string; interrupt?: boolean }
227
+ | { kind: "close"; payload?: { force: boolean } }
228
+ | { kind: "cancel" };
229
+
230
+ /** interact 的结果(失败码 = engine_session_not_resumable / engine_capability_unsupported 等)。 */
231
+ export type InteractResult =
232
+ | { ok: true; delivered: true }
233
+ | { ok: false; code: string; message: string };
234
+
235
+ // ============================================================
236
+ // 终态 / 任务声明
237
+ // ============================================================
238
+
239
+ /** 失败分诊结构化标签。unknown(含缺省)= 可重试(语义守恒)。 */
240
+ export type AgentFailureKind = "stale_context" | "schema_deterministic" | "unknown";
241
+
242
+ /**
243
+ * AgentOutcome.usage 字段型(← core orchestration/models/types.ts AgentUsage 结构等价;
244
+ * SDK 改名消歧——core 的两个同名 AgentUsage 分属 execution 与 orchestration 域)。
245
+ */
246
+ export interface AgentOutcomeUsage {
247
+ input: number;
248
+ output: number;
249
+ cacheRead: number;
250
+ cacheWrite: number;
251
+ cost: number;
252
+ contextTokens: number;
253
+ turns: number;
254
+ }
255
+
256
+ /** 单次 tool 调用记录(workflow trace 形态)。 */
257
+ export interface ToolCallEntry {
258
+ /** Tool name. */
259
+ name: string;
260
+ /** Args preview string. */
261
+ input: string;
262
+ }
263
+
264
+ /** worktree 句柄(结构等价副本;core 权威定义在 execution/types.ts:349)。 */
265
+ export interface WorktreeHandle {
266
+ /** checkout 目录(子 agent 工作目录)。 */
267
+ readonly path: string;
268
+ readonly branch: string;
269
+ readonly baseCommit: string;
270
+ /** 主仓库根目录(cleanup/scan 需要)。 */
271
+ readonly mainCwd: string;
272
+ }
273
+
274
+ /**
275
+ * 一次引擎执行的终态(协议 run 终态应答的 outcome 载荷)。锚定 core
276
+ * orchestration AgentResult 并追加引擎层字段(engineId / engineFallback / exitCode)。
277
+ */
278
+ export interface AgentOutcome {
279
+ content: string;
280
+ /** 失败分诊标签。产出侧 = 引擎;缺省 = unknown = 可重试。 */
281
+ failureKind?: AgentFailureKind;
282
+ /** native 引擎直传 / 仿真层 ajv 产出(D4 硬分流:native 路径宿主不做二次校验)。 */
283
+ parsedOutput?: unknown;
284
+ usage?: AgentOutcomeUsage;
285
+ durationMs?: number;
286
+ /** 错误码前缀格式(`<code>: <detail>`,错误规格见协议 error-codes)。 */
287
+ error?: string;
288
+ /** 引擎语义 session id。 */
289
+ sessionId?: string;
290
+ sessionFile?: string;
291
+ /** 仅诊断——目录可能已被 finalize 清理,不得作为 cwd 复用。 */
292
+ worktreePath?: string;
293
+ toolCalls?: ToolCallEntry[];
294
+ /** 实际执行引擎(fallback 后可能 ≠ 请求值)。 */
295
+ engineId: string;
296
+ /** fallback 留痕(record 同步投影,GUI 警告条数据源)。 */
297
+ engineFallback?: { from: string; reason: string };
298
+ /** null = 被信号杀死(杀链/abort 合成终态的判据)。 */
299
+ exitCode?: number | null;
300
+ }
301
+
302
+ // ============================================================
303
+ // AgentCallOpts 引擎面子集(协议 run.params.task)
304
+ // ============================================================
305
+
306
+ /**
307
+ * 引擎模型目录条目(manifest `modelCatalog.models` 条目形态,设计 §3.4 示例)。
308
+ * 协议面 = initialize 应答 models? 与 listModels 应答 models 的元素型;
309
+ * manifest 解析与生成(gen:model-catalog)归 W4/W5 实装。
310
+ */
311
+ export interface ModelCatalogEntry {
312
+ id: string;
313
+ aliases?: string[];
314
+ canonicalRef?: string;
315
+ }
316
+
317
+ /**
318
+ * 单次 agent 调用的任务声明——引擎面子集(协议 run.params.task;core 全量
319
+ * AgentCallOpts 22 字段留 core,core 侧反向 re-export 保消费面)。
320
+ *
321
+ * 字段裁决(对照 core orchestration/models/types.ts AgentCallOpts,2026-09-09):
322
+ * - 入选 = 引擎消费面:任务语义(prompt/schema/thinkingLevel/skill/skillPath/agent/persona 注入)、
323
+ * 轮次预算(maxTurns/graceTurns/conversation/idleTimeoutMs)、隔离与权限(worktree/
324
+ * fork/forkSource/denyTools/permissionMode)、诊断(description/scene);
325
+ * - 排除并改挂 run.params.ctx(协议层已单列,task 内双写会分叉):model(→ctx.model)、
326
+ * schemaEnv(→ctx.schemaEnv)、cwd(→ctx.cwd)、engineFallback(→ctx.engineFallback);
327
+ * - 排除(宿主侧消费,无引擎语义):engine(路由决策已完成,收到的引擎即选中值)、
328
+ * timeoutMs(宿主超时链 mergeTimeoutSignal → cancel 帧,非引擎参数)、returnMeta
329
+ * (core 注释明确「dropped at the pi boundary」,非引擎消费)。
330
+ *
331
+ * W2 实装 EngineClient run 帧时以本类型为 params.task;core 侧全量 → 子集的方向性
332
+ * 收窄(多余字段宿主自持不透传)不构成类型漂移(断言方向见 contract-closure 测试样板)。
333
+ */
334
+ export interface AgentCallOpts {
335
+ /** The task prompt to send to the agent. */
336
+ prompt: string;
337
+ /** Optional JSON schema for structured output(引擎按 capabilities.schemaEnforcement 分流)。 */
338
+ schema?: Record<string, unknown>;
339
+ /** Thinking level override("high" | "medium" | "low" 等引擎自解释词表)。 */
340
+ thinkingLevel?: string;
341
+ /** Scene name passed through for model-selection hints. */
342
+ scene?: string;
343
+ /** Turn 上限(turn limiter)。未传或 <=0 = 不限。 */
344
+ maxTurns?: number;
345
+ /** Turn limiter 宽限轮数:超 maxTurns 后允许继续的轮数。 */
346
+ graceTurns?: number;
347
+ /** Skill name to load(引擎解析为 SKILL.md 注入)。 */
348
+ skill?: string;
349
+ /** Resolved absolute path to the skill directory or SKILL.md file. */
350
+ skillPath?: string;
351
+ /** Human-readable description for logging and debugging(slug 源字段)。 */
352
+ description?: string;
353
+ /** Agent ref (absolute .md path)——身份解析锚点。 */
354
+ agent?: string;
355
+ /** System prompt injection CONTENT(非文件路径)。 */
356
+ appendSystemPrompt?: string[];
357
+ /** Inherit parent session context (fork mode)。与 worktree(文件隔离)独立。 */
358
+ fork?: boolean;
359
+ /**
360
+ * [v1.x 增量] fork-from 显式分叉源 session 文件绝对路径(断联 subagent 接续场景,
361
+ * 宿主点名任意已有 session 文件;fork=true 则由引擎用主 session 作源,两者互斥——
362
+ * 本字段存在时优先)。字段名对齐引擎侧既有 SpawnRunParams.forkSource(pi 引擎经
363
+ * `--fork <path>` 消费)。可选增量、负向兼容:无此概念的引擎(zcode)按未知可选
364
+ * 字段忽略,行为与不传一致;宿主能力门(capability-gate)仍按 steer/conversation
365
+ * 通道族预检,不依赖引擎对本字段的支持声明。
366
+ */
367
+ forkSource?: string;
368
+ /** Filesystem isolation: 新建 worktree | 复用外部已创建 worktree | 不隔离。 */
369
+ worktree?: boolean | WorktreeHandle;
370
+ /** 可持续对话模式:true = 轮次完成进 idle 态等待 message 续聊。 */
371
+ conversation?: boolean;
372
+ /** 空闲超时毫秒数(仅 conversation 模式有意义)。显式 0/负 = 禁用 idle GC。 */
373
+ idleTimeoutMs?: number;
374
+ /** 工具 denylist(各引擎做语法映射)。 */
375
+ denyTools?: string[];
376
+ /** 中立权限模式(映射按各引擎 capabilities.permissionMode)。 */
377
+ permissionMode?: string;
378
+ }
@@ -0,0 +1,81 @@
1
+ // src/protocol/engine-protocol.ts
2
+ //
3
+ // 引擎协议 v1 版本常量与协商(W1 契约根)。设计权威源:
4
+ // docs/design/subagent-engine-protocolization.md §3.3 + impl-plan §2.1。
5
+ //
6
+ // 传输 = stdio NDJSON(每行一个 JSON 对象)。stdout 独占协议帧;stderr 常驻排空
7
+ // (内存环形缓冲尾 400 字符,崩溃现场由 engine_crashed 携带,宿主侧不落盘)。
8
+ //
9
+ // 版本协商:ENGINE_PROTOCOL_VERSION = 1;core 支持 >=1 <2;越界 →
10
+ // engine_protocol_mismatch(含双方版本 + 升级指引),该引擎标记不可用,
11
+ // 不影响其他引擎与宿主。
12
+ //
13
+ // [v1.x 增量语义(chat-domain 设计 §3.2 D1-A/§3.3)]:chat 域增量(run.params.chat
14
+ // 可选参数、host/roundLifecycle 通道、host/streamDelta 的 recordId 关联形态)以
15
+ // **可选载荷/可选参数**形态向后兼容,major 不 bump、不引入 minor 协商位:
16
+ // - 新 core × 旧引擎:chat 请求被 conversation gate 同步拒(manifest 无 gate 位,
17
+ // A6 方向——engine_capability_unsupported + 升级引擎包指引);run 域零影响;
18
+ // - 旧 core × 新引擎:新引擎可能发出旧 core 词表外的 host/roundLifecycle——
19
+ // 既有反向路由对未知 host/* 通道回 {unsupported:true} 引擎自行降级,无需
20
+ // 独立负向场景(设计已裁决)。
21
+
22
+ /** 协议版本(引擎包 manifest `xyz-agent.subagentEngine.protocol` 与 initialize 应答同值)。 */
23
+ export const ENGINE_PROTOCOL_VERSION = 1;
24
+
25
+ /**
26
+ * core 侧支持的协议版本区间(半开区间 [min, max)):当前 = [1, 2)。
27
+ * 引擎版本落在区间外 → engine_protocol_mismatch。
28
+ */
29
+ export const SUPPORTED_PROTOCOL_RANGE = { min: 1, max: 2 } as const;
30
+
31
+ /** 版本兼容判定(core 握手判据;引擎侧对称用于拒绝过旧/过新宿主)。 */
32
+ export function isProtocolVersionCompatible(version: number): boolean {
33
+ return (
34
+ Number.isInteger(version) &&
35
+ version >= SUPPORTED_PROTOCOL_RANGE.min &&
36
+ version < SUPPORTED_PROTOCOL_RANGE.max
37
+ );
38
+ }
39
+
40
+ // ============================================================
41
+ // 量级常量(impl-plan §2.1 逐项写死,双侧同源)
42
+ // ============================================================
43
+
44
+ /** 正向数据面反向请求(帧④数据面类)未应答容忍时长:10s 未答 = 引擎故障 → 杀进程 + 在途 run 失败。 */
45
+ export const REVERSE_REQUEST_TIMEOUT_MS = 10_000;
46
+
47
+ /** initialize 握手超时(ms):超时 → engine_handshake_timeout,该引擎不可用。 */
48
+ export const HANDSHAKE_TIMEOUT_MS = 10_000;
49
+
50
+ /** cancel 后引擎收敛终态的窗口(ms);超时 core 走杀链。 */
51
+ export const CANCEL_SETTLE_GRACE_MS = 3_000;
52
+
53
+ /** engine_crashed 后重建上限与指数退避序列(ms):1s / 2s / 4s,超限标记不可用至宿主重启。 */
54
+ export const CRASH_REBUILD_MAX_ATTEMPTS = 3;
55
+ // 逐档具名(impl-plan §2.1 写死 1s/2s/4s;数组字面量元素会触发 no-magic-numbers,
56
+ // 且具名档位与 core kill-chain 的 MS_PER_SECOND 私有具名常量惯例同型)。
57
+ const CRASH_REBUILD_BACKOFF_STEP_1_MS = 1_000;
58
+ const CRASH_REBUILD_BACKOFF_STEP_2_MS = 2_000;
59
+ const CRASH_REBUILD_BACKOFF_STEP_3_MS = 4_000;
60
+ export const CRASH_REBUILD_BACKOFF_MS = [
61
+ CRASH_REBUILD_BACKOFF_STEP_1_MS,
62
+ CRASH_REBUILD_BACKOFF_STEP_2_MS,
63
+ CRASH_REBUILD_BACKOFF_STEP_3_MS,
64
+ ] as const;
65
+
66
+ /** stderr 内存环形缓冲保留的尾部字符数(engine_crashed 帧携带崩溃现场)。 */
67
+ export const STDERR_TAIL_CHARS = 400;
68
+
69
+ /** 事件合并开关 env 名(设计级默认关闭 = 值 "0";A1 要求事件逐字段等价,合并不可开)。 */
70
+ export const ENGINE_EVENT_COALESCE_ENV = "XYZ_ENGINE_EVENT_COALESCE";
71
+ export const ENGINE_EVENT_COALESCE_DEFAULT = "0";
72
+
73
+ /**
74
+ * 反向请求超时二分(帧④注释,R9-2):
75
+ * - 数据面类(host/log / host/streamDelta / host/poolResolved / host/handleReady /
76
+ * host/childSpawned / host/childStateChanged / host/roundLifecycle[v1.x]):10s 未答 =
77
+ * 引擎故障;
78
+ * - 人机交互类(host/askUser / host/permission):不设统一超时——core 先回 {ack:true},
79
+ * 结果异步到达;按 ADR-0047「静默 ≠ 卡死」用无进展检测/用户取消,不据此判引擎故障。
80
+ */
81
+ export type ReverseRequestTimeoutClass = "data-plane" | "interaction";