@zhushanwen/subagent-core 0.7.1 → 0.9.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 (176) hide show
  1. package/dist/{chunk-VURUAGMM.js → chunk-LZJOEDGQ.js} +603 -154
  2. package/dist/engine-discovery-scan-Da4Dkzsi.d.cts +818 -0
  3. package/dist/engine-discovery-scan-Da4Dkzsi.d.ts +818 -0
  4. package/dist/execution/engine/engine-discovery-scan.cjs +325 -154
  5. package/dist/execution/engine/engine-discovery-scan.d.cts +1 -2
  6. package/dist/execution/engine/engine-discovery-scan.d.ts +1 -2
  7. package/dist/execution/engine/engine-discovery-scan.js +1 -1
  8. package/dist/execution/relay-env.js +5 -4
  9. package/dist/index.cjs +9799 -7954
  10. package/dist/index.d.cts +1896 -1360
  11. package/dist/index.d.ts +1896 -1360
  12. package/dist/index.js +8952 -7513
  13. package/dist.bundle/index.cjs +7897 -6054
  14. package/package.json +5 -5
  15. package/src/__tests__/manifest-store.test.ts +16 -15
  16. package/src/__tests__/record-store-last-line.test.ts +12 -0
  17. package/src/__tests__/robustness-medium-batch1.test.ts +10 -14
  18. package/src/__tests__/robustness-medium-batch2.test.ts +7 -2
  19. package/src/core/logger.ts +1 -1
  20. package/src/execution/__tests__/alive-store.test.ts +117 -1
  21. package/src/execution/__tests__/batch-finalized.test.ts +206 -0
  22. package/src/execution/__tests__/chat-engine-routing.test.ts +117 -1
  23. package/src/execution/__tests__/{cold-resurrect.test.ts → cold-lookup.test.ts} +133 -33
  24. package/src/execution/__tests__/collect-coordinator-service.test.ts +7 -5
  25. package/src/execution/__tests__/conversation-continuation.test.ts +1452 -0
  26. package/src/execution/__tests__/delivery-methods.test.ts +90 -176
  27. package/src/execution/__tests__/dialog-queue.test.ts +70 -3
  28. package/src/execution/__tests__/dispose-manifest-recovery.test.ts +475 -0
  29. package/src/execution/__tests__/execute-and-await-worktree.test.ts +3 -3
  30. package/src/execution/__tests__/execute-nesting.test.ts +8 -5
  31. package/src/execution/__tests__/execution-record.test.ts +8 -148
  32. package/src/execution/__tests__/finalize-record.test.ts +295 -129
  33. package/src/execution/__tests__/get-record-for-action-restart.test.ts +21 -29
  34. package/src/execution/__tests__/helpers/fake-engine-port.ts +13 -68
  35. package/src/execution/__tests__/helpers/legacy-sidecar.ts +33 -0
  36. package/src/execution/__tests__/helpers/subagent-service-mocks.ts +9 -5
  37. package/src/execution/__tests__/idle-gc.test.ts +60 -0
  38. package/src/execution/__tests__/inflight-production-wiring.test.ts +223 -0
  39. package/src/execution/__tests__/lifecycle-manager.test.ts +3 -254
  40. package/src/execution/__tests__/manifest-store-tmp-recovery.test.ts +43 -22
  41. package/src/execution/__tests__/model-config-service.test.ts +111 -0
  42. package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +10 -6
  43. package/src/execution/__tests__/nested-visibility.test.ts +13 -1
  44. package/src/execution/__tests__/notify-ledger.test.ts +42 -1
  45. package/src/execution/__tests__/rebuild-indexes.test.ts +329 -0
  46. package/src/execution/__tests__/record-binding.test.ts +613 -0
  47. package/src/execution/__tests__/record-origin.test.ts +318 -0
  48. package/src/execution/__tests__/record-store-intent-api.test.ts +600 -0
  49. package/src/execution/__tests__/record-store-orphan-revive.test.ts +71 -3
  50. package/src/execution/__tests__/record-store.test.ts +72 -54
  51. package/src/execution/__tests__/recursive-visibility-baseline.test.ts +8 -5
  52. package/src/execution/__tests__/round-supervisor-workflow-origin.test.ts +205 -0
  53. package/src/execution/__tests__/run-orchestration-write-lease.test.ts +293 -0
  54. package/src/execution/__tests__/run-orchestration.test.ts +199 -0
  55. package/src/execution/__tests__/session-file-gc.test.ts +35 -4
  56. package/src/execution/__tests__/session-reconstructor.test.ts +78 -0
  57. package/src/execution/__tests__/state-marker.test.ts +288 -0
  58. package/src/execution/__tests__/stream-sink-retirement.test.ts +8 -5
  59. package/src/execution/__tests__/subagent-actions-core.test.ts +67 -16
  60. package/src/execution/__tests__/subagent-service-multiproc-guard.test.ts +0 -1
  61. package/src/execution/__tests__/subagent-service-notify-gate.test.ts +27 -11
  62. package/src/execution/__tests__/subagent-service-parent-guard.test.ts +17 -11
  63. package/src/execution/__tests__/subagent-service-recovery-bounds.test.ts +130 -53
  64. package/src/execution/__tests__/subagent-service.test.ts +17 -215
  65. package/src/execution/__tests__/subprocess-agent-runner-no-progress-killall.test.ts +138 -0
  66. package/src/execution/__tests__/subprocess-agent-runner.test.ts +105 -660
  67. package/src/execution/__tests__/sync-collect-recovery.test.ts +23 -16
  68. package/src/execution/__tests__/terminal-write-latency.test.ts +79 -0
  69. package/src/execution/__tests__/workflow-agent-dispatch.test.ts +782 -0
  70. package/src/execution/alive-store.ts +37 -28
  71. package/src/execution/{cold-resurrect.ts → cold-lookup.ts} +48 -45
  72. package/src/execution/config.ts +1 -1
  73. package/src/execution/conversation-continuation.ts +541 -0
  74. package/src/execution/dialog-queue.ts +60 -12
  75. package/src/execution/engine/__tests__/common/capability-gate.test.ts +1 -1
  76. package/src/execution/engine/__tests__/common/journal-wiring.test.ts +16 -1
  77. package/src/execution/engine/__tests__/conformance/__fixtures__/engine-protocol/fake-engine-protocol.mjs +17 -51
  78. package/src/execution/engine/__tests__/conformance/__fixtures__/engine-protocol/smoke-run.fixture.json +0 -5
  79. package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +1 -1
  80. package/src/execution/engine/__tests__/conformance/protocol-blackbox.test.ts +5 -9
  81. package/src/execution/engine/__tests__/conformance/registry-fork-filter.test.ts +55 -53
  82. package/src/execution/engine/__tests__/engine-discovery-scan.test.ts +0 -3
  83. package/src/execution/engine/__tests__/engine-discovery.test.ts +0 -3
  84. package/src/execution/engine/__tests__/inflight-snapshot.test.ts +180 -0
  85. package/src/execution/engine/__tests__/model-prompt.test.ts +0 -3
  86. package/src/execution/engine/__tests__/registry.test.ts +0 -1
  87. package/src/execution/engine/__tests__/routing.test.ts +0 -1
  88. package/src/execution/engine/__tests__/run-failure-worktree-cleanup.test.ts +0 -3
  89. package/src/execution/engine/client/__tests__/__fixtures__/fake-engine.mjs +0 -3
  90. package/src/execution/engine/client/__tests__/engine-client-reap.test.ts +212 -0
  91. package/src/execution/engine/client/__tests__/mirror.test.ts +73 -1
  92. package/src/execution/engine/client/__tests__/protocol-closure.test.ts +2 -9
  93. package/src/execution/engine/client/__tests__/remote-engine.test.ts +46 -12
  94. package/src/execution/engine/client/engine-client.ts +111 -26
  95. package/src/execution/engine/client/mirror.ts +9 -0
  96. package/src/execution/engine/client/remote-engine.ts +52 -34
  97. package/src/execution/engine/client/reverse-router.ts +6 -27
  98. package/src/execution/engine/common/__tests__/run-signals.test.ts +79 -0
  99. package/src/execution/engine/common/capability-gate.ts +27 -0
  100. package/src/execution/engine/common/data-dir.ts +3 -2
  101. package/src/execution/engine/common/errors.ts +1 -1
  102. package/src/execution/engine/common/journal-wiring.ts +18 -9
  103. package/src/execution/engine/common/run-signals.ts +83 -0
  104. package/src/execution/engine/d8-compat.ts +1 -1
  105. package/src/execution/engine/host/__tests__/host-bridge.test.ts +3 -18
  106. package/src/execution/engine/host/host-bridge.ts +26 -41
  107. package/src/execution/engine/host/pi-host-binding.ts +5 -5
  108. package/src/execution/engine/host/spawned-children.ts +1 -1
  109. package/src/execution/engine/inflight-snapshot.ts +92 -0
  110. package/src/execution/engine/port.ts +52 -54
  111. package/src/execution/engine/types.ts +11 -14
  112. package/src/execution/execution-record.ts +15 -47
  113. package/src/execution/finalize-record.ts +94 -197
  114. package/src/execution/idle-gc.ts +9 -3
  115. package/src/execution/lifecycle-manager.ts +25 -361
  116. package/src/execution/lifecycle-predicates.ts +22 -19
  117. package/src/execution/manifest-store.ts +40 -42
  118. package/src/execution/model-config-service.ts +1 -1
  119. package/src/execution/notifier.ts +39 -1
  120. package/src/execution/notify-host.ts +13 -4
  121. package/src/execution/path-encoding.ts +6 -0
  122. package/src/execution/record-entry.ts +20 -2
  123. package/src/execution/record-store.ts +925 -160
  124. package/src/execution/relay-env.ts +8 -3
  125. package/src/execution/round-supervisor/domain.ts +17 -5
  126. package/src/execution/round-supervisor/service-binding.test.ts +89 -53
  127. package/src/execution/round-supervisor/service-binding.ts +71 -21
  128. package/src/execution/round-supervisor/supervisor.ts +23 -9
  129. package/src/execution/service/record-access.ts +547 -0
  130. package/src/execution/service/record-lifecycle.ts +542 -0
  131. package/src/execution/service/run-orchestration.ts +1647 -0
  132. package/src/execution/service/service-bootstrap.ts +111 -0
  133. package/src/execution/service/service-constants.ts +27 -0
  134. package/src/execution/service/session-baselines.ts +401 -0
  135. package/src/execution/service/sync-collect-domain.ts +442 -0
  136. package/src/execution/service/workflow-dispatch.ts +567 -0
  137. package/src/execution/session-file-gc.ts +11 -8
  138. package/src/execution/session-reconstructor.ts +44 -1
  139. package/src/execution/sessions-index.ts +20 -3
  140. package/src/execution/settled-watchdog.ts +86 -43
  141. package/src/execution/state-marker.ts +516 -0
  142. package/src/execution/stream-sink.ts +1 -1
  143. package/src/execution/subagent-actions-core.ts +53 -31
  144. package/src/execution/subagent-service.ts +643 -2955
  145. package/src/execution/subprocess-agent-runner.ts +46 -323
  146. package/src/execution/types.ts +60 -43
  147. package/src/execution/ui-request-handler-factory.ts +5 -0
  148. package/src/execution/worktree-manager.ts +1 -1
  149. package/src/execution/worktree-registry.ts +12 -8
  150. package/src/index.ts +16 -5
  151. package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +2 -3
  152. package/src/orchestration/__tests__/agent-call-stream.test.ts +24 -49
  153. package/src/orchestration/__tests__/error-recovery-terminal-hardening.test.ts +4 -4
  154. package/src/orchestration/__tests__/file-run-store.test.ts +5 -7
  155. package/src/orchestration/__tests__/lifecycle-abort-broadcast-signal.test.ts +2 -3
  156. package/src/orchestration/__tests__/run-snapshot.test.ts +27 -43
  157. package/src/orchestration/__tests__/worker-message-pump-workflow-dispatch.test.ts +274 -0
  158. package/src/orchestration/execute-agent-call.ts +1 -1
  159. package/src/orchestration/file-run-store.ts +1 -1
  160. package/src/orchestration/models/ports.ts +20 -13
  161. package/src/orchestration/models/types.ts +11 -13
  162. package/src/orchestration/run-snapshot.ts +18 -22
  163. package/src/orchestration/worker-message-pump.ts +33 -57
  164. package/src/shared/atomic-write.ts +10 -8
  165. package/dist/chunk-T2SYBW3I.js +0 -24
  166. package/dist/engine-discovery-scan-ocpM8FmI.d.cts +0 -1608
  167. package/dist/engine-discovery-scan-ocpM8FmI.d.ts +0 -1608
  168. package/src/execution/__tests__/chat-round-first-round-watchdog.test.ts +0 -255
  169. package/src/execution/__tests__/finalized-marker.test.ts +0 -104
  170. package/src/execution/__tests__/lifecycle-manager-lock.test.ts +0 -211
  171. package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +0 -488
  172. package/src/execution/__tests__/subprocess-agent-runner-timeout.test.ts +0 -75
  173. package/src/execution/__tests__/tombstone-store.test.ts +0 -73
  174. package/src/execution/engine/__tests__/conformance/chat-round-protocol.test.ts +0 -230
  175. package/src/execution/finalized-marker.ts +0 -70
  176. package/src/execution/tombstone-store.ts +0 -72
