@zhushanwen/subagent-core 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 (330) hide show
  1. package/README.md +114 -0
  2. package/dist/chunk-3VOERJPJ.js +22 -0
  3. package/dist/chunk-A4IVZWVX.js +31 -0
  4. package/dist/execution/engine/engines/zcode/constants.cjs +54 -0
  5. package/dist/execution/engine/engines/zcode/constants.d.cts +31 -0
  6. package/dist/execution/engine/engines/zcode/constants.d.ts +31 -0
  7. package/dist/execution/engine/engines/zcode/constants.js +22 -0
  8. package/dist/execution/engine/engines/zcode/reader.cjs +276 -0
  9. package/dist/execution/engine/engines/zcode/reader.d.cts +20 -0
  10. package/dist/execution/engine/engines/zcode/reader.d.ts +20 -0
  11. package/dist/execution/engine/engines/zcode/reader.js +239 -0
  12. package/dist/execution/engine/paths.cjs +55 -0
  13. package/dist/execution/engine/paths.d.cts +8 -0
  14. package/dist/execution/engine/paths.d.ts +8 -0
  15. package/dist/execution/engine/paths.js +26 -0
  16. package/dist/execution/relay-env.cjs +62 -0
  17. package/dist/execution/relay-env.d.cts +33 -0
  18. package/dist/execution/relay-env.d.ts +33 -0
  19. package/dist/execution/relay-env.js +20 -0
  20. package/dist/index.cjs +1852 -0
  21. package/dist/index.d.cts +1184 -0
  22. package/dist/index.d.ts +1184 -0
  23. package/dist/index.js +1810 -0
  24. package/dist/types-BxyAidGf.d.cts +875 -0
  25. package/dist/types-BxyAidGf.d.ts +875 -0
  26. package/package.json +99 -0
  27. package/src/__tests__/agent-opts-resolver-schema-prompt.test.ts +142 -0
  28. package/src/__tests__/append-system-prompt-assembly.test.ts +242 -0
  29. package/src/__tests__/builtin-workflows-structure.test.ts +180 -0
  30. package/src/__tests__/derive-closed-display-parity.test.ts +93 -0
  31. package/src/__tests__/fr4-get-state-handshake.test.ts +125 -0
  32. package/src/__tests__/fr8-orphan-recovery.test.ts +259 -0
  33. package/src/__tests__/m2-append-content-probe.test.ts +73 -0
  34. package/src/__tests__/manifest-store.test.ts +368 -0
  35. package/src/__tests__/record-store-cache.test.ts +335 -0
  36. package/src/__tests__/record-store-index.test.ts +560 -0
  37. package/src/__tests__/record-store-last-line.test.ts +129 -0
  38. package/src/__tests__/review-fix-loop-script.test.ts +288 -0
  39. package/src/__tests__/review-fix-loop-utils.test.ts +2377 -0
  40. package/src/__tests__/robustness-low-batch1.test.ts +286 -0
  41. package/src/__tests__/robustness-medium-batch1.test.ts +69 -0
  42. package/src/__tests__/robustness-medium-batch2.test.ts +65 -0
  43. package/src/__tests__/robustness-medium-batch3.test.ts +30 -0
  44. package/src/__tests__/robustness-medium-batch4.test.ts +358 -0
  45. package/src/__tests__/session-runner.test.ts +69 -0
  46. package/src/__tests__/smoke.test.ts +9 -0
  47. package/src/__tests__/stream-sink.test.ts +203 -0
  48. package/src/core/__tests__/host-services.test.ts +144 -0
  49. package/src/core/__tests__/logger.test.ts +78 -0
  50. package/src/core/__tests__/notify-ports.test.ts +104 -0
  51. package/src/core/host-services.ts +97 -0
  52. package/src/core/logger.ts +47 -0
  53. package/src/core/notify-ports.ts +126 -0
  54. package/src/execution/__tests__/__fixtures__/notifier-golden-snapshots.json +53 -0
  55. package/src/execution/__tests__/__fixtures__/truncline.snapshot.json +1 -0
  56. package/src/execution/__tests__/agent-result-mapper.test.ts +150 -0
  57. package/src/execution/__tests__/alive-store.test.ts +147 -0
  58. package/src/execution/__tests__/ask-user-transit-e2e.test.ts +490 -0
  59. package/src/execution/__tests__/channel-registry-handshake.test.ts +242 -0
  60. package/src/execution/__tests__/chat-engine-routing.test.ts +610 -0
  61. package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +190 -0
  62. package/src/execution/__tests__/concurrency-pool.test.ts +250 -0
  63. package/src/execution/__tests__/config.test.ts +302 -0
  64. package/src/execution/__tests__/delivery-methods.test.ts +424 -0
  65. package/src/execution/__tests__/dialog-queue.test.ts +299 -0
  66. package/src/execution/__tests__/epipe-fallback.test.ts +241 -0
  67. package/src/execution/__tests__/execute-and-await-worktree.test.ts +243 -0
  68. package/src/execution/__tests__/execute-nesting.test.ts +323 -0
  69. package/src/execution/__tests__/execute-options-mapper.test.ts +200 -0
  70. package/src/execution/__tests__/execution-record.test.ts +1394 -0
  71. package/src/execution/__tests__/explicit-agent-ref-guard.test.ts +171 -0
  72. package/src/execution/__tests__/finalize-record.test.ts +367 -0
  73. package/src/execution/__tests__/finalized-marker.test.ts +104 -0
  74. package/src/execution/__tests__/format-schema-instruction.test.ts +169 -0
  75. package/src/execution/__tests__/gc-timer.test.ts +184 -0
  76. package/src/execution/__tests__/get-record-for-action-restart.test.ts +254 -0
  77. package/src/execution/__tests__/helpers/mock-extension-api.ts +30 -0
  78. package/src/execution/__tests__/helpers/spawn-mock.ts +242 -0
  79. package/src/execution/__tests__/host-mode.test.ts +87 -0
  80. package/src/execution/__tests__/lifecycle-manager-lock.test.ts +211 -0
  81. package/src/execution/__tests__/lifecycle-manager.test.ts +383 -0
  82. package/src/execution/__tests__/lifecycle-predicates.test.ts +116 -0
  83. package/src/execution/__tests__/manifest-parentid.test.ts +117 -0
  84. package/src/execution/__tests__/model-resolver.test.ts +465 -0
  85. package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +287 -0
  86. package/src/execution/__tests__/nested-visibility.test.ts +325 -0
  87. package/src/execution/__tests__/output-collector.test.ts +358 -0
  88. package/src/execution/__tests__/path-encoding.test.ts +104 -0
  89. package/src/execution/__tests__/pi-invocation.test.ts +134 -0
  90. package/src/execution/__tests__/record-store.test.ts +1057 -0
  91. package/src/execution/__tests__/records-cwd-isolation.test.ts +91 -0
  92. package/src/execution/__tests__/recursive-visibility-baseline.test.ts +339 -0
  93. package/src/execution/__tests__/recursive-visibility-env.test.ts +273 -0
  94. package/src/execution/__tests__/relay-env.test.ts +42 -0
  95. package/src/execution/__tests__/resource-policy.test.ts +109 -0
  96. package/src/execution/__tests__/rpc-mode.test.ts +89 -0
  97. package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +267 -0
  98. package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +253 -0
  99. package/src/execution/__tests__/run-spawn-edges.test.ts +687 -0
  100. package/src/execution/__tests__/run-spawn-integration.test.ts +933 -0
  101. package/src/execution/__tests__/run-spawn-resume.test.ts +322 -0
  102. package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +196 -0
  103. package/src/execution/__tests__/run-spawn-stdout-callback-throw.test.ts +199 -0
  104. package/src/execution/__tests__/session-context-resolver.test.ts +167 -0
  105. package/src/execution/__tests__/session-file-gc.test.ts +293 -0
  106. package/src/execution/__tests__/session-reconstructor.test.ts +379 -0
  107. package/src/execution/__tests__/session-runner-epipe.test.ts +178 -0
  108. package/src/execution/__tests__/session-runner-schema-env.test.ts +350 -0
  109. package/src/execution/__tests__/spawn-args.test.ts +445 -0
  110. package/src/execution/__tests__/spawn-event-adapter-rpc.test.ts +189 -0
  111. package/src/execution/__tests__/spawn-event-adapter.test.ts +167 -0
  112. package/src/execution/__tests__/spawn-worktree-guidance.test.ts +207 -0
  113. package/src/execution/__tests__/spawned-children.test.ts +92 -0
  114. package/src/execution/__tests__/start-sync-model-guard.test.ts +150 -0
  115. package/src/execution/__tests__/stdin-writer.test.ts +462 -0
  116. package/src/execution/__tests__/stream-sink-retirement.test.ts +261 -0
  117. package/src/execution/__tests__/subagent-service-abort.test.ts +60 -0
  118. package/src/execution/__tests__/subagent-service-message-close.test.ts +629 -0
  119. package/src/execution/__tests__/subagent-service-parent-guard.test.ts +180 -0
  120. package/src/execution/__tests__/subagent-service.test.ts +788 -0
  121. package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +310 -0
  122. package/src/execution/__tests__/subprocess-agent-runner.test.ts +612 -0
  123. package/src/execution/__tests__/temp-prompt.test.ts +53 -0
  124. package/src/execution/__tests__/timeout-integration.test.ts +615 -0
  125. package/src/execution/__tests__/tombstone-store.test.ts +73 -0
  126. package/src/execution/__tests__/turn-limiter-semantics.test.ts +194 -0
  127. package/src/execution/__tests__/turn-limiter.test.ts +65 -0
  128. package/src/execution/__tests__/ui-channels.test.ts +187 -0
  129. package/src/execution/__tests__/ui-interaction-model.test.ts +67 -0
  130. package/src/execution/__tests__/ui-request-handler-factory.test.ts +369 -0
  131. package/src/execution/__tests__/ui-request-handler.test.ts +204 -0
  132. package/src/execution/__tests__/ui-request-observability.test.ts +113 -0
  133. package/src/execution/__tests__/ui-request-queue.test.ts +133 -0
  134. package/src/execution/__tests__/worktree-manager.test.ts +633 -0
  135. package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +229 -0
  136. package/src/execution/__tests__/worktree-reconcile.integration.test.ts +181 -0
  137. package/src/execution/__tests__/worktree-registry.test.ts +199 -0
  138. package/src/execution/agent-registry.ts +199 -0
  139. package/src/execution/agent-result-mapper.ts +90 -0
  140. package/src/execution/alive-store.ts +119 -0
  141. package/src/execution/argv-mirror.ts +113 -0
  142. package/src/execution/best-effort.ts +38 -0
  143. package/src/execution/channel-registry-access.ts +144 -0
  144. package/src/execution/concurrency-pool.ts +116 -0
  145. package/src/execution/config.ts +165 -0
  146. package/src/execution/dialog-queue.ts +330 -0
  147. package/src/execution/engine/__tests__/common/data-dir.test.ts +78 -0
  148. package/src/execution/engine/__tests__/common/errors.test.ts +132 -0
  149. package/src/execution/engine/__tests__/common/event-journal.test.ts +177 -0
  150. package/src/execution/engine/__tests__/common/kill-chain.test.ts +192 -0
  151. package/src/execution/engine/__tests__/common/nesting-guard.test.ts +81 -0
  152. package/src/execution/engine/__tests__/common/persona-router.test.ts +123 -0
  153. package/src/execution/engine/__tests__/common/pool-manager.test.ts +154 -0
  154. package/src/execution/engine/__tests__/common/schema-emulation.test.ts +128 -0
  155. package/src/execution/engine/__tests__/conformance/__fixtures__/pi-golden-events.json +28 -0
  156. package/src/execution/engine/__tests__/conformance/agent-event-invariants.ts +141 -0
  157. package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +109 -0
  158. package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +101 -0
  159. package/src/execution/engine/__tests__/conformance/contract.probe.test.ts +77 -0
  160. package/src/execution/engine/__tests__/conformance/contract.read-degradation.test.ts +104 -0
  161. package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +201 -0
  162. package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +76 -0
  163. package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +79 -0
  164. package/src/execution/engine/__tests__/engine-discovery.test.ts +87 -0
  165. package/src/execution/engine/__tests__/model-prompt.test.ts +197 -0
  166. package/src/execution/engine/__tests__/paths.test.ts +39 -0
  167. package/src/execution/engine/__tests__/registry.test.ts +120 -0
  168. package/src/execution/engine/__tests__/routing.test.ts +231 -0
  169. package/src/execution/engine/common/data-dir.ts +66 -0
  170. package/src/execution/engine/common/errors.ts +183 -0
  171. package/src/execution/engine/common/event-journal.ts +254 -0
  172. package/src/execution/engine/common/journal-replay.ts +62 -0
  173. package/src/execution/engine/common/kill-chain.ts +221 -0
  174. package/src/execution/engine/common/nesting-guard.ts +50 -0
  175. package/src/execution/engine/common/persona-router.ts +108 -0
  176. package/src/execution/engine/common/pool-manager.ts +226 -0
  177. package/src/execution/engine/common/schema-emulation.ts +189 -0
  178. package/src/execution/engine/common/session-view-projection.ts +51 -0
  179. package/src/execution/engine/engine-discovery.ts +65 -0
  180. package/src/execution/engine/engines/pi/__tests__/pi-engine.test.ts +469 -0
  181. package/src/execution/engine/engines/pi/__tests__/reader.test.ts +155 -0
  182. package/src/execution/engine/engines/pi/__tests__/task-spec-mapper.test.ts +164 -0
  183. package/src/execution/engine/engines/pi/pi-engine.ts +415 -0
  184. package/src/execution/engine/engines/pi/reader.ts +48 -0
  185. package/src/execution/engine/engines/pi/registration.ts +35 -0
  186. package/src/execution/engine/engines/pi/task-spec-mapper.ts +100 -0
  187. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-spawn.json +39 -0
  188. package/src/execution/engine/engines/zcode/__tests__/launcher.test.ts +150 -0
  189. package/src/execution/engine/engines/zcode/__tests__/parser.test.ts +246 -0
  190. package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +228 -0
  191. package/src/execution/engine/engines/zcode/__tests__/reader.test.ts +210 -0
  192. package/src/execution/engine/engines/zcode/__tests__/registration.test.ts +71 -0
  193. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +127 -0
  194. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.test.ts +580 -0
  195. package/src/execution/engine/engines/zcode/constants.ts +43 -0
  196. package/src/execution/engine/engines/zcode/golden-sample.ts +39 -0
  197. package/src/execution/engine/engines/zcode/launcher.ts +161 -0
  198. package/src/execution/engine/engines/zcode/parser.ts +436 -0
  199. package/src/execution/engine/engines/zcode/preparer.ts +363 -0
  200. package/src/execution/engine/engines/zcode/reader.ts +381 -0
  201. package/src/execution/engine/engines/zcode/registration.ts +37 -0
  202. package/src/execution/engine/engines/zcode/zcode-engine.ts +658 -0
  203. package/src/execution/engine/host-task-spec.ts +47 -0
  204. package/src/execution/engine/model-prompt.ts +158 -0
  205. package/src/execution/engine/paths.ts +42 -0
  206. package/src/execution/engine/port.ts +153 -0
  207. package/src/execution/engine/registry.ts +133 -0
  208. package/src/execution/engine/routing.ts +218 -0
  209. package/src/execution/engine/types.ts +309 -0
  210. package/src/execution/execute-options-mapper.ts +115 -0
  211. package/src/execution/execution-record.ts +984 -0
  212. package/src/execution/finalize-record.ts +254 -0
  213. package/src/execution/finalized-marker.ts +70 -0
  214. package/src/execution/get-state-handshake.ts +104 -0
  215. package/src/execution/host-mode.ts +56 -0
  216. package/src/execution/idle-gc.ts +47 -0
  217. package/src/execution/lifecycle-manager.ts +513 -0
  218. package/src/execution/lifecycle-predicates.ts +65 -0
  219. package/src/execution/manifest-store.ts +256 -0
  220. package/src/execution/model-config-service.ts +250 -0
  221. package/src/execution/model-resolver.ts +248 -0
  222. package/src/execution/notifier.ts +372 -0
  223. package/src/execution/notify-ledger.ts +580 -0
  224. package/src/execution/output-collector.ts +228 -0
  225. package/src/execution/path-encoding.ts +60 -0
  226. package/src/execution/pi-invocation.ts +120 -0
  227. package/src/execution/record-entry.ts +132 -0
  228. package/src/execution/record-store.ts +1265 -0
  229. package/src/execution/relay-env.ts +37 -0
  230. package/src/execution/session-context-resolver.ts +64 -0
  231. package/src/execution/session-file-gc.ts +120 -0
  232. package/src/execution/session-pending.ts +170 -0
  233. package/src/execution/session-reconstructor.ts +678 -0
  234. package/src/execution/session-runner.ts +1789 -0
  235. package/src/execution/sessions-index.ts +304 -0
  236. package/src/execution/spawn-event-adapter.ts +363 -0
  237. package/src/execution/stdin-writer.ts +198 -0
  238. package/src/execution/stream-sink.ts +126 -0
  239. package/src/execution/subagent-service.ts +2268 -0
  240. package/src/execution/subprocess-agent-runner.ts +317 -0
  241. package/src/execution/temp-prompt.ts +62 -0
  242. package/src/execution/tombstone-store.ts +72 -0
  243. package/src/execution/turn-limiter.ts +102 -0
  244. package/src/execution/types.ts +1023 -0
  245. package/src/execution/ui-channels.ts +216 -0
  246. package/src/execution/ui-interaction-model.ts +48 -0
  247. package/src/execution/ui-request-handler-factory.ts +243 -0
  248. package/src/execution/ui-request-observability.ts +81 -0
  249. package/src/execution/ui-request-queue.ts +184 -0
  250. package/src/execution/worktree-manager.ts +688 -0
  251. package/src/execution/worktree-registry.ts +279 -0
  252. package/src/index.ts +87 -0
  253. package/src/orchestration/__tests__/__fixtures__/worker-template.snapshot.txt +349 -0
  254. package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +202 -0
  255. package/src/orchestration/__tests__/agent-call-stream.test.ts +152 -0
  256. package/src/orchestration/__tests__/args-validator.test.ts +143 -0
  257. package/src/orchestration/__tests__/config-loader.test.ts +503 -0
  258. package/src/orchestration/__tests__/error-recovery-handlers.test.ts +809 -0
  259. package/src/orchestration/__tests__/error-recovery-postmessage-defense.test.ts +404 -0
  260. package/src/orchestration/__tests__/error-recovery-serialize-failed-result.test.ts +56 -0
  261. package/src/orchestration/__tests__/error-recovery-workflow-call.test.ts +166 -0
  262. package/src/orchestration/__tests__/execute-agent-call.test.ts +451 -0
  263. package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +600 -0
  264. package/src/orchestration/__tests__/lifecycle-runid-injection.test.ts +96 -0
  265. package/src/orchestration/__tests__/lifecycle.test.ts +659 -0
  266. package/src/orchestration/__tests__/non-cloneable-return-e2e.test.ts +95 -0
  267. package/src/orchestration/__tests__/review-fix-loop-scriptpath-failfast.test.ts +183 -0
  268. package/src/orchestration/__tests__/script-lint.test.ts +831 -0
  269. package/src/orchestration/__tests__/skill-discovery.test.ts +210 -0
  270. package/src/orchestration/__tests__/test-mocks.ts +197 -0
  271. package/src/orchestration/__tests__/worker-exit-without-result.test.ts +368 -0
  272. package/src/orchestration/__tests__/worker-host.test.ts +120 -0
  273. package/src/orchestration/__tests__/worker-returnmeta-passthrough.test.ts +164 -0
  274. package/src/orchestration/__tests__/worker-script-builder-runtime.test.ts +563 -0
  275. package/src/orchestration/__tests__/worker-script-builder.test.ts +309 -0
  276. package/src/orchestration/__tests__/worker-script-template-snapshot.test.ts +129 -0
  277. package/src/orchestration/__tests__/workflow-nesting-e2e.test.ts +317 -0
  278. package/src/orchestration/__tests__/workflow-script-lint-memo.test.ts +110 -0
  279. package/src/orchestration/agent-opts-resolver.ts +174 -0
  280. package/src/orchestration/args-validator.ts +127 -0
  281. package/src/orchestration/config-loader.ts +316 -0
  282. package/src/orchestration/error-recovery.ts +1018 -0
  283. package/src/orchestration/execute-agent-call.ts +256 -0
  284. package/src/orchestration/launcher.ts +455 -0
  285. package/src/orchestration/lifecycle.ts +399 -0
  286. package/src/orchestration/models/__tests__/budget.test.ts +307 -0
  287. package/src/orchestration/models/agent-call.ts +83 -0
  288. package/src/orchestration/models/budget.ts +118 -0
  289. package/src/orchestration/models/ports.ts +164 -0
  290. package/src/orchestration/models/run-runtime.ts +104 -0
  291. package/src/orchestration/models/run-spec.ts +83 -0
  292. package/src/orchestration/models/run-state.ts +44 -0
  293. package/src/orchestration/models/trace.ts +183 -0
  294. package/src/orchestration/models/types.ts +301 -0
  295. package/src/orchestration/models/workflow-run.ts +254 -0
  296. package/src/orchestration/models/workflow-script-registry.ts +35 -0
  297. package/src/orchestration/models/workflow-script.ts +117 -0
  298. package/src/orchestration/script-lint.ts +766 -0
  299. package/src/orchestration/skill-discovery.ts +135 -0
  300. package/src/orchestration/worker-handle.ts +115 -0
  301. package/src/orchestration/worker-host.ts +98 -0
  302. package/src/orchestration/worker-script-builder.ts +421 -0
  303. package/src/orchestration/workflow-files.ts +85 -0
  304. package/src/orchestration/workflow-script-registry-impl.ts +133 -0
  305. package/src/shared/__tests__/agent-ref.test.ts +34 -0
  306. package/src/shared/__tests__/meta-parser.test.ts +304 -0
  307. package/src/shared/__tests__/model-ref.test.ts +306 -0
  308. package/src/shared/__tests__/resource-discovery-manifest-cache.test.ts +288 -0
  309. package/src/shared/__tests__/resource-discovery.test.ts +749 -0
  310. package/src/shared/__tests__/resource-meta.test.ts +51 -0
  311. package/src/shared/__tests__/schema-jsonify.test.ts +81 -0
  312. package/src/shared/__tests__/timer-delay.test.ts +61 -0
  313. package/src/shared/agent-event.ts +13 -0
  314. package/src/shared/agent-ref.ts +57 -0
  315. package/src/shared/meta-parser.ts +261 -0
  316. package/src/shared/model-ref.ts +286 -0
  317. package/src/shared/resource-discovery.ts +835 -0
  318. package/src/shared/resource-meta.ts +65 -0
  319. package/src/shared/schema-env.ts +44 -0
  320. package/src/shared/schema-jsonify.ts +58 -0
  321. package/src/shared/timer-delay.ts +54 -0
  322. package/src/shared/xml-injection.ts +35 -0
  323. package/workflows/README.md +81 -0
  324. package/workflows/_shared/agent-refs.cjs +40 -0
  325. package/workflows/chain.js +137 -0
  326. package/workflows/map-reduce.js +180 -0
  327. package/workflows/parallel.js +154 -0
  328. package/workflows/review-fix-loop-utils.cjs +1542 -0
  329. package/workflows/review-fix-loop.js +1605 -0
  330. package/workflows/scatter-gather.js +184 -0
