@zhushanwen/subagent-core 0.5.1 → 0.7.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/README.md +1 -1
- package/dist/chunk-KXVBIVOU.js +16 -0
- package/dist/chunk-T2SYBW3I.js +24 -0
- package/dist/chunk-VURUAGMM.js +2305 -0
- package/dist/{types-Dv4QhSJ_.d.cts → engine-discovery-scan-ocpM8FmI.d.cts} +835 -668
- package/dist/{types-Dv4QhSJ_.d.ts → engine-discovery-scan-ocpM8FmI.d.ts} +835 -668
- package/dist/execution/engine/engine-discovery-scan.cjs +2210 -0
- package/dist/execution/engine/engine-discovery-scan.d.cts +4 -0
- package/dist/execution/engine/engine-discovery-scan.d.ts +4 -0
- package/dist/execution/engine/engine-discovery-scan.js +20 -0
- package/dist/execution/engine/paths.cjs +6 -23
- package/dist/execution/engine/paths.d.cts +1 -8
- package/dist/execution/engine/paths.d.ts +1 -8
- package/dist/execution/engine/paths.js +1 -1
- package/dist/execution/relay-env.cjs +12 -28
- package/dist/execution/relay-env.d.cts +1 -33
- package/dist/execution/relay-env.d.ts +1 -33
- package/dist/execution/relay-env.js +5 -3
- package/dist/index.cjs +14123 -15467
- package/dist/index.d.cts +1179 -1540
- package/dist/index.d.ts +1179 -1540
- package/dist/index.js +7694 -10986
- package/dist.bundle/index.cjs +33485 -0
- package/package.json +20 -26
- package/src/__tests__/record-store-last-line.test.ts +16 -7
- package/src/core/error-message.ts +7 -6
- package/src/core/host-services.ts +8 -2
- package/src/core/notify-ports.ts +17 -2
- package/src/execution/__tests__/agent-registry.test.ts +1 -1
- package/src/execution/__tests__/alive-store.test.ts +1 -1
- package/src/execution/__tests__/chat-engine-routing.test.ts +62 -28
- package/src/execution/__tests__/chat-round-first-round-watchdog.test.ts +255 -0
- package/src/execution/__tests__/collect-budget.test.ts +291 -0
- package/src/execution/__tests__/collect-coordinator-service.test.ts +316 -0
- package/src/execution/__tests__/collect-coordinator.test.ts +371 -0
- package/src/execution/__tests__/collect-mixed-dispatch.test.ts +229 -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 +179 -237
- package/src/execution/__tests__/execute-and-await-worktree.test.ts +0 -2
- package/src/execution/__tests__/execute-nesting.test.ts +20 -13
- package/src/execution/__tests__/explicit-agent-ref-guard.test.ts +21 -34
- package/src/execution/__tests__/finalized-marker.test.ts +1 -1
- package/src/execution/__tests__/gc-timer.test.ts +8 -23
- package/src/execution/__tests__/get-record-for-action-restart.test.ts +20 -10
- package/src/execution/__tests__/helpers/fake-engine-port.ts +187 -0
- package/src/execution/__tests__/helpers/spawn-mock.ts +36 -9
- package/src/execution/__tests__/helpers/subagent-service-mocks.ts +1 -1
- package/src/execution/__tests__/idle-gc.test.ts +200 -0
- package/src/execution/__tests__/lifecycle-predicates.test.ts +26 -21
- package/src/execution/__tests__/manifest-store-tmp-recovery.test.ts +1 -1
- package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +5 -2
- package/src/execution/__tests__/notify-batch.test.ts +500 -0
- package/src/execution/__tests__/notify-ledger.test.ts +27 -0
- package/src/execution/__tests__/reconcile-sweep.test.ts +200 -0
- package/src/execution/__tests__/record-entry-collect.test.ts +102 -0
- package/src/execution/__tests__/record-store.test.ts +60 -6
- package/src/execution/__tests__/recursive-visibility-baseline.test.ts +20 -13
- package/src/execution/__tests__/relay-env.test.ts +12 -1
- package/src/execution/__tests__/round-supervisor.test.ts +293 -0
- package/src/execution/__tests__/session-file-gc.test.ts +1 -1
- package/src/execution/__tests__/session-pending.test.ts +119 -17
- package/src/execution/__tests__/start-collect-guard.test.ts +255 -0
- package/src/execution/__tests__/stream-sink-retirement.test.ts +10 -10
- package/src/execution/__tests__/subagent-actions-core.test.ts +6 -0
- package/src/execution/__tests__/subagent-service-multiproc-guard.test.ts +14 -11
- package/src/execution/__tests__/subagent-service-notify-gate.test.ts +33 -30
- package/src/execution/__tests__/subagent-service-parent-guard.test.ts +2 -9
- package/src/execution/__tests__/subagent-service-recovery-bounds.test.ts +59 -129
- package/src/execution/__tests__/subagent-service.test.ts +2 -2
- package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +109 -7
- package/src/execution/__tests__/subprocess-agent-runner.test.ts +108 -36
- package/src/execution/__tests__/sync-collect-recovery.test.ts +1102 -0
- package/src/execution/__tests__/tombstone-store.test.ts +1 -1
- package/src/execution/__tests__/workflow-state-root.test.ts +232 -0
- package/src/execution/__tests__/worktree-git-ops.test.ts +1 -1
- 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 +6 -2
- package/src/execution/collect-coordinator.ts +200 -0
- package/src/execution/config.ts +77 -5
- package/src/execution/dialog-queue.ts +6 -73
- package/src/execution/engine/__tests__/common/capability-gate.test.ts +115 -15
- package/src/execution/engine/__tests__/common/errors.test.ts +11 -18
- package/src/execution/engine/__tests__/common/event-journal.test.ts +1 -1
- package/src/execution/engine/__tests__/common/kill-chain.test.ts +7 -0
- package/src/execution/engine/__tests__/common/nesting-guard.test.ts +9 -3
- package/src/execution/engine/__tests__/common/pool-manager.test.ts +2 -2
- package/src/execution/engine/__tests__/common/session-view-service.test.ts +90 -3
- package/src/execution/engine/__tests__/conformance/H9-test-disposition.md +116 -0
- package/src/execution/engine/__tests__/conformance/__fixtures__/engine-protocol/fake-engine-protocol.mjs +377 -0
- package/src/execution/engine/__tests__/conformance/__fixtures__/engine-protocol/recorded.fixture.json +331 -0
- package/src/execution/engine/__tests__/conformance/__fixtures__/engine-protocol/smoke-run.fixture.json +213 -0
- package/src/execution/engine/__tests__/conformance/chat-round-protocol.test.ts +230 -0
- package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +69 -42
- package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +4 -81
- package/src/execution/engine/__tests__/conformance/contract.probe.test.ts +67 -44
- package/src/execution/engine/__tests__/conformance/contract.read-degradation.test.ts +82 -55
- package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +133 -70
- package/src/execution/engine/__tests__/conformance/engine-crash.test.ts +143 -0
- package/src/execution/engine/__tests__/conformance/fake-engine-capabilities.ts +19 -0
- package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +8 -3
- package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +6 -5
- package/src/execution/engine/__tests__/conformance/protocol-blackbox.test.ts +398 -0
- package/src/execution/engine/__tests__/conformance/registry-fork-filter.test.ts +221 -0
- package/src/execution/engine/__tests__/conformance/round-liveness-supervisor.test.ts +302 -0
- package/src/execution/engine/__tests__/conformance/static-spawn-guard.test.ts +58 -0
- package/src/execution/engine/__tests__/engine-discovery-scan.test.ts +558 -0
- package/src/execution/engine/__tests__/host-task-spec.test.ts +45 -0
- package/src/execution/engine/__tests__/model-ref-split.test.ts +74 -0
- package/src/execution/engine/__tests__/registry.test.ts +206 -1
- package/src/execution/engine/__tests__/routing.test.ts +97 -0
- package/src/execution/engine/__tests__/run-failure-worktree-cleanup.test.ts +97 -0
- package/src/execution/engine/client/__tests__/__fixtures__/fake-engine.mjs +294 -0
- package/src/execution/engine/client/__tests__/engine-client.test.ts +516 -0
- package/src/execution/engine/client/__tests__/mirror.test.ts +67 -0
- package/src/execution/engine/client/__tests__/pid-file.test.ts +257 -0
- package/src/execution/engine/client/__tests__/protocol-closure.test.ts +95 -0
- package/src/execution/engine/client/__tests__/remote-engine.test.ts +457 -0
- package/src/execution/engine/client/client-options.ts +103 -0
- package/src/execution/engine/client/engine-client.ts +687 -0
- package/src/execution/engine/client/mirror.ts +167 -0
- package/src/execution/engine/client/pid-file.ts +392 -0
- package/src/execution/engine/client/reaper.ts +95 -0
- package/src/execution/engine/client/remote-engine.ts +441 -0
- package/src/execution/engine/client/reverse-router.ts +255 -0
- package/src/execution/engine/common/capability-gate.ts +109 -22
- package/src/execution/engine/common/errors.ts +9 -25
- package/src/execution/engine/common/event-journal.ts +4 -50
- package/src/execution/engine/common/journal-replay.ts +3 -1
- package/src/execution/engine/common/kill-chain.ts +18 -251
- package/src/execution/engine/common/nesting-guard.ts +18 -114
- package/src/execution/engine/common/pool-manager.ts +4 -0
- package/src/execution/engine/common/session-view-service.ts +56 -84
- package/src/execution/engine/config.ts +151 -0
- package/src/execution/engine/d8-compat.ts +346 -0
- package/src/execution/engine/engine-discovery-roots.ts +107 -0
- package/src/execution/engine/engine-discovery-scan.ts +269 -0
- package/src/execution/engine/engine-discovery.ts +30 -7
- package/src/execution/engine/engine-inspect-package.ts +282 -0
- package/src/execution/engine/engine-manifest.ts +244 -0
- package/src/execution/engine/host/__tests__/host-askuser-endpoint.test.ts +123 -0
- package/src/execution/engine/host/__tests__/host-bridge.test.ts +135 -0
- package/src/execution/engine/host/__tests__/spawned-children.test.ts +73 -0
- package/src/execution/engine/host/host-bridge.ts +150 -0
- package/src/execution/engine/host/host-ui-endpoint.ts +47 -0
- package/src/execution/engine/host/pi-host-binding.ts +91 -0
- package/src/execution/engine/host/spawned-children.ts +139 -0
- package/src/execution/engine/host-task-spec.ts +29 -2
- package/src/execution/engine/model-validation.ts +55 -2
- package/src/execution/engine/paths.ts +16 -41
- package/src/execution/engine/port.ts +48 -2
- package/src/execution/engine/registry.ts +153 -34
- package/src/execution/engine/routing.ts +225 -52
- package/src/execution/engine/types.ts +25 -200
- package/src/execution/execution-record.ts +7 -0
- package/src/execution/finalize-record.ts +40 -11
- package/src/execution/idle-gc.ts +89 -14
- package/src/execution/lifecycle-manager.ts +10 -7
- package/src/execution/lifecycle-predicates.ts +10 -8
- package/src/execution/notifier.ts +234 -25
- package/src/execution/notify-host.ts +21 -1
- package/src/execution/record-entry.ts +16 -0
- package/src/execution/record-store.ts +189 -31
- package/src/execution/relay-env.ts +19 -36
- package/src/execution/round-supervisor/domain.ts +89 -0
- package/src/execution/round-supervisor/index.ts +33 -0
- package/src/execution/round-supervisor/notify-accounting.ts +87 -0
- package/src/execution/round-supervisor/reconcile-sweep.ts +235 -0
- package/src/execution/round-supervisor/service-binding.test.ts +661 -0
- package/src/execution/round-supervisor/service-binding.ts +273 -0
- package/src/execution/round-supervisor/supervisor.ts +426 -0
- package/src/execution/session-pending.ts +68 -74
- package/src/execution/settled-watchdog.ts +39 -0
- package/src/execution/subagent-actions-core.ts +62 -6
- package/src/execution/subagent-service.ts +1161 -406
- package/src/execution/subprocess-agent-runner.ts +16 -8
- package/src/execution/sync-rebuild.ts +87 -0
- package/src/execution/types.ts +104 -117
- package/src/execution/ui-channels.ts +13 -214
- package/src/execution/ui-request-handler-factory.ts +7 -4
- package/src/execution/ui-request-observability.ts +2 -2
- package/src/execution/workflow-state-root.ts +67 -0
- package/src/execution/worktree-git-ops.ts +5 -0
- package/src/execution/worktree-manager.ts +11 -1
- package/src/index.ts +55 -26
- package/src/orchestration/__tests__/config-loader.test.ts +1 -1
- package/src/orchestration/__tests__/execute-agent-call.test.ts +1 -1
- 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__/review-fix-loop-scriptpath-failfast.test.ts +1 -1
- package/src/orchestration/__tests__/script-generate.test.ts +5 -5
- package/src/orchestration/__tests__/skill-discovery.test.ts +2 -2
- package/src/orchestration/__tests__/workflow-files.test.ts +10 -10
- package/src/orchestration/__tests__/workflow-script-registry-impl.test.ts +1 -1
- package/src/orchestration/execute-agent-call.ts +1 -1
- package/src/orchestration/file-run-store.ts +144 -59
- package/src/orchestration/models/types.ts +43 -42
- package/src/shared/__tests__/atomic-write.test.ts +1 -1
- package/src/shared/__tests__/resource-discovery-host-roots.test.ts +5 -5
- package/src/shared/zcode-model-ref.ts +31 -0
- package/dist/chunk-43ONBFZX.js +0 -240
- package/dist/chunk-A4IVZWVX.js +0 -31
- package/dist/chunk-APZY4IME.js +0 -27
- package/dist/chunk-V3VHZ2VX.js +0 -59
- package/dist/execution/engine/engines/zcode/constants.cjs +0 -107
- package/dist/execution/engine/engines/zcode/constants.d.cts +0 -135
- package/dist/execution/engine/engines/zcode/constants.d.ts +0 -135
- package/dist/execution/engine/engines/zcode/constants.js +0 -54
- package/dist/execution/engine/engines/zcode/reader.cjs +0 -276
- package/dist/execution/engine/engines/zcode/reader.d.cts +0 -21
- package/dist/execution/engine/engines/zcode/reader.d.ts +0 -21
- package/dist/execution/engine/engines/zcode/reader.js +0 -9
- package/src/__tests__/append-system-prompt-assembly.test.ts +0 -243
- package/src/__tests__/fr4-get-state-handshake.test.ts +0 -125
- package/src/__tests__/session-runner.test.ts +0 -69
- package/src/execution/__tests__/ask-user-transit-e2e.test.ts +0 -490
- package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +0 -191
- package/src/execution/__tests__/descendant-sweep-guards.test.ts +0 -220
- package/src/execution/__tests__/descendant-sweep.test.ts +0 -269
- package/src/execution/__tests__/engine-model-validation.test.ts +0 -741
- package/src/execution/__tests__/epipe-fallback.test.ts +0 -248
- package/src/execution/__tests__/execution-runtime-face.test.ts +0 -272
- package/src/execution/__tests__/get-state-handshake.test.ts +0 -127
- package/src/execution/__tests__/helpers/session-runner-mocks.ts +0 -113
- package/src/execution/__tests__/keep-alive-no-progress.test.ts +0 -280
- package/src/execution/__tests__/kill-all-escalation.test.ts +0 -196
- package/src/execution/__tests__/max-turns-to-watchdog-ms.test.ts +0 -113
- package/src/execution/__tests__/output-collector.test.ts +0 -469
- package/src/execution/__tests__/pi-invocation.test.ts +0 -134
- package/src/execution/__tests__/recursive-visibility-env.test.ts +0 -149
- package/src/execution/__tests__/rpc-mode.test.ts +0 -89
- package/src/execution/__tests__/run-and-finalize-anchoring.test.ts +0 -387
- package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +0 -277
- package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +0 -254
- package/src/execution/__tests__/run-spawn-edges.test.ts +0 -1079
- package/src/execution/__tests__/run-spawn-integration.test.ts +0 -933
- package/src/execution/__tests__/run-spawn-resume.test.ts +0 -322
- package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +0 -196
- package/src/execution/__tests__/run-spawn-stdout-callback-throw.test.ts +0 -207
- package/src/execution/__tests__/service-kill-escalation.test.ts +0 -91
- package/src/execution/__tests__/session-runner-branch-cache-lru.test.ts +0 -110
- package/src/execution/__tests__/session-runner-close-prune.test.ts +0 -181
- package/src/execution/__tests__/session-runner-dispatch.test.ts +0 -489
- package/src/execution/__tests__/session-runner-epipe.test.ts +0 -179
- package/src/execution/__tests__/session-runner-heartbeat-idle-fallback.test.ts +0 -227
- package/src/execution/__tests__/session-runner-lifecycle-helpers.test.ts +0 -290
- package/src/execution/__tests__/session-runner-schema-env.test.ts +0 -352
- package/src/execution/__tests__/settled-watchdog.test.ts +0 -524
- package/src/execution/__tests__/spawn-args.test.ts +0 -446
- package/src/execution/__tests__/spawn-event-adapter-rpc.test.ts +0 -192
- package/src/execution/__tests__/spawn-event-adapter.test.ts +0 -167
- package/src/execution/__tests__/spawn-worktree-guidance.test.ts +0 -208
- package/src/execution/__tests__/spawned-children.test.ts +0 -236
- package/src/execution/__tests__/start-sync-model-guard.test.ts +0 -150
- package/src/execution/__tests__/stdin-writer.test.ts +0 -464
- package/src/execution/__tests__/subagent-service-message-close.test.ts +0 -693
- package/src/execution/__tests__/temp-prompt.test.ts +0 -53
- package/src/execution/__tests__/timeout-integration.test.ts +0 -616
- package/src/execution/__tests__/turn-limiter-semantics.test.ts +0 -194
- package/src/execution/__tests__/turn-limiter.test.ts +0 -65
- package/src/execution/__tests__/ui-request-handler.test.ts +0 -205
- package/src/execution/__tests__/ui-request-queue.test.ts +0 -298
- package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +0 -230
- package/src/execution/engine/__tests__/common/schema-emulation.test.ts +0 -128
- package/src/execution/engine/__tests__/common/session-view-service-zcode-dbpath.test.ts +0 -149
- package/src/execution/engine/__tests__/conformance/__fixtures__/pi-golden-events.json +0 -28
- package/src/execution/engine/__tests__/conformance/zcode-appserver-harness.ts +0 -128
- package/src/execution/engine/__tests__/paths.test.ts +0 -39
- package/src/execution/engine/common/schema-emulation.ts +0 -189
- package/src/execution/engine/common/session-view-projection.ts +0 -51
- package/src/execution/engine/engines/pi/__tests__/pi-engine.test.ts +0 -615
- package/src/execution/engine/engines/pi/__tests__/reader.test.ts +0 -155
- package/src/execution/engine/engines/pi/__tests__/spawn-opts-direct.test.ts +0 -257
- package/src/execution/engine/engines/pi/argv-mirror.ts +0 -135
- package/src/execution/engine/engines/pi/get-state-handshake.ts +0 -179
- package/src/execution/engine/engines/pi/output-collector.ts +0 -317
- package/src/execution/engine/engines/pi/pi-engine.ts +0 -811
- package/src/execution/engine/engines/pi/pi-invocation.ts +0 -120
- package/src/execution/engine/engines/pi/reader.ts +0 -59
- package/src/execution/engine/engines/pi/registration.ts +0 -37
- package/src/execution/engine/engines/pi/session-runner.ts +0 -2840
- package/src/execution/engine/engines/pi/spawn-event-adapter.ts +0 -404
- package/src/execution/engine/engines/pi/stdin-writer.ts +0 -199
- package/src/execution/engine/engines/pi/temp-prompt.ts +0 -62
- package/src/execution/engine/engines/pi/turn-limiter.ts +0 -102
- package/src/execution/engine/engines/zcode/__tests__/__fixtures__/fake-appserver.mjs +0 -301
- package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-appserver.json +0 -36
- package/src/execution/engine/engines/zcode/__tests__/appserver-launcher.test.ts +0 -321
- package/src/execution/engine/engines/zcode/__tests__/connection.test.ts +0 -473
- package/src/execution/engine/engines/zcode/__tests__/parser.test.ts +0 -43
- package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +0 -124
- package/src/execution/engine/engines/zcode/__tests__/reader.test.ts +0 -210
- package/src/execution/engine/engines/zcode/__tests__/registration.test.ts +0 -71
- package/src/execution/engine/engines/zcode/__tests__/session-channel-dispose-harvest.test.ts +0 -247
- package/src/execution/engine/engines/zcode/__tests__/session-channel-turn-timers.test.ts +0 -451
- package/src/execution/engine/engines/zcode/__tests__/session-channel.test.ts +0 -792
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-appserver.test.ts +0 -782
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-degrade.test.ts +0 -168
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-dispose.test.ts +0 -210
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-retry.test.ts +0 -353
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-status.test.ts +0 -282
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-timeout.test.ts +0 -372
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +0 -145
- package/src/execution/engine/engines/zcode/appserver-launcher.ts +0 -167
- package/src/execution/engine/engines/zcode/connection.ts +0 -598
- package/src/execution/engine/engines/zcode/constants.ts +0 -176
- package/src/execution/engine/engines/zcode/golden-sample.ts +0 -47
- package/src/execution/engine/engines/zcode/parser.ts +0 -102
- package/src/execution/engine/engines/zcode/preparer.ts +0 -235
- package/src/execution/engine/engines/zcode/reader.ts +0 -381
- package/src/execution/engine/engines/zcode/registration.ts +0 -37
- package/src/execution/engine/engines/zcode/session-channel.ts +0 -968
- package/src/execution/engine/engines/zcode/zcode-engine.ts +0 -1431
- package/src/execution/round-settlement.ts +0 -93
- package/src/execution/ui-request-queue.ts +0 -215
- package/src/shared/schema-env.ts +0 -44
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
// src/execution/__tests__/start-collect-guard.test.ts
|
|
2
|
+
//
|
|
3
|
+
// startHandler 的 collect 语义(subagent-sync-collect U1 foundation):
|
|
4
|
+
// 1. E4 校验(设计 §3.1.5):conversation:true + collect:"sync" → immediate throw,
|
|
5
|
+
// 不产生半启动 record(execute 零调用);文案指引「sync 仅支持 one-shot,
|
|
6
|
+
// 去掉 conversation 或 collect」;
|
|
7
|
+
// 2. 合法组合放行:collect 透传 service.execute(ExecuteOptions.collect);
|
|
8
|
+
// 3. start 响应 collect 段(设计 §3.1.1):仅 resolved=sync 附段(async 响应字节
|
|
9
|
+
// 零变化,G3);pendingSyncCount = 未闭合批 sync 成员数(collectMode=sync 且无
|
|
10
|
+
// batchFinalized;U2 偏差#4 接线后 record 落 collectMode,枚举天然含本条,无 +1)。
|
|
11
|
+
//
|
|
12
|
+
// stub SubagentService 仅实现 handler 触达的方法子集(subagent-actions-core.test.ts
|
|
13
|
+
// 同款形态);真实 service 行为归属 subagent-service 各自测试。
|
|
14
|
+
|
|
15
|
+
import { describe, expect, it, vi, type Mock } from "vitest";
|
|
16
|
+
|
|
17
|
+
import { startHandler } from "../subagent-actions-core.ts";
|
|
18
|
+
// SubagentService 的权威源是 subagent-service.ts(types.ts 只有 record/tool 契约)
|
|
19
|
+
import type { SubagentService } from "../subagent-service.ts";
|
|
20
|
+
import type { StatusFilter } from "../record-store.ts";
|
|
21
|
+
import type {
|
|
22
|
+
ExecutionHandle,
|
|
23
|
+
SubagentRecord,
|
|
24
|
+
SubagentToolDetails,
|
|
25
|
+
} from "../types.ts";
|
|
26
|
+
|
|
27
|
+
function makeDetails(): SubagentToolDetails {
|
|
28
|
+
return {
|
|
29
|
+
status: "running",
|
|
30
|
+
mode: "background",
|
|
31
|
+
agent: "/home/u/agents/worker.md",
|
|
32
|
+
model: "prov/m1",
|
|
33
|
+
thinkingLevel: undefined,
|
|
34
|
+
slug: "src-slug",
|
|
35
|
+
turns: 0,
|
|
36
|
+
totalTokens: 0,
|
|
37
|
+
elapsedSeconds: 0,
|
|
38
|
+
eventLog: [],
|
|
39
|
+
displayItems: [],
|
|
40
|
+
result: undefined,
|
|
41
|
+
error: undefined,
|
|
42
|
+
} as SubagentToolDetails;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function makeHandle(): ExecutionHandle {
|
|
46
|
+
return { mode: "background", subagentId: "sa-new", sessionFile: undefined, details: makeDetails() };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** collectRecords stub 数据行(只含 pendingSyncCount 口径判读所需字段)。 */
|
|
50
|
+
function makeRec(over: Partial<SubagentRecord> = {}): SubagentRecord {
|
|
51
|
+
return {
|
|
52
|
+
id: "sa-1",
|
|
53
|
+
agent: "/home/u/agents/worker.md",
|
|
54
|
+
task: "t",
|
|
55
|
+
slug: "worker",
|
|
56
|
+
status: "running",
|
|
57
|
+
mode: "background",
|
|
58
|
+
startedAt: 1000,
|
|
59
|
+
rootSessionId: "root-A",
|
|
60
|
+
parentRecordId: undefined,
|
|
61
|
+
depth: 0,
|
|
62
|
+
endedAt: undefined,
|
|
63
|
+
turns: 1,
|
|
64
|
+
totalTokens: 42,
|
|
65
|
+
model: "prov/m1",
|
|
66
|
+
thinkingLevel: undefined,
|
|
67
|
+
eventLog: [],
|
|
68
|
+
displayItems: [],
|
|
69
|
+
...over,
|
|
70
|
+
} as SubagentRecord;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Mock<T> 具名签名 + Omit 类原生同名成员:ReturnType<typeof vi.fn>
|
|
74
|
+
// (= Mock<Procedure | Constructable>)与类方法签名交叉会收窄 never
|
|
75
|
+
type ServiceStub = Omit<SubagentService, "execute" | "collectRecords" | "getCollectSyncDefault"> & {
|
|
76
|
+
// 带首参形态:断言消费 execute.mock.calls[0][0](ExecuteOptions),零参签名为空元组取不到
|
|
77
|
+
execute: Mock<(opts: Record<string, unknown>) => Promise<SubagentRecord>>;
|
|
78
|
+
collectRecords: Mock<(limit: number, statusFilter?: StatusFilter) => SubagentRecord[]>;
|
|
79
|
+
getCollectSyncDefault: Mock<() => "async" | "sync">;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
/** startHandler 的测试包装:stub → SubagentService 断言收口一处(类私有成员不可结构模拟)。 */
|
|
83
|
+
function sh(svc: ServiceStub, input: Record<string, unknown>, signal?: AbortSignal) {
|
|
84
|
+
return startHandler(
|
|
85
|
+
svc as unknown as SubagentService,
|
|
86
|
+
input as Parameters<typeof startHandler>[1],
|
|
87
|
+
signal ?? undefined,
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function makeService(
|
|
92
|
+
collectRecordsReturn: SubagentRecord[] = [],
|
|
93
|
+
collectSyncDefault: "async" | "sync" = "async",
|
|
94
|
+
): ServiceStub {
|
|
95
|
+
const execute = vi.fn(async (_opts: Record<string, unknown>) => makeHandle());
|
|
96
|
+
const collectRecords = vi.fn(() => collectRecordsReturn);
|
|
97
|
+
const getCollectSyncDefault = vi.fn(() => collectSyncDefault);
|
|
98
|
+
// [D4-① 适配] countPendingSyncRecords 经查询面聚合读 collectRecords(dev 重构后
|
|
99
|
+
// service.collectRecords 收窄 private,public 出口 = service.queries.collectRecords)。
|
|
100
|
+
return {
|
|
101
|
+
execute,
|
|
102
|
+
queries: { collectRecords },
|
|
103
|
+
collectRecords,
|
|
104
|
+
getCollectSyncDefault,
|
|
105
|
+
} as unknown as ServiceStub;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const BASE_INPUT = { task: "do things", slug: "do-things" };
|
|
109
|
+
|
|
110
|
+
// ============================================================
|
|
111
|
+
// E4:conversation + collect:"sync" 即拒
|
|
112
|
+
// ============================================================
|
|
113
|
+
|
|
114
|
+
describe("startHandler E4 guard (conversation + collect:sync)", () => {
|
|
115
|
+
it("throws immediately and never calls execute (不产生半启动 record)", async () => {
|
|
116
|
+
const service = makeService();
|
|
117
|
+
await expect(
|
|
118
|
+
sh(service, { ...BASE_INPUT, conversation: true, collect: "sync" }, undefined),
|
|
119
|
+
).rejects.toThrow();
|
|
120
|
+
expect(service.execute).not.toHaveBeenCalled();
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it("error copy carries the design guidance verbatim (文案锚定)", async () => {
|
|
124
|
+
const service = makeService();
|
|
125
|
+
const err = await sh(service,
|
|
126
|
+
{ ...BASE_INPUT, conversation: true, collect: "sync" },
|
|
127
|
+
undefined,
|
|
128
|
+
).catch((e: unknown) => e as Error);
|
|
129
|
+
expect(err).toBeInstanceOf(Error);
|
|
130
|
+
expect((err as Error).message).toBe(
|
|
131
|
+
'collect:"sync" only supports one-shot subagents — it cannot be combined with conversation:true. ' +
|
|
132
|
+
'Remove either conversation or collect (use collect:"async", or omit it, for conversational subagents).',
|
|
133
|
+
);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it("allows conversation:true + collect:async (async 语义与 conversation 正交)", async () => {
|
|
137
|
+
const service = makeService();
|
|
138
|
+
const result = await sh(service,
|
|
139
|
+
{ ...BASE_INPUT, conversation: true, collect: "async" },
|
|
140
|
+
undefined,
|
|
141
|
+
);
|
|
142
|
+
expect(result.subagentId).toBe("sa-new");
|
|
143
|
+
expect(service.execute).toHaveBeenCalledTimes(1);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it("allows collect:sync alone (one-shot sync 是合法主场景)", async () => {
|
|
147
|
+
const service = makeService();
|
|
148
|
+
const result = await sh(service, { ...BASE_INPUT, collect: "sync" }, undefined);
|
|
149
|
+
expect(result.subagentId).toBe("sa-new");
|
|
150
|
+
expect(service.execute).toHaveBeenCalledTimes(1);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it("E4 also blocks conversation when config default is sync (偏差#3 接线:resolved 含 config 默认)", async () => {
|
|
154
|
+
const service = makeService([], "sync");
|
|
155
|
+
await expect(
|
|
156
|
+
sh(service, { ...BASE_INPUT, conversation: true }, undefined),
|
|
157
|
+
).rejects.toThrow('collect:"sync" only supports one-shot subagents');
|
|
158
|
+
expect(service.execute).not.toHaveBeenCalled();
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it("config default=sync applies when collect omitted (缺省读真实 config,U2 偏差#3)", async () => {
|
|
162
|
+
const service = makeService([], "sync");
|
|
163
|
+
const result = await sh(service, { ...BASE_INPUT }, undefined);
|
|
164
|
+
expect(result.response.collect).toBeDefined();
|
|
165
|
+
expect(service.getCollectSyncDefault).toHaveBeenCalledTimes(1);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it("reads config default via service accessor when collect omitted (async 默认零附段)", async () => {
|
|
169
|
+
const service = makeService([], "async");
|
|
170
|
+
const result = await sh(service, { ...BASE_INPUT }, undefined);
|
|
171
|
+
expect(result.response.collect).toBeUndefined();
|
|
172
|
+
expect(service.getCollectSyncDefault).toHaveBeenCalledTimes(1);
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
// ============================================================
|
|
177
|
+
// collect 透传 + 响应 collect 段
|
|
178
|
+
// ============================================================
|
|
179
|
+
|
|
180
|
+
describe("startHandler collect forwarding + response collect segment", () => {
|
|
181
|
+
it("forwards collect to service.execute via ExecuteOptions.collect", async () => {
|
|
182
|
+
const service = makeService();
|
|
183
|
+
await sh(service, { ...BASE_INPUT, collect: "sync" }, undefined);
|
|
184
|
+
const opts = service.execute.mock.calls[0]?.[0] as { collect?: string };
|
|
185
|
+
expect(opts.collect).toBe("sync");
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it("omits collect in ExecuteOptions when not provided (resolved≠sync 时保持 undefined,async 缺省语义)", async () => {
|
|
189
|
+
const service = makeService();
|
|
190
|
+
await sh(service, { ...BASE_INPUT }, undefined);
|
|
191
|
+
const opts = service.execute.mock.calls[0]?.[0] as { collect?: string };
|
|
192
|
+
expect(opts.collect).toBeUndefined();
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it("B1:config default=sync + 省略 collect → execute 收 collect:\"sync\"(缺省解析作用于 record 本体)", async () => {
|
|
196
|
+
// 修复前:execute 收原始 input.collect=undefined → createRecordForMode 只认
|
|
197
|
+
// ==="sync" → record 走 async 逐条通知而响应声称已入批(设计 §3.1.3/types.ts:689
|
|
198
|
+
// 承诺「缺省 = config 默认」作用于 record)。修复后 resolved=sync 落值。
|
|
199
|
+
const service = makeService([], "sync");
|
|
200
|
+
await sh(service, { ...BASE_INPUT }, undefined);
|
|
201
|
+
const opts = service.execute.mock.calls[0]?.[0] as { collect?: string };
|
|
202
|
+
expect(opts.collect).toBe("sync");
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it("B1:config default=sync 时显式 collect:\"async\" 优先(execute 收 \"async\")", async () => {
|
|
206
|
+
const service = makeService([], "sync");
|
|
207
|
+
await sh(service, { ...BASE_INPUT, collect: "async" }, undefined);
|
|
208
|
+
const opts = service.execute.mock.calls[0]?.[0] as { collect?: string };
|
|
209
|
+
expect(opts.collect).toBe("async");
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
it("attaches collect segment counting this very record from the enumeration (U2 偏差#4:无 +1 补偿)", async () => {
|
|
213
|
+
// 本条 record(id=sa-new)已由 createRecordForMode 落 collectMode 入枚举:
|
|
214
|
+
// stub 枚举返回本条 + 另一未闭合 sync → count=2(无 +1 补偿即含本条)
|
|
215
|
+
const service = makeService([
|
|
216
|
+
makeRec({ id: "sa-new", collectMode: "sync" }),
|
|
217
|
+
makeRec({ id: "sa-other", collectMode: "sync", status: "running" }),
|
|
218
|
+
makeRec({ id: "sa-gone", collectMode: "sync", batchFinalized: true }),
|
|
219
|
+
]);
|
|
220
|
+
const result = await sh(service, { ...BASE_INPUT, collect: "sync" }, undefined);
|
|
221
|
+
expect(result.response.collect).toEqual({ mode: "sync", pendingSyncCount: 2 });
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
it("reports the enumeration verbatim when no sync records exist yet (如实反映,无补偿)", async () => {
|
|
225
|
+
const service = makeService([]);
|
|
226
|
+
const result = await sh(service, { ...BASE_INPUT, collect: "sync" }, undefined);
|
|
227
|
+
expect(result.response.collect).toEqual({ mode: "sync", pendingSyncCount: 0 });
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it("counts pending unmarked sync members from the enumeration (跨轮续累口径)", async () => {
|
|
231
|
+
const service = makeService([
|
|
232
|
+
makeRec({ id: "sa-1", collectMode: "sync" }), // 未闭合(无 batchFinalized)→ 计入
|
|
233
|
+
makeRec({ id: "sa-2", collectMode: "sync", batchFinalized: true }), // 已离场 → 排除
|
|
234
|
+
makeRec({ id: "sa-3" }), // async → 排除
|
|
235
|
+
makeRec({ id: "sa-4", collectMode: "sync", batchFinalized: false }), // 显式 false → 计入
|
|
236
|
+
]);
|
|
237
|
+
const result = await sh(service, { ...BASE_INPUT, collect: "sync" }, undefined);
|
|
238
|
+
expect(result.response.collect).toEqual({ mode: "sync", pendingSyncCount: 2 });
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it("omits the collect segment for async starts (G3: async 响应字节零变化)", async () => {
|
|
242
|
+
for (const input of [{ ...BASE_INPUT }, { ...BASE_INPUT, collect: "async" as const }]) {
|
|
243
|
+
const service = makeService();
|
|
244
|
+
const result = await sh(service, input, undefined);
|
|
245
|
+
expect(result.response.collect).toBeUndefined();
|
|
246
|
+
// G3 字节锚:response 其余字段与既有形态全等
|
|
247
|
+
expect(result.response).toEqual({
|
|
248
|
+
status: "running",
|
|
249
|
+
mode: "background",
|
|
250
|
+
message: result.response.message,
|
|
251
|
+
notifyContract: "ledger+at-least-once",
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
});
|
|
@@ -103,14 +103,6 @@ vi.mock("../manifest-store.ts", () => {
|
|
|
103
103
|
return { ManifestStore: vi.fn(function (_recordsDir: string) { return new FakeManifestStore(); }) };
|
|
104
104
|
});
|
|
105
105
|
|
|
106
|
-
vi.mock("../engine/engines/pi/temp-prompt.ts", () => ({
|
|
107
|
-
writePromptToTempFile: vi.fn(async (agent: string) => {
|
|
108
|
-
const safeName = agent.replace(/[^\w.-]+/g, "_");
|
|
109
|
-
return { dir: `/tmp/fake-${safeName}`, filePath: `/tmp/fake-${safeName}/prompt-${safeName}.md` };
|
|
110
|
-
}),
|
|
111
|
-
cleanupTempPrompt: vi.fn(async () => {}),
|
|
112
|
-
}));
|
|
113
|
-
|
|
114
106
|
import { spawn } from "node:child_process";
|
|
115
107
|
|
|
116
108
|
import { ModelConfigService } from "../model-config-service.ts";
|
|
@@ -233,6 +225,11 @@ describe("退役步骤 2 判定层:createBackgroundStream", () => {
|
|
|
233
225
|
});
|
|
234
226
|
|
|
235
227
|
// ── 接线层:service → 工厂的参数透传(mode 传错 = 判定失效)──
|
|
228
|
+
// [W3 改写] 驱动方式从 inproc spawn(FakeChild close)改为协议 seam
|
|
229
|
+
//(registerFakePiEngine 替身)——kickOffChatRound 的 stream 创建先于 pool acquire,
|
|
230
|
+
// 替身 run 挂起即可观察工厂入参。
|
|
231
|
+
import { registerFakePiEngine } from "./helpers/fake-engine-port.ts";
|
|
232
|
+
import { clearEngines } from "../engine/registry.ts";
|
|
236
233
|
|
|
237
234
|
describe("退役步骤 2 接线层:kickOffChatRound 透传 mode/sink 给工厂", () => {
|
|
238
235
|
beforeEach(() => {
|
|
@@ -242,6 +239,7 @@ describe("退役步骤 2 接线层:kickOffChatRound 透传 mode/sink 给工厂
|
|
|
242
239
|
|
|
243
240
|
afterEach(() => {
|
|
244
241
|
for (const key of RELAY_ENV_KEYS) delete process.env[key];
|
|
242
|
+
clearEngines();
|
|
245
243
|
vi.restoreAllMocks();
|
|
246
244
|
});
|
|
247
245
|
|
|
@@ -250,9 +248,11 @@ describe("退役步骤 2 接线层:kickOffChatRound 透传 mode/sink 给工厂
|
|
|
250
248
|
["tui", "tui"],
|
|
251
249
|
["undefined(headless)", undefined],
|
|
252
250
|
])("mode=%s:工厂收到 initSession 注入的 mode 与 streamSink", async (_label, mode) => {
|
|
251
|
+
clearEngines();
|
|
252
|
+
registerFakePiEngine();
|
|
253
253
|
const service = setupService(mode);
|
|
254
|
-
await
|
|
255
|
-
expect(mockCreateStream).toHaveBeenCalledTimes(1);
|
|
254
|
+
await service.execute({ task: "retire test", slug: "test", ctxModel, conversation: true });
|
|
255
|
+
await vi.waitFor(() => expect(mockCreateStream).toHaveBeenCalledTimes(1));
|
|
256
256
|
const [recordId, sinkArg, modeArg] = mockCreateStream.mock.calls[0]!;
|
|
257
257
|
expect(typeof recordId).toBe("string");
|
|
258
258
|
expect(sinkArg).toHaveProperty("setWidget");
|
|
@@ -144,11 +144,17 @@ function makeService(over: Record<string, unknown> = {}): SubagentService {
|
|
|
144
144
|
getRecordForAction: vi.fn(),
|
|
145
145
|
closeSubagent: vi.fn(),
|
|
146
146
|
deliverChatMessage: vi.fn(),
|
|
147
|
+
// [U2] startHandler 缺省 collect 解析读真实 config(偏差#3 接线):stub 缺省 async
|
|
148
|
+
//(本文件不测 collect 语义,专项见 start-collect-guard.test.ts)。
|
|
149
|
+
getCollectSyncDefault: vi.fn(() => "async" as const),
|
|
147
150
|
...over,
|
|
148
151
|
};
|
|
149
152
|
return {
|
|
150
153
|
execute: m.execute,
|
|
151
154
|
cancel: m.cancel,
|
|
155
|
+
// [U2 偏差#3 接线] startHandler 经平铺访问器读 config 缺省 collect(真实 service
|
|
156
|
+
// 为平铺方法 subagent-service.ts:1786,非 queries 聚合面成员),stub 须同构挂载。
|
|
157
|
+
getCollectSyncDefault: m.getCollectSyncDefault,
|
|
152
158
|
queries: {
|
|
153
159
|
findRecord: m.findRecord,
|
|
154
160
|
lookupRecordAnyState: m.lookupRecordAnyState,
|
|
@@ -21,8 +21,7 @@ const { loggerMock } = vi.hoisted(() => ({
|
|
|
21
21
|
}));
|
|
22
22
|
vi.mock("../../core/logger.ts", () => ({ getLogger: () => loggerMock }));
|
|
23
23
|
|
|
24
|
-
const {
|
|
25
|
-
killChildSpy: vi.fn(),
|
|
24
|
+
const { foreignLiveSpy } = vi.hoisted(() => ({
|
|
26
25
|
foreignLiveSpy: vi.fn<() => { pid: number; id: string; startedAt: number } | undefined>(),
|
|
27
26
|
}));
|
|
28
27
|
vi.mock("../alive-store.ts", () => ({
|
|
@@ -34,15 +33,6 @@ vi.mock("../alive-store.ts", () => ({
|
|
|
34
33
|
findForeignLiveInstance: foreignLiveSpy,
|
|
35
34
|
}));
|
|
36
35
|
|
|
37
|
-
vi.mock("../engine/engines/pi/session-runner.ts", () => ({
|
|
38
|
-
runSpawn: vi.fn(),
|
|
39
|
-
killAllSpawnedChildren: vi.fn(),
|
|
40
|
-
getChildByRecord: vi.fn(() => undefined),
|
|
41
|
-
registerSpawnedChildForRecord: vi.fn(),
|
|
42
|
-
spawnedChildren: new Map(),
|
|
43
|
-
killRecordChildWithEscalation: killChildSpy,
|
|
44
|
-
}));
|
|
45
|
-
|
|
46
36
|
import { ModelConfigService } from "../model-config-service.ts";
|
|
47
37
|
import type { RecordStore } from "../record-store.ts";
|
|
48
38
|
import { SubagentService } from "../subagent-service.ts";
|
|
@@ -120,6 +110,19 @@ describe("T5③ cold-lookup running candidate foreign-instance guard", () => {
|
|
|
120
110
|
let store: RecordStore;
|
|
121
111
|
|
|
122
112
|
beforeEach(() => {
|
|
113
|
+
// 身份 env 剥离:initSession 会把 PI_SUBAGENT_ROOT_SESSION_ID 读作 sessionRootId 基线
|
|
114
|
+
//(env 优先于入参 sessionId)——宿主进程(xyz-agent 子 agent 环境)泄漏的身份 env
|
|
115
|
+
// 会让「root-session」桩记录归属校验恒不匹配 → 冷查用例误红(与 collect-coordinator-
|
|
116
|
+
// service.test.ts 同款剥离纪律)。
|
|
117
|
+
for (const k of [
|
|
118
|
+
"PI_SUBAGENT_ROOT_SESSION_ID",
|
|
119
|
+
"PI_SUBAGENT_SELF_RECORD_ID",
|
|
120
|
+
"PI_SUBAGENT_DEPTH",
|
|
121
|
+
"PI_SUBAGENT_ROOT_CWD",
|
|
122
|
+
"PI_SUBAGENT_FORK_DEPTH",
|
|
123
|
+
] as const) {
|
|
124
|
+
delete process.env[k];
|
|
125
|
+
}
|
|
123
126
|
foreignLiveSpy.mockReset();
|
|
124
127
|
foreignLiveSpy.mockReturnValue(undefined);
|
|
125
128
|
({ agentDir, service, store } = setup());
|
|
@@ -22,16 +22,10 @@ const { loggerMock } = vi.hoisted(() => ({
|
|
|
22
22
|
}));
|
|
23
23
|
vi.mock("../../core/logger.ts", () => ({ getLogger: () => loggerMock }));
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
getChildByRecord: vi.fn(() => undefined),
|
|
30
|
-
registerSpawnedChildForRecord: vi.fn(),
|
|
31
|
-
spawnedChildren: new Map(),
|
|
32
|
-
killRecordChildWithEscalation: killChildSpy,
|
|
33
|
-
}));
|
|
34
|
-
|
|
25
|
+
// [W3 改写] 原 vi.mock(inproc pi 引擎目录/session-runner) 随删件消亡——chat 轮次走协议 seam
|
|
26
|
+
//(registerFakePiEngine 替身,kickOffChatRound 的 notify 门经 engine.run 应答驱动)。
|
|
27
|
+
import { registerFakePiEngine } from "./helpers/fake-engine-port.ts";
|
|
28
|
+
import { clearEngines } from "../engine/registry.ts";
|
|
35
29
|
import { bindNotifyLedgerHost, NOTIFY_LEDGER_CUSTOM_TYPE, _resetNotifyLedgerForTest } from "../notify-ledger.ts";
|
|
36
30
|
import { createRecord } from "../execution-record.ts";
|
|
37
31
|
import { ModelConfigService } from "../model-config-service.ts";
|
|
@@ -95,8 +89,10 @@ describe("T4① notify gate closedReason whitelist", () => {
|
|
|
95
89
|
expect(notifyGateAllowsDelivery(undefined)).toBe(true);
|
|
96
90
|
});
|
|
97
91
|
|
|
98
|
-
it("kickOffChatRound
|
|
92
|
+
it("kickOffChatRound 应答回注不注入 parent-new closed records(notify 门白名单)", async () => {
|
|
99
93
|
const { agentDir, service, pi } = setup();
|
|
94
|
+
clearEngines();
|
|
95
|
+
const fake = registerFakePiEngine();
|
|
100
96
|
const record = createRecord("sa-gate-new", {
|
|
101
97
|
agent: "general-purpose",
|
|
102
98
|
model: "test/model",
|
|
@@ -107,34 +103,33 @@ describe("T4① notify gate closedReason whitelist", () => {
|
|
|
107
103
|
rootSessionId: "root-session",
|
|
108
104
|
controller: new AbortController(),
|
|
109
105
|
});
|
|
110
|
-
// 模拟 disposeAllRecords 先行编排性关闭后,迟到的 kickOffChatRound
|
|
106
|
+
// 模拟 disposeAllRecords 先行编排性关闭后,迟到的 kickOffChatRound 应答回注
|
|
111
107
|
record.closedReason = "parent-new";
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
turns: 0,
|
|
115
|
-
durationMs: 1,
|
|
116
|
-
success: false,
|
|
117
|
-
error: "closed due to parent-new",
|
|
118
|
-
sessionId: record.id,
|
|
119
|
-
toolCalls: [],
|
|
120
|
-
});
|
|
121
|
-
(service as unknown as Record<string, unknown>).runAndFinalize = stub;
|
|
122
|
-
// [D4 后形态] 轮次编排入口 kickOffChatRound(私有,bracket 调用先例见
|
|
123
|
-
// subagent-service-recovery-bounds.test.ts privateFn);opts 形参仍是 ExecuteOptions
|
|
124
|
-
//(task/slug),chat 分支由 ticket lossless 携带——task 声明形参不参与校验。
|
|
108
|
+
// [W3] 轮次编排入口 kickOffChatRound(私有,bracket 调用先例)——协议 run 发起后
|
|
109
|
+
// 挂起,编排性关闭先行,再模拟引擎应答(迟到回注被门拦)。
|
|
125
110
|
const kickOffChatRound = (
|
|
126
111
|
service as unknown as Record<string, (...args: unknown[]) => void>
|
|
127
112
|
)["kickOffChatRound"];
|
|
128
|
-
|
|
129
|
-
|
|
113
|
+
const identity = {
|
|
114
|
+
agent: "general-purpose",
|
|
115
|
+
agentConfig: undefined,
|
|
116
|
+
resolved: { model: { id: "model", name: "Model", provider: "test", reasoning: false }, thinkingLevel: undefined },
|
|
117
|
+
};
|
|
118
|
+
kickOffChatRound.call(service, record, { task: "t", slug: "gate" }, identity, undefined, 1000);
|
|
119
|
+
await vi.waitFor(() => expect(fake.runs.length).toBe(1));
|
|
120
|
+
fake.runs[0]!.settle({ content: "late round text" });
|
|
130
121
|
await Promise.resolve();
|
|
131
122
|
await Promise.resolve();
|
|
132
123
|
expect(pi.sendMessage).not.toHaveBeenCalled();
|
|
124
|
+
service.dispose();
|
|
125
|
+
clearEngines();
|
|
133
126
|
fs.rmSync(agentDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
|
|
134
127
|
});
|
|
135
128
|
|
|
136
|
-
it("kickOffChatRound
|
|
129
|
+
it("kickOffChatRound 应答回注对真实失败关闭(gc)仍通知", async () => {
|
|
137
130
|
const { agentDir, service, pi } = setup();
|
|
131
|
+
clearEngines();
|
|
132
|
+
const fake = registerFakePiEngine();
|
|
138
133
|
const record = createRecord("sa-gate-gc", {
|
|
139
134
|
agent: "general-purpose",
|
|
140
135
|
model: "test/model",
|
|
@@ -146,12 +141,20 @@ describe("T4① notify gate closedReason whitelist", () => {
|
|
|
146
141
|
controller: new AbortController(),
|
|
147
142
|
});
|
|
148
143
|
record.closedReason = "gc";
|
|
149
|
-
(service as unknown as Record<string, unknown>).runAndFinalize = vi.fn().mockResolvedValue({});
|
|
150
144
|
const kickOffChatRound = (
|
|
151
145
|
service as unknown as Record<string, (...args: unknown[]) => void>
|
|
152
146
|
)["kickOffChatRound"];
|
|
153
|
-
|
|
147
|
+
const identity = {
|
|
148
|
+
agent: "general-purpose",
|
|
149
|
+
agentConfig: undefined,
|
|
150
|
+
resolved: { model: { id: "model", name: "Model", provider: "test", reasoning: false }, thinkingLevel: undefined },
|
|
151
|
+
};
|
|
152
|
+
kickOffChatRound.call(service, record, { task: "t", slug: "gate" }, identity, undefined, 1000);
|
|
153
|
+
await vi.waitFor(() => expect(fake.runs.length).toBe(1));
|
|
154
|
+
fake.runs[0]!.settle({ content: "round" });
|
|
154
155
|
await vi.waitFor(() => expect(pi.sendMessage).toHaveBeenCalled());
|
|
156
|
+
service.dispose();
|
|
157
|
+
clearEngines();
|
|
155
158
|
fs.rmSync(agentDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
|
|
156
159
|
});
|
|
157
160
|
});
|
|
@@ -25,15 +25,8 @@ const { loggerMock } = vi.hoisted(() => ({
|
|
|
25
25
|
}));
|
|
26
26
|
vi.mock("../../core/logger.ts", () => ({ getLogger: () => loggerMock }));
|
|
27
27
|
|
|
28
|
-
// mock session-runner
|
|
29
|
-
|
|
30
|
-
runSpawn: vi.fn(),
|
|
31
|
-
killAllSpawnedChildren: vi.fn(),
|
|
32
|
-
getChildByRecord: vi.fn(() => undefined),
|
|
33
|
-
registerSpawnedChildForRecord: vi.fn(),
|
|
34
|
-
killRecordChildWithEscalation: vi.fn(),
|
|
35
|
-
spawnedChildren: new Map(),
|
|
36
|
-
}));
|
|
28
|
+
// [W3 改写] 原 vi.mock(inproc pi 引擎目录/session-runner) 随删件消亡——本文件只测
|
|
29
|
+
// getRecordForAction 守卫(纯内存判定,不触引擎链路),现存 import 无需再 mock 引擎替身。
|
|
37
30
|
|
|
38
31
|
import { createRecord } from "../execution-record.ts";
|
|
39
32
|
import { ModelConfigService } from "../model-config-service.ts";
|