@@ -1,8 +1,9 @@
1
1
  // src/execution/engine/common/journal-wiring.ts
2
2
  //
3
- // [D3-③ journal 接线合一] host 侧 event journal 接线的共享 helper(唯一实现,两调用
4
- // 点——SubagentService.runEngineTask(chat 域)与 SubprocessAgentRunner.runworkflow
5
- // 域))。设计权威源:docs/design/subagent-dual-track-convergence.md §3.3 D3-③(writer +
3
+ // [D3-③ journal 接线合一] host 侧 event journal 接线的共享 helper(唯一实现,调用
4
+ // 点全部在 SubagentService:workflow runWorkflowEngineTaskwireEventJournal
5
+ // taskId=record.id)+ chat runEngineTask 与 tool 域 runAndFinalize 两处(同
6
+ // record.id))。设计权威源:docs/design/subagent-dual-track-convergence.md §3.3 D3-③(writer +
6
7
  // retarget + handle 回填两份提为 common 层共享 helper)+ 双轨清单 #6。
7
8
  //
8
9
  // 收敛前形态(两份同构接线):
@@ -17,6 +18,7 @@
17
18
  // fsync 一次,§3.3.6 写入纪律;写失败已由 writer 内部 warn + failed 收口,close 不抛,
18
19
  // journal 是②级尽力而为数据源)。
