@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
|
@@ -15,11 +15,11 @@ import * as path from "node:path";
|
|
|
15
15
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
16
16
|
|
|
17
17
|
import type { AgentCallOpts, AgentResult } from "../../orchestration/models/types.ts";
|
|
18
|
-
import type { RunContext } from "../engine/port.ts";
|
|
18
|
+
import type { RunContext, EnginePort } from "../engine/port.ts";
|
|
19
19
|
import { clearEngines, registerEngine } from "../engine/registry.ts";
|
|
20
|
-
import type {
|
|
20
|
+
import type { ProbeReport } from "../engine/types.ts";
|
|
21
21
|
import { ModelConfigService, setModelConfigService } from "../model-config-service.ts";
|
|
22
|
-
import { getChildByRecord } from "../session-runner.ts";
|
|
22
|
+
import { getChildByRecord } from "../engine/engines/pi/session-runner.ts";
|
|
23
23
|
import { SubprocessAgentRunner } from "../subprocess-agent-runner.ts";
|
|
24
24
|
import type { SubagentService } from "../subagent-service.ts";
|
|
25
25
|
import type { ExecuteOptions } from "../types.ts";
|
|
@@ -31,7 +31,10 @@ interface FakeEngineCalls {
|
|
|
31
31
|
runs: Array<{ taskSpec: unknown; ctx: RunContext }>;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
/** fake zcode 引擎的池 key 缺省值(机制跟随性用例:任意 key 落对应目录)。 */
|
|
35
|
+
const FAKE_POOL_KEY = "home-test-provider-m1";
|
|
36
|
+
|
|
37
|
+
function makeFakeZcodeEngine(probeOk: boolean, poolKey: string = FAKE_POOL_KEY): { engine: EnginePort; calls: FakeEngineCalls } {
|
|
35
38
|
const calls: FakeEngineCalls = { probed: 0, runs: [] };
|
|
36
39
|
const engine: EnginePort = {
|
|
37
40
|
id: "zcode",
|
|
@@ -46,6 +49,7 @@ function makeFakeZcodeEngine(probeOk: boolean): { engine: EnginePort; calls: Fak
|
|
|
46
49
|
resume: "cold",
|
|
47
50
|
interrupt: "kill-only",
|
|
48
51
|
permissionMode: "native",
|
|
52
|
+
maxTurns: false,
|
|
49
53
|
}),
|
|
50
54
|
probe: () => {
|
|
51
55
|
calls.probed++;
|
|
@@ -62,11 +66,11 @@ function makeFakeZcodeEngine(probeOk: boolean): { engine: EnginePort; calls: Fak
|
|
|
62
66
|
run: (taskSpec, ctx) => {
|
|
63
67
|
calls.runs.push({ taskSpec, ctx });
|
|
64
68
|
// 对齐点③模拟:prepare 期声明池 key → 事件 emit(zcode coarse 形态:终态后合成)
|
|
65
|
-
ctx.onPoolResolved?.(
|
|
69
|
+
ctx.onPoolResolved?.(poolKey);
|
|
66
70
|
ctx.onEvent?.({ type: "message_end", usage: { input: 1, output: 1, cacheRead: 0, cacheWrite: 0 } });
|
|
67
71
|
ctx.onEvent?.({ type: "turn_end" });
|
|
68
72
|
return Promise.resolve({
|
|
69
|
-
handle: { data: { v: 1, engineId: "zcode", sessionRef: {}, poolKey
|
|
73
|
+
handle: { data: { v: 1, engineId: "zcode", sessionRef: {}, poolKey, adapterVersion: "t" } },
|
|
70
74
|
outcome: { engineId: "zcode", content: "from-zcode" },
|
|
71
75
|
});
|
|
72
76
|
},
|
|
@@ -84,7 +88,10 @@ function makeMockPiService() {
|
|
|
84
88
|
executeOpts.push(opts);
|
|
85
89
|
return { content: "from-pi", durationMs: 1, toolCalls: [] };
|
|
86
90
|
});
|
|
87
|
-
|
|
91
|
+
// [D4 聚合连带] SAR 构造器经 asEngineService 显式视图取 PiEngineService——fake 的
|
|
92
|
+
// face 即自身,getter 直接返回 self。
|
|
93
|
+
const service = { executeAndAwait } as unknown as SubagentService & { asEngineService: unknown };
|
|
94
|
+
(service as { asEngineService: unknown }).asEngineService = service;
|
|
88
95
|
return { service, executeOpts, executeAndAwait };
|
|
89
96
|
}
|
|
90
97
|
|
|
@@ -134,7 +141,7 @@ afterEach(() => {
|
|
|
134
141
|
if (prevDataDirEnv === undefined) delete process.env["XYZ_AGENT_DATA_DIR"];
|
|
135
142
|
else process.env["XYZ_AGENT_DATA_DIR"] = prevDataDirEnv;
|
|
136
143
|
clearEngines();
|
|
137
|
-
fs.rmSync(tmpRoot, { recursive: true, force: true });
|
|
144
|
+
fs.rmSync(tmpRoot, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
|
|
138
145
|
});
|
|
139
146
|
|
|
140
147
|
describe("SAR 路由集成(P4 验收 1/2/3)", () => {
|
|
@@ -163,13 +170,31 @@ describe("SAR 路由集成(P4 验收 1/2/3)", () => {
|
|
|
163
170
|
expect(result.content).toBe("from-zcode");
|
|
164
171
|
expect(calls.runs).toHaveLength(1);
|
|
165
172
|
expect(pi.executeAndAwait).not.toHaveBeenCalled();
|
|
166
|
-
//
|
|
167
|
-
|
|
173
|
+
// 机制跟随性断言:journal 落在引擎声明的池 key 目录(任意 key 落对应目录——
|
|
174
|
+
// 真实 zcode 引擎 poolKey 恒 'shared',对齐真实行为的断言见下一用例)
|
|
175
|
+
const poolDir = path.join(tmpRoot, "engine-data", "engines", "zcode", FAKE_POOL_KEY);
|
|
168
176
|
const journals = fs.existsSync(poolDir) ? fs.readdirSync(poolDir) : [];
|
|
169
177
|
expect(journals).toHaveLength(1);
|
|
170
178
|
expect(journals[0]).toMatch(/^journal-sa-.+\.jsonl$/);
|
|
171
|
-
|
|
172
|
-
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it("journal 落盘对齐真实行为:poolKey 'shared' → engines/zcode/shared/journal-<taskId>.jsonl", async () => {
|
|
182
|
+
// 生产 zcode 引擎 poolKey 恒 'shared'(ZCODE_SHARED_POOL_KEY)——fake 以同 key
|
|
183
|
+
// 声明,断言 journal 精确落 shared 池目录(旧池化时代「shared 目录不存在」的
|
|
184
|
+
// 反向锚定已随池化删除,此处锚定现行正向语义)
|
|
185
|
+
const agentRef = writeAgentMd("reviewer", "name: reviewer\ndescription: d\nengine: zcode");
|
|
186
|
+
installModelService();
|
|
187
|
+
const { engine, calls } = makeFakeZcodeEngine(true, "shared");
|
|
188
|
+
registerEngine("zcode", () => engine);
|
|
189
|
+
const pi = makeMockPiService();
|
|
190
|
+
const sar = new SubprocessAgentRunner({ subagentService: pi.service });
|
|
191
|
+
|
|
192
|
+
await sar.run(makeOpts({ agent: agentRef }), new AbortController().signal);
|
|
193
|
+
|
|
194
|
+
const taskId = calls.runs[0]?.ctx.taskId;
|
|
195
|
+
expect(taskId).toMatch(/^sa-/);
|
|
196
|
+
const sharedPoolDir = path.join(tmpRoot, "engine-data", "engines", "zcode", "shared");
|
|
197
|
+
expect(fs.readdirSync(sharedPoolDir)).toEqual([`journal-${taskId}.jsonl`]);
|
|
173
198
|
});
|
|
174
199
|
|
|
175
200
|
it("调用参数 engine 覆盖 frontmatter(三层优先级落到 run,A7)", async () => {
|
|
@@ -307,4 +332,55 @@ describe("SAR 路由集成(P4 验收 1/2/3)", () => {
|
|
|
307
332
|
await new Promise<void>((resolve) => child.once("close", () => resolve()));
|
|
308
333
|
expect(getChildByRecord(ctx.taskId)).toBeUndefined();
|
|
309
334
|
});
|
|
335
|
+
|
|
336
|
+
// ── [D3-④] SAR 路径预检(capabilities 驱动;唯一有意行为变化 = zcode+worktree)──
|
|
337
|
+
|
|
338
|
+
it("[D3-④] zcode + worktree:true → engine_capability_unsupported(workflow 域漏拦缺口修复),无 engine.run、无 journal 产物", async () => {
|
|
339
|
+
const agentRef = writeAgentMd("reviewer", "name: reviewer\ndescription: d\nengine: zcode");
|
|
340
|
+
installModelService();
|
|
341
|
+
const { engine, calls } = makeFakeZcodeEngine(true);
|
|
342
|
+
registerEngine("zcode", () => engine);
|
|
343
|
+
const pi = makeMockPiService();
|
|
344
|
+
const sar = new SubprocessAgentRunner({ subagentService: pi.service });
|
|
345
|
+
|
|
346
|
+
const result = await sar.run(makeOpts({ agent: agentRef, worktree: true }), new AbortController().signal);
|
|
347
|
+
|
|
348
|
+
expect(result.error).toContain("engine_capability_unsupported");
|
|
349
|
+
expect(result.error).toContain("worktree");
|
|
350
|
+
// 无进程创建 + 无 journal 落盘(拒绝在 wiring/run 之前)
|
|
351
|
+
expect(calls.runs).toHaveLength(0);
|
|
352
|
+
expect(pi.executeAndAwait).not.toHaveBeenCalled();
|
|
353
|
+
const enginesRoot = path.join(tmpRoot, "engine-data", "engines");
|
|
354
|
+
expect(fs.existsSync(enginesRoot) ? fs.readdirSync(enginesRoot) : []).toEqual([]);
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
it("[D3-④] zcode + maxTurns / fork → engine_capability_unsupported(现状行为保持的正向守护)", async () => {
|
|
358
|
+
const agentRef = writeAgentMd("reviewer", "name: reviewer\ndescription: d\nengine: zcode");
|
|
359
|
+
installModelService();
|
|
360
|
+
const { engine, calls } = makeFakeZcodeEngine(true);
|
|
361
|
+
registerEngine("zcode", () => engine);
|
|
362
|
+
const pi = makeMockPiService();
|
|
363
|
+
const sar = new SubprocessAgentRunner({ subagentService: pi.service });
|
|
364
|
+
|
|
365
|
+
const maxTurnsResult = await sar.run(makeOpts({ agent: agentRef, maxTurns: 5 }), new AbortController().signal);
|
|
366
|
+
expect(maxTurnsResult.error).toContain("engine_capability_unsupported");
|
|
367
|
+
expect(maxTurnsResult.error).toContain("maxTurns");
|
|
368
|
+
expect(maxTurnsResult.error).toContain("capabilities.maxTurns = false");
|
|
369
|
+
|
|
370
|
+
const forkResult = await sar.run(makeOpts({ agent: agentRef, fork: true }), new AbortController().signal);
|
|
371
|
+
expect(forkResult.error).toContain("engine_capability_unsupported");
|
|
372
|
+
expect(forkResult.error).toContain("fork");
|
|
373
|
+
expect(calls.runs).toHaveLength(0);
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
it("[V4⑤ 反向] pi + maxTurns → 直通不拦(pi 既有合法能力零回归),executeAndAwait 收到 maxTurns", async () => {
|
|
377
|
+
installModelService();
|
|
378
|
+
const pi = makeMockPiService();
|
|
379
|
+
const sar = new SubprocessAgentRunner({ subagentService: pi.service });
|
|
380
|
+
|
|
381
|
+
const result = await sar.run(makeOpts({ maxTurns: 3 }), new AbortController().signal);
|
|
382
|
+
|
|
383
|
+
expect(result.content).toBe("from-pi");
|
|
384
|
+
expect(pi.executeOpts[0]?.maxTurns).toBe(3);
|
|
385
|
+
});
|
|
310
386
|
});
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// src/execution/__tests__/subprocess-agent-runner-timeout.test.ts
|
|
2
|
+
//
|
|
3
|
+
// [D6 合流迁移] mergeTimeoutSignal(D-A9:per-call timeoutMs 合并进 AbortSignal)的
|
|
4
|
+
// 行为测试——原定义在已删除的 execution/execute-options-mapper.ts(测试随迁),函数
|
|
5
|
+
// 现居 subprocess-agent-runner.ts(唯一消费点,运行期件随消费方落位)。
|
|
6
|
+
// 原用例编号(execute-options-mapper.test.ts 的 mergeTimeoutSignal describe,7 用例)
|
|
7
|
+
// 与行为语义逐条保持。
|
|
8
|
+
//
|
|
9
|
+
// 接线测试(timeoutMs → engine 收到 merged signal → abort 收口)在
|
|
10
|
+
// subprocess-agent-runner.test.ts 的 T3.6(经真实 PiEngine 链路),本文件锁纯函数行为。
|
|
11
|
+
|
|
12
|
+
import { describe, expect, it, vi } from "vitest";
|
|
13
|
+
|
|
14
|
+
import { mergeTimeoutSignal } from "../subprocess-agent-runner.ts";
|
|
15
|
+
|
|
16
|
+
describe("mergeTimeoutSignal (D-A9)", () => {
|
|
17
|
+
it("T3.6 timeoutMs===undefined → 原样返回 external signal", () => {
|
|
18
|
+
const ctrl = new AbortController();
|
|
19
|
+
const result = mergeTimeoutSignal(ctrl.signal, undefined);
|
|
20
|
+
expect(result).toBe(ctrl.signal);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("T3.6 timeoutMs<=0 → 原样返回 external signal", () => {
|
|
24
|
+
const ctrl = new AbortController();
|
|
25
|
+
const result = mergeTimeoutSignal(ctrl.signal, 0);
|
|
26
|
+
expect(result).toBe(ctrl.signal);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("T3.6 timeoutMs>0 → 返回新 signal(合并外部+超时两路)", () => {
|
|
30
|
+
const ctrl = new AbortController();
|
|
31
|
+
const result = mergeTimeoutSignal(ctrl.signal, 50);
|
|
32
|
+
expect(result).not.toBe(ctrl.signal);
|
|
33
|
+
expect(result.aborted).toBe(false);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("T3.6 timeoutMs 到期 → merged signal abort", () => {
|
|
37
|
+
vi.useFakeTimers();
|
|
38
|
+
const ctrl = new AbortController();
|
|
39
|
+
const merged = mergeTimeoutSignal(ctrl.signal, 50);
|
|
40
|
+
|
|
41
|
+
expect(merged.aborted).toBe(false);
|
|
42
|
+
vi.advanceTimersByTime(51);
|
|
43
|
+
expect(merged.aborted).toBe(true);
|
|
44
|
+
vi.useRealTimers();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("T3.6 外部 signal abort → merged signal abort", () => {
|
|
48
|
+
const ctrl = new AbortController();
|
|
49
|
+
const merged = mergeTimeoutSignal(ctrl.signal, 5000);
|
|
50
|
+
ctrl.abort();
|
|
51
|
+
expect(merged.aborted).toBe(true);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it("T3.6 外部 signal 已 abort → 返回已 abort 的 signal", () => {
|
|
55
|
+
const ctrl = new AbortController();
|
|
56
|
+
ctrl.abort();
|
|
57
|
+
const merged = mergeTimeoutSignal(ctrl.signal, 5000);
|
|
58
|
+
expect(merged.aborted).toBe(true);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("T3.17 NFR: merged signal abort → timeout timer 清理", () => {
|
|
62
|
+
vi.useFakeTimers();
|
|
63
|
+
const ctrl = new AbortController();
|
|
64
|
+
const merged = mergeTimeoutSignal(ctrl.signal, 50);
|
|
65
|
+
|
|
66
|
+
ctrl.abort(); // 外部 abort → merged 也 abort
|
|
67
|
+
expect(merged.aborted).toBe(true);
|
|
68
|
+
|
|
69
|
+
// 推进时间,不应再有副作用
|
|
70
|
+
vi.advanceTimersByTime(100);
|
|
71
|
+
// timer 应被清理(通过 abort event listener)
|
|
72
|
+
// 无异常 = timer 已正确清理
|
|
73
|
+
vi.useRealTimers();
|
|
74
|
+
});
|
|
75
|
+
});
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
// T3.7 (正常): onEvent 桥接 AgentEvent 透传
|
|
12
12
|
// T3.17 (NFR): mergeTimeoutSignal listener 清理
|
|
13
13
|
// T3.18 (NFR): dispose 兜底覆盖(delegate 后子进程进 spawnedChildren)
|
|
14
|
-
// T3.19 (NFR): AgentCallOpts→ExecuteOptions
|
|
14
|
+
// T3.19 (NFR): AgentCallOpts→ExecuteOptions 直出保真(D6 合流后映射在 PiEngine 边界,
|
|
15
|
+
// 本组用例经真实 PiEngine 链路锁定 spawn 参数形态)
|
|
15
16
|
|
|
16
17
|
import { mkdtempSync, readdirSync, rmSync } from "node:fs";
|
|
17
18
|
import { tmpdir } from "node:os";
|
|
@@ -26,9 +27,10 @@ import { configureCore, resetCoreForTests } from "../../core/host-services.ts";
|
|
|
26
27
|
|
|
27
28
|
import type { AgentCallOpts, AgentResult } from "../../orchestration/models/types.ts";
|
|
28
29
|
import { ModelConfigService, setModelConfigService } from "../model-config-service.ts";
|
|
29
|
-
import type { ModelRegistryLike } from "../model-resolver.ts";
|
|
30
|
+
import type { ModelInfo, ModelRegistryLike } from "../model-resolver.ts";
|
|
30
31
|
import { replayJournal } from "../engine/common/event-journal.ts";
|
|
31
32
|
import type { SubprocessAgentRunnerDeps } from "../subprocess-agent-runner.ts";
|
|
33
|
+
import type { SubagentService } from "../subagent-service.ts";
|
|
32
34
|
import { SubprocessAgentRunner } from "../subprocess-agent-runner.ts";
|
|
33
35
|
|
|
34
36
|
// ── 测试辅助 ──
|
|
@@ -46,17 +48,17 @@ function makeMockResult(overrides: Partial<AgentResult> = {}): AgentResult {
|
|
|
46
48
|
};
|
|
47
49
|
}
|
|
48
50
|
|
|
49
|
-
/** 创建 mock SubagentService(只实现 executeAndAwait
|
|
50
|
-
|
|
51
|
+
/** 创建 mock SubagentService(只实现 executeAndAwait)。
|
|
52
|
+
* [D4 聚合连带] SAR 构造器经 asEngineService 显式视图取 PiEngineService——fake 的
|
|
53
|
+
* face 即自身,getter 直接返回 self。 */
|
|
54
|
+
function createMockService(impl?: typeof vi.fn): SubagentService {
|
|
51
55
|
const executeAndAwait = impl ?? vi.fn().mockResolvedValue(makeMockResult());
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
) => Promise<AgentResult>;
|
|
59
|
-
};
|
|
56
|
+
// partial mock(仅 executeAndAwait + asEngineService self-引用)——SAR 测试路径
|
|
57
|
+
// 不触达其余成员,经 unknown 双跳收敛到 SubagentService 视图
|
|
58
|
+
const partial: { executeAndAwait: typeof executeAndAwait; asEngineService?: unknown } = { executeAndAwait };
|
|
59
|
+
const service = partial as unknown as SubagentService;
|
|
60
|
+
partial.asEngineService = service;
|
|
61
|
+
return service;
|
|
60
62
|
}
|
|
61
63
|
|
|
62
64
|
function makeBaseOpts(): AgentCallOpts {
|
|
@@ -171,7 +173,7 @@ describe("SubprocessAgentRunner (wave-4 delegate)", () => {
|
|
|
171
173
|
return Promise.resolve(makeMockResult());
|
|
172
174
|
}),
|
|
173
175
|
);
|
|
174
|
-
const ctxModel = { id: "ctx-model", provider: "test",
|
|
176
|
+
const ctxModel: ModelInfo = { id: "ctx-model", name: "Ctx Model", provider: "test", reasoning: false };
|
|
175
177
|
const deps: SubprocessAgentRunnerDeps = { subagentService: mockService, ctxModel };
|
|
176
178
|
const sar = new SubprocessAgentRunner(deps);
|
|
177
179
|
|
|
@@ -189,7 +191,7 @@ describe("SubprocessAgentRunner (wave-4 delegate)", () => {
|
|
|
189
191
|
return Promise.resolve(makeMockResult());
|
|
190
192
|
}),
|
|
191
193
|
);
|
|
192
|
-
const ctxModel = { id: "ctx-model", provider: "test",
|
|
194
|
+
const ctxModel: ModelInfo = { id: "ctx-model", name: "Ctx Model", provider: "test", reasoning: false };
|
|
193
195
|
const deps: SubprocessAgentRunnerDeps = { subagentService: mockService, ctxModel };
|
|
194
196
|
const sar = new SubprocessAgentRunner(deps);
|
|
195
197
|
|
|
@@ -225,7 +227,7 @@ describe("SubprocessAgentRunner (wave-4 delegate)", () => {
|
|
|
225
227
|
const svc = new ModelConfigService({ agentDir: join(tmpRoot, "agent"), cwd: tmpRoot });
|
|
226
228
|
svc.initModel({ modelRegistry: { getAvailable: () => [], find: () => undefined, hasConfiguredAuth: () => false }, sessionId: "cleanup" });
|
|
227
229
|
setModelConfigService(svc);
|
|
228
|
-
rmSync(tmpRoot, { recursive: true, force: true });
|
|
230
|
+
rmSync(tmpRoot, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
|
|
229
231
|
tmpRoot = "";
|
|
230
232
|
}
|
|
231
233
|
if (prevDataDir === undefined) delete process.env["XYZ_AGENT_DATA_DIR"];
|
|
@@ -305,8 +307,8 @@ describe("SubprocessAgentRunner (wave-4 delegate)", () => {
|
|
|
305
307
|
return Promise.resolve(makeMockResult());
|
|
306
308
|
}),
|
|
307
309
|
);
|
|
308
|
-
const oldModel = { id: "old-model", provider: "test",
|
|
309
|
-
const newModel = { id: "new-model", provider: "test",
|
|
310
|
+
const oldModel: ModelInfo = { id: "old-model", name: "Old Model", provider: "test", reasoning: false };
|
|
311
|
+
const newModel: ModelInfo = { id: "new-model", name: "New Model", provider: "test", reasoning: false };
|
|
310
312
|
const deps: SubprocessAgentRunnerDeps = { subagentService: mockService, ctxModel: oldModel };
|
|
311
313
|
const sar = new SubprocessAgentRunner(deps);
|
|
312
314
|
|
|
@@ -453,7 +455,7 @@ describe("SubprocessAgentRunner (wave-4 delegate)", () => {
|
|
|
453
455
|
} finally {
|
|
454
456
|
if (prevEnv === undefined) delete process.env.XYZ_AGENT_DATA_DIR;
|
|
455
457
|
else process.env.XYZ_AGENT_DATA_DIR = prevEnv;
|
|
456
|
-
rmSync(dataDir, { recursive: true, force: true });
|
|
458
|
+
rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
|
|
457
459
|
}
|
|
458
460
|
});
|
|
459
461
|
});
|
|
@@ -491,8 +493,8 @@ describe("SubprocessAgentRunner (wave-4 delegate)", () => {
|
|
|
491
493
|
// ────────────────────────────────────────────────
|
|
492
494
|
// T3.19: AgentCallOpts → ExecuteOptions 映射保真
|
|
493
495
|
// ────────────────────────────────────────────────
|
|
494
|
-
describe("T3.19
|
|
495
|
-
it("prompt → task, agent → agent, schemaEnv
|
|
496
|
+
describe("T3.19 直出保真(D6:映射点在 PiEngine.agentCallToExecuteOptions,SAR 直传零映射)", () => {
|
|
497
|
+
it("prompt → task, agent → agent, schemaEnv 透传(经 pi 边界直出)", async () => {
|
|
496
498
|
let capturedOpts: Record<string, unknown> | undefined;
|
|
497
499
|
const mockService = createMockService(
|
|
498
500
|
vi.fn().mockImplementation((opts: Record<string, unknown>) => {
|
|
@@ -4,7 +4,7 @@ import * as path from "node:path";
|
|
|
4
4
|
|
|
5
5
|
import { describe, expect, it } from "vitest";
|
|
6
6
|
|
|
7
|
-
import { cleanupTempPrompt, writePromptToTempFile } from "../temp-prompt.ts";
|
|
7
|
+
import { cleanupTempPrompt, writePromptToTempFile } from "../engine/engines/pi/temp-prompt.ts";
|
|
8
8
|
|
|
9
9
|
describe("writePromptToTempFile", () => {
|
|
10
10
|
it("创建临时目录 + 写入 prompt 文件", async () => {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// timeoutMs / signal abort → child.kill 端到端路径测试。
|
|
4
4
|
//
|
|
5
5
|
// 背景:session-runner.ts 无独立 timeoutMs 字段——超时机制是 watchdog(基于
|
|
6
|
-
//
|
|
6
|
+
// maxTurnsToWatchdogMs(opts.maxTurns) 动态计算的下限 30min timer,兜底 SIGTERM);
|
|
7
7
|
// 外部取消通过 opts.signal (AbortSignal) 传播:onAbort → child.kill("SIGTERM")。
|
|
8
8
|
// 故「timeout 端到端路径」实际是 watchdog timer + signal abort → child.kill 两条链路。
|
|
9
9
|
//
|
|
@@ -89,7 +89,7 @@ vi.mock("../alive-store.ts", () => ({
|
|
|
89
89
|
writeAliveMarker: vi.fn(),
|
|
90
90
|
}));
|
|
91
91
|
|
|
92
|
-
vi.mock("../temp-prompt.ts", () => ({
|
|
92
|
+
vi.mock("../engine/engines/pi/temp-prompt.ts", () => ({
|
|
93
93
|
writePromptToTempFile: vi.fn(async (agent: string) => {
|
|
94
94
|
const safeName = agent.replace(/[^\w.-]+/g, "_");
|
|
95
95
|
return { dir: `/tmp/fake-${safeName}`, filePath: `/tmp/fake-${safeName}/prompt-${safeName}.md` };
|
|
@@ -102,13 +102,13 @@ import * as fs from "node:fs";
|
|
|
102
102
|
|
|
103
103
|
import { createRecord } from "../execution-record.ts";
|
|
104
104
|
import {
|
|
105
|
-
|
|
105
|
+
maxTurnsToWatchdogMs,
|
|
106
106
|
type RunOptions,
|
|
107
107
|
resolveSpawnWatchdogMs,
|
|
108
108
|
runSpawn,
|
|
109
109
|
SPAWN_WATCHDOG_ENV,
|
|
110
110
|
type SessionRunnerContext,
|
|
111
|
-
} from "../session-runner.ts";
|
|
111
|
+
} from "../engine/engines/pi/session-runner.ts";
|
|
112
112
|
|
|
113
113
|
const mockSpawn = vi.mocked(spawn);
|
|
114
114
|
const mockExistsSync = vi.mocked(fs.existsSync);
|
|
@@ -160,8 +160,9 @@ function makeRecord() {
|
|
|
160
160
|
return createRecord("run-1", {
|
|
161
161
|
agent: "general-purpose",
|
|
162
162
|
model: "test-model",
|
|
163
|
-
mode: "
|
|
163
|
+
mode: "background",
|
|
164
164
|
task: "do something",
|
|
165
|
+
slug: "test",
|
|
165
166
|
startedAt: 1_000_000,
|
|
166
167
|
rootSessionId: "root-session",
|
|
167
168
|
parentRecordId: undefined,
|
|
@@ -270,8 +271,8 @@ describe("timeoutMs / signal abort → child.kill 端到端路径", () => {
|
|
|
270
271
|
|
|
271
272
|
// ── 1. watchdog 到期 → child.kill ──
|
|
272
273
|
//
|
|
273
|
-
// [R1] watchdog = setTimeout(() => child.kill("SIGTERM"),
|
|
274
|
-
//
|
|
274
|
+
// [R1] watchdog = setTimeout(() => child.kill("SIGTERM"), maxTurnsToWatchdogMs(maxTurns))。
|
|
275
|
+
// maxTurnsToWatchdogMs 下限 30min(SPAWN_WATCHDOG_FLOOR_MS),maxTurns=6 → max(30min, 30min)=30min。
|
|
275
276
|
// 子进程卡死(turn_end 永不触发)时 limiter 失效,watchdog 兜底 kill 防资源泄漏。
|
|
276
277
|
describe("watchdog 到期 → signal abort → child.kill", () => {
|
|
277
278
|
beforeEach(() => {
|
|
@@ -282,9 +283,9 @@ describe("timeoutMs / signal abort → child.kill 端到端路径", () => {
|
|
|
282
283
|
vi.useRealTimers();
|
|
283
284
|
});
|
|
284
285
|
|
|
285
|
-
it("watchdog 到期(超过
|
|
286
|
+
it("watchdog 到期(超过 maxTurnsToWatchdogMs 阈值)→ child.kill(SIGTERM) 被调用", async () => {
|
|
286
287
|
const record = makeRecord();
|
|
287
|
-
// maxTurns=6 →
|
|
288
|
+
// maxTurns=6 → maxTurnsToWatchdogMs = max(30min, 6*5min) = 30min
|
|
288
289
|
// 不 await:runSpawn 内部 await 子进程 close,watchdog kill 后还需 emit close 才 resolve
|
|
289
290
|
const promise = runSpawn(record, "Task: hang", makeOpts({ maxTurns: 6 }), makeCtx());
|
|
290
291
|
|
|
@@ -351,8 +352,8 @@ describe("timeoutMs / signal abort → child.kill 端到端路径", () => {
|
|
|
351
352
|
expect(child.killSignal).toBe("SIGTERM");
|
|
352
353
|
|
|
353
354
|
// 子进程响应 SIGTERM 退出:exitCode 143(SIGTERM 终止形态)+ exit + close。
|
|
354
|
-
// exit 事件触发升级 timer clear
|
|
355
|
-
child.exitCode = 143;
|
|
355
|
+
// exit 事件触发升级 timer clear(公共 kill-chain 的 exit 等待 promise settle → timer clear)。
|
|
356
|
+
(child as unknown as { exitCode: number }).exitCode = 143;
|
|
356
357
|
child.emit("exit", 143);
|
|
357
358
|
child.stdout.end();
|
|
358
359
|
child.emit("close", 143);
|
|
@@ -396,7 +397,7 @@ describe("timeoutMs / signal abort → child.kill 端到端路径", () => {
|
|
|
396
397
|
expect(resolveSpawnWatchdogMs(0)).toBeUndefined();
|
|
397
398
|
expect(resolveSpawnWatchdogMs(-5)).toBeUndefined();
|
|
398
399
|
// maxTurns 有效(>0)→ turns 估算优先于 env 兑底
|
|
399
|
-
expect(resolveSpawnWatchdogMs(6)).toBe(
|
|
400
|
+
expect(resolveSpawnWatchdogMs(6)).toBe(maxTurnsToWatchdogMs(6));
|
|
400
401
|
vi.stubEnv(SPAWN_WATCHDOG_ENV, "abc");
|
|
401
402
|
expect(resolveSpawnWatchdogMs(undefined)).toBeUndefined();
|
|
402
403
|
vi.stubEnv(SPAWN_WATCHDOG_ENV, "-1");
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import { describe, expect, it, vi } from "vitest";
|
|
7
7
|
|
|
8
|
-
import { createTurnLimiter } from "../turn-limiter.ts";
|
|
8
|
+
import { createTurnLimiter } from "../engine/engines/pi/turn-limiter.ts";
|
|
9
9
|
|
|
10
10
|
describe("SP-9: turn-limiter chatMode semantics (maxTurns reset per round)", () => {
|
|
11
11
|
describe("TC-1: chatMode 多轮后 maxTurns 每轮 reset(不累计)", () => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/__tests__/turn-limiter.test.ts
|
|
2
2
|
import { describe, expect, it, vi } from "vitest";
|
|
3
3
|
|
|
4
|
-
import { createTurnLimiter } from "../turn-limiter.ts";
|
|
4
|
+
import { createTurnLimiter } from "../engine/engines/pi/turn-limiter.ts";
|
|
5
5
|
|
|
6
6
|
describe("createTurnLimiter", () => {
|
|
7
7
|
it("does nothing before maxTurns", () => {
|
|
@@ -9,7 +9,10 @@
|
|
|
9
9
|
// realHandler 路由:channel 命中 → channelHandler(经 coerceUiResponse 形变);未命中 → defaultDialogForward(dialog 转发结果,fire-and-forget 转发 ctx.ui.* 后回 ack,未知 method warn + ack)。
|
|
10
10
|
// 测接口契约,不测实现细节。
|
|
11
11
|
|
|
12
|
-
import type { ExtensionContext,
|
|
12
|
+
import type { ExtensionContext, ExtensionUIContext } from "@earendil-works/pi-coding-agent";
|
|
13
|
+
|
|
14
|
+
// ExtensionMode 未从 pi 包根 re-export(实装 0.84.4 核对),从权威 ExtensionContext 派生
|
|
15
|
+
type ExtensionMode = ExtensionContext["mode"];
|
|
13
16
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
14
17
|
|
|
15
18
|
const { loggerMock } = vi.hoisted(() => ({
|
|
@@ -23,7 +26,7 @@ vi.mock("../../core/logger.ts", () => ({
|
|
|
23
26
|
getLogger: () => loggerMock,
|
|
24
27
|
}));
|
|
25
28
|
|
|
26
|
-
import { DialogGlobalQueue, type UiRequest } from "../dialog-queue.ts";
|
|
29
|
+
import { DEFAULT_DIALOG_TIMEOUT_MS, DialogGlobalQueue, type UiRequest } from "../dialog-queue.ts";
|
|
27
30
|
import { type ChannelHandler,createUiChannelRegistry } from "../ui-channels.ts";
|
|
28
31
|
import { createUiRequestHandlerForMode } from "../ui-request-handler-factory.ts";
|
|
29
32
|
|
|
@@ -39,14 +42,17 @@ function makeCtx(mode: ExtensionMode): ExtensionContext {
|
|
|
39
42
|
},
|
|
40
43
|
modelRegistry: undefined,
|
|
41
44
|
model: undefined,
|
|
42
|
-
} as ExtensionContext;
|
|
45
|
+
} as unknown as ExtensionContext;
|
|
43
46
|
}
|
|
44
47
|
|
|
45
48
|
/** 带 mock ctx.ui 的 ExtensionContext(GUI fire-and-forget 转发测试用)。
|
|
46
49
|
* dialog method(select/confirm/input/editor)返回 undefined/true/"" 兜底,
|
|
47
50
|
* fire-and-forget method(notify/setStatus/setWidget/setTitle/setEditorText)是 void spy。 */
|
|
48
|
-
|
|
49
|
-
|
|
51
|
+
// ui 成员 = 真实签名 & vi.fn 能力(映射交叉):调用点走真实签名,mock 打点方法可达
|
|
52
|
+
type MockedUi = { [K in keyof ExtensionUIContext]: ExtensionUIContext[K] & ReturnType<typeof vi.fn> };
|
|
53
|
+
|
|
54
|
+
function makeCtxWithUi(mode: ExtensionMode = "rpc"): Omit<ExtensionContext, "ui"> & { ui: MockedUi } {
|
|
55
|
+
const ui = {
|
|
50
56
|
select: vi.fn(async () => undefined),
|
|
51
57
|
confirm: vi.fn(async () => true),
|
|
52
58
|
input: vi.fn(async () => ""),
|
|
@@ -67,8 +73,8 @@ function makeCtxWithUi(mode: ExtensionMode = "rpc"): ExtensionContext & { ui: Re
|
|
|
67
73
|
},
|
|
68
74
|
modelRegistry: undefined,
|
|
69
75
|
model: undefined,
|
|
70
|
-
ui,
|
|
71
|
-
} as unknown as ExtensionContext & { ui:
|
|
76
|
+
ui: ui as unknown as MockedUi,
|
|
77
|
+
} as unknown as Omit<ExtensionContext, "ui"> & { ui: MockedUi };
|
|
72
78
|
}
|
|
73
79
|
|
|
74
80
|
function dialogReq(id: string, channel?: string): UiRequest {
|
|
@@ -367,3 +373,97 @@ describe("createUiRequestHandlerForMode — TUI 零回归", () => {
|
|
|
367
373
|
}
|
|
368
374
|
});
|
|
369
375
|
});
|
|
376
|
+
|
|
377
|
+
// ── LC-3/T2⑦:dialog timeout 协同(SDK 层超时先到 / 队列级上界兜底,settle 恰一次)──
|
|
378
|
+
|
|
379
|
+
describe("createUiRequestHandlerForMode — dialog timeout 协同(LC-3/T2⑦)", () => {
|
|
380
|
+
it("请求方传 timeout → select/confirm/input 透传 SDK 第三参 {timeout};未传不加第三参(参数个数不变)", async () => {
|
|
381
|
+
const ctx = makeCtxWithUi();
|
|
382
|
+
const handler = createUiRequestHandlerForMode(ctx, createUiChannelRegistry(), new DialogGlobalQueue())!;
|
|
383
|
+
|
|
384
|
+
await handler({ method: "select", id: "t1", title: "Choose", options: ["a"], timeout: 1234 });
|
|
385
|
+
expect(ctx.ui.select).toHaveBeenCalledWith("Choose", ["a"], { timeout: 1234 });
|
|
386
|
+
|
|
387
|
+
await handler({ method: "confirm", id: "t2", title: "Sure?", message: "Go?", timeout: 456 });
|
|
388
|
+
expect(ctx.ui.confirm).toHaveBeenCalledWith("Sure?", "Go?", { timeout: 456 });
|
|
389
|
+
|
|
390
|
+
await handler({ method: "input", id: "t3", title: "In", placeholder: "p", timeout: 78 });
|
|
391
|
+
expect(ctx.ui.input).toHaveBeenCalledWith("In", "p", { timeout: 78 });
|
|
392
|
+
|
|
393
|
+
// 未传 timeout:不加第三参(调用面严格 additive,与既有 (e) 零回归断言同形态)
|
|
394
|
+
await handler({ method: "input", id: "t4", title: "In2", placeholder: "p2" });
|
|
395
|
+
expect(ctx.ui.input).toHaveBeenCalledWith("In2", "p2");
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
it("全链路:req.timeout 经 L2 队列按传值超时 settle(host ctx.ui promise 挂死形态)", async () => {
|
|
399
|
+
const ctx = makeCtxWithUi();
|
|
400
|
+
// host UI promise 挂死:SDK 自身永不返回,唯一回收通道是队列级上界
|
|
401
|
+
ctx.ui.select.mockReturnValue(new Promise(() => {}));
|
|
402
|
+
const handler = createUiRequestHandlerForMode(ctx, createUiChannelRegistry(), new DialogGlobalQueue())!;
|
|
403
|
+
|
|
404
|
+
const p = handler({ method: "select", id: "t1", title: "q", options: ["a"], timeout: 1234 });
|
|
405
|
+
|
|
406
|
+
await vi.advanceTimersByTimeAsync(1233);
|
|
407
|
+
let settled = false;
|
|
408
|
+
void p.then(() => {
|
|
409
|
+
settled = true;
|
|
410
|
+
});
|
|
411
|
+
await vi.advanceTimersByTimeAsync(0);
|
|
412
|
+
expect(settled).toBe(false);
|
|
413
|
+
|
|
414
|
+
await vi.advanceTimersByTimeAsync(1);
|
|
415
|
+
await expect(p).resolves.toEqual({ cancelled: true });
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
it("未传 timeout → 队列级默认上界(30min)兜底 settle,SDK opts 不出现", async () => {
|
|
419
|
+
const ctx = makeCtxWithUi();
|
|
420
|
+
ctx.ui.select.mockReturnValue(new Promise(() => {}));
|
|
421
|
+
const handler = createUiRequestHandlerForMode(ctx, createUiChannelRegistry(), new DialogGlobalQueue())!;
|
|
422
|
+
|
|
423
|
+
const p = handler({ method: "select", id: "t1", title: "q", options: ["a"] });
|
|
424
|
+
expect(ctx.ui.select).toHaveBeenCalledWith("q", ["a"]);
|
|
425
|
+
|
|
426
|
+
await vi.advanceTimersByTimeAsync(DEFAULT_DIALOG_TIMEOUT_MS);
|
|
427
|
+
await expect(p).resolves.toEqual({ cancelled: true });
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
it("竞态恰一次:SDK 层超时先到(auto-dismiss)→ handler 先 settle,队列级 timer 兜底不二 settle", async () => {
|
|
431
|
+
const ctx = makeCtxWithUi();
|
|
432
|
+
// SDK timeout 生效形态:500ms 后 auto-dismiss(resolve undefined = 取消)
|
|
433
|
+
ctx.ui.select.mockImplementation(
|
|
434
|
+
() => new Promise<string | undefined>((resolve) => setTimeout(() => resolve(undefined), 500)),
|
|
435
|
+
);
|
|
436
|
+
const handler = createUiRequestHandlerForMode(ctx, createUiChannelRegistry(), new DialogGlobalQueue())!;
|
|
437
|
+
|
|
438
|
+
const p = handler({ method: "select", id: "t1", title: "q", options: ["a"], timeout: 1000 });
|
|
439
|
+
|
|
440
|
+
// SDK 先到(500ms):handler settle,此时队列级 timer(1000ms)尚未触发
|
|
441
|
+
await vi.advanceTimersByTimeAsync(500);
|
|
442
|
+
await expect(p).resolves.toEqual({ cancelled: true });
|
|
443
|
+
|
|
444
|
+
// 越过队列级超时点:timer 已随 handler 完成清除,无第二次 settle、无队列超时日志
|
|
445
|
+
await vi.advanceTimersByTimeAsync(2000);
|
|
446
|
+
await expect(p).resolves.toEqual({ cancelled: true });
|
|
447
|
+
expect(loggerMock.warn).not.toHaveBeenCalled();
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
// [A2-3] 非法 timeout 与队列层判定对齐:不透传 SDK 第三参(语义反转的 opts
|
|
451
|
+
// (<=0 可能立即 auto-dismiss)不进 SDK),由队列层默认上界兜底 settle。
|
|
452
|
+
it.each([-1, 0, Number.NaN])(
|
|
453
|
+
"timeout 非法(%p)→ SDK 不收第三参(参数个数 2),队列层按默认上界 settle(A2-3)",
|
|
454
|
+
async (badTimeout) => {
|
|
455
|
+
const ctx = makeCtxWithUi();
|
|
456
|
+
ctx.ui.select.mockReturnValue(new Promise(() => {})); // host UI 挂死,暴露队列层兜底
|
|
457
|
+
const handler = createUiRequestHandlerForMode(ctx, createUiChannelRegistry(), new DialogGlobalQueue())!;
|
|
458
|
+
|
|
459
|
+
const p = handler({ method: "select", id: "t1", title: "q", options: ["a"], timeout: badTimeout });
|
|
460
|
+
// 第三参不出现:toHaveBeenCalledWith 逐参精确匹配,两参断言即锁死参数个数为 2
|
|
461
|
+
expect(ctx.ui.select).toHaveBeenCalledWith("q", ["a"]);
|
|
462
|
+
expect(ctx.ui.select).toHaveBeenCalledTimes(1);
|
|
463
|
+
|
|
464
|
+
// 队列层把非法值回落默认上界(30min):到点 settle cancelled
|
|
465
|
+
await vi.advanceTimersByTimeAsync(DEFAULT_DIALOG_TIMEOUT_MS);
|
|
466
|
+
await expect(p).resolves.toEqual({ cancelled: true });
|
|
467
|
+
},
|
|
468
|
+
);
|
|
469
|
+
});
|
|
@@ -18,8 +18,8 @@ import { PassThrough } from "node:stream";
|
|
|
18
18
|
|
|
19
19
|
import { describe, expect, it, vi } from "vitest";
|
|
20
20
|
|
|
21
|
-
import { ASK_USER_RPC_PROMPT } from "../session-runner.ts";
|
|
22
|
-
import { parseSpawnLine } from "../spawn-event-adapter.ts";
|
|
21
|
+
import { ASK_USER_RPC_PROMPT } from "../engine/engines/pi/session-runner.ts";
|
|
22
|
+
import { parseSpawnLine } from "../engine/engines/pi/spawn-event-adapter.ts";
|
|
23
23
|
import { parseChannel } from "../ui-channels.ts";
|
|
24
24
|
import { createUiRequestQueue, type UiRequest, type UiRequestHandler } from "../ui-request-queue.ts";
|
|
25
25
|
|
|
@@ -69,7 +69,8 @@ describe("parseSpawnLine — ask_user 请求解析(Pi 原生格式)", () =>
|
|
|
69
69
|
it("request.title === ASK_USER_MARKER(NUL 前缀 marker 原样保留,由 parseChannel 提取)", () => {
|
|
70
70
|
const result = parseSpawnLine(askUserLine("ui-req-001"));
|
|
71
71
|
if (result?.kind !== "extension_ui_request") return;
|
|
72
|
-
|
|
72
|
+
if (result.request.method !== "select") return expect.fail("request.method 应为 select");
|
|
73
|
+
expect((result.request as { title?: string }).title).toBe(ASK_USER_MARKER);
|
|
73
74
|
});
|
|
74
75
|
|
|
75
76
|
it("id 被正确提取(用于 response 关联)", () => {
|