@zhushanwen/subagent-core 0.2.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -2
- package/agents/analyst.md +60 -0
- package/agents/coder.md +69 -0
- package/agents/debugger.md +66 -0
- package/agents/doc-reviewer.md +49 -0
- package/agents/explorer.md +63 -0
- package/agents/general-purpose.md +32 -0
- package/agents/orchestrator.md +61 -0
- package/agents/planner.md +53 -0
- package/agents/researcher.md +67 -0
- package/agents/reviewer.md +73 -0
- package/dist/chunk-43ONBFZX.js +240 -0
- package/dist/chunk-APZY4IME.js +27 -0
- package/dist/chunk-V3VHZ2VX.js +59 -0
- package/dist/execution/engine/engines/zcode/constants.cjs +62 -9
- package/dist/execution/engine/engines/zcode/constants.d.cts +116 -12
- package/dist/execution/engine/engines/zcode/constants.d.ts +116 -12
- package/dist/execution/engine/engines/zcode/constants.js +39 -7
- package/dist/execution/engine/engines/zcode/reader.d.cts +2 -1
- package/dist/execution/engine/engines/zcode/reader.d.ts +2 -1
- package/dist/execution/engine/engines/zcode/reader.js +4 -234
- package/dist/execution/engine/paths.js +7 -19
- package/dist/index.cjs +18234 -1277
- package/dist/index.d.cts +5646 -673
- package/dist/index.d.ts +5646 -673
- package/dist/index.js +17828 -1277
- package/dist/{types-BxyAidGf.d.cts → types-Dv4QhSJ_.d.cts} +678 -112
- package/dist/{types-BxyAidGf.d.ts → types-Dv4QhSJ_.d.ts} +678 -112
- package/package.json +7 -4
- package/src/__tests__/agent-opts-resolver-schema-prompt.test.ts +0 -1
- package/src/__tests__/append-system-prompt-assembly.test.ts +8 -7
- package/src/__tests__/fr4-get-state-handshake.test.ts +2 -2
- package/src/__tests__/m2-append-content-probe.test.ts +0 -1
- package/src/__tests__/manifest-store.test.ts +10 -9
- package/src/__tests__/record-store-cache.test.ts +0 -2
- package/src/__tests__/record-store-index.test.ts +1 -2
- package/src/__tests__/review-fix-loop-script.test.ts +93 -3
- package/src/__tests__/review-fix-loop-utils.test.ts +31 -10
- package/src/__tests__/robustness-low-batch1.test.ts +6 -5
- package/src/__tests__/robustness-medium-batch1.test.ts +2 -2
- package/src/__tests__/robustness-medium-batch2.test.ts +17 -6
- package/src/__tests__/robustness-medium-batch4.test.ts +2 -2
- package/src/__tests__/session-runner.test.ts +1 -1
- package/src/__tests__/smoke.test.ts +9 -2
- package/src/core/__tests__/host-services.test.ts +2 -2
- package/src/core/__tests__/logger.test.ts +1 -1
- package/src/core/error-message.ts +9 -0
- package/src/core/host-services.ts +21 -5
- package/src/core/notify-ports.ts +18 -5
- package/src/execution/__tests__/agent-profile.test.ts +232 -0
- package/src/execution/__tests__/agent-registry.test.ts +370 -0
- package/src/execution/__tests__/agent-result-mapper.test.ts +18 -2
- package/src/execution/__tests__/agents-assembly.test.ts +219 -0
- package/src/execution/__tests__/ask-user-transit-e2e.test.ts +6 -6
- package/src/execution/__tests__/chat-engine-routing.test.ts +136 -30
- package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +5 -4
- package/src/execution/__tests__/cold-resurrect.test.ts +283 -0
- package/src/execution/__tests__/create-concurrency-pool.test.ts +194 -0
- package/src/execution/__tests__/delivery-methods.test.ts +77 -62
- package/src/execution/__tests__/descendant-sweep-guards.test.ts +220 -0
- package/src/execution/__tests__/descendant-sweep.test.ts +269 -0
- package/src/execution/__tests__/dialog-queue.test.ts +199 -1
- package/src/execution/__tests__/engine-model-validation.test.ts +741 -0
- package/src/execution/__tests__/epipe-fallback.test.ts +31 -24
- package/src/execution/__tests__/execute-and-await-worktree.test.ts +21 -91
- package/src/execution/__tests__/execute-nesting.test.ts +34 -188
- package/src/execution/__tests__/execution-record.test.ts +217 -60
- package/src/execution/__tests__/execution-runtime-face.test.ts +272 -0
- package/src/execution/__tests__/explicit-agent-ref-guard.test.ts +3 -3
- package/src/execution/__tests__/finalize-record.test.ts +278 -16
- package/src/execution/__tests__/gc-timer.test.ts +57 -2
- package/src/execution/__tests__/get-record-for-action-restart.test.ts +14 -12
- package/src/execution/__tests__/get-state-handshake.test.ts +127 -0
- package/src/execution/__tests__/helpers/mock-extension-api.ts +1 -1
- package/src/execution/__tests__/helpers/session-runner-mocks.ts +113 -0
- package/src/execution/__tests__/helpers/spawn-mock.ts +150 -3
- package/src/execution/__tests__/helpers/subagent-service-mocks.ts +137 -0
- package/src/execution/__tests__/keep-alive-no-progress.test.ts +280 -0
- package/src/execution/__tests__/kill-all-escalation.test.ts +196 -0
- package/src/execution/__tests__/lifecycle-manager-idle-timer-identity.test.ts +117 -0
- package/src/execution/__tests__/lifecycle-manager.test.ts +39 -0
- package/src/execution/__tests__/lifecycle-predicates.test.ts +1 -2
- package/src/execution/__tests__/manifest-parentid.test.ts +4 -4
- package/src/execution/__tests__/manifest-store-tmp-recovery.test.ts +99 -0
- package/src/execution/__tests__/max-turns-to-watchdog-ms.test.ts +113 -0
- package/src/execution/__tests__/model-resolver.test.ts +2 -2
- package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +23 -121
- package/src/execution/__tests__/nested-visibility.test.ts +2 -0
- package/src/execution/__tests__/notify-ledger.test.ts +1249 -0
- package/src/execution/__tests__/output-collector.test.ts +117 -6
- package/src/execution/__tests__/pi-invocation.test.ts +1 -1
- package/src/execution/__tests__/record-store-orphan-revive.test.ts +159 -0
- package/src/execution/__tests__/record-store.test.ts +89 -5
- package/src/execution/__tests__/records-cwd-isolation.test.ts +2 -2
- package/src/execution/__tests__/recursive-visibility-baseline.test.ts +29 -132
- package/src/execution/__tests__/recursive-visibility-env.test.ts +55 -179
- package/src/execution/__tests__/rpc-mode.test.ts +2 -2
- package/src/execution/__tests__/run-and-finalize-anchoring.test.ts +387 -0
- package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +19 -9
- package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +5 -4
- package/src/execution/__tests__/run-spawn-edges.test.ts +418 -26
- package/src/execution/__tests__/run-spawn-integration.test.ts +3 -3
- package/src/execution/__tests__/run-spawn-resume.test.ts +2 -2
- package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +2 -2
- package/src/execution/__tests__/run-spawn-stdout-callback-throw.test.ts +16 -8
- package/src/execution/__tests__/service-kill-escalation.test.ts +91 -0
- package/src/execution/__tests__/session-context-resolver.test.ts +0 -2
- package/src/execution/__tests__/session-file-gc.test.ts +35 -0
- package/src/execution/__tests__/session-pending.test.ts +471 -0
- package/src/execution/__tests__/session-reconstructor.test.ts +366 -15
- package/src/execution/__tests__/session-runner-branch-cache-lru.test.ts +110 -0
- package/src/execution/__tests__/session-runner-close-prune.test.ts +181 -0
- package/src/execution/__tests__/session-runner-dispatch.test.ts +489 -0
- package/src/execution/__tests__/session-runner-epipe.test.ts +4 -3
- package/src/execution/__tests__/session-runner-heartbeat-idle-fallback.test.ts +227 -0
- package/src/execution/__tests__/session-runner-lifecycle-helpers.test.ts +290 -0
- package/src/execution/__tests__/session-runner-schema-env.test.ts +7 -5
- package/src/execution/__tests__/settled-watchdog.test.ts +524 -0
- package/src/execution/__tests__/spawn-args.test.ts +11 -10
- package/src/execution/__tests__/spawn-event-adapter-rpc.test.ts +26 -23
- package/src/execution/__tests__/spawn-event-adapter.test.ts +1 -1
- package/src/execution/__tests__/spawn-worktree-guidance.test.ts +5 -4
- package/src/execution/__tests__/spawned-children.test.ts +155 -11
- package/src/execution/__tests__/start-sync-model-guard.test.ts +4 -4
- package/src/execution/__tests__/stdin-writer.test.ts +6 -4
- package/src/execution/__tests__/stream-sink-retirement.test.ts +6 -6
- package/src/execution/__tests__/subagent-actions-core.test.ts +1017 -0
- package/src/execution/__tests__/subagent-service-message-close.test.ts +99 -35
- package/src/execution/__tests__/subagent-service-multiproc-guard.test.ts +174 -0
- package/src/execution/__tests__/subagent-service-notify-gate.test.ts +271 -0
- package/src/execution/__tests__/subagent-service-parent-guard.test.ts +33 -29
- package/src/execution/__tests__/subagent-service-recovery-bounds.test.ts +341 -0
- package/src/execution/__tests__/subagent-service.test.ts +37 -30
- package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +88 -12
- package/src/execution/__tests__/subprocess-agent-runner-timeout.test.ts +75 -0
- package/src/execution/__tests__/subprocess-agent-runner.test.ts +22 -20
- package/src/execution/__tests__/temp-prompt.test.ts +1 -1
- package/src/execution/__tests__/timeout-integration.test.ts +13 -12
- package/src/execution/__tests__/turn-limiter-semantics.test.ts +1 -1
- package/src/execution/__tests__/turn-limiter.test.ts +1 -1
- package/src/execution/__tests__/ui-request-handler-factory.test.ts +107 -7
- package/src/execution/__tests__/ui-request-handler.test.ts +4 -3
- package/src/execution/__tests__/ui-request-queue.test.ts +167 -2
- package/src/execution/__tests__/worktree-git-ops.test.ts +571 -0
- package/src/execution/__tests__/worktree-manager.test.ts +14 -5
- package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +4 -3
- package/src/execution/__tests__/worktree-reconcile-aging.test.ts +204 -0
- package/src/execution/agent-registry.ts +298 -30
- package/src/execution/agent-result-mapper.ts +3 -0
- package/src/execution/agents-assembly.ts +88 -0
- package/src/execution/cold-resurrect.ts +199 -0
- package/src/execution/concurrency-pool.ts +71 -9
- package/src/execution/dialog-queue.ts +101 -3
- package/src/execution/engine/__tests__/common/capability-gate.test.ts +91 -0
- package/src/execution/engine/__tests__/common/data-dir.test.ts +1 -1
- package/src/execution/engine/__tests__/common/journal-wiring.test.ts +84 -0
- package/src/execution/engine/__tests__/common/kill-chain.test.ts +34 -7
- package/src/execution/engine/__tests__/common/persona-router.test.ts +4 -5
- package/src/execution/engine/__tests__/common/pool-manager.test.ts +211 -51
- package/src/execution/engine/__tests__/common/session-view-service-zcode-dbpath.test.ts +149 -0
- package/src/execution/engine/__tests__/common/session-view-service.test.ts +499 -0
- package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +56 -99
- package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +88 -15
- package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +33 -7
- package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +1 -1
- package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +75 -54
- package/src/execution/engine/__tests__/conformance/zcode-appserver-harness.ts +128 -0
- package/src/execution/engine/__tests__/engine-discovery.test.ts +15 -3
- package/src/execution/engine/__tests__/model-prompt.test.ts +15 -3
- package/src/execution/engine/__tests__/registry.test.ts +94 -3
- package/src/execution/engine/__tests__/routing.test.ts +115 -6
- package/src/execution/engine/common/capability-gate.ts +92 -0
- package/src/execution/engine/common/journal-wiring.ts +97 -0
- package/src/execution/engine/common/kill-chain.ts +42 -10
- package/src/execution/engine/common/nesting-guard.ts +66 -0
- package/src/execution/engine/common/persona-router.ts +18 -8
- package/src/execution/engine/common/pool-manager.ts +332 -78
- package/src/execution/engine/common/session-view-service.ts +506 -0
- package/src/execution/engine/common/session-view-types.ts +125 -0
- package/src/execution/engine/engine-discovery.ts +12 -16
- package/src/execution/engine/engines/pi/__tests__/pi-engine.test.ts +174 -28
- package/src/execution/engine/engines/pi/__tests__/spawn-opts-direct.test.ts +257 -0
- package/src/execution/{argv-mirror.ts → engine/engines/pi/argv-mirror.ts} +43 -21
- package/src/execution/{get-state-handshake.ts → engine/engines/pi/get-state-handshake.ts} +86 -11
- package/src/execution/{output-collector.ts → engine/engines/pi/output-collector.ts} +108 -19
- package/src/execution/engine/engines/pi/pi-engine.ts +434 -38
- package/src/execution/{pi-invocation.ts → engine/engines/pi/pi-invocation.ts} +2 -2
- package/src/execution/engine/engines/pi/reader.ts +11 -0
- package/src/execution/engine/engines/pi/registration.ts +4 -2
- package/src/execution/engine/engines/pi/session-runner.ts +2840 -0
- package/src/execution/{spawn-event-adapter.ts → engine/engines/pi/spawn-event-adapter.ts} +75 -34
- package/src/execution/{stdin-writer.ts → engine/engines/pi/stdin-writer.ts} +10 -9
- package/src/execution/{temp-prompt.ts → engine/engines/pi/temp-prompt.ts} +2 -2
- package/src/execution/{turn-limiter.ts → engine/engines/pi/turn-limiter.ts} +1 -1
- package/src/execution/engine/engines/zcode/__tests__/__fixtures__/fake-appserver.mjs +301 -0
- package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-appserver.json +36 -0
- package/src/execution/engine/engines/zcode/__tests__/appserver-launcher.test.ts +321 -0
- package/src/execution/engine/engines/zcode/__tests__/connection.test.ts +473 -0
- package/src/execution/engine/engines/zcode/__tests__/parser.test.ts +7 -210
- package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +6 -110
- package/src/execution/engine/engines/zcode/__tests__/session-channel-dispose-harvest.test.ts +247 -0
- package/src/execution/engine/engines/zcode/__tests__/session-channel-turn-timers.test.ts +451 -0
- package/src/execution/engine/engines/zcode/__tests__/session-channel.test.ts +792 -0
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-appserver.test.ts +782 -0
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-degrade.test.ts +168 -0
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-dispose.test.ts +210 -0
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-retry.test.ts +353 -0
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-status.test.ts +282 -0
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-timeout.test.ts +372 -0
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +65 -47
- package/src/execution/engine/engines/zcode/appserver-launcher.ts +167 -0
- package/src/execution/engine/engines/zcode/connection.ts +598 -0
- package/src/execution/engine/engines/zcode/constants.ts +147 -14
- package/src/execution/engine/engines/zcode/golden-sample.ts +42 -34
- package/src/execution/engine/engines/zcode/parser.ts +12 -346
- package/src/execution/engine/engines/zcode/preparer.ts +22 -150
- package/src/execution/engine/engines/zcode/session-channel.ts +968 -0
- package/src/execution/engine/engines/zcode/zcode-engine.ts +1023 -250
- package/src/execution/engine/host-task-spec.ts +32 -36
- package/src/execution/engine/model-validation.ts +177 -0
- package/src/execution/engine/port.ts +65 -7
- package/src/execution/engine/registry.ts +53 -0
- package/src/execution/engine/routing.ts +75 -1
- package/src/execution/engine/types.ts +30 -103
- package/src/execution/execution-record.ts +222 -144
- package/src/execution/finalize-record.ts +181 -85
- package/src/execution/idle-gc.ts +28 -0
- package/src/execution/lifecycle-manager.ts +27 -3
- package/src/execution/lifecycle-predicates.ts +1 -1
- package/src/execution/manifest-store.ts +53 -62
- package/src/execution/notifier.ts +10 -10
- package/src/execution/notify-host.ts +212 -0
- package/src/execution/notify-ledger.ts +117 -16
- package/src/execution/record-entry.ts +8 -2
- package/src/execution/record-store.ts +148 -88
- package/src/execution/round-settlement.ts +93 -0
- package/src/execution/session-file-gc.ts +96 -62
- package/src/execution/session-pending.ts +213 -62
- package/src/execution/session-reconstructor.ts +256 -143
- package/src/execution/sessions-index.ts +127 -102
- package/src/execution/settled-watchdog.ts +311 -0
- package/src/execution/subagent-actions-core.ts +686 -0
- package/src/execution/subagent-service.ts +1106 -907
- package/src/execution/subprocess-agent-runner.ts +144 -97
- package/src/execution/types.ts +9 -0
- package/src/execution/ui-request-handler-factory.ts +126 -75
- package/src/execution/ui-request-queue.ts +50 -19
- package/src/execution/worktree-git-ops.ts +397 -0
- package/src/execution/worktree-manager.ts +72 -10
- package/src/execution/worktree-registry.ts +6 -12
- package/src/index.ts +542 -9
- package/src/orchestration/__tests__/__fixtures__/worker-template.snapshot.txt +42 -3
- package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +3 -5
- package/src/orchestration/__tests__/agent-call-stream.test.ts +2 -2
- package/src/orchestration/__tests__/args-meta.test.ts +358 -0
- package/src/orchestration/__tests__/args-validator.test.ts +14 -0
- package/src/orchestration/__tests__/error-recovery-rebuild-failure.test.ts +312 -0
- package/src/orchestration/__tests__/error-recovery-terminal-hardening.test.ts +384 -0
- package/src/orchestration/__tests__/execute-agent-call.test.ts +151 -11
- package/src/orchestration/__tests__/file-run-store-prune.test.ts +168 -0
- package/src/orchestration/__tests__/file-run-store-throttle.test.ts +168 -0
- package/src/orchestration/__tests__/file-run-store.test.ts +390 -0
- package/src/orchestration/__tests__/helpers/flush-microtasks.ts +13 -0
- package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +34 -0
- package/src/orchestration/__tests__/lifecycle-abort-broadcast-signal.test.ts +357 -0
- package/src/orchestration/__tests__/lifecycle-recover-crashed.test.ts +289 -0
- package/src/orchestration/__tests__/lifecycle-runid-injection.test.ts +3 -3
- package/src/orchestration/__tests__/lifecycle.test.ts +84 -5
- package/src/orchestration/__tests__/non-cloneable-return-e2e.test.ts +1 -1
- package/src/orchestration/__tests__/run-snapshot.test.ts +356 -0
- package/src/orchestration/__tests__/script-generate.test.ts +314 -0
- package/src/orchestration/__tests__/script-lint.test.ts +17 -0
- package/src/orchestration/__tests__/test-mocks.ts +2 -0
- package/src/orchestration/__tests__/worker-exit-without-result.test.ts +7 -6
- package/src/orchestration/__tests__/worker-message-pump-finalize-run.test.ts +229 -0
- package/src/orchestration/__tests__/{error-recovery-handlers.test.ts → worker-message-pump-handlers.test.ts} +28 -27
- package/src/orchestration/__tests__/{error-recovery-postmessage-defense.test.ts → worker-message-pump-postmessage-defense.test.ts} +8 -8
- package/src/orchestration/__tests__/{error-recovery-serialize-failed-result.test.ts → worker-message-pump-serialize-failed-result.test.ts} +2 -2
- package/src/orchestration/__tests__/{error-recovery-workflow-call.test.ts → worker-message-pump-workflow-call.test.ts} +1 -1
- package/src/orchestration/__tests__/worker-pending-timeout-abort.test.ts +275 -0
- package/src/orchestration/__tests__/worker-script-builder-runtime.test.ts +78 -1
- package/src/orchestration/__tests__/worker-script-builder.test.ts +1 -1
- package/src/orchestration/__tests__/workflow-files.test.ts +186 -0
- package/src/orchestration/__tests__/workflow-nesting-e2e.test.ts +1 -1
- package/src/orchestration/__tests__/workflow-run-summary.test.ts +119 -0
- package/src/orchestration/__tests__/workflow-script-registry-impl.test.ts +124 -0
- package/src/orchestration/agent-opts-resolver.ts +8 -8
- package/src/orchestration/args-meta.ts +198 -0
- package/src/orchestration/args-validator.ts +53 -31
- package/src/orchestration/execute-agent-call.ts +25 -79
- package/src/orchestration/file-run-store.ts +327 -0
- package/src/orchestration/launcher.ts +160 -104
- package/src/orchestration/lifecycle.ts +371 -97
- package/src/orchestration/models/agent-call.ts +7 -7
- package/src/orchestration/models/budget.ts +5 -5
- package/src/orchestration/models/ports.ts +4 -4
- package/src/orchestration/models/run-runtime.ts +15 -15
- package/src/orchestration/models/trace.ts +9 -9
- package/src/orchestration/models/types.ts +111 -22
- package/src/orchestration/models/workflow-run.ts +28 -28
- package/src/orchestration/models/workflow-script.ts +4 -4
- package/src/orchestration/run-snapshot.ts +266 -0
- package/src/orchestration/script-generate.ts +154 -0
- package/src/orchestration/script-lint.ts +123 -90
- package/src/orchestration/worker-handle.ts +10 -10
- package/src/orchestration/worker-host.ts +10 -10
- package/src/orchestration/{error-recovery.ts → worker-message-pump.ts} +498 -221
- package/src/orchestration/worker-script-builder.ts +401 -346
- package/src/orchestration/workflow-files.ts +37 -11
- package/src/orchestration/workflow-run-summary.ts +69 -0
- package/src/orchestration/workflow-script-registry-impl.ts +31 -9
- package/src/shared/__tests__/agent-ref.test.ts +209 -2
- package/src/shared/__tests__/atomic-write.test.ts +267 -0
- package/src/shared/__tests__/bounded-serialize.test.ts +236 -0
- package/src/shared/__tests__/injection-render.test.ts +518 -0
- package/src/shared/__tests__/meta-parser.test.ts +151 -0
- package/src/shared/__tests__/resource-discovery-host-roots.test.ts +474 -0
- package/src/shared/__tests__/resource-discovery.test.ts +261 -217
- package/src/shared/agent-ref.ts +143 -2
- package/src/shared/atomic-write.ts +323 -0
- package/src/shared/bounded-serialize.ts +154 -0
- package/src/shared/injection-render.ts +279 -0
- package/src/shared/meta-parser.ts +182 -68
- package/src/shared/model-ref.ts +15 -2
- package/src/shared/resource-discovery.ts +97 -204
- package/src/shared/resource-meta.ts +14 -0
- package/src/shared/schema-jsonify.ts +1 -1
- package/src/shared/xml-injection.ts +9 -9
- package/workflows/README.md +9 -9
- package/workflows/chain.js +4 -2
- package/workflows/map-reduce.js +5 -3
- package/workflows/parallel.js +5 -3
- package/workflows/review-fix-loop-utils.cjs +165 -92
- package/workflows/review-fix-loop-utils.d.cts +287 -0
- package/workflows/review-fix-loop.js +18 -7
- package/workflows/scatter-gather.js +4 -2
- package/dist/chunk-3VOERJPJ.js +0 -22
- package/src/execution/__tests__/execute-options-mapper.test.ts +0 -200
- package/src/execution/engine/engines/pi/__tests__/task-spec-mapper.test.ts +0 -164
- package/src/execution/engine/engines/pi/task-spec-mapper.ts +0 -100
- package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-spawn.json +0 -39
- package/src/execution/engine/engines/zcode/__tests__/launcher.test.ts +0 -150
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine.test.ts +0 -580
- package/src/execution/engine/engines/zcode/launcher.ts +0 -161
- package/src/execution/execute-options-mapper.ts +0 -115
- package/src/execution/session-runner.ts +0 -1789
- package/src/shared/__tests__/resource-discovery-manifest-cache.test.ts +0 -288
|
@@ -1,47 +1,43 @@
|
|
|
1
1
|
// src/execution/engine/host-task-spec.ts
|
|
2
2
|
//
|
|
3
|
-
// ExecuteOptions →
|
|
3
|
+
// ExecuteOptions → AgentCallOpts 的宿主侧最小正向映射(U0:chat 工具域引擎分支)。
|
|
4
4
|
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
5
|
+
// [D6 任务形状合流] 产出类型从原 AgentTaskSpec 改为合流形状 AgentCallOpts(单一任务
|
|
6
|
+
// 形状,EnginePort.run 入参——原 AgentTaskSpec 已删除)。字段映射是 ExecuteOptions →
|
|
7
|
+
// AgentCallOpts 的中立直译(prompt=task 正文、description=slug 短标签;agent/model/
|
|
8
|
+
// thinkingLevel/skillPath/appendSystemPrompt/schema/maxTurns/graceTurns/worktree/cwd
|
|
9
|
+
// 同名透传)。不 import 任何具体引擎模块(registry.ts 依赖方向纪律:上层按中立类型
|
|
10
|
+
// 组装声明,引擎细节归引擎)。
|
|
11
11
|
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
12
|
+
// schemaEnv 不透传(与原 AgentTaskSpec 形态一致的字段面):pi 边界直出时 schema 派生
|
|
13
|
+
// 优先——透传会在 chat 域引入「opts.schemaEnv 原值 vs compact 派生值」的取值源变化,
|
|
14
|
+
// 维持派生优先保证与合流前行为逐字节一致。
|
|
15
|
+
//
|
|
16
|
+
// conversation/fork 在调用本 mapper 前已被 capability-gate 预检拒绝([D3-④]
|
|
17
|
+
// capabilities 驱动的调用前拒绝,非 pi 引擎 unsupported),透传仅保持映射完整性——
|
|
18
|
+
// 未来引擎支持时无需改本函数。
|
|
14
19
|
|
|
20
|
+
import type { AgentCallOpts } from "../../orchestration/models/types.ts";
|
|
15
21
|
import type { ExecuteOptions } from "../types.ts";
|
|
16
|
-
import type { AgentTaskSpec, PersonaSpec } from "./types.ts";
|
|
17
22
|
|
|
18
|
-
/** 纯函数:ExecuteOptions(chat 域执行选项)→
|
|
19
|
-
export function executeOptionsToEngineTaskSpec(opts: ExecuteOptions):
|
|
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;
|
|
23
|
+
/** 纯函数:ExecuteOptions(chat 域执行选项)→ 合流任务声明 AgentCallOpts。无副作用、幂等。 */
|
|
24
|
+
export function executeOptionsToEngineTaskSpec(opts: ExecuteOptions): AgentCallOpts {
|
|
29
25
|
return {
|
|
30
|
-
|
|
31
|
-
slug: opts.slug,
|
|
32
|
-
agent: opts.agent,
|
|
33
|
-
model: opts.model,
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
...(
|
|
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,
|
|
26
|
+
prompt: opts.task,
|
|
27
|
+
...(opts.slug !== undefined ? { description: opts.slug } : {}),
|
|
28
|
+
...(opts.agent !== undefined ? { agent: opts.agent } : {}),
|
|
29
|
+
...(opts.model !== undefined ? { model: opts.model } : {}),
|
|
30
|
+
...(opts.thinkingLevel !== undefined ? { thinkingLevel: opts.thinkingLevel } : {}),
|
|
31
|
+
...(opts.skillPath !== undefined ? { skillPath: opts.skillPath } : {}),
|
|
32
|
+
...(opts.appendSystemPrompt !== undefined ? { appendSystemPrompt: opts.appendSystemPrompt } : {}),
|
|
33
|
+
...(opts.schema !== undefined ? { schema: opts.schema } : {}),
|
|
34
|
+
...(opts.maxTurns !== undefined ? { maxTurns: opts.maxTurns } : {}),
|
|
35
|
+
...(opts.graceTurns !== undefined ? { graceTurns: opts.graceTurns } : {}),
|
|
36
|
+
...(opts.fork !== undefined ? { fork: opts.fork } : {}),
|
|
37
|
+
...(opts.worktree !== undefined ? { worktree: opts.worktree } : {}),
|
|
38
|
+
...(opts.cwd !== undefined ? { cwd: opts.cwd } : {}),
|
|
39
|
+
...(opts.conversation !== undefined ? { conversation: opts.conversation } : {}),
|
|
40
|
+
...(opts.idleTimeoutMs !== undefined ? { idleTimeoutMs: opts.idleTimeoutMs } : {}),
|
|
45
41
|
// 运行期字段(signal/ctxModel)不入声明——归 RunContext(port.ts 删字段去向)。
|
|
46
42
|
};
|
|
47
43
|
}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
// src/execution/engine/model-validation.ts
|
|
2
|
+
//
|
|
3
|
+
// [u-h2] 引擎感知的派发期 model 校验入口 + 错误文案构造。设计权威源:
|
|
4
|
+
// docs/design/timeout-audit-hygiene-batch.md §3.2(D2-1 路由先行 / D2-2 validateModel
|
|
5
|
+
// 可选面 / D2-3「引擎与模型不配套」文案 / D2-4 pi 未命中跨引擎候选)。
|
|
6
|
+
//
|
|
7
|
+
// 背景(§2.2 双重错配):model 校验曾固定用 pi registry 且时机在引擎路由之前——
|
|
8
|
+
// zcode 合法模型被误导性拒绝(F2-A)、pi 模型过校验后到 zcode 执行期才炸(F2-B)。
|
|
9
|
+
// 修复定案:校验源 = 目标引擎 registry(EnginePort.validateModel 可选面),时机 =
|
|
10
|
+
// 路由之后的派发同步期(record 创建前,不产生孤儿 record)。
|
|
11
|
+
//
|
|
12
|
+
// 两个调用点共享本入口与错误文案(D2-2 调用点双路径覆盖):
|
|
13
|
+
// ① chat 路径 subagent-service.executeViaEngine(非 pi 分支);
|
|
14
|
+
// ② workflow 路径 subprocess-agent-runner.run(route.engine.run 之前,非 pi 分支)。
|
|
15
|
+
|
|
16
|
+
import { stripThinkingSuffix } from "../../shared/model-ref.ts";
|
|
17
|
+
import type { EnginePort } from "./port.ts";
|
|
18
|
+
import { DEFAULT_ENGINE_ID } from "./registry.ts";
|
|
19
|
+
import { toErrorMessage } from "../../core/error-message.ts";
|
|
20
|
+
|
|
21
|
+
/** 错误消息中列出的目标引擎可用清单上限(防超长错误信息;与 shared/model-ref 同量级口径)。 */
|
|
22
|
+
const ENGINE_MODEL_LIST_LIMIT = 20;
|
|
23
|
+
|
|
24
|
+
// ============================================================
|
|
25
|
+
// 场景 2:engine+model 不配套的结构化错误(D2-3)
|
|
26
|
+
// ============================================================
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* 「引擎与模型不配套」错误(设计 §3.2.1 场景 2)。code 沿用 §3.3.3 错误规格表的
|
|
30
|
+
* model_not_available(与 ZcodePrepareError 同码——同一失败域的早抛形态)。
|
|
31
|
+
*/
|
|
32
|
+
class EngineModelMismatchError extends Error {
|
|
33
|
+
readonly code = "model_not_available";
|
|
34
|
+
/** 恢复指引(错误 → 权威源 → 重试闭环;EngineError.recovery 同构字段)。 */
|
|
35
|
+
readonly recovery: string;
|
|
36
|
+
|
|
37
|
+
constructor(message: string, recovery: string) {
|
|
38
|
+
super(message);
|
|
39
|
+
this.name = "EngineModelMismatchError";
|
|
40
|
+
this.recovery = recovery;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* 非 pi 引擎的派发同步期 model 校验(两路径统一入口)。
|
|
46
|
+
*
|
|
47
|
+
* - 引擎实现 validateModel:同步裁决(含 undefined = 查引擎缺省模型),返回 canonical
|
|
48
|
+
* 全名供 record.model 留痕;失败包装为 EngineModelMismatchError(场景 2 文案:
|
|
49
|
+
* 点破 registry 独立 + 目标引擎可用清单 + 按引擎区分的省略语义修正动作)。
|
|
50
|
+
* - 引擎未实现 validateModel:返回 modelRef 原样(透传给其 prepare 期校验兜底——
|
|
51
|
+
* 现状语义,未来引擎零强制接入)。
|
|
52
|
+
*
|
|
53
|
+
* @param engine 路由解析出的目标引擎
|
|
54
|
+
* @param modelRef 显式 model(调用参数或 agent .md frontmatter;undefined = 引擎缺省语义)
|
|
55
|
+
* @returns canonical ref(引擎裁决后全名);未实现校验面时 = modelRef 原样
|
|
56
|
+
*/
|
|
57
|
+
export function validateModelForEngine(
|
|
58
|
+
engine: EnginePort,
|
|
59
|
+
modelRef: string | undefined,
|
|
60
|
+
): string | undefined {
|
|
61
|
+
if (engine.id === DEFAULT_ENGINE_ID) return modelRef; // 防御:pi 不经此入口(走既有三层解析链)
|
|
62
|
+
if (typeof engine.validateModel !== "function") return modelRef;
|
|
63
|
+
try {
|
|
64
|
+
return engine.validateModel(modelRef).canonicalRef;
|
|
65
|
+
} catch (err) {
|
|
66
|
+
throw buildMismatchError(engine, modelRef, err);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* 场景 2 文案构造(D2-3):① 点破 registry 独立;② 列目标引擎可用清单(数据源
|
|
72
|
+
* listModels;引擎未实现时省略清单行,保留引擎原始错误作诊断行);③ 👉 修正动作
|
|
73
|
+
* (清单重试 / 省略 model 用引擎缺省——pi 的「继承主 agent」语义对非 pi 引擎是错误
|
|
74
|
+
* 指引,此处按引擎缺省表述)。
|
|
75
|
+
*/
|
|
76
|
+
function buildMismatchError(engine: EnginePort, modelRef: string | undefined, cause: unknown): EngineModelMismatchError {
|
|
77
|
+
const ref = modelRef === undefined || modelRef.trim() === "" ? "(engine default)" : modelRef;
|
|
78
|
+
const lines = [
|
|
79
|
+
`model '${ref}' is not available on engine '${engine.id}'.`,
|
|
80
|
+
`Engine registries are independent — ids in <available_provider_models> (pi registry) do NOT apply to '${engine.id}' dispatches.`,
|
|
81
|
+
];
|
|
82
|
+
const available = safeListModels(engine);
|
|
83
|
+
if (available.length > 0) {
|
|
84
|
+
lines.push(`${engine.id} models with configured credentials:`);
|
|
85
|
+
lines.push(` ${available.slice(0, ENGINE_MODEL_LIST_LIMIT).join(", ")}${available.length > ENGINE_MODEL_LIST_LIMIT ? ", ..." : ""}`);
|
|
86
|
+
}
|
|
87
|
+
// 引擎缺省模型名(validateModel(undefined) 成功才给——失败时省略句不带具体名,
|
|
88
|
+
// 缺省本身也不可用属于凭据级故障,引擎原始错误行已覆盖诊断)。
|
|
89
|
+
const engineDefault = safeEngineDefault(engine);
|
|
90
|
+
lines.push(
|
|
91
|
+
`👉 Retry with one of the above (exact string), or omit \`model\` to use the '${engine.id}' engine default` +
|
|
92
|
+
(engineDefault !== undefined ? ` (${engineDefault})` : "") +
|
|
93
|
+
`.`,
|
|
94
|
+
);
|
|
95
|
+
// 引擎侧原始裁决失败原因(provider 未配凭据 / 模型未启用等)——诊断行,避免包装层吞掉细节。
|
|
96
|
+
lines.push(`Engine said: ${toErrorMessage(cause)}`);
|
|
97
|
+
const recovery =
|
|
98
|
+
`Retry with an exact model id from the '${engine.id}' list above, or omit the \`model\` param to use the '${engine.id}' engine default` +
|
|
99
|
+
(engineDefault !== undefined ? ` (${engineDefault})` : "") +
|
|
100
|
+
`.`;
|
|
101
|
+
return new EngineModelMismatchError(lines.join("\n"), recovery);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// ============================================================
|
|
105
|
+
// 场景 3:pi registry 未命中的跨引擎纠错候选(D2-4)
|
|
106
|
+
// ============================================================
|
|
107
|
+
|
|
108
|
+
/** notFoundError 的结构化标记(shared/model-ref.ts 挂载;跨引擎反查的识别面)。 */
|
|
109
|
+
interface RefNotFoundMarker {
|
|
110
|
+
refNotFound?: boolean;
|
|
111
|
+
refInput?: string;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* pi registry 未命中时反查其他已注册引擎的 listModels(D2-4):**唯一**引擎全等命中
|
|
116
|
+
* (strip thinking 后缀后与清单 id 全等——对齐零宽容原则,模糊匹配不参与建议)才追加
|
|
117
|
+
* 「该 id 属于引擎 X」候选段;多引擎命中/零命中原样返回(既有文案零回归——V2-4③)。
|
|
118
|
+
*
|
|
119
|
+
* @param err resolveModel 抛出的错误(须带 refNotFound 标记才处理)
|
|
120
|
+
* @param engineIds 已注册引擎清单(registry.listEngines 快照)
|
|
121
|
+
* @param getEngineFn 引擎获取(registry.getEngine;测试注入)
|
|
122
|
+
* @returns 原错误(无可附候选)或追加候选段的新错误(不 mutate 原错误)
|
|
123
|
+
*/
|
|
124
|
+
export function withCrossEngineHint(
|
|
125
|
+
err: unknown,
|
|
126
|
+
engineIds: readonly string[],
|
|
127
|
+
getEngineFn: (id: string) => EnginePort | undefined,
|
|
128
|
+
): unknown {
|
|
129
|
+
if (!(err instanceof Error)) return err;
|
|
130
|
+
const marker = err as Error & RefNotFoundMarker;
|
|
131
|
+
if (marker.refNotFound !== true || marker.refInput === undefined) return err;
|
|
132
|
+
const clean = stripThinkingSuffix(marker.refInput);
|
|
133
|
+
|
|
134
|
+
let matchedEngineId: string | undefined;
|
|
135
|
+
let matchCount = 0;
|
|
136
|
+
for (const id of engineIds) {
|
|
137
|
+
if (id === DEFAULT_ENGINE_ID) continue; // pi 是裁决源本身,不参与反查
|
|
138
|
+
const engine = getEngineFn(id);
|
|
139
|
+
if (engine === undefined) continue;
|
|
140
|
+
// 单引擎清单读取失败/无清单(safeListModels → [])不阻塞反查(可发现性降级语义)
|
|
141
|
+
if (safeListModels(engine).includes(clean)) {
|
|
142
|
+
matchCount++;
|
|
143
|
+
matchedEngineId ??= id;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (matchCount !== 1 || matchedEngineId === undefined) return err;
|
|
147
|
+
return new Error(
|
|
148
|
+
`${err.message}\n` +
|
|
149
|
+
`This id matches the registry of engine '${matchedEngineId}'.\n` +
|
|
150
|
+
`👉 Retry with engine: '${matchedEngineId}', or use a pi model from <available_provider_models>, ` +
|
|
151
|
+
`or omit \`model\` to inherit the main agent model.`,
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// ============================================================
|
|
156
|
+
// 内部:引擎面的失败安全读取
|
|
157
|
+
// ============================================================
|
|
158
|
+
|
|
159
|
+
/** 引擎可用清单(listModels 失败安全——校验错误路径不再叠加清单读取故障;null 契约按零清单)。 */
|
|
160
|
+
function safeListModels(engine: EnginePort): string[] {
|
|
161
|
+
if (typeof engine.listModels !== "function") return [];
|
|
162
|
+
try {
|
|
163
|
+
return engine.listModels()?.map((m) => m.id) ?? [];
|
|
164
|
+
} catch {
|
|
165
|
+
return [];
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** 引擎缺省模型(validateModel(undefined);失败安全返回 undefined)。 */
|
|
170
|
+
function safeEngineDefault(engine: EnginePort): string | undefined {
|
|
171
|
+
if (typeof engine.validateModel !== "function") return undefined;
|
|
172
|
+
try {
|
|
173
|
+
return engine.validateModel(undefined).canonicalRef;
|
|
174
|
+
} catch {
|
|
175
|
+
return undefined;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
@@ -4,6 +4,15 @@
|
|
|
4
4
|
// §3.3.5「EnginePort 完整签名」——本文件是可编码落地的契约层,后续 wave(公共降级层
|
|
5
5
|
// P2 / zcode 引擎 P3 / 配置路由 P4)以本接口为实现契约,字段级变更须先改设计文档。
|
|
6
6
|
//
|
|
7
|
+
// 字段级扩展登记(接上文纪律——先改设计文档再扩接口):
|
|
8
|
+
// - [R1 已实施 2026-08-30] EnginePort.dispose?()——引擎停机面。权威源:
|
|
9
|
+
// docs/design/zcode-engine-appserver-resident.md §3.3 D6 / §3.4 不变量 4。
|
|
10
|
+
// - [R4 已实施 2026-08-30] RunContext.onHandleReady——运行中句柄回填通道
|
|
11
|
+
// (同设计 §3.4 不变量 3:sessionRef 在 create 应答后经本回调送达编排层,
|
|
12
|
+
// 与 onPoolResolved 分立两个时点)。
|
|
13
|
+
// - [u-h2 已实施 2026-09-05] EnginePort.validateModel?()——派发同步期 model 校验面。
|
|
14
|
+
// 权威源:docs/design/timeout-audit-hygiene-batch.md §3.2 D2-2。
|
|
15
|
+
//
|
|
7
16
|
// 四个能力面(D1):
|
|
8
17
|
// run —— 主语义:一次性 fire-to-completion 任务执行;
|
|
9
18
|
// interact —— 交互控制面(chatMode 的 message/close/cancel + idle,可选能力面,
|
|
@@ -14,14 +23,15 @@
|
|
|
14
23
|
|
|
15
24
|
import type { ChildProcess } from "node:child_process";
|
|
16
25
|
|
|
26
|
+
import type { AgentCallOpts } from "../../orchestration/models/types.ts";
|
|
17
27
|
import type { ModelInfo } from "../model-resolver.ts";
|
|
18
28
|
import type { SubagentStream } from "../stream-sink.ts";
|
|
19
29
|
import type { AgentEvent } from "../types.ts";
|
|
20
30
|
import type {
|
|
21
31
|
AgentOutcome,
|
|
22
|
-
AgentTaskSpec,
|
|
23
32
|
EngineCapabilities,
|
|
24
33
|
EngineHandle,
|
|
34
|
+
EngineHandleData,
|
|
25
35
|
InteractAction,
|
|
26
36
|
InteractResult,
|
|
27
37
|
ProbeReport,
|
|
@@ -33,9 +43,9 @@ import type {
|
|
|
33
43
|
// ============================================================
|
|
34
44
|
|
|
35
45
|
/**
|
|
36
|
-
* run 的运行期上下文。任务声明(
|
|
37
|
-
* onComplete 从 ExecuteOptions 移出(设计 §3.3.5
|
|
38
|
-
*
|
|
46
|
+
* run 的运行期上下文。任务声明(AgentCallOpts,D6 合流后的单一形状)与运行期句柄
|
|
47
|
+
* 分离——signal/ctxModel/onComplete 从 ExecuteOptions 移出(设计 §3.3.5 删字段去向),
|
|
48
|
+
* 因为它们是宿主注入的运行期对象,不属于跨引擎持久化的任务声明。
|
|
39
49
|
*
|
|
40
50
|
* 常驻进程友好(D1):onEvent 回调式(而非迭代器式)+ AbortSignal——引擎内部换常驻
|
|
41
51
|
* server 实现(未来 driver host)时接口不动。
|
|
@@ -49,7 +59,13 @@ export interface RunContext {
|
|
|
49
59
|
signal?: AbortSignal;
|
|
50
60
|
/** 事件流出口(host 消费后统一落 journal,D6 第②级)。 */
|
|
51
61
|
onEvent?: (event: AgentEvent) => void;
|
|
52
|
-
/**
|
|
62
|
+
/**
|
|
63
|
+
* model 解析第三层兜底(现有 D-008 语义不变)——**pi 链路专属兜底**:经
|
|
64
|
+
* taskSpecToExecuteOptions → resolveModel 第三层消费(PiEngine 直通)。自带
|
|
65
|
+
* provider 体系与缺省模型的引擎(如 zcode:requested > 引擎缺省常量链)按自身
|
|
66
|
+
* 默认链解析,不消费本字段(zcode 侧在「ctx 有模型但被忽略」时出声留痕,
|
|
67
|
+
* zcode-engine.warnIgnoredCtxModel)。
|
|
68
|
+
*/
|
|
53
69
|
ctxModel?: ModelInfo;
|
|
54
70
|
/**
|
|
55
71
|
* text_delta streaming 通道(宿主侧 UI widget)。与 onEvent 平行的 text_delta 出口:
|
|
@@ -81,12 +97,27 @@ export interface RunContext {
|
|
|
81
97
|
* 未来流式引擎需在事件出口前调用)。
|
|
82
98
|
*/
|
|
83
99
|
onPoolResolved?: (poolKey: string) => void;
|
|
100
|
+
/**
|
|
101
|
+
* [R4 §3.4 不变量 3] 运行中句柄回填通道:引擎在「session/create 应答到达后」
|
|
102
|
+
* 立即回调(早于 run resolve——stream 引擎的 run 生命周期远长于会话建立)。
|
|
103
|
+
* 与 onPoolResolved 分立两个时点:poolKey 在 prepare 期(onPoolResolved,连接
|
|
104
|
+
* 建立前即可知),sessionRef 在 create 应答后(本回调)。编排层收到后立即回填
|
|
105
|
+
* record.engineHandle 并落 entry——运行中的 GUI 经 entry 重建 record 即拿到
|
|
106
|
+
* ①②级读取钥匙,不再等 run resolve 后的终态回填。可选回调:不支持运行中回填
|
|
107
|
+
* 的引擎(spawn 单轮、终态即回填)不调用,宿主语义不受影响。
|
|
108
|
+
*/
|
|
109
|
+
onHandleReady?: (partial: Pick<EngineHandleData, "sessionRef" | "poolKey">) => void;
|
|
84
110
|
/**
|
|
85
111
|
* [U0 D10] 引擎 spawn 的子进程句柄注册钩子(宿主终止链记账)。引擎在 spawn 成功后
|
|
86
112
|
* 同步回调(与 pi runSpawn 的 spawnedChildren.set 同构时机);宿主据此把 child 注册进
|
|
87
113
|
* session-runner 的 spawnedChildren Map(cancel SIGTERM / dispose 收割兜底 / killAll
|
|
88
114
|
* 全量清理对非 pi 引擎 record 生效)。close/error 后由宿主按句守卫移除。可选:引擎
|
|
89
115
|
* 内部不 spawn 进程(如未来常驻 driver host 实现)时不调用,宿主记账自然为空。
|
|
116
|
+
*
|
|
117
|
+
* 边界声明(R1 D6):本钩子只用于 per-record 一次性 spawn(一任务一进程模态)。
|
|
118
|
+
* 引擎持有的常驻进程(跨任务共享,如 app-server 常驻连接)不经本钩子注册、不进
|
|
119
|
+
* spawnedChildren Map——其生命周期完全归引擎 dispose 管理(防 per-record 重复
|
|
120
|
+
* SIGTERM / 单任务 abort 误杀共享进程)。
|
|
90
121
|
*/
|
|
91
122
|
onChildSpawned?: (child: ChildProcess) => void;
|
|
92
123
|
}
|
|
@@ -129,8 +160,9 @@ export interface EnginePort {
|
|
|
129
160
|
/** D7(factory 初始化 + 版本变化检测触发;opts.force 跳过缓存强探)。 */
|
|
130
161
|
probe(opts?: { force?: boolean }): Promise<ProbeReport>;
|
|
131
162
|
|
|
132
|
-
/** D1 主语义:fire-to-completion。
|
|
133
|
-
|
|
163
|
+
/** D1 主语义:fire-to-completion。[D6 合流] task = AgentCallOpts(单一任务形状,
|
|
164
|
+
* 原 AgentTaskSpec 已并入——字段裁定见 orchestration/models/types.ts)。 */
|
|
165
|
+
run(task: AgentCallOpts, ctx: RunContext): Promise<EngineRunResult>;
|
|
134
166
|
|
|
135
167
|
/**
|
|
136
168
|
* D1 可选面:交互控制面。pi 首期原生实现(现有 chatMode 行为直通);不支持
|
|
@@ -150,4 +182,30 @@ export interface EnginePort {
|
|
|
150
182
|
* 侧零改动。
|
|
151
183
|
*/
|
|
152
184
|
listModels?(): Array<{ id: string; name?: string }> | null;
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* [u-h2 D2-2] 可选面:派发同步期 model 校验(引擎 registry 单源裁决)。实现引擎复用其
|
|
188
|
+
* prepare 期同一校验函数(zcode: resolveZcodeModelRef——同一函数两处消费,canonicalRef
|
|
189
|
+
* 归一化与短名缺省 provider 决策不产生双实现漂移);校验失败同步 throw(编排层包装为
|
|
190
|
+
* 「引擎与模型不配套」错误,见 engine/model-validation.ts)。
|
|
191
|
+
*
|
|
192
|
+
* modelRef undefined = 查询引擎缺省模型(D2-1:主 agent 的 pi id 不透传给非 pi 引擎,
|
|
193
|
+
* 缺省语义归引擎——zcode 落 ZCODE_FALLBACK_DEFAULT_MODEL)。返回 canonical 全名供
|
|
194
|
+
* record.model 留痕。
|
|
195
|
+
*
|
|
196
|
+
* 未实现:model 透传,引擎自身 prepare 期校验兜底(现状语义);pi 不实现(pi 链走
|
|
197
|
+
* 既有三层解析 + assertCanonicalModelRef 裁决,搬迁是大重构,设计 D2-2 被否②)。
|
|
198
|
+
*/
|
|
199
|
+
validateModel?(modelRef: string | undefined): { canonicalRef: string };
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* [R1 D6] 可选停机面:释放引擎持有的常驻资源(如 app-server 常驻进程 / 长连接)。
|
|
203
|
+
* 幂等契约(§3.4 不变量 4):重复调用无副作用;dispose 后首个 run 自动重建(与
|
|
204
|
+
* 「进程死后重建」同一代码路径)。可选成员保持向后兼容——无常驻资源的引擎(pi
|
|
205
|
+
* 现状 spawn 单轮)不必实现。等待策略(D6①「触发不等待」):宿主收割入口
|
|
206
|
+
* (registry disposeEngines → killAllSpawnedChildren)只同步调用拿 Promise 不
|
|
207
|
+
* await,引擎实现须自行保证同步面(立即 fire close 帧 + 同步 SIGTERM)在返回
|
|
208
|
+
* Promise 前完成;grace→SIGKILL 升级序列属异步面(promise 段)。
|
|
209
|
+
*/
|
|
210
|
+
dispose?(): Promise<void>;
|
|
153
211
|
}
|
|
@@ -10,9 +10,15 @@
|
|
|
10
10
|
//
|
|
11
11
|
// 依赖方向(设计 §3.3.1 贯穿纪律④):registry 只依赖 port.ts 的类型,不 import 任何
|
|
12
12
|
// 具体引擎——注册由组合根(index.ts)或引擎自己的 registration 模块完成,防循环依赖。
|
|
13
|
+
// (core/logger 是 facade 基础设施非引擎,dispose best-effort 记日志需要它,不违反本纪律。)
|
|
14
|
+
|
|
15
|
+
import { getLogger } from "../../core/logger.ts";
|
|
13
16
|
|
|
14
17
|
import type { EnginePort } from "./port.ts";
|
|
15
18
|
|
|
19
|
+
// core log facade(execution 层统一 "subagents" component,模块顶层缓存惯例)。
|
|
20
|
+
const logger = getLogger("subagents");
|
|
21
|
+
|
|
16
22
|
/** 引擎工厂:惰性创建引擎实例(getEngine 首次取用时执行)。 */
|
|
17
23
|
export type EngineFactory = () => EnginePort;
|
|
18
24
|
|
|
@@ -87,17 +93,64 @@ function getRegistrySlot(): EngineRegistrySlot {
|
|
|
87
93
|
return slot;
|
|
88
94
|
}
|
|
89
95
|
|
|
96
|
+
/**
|
|
97
|
+
* [R1 D6] 触发引擎 dispose:同步调用拿 Promise 不 await(「触发不等待」,D6①——
|
|
98
|
+
* dispose 的同步面〔fire close 帧 + 同步 SIGTERM〕由引擎实现保证在返回 Promise 前
|
|
99
|
+
* 完成,registry 不等待异步段)。同步 throw 与异步 reject 均记日志吞掉,绝不外溢
|
|
100
|
+
* 阻断调用方——重注册替换(D6②)与宿主收割(D6③)都是 best-effort 面,且 reject
|
|
101
|
+
* 无人接会成为 unhandledRejection 崩宿主。两条 dispose 路径共用本函数。
|
|
102
|
+
*/
|
|
103
|
+
function triggerEngineDispose(engine: EnginePort, source: string): void {
|
|
104
|
+
if (typeof engine.dispose !== "function") return;
|
|
105
|
+
try {
|
|
106
|
+
engine.dispose().then(undefined, (err: unknown) => {
|
|
107
|
+
logger.warn(
|
|
108
|
+
`[engine-registry] engine '${engine.id}' dispose rejected (${source}, best-effort continue): ${
|
|
109
|
+
err instanceof Error ? err.message : String(err)
|
|
110
|
+
}`,
|
|
111
|
+
);
|
|
112
|
+
});
|
|
113
|
+
} catch (err) {
|
|
114
|
+
logger.warn(
|
|
115
|
+
`[engine-registry] engine '${engine.id}' dispose threw synchronously (${source}, best-effort continue): ${
|
|
116
|
+
err instanceof Error ? err.message : String(err)
|
|
117
|
+
}`,
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
90
122
|
/**
|
|
91
123
|
* 登记引擎工厂。重复注册同一 id = 覆盖(组合根可能多次执行,如每次 session_start 重跑
|
|
92
124
|
* registerPiEngine——幂等覆盖保证不炸也不堆积),覆盖时丢弃缓存的旧单例,让下一次
|
|
93
125
|
* getEngine 用新工厂重建。
|
|
126
|
+
*
|
|
127
|
+
* [R1 D6②] 覆盖前对已实例化的旧单例触发 dispose(防泄漏——旧实例可能持有常驻进程/
|
|
128
|
+
* 长连接);触发不等待 + 失败不阻断(见 triggerEngineDispose),幂等覆盖语义不变。
|
|
94
129
|
*/
|
|
95
130
|
export function registerEngine(id: string, factory: EngineFactory): void {
|
|
96
131
|
const slot = getRegistrySlot();
|
|
132
|
+
const previous = slot.singletons.get(id);
|
|
133
|
+
if (previous) triggerEngineDispose(previous, `registerEngine('${id}') overwrite`);
|
|
97
134
|
slot.factories.set(id, factory);
|
|
98
135
|
slot.singletons.delete(id);
|
|
99
136
|
}
|
|
100
137
|
|
|
138
|
+
/**
|
|
139
|
+
* [R1 D6③] 对已实例化的引擎单例触发 dispose(触发不等待)。宿主唯一收割入口
|
|
140
|
+
* (session-runner killAllSpawnedChildren)在杀 per-record children 之前调用——
|
|
141
|
+
* 常驻进程的回收归引擎 dispose,本函数只负责按序触发。
|
|
142
|
+
*
|
|
143
|
+
* 只遍历 singletons:已实例化才可能持有常驻资源,绝不经 getEngine 实例化未用
|
|
144
|
+
* 引擎(停机路径反向创建资源违背停机语义)。dispose 后不删单例——幂等与
|
|
145
|
+
* 「dispose 后首个 run 自动重建」由引擎实现承诺(§3.4 不变量 4),registry
|
|
146
|
+
* 不越权管理引擎内部生命周期。
|
|
147
|
+
*/
|
|
148
|
+
export function disposeEngines(): void {
|
|
149
|
+
for (const engine of getRegistrySlot().singletons.values()) {
|
|
150
|
+
triggerEngineDispose(engine, "disposeEngines()");
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
101
154
|
/** 未注册 id 抛 EngineNotFoundError(含已注册清单与配置指引)。 */
|
|
102
155
|
export function getEngine(id: string): EnginePort {
|
|
103
156
|
const slot = getRegistrySlot();
|
|
@@ -150,7 +150,8 @@ export async function routeEngine(opts: EngineRouteOptions): Promise<EngineRoute
|
|
|
150
150
|
}
|
|
151
151
|
// 守卫 a/b(首期合流):显式指定(调用参数或 step 级)= 能力依赖声明,静默换引擎
|
|
152
152
|
// 违反意图——沙箱类任务被静默卸除安全能力正是要防的形态(D9① 原文)。守卫 b 的
|
|
153
|
-
//
|
|
153
|
+
// 独立载体(合流形状 AgentCallOpts 上的能力依赖声明字段,requires 已随 D6 裁撤)
|
|
154
|
+
// 下钻后在本分支前独立判定,首期显式 engine 即声明。
|
|
154
155
|
if (routing.source === "call") {
|
|
155
156
|
throw probeFailedError(routing.engineId, report, "engine 来自调用参数显式指定(能力依赖声明)——不兜底");
|
|
156
157
|
}
|
|
@@ -216,3 +217,76 @@ function describeRoutingSource(routing: EngineRoutingInput): string | undefined
|
|
|
216
217
|
}
|
|
217
218
|
return undefined;
|
|
218
219
|
}
|
|
220
|
+
|
|
221
|
+
// ============================================================
|
|
222
|
+
// routeEngineForHost:宿主两调用点的统一编排(D3-② 路由单点)
|
|
223
|
+
// ============================================================
|
|
224
|
+
|
|
225
|
+
/** routeEngineForHost 的参数(宿主装配:本地 pi 引擎 + 路由三件注入)。 */
|
|
226
|
+
export interface HostRouteOptions {
|
|
227
|
+
/** 三层路由输入(调用方装配:调用参数 / frontmatter / 全局默认)。 */
|
|
228
|
+
routing: EngineRoutingInput;
|
|
229
|
+
/**
|
|
230
|
+
* 守卫 c 判据:调用方显式指定的 model(与 routeEngine.taskModel 同口径——解析后的
|
|
231
|
+
* 兼底 model 恒非空会把一切兜底误判为 model 绑定命中,故只传显式值)。
|
|
232
|
+
*/
|
|
233
|
+
taskModel?: string;
|
|
234
|
+
/** engineRouting.strict(config.json):true = 一切 probe 失败直接报错。 */
|
|
235
|
+
strict: boolean;
|
|
236
|
+
/** 探针执行体(生产 = registry 引擎 .probe();测试可注入)。 */
|
|
237
|
+
probe: (engineId: string) => Promise<ProbeReport>;
|
|
238
|
+
/**
|
|
239
|
+
* 本地 pi 引擎实例(chat 域 = Service 的 chatPiEngine;workflow 域 = SAR 的 per-session
|
|
240
|
+
* DI 实例)。pi 请求与「非 pi 兜底回 pi」两种形态都由它接管——不依赖 registry 全局
|
|
241
|
+
* 注册态(单测注入 mock 时全局单例不可见;生产环境两者是同一进程单例对象)。
|
|
242
|
+
*/
|
|
243
|
+
piEngine: EnginePort;
|
|
244
|
+
/** 非 pi 引擎获取(缺省 registry.getEngine;测试注入)。 */
|
|
245
|
+
getEngineFn?: (engineId: string) => EnginePort;
|
|
246
|
+
/** 非 pi 注册表存在性检查(缺省 registry.hasEngine)。 */
|
|
247
|
+
hasEngineFn?: (engineId: string) => boolean;
|
|
248
|
+
/** 非 pi 注册表清单(缺省 registry.listEngines)。 */
|
|
249
|
+
listEnginesFn?: () => string[];
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* 宿主侧统一路由编排(D3-②:唯一实现,两调用点——SubagentService.execute 与
|
|
254
|
+
* SAR.run)。把原先散在两调用点的「pi 同步短路 + registry 注入(本地 pi 恒可用,
|
|
255
|
+
* engine_not_found 文案不把本地 pi 漏报成未注册)+ 兜底回 pi 时换本地实例」收敛到本函数。
|
|
256
|
+
*
|
|
257
|
+
* 返回值形态(时序契约):pi 请求路径**同步返回** EngineRouteResult(非 Promise)——
|
|
258
|
+
* 不引入微任务边界,SAR 的「run 内首个 await 前已触达 executeAndAwait」缺省路径时序
|
|
259
|
+
* 与旧形态逐字节一致;非 pi 路径返回 Promise(probe 编排固有异步),调用方统一用
|
|
260
|
+
* `routed instanceof Promise ? await routed : routed` 消费(pi 路径零 await)。
|
|
261
|
+
*/
|
|
262
|
+
export function routeEngineForHost(opts: HostRouteOptions): EngineRouteResult | Promise<EngineRouteResult> {
|
|
263
|
+
const routing = resolveEngineRouting(opts.routing);
|
|
264
|
+
|
|
265
|
+
// pi 请求(缺省/显式 pi):本地 DI 实例同步短路——pi 恒免探、无 fallback 可言,
|
|
266
|
+
// 不经 routeEngine 的 await/probe(「缺省路径行为零变化」A1 硬约束)。
|
|
267
|
+
if (routing.engineId === DEFAULT_ENGINE_ID) {
|
|
268
|
+
return {
|
|
269
|
+
engine: opts.piEngine,
|
|
270
|
+
engineId: DEFAULT_ENGINE_ID,
|
|
271
|
+
requestedEngineId: DEFAULT_ENGINE_ID,
|
|
272
|
+
source: routing.source,
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return routeEngine({
|
|
277
|
+
routing: opts.routing,
|
|
278
|
+
taskModel: opts.taskModel,
|
|
279
|
+
strict: opts.strict,
|
|
280
|
+
probe: opts.probe,
|
|
281
|
+
// 本地 pi 恒可用(per-session DI 绑定)——get/has/list 注入同一口径:
|
|
282
|
+
// probe 失败兜底回 pi 时取本地实例接管,engine_not_found 文案不漏报本地 pi。
|
|
283
|
+
getEngineFn: (engineId) =>
|
|
284
|
+
engineId === DEFAULT_ENGINE_ID ? opts.piEngine : (opts.getEngineFn?.(engineId) ?? getEngine(engineId)),
|
|
285
|
+
hasEngineFn: (engineId) =>
|
|
286
|
+
engineId === DEFAULT_ENGINE_ID || (opts.hasEngineFn?.(engineId) ?? hasEngine(engineId)),
|
|
287
|
+
listEnginesFn: () => {
|
|
288
|
+
const listed = opts.listEnginesFn?.() ?? listEngines();
|
|
289
|
+
return listed.includes(DEFAULT_ENGINE_ID) ? listed : [DEFAULT_ENGINE_ID, ...listed];
|
|
290
|
+
},
|
|
291
|
+
});
|
|
292
|
+
}
|