19
20
 
21
+ import { SHARED_POOL_KEY } from "@zhushanwen/subagent-engine-sdk";
20
22
  import type { AgentEvent } from "../../../shared/agent-event.ts";
21
23
  import { getEngineDataDir } from "./data-dir.ts";
22
24
  import { JournalWriter } from "./event-journal.ts";
@@ -26,16 +28,17 @@ import type { EngineHandle } from "../types.ts";
26
28
  /**
27
29
  * journal 初始占位池 key(= pi 的恒定池 key 'shared')。pi 无隔离池
28
30
  * (PI_CODING_AGENT_DIR 全局一份,设计 §3.3.9),占位即终值;zcode 在 prepare 期
29
- * retarget 到实际池 key。值与 RunContext.poolKey 的初始占位同源——本常量是该值在
30
- * common 层的单一权威(原先 Service 用 'shared' 字面量、SAR 用 PI_POOL_KEY,等值异名)。
31
+ * retarget 到实际池 key。值与 RunContext.poolKey 的初始占位同源——值单源
32
+ * SDK SHARED_POOL_KEY(L3 收编:原先 Service 用 'shared' 字面量、SAR 用 PI_POOL_KEY
33
+ * 等值异名;本名保留 journal 占位语义,值不再本地声明)。
31
34
  */
32
- export const JOURNAL_INITIAL_POOL_KEY = "shared";
35
+ export const JOURNAL_INITIAL_POOL_KEY = SHARED_POOL_KEY;
33
36
 
34
37
  /** wireEventJournal 的参数。 */
35
38
  export interface JournalWiringOptions {
36
39
  /** 实际执行引擎 id(journal 路径分段 + line 元数据)。 */
37
40
  engineId: string;
38
- /** 宿主侧任务标识(journal 文件名与池引用计数 key:chat = record.id;workflow 域 = 'sa-' 前缀占位)。 */
41
+ /** 宿主侧任务标识(journal 文件名与池引用计数 key;三处调用点统一 = record.id)。 */
39
42
  taskId: string;
40
43
  /**
41
44
  * journal 落盘后的事件转发(workflow 域的 liveRecord 通道)。缺省不转发(chat 域
@@ -77,9 +80,15 @@ export function wireEventJournal(opts: JournalWiringOptions): JournalWiring {
77
80
  });
78
81
  return {
79
82
  // 先落盘再转发(原 onEvent 未传时也恒传包装版——下游 onEvent 通道是事件生成后的
80
- // 纯转发,无行为分支,仅多一次入队)
83
+ // 纯转发,无行为分支,仅多一次入队)。
84
+ //
85
+ // activity 豁免 append:纯活性信号不进持久/重放面——双侧 reducer(SDK
86
+ // journal-replay / core execution-record)对其 no-op,豁免不破坏 live≡reload
87
+ // 重放等价性;seq 由 append 铸造、过滤在 append 前故无 seq 空洞;
88
+ // forwardEvents 照发(workflow liveRecord reducer no-op,chat/守护刷新面在
89
+ // observedEvent 上游不受影响);取证面由 pi stdout/stderr tee 覆盖。
81
90
  onEvent: (event) => {
82
- journal.append(event);
91
+ if (event.type !== "activity") journal.append(event);
83
92
  opts.forwardEvents?.(event);
84
93
  },
85
94
  onPoolResolved: (poolKey) => {
@@ -0,0 +1,83 @@
1
+ // src/execution/engine/common/run-signals.ts
2
+ //
3
+ // [H2 W2 迁移步⑥] 运行期 signal 合流公共 helper——原定义在 subprocess-agent-runner.ts
4
+ // (模块内直调),随 service 统一编排入口 executeWorkflowAgent 接管 workflow 派发
5
+ // (设计 docs/design/subagent-workflow-record-unification.md §5 W2 八步迁移表)提为
6
+ // engine/common 公共面:SAR 与 SubagentService 两调用点共用同一实现(行为逐字节
7
+ // 等价搬移,函数体不改)。SAR 侧经 re-export 保持既有 import 路径(测试消费面零
8
+ // 改动),W4 掏空 SAR.run 后本文件成为唯一权威落点。
9
+
10
+ import { HOST_TIMEOUT_ABORT_REASON } from "./kill-chain.ts";
11
+
12
+ /** 合并 signal 的句柄:signal 供 engine.run 消费,dispose 移除桥接 listener(finally 必达)。 */
13
+ export interface MergedRunSignalHandle {
14
+ signal: AbortSignal;
15
+ /** 移除全部桥接 listener(幂等)。run 正常收敛(merged 不 abort)时是唯一清理通道。 */
16
+ dispose(): void;
17
+ }
18
+
19
+ /**
20
+ * D-A9 + [M3] 运行期 signal 合流:外部 signal(run 级 abort)+ per-call 墙钟 timeoutMs
21
+ * + [M3] no-progress watchdog abort —— 任一 abort 都让返回 signal abort。
22
+ *
23
+ * reason 语义保持 D-A9 原样:timeoutMs 到期 abort 带 HOST_TIMEOUT_ABORT_REASON 标记
24
+ *(引擎合成终态时判别「宿主超时」vs「外部 cancel」);外部 signal 与 watchdog 的
25
+ * abort 不带标记(wireAbortSignal 只消费 abort 事实,不读 reason)。
26
+ *
27
+ * 无任何信号源(timeoutMs 缺省/<=0 且无 watchdog)时原样返回 external signal(零新对象,
28
+ * 既有行为逐点不变)。
29
+ *
30
+ * dispose 的必要性:merged signal 正常收敛(不 abort)时,桥接在外部 run 级 signal 上的
31
+ * listener 不会自行移除——同一 run 多次 agent 调用会累积 listener 直至
32
+ * MaxListenersExceededWarning,故由调用方 finally 调 dispose。
33
+ */
34
+ export function mergeRunSignals(
35
+ signal: AbortSignal,
36
+ timeoutMs?: number,
37
+ noProgressSignal?: AbortSignal,
38
+ ): MergedRunSignalHandle {
39
+ const hasTimeout = timeoutMs !== undefined && timeoutMs > 0;
40
+ if (!hasTimeout && noProgressSignal === undefined) {
41
+ return { signal, dispose: () => {} };
42
+ }
43
+
44
+ const controller = new AbortController();
45
+ const bridges: Array<{ source: AbortSignal; handler: () => void }> = [];
46
+ let timer: NodeJS.Timeout | undefined;
47
+
48
+ const dispose = (): void => {
49
+ for (const bridge of bridges) bridge.source.removeEventListener("abort", bridge.handler);
50
+ bridges.length = 0;
51
+ if (timer !== undefined) {
52
+ clearTimeout(timer);
53
+ timer = undefined;
54
+ }
55
+ };
56
+
57
+ // 先挂清理 listener:任一信号源已 abort 时 bridge 会同步 abort controller,若清理
58
+ // listener 尚未就位,timeout timer / 已挂 listener 将不会被回收(原实现的既有时序盲区)。
59
+ controller.signal.addEventListener(
60
+ "abort",
61
+ () => dispose(),
62
+ { once: true },
63
+ );
64
+
65
+ if (hasTimeout) {
66
+ timer = setTimeout(() => controller.abort(HOST_TIMEOUT_ABORT_REASON), timeoutMs);
67
+ timer.unref();
68
+ }
69
+
70
+ const bridge = (source: AbortSignal): void => {
71
+ // 已 abort(前序信号源抢先 / 外部 signal 传入时已中止)后不再挂新 listener:
72
+ // 否则该 listener 永远等不到 controller 的清理(已过 abort 时点)。
73
+ if (controller.signal.aborted) return;
74
+ const handler = (): void => controller.abort();
75
+ bridges.push({ source, handler });
76
+ if (source.aborted) handler();
77
+ else source.addEventListener("abort", handler, { once: true });
78
+ };
79
+ bridge(signal);
80
+ if (noProgressSignal !== undefined) bridge(noProgressSignal);
81
+
82
+ return { signal: controller.signal, dispose };
83
+ }
@@ -32,7 +32,7 @@ import { EngineClient } from "./client/engine-client.ts";
32
32
  import { RemoteEngine, type RemoteEngineManifestSnapshot } from "./client/remote-engine.ts";
33
33
  import {
34
34
  readRelayForwardEnv,
35
- } from "../relay-env.ts";
35
+ } from "@zhushanwen/subagent-engine-sdk";
36
36
  import { getEngineDataDir } from "./common/data-dir.ts";
