@zhushanwen/subagent-core 0.2.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -2
- package/agents/analyst.md +60 -0
- package/agents/coder.md +69 -0
- package/agents/debugger.md +66 -0
- package/agents/doc-reviewer.md +49 -0
- package/agents/explorer.md +63 -0
- package/agents/general-purpose.md +32 -0
- package/agents/orchestrator.md +61 -0
- package/agents/planner.md +53 -0
- package/agents/researcher.md +67 -0
- package/agents/reviewer.md +73 -0
- package/dist/chunk-43ONBFZX.js +240 -0
- package/dist/chunk-APZY4IME.js +27 -0
- package/dist/chunk-V3VHZ2VX.js +59 -0
- package/dist/execution/engine/engines/zcode/constants.cjs +62 -9
- package/dist/execution/engine/engines/zcode/constants.d.cts +116 -12
- package/dist/execution/engine/engines/zcode/constants.d.ts +116 -12
- package/dist/execution/engine/engines/zcode/constants.js +39 -7
- package/dist/execution/engine/engines/zcode/reader.d.cts +2 -1
- package/dist/execution/engine/engines/zcode/reader.d.ts +2 -1
- package/dist/execution/engine/engines/zcode/reader.js +4 -234
- package/dist/execution/engine/paths.js +7 -19
- package/dist/index.cjs +18234 -1277
- package/dist/index.d.cts +5646 -673
- package/dist/index.d.ts +5646 -673
- package/dist/index.js +17828 -1277
- package/dist/{types-BxyAidGf.d.cts → types-Dv4QhSJ_.d.cts} +678 -112
- package/dist/{types-BxyAidGf.d.ts → types-Dv4QhSJ_.d.ts} +678 -112
- package/package.json +7 -4
- package/src/__tests__/agent-opts-resolver-schema-prompt.test.ts +0 -1
- package/src/__tests__/append-system-prompt-assembly.test.ts +8 -7
- package/src/__tests__/fr4-get-state-handshake.test.ts +2 -2
- package/src/__tests__/m2-append-content-probe.test.ts +0 -1
- package/src/__tests__/manifest-store.test.ts +10 -9
- package/src/__tests__/record-store-cache.test.ts +0 -2
- package/src/__tests__/record-store-index.test.ts +1 -2
- package/src/__tests__/review-fix-loop-script.test.ts +93 -3
- package/src/__tests__/review-fix-loop-utils.test.ts +31 -10
- package/src/__tests__/robustness-low-batch1.test.ts +6 -5
- package/src/__tests__/robustness-medium-batch1.test.ts +2 -2
- package/src/__tests__/robustness-medium-batch2.test.ts +17 -6
- package/src/__tests__/robustness-medium-batch4.test.ts +2 -2
- package/src/__tests__/session-runner.test.ts +1 -1
- package/src/__tests__/smoke.test.ts +9 -2
- package/src/core/__tests__/host-services.test.ts +2 -2
- package/src/core/__tests__/logger.test.ts +1 -1
- package/src/core/error-message.ts +9 -0
- package/src/core/host-services.ts +21 -5
- package/src/core/notify-ports.ts +18 -5
- package/src/execution/__tests__/agent-profile.test.ts +232 -0
- package/src/execution/__tests__/agent-registry.test.ts +370 -0
- package/src/execution/__tests__/agent-result-mapper.test.ts +18 -2
- package/src/execution/__tests__/agents-assembly.test.ts +219 -0
- package/src/execution/__tests__/ask-user-transit-e2e.test.ts +6 -6
- package/src/execution/__tests__/chat-engine-routing.test.ts +136 -30
- package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +5 -4
- package/src/execution/__tests__/cold-resurrect.test.ts +283 -0
- package/src/execution/__tests__/create-concurrency-pool.test.ts +194 -0
- package/src/execution/__tests__/delivery-methods.test.ts +77 -62
- package/src/execution/__tests__/descendant-sweep-guards.test.ts +220 -0
- package/src/execution/__tests__/descendant-sweep.test.ts +269 -0
- package/src/execution/__tests__/dialog-queue.test.ts +199 -1
- package/src/execution/__tests__/engine-model-validation.test.ts +741 -0
- package/src/execution/__tests__/epipe-fallback.test.ts +31 -24
- package/src/execution/__tests__/execute-and-await-worktree.test.ts +21 -91
- package/src/execution/__tests__/execute-nesting.test.ts +34 -188
- package/src/execution/__tests__/execution-record.test.ts +217 -60
- package/src/execution/__tests__/execution-runtime-face.test.ts +272 -0
- package/src/execution/__tests__/explicit-agent-ref-guard.test.ts +3 -3
- package/src/execution/__tests__/finalize-record.test.ts +278 -16
- package/src/execution/__tests__/gc-timer.test.ts +57 -2
- package/src/execution/__tests__/get-record-for-action-restart.test.ts +14 -12
- package/src/execution/__tests__/get-state-handshake.test.ts +127 -0
- package/src/execution/__tests__/helpers/mock-extension-api.ts +1 -1
- package/src/execution/__tests__/helpers/session-runner-mocks.ts +113 -0
- package/src/execution/__tests__/helpers/spawn-mock.ts +150 -3
- package/src/execution/__tests__/helpers/subagent-service-mocks.ts +137 -0
- package/src/execution/__tests__/keep-alive-no-progress.test.ts +280 -0
- package/src/execution/__tests__/kill-all-escalation.test.ts +196 -0
- package/src/execution/__tests__/lifecycle-manager-idle-timer-identity.test.ts +117 -0
- package/src/execution/__tests__/lifecycle-manager.test.ts +39 -0
- package/src/execution/__tests__/lifecycle-predicates.test.ts +1 -2
- package/src/execution/__tests__/manifest-parentid.test.ts +4 -4
- package/src/execution/__tests__/manifest-store-tmp-recovery.test.ts +99 -0
- package/src/execution/__tests__/max-turns-to-watchdog-ms.test.ts +113 -0
- package/src/execution/__tests__/model-resolver.test.ts +2 -2
- package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +23 -121
- package/src/execution/__tests__/nested-visibility.test.ts +2 -0
- package/src/execution/__tests__/notify-ledger.test.ts +1249 -0
- package/src/execution/__tests__/output-collector.test.ts +117 -6
- package/src/execution/__tests__/pi-invocation.test.ts +1 -1
- package/src/execution/__tests__/record-store-orphan-revive.test.ts +159 -0
- package/src/execution/__tests__/record-store.test.ts +89 -5
- package/src/execution/__tests__/records-cwd-isolation.test.ts +2 -2
- package/src/execution/__tests__/recursive-visibility-baseline.test.ts +29 -132
- package/src/execution/__tests__/recursive-visibility-env.test.ts +55 -179
- package/src/execution/__tests__/rpc-mode.test.ts +2 -2
- package/src/execution/__tests__/run-and-finalize-anchoring.test.ts +387 -0
- package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +19 -9
- package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +5 -4
- package/src/execution/__tests__/run-spawn-edges.test.ts +418 -26
- package/src/execution/__tests__/run-spawn-integration.test.ts +3 -3
- package/src/execution/__tests__/run-spawn-resume.test.ts +2 -2
- package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +2 -2
- package/src/execution/__tests__/run-spawn-stdout-callback-throw.test.ts +16 -8
- package/src/execution/__tests__/service-kill-escalation.test.ts +91 -0
- package/src/execution/__tests__/session-context-resolver.test.ts +0 -2
- package/src/execution/__tests__/session-file-gc.test.ts +35 -0
- package/src/execution/__tests__/session-pending.test.ts +471 -0
- package/src/execution/__tests__/session-reconstructor.test.ts +366 -15
- package/src/execution/__tests__/session-runner-branch-cache-lru.test.ts +110 -0
- package/src/execution/__tests__/session-runner-close-prune.test.ts +181 -0
- package/src/execution/__tests__/session-runner-dispatch.test.ts +489 -0
- package/src/execution/__tests__/session-runner-epipe.test.ts +4 -3
- package/src/execution/__tests__/session-runner-heartbeat-idle-fallback.test.ts +227 -0
- package/src/execution/__tests__/session-runner-lifecycle-helpers.test.ts +290 -0
- package/src/execution/__tests__/session-runner-schema-env.test.ts +7 -5
- package/src/execution/__tests__/settled-watchdog.test.ts +524 -0
- package/src/execution/__tests__/spawn-args.test.ts +11 -10
- package/src/execution/__tests__/spawn-event-adapter-rpc.test.ts +26 -23
- package/src/execution/__tests__/spawn-event-adapter.test.ts +1 -1
- package/src/execution/__tests__/spawn-worktree-guidance.test.ts +5 -4
- package/src/execution/__tests__/spawned-children.test.ts +155 -11
- package/src/execution/__tests__/start-sync-model-guard.test.ts +4 -4
- package/src/execution/__tests__/stdin-writer.test.ts +6 -4
- package/src/execution/__tests__/stream-sink-retirement.test.ts +6 -6
- package/src/execution/__tests__/subagent-actions-core.test.ts +1017 -0
- package/src/execution/__tests__/subagent-service-message-close.test.ts +99 -35
- package/src/execution/__tests__/subagent-service-multiproc-guard.test.ts +174 -0
- package/src/execution/__tests__/subagent-service-notify-gate.test.ts +271 -0
- package/src/execution/__tests__/subagent-service-parent-guard.test.ts +33 -29
- package/src/execution/__tests__/subagent-service-recovery-bounds.test.ts +341 -0
- package/src/execution/__tests__/subagent-service.test.ts +37 -30
- package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +88 -12
- package/src/execution/__tests__/subprocess-agent-runner-timeout.test.ts +75 -0
- package/src/execution/__tests__/subprocess-agent-runner.test.ts +22 -20
- package/src/execution/__tests__/temp-prompt.test.ts +1 -1
- package/src/execution/__tests__/timeout-integration.test.ts +13 -12
- package/src/execution/__tests__/turn-limiter-semantics.test.ts +1 -1
- package/src/execution/__tests__/turn-limiter.test.ts +1 -1
- package/src/execution/__tests__/ui-request-handler-factory.test.ts +107 -7
- package/src/execution/__tests__/ui-request-handler.test.ts +4 -3
- package/src/execution/__tests__/ui-request-queue.test.ts +167 -2
- package/src/execution/__tests__/worktree-git-ops.test.ts +571 -0
- package/src/execution/__tests__/worktree-manager.test.ts +14 -5
- package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +4 -3
- package/src/execution/__tests__/worktree-reconcile-aging.test.ts +204 -0
- package/src/execution/agent-registry.ts +298 -30
- package/src/execution/agent-result-mapper.ts +3 -0
- package/src/execution/agents-assembly.ts +88 -0
- package/src/execution/cold-resurrect.ts +199 -0
- package/src/execution/concurrency-pool.ts +71 -9
- package/src/execution/dialog-queue.ts +101 -3
- package/src/execution/engine/__tests__/common/capability-gate.test.ts +91 -0
- package/src/execution/engine/__tests__/common/data-dir.test.ts +1 -1
- package/src/execution/engine/__tests__/common/journal-wiring.test.ts +84 -0
- package/src/execution/engine/__tests__/common/kill-chain.test.ts +34 -7
- package/src/execution/engine/__tests__/common/persona-router.test.ts +4 -5
- package/src/execution/engine/__tests__/common/pool-manager.test.ts +211 -51
- package/src/execution/engine/__tests__/common/session-view-service-zcode-dbpath.test.ts +149 -0
- package/src/execution/engine/__tests__/common/session-view-service.test.ts +499 -0
- package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +56 -99
- package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +88 -15
- package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +33 -7
- package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +1 -1
- package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +75 -54
- package/src/execution/engine/__tests__/conformance/zcode-appserver-harness.ts +128 -0
- package/src/execution/engine/__tests__/engine-discovery.test.ts +15 -3
- package/src/execution/engine/__tests__/model-prompt.test.ts +15 -3
- package/src/execution/engine/__tests__/registry.test.ts +94 -3
- package/src/execution/engine/__tests__/routing.test.ts +115 -6
- package/src/execution/engine/common/capability-gate.ts +92 -0
- package/src/execution/engine/common/journal-wiring.ts +97 -0
- package/src/execution/engine/common/kill-chain.ts +42 -10
- package/src/execution/engine/common/nesting-guard.ts +66 -0
- package/src/execution/engine/common/persona-router.ts +18 -8
- package/src/execution/engine/common/pool-manager.ts +332 -78
- package/src/execution/engine/common/session-view-service.ts +506 -0
- package/src/execution/engine/common/session-view-types.ts +125 -0
- package/src/execution/engine/engine-discovery.ts +12 -16
- package/src/execution/engine/engines/pi/__tests__/pi-engine.test.ts +174 -28
- package/src/execution/engine/engines/pi/__tests__/spawn-opts-direct.test.ts +257 -0
- package/src/execution/{argv-mirror.ts → engine/engines/pi/argv-mirror.ts} +43 -21
- package/src/execution/{get-state-handshake.ts → engine/engines/pi/get-state-handshake.ts} +86 -11
- package/src/execution/{output-collector.ts → engine/engines/pi/output-collector.ts} +108 -19
- package/src/execution/engine/engines/pi/pi-engine.ts +434 -38
- package/src/execution/{pi-invocation.ts → engine/engines/pi/pi-invocation.ts} +2 -2
- package/src/execution/engine/engines/pi/reader.ts +11 -0
- package/src/execution/engine/engines/pi/registration.ts +4 -2
- package/src/execution/engine/engines/pi/session-runner.ts +2840 -0
- package/src/execution/{spawn-event-adapter.ts → engine/engines/pi/spawn-event-adapter.ts} +75 -34
- package/src/execution/{stdin-writer.ts → engine/engines/pi/stdin-writer.ts} +10 -9
- package/src/execution/{temp-prompt.ts → engine/engines/pi/temp-prompt.ts} +2 -2
- package/src/execution/{turn-limiter.ts → engine/engines/pi/turn-limiter.ts} +1 -1
- package/src/execution/engine/engines/zcode/__tests__/__fixtures__/fake-appserver.mjs +301 -0
- package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-appserver.json +36 -0
- package/src/execution/engine/engines/zcode/__tests__/appserver-launcher.test.ts +321 -0
- package/src/execution/engine/engines/zcode/__tests__/connection.test.ts +473 -0
- package/src/execution/engine/engines/zcode/__tests__/parser.test.ts +7 -210
- package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +6 -110
- package/src/execution/engine/engines/zcode/__tests__/session-channel-dispose-harvest.test.ts +247 -0
- package/src/execution/engine/engines/zcode/__tests__/session-channel-turn-timers.test.ts +451 -0
- package/src/execution/engine/engines/zcode/__tests__/session-channel.test.ts +792 -0
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-appserver.test.ts +782 -0
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-degrade.test.ts +168 -0
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-dispose.test.ts +210 -0
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-retry.test.ts +353 -0
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-status.test.ts +282 -0
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-timeout.test.ts +372 -0
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +65 -47
- package/src/execution/engine/engines/zcode/appserver-launcher.ts +167 -0
- package/src/execution/engine/engines/zcode/connection.ts +598 -0
- package/src/execution/engine/engines/zcode/constants.ts +147 -14
- package/src/execution/engine/engines/zcode/golden-sample.ts +42 -34
- package/src/execution/engine/engines/zcode/parser.ts +12 -346
- package/src/execution/engine/engines/zcode/preparer.ts +22 -150
- package/src/execution/engine/engines/zcode/session-channel.ts +968 -0
- package/src/execution/engine/engines/zcode/zcode-engine.ts +1023 -250
- package/src/execution/engine/host-task-spec.ts +32 -36
- package/src/execution/engine/model-validation.ts +177 -0
- package/src/execution/engine/port.ts +65 -7
- package/src/execution/engine/registry.ts +53 -0
- package/src/execution/engine/routing.ts +75 -1
- package/src/execution/engine/types.ts +30 -103
- package/src/execution/execution-record.ts +222 -144
- package/src/execution/finalize-record.ts +181 -85
- package/src/execution/idle-gc.ts +28 -0
- package/src/execution/lifecycle-manager.ts +27 -3
- package/src/execution/lifecycle-predicates.ts +1 -1
- package/src/execution/manifest-store.ts +53 -62
- package/src/execution/notifier.ts +10 -10
- package/src/execution/notify-host.ts +212 -0
- package/src/execution/notify-ledger.ts +117 -16
- package/src/execution/record-entry.ts +8 -2
- package/src/execution/record-store.ts +148 -88
- package/src/execution/round-settlement.ts +93 -0
- package/src/execution/session-file-gc.ts +96 -62
- package/src/execution/session-pending.ts +213 -62
- package/src/execution/session-reconstructor.ts +256 -143
- package/src/execution/sessions-index.ts +127 -102
- package/src/execution/settled-watchdog.ts +311 -0
- package/src/execution/subagent-actions-core.ts +686 -0
- package/src/execution/subagent-service.ts +1106 -907
- package/src/execution/subprocess-agent-runner.ts +144 -97
- package/src/execution/types.ts +9 -0
- package/src/execution/ui-request-handler-factory.ts +126 -75
- package/src/execution/ui-request-queue.ts +50 -19
- package/src/execution/worktree-git-ops.ts +397 -0
- package/src/execution/worktree-manager.ts +72 -10
- package/src/execution/worktree-registry.ts +6 -12
- package/src/index.ts +542 -9
- package/src/orchestration/__tests__/__fixtures__/worker-template.snapshot.txt +42 -3
- package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +3 -5
- package/src/orchestration/__tests__/agent-call-stream.test.ts +2 -2
- package/src/orchestration/__tests__/args-meta.test.ts +358 -0
- package/src/orchestration/__tests__/args-validator.test.ts +14 -0
- package/src/orchestration/__tests__/error-recovery-rebuild-failure.test.ts +312 -0
- package/src/orchestration/__tests__/error-recovery-terminal-hardening.test.ts +384 -0
- package/src/orchestration/__tests__/execute-agent-call.test.ts +151 -11
- package/src/orchestration/__tests__/file-run-store-prune.test.ts +168 -0
- package/src/orchestration/__tests__/file-run-store-throttle.test.ts +168 -0
- package/src/orchestration/__tests__/file-run-store.test.ts +390 -0
- package/src/orchestration/__tests__/helpers/flush-microtasks.ts +13 -0
- package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +34 -0
- package/src/orchestration/__tests__/lifecycle-abort-broadcast-signal.test.ts +357 -0
- package/src/orchestration/__tests__/lifecycle-recover-crashed.test.ts +289 -0
- package/src/orchestration/__tests__/lifecycle-runid-injection.test.ts +3 -3
- package/src/orchestration/__tests__/lifecycle.test.ts +84 -5
- package/src/orchestration/__tests__/non-cloneable-return-e2e.test.ts +1 -1
- package/src/orchestration/__tests__/run-snapshot.test.ts +356 -0
- package/src/orchestration/__tests__/script-generate.test.ts +314 -0
- package/src/orchestration/__tests__/script-lint.test.ts +17 -0
- package/src/orchestration/__tests__/test-mocks.ts +2 -0
- package/src/orchestration/__tests__/worker-exit-without-result.test.ts +7 -6
- package/src/orchestration/__tests__/worker-message-pump-finalize-run.test.ts +229 -0
- package/src/orchestration/__tests__/{error-recovery-handlers.test.ts → worker-message-pump-handlers.test.ts} +28 -27
- package/src/orchestration/__tests__/{error-recovery-postmessage-defense.test.ts → worker-message-pump-postmessage-defense.test.ts} +8 -8
- package/src/orchestration/__tests__/{error-recovery-serialize-failed-result.test.ts → worker-message-pump-serialize-failed-result.test.ts} +2 -2
- package/src/orchestration/__tests__/{error-recovery-workflow-call.test.ts → worker-message-pump-workflow-call.test.ts} +1 -1
- package/src/orchestration/__tests__/worker-pending-timeout-abort.test.ts +275 -0
- package/src/orchestration/__tests__/worker-script-builder-runtime.test.ts +78 -1
- package/src/orchestration/__tests__/worker-script-builder.test.ts +1 -1
- package/src/orchestration/__tests__/workflow-files.test.ts +186 -0
- package/src/orchestration/__tests__/workflow-nesting-e2e.test.ts +1 -1
- package/src/orchestration/__tests__/workflow-run-summary.test.ts +119 -0
- package/src/orchestration/__tests__/workflow-script-registry-impl.test.ts +124 -0
- package/src/orchestration/agent-opts-resolver.ts +8 -8
- package/src/orchestration/args-meta.ts +198 -0
- package/src/orchestration/args-validator.ts +53 -31
- package/src/orchestration/execute-agent-call.ts +25 -79
- package/src/orchestration/file-run-store.ts +327 -0
- package/src/orchestration/launcher.ts +160 -104
- package/src/orchestration/lifecycle.ts +371 -97
- package/src/orchestration/models/agent-call.ts +7 -7
- package/src/orchestration/models/budget.ts +5 -5
- package/src/orchestration/models/ports.ts +4 -4
- package/src/orchestration/models/run-runtime.ts +15 -15
- package/src/orchestration/models/trace.ts +9 -9
- package/src/orchestration/models/types.ts +111 -22
- package/src/orchestration/models/workflow-run.ts +28 -28
- package/src/orchestration/models/workflow-script.ts +4 -4
- package/src/orchestration/run-snapshot.ts +266 -0
- package/src/orchestration/script-generate.ts +154 -0
- package/src/orchestration/script-lint.ts +123 -90
- package/src/orchestration/worker-handle.ts +10 -10
- package/src/orchestration/worker-host.ts +10 -10
- package/src/orchestration/{error-recovery.ts → worker-message-pump.ts} +498 -221
- package/src/orchestration/worker-script-builder.ts +401 -346
- package/src/orchestration/workflow-files.ts +37 -11
- package/src/orchestration/workflow-run-summary.ts +69 -0
- package/src/orchestration/workflow-script-registry-impl.ts +31 -9
- package/src/shared/__tests__/agent-ref.test.ts +209 -2
- package/src/shared/__tests__/atomic-write.test.ts +267 -0
- package/src/shared/__tests__/bounded-serialize.test.ts +236 -0
- package/src/shared/__tests__/injection-render.test.ts +518 -0
- package/src/shared/__tests__/meta-parser.test.ts +151 -0
- package/src/shared/__tests__/resource-discovery-host-roots.test.ts +474 -0
- package/src/shared/__tests__/resource-discovery.test.ts +261 -217
- package/src/shared/agent-ref.ts +143 -2
- package/src/shared/atomic-write.ts +323 -0
- package/src/shared/bounded-serialize.ts +154 -0
- package/src/shared/injection-render.ts +279 -0
- package/src/shared/meta-parser.ts +182 -68
- package/src/shared/model-ref.ts +15 -2
- package/src/shared/resource-discovery.ts +97 -204
- package/src/shared/resource-meta.ts +14 -0
- package/src/shared/schema-jsonify.ts +1 -1
- package/src/shared/xml-injection.ts +9 -9
- package/workflows/README.md +9 -9
- package/workflows/chain.js +4 -2
- package/workflows/map-reduce.js +5 -3
- package/workflows/parallel.js +5 -3
- package/workflows/review-fix-loop-utils.cjs +165 -92
- package/workflows/review-fix-loop-utils.d.cts +287 -0
- package/workflows/review-fix-loop.js +18 -7
- package/workflows/scatter-gather.js +4 -2
- package/dist/chunk-3VOERJPJ.js +0 -22
- package/src/execution/__tests__/execute-options-mapper.test.ts +0 -200
- package/src/execution/engine/engines/pi/__tests__/task-spec-mapper.test.ts +0 -164
- package/src/execution/engine/engines/pi/task-spec-mapper.ts +0 -100
- package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-spawn.json +0 -39
- package/src/execution/engine/engines/zcode/__tests__/launcher.test.ts +0 -150
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine.test.ts +0 -580
- package/src/execution/engine/engines/zcode/launcher.ts +0 -161
- package/src/execution/execute-options-mapper.ts +0 -115
- package/src/execution/session-runner.ts +0 -1789
- package/src/shared/__tests__/resource-discovery-manifest-cache.test.ts +0 -288
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
// [D4-① 通知簇职责轴] background 完成通知的 host 面——原 SubagentService 私有通知簇
|
|
2
|
+
// (notifyComplete / notifyClosed / piAdapter / toNotifyRecord / emitPendingRegister /
|
|
3
|
+
// emitPendingUnregister + notifier 实例持有)整体搬移至此(行为逐字节等价:搬移 +
|
|
4
|
+
// 依赖注入,不重写逻辑)。变化轴:改通知文案 / dedup 身份 / 放行守卫 / pending 注册
|
|
5
|
+
// 注销协议,只改本文件;Service 只保留编排与依赖注入(getPi / listRunning / isIdle)。
|
|
6
|
+
|
|
7
|
+
import { displayAgentName } from "../shared/agent-ref.ts";
|
|
8
|
+
import { snapshot } from "./execution-record.ts";
|
|
9
|
+
import { hasIdleTimer } from "./lifecycle-manager.ts";
|
|
10
|
+
import { hasLiveProcessHandle, isIdle, isResumable } from "./lifecycle-predicates.ts";
|
|
11
|
+
import type { BgNotifier, NotifierHost } from "./notifier.ts";
|
|
12
|
+
import { createNotifier } from "./notifier.ts";
|
|
13
|
+
import type { BgNotifyRecord } from "./notifier.ts";
|
|
14
|
+
import type { ExecutionRecord, RecordSnapshot } from "./types.ts";
|
|
15
|
+
|
|
16
|
+
/** Pi ExtensionAPI 的最小接口(duck-typed)——原定义于 subagent-service.ts,随通知簇
|
|
17
|
+
* (piAdapter / emitPending* 的依赖)搬移至此并导出(Service 的 session 注入参数仍引用)。
|
|
18
|
+
* subagent-service 直接调 pi.sendMessage 发 background 完成通知(BgNotifier 滑动窗口合并),
|
|
19
|
+
* 不委托 pending-notifications EventBus 中继——后者只管 registry 不参与通知发送。 */
|
|
20
|
+
export interface PiLike {
|
|
21
|
+
appendEntry(customType: string, data?: unknown): void;
|
|
22
|
+
events: { emit(channel: string, data: unknown): void };
|
|
23
|
+
sendMessage(
|
|
24
|
+
message: { customType: string; content: string; display: boolean; details?: unknown },
|
|
25
|
+
options?: { triggerTurn?: boolean; deliverAs?: "steer" | "followUp" | "nextTurn" }, // g4-allow: 类型注解——PiLike 接口形状(pi.sendMessage 签面子集),非投递调用
|
|
26
|
+
): void;
|
|
27
|
+
/** 订阅 pi 事件(D8:notifier 的 settled 边沿订阅用 'agent_settled')。
|
|
28
|
+
* pi 0.84.1 的 on 返回 void 且无 off——退订语义由调用侧 disposed 标志包装兑现。
|
|
29
|
+
* 可选:旧测试 mock pi 可能未实现 on,缺省时 notifier 退化为内核退避路径。 */
|
|
30
|
+
on?(event: "agent_settled", handler: () => void): void;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** NotifyHost 的依赖注入(Service 侧供给,全部惰性求值——pi/session 级状态运行时可变)。 */
|
|
34
|
+
export interface NotifyHostDeps {
|
|
35
|
+
/** 当前 pi session handle(session_start 注入 / shutdown 置 null)。 */
|
|
36
|
+
getPi: () => PiLike | null;
|
|
37
|
+
/** store 的 running record 快照(piAdapter.hasRunningBackground 用)。 */
|
|
38
|
+
listRunning: () => RecordSnapshot[];
|
|
39
|
+
/** 主 agent isIdle 查询(ctx.isIdle,initSession 注入;未注入时 undefined)。 */
|
|
40
|
+
getIsIdle: () => (() => boolean) | undefined;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** 通知簇 host 面(Service 经此消费;notifier 实例封装在内部不外露)。 */
|
|
44
|
+
export interface NotifyHost {
|
|
45
|
+
/** background 完成回注(原 Service.notifyComplete)。 */
|
|
46
|
+
notifyComplete(record: ExecutionRecord): void;
|
|
47
|
+
/** [C-1] chatMode close 终态通知(原 Service.notifyClosed)。 */
|
|
48
|
+
notifyClosed(record: ExecutionRecord, emptyBody?: boolean): void;
|
|
49
|
+
/** pending-notifications 注册(原模块函数 emitPendingRegister,pi 经 deps 取)。 */
|
|
50
|
+
emitPendingRegister(id: string, name?: string): void;
|
|
51
|
+
/** pending-notifications 注销(原模块函数 emitPendingUnregister)。 */
|
|
52
|
+
emitPendingUnregister(id: string, reason: string): void;
|
|
53
|
+
/** dispose 的逆操作(initSession 复活,原 notifier.revive 委托)。 */
|
|
54
|
+
revive(): void;
|
|
55
|
+
/** dispose 前冲刷待发通知(原 notifier.flushPendingNotifications 委托)。 */
|
|
56
|
+
flushPendingNotifications(): void;
|
|
57
|
+
/** 丢弃 pending 通知(原 notifier.dispose 委托)。 */
|
|
58
|
+
dispose(): void;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** pending-notifications 注册/注销 helper(避免重复代码)。
|
|
62
|
+
* name 是 GUI pending 通知的显示名——取 basename 短名(displayAgentName),
|
|
63
|
+
* 完整路径仍走 record.agent(env 注入 / 持久化)。 */
|
|
64
|
+
function emitPendingRegister(pi: PiLike | null, id: string, name?: string): void {
|
|
65
|
+
pi?.events.emit("pending:register", {
|
|
66
|
+
id,
|
|
67
|
+
type: "subagent",
|
|
68
|
+
name: name ? displayAgentName(name) : id,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function emitPendingUnregister(
|
|
73
|
+
pi: PiLike | null,
|
|
74
|
+
id: string,
|
|
75
|
+
reason: string,
|
|
76
|
+
): void {
|
|
77
|
+
pi?.events.emit("pending:unregister", {
|
|
78
|
+
id,
|
|
79
|
+
reason,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** 通知簇工厂:notifier 实例随本函数创建并封装(原 Service 构造器
|
|
84
|
+
* `createNotifier(this.piAdapter())` 的等价形态)。 */
|
|
85
|
+
export function createNotifyHost(deps: NotifyHostDeps): NotifyHost {
|
|
86
|
+
/** notifier 的 NotifierHost 适配器(绑定到 pi.sendMessage + store 查询)。 */
|
|
87
|
+
const piAdapter = (): NotifierHost => {
|
|
88
|
+
return {
|
|
89
|
+
sendMessage: (message, options) => {
|
|
90
|
+
deps.getPi()?.sendMessage(message, options);
|
|
91
|
+
},
|
|
92
|
+
hasRunningBackground: () => {
|
|
93
|
+
// [M3] 「在跑的 background 工作」= 有活进程且非等待续聊(idle timer armed)。
|
|
94
|
+
// v4 B-1 把旧 idle 折入 running 且 record 留 store:轮次完成的 chatMode record
|
|
95
|
+
// (timer armed、无在跑轮)与 one-shot 完成后等待 message 升级的 record 都不再计入。
|
|
96
|
+
// 旧判定 `mode === "background"` 对这两类恒 true → 轮次完成通知恒挂 60s 合并窗口
|
|
97
|
+
// (notifier MERGE_WINDOW_MS),主 agent 的续聊回复固定延迟 60s 送达,持续对话(G1)失效。
|
|
98
|
+
return deps.listRunning().some(
|
|
99
|
+
(r) => r.mode === "background" && hasLiveProcessHandle(r.id) && !hasIdleTimer(r.id),
|
|
100
|
+
);
|
|
101
|
+
},
|
|
102
|
+
isIdle: () => deps.getIsIdle()?.() ?? true,
|
|
103
|
+
// [must-fix #4 / D8] settled 边沿订阅,与 isIdle 同源(session_start 注入的 pi)。
|
|
104
|
+
// 只注入原生订阅能力;disposed 标志包装(退订语义)在 notifier 的 port 装配完成。
|
|
105
|
+
onAgentSettled: (handler) => { deps.getPi()?.on?.("agent_settled", handler); },
|
|
106
|
+
};
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const notifier: BgNotifier = createNotifier(piAdapter());
|
|
110
|
+
|
|
111
|
+
/** record → BgNotifyRecord(notifier.notify 入参映射,内部不外露)。
|
|
112
|
+
* v4 B-1:守卫放行 closed(终态,含 cancelled)、isIdle(对话模式轮次完成,notify 主 agent G1)
|
|
113
|
+
* 或 isResumable(running + 无活进程——SP-5 one-shot 成功完成 / MF-6 失败轮回退)。
|
|
114
|
+
* 正在执行(running + 活进程 + 非 timer-armed)返回 undefined(调用方 notifyComplete 跳过)。
|
|
115
|
+
* SP-1: closed 统一终态,closedReason 由 BgNotifyRecord 携带。 */
|
|
116
|
+
const toNotifyRecord = (record: ExecutionRecord): BgNotifyRecord | undefined => {
|
|
117
|
+
const snap = snapshot(record);
|
|
118
|
+
const s = snap.status;
|
|
119
|
+
// [N1] isResumable 放行:SP-5 one-shot 成功完成后 finalizeRoundToIdle 把 record 回退
|
|
120
|
+
// running-resumable——进程已死且永不 arm idle timer(armIdleTimer 只在 agent_settled 的
|
|
121
|
+
// chatMode 分支调用),旧守卫(closed / isIdle only)对其恒拒绝 → 完成通知静默丢失,
|
|
122
|
+
// 而 one-shot 失败走 finalizeRecord 保持 closed 反而通知——与 tool 契约「runs once,
|
|
123
|
+
// notifies on completion」完全倒置。isResumable = running + 无活进程,恰为该完成态;
|
|
124
|
+
// 在跑轮的 record 有活进程,不会被误放行。
|
|
125
|
+
if (s !== "closed" && !isIdle(record) && !isResumable(record)) return undefined;
|
|
126
|
+
// closed → BgNotifyRecord.closed(cancelled 区分靠 closedReason);chatMode 的 isIdle/
|
|
127
|
+
// isResumable(轮次完成或 MF-6 失败轮回退,对话可续)→ running(轮次完成)。
|
|
128
|
+
// isResumable 且非 chatMode(SP-5 one-shot 成功完成)→ closed:对主 agent 的语义是
|
|
129
|
+
// completed(非对话轮次),且只有 closed 分支文案携带 worktree patchFile 的 git apply
|
|
130
|
+
// 提示——one-shot worktree 模式的改动回收依赖该提示(running 分支文案不含 patchFile)。
|
|
131
|
+
const notifyStatus: BgNotifyRecord["status"] =
|
|
132
|
+
s === "closed" || !record.chatMode ? "closed" : "running";
|
|
133
|
+
return {
|
|
134
|
+
id: snap.id,
|
|
135
|
+
status: notifyStatus,
|
|
136
|
+
agent: snap.agent,
|
|
137
|
+
model: snap.model,
|
|
138
|
+
result: snap.result,
|
|
139
|
+
error: snap.error,
|
|
140
|
+
startedAt: snap.startedAt,
|
|
141
|
+
endedAt: snap.endedAt,
|
|
142
|
+
patchFile: record.patchFile,
|
|
143
|
+
// round 透传给 notifier 的 dedup key(对话模式按轮次去重,G1 决策 9)。
|
|
144
|
+
round: record.round,
|
|
145
|
+
// SP-1: closedReason 透传给 notifier(L2 原因,供通知文案按需展示)。
|
|
146
|
+
closedReason: record.closedReason,
|
|
147
|
+
// [wave2] chatMode 条件透传 sessionFile:通知末尾追加 Full transcript 指针行
|
|
148
|
+
//(增量语义的全文恢复通道,见 notifier.buildLlmContent)。one-shot(chatMode
|
|
149
|
+
// falsy)不透传——通知输出逐字节不变(G4),该条件由 message-close 测试的
|
|
150
|
+
// 必选用例锁死(漏加条件时 notifier 单测不红——notifier 层只见最终字段)。
|
|
151
|
+
sessionFile: record.chatMode ? record.sessionFile : undefined,
|
|
152
|
+
};
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
/** background 完成回注(record → BgNotifyRecord 映射 + notifier.notify)。
|
|
157
|
+
* 正在执行(running + 活进程 + 非 timer-armed)静默跳过——notify 只对 closed(终态)、
|
|
158
|
+
* isIdle(chatMode 轮次完成)或 isResumable(SP-5 one-shot 成功完成 / MF-6 失败轮回退)有意义。
|
|
159
|
+
* SP-1: closed 统一终态(done/failed/crashed 合并),closedReason 携带 L2 原因。 */
|
|
160
|
+
notifyComplete(record: ExecutionRecord): void {
|
|
161
|
+
const notify = toNotifyRecord(record);
|
|
162
|
+
if (notify) notifier.notify(notify);
|
|
163
|
+
},
|
|
164
|
+
|
|
165
|
+
/** [C-1] chatMode close 终态通知(设计 D2:正文空/本轮增量 + sessionFile 指针行)。
|
|
166
|
+
*
|
|
167
|
+
* 与 notifyComplete 的差异只在 dedup 身份与轮次统计:终态通知必须与最后一轮的轮次通知
|
|
168
|
+
* 区分(轮次通知 key=`id:round`),否则同 key 被 60s dedup 吞——close 后父 agent 永远
|
|
169
|
+
* 收不到带指针行的终态通知(审查 C-1)。故 round 置 undefined(key 回退为裸 id),
|
|
170
|
+
* 轮数改经 totalRounds 进文案 "completed after N rounds."(C-2)。
|
|
171
|
+
*
|
|
172
|
+
* 仅 chatMode close 语义调用(closeChatIdle / closeAfterRoundSettled 终态化成功后)。
|
|
173
|
+
* one-shot 显式拒绝(G4:one-shot close 路径现状无终态通知,字节不变);cancel 走
|
|
174
|
+
* cancelBackground 自己的 notifyComplete,不经本方法。幂等性:两条 close 路径均由
|
|
175
|
+
* closeSubagent 的 status 分流守卫(closed 后幂等 no-op)/ CAS 抢锁保证只执行一次,
|
|
176
|
+
* 本方法自身不重复发送;迟到的轮次收尾 .then 通知与轮次通知同 key=`id:round`,
|
|
177
|
+
* 60s 窗内仍被吞,不构成第三条。 */
|
|
178
|
+
/** @param emptyBody true = 终态通知正文置空串(D2 路径②)。W16 P-1 修复后
|
|
179
|
+
* closeChatIdle 的 doneResult.text 改用 record.result 保真(close 终态
|
|
180
|
+
* subagent-record entry 的 result 不抹空轮终真实值),「正文空」不再由合成空
|
|
181
|
+
* text 的副作用承载,改为显式参数——持久化 result 与通知正文两个关注点解耦。 */
|
|
182
|
+
notifyClosed(record: ExecutionRecord, emptyBody = false): void {
|
|
183
|
+
if (!record.chatMode) return;
|
|
184
|
+
const notify = toNotifyRecord(record);
|
|
185
|
+
if (!notify) return;
|
|
186
|
+
notify.round = undefined;
|
|
187
|
+
if (emptyBody) notify.result = "";
|
|
188
|
+
if (record.round != null) notify.totalRounds = record.round;
|
|
189
|
+
notifier.notify(notify);
|
|
190
|
+
},
|
|
191
|
+
|
|
192
|
+
emitPendingRegister(id: string, name?: string): void {
|
|
193
|
+
emitPendingRegister(deps.getPi(), id, name);
|
|
194
|
+
},
|
|
195
|
+
|
|
196
|
+
emitPendingUnregister(id: string, reason: string): void {
|
|
197
|
+
emitPendingUnregister(deps.getPi(), id, reason);
|
|
198
|
+
},
|
|
199
|
+
|
|
200
|
+
revive(): void {
|
|
201
|
+
notifier.revive();
|
|
202
|
+
},
|
|
203
|
+
|
|
204
|
+
flushPendingNotifications(): void {
|
|
205
|
+
notifier.flushPendingNotifications();
|
|
206
|
+
},
|
|
207
|
+
|
|
208
|
+
dispose(): void {
|
|
209
|
+
notifier.dispose();
|
|
210
|
+
},
|
|
211
|
+
};
|
|
212
|
+
}
|
|
@@ -21,10 +21,16 @@
|
|
|
21
21
|
// D5);同一边沿的多条 pending 合并为一条注入
|
|
22
22
|
// ③ ack:回执判定成功(主 session 出现 notifyId 匹配的 subagent-bg-notify
|
|
23
23
|
// custom_message entry)后 appendEntry("subagent-bg-notify-ack")
|
|
24
|
-
// ④ replay:重启恢复扫描 ledger/ack
|
|
24
|
+
// ④ replay:重启恢复扫描 ledger/ack/abandoned entry 差集重放;重放按 notifyId 幂等去重
|
|
25
25
|
// (details 携带 notifyId,重复条目可识别)
|
|
26
26
|
//
|
|
27
|
-
//
|
|
27
|
+
// 止损上半场(T4③/PS-6):④只保证「送达保证」下半场,回执确认不可达时(如送达
|
|
28
|
+
// entry 被 compaction 清除)attempts 无上限 = 同一条通知每 120s 重复注入并
|
|
29
|
+
// triggerTurn 无限唤醒 LLM。收敛:重投达 NOTIFY_REDELIVERY_MAX_ATTEMPTS 仍无回执 →
|
|
30
|
+
// 写 abandoned 终态 entry 放弃(warn 含 subagent 标识与 subagents action:"list"
|
|
31
|
+
// 手动核对指引),放弃号跨重启不复活(恢复扫描视同已销账)。
|
|
32
|
+
//
|
|
33
|
+
// 通道分工(D4):ledger/ack/abandoned 用 plain appendEntry(type=custom 不进 LLM 上下文——
|
|
28
34
|
// session-manager sessionEntryToContextMessages 对 custom 返回 []);送达消息用
|
|
29
35
|
// pi.sendMessage({triggerTurn:true})(custom_message 进上下文)。两通道不得混用。
|
|
30
36
|
//
|
|
@@ -49,6 +55,11 @@ const logger = getLogger("subagents");
|
|
|
49
55
|
export const NOTIFY_LEDGER_CUSTOM_TYPE = "subagent-bg-notify-ledger";
|
|
50
56
|
/** 销账 entry customType(plain custom entry,不进 LLM 上下文)。 */
|
|
51
57
|
export const NOTIFY_ACK_CUSTOM_TYPE = "subagent-bg-notify-ack";
|
|
58
|
+
/**
|
|
59
|
+
* [T4③/PS-6] 放弃终态 entry customType(plain custom entry,不进 LLM 上下文)。
|
|
60
|
+
* 与 ack 同形同域:恢复/compaction 扫描把它视同已销账——放弃条目跨重启不复活。
|
|
61
|
+
*/
|
|
62
|
+
export const NOTIFY_ABANDONED_CUSTOM_TYPE = "subagent-bg-notify-abandoned";
|
|
52
63
|
|
|
53
64
|
/**
|
|
54
65
|
* 送达消息的 customType。notifier.ts / bg-notify-render / index.ts(messageRenderer
|
|
@@ -65,6 +76,14 @@ export const NOTIFY_CUSTOM_TYPE = "subagent-bg-notify";
|
|
|
65
76
|
*/
|
|
66
77
|
export const NOTIFY_WATCHDOG_MS = 120_000;
|
|
67
78
|
|
|
79
|
+
/**
|
|
80
|
+
* [T4③/PS-6] 单条通知投递尝试上限(attempts 字段含首次投递):看门狗把 sent 超期
|
|
81
|
+
* 条目转回 pending 前,attempts 已达本上限 → 不再重投,转放弃终态(abandoned entry
|
|
82
|
+
* + warn 恢复指引)。被否语义:「重投无限但幂等」——幂等只防重复入账,不防重复
|
|
83
|
+
* 投递唤醒 LLM(设计 docs/design/subagent-core-unbounded-wait-audit.md §7.2 T4③)。
|
|
84
|
+
*/
|
|
85
|
+
export const NOTIFY_REDELIVERY_MAX_ATTEMPTS = 5;
|
|
86
|
+
|
|
68
87
|
/**
|
|
69
88
|
* U4 投递计数分桶(设计 §5 U4:分桶口径与 §2.2 三条丢失路径一一对应,回归时定位到
|
|
70
89
|
* 具体环节):
|
|
@@ -103,16 +122,22 @@ export interface NotifyAckEntryData {
|
|
|
103
122
|
notifyId: string;
|
|
104
123
|
}
|
|
105
124
|
|
|
125
|
+
/** [T4③/PS-6] abandoned entry 的 data schema(v1,与 ack 同形——终态标记只需身份键)。 */
|
|
126
|
+
export interface NotifyAbandonedEntryData {
|
|
127
|
+
v: 1;
|
|
128
|
+
notifyId: string;
|
|
129
|
+
}
|
|
130
|
+
|
|
106
131
|
/** ledger 依赖的宿主最小接口(index.ts session_start 装配;解耦便于测试)。 */
|
|
107
132
|
export interface NotifyLedgerHost {
|
|
108
|
-
/** 写 plain custom entry(ledger/ack 通道;pi.appendEntry)。 */
|
|
133
|
+
/** 写 plain custom entry(ledger/ack/abandoned 通道;pi.appendEntry)。 */
|
|
109
134
|
appendLedgerEntry(customType: string, data: unknown): void;
|
|
110
135
|
/** 读当前 session 全部 entry(回执扫描 + 恢复扫描;ctx.sessionManager.getEntries())。 */
|
|
111
136
|
readSessionEntries(): readonly unknown[];
|
|
112
137
|
/** 主 agent 是否空闲(发送前二次复查用;ctx.isIdle())。 */
|
|
113
138
|
isIdle(): boolean;
|
|
114
139
|
/** 订阅 settled 边沿(pi.on("agent_settled")——无退订语义:createExtensionAPI.on
|
|
115
|
-
* 只 push 进 extension.handlers、无 off(pi 0.84.
|
|
140
|
+
* 只 push 进 extension.handlers、无 off(pi 0.84.4 loader.js:209-214),由 ledger
|
|
116
141
|
* disposed 标志包装)。注意与 ctx.events.on(channel) 消歧:后者走 eventBus、有
|
|
117
142
|
* trackEventBusSubscription 退订通路(loader.js:174、:338),语义不同。 */
|
|
118
143
|
onAgentSettled(handler: () => void): void;
|
|
@@ -128,7 +153,7 @@ interface NotifyLedgerItem {
|
|
|
128
153
|
recordedAt: number;
|
|
129
154
|
/** 最近一次投递受理时刻;undefined = 尚未投递(pending,等下一边沿)。 */
|
|
130
155
|
sentAt: number | undefined;
|
|
131
|
-
/**
|
|
156
|
+
/** 投递尝试次数(含首次;达 NOTIFY_REDELIVERY_MAX_ATTEMPTS 后超期即放弃,诊断用)。 */
|
|
132
157
|
attempts: number;
|
|
133
158
|
}
|
|
134
159
|
|
|
@@ -141,16 +166,24 @@ export interface NotifyLedger {
|
|
|
141
166
|
* 同批 pending 合并单条送达(triggerTurn 直达)。 */
|
|
142
167
|
attemptDeliver(): void;
|
|
143
168
|
/** ③ 回执销账:扫 session entries,出现 notifyId 匹配的送达 custom_message entry
|
|
144
|
-
* → appendEntry(ack) + 摘账(内存态不承担销账职责,权威 =
|
|
169
|
+
* → appendEntry(ack) + 摘账(内存态不承担销账职责,权威 = 多列 entry 差集)。 */
|
|
145
170
|
checkReceipts(): void;
|
|
146
|
-
/** ④ 重启恢复:扫 ledger/ack
|
|
171
|
+
/** ④ 重启恢复:扫 ledger/ack/abandoned entry 差集,未销账且未放弃号重新入账并投递
|
|
172
|
+
* (已销账零重发;已放弃号不复活——[T4③/PS-6] 止损终态跨重启生效)。
|
|
147
173
|
* @returns 重放条数。 */
|
|
148
174
|
recoverFromSession(): number;
|
|
149
|
-
/** compaction 降级(P-B4 未验证):检测 ledger/ack entry 被清除 → 按内存态补写。
|
|
175
|
+
/** compaction 降级(P-B4 未验证):检测 ledger/ack/abandoned entry 被清除 → 按内存态补写。
|
|
150
176
|
* @returns 补写条数。 */
|
|
151
177
|
compactionCheck(): number;
|
|
152
178
|
/** 诊断/测试:pending(已记账未投递)条数。 */
|
|
153
179
|
pendingCount(): number;
|
|
180
|
+
/**
|
|
181
|
+
* [T4④/PS-5] pending 只读快照(notifyId/content/record,副本非活引用):
|
|
182
|
+
* 供 SubagentService.dispose 在「shutdown flush 被 isIdle 门拦」时把未投递
|
|
183
|
+
* pending 复写落盘(同一 ledger entry 通道,notifyId 幂等)供重启 replay。
|
|
184
|
+
* 消费侧配合面仅此只读方法——不改变 attemptDeliver/abandon 既有语义。
|
|
185
|
+
*/
|
|
186
|
+
pendingEntries(): ReadonlyArray<{ notifyId: string; content: string; record: object }>;
|
|
154
187
|
/** 诊断/测试:已投递待回执条数。 */
|
|
155
188
|
waitingReceiptCount(): number;
|
|
156
189
|
/** U4 诊断:三桶计数快照(副本;增量同时经 extensionLogger 通道落日志)。 */
|
|
@@ -166,13 +199,15 @@ function isPlainObject(v: unknown): v is Record<string, unknown> {
|
|
|
166
199
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
167
200
|
}
|
|
168
201
|
|
|
169
|
-
/** 扫 ledger/ack
|
|
202
|
+
/** 扫 ledger/ack/abandoned 三列 plain custom entry(恢复 / compaction 检查共用)。 */
|
|
170
203
|
function scanSessionLedgerEntries(entries: readonly unknown[]): {
|
|
171
204
|
ledger: Map<string, NotifyLedgerEntryData>;
|
|
172
205
|
acked: Set<string>;
|
|
206
|
+
abandoned: Set<string>;
|
|
173
207
|
} {
|
|
174
208
|
const ledger = new Map<string, NotifyLedgerEntryData>();
|
|
175
209
|
const acked = new Set<string>();
|
|
210
|
+
const abandoned = new Set<string>();
|
|
176
211
|
for (const entry of entries) {
|
|
177
212
|
if (!isPlainObject(entry) || entry["type"] !== "custom") continue;
|
|
178
213
|
const customType = entry["customType"];
|
|
@@ -189,9 +224,11 @@ function scanSessionLedgerEntries(entries: readonly unknown[]): {
|
|
|
189
224
|
}
|
|
190
225
|
} else if (customType === NOTIFY_ACK_CUSTOM_TYPE) {
|
|
191
226
|
acked.add(notifyId);
|
|
227
|
+
} else if (customType === NOTIFY_ABANDONED_CUSTOM_TYPE) {
|
|
228
|
+
abandoned.add(notifyId);
|
|
192
229
|
}
|
|
193
230
|
}
|
|
194
|
-
return { ledger, acked };
|
|
231
|
+
return { ledger, acked, abandoned };
|
|
195
232
|
}
|
|
196
233
|
|
|
197
234
|
/** 收集 wanted 集合中已送达(custom_message entry 出现)的 notifyId。
|
|
@@ -232,6 +269,11 @@ export function createNotifyLedger(
|
|
|
232
269
|
const items = new Map<string, NotifyLedgerItem>();
|
|
233
270
|
/** 已销账内存索引(notifyId 幂等判重 + compaction 补写源;权威 = ack entry 列)。 */
|
|
234
271
|
const ackedIds = new Set<string>();
|
|
272
|
+
/**
|
|
273
|
+
* [T4③/PS-6] 已放弃终态内存索引(幂等判重 + compaction 补写源;权威 = abandoned
|
|
274
|
+
* entry 列)。与 ackedIds 同型:放弃是终态,同 notifyId 绝不再入账/重投/复活。
|
|
275
|
+
*/
|
|
276
|
+
const abandonedIds = new Set<string>();
|
|
235
277
|
/** U4 投递计数三桶(诊断快照源;增量经 emitBucketLog 落 extensionLogger)。 */
|
|
236
278
|
const buckets: NotifyDeliveryBucketMetrics = {
|
|
237
279
|
settleRejected: 0,
|
|
@@ -244,7 +286,8 @@ export function createNotifyLedger(
|
|
|
244
286
|
const api: NotifyLedger = {
|
|
245
287
|
record(notifyId, content, record): boolean {
|
|
246
288
|
if (disposed) return false;
|
|
247
|
-
|
|
289
|
+
// 幂等去重:在账(pending/sent)/ 已销账 / 已放弃([T4③] 终态绝不重发)→ false
|
|
290
|
+
if (items.has(notifyId) || ackedIds.has(notifyId) || abandonedIds.has(notifyId)) return false;
|
|
248
291
|
host.appendLedgerEntry(NOTIFY_LEDGER_CUSTOM_TYPE, {
|
|
249
292
|
v: 1,
|
|
250
293
|
notifyId,
|
|
@@ -297,9 +340,13 @@ export function createNotifyLedger(
|
|
|
297
340
|
if (disposed) return 0;
|
|
298
341
|
const state = scanSessionLedgerEntries(host.readSessionEntries());
|
|
299
342
|
for (const notifyId of state.acked) ackedIds.add(notifyId);
|
|
343
|
+
// [T4③/PS-6] 放弃终态跨重启生效:abandoned entry 视同已销账,下方差集重放跳过
|
|
344
|
+
// ——放弃号重启后不复活不重投(止损语义不以进程边界失效)。
|
|
345
|
+
for (const notifyId of state.abandoned) abandonedIds.add(notifyId);
|
|
300
346
|
let replayed = 0;
|
|
301
347
|
for (const entry of state.ledger.values()) {
|
|
302
348
|
if (state.acked.has(entry.notifyId)) continue; // 已销账零重发
|
|
349
|
+
if (abandonedIds.has(entry.notifyId)) continue; // 已放弃不复活(止损终态)
|
|
303
350
|
if (items.has(entry.notifyId) || ackedIds.has(entry.notifyId)) continue; // 幂等
|
|
304
351
|
items.set(entry.notifyId, {
|
|
305
352
|
...entry,
|
|
@@ -345,6 +392,14 @@ export function createNotifyLedger(
|
|
|
345
392
|
rewritten += 1;
|
|
346
393
|
}
|
|
347
394
|
}
|
|
395
|
+
// [T4③/PS-6] 放弃终态同享补写:内存是权威,compaction 清掉 abandoned entry 后
|
|
396
|
+
// 不补写会让放弃号在下次重启按差集复活(重投重启)。
|
|
397
|
+
for (const notifyId of abandonedIds) {
|
|
398
|
+
if (!state.abandoned.has(notifyId)) {
|
|
399
|
+
host.appendLedgerEntry(NOTIFY_ABANDONED_CUSTOM_TYPE, { v: 1, notifyId } satisfies NotifyAbandonedEntryData);
|
|
400
|
+
rewritten += 1;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
348
403
|
return rewritten;
|
|
349
404
|
},
|
|
350
405
|
|
|
@@ -356,6 +411,16 @@ export function createNotifyLedger(
|
|
|
356
411
|
return n;
|
|
357
412
|
},
|
|
358
413
|
|
|
414
|
+
pendingEntries(): ReadonlyArray<{ notifyId: string; content: string; record: object }> {
|
|
415
|
+
const out: Array<{ notifyId: string; content: string; record: object }> = [];
|
|
416
|
+
for (const item of items.values()) {
|
|
417
|
+
if (item.sentAt !== undefined) continue;
|
|
418
|
+
// 逐条浅拷贝:消费方(dispose 落盘复写)不得持有内部可变态。
|
|
419
|
+
out.push({ notifyId: item.notifyId, content: item.content, record: { ...item.record } });
|
|
420
|
+
}
|
|
421
|
+
return out;
|
|
422
|
+
},
|
|
423
|
+
|
|
359
424
|
waitingReceiptCount(): number {
|
|
360
425
|
let n = 0;
|
|
361
426
|
for (const item of items.values()) {
|
|
@@ -408,6 +473,35 @@ export function createNotifyLedger(
|
|
|
408
473
|
};
|
|
409
474
|
}
|
|
410
475
|
|
|
476
|
+
/** [T4③/PS-6] 放弃终态:appendEntry(abandoned) 落盘终态标记(重启恢复不复活)+
|
|
477
|
+
* warn 恢复指引。放弃后账面摘除(pending/waiting 计数归零、看门狗可停),同
|
|
478
|
+
* notifyId 被 record 幂等拒绝——「确认不可达」的止损上半场;通知内容本身仍可
|
|
479
|
+
* 经 subagents action:"list" 手动核对(账本 entry 与 result 落盘不受影响)。
|
|
480
|
+
* 放弃不计入 watchdogReplays 桶(该桶口径 = 实际发生重投的条数)。 */
|
|
481
|
+
function abandonItem(item: NotifyLedgerItem): void {
|
|
482
|
+
host.appendLedgerEntry(NOTIFY_ABANDONED_CUSTOM_TYPE, { v: 1, notifyId: item.notifyId } satisfies NotifyAbandonedEntryData);
|
|
483
|
+
items.delete(item.notifyId);
|
|
484
|
+
abandonedIds.add(item.notifyId);
|
|
485
|
+
// 消息含 subagent 标识与恢复指引(S-E 验收面);notifyId/attempts 等动态值按
|
|
486
|
+
// D4 约定放 data 参数(msg 近固定 key,限流命中面)。
|
|
487
|
+
logger.warn(
|
|
488
|
+
`Subagent "${itemLabel(item)}" notification abandoned - no receipt after ` +
|
|
489
|
+
`${NOTIFY_REDELIVERY_MAX_ATTEMPTS} delivery attempts; verify manually via subagents action:"list"`,
|
|
490
|
+
{ notifyId: item.notifyId, attempts: item.attempts },
|
|
491
|
+
);
|
|
492
|
+
maybeStopWatchdog();
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/** 放弃 warn 的 subagent 标识:优先 record.agent(人可读);record 形态异常时
|
|
496
|
+
* (ledger 对 record 不透明,见 NotifyLedgerEntryData)退回 notifyId(仍可检索)。 */
|
|
497
|
+
function itemLabel(item: NotifyLedgerItem): string {
|
|
498
|
+
if (isPlainObject(item.record)) {
|
|
499
|
+
const agent = item.record["agent"];
|
|
500
|
+
if (typeof agent === "string" && agent.length > 0) return agent;
|
|
501
|
+
}
|
|
502
|
+
return item.notifyId;
|
|
503
|
+
}
|
|
504
|
+
|
|
411
505
|
function ensureWatchdog(): void {
|
|
412
506
|
if (watchdogTimer !== undefined || disposed) return;
|
|
413
507
|
// 看门狗(D5 ②兜底触发面):回执检查 + 超时重投 + pending 补投。
|
|
@@ -418,12 +512,19 @@ export function createNotifyLedger(
|
|
|
418
512
|
// attemptDeliver 即重投——正常时序 settled 边沿早已销账,只有消息真丢失才到这
|
|
419
513
|
const cutoff = Date.now() - NOTIFY_WATCHDOG_MS;
|
|
420
514
|
let timedOut = 0;
|
|
515
|
+
// [T4③/PS-6] 止损:attempts 已达上限仍超期 = 确认不可达 → 放弃转终态,
|
|
516
|
+
// 不再重投(同一条完成通知不无限重复注入唤醒 LLM)。
|
|
517
|
+
const givenUp: NotifyLedgerItem[] = [];
|
|
421
518
|
for (const item of items.values()) {
|
|
422
|
-
if (item.sentAt
|
|
423
|
-
|
|
424
|
-
|
|
519
|
+
if (item.sentAt === undefined || item.sentAt > cutoff) continue;
|
|
520
|
+
if (item.attempts >= NOTIFY_REDELIVERY_MAX_ATTEMPTS) {
|
|
521
|
+
givenUp.push(item);
|
|
522
|
+
continue;
|
|
425
523
|
}
|
|
524
|
+
item.sentAt = undefined;
|
|
525
|
+
timedOut += 1;
|
|
426
526
|
}
|
|
527
|
+
for (const item of givenUp) abandonItem(item);
|
|
427
528
|
if (timedOut > 0) {
|
|
428
529
|
// U4 ①watchdogReplays 桶:busy 窗口滞留兜底的重投条数(同一消息反复超时累计)
|
|
429
530
|
buckets.watchdogReplays += timedOut;
|
|
@@ -467,7 +568,7 @@ export function createNotifyLedger(
|
|
|
467
568
|
// (P-B0 相邻机制已源码级锚定,agent-session.js:327-331,PS-07)。
|
|
468
569
|
// [MF-5] registerSettledListener=false(bind 路径)时跳过注册:pi.on("agent_settled")
|
|
469
570
|
// 无退订语义——createExtensionAPI.on 只 push 进 extension.handlers、无 off
|
|
470
|
-
//(pi 0.84.
|
|
571
|
+
//(pi 0.84.4 dist/core/extensions/loader.js:209-214)。注意消歧两类订阅面:此处的
|
|
471
572
|
// pi.on 是生命周期事件订阅(无退订);ctx.events.on(channel) 走 eventBus、有
|
|
472
573
|
// trackEventBusSubscription 退订通路(loader.js:174、:338)——勿按后者的可退订
|
|
473
574
|
// 语义「修复」此处。per-bind 注册会随 session 切换累积死 handler
|
|
@@ -543,7 +644,7 @@ function settledEdgeDispatch(): void {
|
|
|
543
644
|
/**
|
|
544
645
|
* session_start 装配(index.ts):构造新 ledger 并绑定为模块级单例(notifier.notify
|
|
545
646
|
* 经 getBoundNotifyLedger 消费)。重复 bind(/resume /fork /new 的 session_start)
|
|
546
|
-
* 替换旧实例——内存态清零符合「内存不承担销账职责」,权威 = entry
|
|
647
|
+
* 替换旧实例——内存态清零符合「内存不承担销账职责」,权威 = entry 多列差集
|
|
547
648
|
* (调用方随后 recoverFromSession 重建)。
|
|
548
649
|
*
|
|
549
650
|
* [MF-5] 监听单例化:首次 bind 经当次 host 注册模块级单例 handler
|
|
@@ -21,7 +21,9 @@ import type {
|
|
|
21
21
|
} from "./types.ts";
|
|
22
22
|
|
|
23
23
|
/** 自描述 record entry 的 customType。写点字面量与本常量的等值由
|
|
24
|
-
* __tests__/record-store.test.ts 断言钉住(消费方引用本常量,勿用裸字符串)。
|
|
24
|
+
* __tests__/record-store.test.ts 断言钉住(消费方引用本常量,勿用裸字符串)。
|
|
25
|
+
*
|
|
26
|
+
* @experimental execution 运行时面(U10① D6):一个 minor 周期内允许签名微调。 */
|
|
25
27
|
export const SUBAGENT_RECORD_CUSTOM_TYPE = "subagent-record";
|
|
26
28
|
|
|
27
29
|
/**
|
|
@@ -34,6 +36,8 @@ export const SUBAGENT_RECORD_CUSTOM_TYPE = "subagent-record";
|
|
|
34
36
|
* - worktreeHandle:不可 JSON 序列化的运行时句柄(布尔投影 worktree 保留)。
|
|
35
37
|
*
|
|
36
38
|
* undefined 字段经 JSON.stringify 自然缺省(与 SubagentRecord 重建侧语义一致)。
|
|
39
|
+
*
|
|
40
|
+
* @experimental execution 运行时面(U10① D6):一个 minor 周期内允许签名微调。
|
|
37
41
|
*/
|
|
38
42
|
export interface SubagentRecordEntryData {
|
|
39
43
|
/** schema 版本(W16 起 v1)。消费方按 v 判别解析,不认识的版本跳过而非猜测。 */
|
|
@@ -95,7 +99,9 @@ export interface SubagentRecordEntryData {
|
|
|
95
99
|
engineHandle?: { sessionRef: Record<string, string>; journalPath?: string; poolKey: string };
|
|
96
100
|
}
|
|
97
101
|
|
|
98
|
-
/** SubagentRecord → 自描述 entry data(快照投影,不 mutate 源)。
|
|
102
|
+
/** SubagentRecord → 自描述 entry data(快照投影,不 mutate 源)。
|
|
103
|
+
*
|
|
104
|
+
* @experimental execution 运行时面(U10① D6):一个 minor 周期内允许签名微调。 */
|
|
99
105
|
export function toSubagentRecordEntry(record: SubagentRecord): SubagentRecordEntryData {
|
|
100
106
|
return {
|
|
101
107
|
v: 1,
|