@zhushanwen/subagent-core 0.4.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/dist/{chunk-4KN4TTG7.js → chunk-43ONBFZX.js} +1 -1
- package/dist/{chunk-X7SZ5HLQ.js → chunk-V3VHZ2VX.js} +20 -27
- package/dist/execution/engine/engines/zcode/constants.cjs +29 -41
- package/dist/execution/engine/engines/zcode/constants.d.cts +65 -53
- package/dist/execution/engine/engines/zcode/constants.d.ts +65 -53
- package/dist/execution/engine/engines/zcode/constants.js +17 -27
- package/dist/execution/engine/engines/zcode/reader.d.cts +2 -1
- package/dist/execution/engine/engines/zcode/reader.d.ts +2 -1
- package/dist/execution/engine/engines/zcode/reader.js +2 -2
- package/dist/index.cjs +16418 -14070
- package/dist/index.d.cts +5136 -4016
- package/dist/index.d.ts +5136 -4016
- package/dist/index.js +16343 -14048
- package/dist/{types-DpUO16pj.d.cts → types-Dv4QhSJ_.d.cts} +215 -112
- package/dist/{types-DpUO16pj.d.ts → types-Dv4QhSJ_.d.ts} +215 -112
- package/package.json +3 -3
- package/src/__tests__/agent-opts-resolver-schema-prompt.test.ts +0 -1
- package/src/__tests__/append-system-prompt-assembly.test.ts +8 -7
- package/src/__tests__/fr4-get-state-handshake.test.ts +2 -2
- package/src/__tests__/m2-append-content-probe.test.ts +0 -1
- package/src/__tests__/manifest-store.test.ts +10 -9
- package/src/__tests__/record-store-cache.test.ts +0 -2
- package/src/__tests__/record-store-index.test.ts +1 -2
- package/src/__tests__/review-fix-loop-script.test.ts +4 -2
- package/src/__tests__/review-fix-loop-utils.test.ts +10 -10
- package/src/__tests__/robustness-low-batch1.test.ts +6 -5
- package/src/__tests__/robustness-medium-batch1.test.ts +2 -2
- package/src/__tests__/robustness-medium-batch2.test.ts +17 -6
- package/src/__tests__/robustness-medium-batch4.test.ts +2 -2
- package/src/__tests__/session-runner.test.ts +1 -1
- package/src/core/__tests__/host-services.test.ts +2 -2
- package/src/core/__tests__/logger.test.ts +1 -1
- package/src/core/error-message.ts +9 -0
- package/src/core/host-services.ts +21 -5
- package/src/core/notify-ports.ts +18 -5
- package/src/execution/__tests__/agent-profile.test.ts +4 -4
- package/src/execution/__tests__/agent-registry.test.ts +370 -0
- package/src/execution/__tests__/agent-result-mapper.test.ts +18 -2
- package/src/execution/__tests__/agents-assembly.test.ts +2 -2
- package/src/execution/__tests__/ask-user-transit-e2e.test.ts +6 -6
- package/src/execution/__tests__/chat-engine-routing.test.ts +68 -33
- package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +4 -4
- package/src/execution/__tests__/cold-resurrect.test.ts +283 -0
- package/src/execution/__tests__/delivery-methods.test.ts +75 -62
- package/src/execution/__tests__/descendant-sweep-guards.test.ts +220 -0
- package/src/execution/__tests__/descendant-sweep.test.ts +6 -6
- package/src/execution/__tests__/dialog-queue.test.ts +2 -2
- package/src/execution/__tests__/engine-model-validation.test.ts +741 -0
- package/src/execution/__tests__/epipe-fallback.test.ts +29 -24
- package/src/execution/__tests__/execute-and-await-worktree.test.ts +21 -91
- package/src/execution/__tests__/execute-nesting.test.ts +34 -188
- package/src/execution/__tests__/execution-record.test.ts +217 -60
- package/src/execution/__tests__/execution-runtime-face.test.ts +5 -5
- package/src/execution/__tests__/explicit-agent-ref-guard.test.ts +3 -3
- package/src/execution/__tests__/finalize-record.test.ts +173 -17
- package/src/execution/__tests__/gc-timer.test.ts +55 -2
- package/src/execution/__tests__/get-record-for-action-restart.test.ts +12 -12
- package/src/execution/__tests__/get-state-handshake.test.ts +1 -1
- package/src/execution/__tests__/helpers/mock-extension-api.ts +1 -1
- package/src/execution/__tests__/helpers/session-runner-mocks.ts +113 -0
- package/src/execution/__tests__/helpers/spawn-mock.ts +150 -3
- package/src/execution/__tests__/helpers/subagent-service-mocks.ts +137 -0
- package/src/execution/__tests__/keep-alive-no-progress.test.ts +50 -148
- package/src/execution/__tests__/kill-all-escalation.test.ts +2 -2
- package/src/execution/__tests__/lifecycle-predicates.test.ts +1 -2
- package/src/execution/__tests__/manifest-parentid.test.ts +4 -4
- package/src/execution/__tests__/max-turns-to-watchdog-ms.test.ts +1 -1
- package/src/execution/__tests__/model-resolver.test.ts +2 -2
- package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +23 -121
- package/src/execution/__tests__/nested-visibility.test.ts +2 -0
- package/src/execution/__tests__/notify-ledger.test.ts +973 -18
- 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.test.ts +10 -9
- package/src/execution/__tests__/records-cwd-isolation.test.ts +2 -2
- package/src/execution/__tests__/recursive-visibility-baseline.test.ts +29 -132
- package/src/execution/__tests__/recursive-visibility-env.test.ts +55 -179
- package/src/execution/__tests__/rpc-mode.test.ts +2 -2
- package/src/execution/__tests__/run-and-finalize-anchoring.test.ts +387 -0
- package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +15 -9
- package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +4 -4
- package/src/execution/__tests__/run-spawn-edges.test.ts +17 -15
- package/src/execution/__tests__/run-spawn-integration.test.ts +2 -2
- package/src/execution/__tests__/run-spawn-resume.test.ts +2 -2
- package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +2 -2
- package/src/execution/__tests__/run-spawn-stdout-callback-throw.test.ts +4 -4
- package/src/execution/__tests__/service-kill-escalation.test.ts +7 -5
- package/src/execution/__tests__/session-context-resolver.test.ts +0 -2
- package/src/execution/__tests__/session-file-gc.test.ts +35 -0
- package/src/execution/__tests__/session-pending.test.ts +257 -14
- package/src/execution/__tests__/session-reconstructor.test.ts +366 -15
- package/src/execution/__tests__/session-runner-branch-cache-lru.test.ts +1 -1
- package/src/execution/__tests__/session-runner-close-prune.test.ts +2 -2
- package/src/execution/__tests__/session-runner-dispatch.test.ts +489 -0
- package/src/execution/__tests__/session-runner-epipe.test.ts +3 -3
- package/src/execution/__tests__/session-runner-heartbeat-idle-fallback.test.ts +5 -4
- package/src/execution/__tests__/session-runner-lifecycle-helpers.test.ts +290 -0
- package/src/execution/__tests__/session-runner-schema-env.test.ts +7 -5
- package/src/execution/__tests__/settled-watchdog.test.ts +282 -47
- package/src/execution/__tests__/spawn-args.test.ts +11 -10
- package/src/execution/__tests__/spawn-event-adapter-rpc.test.ts +26 -23
- package/src/execution/__tests__/spawn-event-adapter.test.ts +1 -1
- package/src/execution/__tests__/spawn-worktree-guidance.test.ts +5 -4
- package/src/execution/__tests__/spawned-children.test.ts +2 -1
- package/src/execution/__tests__/start-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 +42 -22
- package/src/execution/__tests__/subagent-service-message-close.test.ts +29 -26
- package/src/execution/__tests__/subagent-service-multiproc-guard.test.ts +8 -8
- package/src/execution/__tests__/subagent-service-notify-gate.test.ts +27 -22
- package/src/execution/__tests__/subagent-service-parent-guard.test.ts +30 -29
- package/src/execution/__tests__/subagent-service-recovery-bounds.test.ts +45 -20
- package/src/execution/__tests__/subagent-service.test.ts +37 -30
- package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +88 -12
- package/src/execution/__tests__/subprocess-agent-runner-timeout.test.ts +75 -0
- package/src/execution/__tests__/subprocess-agent-runner.test.ts +22 -20
- package/src/execution/__tests__/temp-prompt.test.ts +1 -1
- package/src/execution/__tests__/timeout-integration.test.ts +6 -5
- package/src/execution/__tests__/turn-limiter-semantics.test.ts +1 -1
- package/src/execution/__tests__/turn-limiter.test.ts +1 -1
- package/src/execution/__tests__/ui-request-handler-factory.test.ts +12 -6
- package/src/execution/__tests__/ui-request-handler.test.ts +4 -3
- package/src/execution/__tests__/ui-request-queue.test.ts +142 -2
- package/src/execution/__tests__/worktree-manager.test.ts +14 -5
- package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +4 -3
- package/src/execution/agent-registry.ts +74 -30
- package/src/execution/agent-result-mapper.ts +3 -0
- package/src/execution/cold-resurrect.ts +199 -0
- package/src/execution/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 +22 -112
- package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +15 -28
- package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +12 -12
- package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +1 -1
- package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +21 -82
- package/src/execution/engine/__tests__/conformance/zcode-appserver-harness.ts +4 -7
- package/src/execution/engine/__tests__/engine-discovery.test.ts +15 -3
- package/src/execution/engine/__tests__/model-prompt.test.ts +15 -3
- package/src/execution/engine/__tests__/registry.test.ts +4 -2
- package/src/execution/engine/__tests__/routing.test.ts +115 -6
- package/src/execution/engine/common/capability-gate.ts +92 -0
- package/src/execution/engine/common/journal-wiring.ts +97 -0
- package/src/execution/engine/common/kill-chain.ts +42 -10
- package/src/execution/engine/common/nesting-guard.ts +66 -0
- package/src/execution/engine/common/persona-router.ts +18 -8
- package/src/execution/engine/common/pool-manager.ts +332 -78
- package/src/execution/engine/common/session-view-service.ts +506 -0
- package/src/execution/engine/common/session-view-types.ts +125 -0
- package/src/execution/engine/engines/pi/__tests__/pi-engine.test.ts +174 -28
- package/src/execution/engine/engines/pi/__tests__/spawn-opts-direct.test.ts +257 -0
- package/src/execution/{argv-mirror.ts → engine/engines/pi/argv-mirror.ts} +43 -21
- package/src/execution/{get-state-handshake.ts → engine/engines/pi/get-state-handshake.ts} +1 -1
- package/src/execution/{output-collector.ts → engine/engines/pi/output-collector.ts} +108 -19
- package/src/execution/engine/engines/pi/pi-engine.ts +434 -38
- package/src/execution/{pi-invocation.ts → engine/engines/pi/pi-invocation.ts} +2 -2
- package/src/execution/engine/engines/pi/reader.ts +11 -0
- package/src/execution/engine/engines/pi/registration.ts +4 -2
- package/src/execution/{session-runner.ts → engine/engines/pi/session-runner.ts} +617 -412
- package/src/execution/{spawn-event-adapter.ts → engine/engines/pi/spawn-event-adapter.ts} +75 -34
- package/src/execution/{stdin-writer.ts → engine/engines/pi/stdin-writer.ts} +10 -9
- package/src/execution/{temp-prompt.ts → engine/engines/pi/temp-prompt.ts} +2 -2
- package/src/execution/{turn-limiter.ts → engine/engines/pi/turn-limiter.ts} +1 -1
- package/src/execution/engine/engines/zcode/__tests__/__fixtures__/fake-appserver.mjs +54 -27
- package/src/execution/engine/engines/zcode/__tests__/appserver-launcher.test.ts +321 -0
- package/src/execution/engine/engines/zcode/__tests__/connection.test.ts +13 -12
- package/src/execution/engine/engines/zcode/__tests__/parser.test.ts +7 -210
- package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +6 -110
- package/src/execution/engine/engines/zcode/__tests__/session-channel-dispose-harvest.test.ts +247 -0
- package/src/execution/engine/engines/zcode/__tests__/session-channel-turn-timers.test.ts +451 -0
- package/src/execution/engine/engines/zcode/__tests__/session-channel.test.ts +20 -8
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-appserver.test.ts +77 -110
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-degrade.test.ts +25 -319
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-dispose.test.ts +210 -0
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-retry.test.ts +353 -0
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-status.test.ts +282 -0
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-timeout.test.ts +372 -0
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +48 -148
- package/src/execution/engine/engines/zcode/appserver-launcher.ts +167 -0
- package/src/execution/engine/engines/zcode/connection.ts +24 -11
- package/src/execution/engine/engines/zcode/constants.ts +75 -71
- package/src/execution/engine/engines/zcode/golden-sample.ts +8 -46
- package/src/execution/engine/engines/zcode/parser.ts +12 -346
- package/src/execution/engine/engines/zcode/preparer.ts +12 -143
- package/src/execution/engine/engines/zcode/session-channel.ts +351 -39
- package/src/execution/engine/engines/zcode/zcode-engine.ts +665 -760
- package/src/execution/engine/host-task-spec.ts +32 -36
- package/src/execution/engine/model-validation.ts +177 -0
- package/src/execution/engine/port.ts +24 -6
- package/src/execution/engine/routing.ts +75 -1
- package/src/execution/engine/types.ts +30 -103
- package/src/execution/execution-record.ts +222 -144
- package/src/execution/finalize-record.ts +131 -93
- package/src/execution/idle-gc.ts +28 -0
- package/src/execution/lifecycle-predicates.ts +1 -1
- package/src/execution/notify-host.ts +212 -0
- package/src/execution/record-store.ts +119 -73
- package/src/execution/round-settlement.ts +93 -0
- package/src/execution/session-file-gc.ts +96 -62
- package/src/execution/session-reconstructor.ts +256 -143
- package/src/execution/sessions-index.ts +117 -47
- package/src/execution/settled-watchdog.ts +264 -52
- package/src/execution/subagent-actions-core.ts +22 -22
- package/src/execution/subagent-service.ts +815 -963
- package/src/execution/subprocess-agent-runner.ts +144 -97
- package/src/execution/types.ts +9 -0
- package/src/execution/ui-request-handler-factory.ts +102 -74
- package/src/execution/ui-request-queue.ts +50 -19
- package/src/index.ts +442 -316
- package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +1 -1
- package/src/orchestration/__tests__/agent-call-stream.test.ts +2 -2
- package/src/orchestration/__tests__/args-validator.test.ts +14 -0
- package/src/orchestration/__tests__/error-recovery-rebuild-failure.test.ts +1 -1
- package/src/orchestration/__tests__/error-recovery-terminal-hardening.test.ts +11 -9
- package/src/orchestration/__tests__/execute-agent-call.test.ts +151 -11
- package/src/orchestration/__tests__/file-run-store.test.ts +7 -6
- package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +2 -2
- package/src/orchestration/__tests__/lifecycle-abort-broadcast-signal.test.ts +1 -1
- package/src/orchestration/__tests__/lifecycle-runid-injection.test.ts +3 -3
- package/src/orchestration/__tests__/lifecycle.test.ts +7 -5
- package/src/orchestration/__tests__/non-cloneable-return-e2e.test.ts +1 -1
- package/src/orchestration/__tests__/run-snapshot.test.ts +8 -5
- 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} +27 -19
- package/src/orchestration/__tests__/{error-recovery-postmessage-defense.test.ts → worker-message-pump-postmessage-defense.test.ts} +8 -8
- package/src/orchestration/__tests__/{error-recovery-serialize-failed-result.test.ts → worker-message-pump-serialize-failed-result.test.ts} +2 -2
- package/src/orchestration/__tests__/{error-recovery-workflow-call.test.ts → worker-message-pump-workflow-call.test.ts} +1 -1
- package/src/orchestration/__tests__/worker-pending-timeout-abort.test.ts +1 -1
- package/src/orchestration/__tests__/worker-script-builder.test.ts +1 -1
- package/src/orchestration/__tests__/workflow-nesting-e2e.test.ts +1 -1
- package/src/orchestration/agent-opts-resolver.ts +1 -1
- package/src/orchestration/args-validator.ts +53 -31
- package/src/orchestration/execute-agent-call.ts +19 -73
- package/src/orchestration/launcher.ts +128 -81
- package/src/orchestration/lifecycle.ts +43 -45
- package/src/orchestration/models/ports.ts +4 -4
- package/src/orchestration/models/run-runtime.ts +2 -2
- package/src/orchestration/models/trace.ts +1 -1
- package/src/orchestration/models/types.ts +111 -22
- package/src/orchestration/models/workflow-run.ts +1 -1
- package/src/orchestration/script-lint.ts +91 -58
- package/src/orchestration/{error-recovery.ts → worker-message-pump.ts} +157 -150
- package/src/shared/__tests__/meta-parser.test.ts +151 -0
- package/src/shared/__tests__/resource-discovery.test.ts +258 -215
- package/src/shared/atomic-write.ts +12 -9
- package/src/shared/meta-parser.ts +158 -84
- package/src/shared/model-ref.ts +15 -2
- package/src/shared/resource-discovery.ts +9 -183
- package/src/shared/schema-jsonify.ts +1 -1
- package/workflows/review-fix-loop-utils.cjs +151 -89
- package/workflows/review-fix-loop-utils.d.cts +287 -0
- package/src/execution/__tests__/execute-options-mapper.test.ts +0 -200
- package/src/execution/engine/engines/pi/__tests__/task-spec-mapper.test.ts +0 -164
- package/src/execution/engine/engines/pi/task-spec-mapper.ts +0 -100
- package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-spawn.json +0 -39
- package/src/execution/engine/engines/zcode/__tests__/launcher.test.ts +0 -150
- package/src/execution/engine/engines/zcode/__tests__/preparer-appserver.test.ts +0 -387
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine.test.ts +0 -710
- package/src/execution/engine/engines/zcode/appserver-home.ts +0 -442
- package/src/execution/engine/engines/zcode/appserver-probe.ts +0 -141
- package/src/execution/engine/engines/zcode/launcher.ts +0 -161
- package/src/execution/execute-options-mapper.ts +0 -115
- package/src/shared/__tests__/resource-discovery-manifest-cache.test.ts +0 -288
|
@@ -8,16 +8,23 @@
|
|
|
8
8
|
* 职责:
|
|
9
9
|
* - 重试:3 次 + 指数退避(BACKOFF_MS = [1000, 2000, 4000])
|
|
10
10
|
* - 预算:超限不重试(直接 markDone failed)
|
|
11
|
-
* - stale-context
|
|
12
|
-
* - [MF-1] 确定性 schema
|
|
11
|
+
* - stale-context(result.failureKind="stale_context"):不重试(直接 markDone failed)
|
|
12
|
+
* - [MF-1] 确定性 schema 失败(result.failureKind="schema_deterministic"):不重试
|
|
13
|
+
* (直接 markDone failed)
|
|
13
14
|
* - 成功:consume usage + incrementCallCount + markDone + trace.update(completed)
|
|
14
15
|
*
|
|
16
|
+
* [D5-③ 结构化分诊] 失败分诊读 AgentResult.failureKind 字段(产出侧唯一识别点 =
|
|
17
|
+
* execution/engine/engines/pi/output-collector.ts 的 classifyFailureKind,词表归属
|
|
18
|
+
* 见其文件头)。本模块不再扫 error 文案子串——**语义守恒(r1 MF4)**:unknown
|
|
19
|
+
* (含字段缺省)= 可重试,保持收敛前的默认重试语义;仅 stale_context(不重试、
|
|
20
|
+
* 换参重发场景由调用方编排)与 schema_deterministic 维持特判。
|
|
21
|
+
*
|
|
15
22
|
* 关键设计:
|
|
16
23
|
* - **usage 透传**:result.usage 直接交给 budget.consume,加权由 Budget 内部的权重常量
|
|
17
|
-
*
|
|
24
|
+
* 处理(见 budget.ts)。此函数不再做 usage 形状的改写。
|
|
18
25
|
* - **参数显式化**:runner 直接传入(而非 ctx.getRun(runId).pool),无 runId 查找 / pool 守卫。
|
|
19
26
|
* - **stale-state 检查**:signal.aborted 时早返回。WorkflowRun 状态由调用方 lifecycle
|
|
20
|
-
*
|
|
27
|
+
* 持有,executeAgentCall 只关心单次 call 生命周期。
|
|
21
28
|
*
|
|
22
29
|
* 层归属:Engine。零 infra 依赖(runner 是 AgentRunner port,budget/trace/call 是 Engine 模型)。
|
|
23
30
|
*
|
|
@@ -41,69 +48,6 @@ const BACKOFF_EXPONENT_BASE = 2;
|
|
|
41
48
|
/** 最大尝试次数(含首次):initial + 2 retries = 3。 */
|
|
42
49
|
const MAX_ATTEMPTS = 3;
|
|
43
50
|
|
|
44
|
-
/**
|
|
45
|
-
* Stale context 检测模式(P1-5;W4b 对齐 pi 0.84.x 真实文案)。
|
|
46
|
-
*
|
|
47
|
-
* pi session context 被 compact/cancel 时报告的模式。这种情况下重试无意义——
|
|
48
|
-
* 同样的 call 会再次失败。直接 markDone failed 终止单次调用。
|
|
49
|
-
*
|
|
50
|
-
* W4b:原 "stale context"/"stalecontext" 与 pi 真实文案零匹配(真实文案为
|
|
51
|
-
* "This extension ctx is stale after session replacement or reload. ..."——
|
|
52
|
-
* runner.ts:544(dist runner.js:352),词序是 "ctx is stale" 而非 "stale context"),stale 分诊对
|
|
53
|
-
* 真实文案失效。现对齐:
|
|
54
|
-
* - "ctx is stale":真实文案核心子串(词序修正)
|
|
55
|
-
* - "stale after session replacement":scheduler 已验证 marker(runtime.ts
|
|
56
|
-
* STALE_CTX_MARKER,同文案锚定)
|
|
57
|
-
* - "context canceled"/"aborted":保留——abort 族错误同样不重试(signal.aborted
|
|
58
|
-
* 分支的先行分诊,防边界竞态漏网),删除会放宽重试语义。
|
|
59
|
-
*/
|
|
60
|
-
export const STALE_CONTEXT_PATTERNS = [
|
|
61
|
-
"ctx is stale",
|
|
62
|
-
"stale after session replacement",
|
|
63
|
-
"context canceled",
|
|
64
|
-
"aborted",
|
|
65
|
-
] as const;
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* 判断错误信息是否表示 stale/canceled pi session context。
|
|
69
|
-
* 命中时不重试——重试只会再次失败(P1-5)。
|
|
70
|
-
*/
|
|
71
|
-
export function isStaleContextErrorMsg(msg: string | undefined): boolean {
|
|
72
|
-
if (!msg) return false;
|
|
73
|
-
const lower = msg.toLowerCase();
|
|
74
|
-
return STALE_CONTEXT_PATTERNS.some((p) => lower.includes(p));
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* [MF-1] 确定性 schema 失败标记(error 文本前缀,产出方 = output-collector 的
|
|
79
|
-
* describeMissingParsedOutput)。
|
|
80
|
-
*
|
|
81
|
-
* 标记 SSOT 放本模块(与 STALE_CONTEXT_PATTERNS 同布局:orchestration 持表、
|
|
82
|
-
* execution 值引用;反向引用会形成 execute-agent-call → output-collector →
|
|
83
|
-
* execute-agent-call 运行时循环)。
|
|
84
|
-
*
|
|
85
|
-
* 标记词逐字核对不命中 STALE_CONTEXT_PATTERNS 任一 pattern 与
|
|
86
|
-
* isStaleContextErrorMsg 的子串匹配(否则归因 error 被误诊 stale-context,
|
|
87
|
-
* 虽然同样不重试但归因语义被污染;output-collector.test 有交叉锁定)。
|
|
88
|
-
*
|
|
89
|
-
* 三态可重试性矩阵(F-1 归因):
|
|
90
|
-
* | 归因态 | 带本标记 | 可重试性 | 理由 |
|
|
91
|
-
* |----------------------------|---------|---------|------|
|
|
92
|
-
* | ① 从未调用 SO tool | 是 | 不可重试 | 缺 extension 是环境确定性(C1 安装盲区),同环境重试必同结果 |
|
|
93
|
-
* | ② SO 调用 isError(gate 终止/不可满足 schema) | 是 | 不可重试 | 同 schema 重试必同结果(第五轮实测:3 attempts/4 子进程/235s 纯烧钱) |
|
|
94
|
-
* | ③ 调用过但无 details | 否 | 可重试 | 可能瞬态(details 提取/序列化异常),保留既有重试语义 |
|
|
95
|
-
*/
|
|
96
|
-
export const DETERMINISTIC_SCHEMA_FAILURE_PREFIX = "Structured output failed deterministically:";
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* [MF-1] 判断错误信息是否为确定性 schema 失败(命中标记前缀)。
|
|
100
|
-
* 命中时不重试——同 schema 重试必同结果(矩阵见 DETERMINISTIC_SCHEMA_FAILURE_PREFIX)。
|
|
101
|
-
*/
|
|
102
|
-
export function isDeterministicSchemaFailureMsg(msg: string | undefined): boolean {
|
|
103
|
-
if (!msg) return false;
|
|
104
|
-
return msg.includes(DETERMINISTIC_SCHEMA_FAILURE_PREFIX);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
51
|
// ── 内部 helper ──────────────────────────────────────────────
|
|
108
52
|
|
|
109
53
|
/**
|
|
@@ -124,7 +68,7 @@ function backoffDelay(retryIndex: number): number {
|
|
|
124
68
|
* rebuild 竞态窗口中,重跑 dispatch 已 append 同 stepIndex 新节点,旧代际
|
|
125
69
|
* finalize 的 update 会命中新节点,TUI/中间快照短暂可见错误终态。正确性论证:
|
|
126
70
|
* 运行期 calls Map 写点仅 discardInFlightCalls 的 delete 与 dispatchAgentCall 的
|
|
127
|
-
* set 两族(
|
|
71
|
+
* set 两族(worker-message-pump.ts isOrphanedCall 文档注释既定),故实例不等 ⟺ 本
|
|
128
72
|
* finalize 属于被丢弃/被替换的旧代际——与 dispatch 层 .then/.catch 守卫
|
|
129
73
|
* (S7-second 修复,8353f6b60)同一判定语义,本守卫只是把它前移到 trace.update
|
|
130
74
|
* 之前。markDone 与 sessionId/sessionFile 同步保留(markDone 在孤儿实例上无害,
|
|
@@ -208,16 +152,18 @@ export async function executeAgentCall(
|
|
|
208
152
|
budget.consume(result.usage);
|
|
209
153
|
}
|
|
210
154
|
|
|
211
|
-
// stale-context
|
|
212
|
-
|
|
155
|
+
// stale-context(D5-③ 结构化分诊:读 failureKind 字段,词表识别在产出侧
|
|
156
|
+
// output-collector):不重试(P1-5)
|
|
157
|
+
if (result.error !== undefined && result.failureKind === "stale_context") {
|
|
213
158
|
finalizeCall(call, result, trace, isOrphaned);
|
|
214
159
|
budget.incrementCallCount();
|
|
215
160
|
return;
|
|
216
161
|
}
|
|
217
162
|
|
|
218
|
-
// [MF-1] 确定性 schema
|
|
219
|
-
//
|
|
220
|
-
|
|
163
|
+
// [MF-1] 确定性 schema 失败(failureKind="schema_deterministic"):不重试
|
|
164
|
+
// (gate 终止/不可满足 schema 同 schema 重试必同结果——重试纯烧钱;三态矩阵
|
|
165
|
+
// 见产出侧 output-collector 的确定性失败标记注释)
|
|
166
|
+
if (result.error !== undefined && result.failureKind === "schema_deterministic") {
|
|
221
167
|
finalizeCall(call, result, trace, isOrphaned);
|
|
222
168
|
budget.incrementCallCount();
|
|
223
169
|
return;
|
|
@@ -31,7 +31,9 @@ import type { LifecycleDeps } from "./models/ports.ts";
|
|
|
31
31
|
import type { RunSpec } from "./models/run-spec.ts";
|
|
32
32
|
import type { DoneReason } from "./models/types.ts";
|
|
33
33
|
import type { WorkflowRun } from "./models/workflow-run.ts";
|
|
34
|
+
import type { WorkflowScript } from "./models/workflow-script.ts";
|
|
34
35
|
import type { WorkflowScriptRegistry } from "./models/workflow-script-registry.ts";
|
|
36
|
+
import type { LintResult } from "./script-lint.ts";
|
|
35
37
|
import { assertSafeTimerDelay } from "../shared/timer-delay.ts";
|
|
36
38
|
|
|
37
39
|
// ── 常量 ─────────────────────────────────────────────────────
|
|
@@ -106,6 +108,14 @@ function pollInterval(): Promise<void> {
|
|
|
106
108
|
});
|
|
107
109
|
}
|
|
108
110
|
|
|
111
|
+
/** lint findings 摘要串(runAndWait / executeNestedWorkflow 共用同一错误文案格式)。 */
|
|
112
|
+
function formatLintErrorSummary(lintResult: LintResult): string {
|
|
113
|
+
return lintResult.findings
|
|
114
|
+
.filter((f) => f.severity === "error")
|
|
115
|
+
.map((f) => `L${f.line}: ${f.message}`)
|
|
116
|
+
.join("; ");
|
|
117
|
+
}
|
|
118
|
+
|
|
109
119
|
/**
|
|
110
120
|
* 从 WorkflowRun 构建 WorkflowRunResult(D-8)。
|
|
111
121
|
*
|
|
@@ -243,11 +253,9 @@ export async function runAndWait(
|
|
|
243
253
|
// 2. lint 校验(失败抛错——脚本本身有问题,不应静默吞)
|
|
244
254
|
const lintResult = script.validate();
|
|
245
255
|
if (!lintResult.valid) {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
.join("; ");
|
|
250
|
-
throw new Error(`Workflow script '${name}' has lint errors: ${errors}`);
|
|
256
|
+
throw new Error(
|
|
257
|
+
`Workflow script '${name}' has lint errors: ${formatLintErrorSummary(lintResult)}`,
|
|
258
|
+
);
|
|
251
259
|
}
|
|
252
260
|
|
|
253
261
|
// 3. 构建 RunSpec
|
|
@@ -312,19 +320,118 @@ async function safeAbort(
|
|
|
312
320
|
|
|
313
321
|
// ── executeNestedWorkflow(workflow() 嵌套调用实现) ────────
|
|
314
322
|
|
|
323
|
+
/** 父 run 的循环检测链:[...parentChain, parentScriptName](顶层 run 无 chain 时前段为空)。 */
|
|
324
|
+
function buildParentChain(parentRun: WorkflowRun): string[] {
|
|
325
|
+
return [...(parentRun.spec.parentWorkflowChain ?? []), parentRun.spec.scriptName];
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/** Step 2 的 signal 继承产物(childController + 父 signal/回调——finally 移除 listener 用)。 */
|
|
329
|
+
interface InheritedSignal {
|
|
330
|
+
childController: AbortController;
|
|
331
|
+
parentSignal: AbortSignal | undefined;
|
|
332
|
+
onParentAbort: () => void;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Step 2: signal 继承——子 run 响应父 run abort(parentController → childController)。
|
|
337
|
+
*
|
|
338
|
+
* [L-2] onParentAbort 提取为命名函数以便 finally removeEventListener,防子 run 完成后
|
|
339
|
+
* parentSignal 上残留 listener(多次嵌套调用会累积)。
|
|
340
|
+
*/
|
|
341
|
+
function inheritParentSignal(parentRun: WorkflowRun): InheritedSignal {
|
|
342
|
+
const childController = new AbortController();
|
|
343
|
+
const parentSignal = parentRun.runtime?.controller.signal;
|
|
344
|
+
const onParentAbort = (): void => childController.abort();
|
|
345
|
+
if (parentSignal) {
|
|
346
|
+
if (parentSignal.aborted) {
|
|
347
|
+
childController.abort();
|
|
348
|
+
} else {
|
|
349
|
+
parentSignal.addEventListener("abort", onParentAbort, { once: true });
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
return { childController, parentSignal, onParentAbort };
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Step 4: 构建 RunSpec(共享父 Budget + 循环链)。
|
|
357
|
+
*
|
|
358
|
+
* budget 共享(F-7 方案 B):子 run 直接复用父 Budget 引用(budgetRef),consume 实时
|
|
359
|
+
* 累加到父 Budget,消除并行嵌套下的超支窗口,无需 sync-back。
|
|
360
|
+
*/
|
|
361
|
+
function buildNestedSpec(
|
|
362
|
+
args: Record<string, unknown>,
|
|
363
|
+
parentRun: WorkflowRun,
|
|
364
|
+
script: WorkflowScript,
|
|
365
|
+
chain: string[],
|
|
366
|
+
): RunSpec {
|
|
367
|
+
return {
|
|
368
|
+
scriptSource: script.toExecutable(),
|
|
369
|
+
args,
|
|
370
|
+
budgetRef: parentRun.state.budget,
|
|
371
|
+
// Run-level override 传播(与父 run 对齐):子 run 继承父 run 的 model/thinkingLevel,
|
|
372
|
+
// 否则嵌套 workflow 丢失父 run 的模型指定,回落主 agent 模型。
|
|
373
|
+
model: parentRun.spec.model,
|
|
374
|
+
thinkingLevel: parentRun.spec.thinkingLevel,
|
|
375
|
+
scriptName: script.name,
|
|
376
|
+
scriptPath: script.path,
|
|
377
|
+
description: script.meta.description,
|
|
378
|
+
parameters: script.meta.parameters,
|
|
379
|
+
parentWorkflowChain: chain,
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* 嵌套 workflow timeout 从父 run 完整传导:父 spec.budgetTimeMs 显式设定时原样作为子 run
|
|
385
|
+
* 轮询 deadline(不 min(DEFAULT) 封顶——旧实现把父 time:2h 截断到 10min,违背「显式传参
|
|
386
|
+
* 完整生效」语义);父未设 → undefined,无 deadline(不限)。
|
|
387
|
+
* [U2] 预算语义统一:父 budgetTimeMs <=0(含 0/负)与 undefined 同义 = 不限——与
|
|
388
|
+
* lifecycle.runWorkflow 的 budgetTimeMs 判定(>0 才挂 scheduleTimeBudget)对齐。
|
|
389
|
+
*/
|
|
390
|
+
function resolveNestedTimeoutMs(parentRun: WorkflowRun): number | undefined {
|
|
391
|
+
const raw = parentRun.spec.budgetTimeMs;
|
|
392
|
+
return raw !== undefined && raw > 0 ? raw : undefined;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Step 6: 结果转换(budget 已通过共享 budgetRef 实时同步,无需 sync-back)。
|
|
397
|
+
* completed → content = 字符串原样 / 其余 JSON.stringify;非 completed → error result。
|
|
398
|
+
*/
|
|
399
|
+
function toNestedCallResult(
|
|
400
|
+
name: string,
|
|
401
|
+
result: WorkflowRunResult,
|
|
402
|
+
): { content: string; parsedOutput?: unknown; error?: string } {
|
|
403
|
+
if (result.reason === "completed") {
|
|
404
|
+
const scriptResult = result.scriptResult;
|
|
405
|
+
return {
|
|
406
|
+
content:
|
|
407
|
+
typeof scriptResult === "string"
|
|
408
|
+
? scriptResult
|
|
409
|
+
: JSON.stringify(scriptResult ?? ""),
|
|
410
|
+
parsedOutput:
|
|
411
|
+
typeof scriptResult === "object" && scriptResult !== null
|
|
412
|
+
? scriptResult
|
|
413
|
+
: undefined,
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
return {
|
|
417
|
+
content: "",
|
|
418
|
+
error: result.error ?? `Workflow '${name}' ended: ${result.reason}`,
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
|
|
315
422
|
/**
|
|
316
423
|
* workflow() 嵌套调用的 Engine 实现。
|
|
317
424
|
*
|
|
318
|
-
* Worker 脚本内调 workflow(name, args) 时,
|
|
425
|
+
* Worker 脚本内调 workflow(name, args) 时,worker-message-pump.dispatchWorkflowCall 路由
|
|
319
426
|
* 到 deps.onWorkflowCall,后者(Interface 层 makeDeps 注入)委托本函数。
|
|
320
427
|
*
|
|
321
|
-
* 流程(6
|
|
428
|
+
* 流程(6 步,Step 2-6 的机制细节见各 helper):
|
|
322
429
|
* 1. 循环检测——name 已在 parentWorkflowChain 中则拒绝(防 A→B→A 死循环)
|
|
323
|
-
* 2. signal 继承——子 run 响应父 run abort(
|
|
430
|
+
* 2. signal 继承——子 run 响应父 run abort(inheritParentSignal)
|
|
324
431
|
* 3. registry.get + lint——失败返回 error result(不抛错,让脚本 soft-fail)
|
|
325
432
|
* 4. 构建 RunSpec(共享父 Budget 引用 + parentWorkflowChain 延长)+ runWorkflow
|
|
326
433
|
* 5. pollRunToResult 轮询至 done(复用 runAndWait 的轮询逻辑)
|
|
327
|
-
* 6. 结果转换(
|
|
434
|
+
* 6. 结果转换(toNestedCallResult)
|
|
328
435
|
*
|
|
329
436
|
* 不走 runAndWait:runAndWait 内部构建 RunSpec 不支持 parentWorkflowChain 与 budget
|
|
330
437
|
* 共享引用,故直接构建 spec + runWorkflow + pollRunToResult。
|
|
@@ -342,10 +449,7 @@ export async function executeNestedWorkflow(
|
|
|
342
449
|
deps: LauncherDeps,
|
|
343
450
|
): Promise<{ content: string; parsedOutput?: unknown; error?: string }> {
|
|
344
451
|
// Step 1: 循环检测——parentWorkflowChain 不存在时为 [](顶层 run)
|
|
345
|
-
const chain =
|
|
346
|
-
...(parentRun.spec.parentWorkflowChain ?? []),
|
|
347
|
-
parentRun.spec.scriptName,
|
|
348
|
-
];
|
|
452
|
+
const chain = buildParentChain(parentRun);
|
|
349
453
|
if (chain.includes(name)) {
|
|
350
454
|
return {
|
|
351
455
|
content: "",
|
|
@@ -354,21 +458,10 @@ export async function executeNestedWorkflow(
|
|
|
354
458
|
}
|
|
355
459
|
|
|
356
460
|
// Step 2: signal 继承——子 run 响应父 run abort
|
|
357
|
-
|
|
358
|
-
// parentSignal 上残留 listener(多次嵌套调用会累积)。
|
|
359
|
-
const childController = new AbortController();
|
|
360
|
-
const parentSignal = parentRun.runtime?.controller.signal;
|
|
361
|
-
const onParentAbort = (): void => childController.abort();
|
|
362
|
-
if (parentSignal) {
|
|
363
|
-
if (parentSignal.aborted) {
|
|
364
|
-
childController.abort();
|
|
365
|
-
} else {
|
|
366
|
-
parentSignal.addEventListener("abort", onParentAbort, { once: true });
|
|
367
|
-
}
|
|
368
|
-
}
|
|
461
|
+
const { childController, parentSignal, onParentAbort } = inheritParentSignal(parentRun);
|
|
369
462
|
|
|
370
463
|
// Step 3+:registry 查找 + lint + RunSpec + runWorkflow + poll 全程 try(m3 E8——
|
|
371
|
-
// try
|
|
464
|
+
// try 起点在 Step 2 的 listener 注册之后,覆盖 Step 3-6。runWorkflow throw
|
|
372
465
|
// (含 chokepoint ArgsValidationError)与 not found/lint 早返回均走 finally 移除
|
|
373
466
|
// parentSignal listener——修复原 try 外 runWorkflow 的泄漏路径)。
|
|
374
467
|
try {
|
|
@@ -379,76 +472,30 @@ export async function executeNestedWorkflow(
|
|
|
379
472
|
}
|
|
380
473
|
const lintResult = script.validate();
|
|
381
474
|
if (!lintResult.valid) {
|
|
382
|
-
const errors = lintResult.findings
|
|
383
|
-
.filter((f) => f.severity === "error")
|
|
384
|
-
.map((f) => `L${f.line}: ${f.message}`)
|
|
385
|
-
.join("; ");
|
|
386
475
|
return {
|
|
387
476
|
content: "",
|
|
388
|
-
error: `Workflow script '${name}' has lint errors: ${
|
|
477
|
+
error: `Workflow script '${name}' has lint errors: ${formatLintErrorSummary(lintResult)}`,
|
|
389
478
|
};
|
|
390
479
|
}
|
|
391
480
|
|
|
392
|
-
// Step 4: 构建 RunSpec
|
|
393
|
-
//
|
|
394
|
-
//
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
args,
|
|
398
|
-
budgetRef: parentRun.state.budget,
|
|
399
|
-
// Run-level override 传播(与父 run 对齐):子 run 继承父 run 的 model/thinkingLevel,
|
|
400
|
-
// 否则嵌套 workflow 丢失父 run 的模型指定,回落主 agent 模型。
|
|
401
|
-
model: parentRun.spec.model,
|
|
402
|
-
thinkingLevel: parentRun.spec.thinkingLevel,
|
|
403
|
-
scriptName: script.name,
|
|
404
|
-
scriptPath: script.path,
|
|
405
|
-
description: script.meta.description,
|
|
406
|
-
parameters: script.meta.parameters,
|
|
407
|
-
parentWorkflowChain: chain,
|
|
408
|
-
};
|
|
481
|
+
// Step 4: 构建 RunSpec + 启动子 workflow
|
|
482
|
+
// budgetRef(共享 Budget)已在 spec 透传给子 run 处理 token/cost 预算,
|
|
483
|
+
// resolveNestedTimeoutMs 的 budgetTimeMs 只服务 pollRunToResult 的轮询 deadline
|
|
484
|
+
// (wall-clock 兜底)。
|
|
485
|
+
const spec = buildNestedSpec(args, parentRun, script, chain);
|
|
409
486
|
const runId = await runWorkflow(spec, deps, childController.signal);
|
|
410
487
|
|
|
411
488
|
// Step 5: 轮询至 done(复用 runAndWait 的轮询逻辑)
|
|
412
|
-
// [H-1] 嵌套 workflow timeout 从父 run 完整传导:父 spec.budgetTimeMs 显式设定时
|
|
413
|
-
// 原样作为子 run 轮询 deadline(不 min(DEFAULT) 封顶——旧实现把父 time:2h 截断到
|
|
414
|
-
// 10min,违背「显式传参完整生效」语义);父未设 → undefined,无 deadline(不限)。
|
|
415
|
-
// budgetRef(共享 Budget)已在 Step 4 透传给子 run 处理 token/cost 预算,
|
|
416
|
-
// 此处的 budgetTimeMs 只服务 pollRunToResult 的轮询 deadline(wall-clock 兜底)。
|
|
417
|
-
// [U2] 预算语义统一:父 budgetTimeMs <=0(含 0/负)与 undefined 同义 = 不限——
|
|
418
|
-
// 与 lifecycle.runWorkflow 的 budgetTimeMs 判定(>0 才挂 scheduleTimeBudget)对齐。
|
|
419
|
-
// 旧实现 0 传导给子 run 后 deadline=now 立即超时("timed out after 0ms"),与
|
|
420
|
-
// lifecycle 的 0=不限 语义分裂。pollRunToResult 内亦对非正值兜底归一(双写防漂移),
|
|
421
|
-
// 此处显式归一是传导语义的文档化表达。
|
|
422
|
-
const rawNestedTimeoutMs = parentRun.spec.budgetTimeMs;
|
|
423
|
-
const nestedTimeoutMs =
|
|
424
|
-
rawNestedTimeoutMs !== undefined && rawNestedTimeoutMs > 0 ? rawNestedTimeoutMs : undefined;
|
|
425
|
-
|
|
426
489
|
const result = await pollRunToResult(
|
|
427
490
|
runId,
|
|
428
491
|
deps,
|
|
429
492
|
childController.signal,
|
|
430
|
-
|
|
493
|
+
resolveNestedTimeoutMs(parentRun),
|
|
431
494
|
"Aborted by parent signal",
|
|
432
495
|
);
|
|
433
496
|
|
|
434
|
-
// Step 6:
|
|
435
|
-
|
|
436
|
-
const scriptResult = result.scriptResult;
|
|
437
|
-
return {
|
|
438
|
-
content:
|
|
439
|
-
typeof scriptResult === "string"
|
|
440
|
-
? scriptResult
|
|
441
|
-
: JSON.stringify(scriptResult ?? ""),
|
|
442
|
-
parsedOutput:
|
|
443
|
-
typeof scriptResult === "object" && scriptResult !== null
|
|
444
|
-
? scriptResult
|
|
445
|
-
: undefined,
|
|
446
|
-
};
|
|
447
|
-
}
|
|
448
|
-
return {
|
|
449
|
-
content: "",
|
|
450
|
-
error: result.error ?? `Workflow '${name}' ended: ${result.reason}`,
|
|
451
|
-
};
|
|
497
|
+
// Step 6: 结果转换
|
|
498
|
+
return toNestedCallResult(name, result);
|
|
452
499
|
} catch (err) {
|
|
453
500
|
// m3:chokepoint 校验失败 → {error}(§5.3 指引文案),非 ArgsValidationError 保持传播
|
|
454
501
|
// (dispatchWorkflowCall 的 .catch 兜底转 postResult,worker 不崩)。
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
* 「releaseRuntime → 改 status」原子顺序。
|
|
25
25
|
*
|
|
26
26
|
* **G3-001**(run 一次性生命周期):AbortController 一次性无法复用,runtime 释放后
|
|
27
|
-
* 只有两类重建——rebuildRuntime(
|
|
27
|
+
* 只有两类重建——rebuildRuntime(worker-message-pump,崩溃重试路径,run 保持 running、
|
|
28
28
|
* replaceRuntime 原子换新)与 abort/terminate 的终态释放(transition("done") 内
|
|
29
29
|
* releaseRuntime,run 不再恢复)。
|
|
30
30
|
* (旧并发门闩 gate 抽象已删——no-op 无生产语义,实际并发由 SubagentService
|
|
@@ -42,12 +42,11 @@ import { assertSafeTimerDelay } from "../shared/timer-delay.ts";
|
|
|
42
42
|
import { validateRunArgs } from "./args-validator.ts";
|
|
43
43
|
import {
|
|
44
44
|
closeOutInFlightCalls,
|
|
45
|
-
|
|
46
|
-
emitTerminalSideEffects,
|
|
45
|
+
finalizeRun,
|
|
47
46
|
handleWorkerError,
|
|
48
47
|
handleWorkerExit,
|
|
49
48
|
handleWorkerMessage,
|
|
50
|
-
} from "./
|
|
49
|
+
} from "./worker-message-pump.ts";
|
|
51
50
|
import { Budget } from "./models/budget.ts";
|
|
52
51
|
import type { LifecycleDeps, RunStore, WorkerHandlers } from "./models/ports.ts";
|
|
53
52
|
import { RunRuntime } from "./models/run-runtime.ts";
|
|
@@ -56,6 +55,7 @@ import { Trace } from "./models/trace.ts";
|
|
|
56
55
|
import type { DoneReason } from "./models/types.ts";
|
|
57
56
|
import { WorkflowRun } from "./models/workflow-run.ts";
|
|
58
57
|
import type { WorkerHandle } from "./worker-handle.ts";
|
|
58
|
+
import { toErrorMessage } from "../core/error-message.ts";
|
|
59
59
|
|
|
60
60
|
const logger = getLogger("subagents");
|
|
61
61
|
|
|
@@ -118,24 +118,24 @@ function broadcastAbortToWorker(run: WorkflowRun, reason: string): void {
|
|
|
118
118
|
try {
|
|
119
119
|
run.runtime?.worker.postMessage({ type: "abort", reason });
|
|
120
120
|
} catch (err) {
|
|
121
|
-
const msg =
|
|
121
|
+
const msg = toErrorMessage(err);
|
|
122
122
|
logger.debug(
|
|
123
123
|
`[workflow] abort broadcast to worker failed (runId=${run.runId}, worker likely already exited): ${msg}`,
|
|
124
124
|
);
|
|
125
125
|
}
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
-
// ── makeHandlers(路由 worker 事件到
|
|
128
|
+
// ── makeHandlers(路由 worker 事件到 worker-message-pump handle* 函数) ──────
|
|
129
129
|
|
|
130
130
|
/**
|
|
131
131
|
* 构造 WorkerHandlers——将 worker 的 onMessage/onError/onExit 事件路由到
|
|
132
|
-
*
|
|
132
|
+
* worker-message-pump 的 handleWorker* 函数。
|
|
133
133
|
*
|
|
134
134
|
* 闭包捕获 run + deps。runtime 重建(replaceRuntime)后 run 实例不变、deps 不变,
|
|
135
|
-
* 故 handlers 对新 worker 仍有效(lifecycle 与
|
|
135
|
+
* 故 handlers 对新 worker 仍有效(lifecycle 与 worker-message-pump 共用 handlers)。
|
|
136
136
|
*
|
|
137
137
|
* **onExit G-025**:handleWorkerExit 内部检查 handle.isCurrent(stale exit 丢弃)。
|
|
138
|
-
* 本函数不在 onExit 里重复检查——
|
|
138
|
+
* 本函数不在 onExit 里重复检查——worker-message-pump.handleWorkerExit 是单一守卫点。
|
|
139
139
|
*
|
|
140
140
|
* **workerErrorCount**:onError 触发时递增(C.5 跨 runtime 存活的重试计数载体)。
|
|
141
141
|
* 注意 handleWorkerError 内部也会递增——这里 onError 递增是 worker 事件层面的
|
|
@@ -144,10 +144,10 @@ function broadcastAbortToWorker(run: WorkflowRun, reason: string): void {
|
|
|
144
144
|
*/
|
|
145
145
|
function makeHandlers(run: WorkflowRun, deps: LifecycleDeps): WorkerHandlers {
|
|
146
146
|
// [OR-7] per-run deps 视图:包装 onRunDone,把「run 终态」转译为「移除 signal abort
|
|
147
|
-
// listener」。
|
|
147
|
+
// listener」。worker-message-pump 全部终态路径(handleReturn / handleWorkerError /
|
|
148
148
|
// handleScriptError / handleWorkerExit / 预算终止 / time_limited / [OR-2] rebuild
|
|
149
|
-
//
|
|
150
|
-
// abortRun / terminateRunningRuns 两个 lifecycle 自有终态路径另行显式 dispose。
|
|
149
|
+
// 失败收敛——均经 finalizeRun)都经 handlers 调用链消费本视图——消息面终态在此
|
|
150
|
+
// 统一收口;abortRun / terminateRunningRuns 两个 lifecycle 自有终态路径另行显式 dispose。
|
|
151
151
|
const depsWithTerminalCleanup: LifecycleDeps = {
|
|
152
152
|
...deps,
|
|
153
153
|
onRunDone: (doneRun: WorkflowRun): void => {
|
|
@@ -155,7 +155,7 @@ function makeHandlers(run: WorkflowRun, deps: LifecycleDeps): WorkerHandlers {
|
|
|
155
155
|
deps.onRunDone?.(doneRun);
|
|
156
156
|
},
|
|
157
157
|
};
|
|
158
|
-
// 自引用——
|
|
158
|
+
// 自引用——worker-message-pump rebuildRuntime 需要 handlers 参数(handlers 引用自身)
|
|
159
159
|
const handlers: WorkerHandlers = {
|
|
160
160
|
async onMessage(raw: unknown): Promise<void> {
|
|
161
161
|
await handleWorkerMessage(run, raw, depsWithTerminalCleanup, handlers);
|
|
@@ -198,7 +198,7 @@ export function scheduleTimeBudget(
|
|
|
198
198
|
const timer = setTimeout(() => {
|
|
199
199
|
void abortRun(runId, deps, "Time budget exceeded", "time_limited").catch(
|
|
200
200
|
(err: unknown) => {
|
|
201
|
-
const msg =
|
|
201
|
+
const msg = toErrorMessage(err);
|
|
202
202
|
logger.error(`[workflow] time budget abort failed: ${msg}`);
|
|
203
203
|
},
|
|
204
204
|
);
|
|
@@ -213,7 +213,7 @@ export function scheduleTimeBudget(
|
|
|
213
213
|
/**
|
|
214
214
|
* rfl 仪表(tier-1 §7.1):向 spec.args 原地注入稳定 _runId。runAndWait 与
|
|
215
215
|
* executeNestedWorkflow 两个 args 入口都经 runWorkflow 这一 choke point;
|
|
216
|
-
* rebuildRuntime 复用 run.spec.args 同一对象(
|
|
216
|
+
* rebuildRuntime 复用 run.spec.args 同一对象(worker-message-pump.ts),worker rebuild
|
|
217
217
|
* 后脚本侧 $ARGS._runId 不漂移——修复「rebuild 回退 run-<Date.now()> 导致同一
|
|
218
218
|
* 逻辑 run 碎裂到多个 state 目录」。注入在 validateRunArgs 之后,不参与脚本
|
|
219
219
|
* 参数 schema 校验(引擎内部字段)。
|
|
@@ -307,7 +307,7 @@ function registerSignalAbortListener(
|
|
|
307
307
|
const onAbort = (): void => {
|
|
308
308
|
disposeSignalAbortListener(run);
|
|
309
309
|
void abortRun(runId, deps, "External signal aborted").catch((err: unknown) => {
|
|
310
|
-
const msg =
|
|
310
|
+
const msg = toErrorMessage(err);
|
|
311
311
|
logger.error(`[workflow] abortRun on signal failed: ${msg}`);
|
|
312
312
|
});
|
|
313
313
|
};
|
|
@@ -426,20 +426,16 @@ export async function abortRun(
|
|
|
426
426
|
// [OR-3] 先广播 abort 再 transition(transition 内 releaseRuntime→terminate,
|
|
427
427
|
// terminate 之后广播发不进去)——worker 侧 pending 优雅解阻
|
|
428
428
|
broadcastAbortToWorker(run, reason ?? `Workflow aborted (${doneReason})`);
|
|
429
|
-
// A4: transition 内部 releaseRuntime(cleanup before mutate)
|
|
430
|
-
run.transition("done", doneReason);
|
|
431
429
|
// [OR-7] run 终态:移除 signal abort listener(幂等;abort 由 signal 触发时
|
|
432
|
-
// listener 已在 onAbort 内自移除,此处为其余 abort
|
|
430
|
+
// listener 已在 onAbort 内自移除,此处为其余 abort 入口的收口;即使 finalizeRun
|
|
431
|
+
// 因并发终态化让位,WeakMap 条目也应清除,不依赖 transition 成败)
|
|
433
432
|
disposeSignalAbortListener(run);
|
|
434
|
-
//
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
//
|
|
439
|
-
|
|
440
|
-
// listener 同步抛错不再跳过 onRunDone 或把错误抛给 abort 调用方;错误 error 留痕后
|
|
441
|
-
// 本函数仍按 abort 成功语义正常返回(内存态已终态)。
|
|
442
|
-
emitTerminalSideEffects(run, deps, `abortRun (done,${doneReason})`);
|
|
433
|
+
// A4 + C-4: transition 内部 releaseRuntime(cleanup before mutate);到达 done 终态
|
|
434
|
+
// → 注销 pending-notification + 通知 Interface 层(D5-② 终态 coda 收敛为
|
|
435
|
+
// worker-message-pump 的 finalizeRun 单写点——OR-8 in-flight 收口 + save best-effort
|
|
436
|
+
// (SW-DATA-3)不再向上抛,内存态已终态,调用方无需因落盘失败收到 abort 异常;
|
|
437
|
+
// OR-4/B-4 unregister 与 onRunDone 各自独立围栏)
|
|
438
|
+
await finalizeRun(run, deps, doneReason, { context: `abortRun (${doneReason})` });
|
|
443
439
|
}
|
|
444
440
|
|
|
445
441
|
// ── terminateRunningRuns(session 切换/关闭:终止全部 running run) ────────
|
|
@@ -451,11 +447,12 @@ export async function abortRun(
|
|
|
451
447
|
* done,failed 持久化落盘——重启后 kill-9 恢复不误判,也不再存在「挂起待恢复」
|
|
452
448
|
* 的中间态。
|
|
453
449
|
*
|
|
454
|
-
* per-run 行为:`state.error = reason` → `
|
|
455
|
-
* releaseRuntime,A4
|
|
456
|
-
* {reason:"failed"})
|
|
450
|
+
* per-run 行为:`state.error = reason` → `finalizeRun(run, deps, "failed",
|
|
451
|
+
* {notifyDone:false})`(transition("done","failed") 内部先 releaseRuntime,A4 →
|
|
452
|
+
* save best-effort → `eventBus.emit("pending:unregister", {reason:"failed"})`)。
|
|
457
453
|
*
|
|
458
|
-
* **不调 deps.onRunDone
|
|
454
|
+
* **不调 deps.onRunDone**(经 finalizeRun 的 notifyDone:false 承载,D5-②):
|
|
455
|
+
* 对齐 session_start 恢复先例(index.ts kill-9 恢复只发
|
|
459
456
|
* unregister、不发 onRunDone)——session 切换/关闭语境下主 agent 已离开本 session,
|
|
460
457
|
* 注入完成通知只会把消息发给已离开的 session。
|
|
461
458
|
*
|
|
@@ -480,21 +477,22 @@ export async function terminateRunningRuns(
|
|
|
480
477
|
run.state.error = reason;
|
|
481
478
|
// [OR-3] 同 abortRun:先广播 abort 再 transition(worker 侧 pending 优雅解阻)
|
|
482
479
|
broadcastAbortToWorker(run, reason);
|
|
483
|
-
// A4: transition 内部先 releaseRuntime(cleanup before mutate)
|
|
484
|
-
run.transition("done", "failed");
|
|
485
480
|
// [OR-7] run 终态:移除 signal abort listener(terminateRunningRuns 不走
|
|
486
|
-
// onRunDone
|
|
481
|
+
// onRunDone——本路径显式收口,不依赖 finalizeRun 的 notifyDone 分支)
|
|
487
482
|
disposeSignalAbortListener(run);
|
|
488
|
-
//
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
//
|
|
492
|
-
//
|
|
493
|
-
//
|
|
494
|
-
|
|
483
|
+
// A4 + C-4: transition 内部 releaseRuntime(cleanup before mutate);done 终态 →
|
|
484
|
+
// 注销 pending-notification(D5-② 终态 coda 收敛为 finalizeRun 单写点)。
|
|
485
|
+
// notifyDone: false——**不调 deps.onRunDone**(真差异经参数承载):对齐
|
|
486
|
+
// session_start 恢复先例(index.ts kill-9 恢复只发 unregister、不发
|
|
487
|
+
// onRunDone)——session 切换/关闭语境下主 agent 已离开本 session,注入完成
|
|
488
|
+
// 通知只会把消息发给已离开的 session。OR-8 in-flight 收口由 finalizeRun 承载。
|
|
489
|
+
await finalizeRun(run, deps, "failed", {
|
|
490
|
+
context: "terminateRunningRuns",
|
|
491
|
+
notifyDone: false,
|
|
492
|
+
});
|
|
495
493
|
deps.log?.("debug", "workflow:lifecycle", "run terminated", { runId: run.runId, reason: run.state.reason });
|
|
496
494
|
} catch (err) {
|
|
497
|
-
const msg =
|
|
495
|
+
const msg = toErrorMessage(err);
|
|
498
496
|
logger.error(
|
|
499
497
|
`[workflow] terminateRunningRuns failed for run ${run.runId}: ${msg} (reason: ${reason})`,
|
|
500
498
|
);
|
|
@@ -644,7 +642,7 @@ export async function recoverCrashedRuns(
|
|
|
644
642
|
try {
|
|
645
643
|
hooks?.onRunRecovered?.({ id: run.runId, reason: "failed" });
|
|
646
644
|
} catch (err) {
|
|
647
|
-
const msg =
|
|
645
|
+
const msg = toErrorMessage(err);
|
|
648
646
|
logger.warn(
|
|
649
647
|
`[workflow] recoverCrashedRuns onRunRecovered hook failed for run ${run.runId} (recovery continues): ${msg}`,
|
|
650
648
|
);
|
|
@@ -653,7 +651,7 @@ export async function recoverCrashedRuns(
|
|
|
653
651
|
try {
|
|
654
652
|
await store.save(run);
|
|
655
653
|
} catch (err) {
|
|
656
|
-
const msg =
|
|
654
|
+
const msg = toErrorMessage(err);
|
|
657
655
|
logger.error(
|
|
658
656
|
`[workflow] recoverCrashedRuns store.save failed for run ${run.runId}: ${msg} (reason: ${reason})`,
|
|
659
657
|
);
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* 是真需要 mock 测试的依赖(子进程/文件系统/线程)。
|
|
6
6
|
*
|
|
7
7
|
* 编排层共享类型(WorkerHandlers / LifecycleDeps)——打破 lifecycle ↔
|
|
8
|
-
*
|
|
8
|
+
* worker-message-pump 循环依赖:2 个 engine 函数文件各自独立,共用同一组
|
|
9
9
|
* 依赖签名(D-12)。
|
|
10
10
|
*
|
|
11
11
|
* 层归属:Engine。零 infra 依赖(AC-1)。
|
|
@@ -71,7 +71,7 @@ export interface WorkerHost {
|
|
|
71
71
|
|
|
72
72
|
/**
|
|
73
73
|
* Worker 线程事件回调集合——WorkerHost.start 的入参,由 lifecycle
|
|
74
|
-
* 构造并注入。2 个 engine 文件(lifecycle /
|
|
74
|
+
* 构造并注入。2 个 engine 文件(lifecycle / worker-message-pump)共用此签名,
|
|
75
75
|
* 避免各自定义形状不一致的 handler bag(打破循环依赖)。
|
|
76
76
|
*
|
|
77
77
|
* 所有回调返回 Promise——允许 engine 层在回调内做 await persistState 等异步操作。
|
|
@@ -88,7 +88,7 @@ export interface WorkerHandlers {
|
|
|
88
88
|
// ── 编排层共享类型 2: LifecycleDeps ────────────────────────────
|
|
89
89
|
|
|
90
90
|
/**
|
|
91
|
-
* lifecycle /
|
|
91
|
+
* lifecycle / worker-message-pump 2 个 engine 函数文件的共同依赖 bag。
|
|
92
92
|
*
|
|
93
93
|
* 取代旧 4 个 Context factory(errorHandlerContext / agentCallContext /
|
|
94
94
|
* budgetCallbacks / 旧 terminate bag,AC-2 目标)。函数签名 `(deps: LifecycleDeps, ...)`
|
|
@@ -142,7 +142,7 @@ export interface LifecycleDeps {
|
|
|
142
142
|
* workflow() 嵌套调用回调(可选)。Worker 脚本内调 workflow(name, args) 时触发。
|
|
143
143
|
*
|
|
144
144
|
* 由 Interface 层 makeDeps 注入(闭包捕获 registry + deps)。Engine 层的
|
|
145
|
-
*
|
|
145
|
+
* worker-message-pump.handleWorkerMessage 收到 workflow-call 消息后调本回调,
|
|
146
146
|
* 拿到子 workflow 执行结果后 postMessage(workflow-result) 回 worker。
|
|
147
147
|
*
|
|
148
148
|
* 不注入时 workflow() 返回 error result(向后兼容,不影响非嵌套场景)。
|