37
37
  import {
38
38
  CONSERVATIVE_CAPABILITIES,
@@ -1,6 +1,6 @@
1
- // HostBridge 契约 + core 实现 单测(W6,impl-plan §2.6 2 / 设计 §3.8 最小示例 9 方法)。
2
- // 覆盖:9 方法委托行为、getRecordForAction 异常 → null、cancel 的 void 包装、
3
- // takeChatRound 未提供 → null、armIdleTimer/disarmIdleTimer 对 lifecycle-manager 的
1
+ // HostBridge 契约 + core 实现 单测(W6;[H1 U6] takeChatRound 交接面用例随 chat
2
+ // 退役删除)。覆盖:方法委托行为、getRecordForAction 异常 → null、cancel 的 void 包装、
3
+ // armIdleTimer/disarmIdleTimer 对 lifecycle-manager 的
4
4
  // 接线(含超时回调 onIdleTimeout 触发,fake timers)。
5
5
 
6
6
  import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
@@ -9,7 +9,6 @@ import {
9
9
  createHostBridge,
10
10
  type HostBridge,
11
11
  type HostBridgeServiceFace,
12
- type HostChatRoundTicket,
13
12
  } from "../host-bridge.ts";
14
13
  import {
15
14
  _resetLifecycleState,
@@ -32,7 +31,6 @@ function makeService(): HostBridgeServiceFace & {
32
31
  closeSubagent: vi.fn(async () => {}),
33
32
  cancel: vi.fn(() => true),
34
33
  collectRecords: vi.fn((): SubagentRecord[] => [{ id: "r1" } as SubagentRecord]),
35
- takeChatRound: vi.fn(() => undefined),
36
34
  reportRecordTransition: vi.fn(() => {}),
37
35
  };
38
36
  return {
@@ -42,7 +40,6 @@ function makeService(): HostBridgeServiceFace & {
42
40
  closeSubagent: spies.closeSubagent,
43
41
  cancel: spies.cancel,
44
42
  collectRecords: spies.collectRecords,
45
- takeChatRound: spies.takeChatRound as HostBridgeServiceFace["takeChatRound"],
46
43
  reportRecordTransition: spies.reportRecordTransition,
47
44
  };
48
45
  }
@@ -96,18 +93,6 @@ describe("HostBridge(W6,设计 §3.8 最小示例 9 方法)", () => {
96
93
  expect(service.spies.cancel).toHaveBeenCalledWith("r1");
97
94
  });
98
95
 
99
- it("takeChatRound:有票 → 透传;无票 / 服务面未提供 → null", () => {
100
- expect(bridge.takeChatRound("t1")).toBeNull();
101
- const ticket: HostChatRoundTicket = {
102
- record: fakeRecord("r1"),
103
- opts: {} as HostChatRoundTicket["opts"],
104
- signal: undefined,
105
- priority: 1,
106
- };
107
- (service.spies.takeChatRound as ReturnType<typeof vi.fn>).mockReturnValue(ticket);
108
- expect(bridge.takeChatRound("t1")).toBe(ticket);
109
- });
110
-
111
96
  it("reportRecordTransition 委托(record 整体上报,无 patch 形态——见契约头注释)", () => {
112
97
  const record = fakeRecord("r1");
113
98
  bridge.reportRecordTransition(record);
@@ -2,12 +2,12 @@
2
2
  //
3
3
  // HostBridge 契约 + core 侧实现(W6,impl-plan §2.6 / 设计 §3.8 D2 表 + 最小示例)。
4
4
  //
5
- // 归属裁定(设计 §3.8 D2 表逐条):PiEngineService 9 成员中——executeAndAwait /
6
- // getRecordForAction / collectRecords / closeSubagent / cancel / ChatRoundTicket /
7
- // record 状态回写 / idle+activate lock 定时器——都是「宿主执行链 / 数据所有权在宿主」,
8
- // HostBridge(core);pi 包(W7)经 host/* 反向请求消费本面。spawnedChildren
9
- // 引擎进程(core 镜像见同目录 spawned-children.ts);sendPromptCommand / EPIPE 兜底 /
10
- // 冷续轮 resume(stdin-writer)归 pi 包(W7 迁移物)。
5
+ // 归属裁定(设计 §3.8 D2 表逐条):executeAndAwait / getRecordForAction /
6
+ // collectRecords / closeSubagent / cancel / record 状态回写 / idle+activate lock
7
+ // 定时器——都是「宿主执行链 / 数据所有权在宿主」,归 HostBridge(core);pi 包(W7)
8
+ // host/* 反向请求消费本面。spawnedChildren 归引擎进程(core 镜像见同目录
9
+ // spawned-children.ts);sendPromptCommand / EPIPE 兜底归 pi 包(W7 迁移物)。
10
+ // [H1 U6] ChatRoundTicket 交接面与冷续轮 resume(stdin-writer)已随 chat 域退役。
11
11
  //
12
12
  // 本文件只依赖 core 公共类型(types.ts / record-store / stream-sink /
13
13
  // lifecycle-manager / orchestration 类型),不 import inproc pi 引擎目录 内部——它是 pi 包
@@ -16,39 +16,31 @@
16
16
  // chat-session.cancel 等价承接,偏差登记见 chat-domain impl-plan §5。
17
17
 
18
18
  import { armIdleTimer, disarmIdleTimer } from "../../lifecycle-manager.ts";
19
+ // u7a D5 在途记账迁移点(crash-forensics §3.3 D5):idle timer arm/disarm 是「保活 ↔
20
+ // 正在执行」翻转的全部迁移点(agent_settled arm / 新 turn disarm / 热路径 re-arm 均经
21
+ // 本委托),迁移后推最新绝对计数给壳层监听者(同步 fire-and-forget,不进投递 await 面;
22
+ // 环规避同 inflight-snapshot.ts 头注释——挂桥层而非 lifecycle-manager)。
23
+ import { notifyInFlightChanged } from "../inflight-snapshot.ts";
19
24
  import type { AgentResult as WorkflowAgentResult } from "../../../orchestration/models/types.ts";
20
25
  import type { StatusFilter } from "../../record-store.ts";
21
26
  import type { SubagentStream } from "../../stream-sink.ts";
22
27
  import type {
23
28
  AgentEvent,
24
- AgentResult,
25
29
  ExecuteOptions,
26
30
  ExecutionRecord,
27
31
  SubagentRecord,
28
32
  } from "../../types.ts";
29
33
 
30
- /**
31
- * chat 域轮次交接包的 core 契约基座(设计 §3.8 D2「ChatRoundTicket → HostBridge」)。
32
- * pi 专有扩展(identity / SessionRunnerContext / SpawnResumeOpts resume)在
33
- * pi-engine.ChatRoundTicket extends 本接口(W7 随包迁移;过渡期 record/opts/signal/
34
- * priority/stream 五字段的宿主编排语义在此单一权威)。
35
- */
36
- export interface HostChatRoundTicket {
37
- record: ExecutionRecord;
38
- opts: ExecuteOptions;
39
- signal: AbortSignal | undefined;
40
- priority: number;
41
- stream?: SubagentStream;
42
- }
43
-
44
34
  /**
45
35
  * HostBridge 的服务实现面(SubagentService 的结构子集,鸭子类型——与原 pi-engine 的
46
- * PiEngineService 同一形态的协议化泛化:chat 域轮次面泛型参数化,pi 绑定 =
47
- * HostBridgeServiceFace<ChatRoundTicket>,见 pi-host-binding.ts re-export)。
48
- * 为什么用结构接口而非 import SubagentService 类型:防 Service 内部演进连锁影响
49
- * 契约面 + 测试可注入 fake(PiEngineService 的既有先例,语义照搬)。
36
+ * PiEngineService 同一形态的协议化泛化)。为什么用结构接口而非 import SubagentService
37
+ * 类型:防 Service 内部演进连锁影响契约面 + 测试可注入 fake(PiEngineService 的既有
38
+ * 先例,语义照搬)。
39
+ * [H1 U6] chat 域轮次交接可选面(HostChatRoundTicket / takeChatRound / runChatRound /
40
+ * resumeChatRound)已随 chat 域退役删除——续聊 = Continuation → 新 run + resume,
41
+ * 引擎经协议 converse,不再回调宿主编排面。
50
42
  */
51
- export interface HostBridgeServiceFace<TTicket extends HostChatRoundTicket = HostChatRoundTicket> {
43
+ export interface HostBridgeServiceFace {
52
44
  executeAndAwait(
53
45
  opts: ExecuteOptions,
54
46
  signal?: AbortSignal,
@@ -59,23 +51,18 @@ export interface HostBridgeServiceFace<TTicket extends HostChatRoundTicket = Hos
59
51
  closeSubagent(record: ExecutionRecord, force: boolean): Promise<void>;
60
52
  cancel(id: string): boolean;
61
53
  collectRecords(limit: number, statusFilter?: StatusFilter): SubagentRecord[];
62
- /** chat 域轮次交接(run 的 chat 分支入口):按 taskId 取走预备包(一次性消费)。 */
63
- takeChatRound?(taskId: string): TTicket | undefined;
64
- /** 执行预备的 chat 轮次(编排归 Service:pool 槽 + runSpawn + 终态迁移)。 */
65
- runChatRound?(ticket: TTicket): Promise<AgentResult>;
66
- /** 冷路径续轮(interact message 分支的编排回调:守卫 + record 迁移 + kick-off)。 */
67
- resumeChatRound?(record: ExecutionRecord, text: string): void;
68
54
  /** record 状态迁移上报(热路径投递后让 runtime 派生缓存失效 / GUI 回流)。 */
69
55
  reportRecordTransition?(record: ExecutionRecord): void;
70
56
  }
71
57
 
72
58
  /**
73
- * HostBridge 接口(设计 §3.8 最小示例,9 方法)。core 侧实现;pi 包经 host/* 反向
74
- * 请求消费。签名与最小示例的两处实现级偏差(均按现状语义落地):
59
+ * HostBridge 接口(设计 §3.8 最小示例的协议化视图)。core 侧实现;pi 包经 host/*
60
+ * 反向请求消费。签名与最小示例的实现级偏差(均按现状语义落地):
75
61
  * - getRecordForAction 返回 ExecutionRecord | null(现状实现面的活 record 形态;
76
62
  * 不存在 / 不可达 → null,引擎侧 resolveRecord 的 try/catch 语义内聚到本面);
77
63
  * - reportRecordTransition 收 record 对象(现状状态回写以 record 为单位整体上报,
78
64
  * 无 patch 增量形态——造 patch 形态属凭空造词,W7 反向通道载荷再议)。
65
+ * [H1 U6] takeChatRound(chat 域轮次交接)已随 chat 域退役删除。
79
66
  */
80
67
  export interface HostBridge {
81
68
  executeAndAwait(
@@ -88,7 +75,6 @@ export interface HostBridge {
88
75
  collectRecords(limit: number, filter?: StatusFilter): SubagentRecord[];
89
76
  closeSubagent(record: ExecutionRecord, force: boolean): Promise<void>;
90
77
  cancel(id: string): Promise<void>;
91
- takeChatRound(taskId: string): HostChatRoundTicket | null;
92
78
  reportRecordTransition(record: ExecutionRecord): void;
93
79
  armIdleTimer(id: string, ms: number): void;
94
80
  disarmIdleTimer(id: string): void;
@@ -106,10 +92,8 @@ export interface HostBridgeDeps {
106
92
  onIdleTimeout: (recordId: string) => void;
107
93
  // [F-3 删除登记] 曾有的 waitForRoundTerminal / escalateKill 可选注入(W3 D3 cancel
108
94
  // 终态等待面)已删:createHostBridge 全仓无生产调用点,且该面与生产 cancel 链结构
109
- // 冲突(cancelBackground 同步 unregisterChatRoundRoute 后,waitForRoundTerminal
110
- // race 轮终相位恒等满 3s 超时)。D3 core 侧收敛语义由引擎面等价承接 =
111
- // chat-session.cancel(waiter 先于 kill 注册 + killChain 有界升级),偏差登记见
112
- // chat-domain-v1x-liveness-governance.impl-plan.md §5。
95
+ // 冲突(waitForRoundTerminal race 轮终相位恒等满 3s 超时)。[H1 U6] 注释内旧符号
96
+ // (chat 轮路由注销 / chat-session.cancel)已随 chat 域退役消亡。
113
97
  }
114
98
 
115
99
  /** HostBridge core 实现(SubagentService 编排面的协议化视图)。 */
@@ -131,20 +115,21 @@ export function createHostBridge(deps: HostBridgeDeps): HostBridge {
131
115
  * cancel 语义 = 受理即返回(service.cancel 同步布尔 → 契约 void)。
132
116
  * [F-3 删除登记] 终态等待/杀链升级面已删(无生产装配点 + 与 cancelBackground 的
133
117
  * 路由注销冲突,见 HostBridgeDeps 尾注);生产收敛语义由引擎面承接 =
134
- * chat-session.cancel(waiter 先于 kill 注册 → roundLifecycle 终态相位
118
+ * chat-session.cancel(waiter 先于 kill 注册 → 等轮次终态相位
135
119
  * CANCEL_SETTLE_GRACE_MS 未收敛走 killChain 有界升级)。resolve 语义归引擎侧
136
120
  * 判 notResumable(契约注释,W6 起如此)。
137
121
  */
138
122
  cancel: async (id) => {
139
123
  service.cancel(id);
140
124
  },
141
- takeChatRound: (taskId) => service.takeChatRound?.(taskId) ?? null,
142
125
  reportRecordTransition: (record) => service.reportRecordTransition?.(record),
143
126
  armIdleTimer: (id, ms) => {
144
127
  armIdleTimer(id, () => deps.onIdleTimeout(id), ms);
128
+ notifyInFlightChanged();
145
129
  },
146
130
  disarmIdleTimer: (id) => {
147
131
  disarmIdleTimer(id);
132
+ notifyInFlightChanged();
148
133
  },
149
134
  };
150
135
  }
@@ -23,11 +23,12 @@
23
23
  // (pi-subagent-cli spawn-runner 的 spawn watchdog)保持同源常量,漂移由 conformance
24
24
  // chat golden(spawn-args 断言)在引擎包侧守护。
25
25
 
26
+ import { SHARED_POOL_KEY } from "@zhushanwen/subagent-engine-sdk";
26
27
  import type { EnginePort } from "../port.ts";
27
28
  import { EngineNotFoundError, getEngine, hasEngine, listEngines } from "../registry.ts";
28
29
 
29
30
  /** pi 无隔离池(PI_CODING_AGENT_DIR 全局一份,协议化设计 §3.3.9),poolKey 恒 'shared'。 */
30
- export const PI_POOL_KEY = "shared";
31
+ export const PI_POOL_KEY = SHARED_POOL_KEY;
31
32
 
32
33
  /** watchdog 换算下限(分钟):与引擎包 spawn-runner 的 floor 同源(30min)。 */
33
34
  const WATCHDOG_FLOOR_MINUTES = 30;
@@ -46,9 +47,9 @@ export function maxTurnsToWatchdogMs(maxTurns: number): number {
46
47
  }
47
48
 
48
49
  /**
49
- * 宿主侧 pi EnginePort 解析(SAR / chat 域路由):registry 的 'pi'(发现器装载的
50
- * cli descriptor → RemoteEngine)直接返回——chat 轮次与 run 域同路(协议 run(interact)
51
- * 发往 pi-subagent-cli 引擎进程)。
50
+ * 宿主侧 pi EnginePort 解析(SAR / 会话形态轮路由):registry 的 'pi'(发现器装载的
51
+ * cli descriptor → RemoteEngine)直接返回——续聊轮与 run 域同路(协议 run 帧发往
52
+ * pi-subagent-cli 引擎进程)。
52
53
  * [U-2 一致性修复] pi **未注册**(引擎包未装/发现失败)时返回不可用 stub,不静默
53
54
  * 直构任何本地实例——保留设计 D4「全不可用 → 派发期 engine_not_found + 安装指引」
54
55
  * 错误契约(zcode 侧 d8-compat 同语义,两引擎对称)。
@@ -85,7 +86,6 @@ function piUnavailableEnginePort(): EnginePort {
85
86
  }),
86
87
  probe: () => fail(),
87
88
  run: () => fail(),
88
- interact: () => fail(),
89
89
  read: () => fail(),
90
90
  };
91
91
  }
@@ -71,7 +71,7 @@ class CoreSpawnedChildrenMirror {
71
71
  }
72
72
 
73
73
  /** 快照(诊断/测试)。 */
74
- snapshot(): SpawnedChildMirrorEntry[] {
74
+ snapshot(): Array<SpawnedChildMirrorEntry & { recordId: string }> {
75
75
  return [...this.entries.entries()].map(([recordId, entry]) => ({ recordId, ...entry }));
76
76
  }
77
77
 
@@ -0,0 +1,92 @@
1
+ // src/execution/engine/inflight-snapshot.ts
2
+ //
3
+ // core→壳在途事件出口(u7a,设计权威源:docs/design/crash-forensics-and-watchdog.md
4
+ // §3.3 D5「在途判定谓词 + 求值位置」)。
5
+ //
6
+ // 在途状态(spawnedChildren Map / idleTimers Map)真实存在于本包(随 subagent-workflow
7
+ // extension 加载进 pi 进程),runtime 无法直查——D5 裁决为 extension 聚合上报:壳层
8
+ // (extensions/universal/subagent-workflow 的 host/inflight-reporter)经 select 通道
9
+ // 把绝对计数推给 runtime。本模块是这条通道的 core 侧出口:
10
+ // - 求值位置 = 状态所在的 pi 进程(本模块 getInFlightSnapshot——谓词与
11
+ // notify-host.ts hasRunningBackground 的双谓词过滤同源:hasLiveProcessHandle &&
12
+ // !hasIdleTimer,只把「正在执行」计为在途,Path A 保活(idle timer armed)不计);
13
+ // - 事件产生点 = 引擎域内的状态迁移点(session-runner 子进程注册/移除、idle timer
14
+ // arm/disarm),迁移后调 notifyInFlightChanged() 把最新快照推给壳层监听者;
15
+ // - core 闭包红线:本模块零 pi SDK import(只 import 本包 lifecycle 记账面),
16
+ // 壳层经包根 barrel 消费 setInFlightListener / getInFlightSnapshot(exports 面
17
+ // 收窄后壳侧生产消费必须走 barrel,无深路径豁免)。
18
+ //
19
+ // 回调注入形态(RunContext 回调先例):监听者由壳层注册,core 同步调用、绝不 await
20
+ // 返回值——满足 D5 接线约束①「上报不阻塞生命周期主链、不 await 进 agent_settled
21
+ // handler 链」(该链有时序保护约束 armIdleTimer 先于 notify)。
22
+
23
+ import { hasIdleTimer } from "../lifecycle-manager.ts";
24
+ import { hasLiveProcessHandle } from "../lifecycle-predicates.ts";
25
+ // 环声明:session-runner(迁移点)import 本模块的 notifyInFlightChanged,本模块经
26
+ // lifecycle-predicates → session-runner.getChildByRecord 读句柄记账 + 直接取
27
+ // spawnedChildren 键集——双向仅函数体内取值(ESM 活绑定,调用期解析),模块求值序
28
+ // 无依赖,环安全;esbuild bundle(builtin 打包)同规则成立。
29
+ // W3 合并改写:inproc 引擎已删,句柄记账唯一源 = engine/host/spawned-children 镜像
30
+ //(coreSpawnedChildrenMirror().snapshot() 返回 [{recordId, ...}],键集等价旧 Map.keys())。
31
+ import { coreSpawnedChildrenMirror } from "./host/spawned-children.ts";
32
+
33
+ /** 在途快照(与 EnginePort.inFlightSnapshot? 返回形状一致——runtime 侧统一消费形状)。 */
34
+ export interface InFlightSnapshot {
35
+ /** 当前非 idle 句柄数(绝对计数,非增量)。 */
36
+ inFlight: number;
37
+ }
38
+
39
+ /** 壳层注册的监听回调(同步、fire-and-forget;core 不 await 不重试)。 */
40
+ export type InFlightListener = (snapshot: InFlightSnapshot) => void;
41
+
42
+ /**
43
+ * 进程级单监听者(非 per-session 状态——在途计数本身是 pi 进程级模块状态
44
+ * (spawnedChildren/idleTimers 均模块级 Map),出口与之同域;壳层 reporter 持有
45
+ * 当前 session 上下文负责归属,与本出口无关)。后注册覆盖先注册(jiti 模块重载
46
+ * /多 factory 实例场景幂等),null 注销。
47
+ */
48
+ let listener: InFlightListener | null = null;
49
+
50
+ /** 壳层注册监听(extension factory 装配点调用;传 null 注销)。 */
51
+ export function setInFlightListener(next: InFlightListener | null): void {
52
+ listener = next;
53
+ }
54
+
55
+ /**
56
+ * 当前在途快照(纯读,无副作用):遍历活句柄记账(spawnedChildren 的 recordId 键集),
57
+ * 按双谓词过滤——活句柄(child 存在且未 killed)且无 armed idle timer。
58
+ *
59
+ * SSOT 复用:谓词取 lifecycle-predicates/lifecycle-manager 既有导出,与 notify-host
60
+ * hasRunningBackground 完全同源,不复制判定逻辑。活句柄记账里天然覆盖 pi 引擎进程内
61
+ * 与 relay 形态 child 两种宿主(relay spawn 经同一 runSpawn/spawnedChildren 记账——
62
+ * D5「extension 是两形态派生的共同属主」)。
63
+ */
64
+ export function getInFlightSnapshot(): InFlightSnapshot {
65
+ return { inFlight: countInFlight() };
66
+ }
67
+
68
+ /**
69
+ * 状态迁移点调用:把最新快照同步推给监听者。约束(D5 接线①):
70
+ * - 同步 void 语义——调用方(含 agent_settled handler 链内的 armIdleTimer 迁移点)
71
+ * 不 await 本函数的任何下游(监听者内部自行 fire-and-forget);
72
+ * - 监听者异常不反噬 core(壳层 bug 不得打断生命周期主链),catch 后照常返回。
73
+ */
74
+ export function notifyInFlightChanged(): void {
75
+ if (listener === null) return;
76
+ try {
77
+ listener(getInFlightSnapshot());
78
+ // eslint-disable-next-line taste/no-silent-catch -- 上报出口故障刻意静默(D5 约束①):壳层 bug 不得打断生命周期主链;绝对计数语义下后续事件自愈,丢失单帧无累积误差,记日志徒增 core logger 噪音面
79
+ } catch {
80
+ // 同上:静默是接受的。
81
+ }
82
+ }
83
+
84
+ /** 双谓词过滤的绝对计数(getInFlightSnapshot 与 notifyInFlightChanged 共用)。 */
85
+ function countInFlight(): number {
86
+ let count = 0;
87
+ for (const entry of coreSpawnedChildrenMirror().snapshot()) {
88
+ const recordId = entry.recordId;
89
+ if (hasLiveProcessHandle(recordId) && !hasIdleTimer(recordId)) count++;
90
+ }
91
+ return count;
92
+ }
@@ -12,21 +12,20 @@
12
12
  // 与 onPoolResolved 分立两个时点)。
13
13
  // - [u-h2 已实施 2026-09-05] EnginePort.validateModel?()——派发同步期 model 校验面。
14
14
  // 权威源:docs/design/timeout-audit-hygiene-batch.md §3.2 D2-2。
15
+ // - [u7a 已实施 2026-09-10] EnginePort.inFlightSnapshot?()——引擎在途只读快照面
16
+ // (滚动重启推迟谓词输入)。权威源:
17
+ // docs/design/crash-forensics-and-watchdog.md §3.3 D5。
15
18
  //
16
- // 四个能力面(D1):
17
- // run —— 主语义:一次性 fire-to-completion 任务执行;
18
- // interact —— 交互控制面(chatMode message/close/cancel + idle,可选能力面,
19
- // capabilities.conversation 声明接通与否);
19
+ // 三个能力面(D1;[H1 U6] interact 面已随 chat 域退役删除——续聊统一为新 run + resume):
20
+ // run —— 主语义:一次性 fire-to-completion 任务执行(会话形态续聊轮同走 run,
21
+ // resume 锚点经 RunContext.resume 携带);
20
22
  // read —— session 历史读取(D6 三级降级链);
21
23
  // probe —— 探针(D7:二进制存在/版本解析/干跑校验)。
22
24
  // capabilities() 同步无副作用——「调用前拒绝」(D11 处置三级)的判据。
23
25
 
24
26
  import type { ChildProcess } from "node:child_process";
25
27
 
26
- import type {
27
- HostRoundLifecycleParams,
28
- ResumeAnchor,
29
- } from "@zhushanwen/subagent-engine-sdk";
28
+ import type { ResumeAnchor } from "@zhushanwen/subagent-engine-sdk";
30
29
 
31
30
  import type { AgentCallOpts } from "../../orchestration/models/types.ts";
32
31
  import type { ModelInfo } from "../model-resolver.ts";
@@ -37,8 +36,6 @@ import type {
37
36
  EngineCapabilities,
38
37
  EngineHandle,
39
38
  EngineHandleData,
40
- InteractAction,
41
- InteractResult,
42
39
  ProbeReport,
43
40
  SessionView,
44
41
  } from "./types.ts";
@@ -93,6 +90,25 @@ export interface RunContext {
93
90
  * pi 引擎另经 ExecuteOptions 投影进 record)。
94
91
  */
95
92
  engineFallback?: { from: string; reason: string };
93
+ /**
94
+ * [F6] 根 session id(SubagentService.sessionRootId 注入)——pi 引擎 relay 归属键
95
+ * SESSION_ID 的权威来源(经 wire ctx.sessionRootId → server 还原 → SpawnRunParams
96
+ * → buildChildEnv)。刻意走 per-run ctx 而非 EngineClient 的进程级 env:客户端按
97
+ * 引擎缓存为惰性单例,进程级 env 在 pi fork 换 sessionId 后会陈旧;per-run ctx 恒
98
+ * 新鲜,且与 RECORD_ID 已有的 per-run 形态一致。additive:undefined/null/空串不
99
+ * 上 wire,zcode 等引擎忽略。
100
+ */
101
+ sessionRootId?: string;
102
+ /**
103
+ * [Option C 协议化] 权威 subagent session 目录(getSubagentSessionDir(agentDir,
104
+ * rootCwd) 宿主推导值)——经 wire ctx.sessionDir 送达 pi 引擎组装 `--session-dir`。
105
+ * 生产注入方 = RemoteEngine(cli 形态引擎的唯一宿主侧适配点,env 同源推导,见
106
+ * remote-engine buildRunParams);编排层显式注入(ctx.sessionDir 有值)时优先于
107
+ * RemoteEngine 自推导。zcode 等不消费 session 目录的引擎忽略本字段。编排层可
108
+ * 不注入;RemoteEngine 缺省以同源 env 推导值补齐后恒上 wire;[LEGACY] fallback
109
+ * 仅旧宿主/独立运行引擎形态可达。
110
+ */
111
+ sessionDir?: string;
96
112
  /**
97
113
  * [P4 对齐点③] 引擎声明实际隔离池 key(journal 落盘路径权威)。宿主创建 journal
98
114
  * writer 时只能用缺省占位 poolKey(pi 恒 'shared'),非池化稳定的引擎(zcode 按
@@ -126,33 +142,16 @@ export interface RunContext {
126
142
  */
127
143
  onChildSpawned?: (child: ChildProcess) => void;
128
144
  /**
129
- * [W3 v1.x] chat 会话形态参数(协议 run.params.chat 的 RunContext 承载位):
130
- * - recordId:core 预建 record 的关联键(引擎据此上报首轮 runId 键之外的反向
131
- * 载荷与 interact 定位)——task.conversation === true 的 chat 轮必传;
132
- * - resume:冷续锚点(重开已 idle session 续聊;pi 消费 sessionRef.sessionFile
133
- * ——对照协议化设计前 SpawnResumeOpts.sessionFile 的锚点面)。
134
- * 类型权威 = SDK RunChatParams(remote-engine 直传,结构互证由 implements 关系
135
- * typecheck 期承载)。非 chat 轮不传,wire 上不出现该键。
145
+ * [W3 v1.x → H1 U6 终态] 会话形态参数(协议 run.params.resume 的 RunContext
146
+ * 承载位,键已随 U6 键切换从 `chat` 泛化为 `resume`):
147
+ * - recordId:core 预建 record 的关联键(引擎据此上报 childSpawned/childStateChanged
148
+ * record 键形态与 handle 锚定)——会话形态轮(task.conversation === true)必传;
149
+ * - resume:续聊锚点(record.sessionFile 续写原文件;pi 消费
150
+ * sessionRef.sessionFile——对照协议化设计前 SpawnResumeOpts.sessionFile 的锚点面)。
151
+ * 类型权威 = SDK RunResumeParams(remote-engine 直传,结构互证由 implements 关系
152
+ * 在 typecheck 期承载)。一次性轮不传,wire 上不出现该键。
136
153
  */
137
- chat?: { recordId: string; resume?: ResumeAnchor };
138
- /**
139
- * [W3 v1.x] host/roundLifecycle 轮次生命周期消费口(第 9 反向通道,settled/idle/
140
- * failed 三相位;关联键 runId|recordId 互斥)。首轮(run 会话形态)经 run 作用域
141
- * 路由到达(runId 键);续聊轮(interact)无 runId——经 EnginePort
142
- * registerChatRoundRoute 的 recordId 键路由到达(见下)。消费语义(arm/disarm/
143
- * settled 交棒)归宿主编排层(settled-watchdog 协议事件面接线,W4 三入口)。
144
- */
145
- onRoundLifecycle?: (phase: HostRoundLifecycleParams) => void;
146
- }
147
-
148
- /**
149
- * [W3 v1.x] chat 轮次反向通道路由(recordId 键)——interact 续聊轮的 streamDelta /
150
- * roundLifecycle 分发目标(协议关联键裁定 D1-A:续聊轮无独立 runId)。与 run 作用域
151
- * RunRoute 同构的薄消费面;注册/注销时机归宿主 chat 编排(轮开始注册、record 终态注销)。
152
- */
153
- export interface ChatRoundRoute {
154
- onStreamDelta?: (delta: string) => void | Promise<void>;
155
- onRoundLifecycle?: (phase: HostRoundLifecycleParams) => void | Promise<void>;
154
+ resume?: { recordId: string; resume?: ResumeAnchor };
156
155
  }
157
156
 
158
157
  // ============================================================
@@ -194,29 +193,13 @@ export interface EnginePort {
194
193
  probe(opts?: { force?: boolean }): Promise<ProbeReport>;
195
194
 
196
195
  /** D1 主语义:fire-to-completion。[D6 合流] task = AgentCallOpts(单一任务形状,
197
- * 原 AgentTaskSpec 已并入——字段裁定见 orchestration/models/types.ts)。 */
196
+ * 原 AgentTaskSpec 已并入——字段裁定见 orchestration/models/types.ts)。会话形态
197
+ * 续聊轮同走本方法(resume 锚点经 ctx.resume 携带,[H1 U6] interact 面退役)。 */
198
198
  run(task: AgentCallOpts, ctx: RunContext): Promise<EngineRunResult>;
199
199
 
200
- /**
201
- * D1 可选面:交互控制面。pi 首期原生实现(现有 chatMode 行为直通);不支持
202
- * conversation 的引擎返回 engine_capability_unsupported(同步拒绝、不创建进程)。
203
- */
204
- interact(handle: EngineHandle, action: InteractAction): Promise<InteractResult>;
205
-
206
200
  /** D6 三级降级链:①引擎原生读取 → ②宿主 event journal(P2)→ ③outcome-only。 */
207
201
  read(handle: EngineHandle): Promise<SessionView>;
208
202
 
209
- /**
210
- * [W3 v1.x] 可选面:chat 轮次反向通道路由注册(recordId 键)。interact 续聊轮的
211
- * streamDelta / roundLifecycle 按 recordId 关联(无 runId,D1-A),引擎进程发射后
212
- * 经协议客户端分发到本路由。与 validateModel/listModels 同款的 additively-optional
213
- * 演进:宿主 feature-detect(`typeof registerChatRoundRoute === "function"`),
214
- * 未实现的引擎(不支持 chat 域或旧客户端)续聊轮 delta/生命周期静默不可达——
215
- * conversation gate 已在派发前拦住无 chat 能力的引擎,本缺省只在「能力声明与
216
- * 客户端实现错位」的诊断形态出现。返回注销函数(record 终态时宿主调用)。
217
- */
218
- registerChatRoundRoute?(recordId: string, route: ChatRoundRoute): () => void;
219
-
220
203
  /**
221
204
  * [U7] 可选面:模型可发现性——引擎自带 provider/model 体系时(如 zcode 的 v2 桌面
222
205
  * 登录态),列出当前环境实际可用的模型清单(带凭据校验),供 system prompt 引擎段
@@ -254,4 +237,19 @@ export interface EnginePort {
254
237
  * Promise 前完成;grace→SIGKILL 升级序列属异步面(promise 段)。
255
238
  */
256
239
  dispose?(): Promise<void>;
240
+
241
+ /**
242
+ * [u7a D5] 可选面:引擎在途任务只读快照(滚动重启推迟谓词的引擎侧输入——
243
+ * 权威源:docs/design/crash-forensics-and-watchdog.md §3.3 D5「推迟判定源 =
244
+ * relay ∪ 引擎池在途 ∪ pi 侧 extension 聚合上报」)。同步纯读、无副作用。
245
+ *
246
+ * 返回 null = 引擎不提供快照;成员缺席(undefined,pi 引擎不实现)= 无引擎侧
247
+ * 在途面——pi 形态的在途由 subagent-workflow extension 聚合上报覆盖(EnginePort
248
+ * 之外的第 4 通道,两通道互不替代)。可选成员保持向后兼容(port.ts 既有扩展
249
+ * 先例:listModels / validateModel / dispose 全为可选成员)。
250
+ *
251
+ * zcode 实现语义(显式裁决):在途 = activeSessions 非空——poolKey 'shared' 的
252
+ * app-server 空闲常驻进程恒活,**禁止按进程存在判定**(会恒真、推迟常态化)。
253
+ */
254
+ inFlightSnapshot?(): { inFlight: number } | null;
257
255
  }