@@ -0,0 +1,47 @@
1
+ // src/execution/engine/host-task-spec.ts
2
+ //
3
+ // ExecuteOptions → AgentTaskSpec 的宿主侧最小正向映射(U0:chat 工具域引擎分支)。
4
+ //
5
+ // 与 engines/pi/task-spec-mapper.ts 的关系:那是 pi 引擎方向的映射(taskSpecToExecuteOptions
6
+ // 还原 + schemaEnv 内化派生等 pi 专有语义),归属 pi 引擎模块;本 mapper 服务宿主编排层
7
+ // (subagent-service 引擎分支),不 import 任何具体引擎模块(registry.ts 依赖方向纪律:
8
+ // 上层按中立类型组装声明,引擎细节归引擎)。字段映射是 ExecuteOptions → AgentTaskSpec
9
+ // 的中立直译(task/slug/agent/model 原样;thinkingLevel → effort;skillPath +
10
+ // appendSystemPrompt → persona;schema/maxTurns/graceTurns/worktree/cwd 原样透传)。
11
+ //
12
+ // conversation/fork 在调用本 mapper 前已被 assertEngineParamSupport 预检拒绝(非 pi 引擎
13
+ // unsupported),透传仅保持映射完整性——未来引擎支持时无需改本函数。
14
+
15
+ import type { ExecuteOptions } from "../types.ts";
16
+ import type { AgentTaskSpec, PersonaSpec } from "./types.ts";
17
+
18
+ /** 纯函数:ExecuteOptions(chat 域执行选项)→ 引擎中立任务声明。无副作用、幂等。 */
19
+ export function executeOptionsToEngineTaskSpec(opts: ExecuteOptions): AgentTaskSpec {
20
+ // persona 归并口径与 pi mapper 一致:skillPath / appendSystemPrompt 有其一即建,
21
+ // 避免空对象噪声(下游 spread 空数组与 undefined 均为 no-op)。
22
+ const persona: PersonaSpec | undefined =
23
+ opts.skillPath !== undefined || opts.appendSystemPrompt !== undefined
24
+ ? {
25
+ ...(opts.skillPath !== undefined ? { skillPath: opts.skillPath } : {}),
26
+ ...(opts.appendSystemPrompt !== undefined ? { appendSystemPrompt: opts.appendSystemPrompt } : {}),
27
+ }
28
+ : undefined;
29
+ return {
30
+ task: opts.task,
31
+ slug: opts.slug,
32
+ agent: opts.agent,
33
+ model: opts.model,
34
+ // pi 7 档 thinkingLevel 是引擎私有语义——中立层透传 effort 字符串,各引擎自行映射
35
+ effort: opts.thinkingLevel,
36
+ ...(persona !== undefined ? { persona } : {}),
37
+ schema: opts.schema,
38
+ maxTurns: opts.maxTurns,
39
+ graceTurns: opts.graceTurns,
40
+ fork: opts.fork,
41
+ worktree: opts.worktree,
42
+ cwd: opts.cwd,
43
+ conversation: opts.conversation,
44
+ idleTimeoutMs: opts.idleTimeoutMs,
45
+ // 运行期字段(signal/ctxModel)不入声明——归 RunContext(port.ts 删字段去向)。
46
+ };
47
+ }
@@ -0,0 +1,158 @@
1
+ // src/execution/engine/model-prompt.ts
2
+ //
3
+ // [U7] 引擎模型段 system prompt 注入(模型可发现性)。
4
+ // [engine-awareness U2] 引擎恒在状态段 <current_subagent_engine>(设计权威源:
5
+ // docs/design/subagent-engine-awareness-injection.md §3.1 终态逐字基准 / §3.3 D6、D7)。
6
+ //
7
+ // 背景:pi 核心在 system prompt 生成 <available_provider_models> 段并教育 agent
8
+ // 「subagent/workflow 的 model 参数用这些 id」——该教育对 engine: zcode 等自带
9
+ // provider 体系的引擎是误导(pi 的 id 在引擎侧是未知 provider)。本模块按
10
+ // 「defaultEngine 开关」(用户拍板 2026-08-25)补齐非默认引擎的模型可发现性:
11
+ // defaultEngine 指向非 pi 引擎且该引擎实现 EnginePort.listModels 时,追加
12
+ // <available_<engine>_models> 段,与 pi 段形成「一段一引擎」的分界标注。
13
+ //
14
+ // 恒在状态段(D6):现状 AI 对「当前默认引擎」无权威信息源,只能从「zcode 段缺失
15
+ // 与否」反推(pi 时完全无声明)。<current_subagent_engine> 恒在段显式声明当前引擎
16
+ // 并裁决「AGENTS.md 路由表的 pi-registry id 在非 pi 引擎下不适用」的指令冲突。
17
+ //
18
+ // engine-neutral:遍历注册表驱动,未来引擎实现 listModels 即自动注入,宿主零改动。
19
+
20
+ import { DEFAULT_ENGINE_ID, getEngine, hasEngine, normalizeEngineId } from "./registry.ts";
21
+
22
+ /** pi 段之外的引擎才需要清单段(pi 与主 agent 模型体系一致,核心已有段)。 */
23
+ const CORE_ENGINE_ID = DEFAULT_ENGINE_ID;
24
+
25
+ /** 单引擎段格式:XML 包裹 + 分界语义(与 pi 核心段的 <model><id> 形态对齐)。 */
26
+ function buildEngineSection(engineId: string, models: Array<{ id: string; name?: string }>): string {
27
+ const lines = models.map((m) =>
28
+ m.name !== undefined ? `<model><id>${m.id}</id><name>${m.name}</name></model>` : `<model><id>${m.id}</id></model>`,
29
+ );
30
+ return [
31
+ `<available_${engineId}_models>`,
32
+ `The following models are available for subagents dispatched with engine '${engineId}' ONLY (their provider registry differs from the main agent's; ids above in <available_provider_models> do NOT apply to engine '${engineId}' dispatches). Omit model to use the engine default.`,
33
+ ...lines,
34
+ `</available_${engineId}_models>`,
35
+ ].join("\n");
36
+ }
37
+
38
+ /**
39
+ * 恒在状态段 <current_subagent_engine>(设计 D6:pi 引擎也声明——AI 不需要
40
+ * 「从段缺失反推」当前引擎)。三种形态(§3.1 终态逐字基准 + 失败路径表):
41
+ * - 缺省 / pi:声明 pi + 指向上方核心段 <available_provider_models>(无冲突 bullet);
42
+ * - 非 pi 且已注册:指向下方该引擎清单段 + 「pi registry id 不适用」+ AGENTS.md
43
+ * 冲突裁决 bullet + 省略 model 用引擎默认;
44
+ * - 未注册引擎(如配置手误 "ghost"):如实显示配置值 + 警告行(派发将报
45
+ * engine_not_found,指引修 subagents/config.json)——G4 诚实降级:不静默、不伪造。
46
+ *
47
+ * 字节稳定(D7):纯字符串确定性拼装(无 localeCompare / 无随机序 / 无时间态);
48
+ * 引擎注册与否经 hasEngine 只读判断(不取实例、不触发工厂副作用),同输入恒同输出。
49
+ */
50
+ export function buildSubagentEngineSection(defaultEngine: string | undefined): string {
51
+ // 归一走 registry.normalizeEngineId 单一权威源:本函数与 buildEngineModelsPromptAppend
52
+ // (及引擎感知检测 diff)必须对同一读取结果给出同一引擎 id,否则两处会说谎
53
+ const engineId = normalizeEngineId(defaultEngine);
54
+ const lines = [
55
+ "<current_subagent_engine>",
56
+ "Default engine for subagent dispatches when neither the call's `engine` param",
57
+ `nor an agent .md \`engine\` frontmatter overrides: ${engineId}`,
58
+ ];
59
+ if (engineId === CORE_ENGINE_ID) {
60
+ // pi:清单在上方核心段,无需引擎侧清单段,也无 AGENTS.md 冲突(路由表 id 本就是 pi 的)
61
+ lines.push(
62
+ "- Model ids for pi dispatches are the ids in <available_provider_models> above.",
63
+ "- Omit `model` to use the engine default.",
64
+ );
65
+ } else if (hasEngine(engineId)) {
66
+ lines.push(
67
+ `- Model ids for ${engineId} dispatches are listed in <available_${engineId}_models> below.`,
68
+ ` Ids in <available_provider_models> do NOT apply to ${engineId} dispatches.`,
69
+ "- Omit `model` to use the engine default.",
70
+ // AGENTS.md 冲突裁决 bullet(§3.1 逐字基准):全局路由表给的绝对 pi id 是 2026-08-28
71
+ // 事故根因——更强的指令源必须被段内显式裁决约束
72
+ "- If AGENTS.md or other standing guidance names model ids from the pi registry",
73
+ " (e.g. zai-coding-cn/*), those ids apply to pi-engine dispatches ONLY — when",
74
+ " the current engine is not pi, use only ids from the engine section below.",
75
+ );
76
+ } else {
77
+ // 失败路径表「未注册引擎」行:文案逐字为恢复指引(与 dispatch 期 engine_not_found 对齐)
78
+ lines.push(
79
+ `- engine '${engineId}' is not registered — dispatches will fail at routing; fix subagents/config.json`,
80
+ );
81
+ }
82
+ lines.push("</current_subagent_engine>");
83
+ return lines.join("\n");
84
+ }
85
+
86
+ /**
87
+ * 清单段「无凭据模型」提示行形态(§3.1 失败路径表:状态段正常、清单段显示提示行)。
88
+ * 为什么不返回空串:状态段(恒在)声明「ids listed in <available_<engine>_models>
89
+ * below」,段缺失会让该声明说谎;提示行保持段存在且如实声明当前无任何可派发的
90
+ * 显式模型(G4 诚实降级)。文案逐字取自设计失败路径表恢复指引列。
91
+ *
92
+ * 仅服务「引擎实现了 listModels 但当前空清单 / 抛异常」两种形态——引擎侧 provider
93
+ * 体系存在、只是暂时没有可用模型,恢复动作是去宿主配置凭据。
94
+ */
95
+ function buildEmptyModelsHint(engineId: string): string {
96
+ return [
97
+ `<available_${engineId}_models>`,
98
+ `engine '${engineId}' has no credentialed models right now — configure the provider in ZCode desktop first`,
99
+ `</available_${engineId}_models>`,
100
+ ].join("\n");
101
+ }
102
+
103
+ /**
104
+ * 清单段「与主 agent 模型体系一致」声明行形态(U2 一致性审查修订:未实现 ≠ 无模型)。
105
+ * port 契约(port.ts listModels JSDoc):引擎省略 listModels 或返回 null = 引擎没有
106
+ * 自己的 provider 枚举面,模型 id 沿用主 agent 的 <available_provider_models>——
107
+ * 与「引擎有 provider 体系但无凭据模型」(buildEmptyModelsHint)是两种不同事实,
108
+ * 文案必须区分:此处若复用「no credentialed models + ZCode desktop 指引」会让 AI
109
+ * 误以为引擎不可派发、且 ZCode desktop 指引无处落地。
110
+ * 段仍保留 <available_<engine>_models> 包裹:状态段恒在声明「listed in ... below」,
111
+ * 段缺失会让该声明说谎(与 buildEmptyModelsHint 同理)。
112
+ */
113
+ function buildCoreAlignedHint(engineId: string): string {
114
+ return [
115
+ `<available_${engineId}_models>`,
116
+ `engine '${engineId}' uses the same model registry as the main agent — use ids from <available_provider_models> above`,
117
+ `</available_${engineId}_models>`,
118
+ ].join("\n");
119
+ }
120
+
121
+ /**
122
+ * 依据全局 defaultEngine 生成追加段(不含前导换行)。
123
+ *
124
+ * 规则(设计 §3.1 失败路径表 + G4 + U2 一致性审查修订):
125
+ * - defaultEngine 为 pi / 缺省 → 不注入(pi 段已由核心提供);
126
+ * - 引擎未注册 → 不注入(状态段 <current_subagent_engine> 已有警告行,避免双份);
127
+ * - 已注册且 listModels 有清单 → 注入该引擎段(渲染不变);
128
+ * - 已注册但 listModels 未实现 / 返回 null → 「与主 agent 模型体系一致」声明段
129
+ * (port 契约语义:引擎无自有 provider 枚举面,id 见上方核心段,见
130
+ * buildCoreAlignedHint);
131
+ * - 已注册但空清单 / listModels 抛异常 → 「无凭据模型」提示行段(引擎 provider
132
+ * 体系存在但当前无可用模型,见 buildEmptyModelsHint;从「静默不注入」改为如实
133
+ * 声明——空清单返回空串会让 AI 误以为没有任何引擎清单可看)。
134
+ * fail-safe:listModels 异常同样落提示行段、不向外抛(注入失败不阻塞 agent loop——
135
+ * 与 system-prompt extension 的 before_agent_start 处置一致)。
136
+ */
137
+ export function buildEngineModelsPromptAppend(defaultEngine: string | undefined): string {
138
+ // 归一走 registry.normalizeEngineId 单一权威源(与状态段渲染同一 normalize,见上文)
139
+ const engineId = normalizeEngineId(defaultEngine);
140
+ if (engineId === CORE_ENGINE_ID) return "";
141
+ // hasEngine 只读判断(不触发工厂);未注册时状态段负责警告,这里保持空串
142
+ if (!hasEngine(engineId)) return "";
143
+ try {
144
+ const engine = getEngine(engineId);
145
+ if (engine.listModels === undefined) return buildCoreAlignedHint(engineId);
146
+ const models = engine.listModels();
147
+ if (models === null) return buildCoreAlignedHint(engineId);
148
+ if (models.length === 0) return buildEmptyModelsHint(engineId);
149
+ return buildEngineSection(engineId, models);
150
+ } catch {
151
+ // listModels 抛异常(如 v2 config 损坏)=引擎枚举面存在但读取失败,与空清单
152
+ // 同属「暂无可派发的显式模型」:降级为无凭据提示行而非静默
153
+ return buildEmptyModelsHint(engineId);
154
+ }
155
+ }
156
+
157
+ /** 测试口:段格式导出(避免测试依赖注册表组装全链)。 */
158
+ export const _testHooks = { buildEngineSection, CORE_ENGINE_ID };
@@ -0,0 +1,42 @@
1
+ import { join } from 'node:path';
2
+
3
+ /**
4
+ * 引擎数据目录布局 SSOT(设计文档 D5/D6)。
5
+ *
6
+ * 为什么独立成模块:extension 写侧(journal 落盘 / preparer 池目录)与
7
+ * runtime 校验侧(subagent-extractor 前缀白名单)必须同源推导——
8
+ * 双方 import 同一份纯函数,禁止各自拼字符串漂移。
9
+ *
10
+ * 布局:`<dataDir>/engines/<engineId>/<pool-key>/journal-<taskId>.jsonl`
11
+ * 隔离池跨任务保留复用;journal 生命周期跟随 record,不随池删除(D5)。
12
+ */
13
+
14
+ /** 路径段安全编码后的最大字符数(防超长段击穿文件名长度上限;runtime 校验侧同源)。 */
15
+ const MAX_SEG_CHARS = 80;
16
+
17
+ /** 路径段进入文件系统前的安全编码:路径穿越、分隔符、空白、超长全部归一。 */
18
+ export function sanitizeSeg(input: string): string {
19
+ const s = input.replace(/[^A-Za-z0-9-]+/g, '-').replace(/^-+|-+$/g, '');
20
+ return s.length > 0 ? s.slice(0, MAX_SEG_CHARS) : 'default';
21
+ }
22
+
23
+ export function resolveEnginesRoot(dataDir: string): string {
24
+ return join(dataDir, 'engines');
25
+ }
26
+
27
+ export function resolveEngineDir(dataDir: string, engineId: string): string {
28
+ return join(resolveEnginesRoot(dataDir), sanitizeSeg(engineId));
29
+ }
30
+
31
+ export function resolvePoolDir(dataDir: string, engineId: string, poolKey: string): string {
32
+ return join(resolveEngineDir(dataDir, sanitizeSeg(engineId)), sanitizeSeg(poolKey));
33
+ }
34
+
35
+ export function resolveJournalPath(
36
+ dataDir: string,
37
+ engineId: string,
38
+ poolKey: string,
39
+ taskId: string,
40
+ ): string {
41
+ return join(resolvePoolDir(dataDir, engineId, poolKey), `journal-${sanitizeSeg(taskId)}.jsonl`);
42
+ }
@@ -0,0 +1,153 @@
1
+ // src/execution/engine/port.ts
2
+ //
3
+ // EnginePort 接口(P1)。设计权威源:docs/architecture/subagent-engine-abstraction.md
4
+ // §3.3.5「EnginePort 完整签名」——本文件是可编码落地的契约层,后续 wave(公共降级层
5
+ // P2 / zcode 引擎 P3 / 配置路由 P4)以本接口为实现契约,字段级变更须先改设计文档。
6
+ //
7
+ // 四个能力面(D1):
8
+ // run —— 主语义:一次性 fire-to-completion 任务执行;
9
+ // interact —— 交互控制面(chatMode 的 message/close/cancel + idle,可选能力面,
10
+ // capabilities.conversation 声明接通与否);
11
+ // read —— session 历史读取(D6 三级降级链);
12
+ // probe —— 探针(D7:二进制存在/版本解析/干跑校验)。
13
+ // capabilities() 同步无副作用——「调用前拒绝」(D11 处置三级)的判据。
14
+
15
+ import type { ChildProcess } from "node:child_process";
16
+
17
+ import type { ModelInfo } from "../model-resolver.ts";
18
+ import type { SubagentStream } from "../stream-sink.ts";
19
+ import type { AgentEvent } from "../types.ts";
20
+ import type {
21
+ AgentOutcome,
22
+ AgentTaskSpec,
23
+ EngineCapabilities,
24
+ EngineHandle,
25
+ InteractAction,
26
+ InteractResult,
27
+ ProbeReport,
28
+ SessionView,
29
+ } from "./types.ts";
30
+
31
+ // ============================================================
32
+ // RunContext(run 的运行期上下文)
33
+ // ============================================================
34
+
35
+ /**
36
+ * run 的运行期上下文。任务声明(AgentTaskSpec)与运行期句柄分离——signal/ctxModel/
37
+ * onComplete 从 ExecuteOptions 移出(设计 §3.3.5 删字段去向),因为它们是宿主注入的
38
+ * 运行期对象,不属于跨引擎持久化的任务声明。
39
+ *
40
+ * 常驻进程友好(D1):onEvent 回调式(而非迭代器式)+ AbortSignal——引擎内部换常驻
41
+ * server 实现(未来 driver host)时接口不动。
42
+ */
43
+ export interface RunContext {
44
+ /** = record.id(bg-N-xxx / run-N)——journal 文件名与池引用计数 key(P2 消费)。 */
45
+ taskId: string;
46
+ /** D5 隔离池(宿主分配,设计 §3.3.9;pi 无池化恒 'shared')。 */
47
+ poolKey: string;
48
+ /** abort 分级入口(D1:引擎原生中断 → 公共杀链兜底)。 */
49
+ signal?: AbortSignal;
50
+ /** 事件流出口(host 消费后统一落 journal,D6 第②级)。 */
51
+ onEvent?: (event: AgentEvent) => void;
52
+ /** model 解析第三层兼底(现有 D-008 语义不变)。 */
53
+ ctxModel?: ModelInfo;
54
+ /**
55
+ * text_delta streaming 通道(宿主侧 UI widget)。与 onEvent 平行的 text_delta 出口:
56
+ * background 路径 onEvent=undefined 但流式仍需送达(双通道互斥设计,见 session-runner
57
+ * agentEvent 出口注释)。pi 回填期承载 AgentRunner port 的 stream 透传(行为零变化),
58
+ * 语义上是宿主设施而非引擎专有——未来引擎的 text_delta 同样可走此通道。
59
+ */
60
+ stream?: SubagentStream;
61
+ /**
62
+ * [P1 pi 回填透传] 调用方已持有的 schema 激活预编码值(AgentCallOpts.schemaEnv 直传
63
+ * 形态)。生产路径中 resolveAgentOpts 恒耦合产出 schema+schemaEnv(值 = JSON.stringify
64
+ * (schema)),引擎从 task.schema 派生即可逐字节等值;解耦形态(有 schemaEnv 无
65
+ * schema)生产不可达、仅见于直构调用,派生无源——本字段是其唯一透交通道。
66
+ * 引擎在 task.schema 存在时忽略此值(派生优先,设计 §3.3.5 删字段去向)。
67
+ */
68
+ schemaEnv?: string;
69
+ /**
70
+ * [P4 D9①] 引擎 fallback 留痕(probe 失败路由回默认引擎)。路由层(routing.ts)
71
+ * 产出,引擎投影到 outcome.engineFallback(zcode 等无 record 通路的引擎以此留痕;
72
+ * pi 引擎另经 ExecuteOptions 投影进 record)。
73
+ */
74
+ engineFallback?: { from: string; reason: string };
75
+ /**
76
+ * [P4 对齐点③] 引擎声明实际隔离池 key(journal 落盘路径权威)。宿主创建 journal
77
+ * writer 时只能用缺省占位 poolKey(pi 恒 'shared'),非池化稳定的引擎(zcode 按
78
+ * provider+model 池化)在 prepare 期确定 poolKey 后回调本方法重定向 writer——
79
+ * 保证 journal 落盘路径与 handle.poolKey 同源(单一权威,不再两边推导)。
80
+ * 契约:必须在首个事件 emit 之前调用(zcode coarse 事件在终态后合成,天然满足;
81
+ * 未来流式引擎需在事件出口前调用)。
82
+ */
83
+ onPoolResolved?: (poolKey: string) => void;
84
+ /**
85
+ * [U0 D10] 引擎 spawn 的子进程句柄注册钩子(宿主终止链记账)。引擎在 spawn 成功后
86
+ * 同步回调(与 pi runSpawn 的 spawnedChildren.set 同构时机);宿主据此把 child 注册进
87
+ * session-runner 的 spawnedChildren Map(cancel SIGTERM / dispose 收割兜底 / killAll
88
+ * 全量清理对非 pi 引擎 record 生效)。close/error 后由宿主按句守卫移除。可选:引擎
89
+ * 内部不 spawn 进程(如未来常驻 driver host 实现)时不调用,宿主记账自然为空。
90
+ */
91
+ onChildSpawned?: (child: ChildProcess) => void;
92
+ }
93
+
94
+ // ============================================================
95
+ // run 返回(handle + outcome)
96
+ // ============================================================
97
+
98
+ /**
99
+ * run 的返回:终态 + 可持久化 handle。
100
+ *
101
+ * handle 语义(设计 §3.3.5 run 错误语义三条):prepare 期错误(credential_missing /
102
+ * model_not_available / prompt_too_large)在进程创建前 reject、不产生 handle;运行中
103
+ * 失败不 reject——合成 error outcome + 正常 handle 返回(record 必须收尾);abort 走
104
+ * 完杀链后同前(exitCode=null + error 含杀链标记)。
105
+ */
106
+ export interface EngineRunResult {
107
+ handle: EngineHandle;
108
+ outcome: AgentOutcome;
109
+ }
110
+
111
+ // ============================================================
112
+ // EnginePort
113
+ // ============================================================
114
+
115
+ /**
116
+ * subagent 执行引擎的唯一契约点(D1)。实现方:PiEngine(回填)/ ZcodeEngine(P3)/
117
+ * 未来各引擎适配器。上层(工具面/workflow 引擎/GUI)只消费中立类型,不感知引擎。
118
+ *
119
+ * 贯穿纪律(设计 §3.3.1):宿主编排——引擎只当单 agent 执行器,六家原生多 agent 机制
120
+ * 一律禁用不依赖。
121
+ */
122
+ export interface EnginePort {
123
+ /** 注册表 key('pi' | 'zcode' | ...)。 */
124
+ readonly id: string;
125
+
126
+ /** D3(同步无副作用——调用前拒绝的判据)。 */
127
+ capabilities(): EngineCapabilities;
128
+
129
+ /** D7(factory 初始化 + 版本变化检测触发;opts.force 跳过缓存强探)。 */
130
+ probe(opts?: { force?: boolean }): Promise<ProbeReport>;
131
+
132
+ /** D1 主语义:fire-to-completion。 */
133
+ run(task: AgentTaskSpec, ctx: RunContext): Promise<EngineRunResult>;
134
+
135
+ /**
136
+ * D1 可选面:交互控制面。pi 首期原生实现(现有 chatMode 行为直通);不支持
137
+ * conversation 的引擎返回 engine_capability_unsupported(同步拒绝、不创建进程)。
138
+ */
139
+ interact(handle: EngineHandle, action: InteractAction): Promise<InteractResult>;
140
+
141
+ /** D6 三级降级链:①引擎原生读取 → ②宿主 event journal(P2)→ ③outcome-only。 */
142
+ read(handle: EngineHandle): Promise<SessionView>;
143
+
144
+ /**
145
+ * [U7] 可选面:模型可发现性——引擎自带 provider/model 体系时(如 zcode 的 v2 桌面
146
+ * 登录态),列出当前环境实际可用的模型清单(带凭据校验),供 system prompt 引擎段
147
+ * 与 GUI 引擎选择器消费。省略/返回 null = 「与主 agent 模型体系一致」(pi 的语义:
148
+ * system prompt 已有 <available_provider_models> 段,无需引擎再列)。
149
+ * engine-neutral:未来引擎(AcpEngine 等)实现本方法即自动获得注入与展示,宿主
150
+ * 侧零改动。
151
+ */
152
+ listModels?(): Array<{ id: string; name?: string }> | null;
153
+ }
@@ -0,0 +1,133 @@
1
+ // src/execution/engine/registry.ts
2
+ //
3
+ // 引擎注册表(P1)。设计权威源:docs/architecture/subagent-engine-abstraction.md
4
+ // §3.3.1 分层总图([引擎注册表 engine registry](id → factory))与 §3.3.3 错误规格
5
+ // 第 1 行(engine_not_found → 指向注册表清单 + 配置文件路径)。
6
+ //
7
+ // 为什么需要注册表:引擎身份是「spawn 细节的归属边界」(设计 §2.3 根因一)——上层
8
+ // (配置路由/agent 解析,P4 接线)按 id 取引擎,不感知实现类;新引擎接入 = 新增一个
9
+ // 适配器模块 + 注册表登记一行,不改上层与既有引擎(目标 5)。
10
+ //
11
+ // 依赖方向(设计 §3.3.1 贯穿纪律④):registry 只依赖 port.ts 的类型,不 import 任何
12
+ // 具体引擎——注册由组合根(index.ts)或引擎自己的 registration 模块完成,防循环依赖。
13
+
14
+ import type { EnginePort } from "./port.ts";
15
+
16
+ /** 引擎工厂:惰性创建引擎实例(getEngine 首次取用时执行)。 */
17
+ export type EngineFactory = () => EnginePort;
18
+
19
+ /**
20
+ * 缺省引擎 id(D9:缺省引擎 = 'pi',回填期零风险默认)。
21
+ * P1 无 per-agent/调用级 engine 字段(P4 配置路由引入三层优先级),一切执行恒走缺省。
22
+ */
23
+ export const DEFAULT_ENGINE_ID = "pi";
24
+
25
+ /**
26
+ * defaultEngine 缺省归一(单一权威源):空白 / undefined 归一到缺省引擎('pi')。
27
+ * 引擎感知检测 diff 与状态段渲染必须对同一读取结果给出同一引擎 id——若两处各自
28
+ * 内联归一,一致性只靠注释人工耦合,漂移即两处说谎;故收敛到本函数供各处调用。
29
+ * sanitize 保证透传值非空,但可能带首尾空格,故 trim 后再判。
30
+ */
31
+ export function normalizeEngineId(engine: string | undefined): string {
32
+ return engine?.trim() || DEFAULT_ENGINE_ID;
33
+ }
34
+
35
+ /**
36
+ * engine_not_found(错误规格表第 1 行):agent frontmatter 写了未注册 engine id。
37
+ * 错误文案契约:含已注册引擎清单 + 配置文件指引——配置错误前置暴露(agent 解析期),
38
+ * 不留到运行时神秘失败(设计目标 4)。
39
+ */
40
+ export class EngineNotFoundError extends Error {
41
+ /** 结构化错误码(§3.3.3 错误规格表的 code 列,供调用方程序化分流)。 */
42
+ readonly code = "engine_not_found";
43
+ /** 请求的(未注册的)引擎 id。 */
44
+ readonly engineId: string;
45
+ /** 请求时刻的已注册清单快照(防错误对象跨时间读 Map 的失真)。 */
46
+ readonly registered: readonly string[];
47
+ /** 错误来源定位(agent .md 文件路径 / 配置键等;运行期 getEngine 无来源不传)。 */
48
+ readonly source: string | undefined;
49
+
50
+ constructor(engineId: string, registered: readonly string[], source?: string) {
51
+ super(
52
+ `engine_not_found: engine '${engineId}' is not registered. ` +
53
+ `Registered engines: ${registered.length > 0 ? registered.join(", ") : "(none)"}. ` +
54
+ `Recovery: check the engine id in the agent .md frontmatter (engine: field) or the global ` +
55
+ `default engine setting, fix the typo, or install/register the engine first ` +
56
+ `(registered engines are listed above).` +
57
+ (source !== undefined ? ` Source: ${source}.` : ""),
58
+ );
59
+ this.name = "EngineNotFoundError";
60
+ this.engineId = engineId;
61
+ this.registered = registered;
62
+ this.source = source;
63
+ }
64
+ }
65
+
66
+ /**
67
+ * id → factory(注册表本体)+ id → 惰性单例(getEngine 首次取用创建;registerEngine
68
+ * 覆盖时丢弃旧实例)。进程级单例状态,用 globalThis[Symbol.for] 持有防 jiti 双路径
69
+ * 加载分裂(development-guide §7.5),不用模块级 const。
70
+ */
71
+ const ENGINE_REGISTRY_SLOT_KEY = Symbol.for("@zhushanwen/pi-subagent-workflow.engineRegistry");
72
+
73
+ /** 注册表槽位形状(同文件唯一写入点,运行时保证)。 */
74
+ interface EngineRegistrySlot {
75
+ factories: Map<string, EngineFactory>;
76
+ singletons: Map<string, EnginePort>;
77
+ }
78
+
79
+ function getRegistrySlot(): EngineRegistrySlot {
80
+ // globalThis 无 symbol 索引签名,但运行时支持 symbol 键——用 Reflect 安全读写,
81
+ // 避免双重断言(同 model-config-service.ts 先例)。
82
+ let slot = Reflect.get(globalThis, ENGINE_REGISTRY_SLOT_KEY) as EngineRegistrySlot | undefined;
83
+ if (!slot) {
84
+ slot = { factories: new Map(), singletons: new Map() };
85
+ Reflect.set(globalThis, ENGINE_REGISTRY_SLOT_KEY, slot);
86
+ }
87
+ return slot;
88
+ }
89
+
90
+ /**
91
+ * 登记引擎工厂。重复注册同一 id = 覆盖(组合根可能多次执行,如每次 session_start 重跑
92
+ * registerPiEngine——幂等覆盖保证不炸也不堆积),覆盖时丢弃缓存的旧单例,让下一次
93
+ * getEngine 用新工厂重建。
94
+ */
95
+ export function registerEngine(id: string, factory: EngineFactory): void {
96
+ const slot = getRegistrySlot();
97
+ slot.factories.set(id, factory);
98
+ slot.singletons.delete(id);
99
+ }
100
+
101
+ /** 未注册 id 抛 EngineNotFoundError(含已注册清单与配置指引)。 */
102
+ export function getEngine(id: string): EnginePort {
103
+ const slot = getRegistrySlot();
104
+ const cached = slot.singletons.get(id);
105
+ if (cached) return cached;
106
+ const factory = slot.factories.get(id);
107
+ if (!factory) {
108
+ throw new EngineNotFoundError(id, listEngines());
109
+ }
110
+ const engine = factory();
111
+ slot.singletons.set(id, engine);
112
+ return engine;
113
+ }
114
+
115
+ /** id 是否已注册(agent 解析期的配置校验入口,D9——不取实例、不触发工厂副作用)。 */
116
+ export function hasEngine(id: string): boolean {
117
+ return getRegistrySlot().factories.has(id);
118
+ }
119
+
120
+ /** 已注册引擎 id 清单(稳定序 = 注册序;错误文案与 GUI 引擎选择器共用)。 */
121
+ export function listEngines(): string[] {
122
+ return [...getRegistrySlot().factories.keys()];
123
+ }
124
+
125
+ /**
126
+ * 清空注册表(测试隔离专用:防止用例间工厂/单例泄漏串扰)。
127
+ * 生产代码禁用——进程内注册表是全局状态,清空会让已获取的引擎句柄与新注册表脱钩。
128
+ */
129
+ export function clearEngines(): void {
130
+ const slot = getRegistrySlot();
131
+ slot.factories.clear();
132
+ slot.singletons.clear();
133
+ }