@zhushanwen/subagent-core 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-4KN4TTG7.js → chunk-43ONBFZX.js} +1 -1
- package/dist/{chunk-X7SZ5HLQ.js → chunk-V3VHZ2VX.js} +20 -27
- package/dist/execution/engine/engines/zcode/constants.cjs +29 -41
- package/dist/execution/engine/engines/zcode/constants.d.cts +65 -53
- package/dist/execution/engine/engines/zcode/constants.d.ts +65 -53
- package/dist/execution/engine/engines/zcode/constants.js +17 -27
- 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 +2 -2
- package/dist/index.cjs +17100 -14082
- package/dist/index.d.cts +5336 -4033
- package/dist/index.d.ts +5336 -4033
- package/dist/index.js +17020 -14055
- package/dist/{types-DpUO16pj.d.cts → types-C3fE3R9x.d.cts} +280 -112
- package/dist/{types-DpUO16pj.d.ts → types-C3fE3R9x.d.ts} +280 -112
- package/dist.bundle/index.cjs +34933 -0
- package/package.json +3 -3
- 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 +4 -2
- package/src/__tests__/review-fix-loop-utils.test.ts +10 -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/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 +4 -4
- 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 +2 -2
- package/src/execution/__tests__/alive-store.test.ts +1 -1
- package/src/execution/__tests__/ask-user-transit-e2e.test.ts +6 -6
- package/src/execution/__tests__/chat-engine-routing.test.ts +68 -33
- package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +4 -4
- package/src/execution/__tests__/cold-resurrect.test.ts +283 -0
- package/src/execution/__tests__/collect-budget.test.ts +291 -0
- package/src/execution/__tests__/collect-coordinator-service.test.ts +327 -0
- package/src/execution/__tests__/collect-coordinator.test.ts +371 -0
- package/src/execution/__tests__/collect-mixed-dispatch.test.ts +262 -0
- package/src/execution/__tests__/config-collect-sync.test.ts +120 -0
- package/src/execution/__tests__/config.test.ts +1 -1
- package/src/execution/__tests__/delivery-methods.test.ts +75 -62
- package/src/execution/__tests__/descendant-sweep-guards.test.ts +220 -0
- package/src/execution/__tests__/descendant-sweep.test.ts +6 -6
- package/src/execution/__tests__/dialog-queue.test.ts +2 -2
- package/src/execution/__tests__/engine-model-validation.test.ts +741 -0
- package/src/execution/__tests__/epipe-fallback.test.ts +29 -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 +5 -5
- package/src/execution/__tests__/explicit-agent-ref-guard.test.ts +4 -4
- package/src/execution/__tests__/finalize-record.test.ts +173 -17
- package/src/execution/__tests__/finalized-marker.test.ts +1 -1
- package/src/execution/__tests__/gc-timer.test.ts +56 -3
- package/src/execution/__tests__/get-record-for-action-restart.test.ts +12 -12
- package/src/execution/__tests__/get-state-handshake.test.ts +1 -1
- 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 +50 -148
- package/src/execution/__tests__/kill-all-escalation.test.ts +2 -2
- 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 +1 -1
- package/src/execution/__tests__/max-turns-to-watchdog-ms.test.ts +1 -1
- 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-batch.test.ts +500 -0
- package/src/execution/__tests__/notify-ledger.test.ts +1000 -18
- package/src/execution/__tests__/output-collector.test.ts +117 -6
- package/src/execution/__tests__/pi-invocation.test.ts +36 -4
- package/src/execution/__tests__/record-entry-collect.test.ts +102 -0
- package/src/execution/__tests__/record-store.test.ts +10 -9
- 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__/relay-env.test.ts +12 -1
- 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 +15 -9
- package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +4 -4
- package/src/execution/__tests__/run-spawn-edges.test.ts +17 -15
- package/src/execution/__tests__/run-spawn-integration.test.ts +2 -2
- 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 +4 -4
- package/src/execution/__tests__/service-kill-escalation.test.ts +7 -5
- package/src/execution/__tests__/session-context-resolver.test.ts +0 -2
- package/src/execution/__tests__/session-file-gc.test.ts +36 -1
- package/src/execution/__tests__/session-pending.test.ts +257 -14
- package/src/execution/__tests__/session-reconstructor.test.ts +366 -15
- package/src/execution/__tests__/session-runner-branch-cache-lru.test.ts +1 -1
- package/src/execution/__tests__/session-runner-close-prune.test.ts +2 -2
- package/src/execution/__tests__/session-runner-dispatch.test.ts +489 -0
- package/src/execution/__tests__/session-runner-epipe.test.ts +3 -3
- package/src/execution/__tests__/session-runner-heartbeat-idle-fallback.test.ts +5 -4
- 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 +282 -47
- 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 +3 -3
- package/src/execution/__tests__/spawn-worktree-guidance.test.ts +5 -4
- package/src/execution/__tests__/spawned-children.test.ts +2 -1
- package/src/execution/__tests__/start-collect-guard.test.ts +255 -0
- package/src/execution/__tests__/start-sync-model-guard.test.ts +5 -5
- 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 +48 -22
- package/src/execution/__tests__/subagent-service-message-close.test.ts +29 -26
- package/src/execution/__tests__/subagent-service-multiproc-guard.test.ts +21 -8
- package/src/execution/__tests__/subagent-service-notify-gate.test.ts +27 -22
- package/src/execution/__tests__/subagent-service-parent-guard.test.ts +30 -29
- package/src/execution/__tests__/subagent-service-recovery-bounds.test.ts +45 -20
- 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__/sync-collect-recovery.test.ts +1117 -0
- package/src/execution/__tests__/temp-prompt.test.ts +1 -1
- package/src/execution/__tests__/timeout-integration.test.ts +6 -5
- package/src/execution/__tests__/tombstone-store.test.ts +1 -1
- 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 +12 -6
- package/src/execution/__tests__/ui-request-handler.test.ts +4 -3
- package/src/execution/__tests__/ui-request-queue.test.ts +142 -2
- package/src/execution/__tests__/worktree-git-ops.test.ts +1 -1
- 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 +2 -2
- package/src/execution/__tests__/worktree-reconcile.integration.test.ts +1 -1
- package/src/execution/__tests__/worktree-registry.test.ts +1 -1
- package/src/execution/agent-registry.ts +74 -30
- package/src/execution/agent-result-mapper.ts +3 -0
- package/src/execution/cold-resurrect.ts +199 -0
- package/src/execution/collect-coordinator.ts +200 -0
- package/src/execution/config.ts +77 -5
- 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/event-journal.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 +213 -53
- 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 +22 -112
- package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +15 -28
- package/src/execution/engine/__tests__/conformance/contract.read-degradation.test.ts +1 -1
- package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +12 -12
- package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +2 -2
- package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +21 -82
- package/src/execution/engine/__tests__/conformance/zcode-appserver-harness.ts +4 -7
- 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 +4 -2
- 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/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} +1 -1
- 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/{session-runner.ts → engine/engines/pi/session-runner.ts} +617 -412
- 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 +54 -27
- package/src/execution/engine/engines/zcode/__tests__/appserver-launcher.test.ts +321 -0
- package/src/execution/engine/engines/zcode/__tests__/connection.test.ts +13 -12
- 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 +20 -8
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-appserver.test.ts +77 -110
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-degrade.test.ts +26 -320
- 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 +48 -148
- package/src/execution/engine/engines/zcode/appserver-launcher.ts +167 -0
- package/src/execution/engine/engines/zcode/connection.ts +24 -11
- package/src/execution/engine/engines/zcode/constants.ts +75 -71
- package/src/execution/engine/engines/zcode/golden-sample.ts +8 -46
- package/src/execution/engine/engines/zcode/parser.ts +12 -346
- package/src/execution/engine/engines/zcode/preparer.ts +12 -143
- package/src/execution/engine/engines/zcode/session-channel.ts +351 -39
- package/src/execution/engine/engines/zcode/zcode-engine.ts +665 -760
- 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 +24 -6
- package/src/execution/engine/routing.ts +75 -1
- package/src/execution/engine/types.ts +30 -103
- package/src/execution/execution-record.ts +229 -144
- package/src/execution/finalize-record.ts +141 -99
- package/src/execution/idle-gc.ts +28 -0
- package/src/execution/lifecycle-predicates.ts +1 -1
- package/src/execution/notifier.ts +234 -25
- package/src/execution/notify-host.ts +232 -0
- package/src/execution/record-entry.ts +16 -0
- package/src/execution/record-store.ts +280 -103
- package/src/execution/round-settlement.ts +93 -0
- package/src/execution/session-file-gc.ts +96 -62
- package/src/execution/session-reconstructor.ts +256 -143
- package/src/execution/sessions-index.ts +117 -47
- package/src/execution/settled-watchdog.ts +264 -52
- package/src/execution/subagent-actions-core.ts +84 -28
- package/src/execution/subagent-service.ts +1225 -964
- package/src/execution/subprocess-agent-runner.ts +144 -97
- package/src/execution/sync-rebuild.ts +87 -0
- package/src/execution/types.ts +72 -0
- package/src/execution/ui-request-handler-factory.ts +102 -74
- package/src/execution/ui-request-queue.ts +50 -19
- package/src/index.ts +442 -316
- package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +1 -1
- package/src/orchestration/__tests__/agent-call-stream.test.ts +2 -2
- package/src/orchestration/__tests__/args-validator.test.ts +14 -0
- package/src/orchestration/__tests__/config-loader.test.ts +1 -1
- package/src/orchestration/__tests__/error-recovery-rebuild-failure.test.ts +1 -1
- package/src/orchestration/__tests__/error-recovery-terminal-hardening.test.ts +11 -9
- package/src/orchestration/__tests__/execute-agent-call.test.ts +151 -11
- package/src/orchestration/__tests__/file-run-store-prune.test.ts +1 -1
- package/src/orchestration/__tests__/file-run-store-throttle.test.ts +1 -1
- package/src/orchestration/__tests__/file-run-store.test.ts +7 -6
- package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +2 -2
- package/src/orchestration/__tests__/lifecycle-abort-broadcast-signal.test.ts +1 -1
- package/src/orchestration/__tests__/lifecycle-runid-injection.test.ts +3 -3
- package/src/orchestration/__tests__/lifecycle.test.ts +7 -5
- package/src/orchestration/__tests__/non-cloneable-return-e2e.test.ts +1 -1
- package/src/orchestration/__tests__/review-fix-loop-scriptpath-failfast.test.ts +1 -1
- package/src/orchestration/__tests__/run-snapshot.test.ts +8 -5
- package/src/orchestration/__tests__/script-generate.test.ts +5 -5
- package/src/orchestration/__tests__/script-lint.test.ts +17 -0
- package/src/orchestration/__tests__/skill-discovery.test.ts +2 -2
- 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} +27 -19
- 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 +1 -1
- package/src/orchestration/__tests__/worker-script-builder.test.ts +1 -1
- package/src/orchestration/__tests__/workflow-files.test.ts +10 -10
- package/src/orchestration/__tests__/workflow-nesting-e2e.test.ts +1 -1
- package/src/orchestration/__tests__/workflow-script-registry-impl.test.ts +1 -1
- package/src/orchestration/agent-opts-resolver.ts +1 -1
- package/src/orchestration/args-validator.ts +53 -31
- package/src/orchestration/execute-agent-call.ts +19 -73
- package/src/orchestration/launcher.ts +128 -81
- package/src/orchestration/lifecycle.ts +43 -45
- package/src/orchestration/models/ports.ts +4 -4
- package/src/orchestration/models/run-runtime.ts +2 -2
- package/src/orchestration/models/trace.ts +1 -1
- package/src/orchestration/models/types.ts +111 -22
- package/src/orchestration/models/workflow-run.ts +1 -1
- package/src/orchestration/script-lint.ts +91 -58
- package/src/orchestration/{error-recovery.ts → worker-message-pump.ts} +157 -150
- package/src/shared/__tests__/atomic-write.test.ts +1 -1
- package/src/shared/__tests__/meta-parser.test.ts +151 -0
- package/src/shared/__tests__/resource-discovery-host-roots.test.ts +5 -5
- package/src/shared/__tests__/resource-discovery.test.ts +258 -215
- package/src/shared/atomic-write.ts +12 -9
- package/src/shared/meta-parser.ts +158 -84
- package/src/shared/model-ref.ts +15 -2
- package/src/shared/resource-discovery.ts +9 -183
- package/src/shared/schema-jsonify.ts +1 -1
- package/workflows/review-fix-loop-utils.cjs +151 -89
- package/workflows/review-fix-loop-utils.d.cts +287 -0
- 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__/preparer-appserver.test.ts +0 -387
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine.test.ts +0 -710
- package/src/execution/engine/engines/zcode/appserver-home.ts +0 -442
- package/src/execution/engine/engines/zcode/appserver-probe.ts +0 -141
- package/src/execution/engine/engines/zcode/launcher.ts +0 -161
- package/src/execution/execute-options-mapper.ts +0 -115
- package/src/shared/__tests__/resource-discovery-manifest-cache.test.ts +0 -288
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
// src/execution/engine/engines/pi/__tests__/pi-engine.test.ts
|
|
2
2
|
//
|
|
3
|
-
// PiEngine
|
|
4
|
-
|
|
5
|
-
//
|
|
3
|
+
// PiEngine 引擎边界测试(D2 后形态):capabilities 链路接通口径(D3)、run 双分支
|
|
4
|
+
//(chat ticket 交接 / workflow executeAndAwait 委托)与中立声明→ExecuteOptions 映射、
|
|
5
|
+
// interact message 原生协议(stdin 直写 + 冷路径续轮回调;D2 协议知识下沉)、close/cancel
|
|
6
|
+
// 直通、read 三级降级、probe 形状(C1)。fake PiEngineService 注入,不 spawn 真进程。
|
|
6
7
|
|
|
7
8
|
import * as fs from "node:fs";
|
|
8
9
|
import * as os from "node:os";
|
|
9
10
|
import * as path from "node:path";
|
|
10
11
|
|
|
12
|
+
import type { ChildProcess } from "node:child_process";
|
|
13
|
+
import { PassThrough } from "node:stream";
|
|
14
|
+
|
|
11
15
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
12
16
|
|
|
13
17
|
import { createRecord } from "../../../../execution-record.ts";
|
|
@@ -15,11 +19,15 @@ import type { ExecuteOptions, SubagentRecord } from "../../../../types.ts";
|
|
|
15
19
|
import { IDENTITY_CUSTOM_TYPE } from "../../../../session-reconstructor.ts";
|
|
16
20
|
import { SubagentStream } from "../../../../stream-sink.ts";
|
|
17
21
|
import type { RunContext } from "../../../port.ts";
|
|
18
|
-
import type {
|
|
22
|
+
import type { AgentEvent, EngineHandle } from "../../../types.ts";
|
|
23
|
+
import type { AgentCallOpts } from "../../../../../orchestration/models/types.ts";
|
|
24
|
+
import { spawnedChildren } from "../session-runner.ts";
|
|
25
|
+
import { resetAllEpipeFailures } from "../stdin-writer.ts";
|
|
19
26
|
import {
|
|
20
27
|
PI_ADAPTER_VERSION,
|
|
21
28
|
PI_ENGINE_ID,
|
|
22
29
|
PiEngine,
|
|
30
|
+
type ChatRoundTicket,
|
|
23
31
|
type PiEngineService,
|
|
24
32
|
} from "../pi-engine.ts";
|
|
25
33
|
|
|
@@ -28,12 +36,13 @@ import {
|
|
|
28
36
|
interface ServiceCalls {
|
|
29
37
|
executeOpts?: ExecuteOptions;
|
|
30
38
|
signal?: AbortSignal;
|
|
31
|
-
onEvent?: (event:
|
|
39
|
+
onEvent?: (event: AgentEvent) => void;
|
|
32
40
|
stream?: unknown;
|
|
33
|
-
|
|
41
|
+
resumeChatRound?: { recordId: string; text: string };
|
|
34
42
|
close?: { recordId: string; force: boolean };
|
|
35
43
|
cancelId?: string;
|
|
36
44
|
getRecordId?: string;
|
|
45
|
+
reportedTransitionIds?: string[];
|
|
37
46
|
}
|
|
38
47
|
|
|
39
48
|
/** 构造最小完整 SubagentRecord(collectRecords 返回项——resolveRecordId 只读 id/sessionFile)。 */
|
|
@@ -66,9 +75,9 @@ function makeFakeService(overrides?: {
|
|
|
66
75
|
recordsById?: Map<string, ReturnType<typeof createRecord>>;
|
|
67
76
|
listed?: Array<{ id: string; sessionFile?: string }>;
|
|
68
77
|
cancelResult?: boolean;
|
|
69
|
-
|
|
78
|
+
resumeReject?: Error;
|
|
70
79
|
}): { service: PiEngineService; calls: ServiceCalls } {
|
|
71
|
-
const calls: ServiceCalls = {};
|
|
80
|
+
const calls: ServiceCalls = { reportedTransitionIds: [] };
|
|
72
81
|
const record = createRecord("sa-fake", {
|
|
73
82
|
agent: "reviewer",
|
|
74
83
|
model: "p/m",
|
|
@@ -106,9 +115,12 @@ function makeFakeService(overrides?: {
|
|
|
106
115
|
}
|
|
107
116
|
return record;
|
|
108
117
|
},
|
|
109
|
-
|
|
110
|
-
calls.
|
|
111
|
-
if (overrides?.
|
|
118
|
+
resumeChatRound: (rec, text) => {
|
|
119
|
+
calls.resumeChatRound = { recordId: rec.id, text };
|
|
120
|
+
if (overrides?.resumeReject) throw overrides.resumeReject;
|
|
121
|
+
},
|
|
122
|
+
reportRecordTransition: (rec) => {
|
|
123
|
+
calls.reportedTransitionIds?.push(rec.id);
|
|
112
124
|
},
|
|
113
125
|
closeSubagent: async (rec, force) => {
|
|
114
126
|
calls.close = { recordId: rec.id, force };
|
|
@@ -123,15 +135,16 @@ function makeFakeService(overrides?: {
|
|
|
123
135
|
return { service, calls };
|
|
124
136
|
}
|
|
125
137
|
|
|
126
|
-
/**
|
|
127
|
-
function makeSpec():
|
|
138
|
+
/** 全字段任务声明(D6 合流形状 AgentCallOpts,覆盖全部直出映射点)。 */
|
|
139
|
+
function makeSpec(): AgentCallOpts {
|
|
128
140
|
return {
|
|
129
|
-
|
|
130
|
-
|
|
141
|
+
prompt: "do the thing",
|
|
142
|
+
description: "do-thing",
|
|
131
143
|
agent: "reviewer",
|
|
132
144
|
model: "zai-coding-cn/glm-5.2",
|
|
133
|
-
|
|
134
|
-
|
|
145
|
+
thinkingLevel: "high",
|
|
146
|
+
skillPath: "/skills/r/SKILL.md",
|
|
147
|
+
appendSystemPrompt: ["extra"],
|
|
135
148
|
schema: { type: "object", properties: { ok: { type: "boolean" } } },
|
|
136
149
|
maxTurns: 5,
|
|
137
150
|
graceTurns: 2,
|
|
@@ -168,6 +181,7 @@ describe("PiEngine.capabilities(D3 链路接通口径)", () => {
|
|
|
168
181
|
resume: "native", // 同进程 idle 复用 + --session 冷续写
|
|
169
182
|
interrupt: "kill-only", // 现链路 abort = SIGTERM,rpc abort 未接通
|
|
170
183
|
permissionMode: "native", // argv-mirror 镜像主进程 flag
|
|
184
|
+
maxTurns: true, // [D3-④] turn limiter 兑现
|
|
171
185
|
});
|
|
172
186
|
});
|
|
173
187
|
});
|
|
@@ -175,7 +189,7 @@ describe("PiEngine.capabilities(D3 链路接通口径)", () => {
|
|
|
175
189
|
// ── run ──
|
|
176
190
|
|
|
177
191
|
describe("PiEngine.run", () => {
|
|
178
|
-
it("
|
|
192
|
+
it("[D6 一次直出] 合流声明 AgentCallOpts → ExecuteOptions + signal/onEvent/stream/ctxModel 直通(行为零变化)", async () => {
|
|
179
193
|
const { service, calls } = makeFakeService();
|
|
180
194
|
const engine = new PiEngine({ getService: () => service });
|
|
181
195
|
const spec = makeSpec();
|
|
@@ -239,35 +253,167 @@ describe("PiEngine.run", () => {
|
|
|
239
253
|
executeResult: { content: "x", sessionFile: "/tmp/s.jsonl", sessionId: "sess-1", toolCalls: [] },
|
|
240
254
|
});
|
|
241
255
|
const engine = new PiEngine({ getService: () => service });
|
|
242
|
-
const r1 = await engine.run({
|
|
256
|
+
const r1 = await engine.run({ prompt: "t" }, makeRunCtx({ poolKey: "agent-reviewer" }));
|
|
243
257
|
expect(r1.handle.data.sessionRef).toEqual({ sessionFile: "/tmp/s.jsonl" });
|
|
244
258
|
expect(r1.handle.data.poolKey).toBe("agent-reviewer");
|
|
245
259
|
expect(r1.outcome.sessionId).toBe("sess-1");
|
|
246
|
-
const r2 = await engine.run({
|
|
260
|
+
const r2 = await engine.run({ prompt: "t" }, makeRunCtx({ poolKey: "" }));
|
|
247
261
|
expect(r2.handle.data.poolKey).toBe("shared");
|
|
248
262
|
});
|
|
249
263
|
|
|
264
|
+
it("[D2 chat 分支] ctx.taskId 命中交接包 → runChatRound 执行 + handle/outcome 形态(chat 编排不消费,形态完备)", async () => {
|
|
265
|
+
const ticketCalls: string[] = [];
|
|
266
|
+
const record = createRecord("sa-chat-ticket", {
|
|
267
|
+
agent: "reviewer", model: "p/m", thinkingLevel: "high", mode: "background",
|
|
268
|
+
task: "t", slug: "s", startedAt: 1, controller: new AbortController(),
|
|
269
|
+
});
|
|
270
|
+
const chatTicket: ChatRoundTicket = {
|
|
271
|
+
record,
|
|
272
|
+
opts: { task: "chat task", slug: "s" },
|
|
273
|
+
identity: { agent: "reviewer", agentConfig: undefined, resolved: { model: { id: "m", name: "M", provider: "p", reasoning: false }, thinkingLevel: "high" } },
|
|
274
|
+
ctx: { cwd: "/w" } as ChatRoundTicket["ctx"],
|
|
275
|
+
signal: undefined,
|
|
276
|
+
priority: 1000,
|
|
277
|
+
};
|
|
278
|
+
const service: PiEngineService = {
|
|
279
|
+
executeAndAwait: async () => { throw new Error("workflow branch must not run"); },
|
|
280
|
+
getRecordForAction: () => { throw new Error("unused"); },
|
|
281
|
+
closeSubagent: async () => {},
|
|
282
|
+
cancel: () => true,
|
|
283
|
+
collectRecords: () => [],
|
|
284
|
+
takeChatRound: (taskId) => {
|
|
285
|
+
ticketCalls.push(taskId);
|
|
286
|
+
return taskId === "sa-chat-ticket" ? chatTicket : undefined;
|
|
287
|
+
},
|
|
288
|
+
runChatRound: async (t) => ({
|
|
289
|
+
text: "chat done", turns: 2, durationMs: 7, success: true,
|
|
290
|
+
sessionId: t.record.id, toolCalls: [],
|
|
291
|
+
}),
|
|
292
|
+
};
|
|
293
|
+
const engine = new PiEngine({ getService: () => service });
|
|
294
|
+
const { handle, outcome } = await engine.run({ prompt: "t" }, makeRunCtx({ taskId: "sa-chat-ticket" }));
|
|
295
|
+
expect(ticketCalls).toEqual(["sa-chat-ticket"]);
|
|
296
|
+
expect(handle.data.sessionRef).toEqual({ recordId: "sa-chat-ticket" });
|
|
297
|
+
expect(handle.data.poolKey).toBe("shared");
|
|
298
|
+
expect(outcome).toMatchObject({ content: "chat done", engineId: "pi", sessionId: "sa-chat-ticket" });
|
|
299
|
+
// 非 chat taskId(workflow 域)→ 交接 miss → executeAndAwait 分支(此处 throw 证明未误入)
|
|
300
|
+
await expect(engine.run({ prompt: "t" }, makeRunCtx({ taskId: "sa-workflow" }))).rejects.toThrow(
|
|
301
|
+
"workflow branch must not run",
|
|
302
|
+
);
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
it("[D6/u-3b 硬验收] chat pi fork-from 零回归:ticket.opts.forkFromSessionFile 经 run chat 分支 lossless 送达 runChatRound", async () => {
|
|
306
|
+
// 链路(合流前后均不经任务声明):壳 fork-from action → ExecuteOptions.forkFromSessionFile
|
|
307
|
+
// → kickOffChatRound 挂 ticket → 本分支 → runChatRound(ticket) → runAndFinalize →
|
|
308
|
+
// runSpawn(fork-from 源优先于 fork 推导)。本用例锁定合流后 ticket 交接不丢该字段。
|
|
309
|
+
const record = createRecord("sa-forkfrom", {
|
|
310
|
+
agent: "reviewer", model: "p/m", thinkingLevel: "high", mode: "background",
|
|
311
|
+
task: "t", slug: "s", startedAt: 1, controller: new AbortController(),
|
|
312
|
+
});
|
|
313
|
+
const ticketOpts: ExecuteOptions = { task: "continue", slug: "s", forkFromSessionFile: "/sessions/parent.jsonl" };
|
|
314
|
+
const chatTicket: ChatRoundTicket = {
|
|
315
|
+
record,
|
|
316
|
+
opts: ticketOpts,
|
|
317
|
+
identity: { agent: "reviewer", agentConfig: undefined, resolved: { model: { id: "m", name: "M", provider: "p", reasoning: false }, thinkingLevel: "high" } },
|
|
318
|
+
ctx: { cwd: "/w" } as ChatRoundTicket["ctx"],
|
|
319
|
+
signal: undefined,
|
|
320
|
+
priority: 1000,
|
|
321
|
+
};
|
|
322
|
+
let received: ChatRoundTicket | undefined;
|
|
323
|
+
const service: PiEngineService = {
|
|
324
|
+
executeAndAwait: async () => { throw new Error("workflow branch must not run"); },
|
|
325
|
+
getRecordForAction: () => { throw new Error("unused"); },
|
|
326
|
+
closeSubagent: async () => {},
|
|
327
|
+
cancel: () => true,
|
|
328
|
+
collectRecords: () => [],
|
|
329
|
+
takeChatRound: (taskId) => (taskId === "sa-forkfrom" ? chatTicket : undefined),
|
|
330
|
+
runChatRound: async (t) => {
|
|
331
|
+
received = t;
|
|
332
|
+
return { content: "ok", text: "ok", sessionId: "sess-1", turns: 1, durationMs: 1, success: true, toolCalls: [] };
|
|
333
|
+
},
|
|
334
|
+
};
|
|
335
|
+
const engine = new PiEngine({ getService: () => service });
|
|
336
|
+
await engine.run({ prompt: "t" }, makeRunCtx({ taskId: "sa-forkfrom" }));
|
|
337
|
+
// lossless 断言:runChatRound 收到同一 ticket 对象,opts 引用与 forkFromSessionFile 原值逐字节保持
|
|
338
|
+
expect(received).toBe(chatTicket);
|
|
339
|
+
expect(received?.opts).toBe(ticketOpts);
|
|
340
|
+
expect(received?.opts.forkFromSessionFile).toBe("/sessions/parent.jsonl");
|
|
341
|
+
});
|
|
342
|
+
|
|
250
343
|
it("服务不可用(prepare 期)→ reject 且不产生 handle", async () => {
|
|
251
344
|
const engine = new PiEngine({ getService: () => null });
|
|
252
|
-
await expect(engine.run({
|
|
345
|
+
await expect(engine.run({ prompt: "t" }, makeRunCtx())).rejects.toThrow(/SubagentService unavailable/);
|
|
253
346
|
});
|
|
254
347
|
|
|
255
348
|
it("executeAndAwait throw(嵌套超限等创建期异常)→ 向上传播(SAR catch 兜底不变)", async () => {
|
|
256
349
|
const { service } = makeFakeService({ executeReject: new Error("nesting depth exceeded") });
|
|
257
350
|
const engine = new PiEngine({ getService: () => service });
|
|
258
|
-
await expect(engine.run({
|
|
351
|
+
await expect(engine.run({ prompt: "t" }, makeRunCtx())).rejects.toThrow("nesting depth exceeded");
|
|
259
352
|
});
|
|
260
353
|
});
|
|
261
354
|
|
|
262
355
|
// ── interact ──
|
|
263
356
|
|
|
264
|
-
describe("PiEngine.interact(chatMode
|
|
265
|
-
|
|
357
|
+
describe("PiEngine.interact(chatMode 交互面:message 原生协议 + close/cancel 直通)", () => {
|
|
358
|
+
// [D2] message 分支原生实现(PiEngine.deliverPrompt):热路径经真实 session-runner
|
|
359
|
+
// spawnedChildren Map + 真实 stdin-writer(不 mock——端到端验证协议字节)。
|
|
360
|
+
let hotChildren: Map<string, unknown>;
|
|
361
|
+
beforeEach(() => {
|
|
362
|
+
hotChildren = spawnedChildren as unknown as Map<string, unknown>;
|
|
363
|
+
hotChildren.clear();
|
|
364
|
+
});
|
|
365
|
+
afterEach(() => {
|
|
366
|
+
hotChildren.clear();
|
|
367
|
+
resetAllEpipeFailures();
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
function makeHotChild(): { child: ChildProcess; stdin: PassThrough } {
|
|
371
|
+
// exitCode/signalCode 缺省 null([race-F5] 写后死检测的判据,undefined 会被误判已死)
|
|
372
|
+
const stdin = new PassThrough();
|
|
373
|
+
const child = { stdin, pid: 4242, exitCode: null, signalCode: null, killed: false } as unknown as ChildProcess;
|
|
374
|
+
return { child, stdin };
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
function readStdinLines(stdin: PassThrough): Array<Record<string, unknown>> {
|
|
378
|
+
stdin.pause();
|
|
379
|
+
// PassThrough.read() 类型 any——显式标注 string,下游 split/map 参数可推导
|
|
380
|
+
const text: string = stdin.read()?.toString() ?? "";
|
|
381
|
+
return text
|
|
382
|
+
.split("\n")
|
|
383
|
+
.map((l) => l.trim())
|
|
384
|
+
.filter((l) => l.length > 0)
|
|
385
|
+
.map((l) => JSON.parse(l) as Record<string, unknown>);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
it("message 热路径(进程活):sendPromptCommand 直写 stdin,interrupt → streamingBehavior(steer/followUp)+ record 迁移上报", async () => {
|
|
389
|
+
const { service, calls } = makeFakeService();
|
|
390
|
+
const engine = new PiEngine({ getService: () => service });
|
|
391
|
+
const { child, stdin } = makeHotChild();
|
|
392
|
+
hotChildren.set("sa-fake", child);
|
|
393
|
+
|
|
394
|
+
const res = await engine.interact(makeHandle({ recordId: "sa-fake" }), { kind: "message", payload: "next round", interrupt: true });
|
|
395
|
+
expect(res).toEqual({ ok: true, delivered: true });
|
|
396
|
+
|
|
397
|
+
const lines = readStdinLines(stdin);
|
|
398
|
+
expect(lines).toHaveLength(1);
|
|
399
|
+
expect(lines[0]).toMatchObject({ type: "prompt", message: "next round", streamingBehavior: "steer" });
|
|
400
|
+
|
|
401
|
+
// 无 interrupt → followUp;record 迁移经 reportRecordTransition 上报(轮始信号清除后)
|
|
402
|
+
const { stdin: stdin2 } = makeHotChild();
|
|
403
|
+
hotChildren.set("sa-fake", { stdin: stdin2, pid: 4243, exitCode: null, signalCode: null, killed: false } as unknown as ChildProcess);
|
|
404
|
+
await engine.interact(makeHandle({ recordId: "sa-fake" }), { kind: "message", payload: "queued" });
|
|
405
|
+
const lines2 = readStdinLines(stdin2);
|
|
406
|
+
expect(lines2[0]).toMatchObject({ type: "prompt", message: "queued", streamingBehavior: "followUp" });
|
|
407
|
+
expect(calls.reportedTransitionIds).toEqual(["sa-fake", "sa-fake"]);
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
it("message 冷路径(进程死):resumeChatRound 编排回调(重开 session 续聊)", async () => {
|
|
266
411
|
const { service, calls } = makeFakeService();
|
|
267
412
|
const engine = new PiEngine({ getService: () => service });
|
|
268
|
-
|
|
413
|
+
// spawnedChildren 无该 record → getChildByRecord undefined → 冷路径
|
|
414
|
+
const res = await engine.interact(makeHandle({ recordId: "sa-fake" }), { kind: "message", payload: "resume msg" });
|
|
269
415
|
expect(res).toEqual({ ok: true, delivered: true });
|
|
270
|
-
expect(calls.
|
|
416
|
+
expect(calls.resumeChatRound).toEqual({ recordId: "sa-fake", text: "resume msg" });
|
|
271
417
|
});
|
|
272
418
|
|
|
273
419
|
it("close → closeSubagent(record, force);payload 缺省 force=false", async () => {
|
|
@@ -318,7 +464,7 @@ describe("PiEngine.interact(chatMode 交互面直通)", () => {
|
|
|
318
464
|
|
|
319
465
|
it("交互面 throw → engine_interact_failed(message 文案透传行动语言)", async () => {
|
|
320
466
|
const { service } = makeFakeService({
|
|
321
|
-
|
|
467
|
+
resumeReject: new Error("subagent sa-fake is not ready for a new message"),
|
|
322
468
|
});
|
|
323
469
|
const engine = new PiEngine({ getService: () => service });
|
|
324
470
|
const res = await engine.interact(makeHandle({ recordId: "sa-fake" }), { kind: "message", payload: "hi" });
|
|
@@ -346,7 +492,7 @@ describe("PiEngine.read(D6 降级链)", () => {
|
|
|
346
492
|
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-engine-read-"));
|
|
347
493
|
});
|
|
348
494
|
afterEach(() => {
|
|
349
|
-
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
495
|
+
fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
|
|
350
496
|
});
|
|
351
497
|
|
|
352
498
|
it("无 sessionRef → outcome-only(turns 空)", async () => {
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
// src/execution/engine/engines/pi/__tests__/spawn-opts-direct.test.ts
|
|
2
|
+
//
|
|
3
|
+
// [D6 任务形状合流 / 实施期门⑤ ⛔ 硬门产物] pi 边界一次直出映射
|
|
4
|
+
// (agentCallToExecuteOptions:AgentCallOpts → ExecuteOptions)的字段完整性对照表
|
|
5
|
+
// 与逐字段断言。本文件取代已删除的两个往返保真测试:
|
|
6
|
+
// - execution/__tests__/execute-options-mapper.test.ts(mapToExecuteOptions,18 用例)
|
|
7
|
+
// - engines/pi/__tests__/task-spec-mapper.test.ts(spec 往返保真,12 用例)
|
|
8
|
+
//
|
|
9
|
+
// ════════════════════════════════════════════════════════════════════════
|
|
10
|
+
// 字段完整性对照表(从两个被删 mapper 的现有测试提取字段全集,逐字段核对)
|
|
11
|
+
// ════════════════════════════════════════════════════════════════════════
|
|
12
|
+
//
|
|
13
|
+
// 合流前链路(三形态两映射):
|
|
14
|
+
// AgentCallOpts --mapToExecuteOptions--> ExecuteOptions
|
|
15
|
+
// --executeOptionsToTaskSpec--> AgentTaskSpec --taskSpecToExecuteOptions--> ExecuteOptions
|
|
16
|
+
// 合流后(单一形状一次直出):
|
|
17
|
+
// AgentCallOpts --agentCallToExecuteOptions--> ExecuteOptions
|
|
18
|
+
//
|
|
19
|
+
// ┌────────────────────┬──────────────────────────────────────┬────────────────────────────────────┬──────────────┐
|
|
20
|
+
// │ ExecuteOptions 字段 │ 合流前(两级链的合成语义) │ 合流后(一次直出) │ 断言用例 │
|
|
21
|
+
// ├────────────────────┼──────────────────────────────────────┼────────────────────────────────────┼──────────────┤
|
|
22
|
+
// │ task │ prompt→opts.task→spec.task(恒等往返)│ prompt 直取 │ D-01 │
|
|
23
|
+
// │ slug │ description??agent??"workflow-agent" │ 同规则内联(截断 SLUG_MAX_LENGTH=35)│ D-02..D-05 │
|
|
24
|
+
// │ │ 截断(mapToExecuteOptions) │ │ │
|
|
25
|
+
// │ agent │ spec.agent ?? persona.agentRef │ agent 直取(agentRef 无写入方,裁撤) │ D-06 │
|
|
26
|
+
// │ model │ 透传(显式 override,不与 ctxModel 混)│ 同 │ D-07 │
|
|
27
|
+
// │ thinkingLevel │ spec.effort 恒等映射回 │ thinkingLevel 直取(恒等层删除) │ D-08 │
|
|
28
|
+
// │ skillPath │ persona.skillPath 收拢/还原(恒等) │ skillPath 直取(平铺保留) │ D-09 │
|
|
29
|
+
// │ appendSystemPrompt │ persona.appendSystemPrompt 收拢/还原 │ appendSystemPrompt 直取 │ D-10 │
|
|
30
|
+
// │ schema │ 透传 │ 同 │ D-11 │
|
|
31
|
+
// │ schemaEnv │ spec.schema 派生优先(stringifyCached │ schema 派生优先;无 schema 时 │ D-12..D-14 │
|
|
32
|
+
// │ │ compact,与 resolver 同函数同缓存)+ │ schemaEnv 兜底(原 ctx.schemaEnv │ │
|
|
33
|
+
// │ │ ctx.schemaEnv 兜底(源 = opts.schemaEnv)│ 通道的合流等价);均无 → undefined │ │
|
|
34
|
+
// │ maxTurns │ 透传(预算语义:undefined = 不限) │ 同 │ D-15 │
|
|
35
|
+
// │ graceTurns │ 透传(spec 字段) │ 同(合流形状可选字段) │ D-16 │
|
|
36
|
+
// │ ctxModel │ RunContext.ctxModel 回填 │ 第 2 参直取(运行期件,不入声明) │ D-17 │
|
|
37
|
+
// │ fork │ 透传 │ 同 │ D-18 │
|
|
38
|
+
// │ worktree │ 透传(boolean | WorktreeHandle 三态) │ 同 │ D-19 │
|
|
39
|
+
// │ cwd │ 透传 │ 同 │ D-20 │
|
|
40
|
+
// │ conversation │ 透传(interact 控制面 task 标志) │ 同 │ D-21 │
|
|
41
|
+
// │ idleTimeoutMs │ 透传(同上) │ 同 │ D-22 │
|
|
42
|
+
// │ engine/engineFallback│ PiEngine.run 调用方追加(D9① 留痕) │ 同(不在本函数,pi-engine.test 覆盖) │ pi-engine.test│
|
|
43
|
+
// │ signal/onComplete │ 不入 opts(port 设计删字段去向) │ 同(RunContext/编排侧各归其位) │ D-23 │
|
|
44
|
+
// └────────────────────┴──────────────────────────────────────┴────────────────────────────────────┴──────────────┘
|
|
45
|
+
//
|
|
46
|
+
// 调用方扩展字段(引擎不消费,不入 spawn 参数):scene / timeoutMs(SAR mergeTimeoutSignal
|
|
47
|
+
// 合并进 signal)/ skill(resolver 解析为 skillPath)/ engine(SAR 路由层)/ returnMeta
|
|
48
|
+
// (worker 层)——不入本映射即正确(D-24 断言不泄漏)。
|
|
49
|
+
// 已裁撤字段(D6 登记于 AgentCallOpts 类型注释):persona.agentRef、requires。
|
|
50
|
+
//
|
|
51
|
+
// 全字段直出快照断言(D-00)+ 逐字段用例双保险:快照锁全集、用例锁语义边界。
|
|
52
|
+
|
|
53
|
+
import { describe, expect, it } from "vitest";
|
|
54
|
+
|
|
55
|
+
import type { AgentCallOpts } from "../../../../../orchestration/models/types.ts";
|
|
56
|
+
import { SLUG_MAX_LENGTH } from "../../../../../orchestration/models/types.ts";
|
|
57
|
+
import type { ModelInfo } from "../../../../model-resolver.ts";
|
|
58
|
+
import type { ExecuteOptions } from "../../../../types.ts";
|
|
59
|
+
import { agentCallToExecuteOptions } from "../pi-engine.ts";
|
|
60
|
+
|
|
61
|
+
/** 全字段样例(覆盖对照表全部直出映射点)。 */
|
|
62
|
+
function makeFullCall(): AgentCallOpts {
|
|
63
|
+
return {
|
|
64
|
+
prompt: "review the diff",
|
|
65
|
+
description: "review-diff",
|
|
66
|
+
agent: "/agents/reviewer.md",
|
|
67
|
+
model: "zai-coding-cn/glm-5.2",
|
|
68
|
+
thinkingLevel: "high",
|
|
69
|
+
skillPath: "/skills/code-review/SKILL.md",
|
|
70
|
+
appendSystemPrompt: ["extra system prompt line"],
|
|
71
|
+
schema: { type: "object", properties: { verdict: { type: "string" } }, required: ["verdict"] },
|
|
72
|
+
maxTurns: 20,
|
|
73
|
+
graceTurns: 3,
|
|
74
|
+
fork: true,
|
|
75
|
+
worktree: true,
|
|
76
|
+
cwd: "/repo/worktree-x",
|
|
77
|
+
conversation: true,
|
|
78
|
+
idleTimeoutMs: 600_000,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
describe("agentCallToExecuteOptions(D6 一次直出:AgentCallOpts → pi spawn 编排参数)", () => {
|
|
83
|
+
it("D-00 全字段直出快照(与合流前两级链的合成结果逐字段一致——原往返保真测试的直出等价物)", () => {
|
|
84
|
+
const result = agentCallToExecuteOptions(makeFullCall());
|
|
85
|
+
const expected: ExecuteOptions = {
|
|
86
|
+
task: "review the diff",
|
|
87
|
+
slug: "review-diff",
|
|
88
|
+
agent: "/agents/reviewer.md",
|
|
89
|
+
model: "zai-coding-cn/glm-5.2",
|
|
90
|
+
thinkingLevel: "high",
|
|
91
|
+
skillPath: "/skills/code-review/SKILL.md",
|
|
92
|
+
appendSystemPrompt: ["extra system prompt line"],
|
|
93
|
+
schema: { type: "object", properties: { verdict: { type: "string" } }, required: ["verdict"] },
|
|
94
|
+
schemaEnv: JSON.stringify({ type: "object", properties: { verdict: { type: "string" } }, required: ["verdict"] }),
|
|
95
|
+
maxTurns: 20,
|
|
96
|
+
graceTurns: 3,
|
|
97
|
+
ctxModel: undefined,
|
|
98
|
+
fork: true,
|
|
99
|
+
worktree: true,
|
|
100
|
+
cwd: "/repo/worktree-x",
|
|
101
|
+
conversation: true,
|
|
102
|
+
idleTimeoutMs: 600_000,
|
|
103
|
+
};
|
|
104
|
+
expect(result).toEqual(expected);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// ── task / slug(D-01..D-05)──
|
|
108
|
+
|
|
109
|
+
it("D-01 prompt → task", () => {
|
|
110
|
+
expect(agentCallToExecuteOptions({ prompt: "do the thing" }).task).toBe("do the thing");
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it("D-02 description → slug", () => {
|
|
114
|
+
expect(agentCallToExecuteOptions({ prompt: "t", description: "fix-login" }).slug).toBe("fix-login");
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it("D-03 description 缺失 → 回落 agent 名(保证 slug 非空)", () => {
|
|
118
|
+
expect(agentCallToExecuteOptions({ prompt: "t", agent: "worker" }).slug).toBe("worker");
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("D-04 description 与 agent 均缺失 → 回落 'workflow-agent'", () => {
|
|
122
|
+
expect(agentCallToExecuteOptions({ prompt: "t" }).slug).toBe("workflow-agent");
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it("D-05 slug 截断:description > SLUG_MAX_LENGTH(35) 截到 35;= 35 不截(边界)", () => {
|
|
126
|
+
expect(agentCallToExecuteOptions({ prompt: "t", description: "a".repeat(36) }).slug).toBe("a".repeat(35));
|
|
127
|
+
expect(agentCallToExecuteOptions({ prompt: "t", description: "a".repeat(35) }).slug).toBe("a".repeat(35));
|
|
128
|
+
expect(SLUG_MAX_LENGTH).toBe(35);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// ── 身份 / 模型 / 推理档位(D-06..D-08)──
|
|
132
|
+
|
|
133
|
+
it("D-06 agent 直取(原 persona.agentRef 兜底随 PersonaSpec 裁撤——无生产写入方)", () => {
|
|
134
|
+
expect(agentCallToExecuteOptions({ prompt: "t", agent: "/a.md" }).agent).toBe("/a.md");
|
|
135
|
+
expect(agentCallToExecuteOptions({ prompt: "t" }).agent).toBeUndefined();
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it("D-07 model:显式 override 透传;缺省 undefined(不与 ctxModel 混合)", () => {
|
|
139
|
+
const ctxModel: ModelInfo = { id: "ctx-model", name: "Ctx", provider: "test", reasoning: false };
|
|
140
|
+
expect(agentCallToExecuteOptions({ prompt: "t", model: "explicit-model" }, ctxModel).model).toBe("explicit-model");
|
|
141
|
+
expect(agentCallToExecuteOptions({ prompt: "t" }, ctxModel).model).toBeUndefined();
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it("D-08 thinkingLevel 直取(原 effort 恒等映射层删除,含 7 档外的缺省)", () => {
|
|
145
|
+
for (const level of ["off", "low", "medium", "high", "max", undefined]) {
|
|
146
|
+
expect(agentCallToExecuteOptions({ prompt: "t", thinkingLevel: level }).thinkingLevel).toBe(level);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// ── persona 平铺字段(D-09..D-10)──
|
|
151
|
+
|
|
152
|
+
it("D-09 skillPath 直取(原 persona 收拢/还原恒等)", () => {
|
|
153
|
+
expect(agentCallToExecuteOptions({ prompt: "t", skillPath: "/s" }).skillPath).toBe("/s");
|
|
154
|
+
expect(agentCallToExecuteOptions({ prompt: "t" }).skillPath).toBeUndefined();
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it("D-10 appendSystemPrompt 直取(含空数组归一语义:空数组保持空数组——下游 spread no-op 等价)", () => {
|
|
158
|
+
expect(agentCallToExecuteOptions({ prompt: "t", appendSystemPrompt: ["l1", "l2"] }).appendSystemPrompt).toEqual(["l1", "l2"]);
|
|
159
|
+
expect(agentCallToExecuteOptions({ prompt: "t", appendSystemPrompt: [] }).appendSystemPrompt).toEqual([]);
|
|
160
|
+
expect(agentCallToExecuteOptions({ prompt: "t" }).appendSystemPrompt).toBeUndefined();
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// ── schema / schemaEnv(D-11..D-14)──
|
|
164
|
+
|
|
165
|
+
it("D-11 schema 透传为原始对象引用", () => {
|
|
166
|
+
const schema = { type: "object" };
|
|
167
|
+
expect(agentCallToExecuteOptions({ prompt: "t", schema }).schema).toBe(schema);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it("D-12 schemaEnv 派生:与 agent-opts-resolver 同函数(stringifySchemaCached compact),逐字节等值", () => {
|
|
171
|
+
const schema = { type: "object", properties: { a: { type: "number" } } };
|
|
172
|
+
expect(agentCallToExecuteOptions({ prompt: "t", schema }).schemaEnv).toBe(JSON.stringify(schema));
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it("D-13 派生优先:schema 存在时 opts.schemaEnv(stale 值)被忽略", () => {
|
|
176
|
+
const schema = { type: "object" };
|
|
177
|
+
expect(agentCallToExecuteOptions({ prompt: "t", schema, schemaEnv: "STALE" }).schemaEnv).toBe(JSON.stringify(schema));
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it("D-14 schemaEnv 兜底/缺省:无 schema 时用 opts.schemaEnv(解耦形态,原 ctx 兜底通道等价);均无 → undefined(BC-6:childEnv 不注入)", () => {
|
|
181
|
+
expect(agentCallToExecuteOptions({ prompt: "t", schemaEnv: '{"type":"object"}' }).schemaEnv).toBe('{"type":"object"}');
|
|
182
|
+
expect(agentCallToExecuteOptions({ prompt: "t" }).schemaEnv).toBeUndefined();
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
// ── 轮数 / 运行期 / 隔离(D-15..D-20)──
|
|
186
|
+
|
|
187
|
+
it("D-15 maxTurns 透传(undefined = 不限,不挂 turns 估算 watchdog)", () => {
|
|
188
|
+
expect(agentCallToExecuteOptions({ prompt: "t", maxTurns: 20 }).maxTurns).toBe(20);
|
|
189
|
+
expect(agentCallToExecuteOptions({ prompt: "t" }).maxTurns).toBeUndefined();
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it("D-16 graceTurns 透传(合流形状可选字段,chat 域经 host-task-spec 填充)", () => {
|
|
193
|
+
expect(agentCallToExecuteOptions({ prompt: "t", graceTurns: 3 }).graceTurns).toBe(3);
|
|
194
|
+
expect(agentCallToExecuteOptions({ prompt: "t" }).graceTurns).toBeUndefined();
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it("D-17 ctxModel 从第 2 参回填(运行期件不入任务声明——D-008 兼底链路)", () => {
|
|
198
|
+
const ctxModel: ModelInfo = { id: "mimo-v2.5-pro", name: "MiMo", provider: "router-openai", reasoning: false };
|
|
199
|
+
expect(agentCallToExecuteOptions({ prompt: "t" }, ctxModel).ctxModel).toBe(ctxModel);
|
|
200
|
+
expect(agentCallToExecuteOptions({ prompt: "t" }).ctxModel).toBeUndefined();
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it("D-18 fork 透传", () => {
|
|
204
|
+
expect(agentCallToExecuteOptions({ prompt: "t", fork: true }).fork).toBe(true);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it("D-19 worktree 三态(true/false/WorktreeHandle)直出保持", () => {
|
|
208
|
+
const handle = { path: "/wt", branch: "b", baseCommit: "c", mainCwd: "/repo" };
|
|
209
|
+
for (const wt of [true, false, handle] as const) {
|
|
210
|
+
expect(agentCallToExecuteOptions({ prompt: "t", worktree: wt }).worktree).toBe(wt);
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it("D-20 cwd 透传", () => {
|
|
215
|
+
expect(agentCallToExecuteOptions({ prompt: "t", cwd: "/work" }).cwd).toBe("/work");
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
// ── 交互控制面(D-21..D-22)──
|
|
219
|
+
|
|
220
|
+
it("D-21 conversation 透传(interact 控制面的 task 标志)", () => {
|
|
221
|
+
expect(agentCallToExecuteOptions({ prompt: "t", conversation: true }).conversation).toBe(true);
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
it("D-22 idleTimeoutMs 透传", () => {
|
|
225
|
+
expect(agentCallToExecuteOptions({ prompt: "t", idleTimeoutMs: 12345 }).idleTimeoutMs).toBe(12345);
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
// ── 声明边界(D-23..D-24)──
|
|
229
|
+
|
|
230
|
+
it("D-23 运行期字段不入直出产物:signal/onComplete/engine/engineFallback 不由本函数产出(engine 由 run 调用方追加)", () => {
|
|
231
|
+
const result = agentCallToExecuteOptions(makeFullCall()) as unknown as Record<string, unknown>;
|
|
232
|
+
expect("signal" in result).toBe(false);
|
|
233
|
+
expect("onComplete" in result).toBe(false);
|
|
234
|
+
expect("engine" in result).toBe(false);
|
|
235
|
+
expect("engineFallback" in result).toBe(false);
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
it("D-24 调用方扩展字段不泄漏进 spawn 参数:scene/timeoutMs/skill/engine/returnMeta/denyTools/permissionMode", () => {
|
|
239
|
+
const result = agentCallToExecuteOptions({
|
|
240
|
+
prompt: "t",
|
|
241
|
+
scene: "coding",
|
|
242
|
+
timeoutMs: 5000,
|
|
243
|
+
skill: "code-review",
|
|
244
|
+
engine: "pi",
|
|
245
|
+
returnMeta: true,
|
|
246
|
+
denyTools: ["bash"],
|
|
247
|
+
permissionMode: "yolo",
|
|
248
|
+
}) as unknown as Record<string, unknown>;
|
|
249
|
+
expect("scene" in result).toBe(false);
|
|
250
|
+
expect("timeoutMs" in result).toBe(false);
|
|
251
|
+
expect("skill" in result).toBe(false);
|
|
252
|
+
expect("engine" in result).toBe(false);
|
|
253
|
+
expect("returnMeta" in result).toBe(false);
|
|
254
|
+
expect("denyTools" in result).toBe(false);
|
|
255
|
+
expect("permissionMode" in result).toBe(false);
|
|
256
|
+
});
|
|
257
|
+
});
|