@zhushanwen/subagent-core 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +114 -0
- package/dist/chunk-3VOERJPJ.js +22 -0
- package/dist/chunk-A4IVZWVX.js +31 -0
- package/dist/execution/engine/engines/zcode/constants.cjs +54 -0
- package/dist/execution/engine/engines/zcode/constants.d.cts +31 -0
- package/dist/execution/engine/engines/zcode/constants.d.ts +31 -0
- package/dist/execution/engine/engines/zcode/constants.js +22 -0
- package/dist/execution/engine/engines/zcode/reader.cjs +276 -0
- package/dist/execution/engine/engines/zcode/reader.d.cts +20 -0
- package/dist/execution/engine/engines/zcode/reader.d.ts +20 -0
- package/dist/execution/engine/engines/zcode/reader.js +239 -0
- package/dist/execution/engine/paths.cjs +55 -0
- package/dist/execution/engine/paths.d.cts +8 -0
- package/dist/execution/engine/paths.d.ts +8 -0
- package/dist/execution/engine/paths.js +26 -0
- package/dist/execution/relay-env.cjs +62 -0
- package/dist/execution/relay-env.d.cts +33 -0
- package/dist/execution/relay-env.d.ts +33 -0
- package/dist/execution/relay-env.js +20 -0
- package/dist/index.cjs +1852 -0
- package/dist/index.d.cts +1184 -0
- package/dist/index.d.ts +1184 -0
- package/dist/index.js +1810 -0
- package/dist/types-BxyAidGf.d.cts +875 -0
- package/dist/types-BxyAidGf.d.ts +875 -0
- package/package.json +99 -0
- package/src/__tests__/agent-opts-resolver-schema-prompt.test.ts +142 -0
- package/src/__tests__/append-system-prompt-assembly.test.ts +242 -0
- package/src/__tests__/builtin-workflows-structure.test.ts +180 -0
- package/src/__tests__/derive-closed-display-parity.test.ts +93 -0
- package/src/__tests__/fr4-get-state-handshake.test.ts +125 -0
- package/src/__tests__/fr8-orphan-recovery.test.ts +259 -0
- package/src/__tests__/m2-append-content-probe.test.ts +73 -0
- package/src/__tests__/manifest-store.test.ts +368 -0
- package/src/__tests__/record-store-cache.test.ts +335 -0
- package/src/__tests__/record-store-index.test.ts +560 -0
- package/src/__tests__/record-store-last-line.test.ts +129 -0
- package/src/__tests__/review-fix-loop-script.test.ts +288 -0
- package/src/__tests__/review-fix-loop-utils.test.ts +2377 -0
- package/src/__tests__/robustness-low-batch1.test.ts +286 -0
- package/src/__tests__/robustness-medium-batch1.test.ts +69 -0
- package/src/__tests__/robustness-medium-batch2.test.ts +65 -0
- package/src/__tests__/robustness-medium-batch3.test.ts +30 -0
- package/src/__tests__/robustness-medium-batch4.test.ts +358 -0
- package/src/__tests__/session-runner.test.ts +69 -0
- package/src/__tests__/smoke.test.ts +9 -0
- package/src/__tests__/stream-sink.test.ts +203 -0
- package/src/core/__tests__/host-services.test.ts +144 -0
- package/src/core/__tests__/logger.test.ts +78 -0
- package/src/core/__tests__/notify-ports.test.ts +104 -0
- package/src/core/host-services.ts +97 -0
- package/src/core/logger.ts +47 -0
- package/src/core/notify-ports.ts +126 -0
- package/src/execution/__tests__/__fixtures__/notifier-golden-snapshots.json +53 -0
- package/src/execution/__tests__/__fixtures__/truncline.snapshot.json +1 -0
- package/src/execution/__tests__/agent-result-mapper.test.ts +150 -0
- package/src/execution/__tests__/alive-store.test.ts +147 -0
- package/src/execution/__tests__/ask-user-transit-e2e.test.ts +490 -0
- package/src/execution/__tests__/channel-registry-handshake.test.ts +242 -0
- package/src/execution/__tests__/chat-engine-routing.test.ts +610 -0
- package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +190 -0
- package/src/execution/__tests__/concurrency-pool.test.ts +250 -0
- package/src/execution/__tests__/config.test.ts +302 -0
- package/src/execution/__tests__/delivery-methods.test.ts +424 -0
- package/src/execution/__tests__/dialog-queue.test.ts +299 -0
- package/src/execution/__tests__/epipe-fallback.test.ts +241 -0
- package/src/execution/__tests__/execute-and-await-worktree.test.ts +243 -0
- package/src/execution/__tests__/execute-nesting.test.ts +323 -0
- package/src/execution/__tests__/execute-options-mapper.test.ts +200 -0
- package/src/execution/__tests__/execution-record.test.ts +1394 -0
- package/src/execution/__tests__/explicit-agent-ref-guard.test.ts +171 -0
- package/src/execution/__tests__/finalize-record.test.ts +367 -0
- package/src/execution/__tests__/finalized-marker.test.ts +104 -0
- package/src/execution/__tests__/format-schema-instruction.test.ts +169 -0
- package/src/execution/__tests__/gc-timer.test.ts +184 -0
- package/src/execution/__tests__/get-record-for-action-restart.test.ts +254 -0
- package/src/execution/__tests__/helpers/mock-extension-api.ts +30 -0
- package/src/execution/__tests__/helpers/spawn-mock.ts +242 -0
- package/src/execution/__tests__/host-mode.test.ts +87 -0
- package/src/execution/__tests__/lifecycle-manager-lock.test.ts +211 -0
- package/src/execution/__tests__/lifecycle-manager.test.ts +383 -0
- package/src/execution/__tests__/lifecycle-predicates.test.ts +116 -0
- package/src/execution/__tests__/manifest-parentid.test.ts +117 -0
- package/src/execution/__tests__/model-resolver.test.ts +465 -0
- package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +287 -0
- package/src/execution/__tests__/nested-visibility.test.ts +325 -0
- package/src/execution/__tests__/output-collector.test.ts +358 -0
- package/src/execution/__tests__/path-encoding.test.ts +104 -0
- package/src/execution/__tests__/pi-invocation.test.ts +134 -0
- package/src/execution/__tests__/record-store.test.ts +1057 -0
- package/src/execution/__tests__/records-cwd-isolation.test.ts +91 -0
- package/src/execution/__tests__/recursive-visibility-baseline.test.ts +339 -0
- package/src/execution/__tests__/recursive-visibility-env.test.ts +273 -0
- package/src/execution/__tests__/relay-env.test.ts +42 -0
- package/src/execution/__tests__/resource-policy.test.ts +109 -0
- package/src/execution/__tests__/rpc-mode.test.ts +89 -0
- package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +267 -0
- package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +253 -0
- package/src/execution/__tests__/run-spawn-edges.test.ts +687 -0
- package/src/execution/__tests__/run-spawn-integration.test.ts +933 -0
- package/src/execution/__tests__/run-spawn-resume.test.ts +322 -0
- package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +196 -0
- package/src/execution/__tests__/run-spawn-stdout-callback-throw.test.ts +199 -0
- package/src/execution/__tests__/session-context-resolver.test.ts +167 -0
- package/src/execution/__tests__/session-file-gc.test.ts +293 -0
- package/src/execution/__tests__/session-reconstructor.test.ts +379 -0
- package/src/execution/__tests__/session-runner-epipe.test.ts +178 -0
- package/src/execution/__tests__/session-runner-schema-env.test.ts +350 -0
- package/src/execution/__tests__/spawn-args.test.ts +445 -0
- package/src/execution/__tests__/spawn-event-adapter-rpc.test.ts +189 -0
- package/src/execution/__tests__/spawn-event-adapter.test.ts +167 -0
- package/src/execution/__tests__/spawn-worktree-guidance.test.ts +207 -0
- package/src/execution/__tests__/spawned-children.test.ts +92 -0
- package/src/execution/__tests__/start-sync-model-guard.test.ts +150 -0
- package/src/execution/__tests__/stdin-writer.test.ts +462 -0
- package/src/execution/__tests__/stream-sink-retirement.test.ts +261 -0
- package/src/execution/__tests__/subagent-service-abort.test.ts +60 -0
- package/src/execution/__tests__/subagent-service-message-close.test.ts +629 -0
- package/src/execution/__tests__/subagent-service-parent-guard.test.ts +180 -0
- package/src/execution/__tests__/subagent-service.test.ts +788 -0
- package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +310 -0
- package/src/execution/__tests__/subprocess-agent-runner.test.ts +612 -0
- package/src/execution/__tests__/temp-prompt.test.ts +53 -0
- package/src/execution/__tests__/timeout-integration.test.ts +615 -0
- package/src/execution/__tests__/tombstone-store.test.ts +73 -0
- package/src/execution/__tests__/turn-limiter-semantics.test.ts +194 -0
- package/src/execution/__tests__/turn-limiter.test.ts +65 -0
- package/src/execution/__tests__/ui-channels.test.ts +187 -0
- package/src/execution/__tests__/ui-interaction-model.test.ts +67 -0
- package/src/execution/__tests__/ui-request-handler-factory.test.ts +369 -0
- package/src/execution/__tests__/ui-request-handler.test.ts +204 -0
- package/src/execution/__tests__/ui-request-observability.test.ts +113 -0
- package/src/execution/__tests__/ui-request-queue.test.ts +133 -0
- package/src/execution/__tests__/worktree-manager.test.ts +633 -0
- package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +229 -0
- package/src/execution/__tests__/worktree-reconcile.integration.test.ts +181 -0
- package/src/execution/__tests__/worktree-registry.test.ts +199 -0
- package/src/execution/agent-registry.ts +199 -0
- package/src/execution/agent-result-mapper.ts +90 -0
- package/src/execution/alive-store.ts +119 -0
- package/src/execution/argv-mirror.ts +113 -0
- package/src/execution/best-effort.ts +38 -0
- package/src/execution/channel-registry-access.ts +144 -0
- package/src/execution/concurrency-pool.ts +116 -0
- package/src/execution/config.ts +165 -0
- package/src/execution/dialog-queue.ts +330 -0
- package/src/execution/engine/__tests__/common/data-dir.test.ts +78 -0
- package/src/execution/engine/__tests__/common/errors.test.ts +132 -0
- package/src/execution/engine/__tests__/common/event-journal.test.ts +177 -0
- package/src/execution/engine/__tests__/common/kill-chain.test.ts +192 -0
- package/src/execution/engine/__tests__/common/nesting-guard.test.ts +81 -0
- package/src/execution/engine/__tests__/common/persona-router.test.ts +123 -0
- package/src/execution/engine/__tests__/common/pool-manager.test.ts +154 -0
- package/src/execution/engine/__tests__/common/schema-emulation.test.ts +128 -0
- package/src/execution/engine/__tests__/conformance/__fixtures__/pi-golden-events.json +28 -0
- package/src/execution/engine/__tests__/conformance/agent-event-invariants.ts +141 -0
- package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +109 -0
- package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +101 -0
- package/src/execution/engine/__tests__/conformance/contract.probe.test.ts +77 -0
- package/src/execution/engine/__tests__/conformance/contract.read-degradation.test.ts +104 -0
- package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +201 -0
- package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +76 -0
- package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +79 -0
- package/src/execution/engine/__tests__/engine-discovery.test.ts +87 -0
- package/src/execution/engine/__tests__/model-prompt.test.ts +197 -0
- package/src/execution/engine/__tests__/paths.test.ts +39 -0
- package/src/execution/engine/__tests__/registry.test.ts +120 -0
- package/src/execution/engine/__tests__/routing.test.ts +231 -0
- package/src/execution/engine/common/data-dir.ts +66 -0
- package/src/execution/engine/common/errors.ts +183 -0
- package/src/execution/engine/common/event-journal.ts +254 -0
- package/src/execution/engine/common/journal-replay.ts +62 -0
- package/src/execution/engine/common/kill-chain.ts +221 -0
- package/src/execution/engine/common/nesting-guard.ts +50 -0
- package/src/execution/engine/common/persona-router.ts +108 -0
- package/src/execution/engine/common/pool-manager.ts +226 -0
- package/src/execution/engine/common/schema-emulation.ts +189 -0
- package/src/execution/engine/common/session-view-projection.ts +51 -0
- package/src/execution/engine/engine-discovery.ts +65 -0
- package/src/execution/engine/engines/pi/__tests__/pi-engine.test.ts +469 -0
- package/src/execution/engine/engines/pi/__tests__/reader.test.ts +155 -0
- package/src/execution/engine/engines/pi/__tests__/task-spec-mapper.test.ts +164 -0
- package/src/execution/engine/engines/pi/pi-engine.ts +415 -0
- package/src/execution/engine/engines/pi/reader.ts +48 -0
- package/src/execution/engine/engines/pi/registration.ts +35 -0
- package/src/execution/engine/engines/pi/task-spec-mapper.ts +100 -0
- package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-spawn.json +39 -0
- package/src/execution/engine/engines/zcode/__tests__/launcher.test.ts +150 -0
- package/src/execution/engine/engines/zcode/__tests__/parser.test.ts +246 -0
- package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +228 -0
- package/src/execution/engine/engines/zcode/__tests__/reader.test.ts +210 -0
- package/src/execution/engine/engines/zcode/__tests__/registration.test.ts +71 -0
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +127 -0
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine.test.ts +580 -0
- package/src/execution/engine/engines/zcode/constants.ts +43 -0
- package/src/execution/engine/engines/zcode/golden-sample.ts +39 -0
- package/src/execution/engine/engines/zcode/launcher.ts +161 -0
- package/src/execution/engine/engines/zcode/parser.ts +436 -0
- package/src/execution/engine/engines/zcode/preparer.ts +363 -0
- package/src/execution/engine/engines/zcode/reader.ts +381 -0
- package/src/execution/engine/engines/zcode/registration.ts +37 -0
- package/src/execution/engine/engines/zcode/zcode-engine.ts +658 -0
- package/src/execution/engine/host-task-spec.ts +47 -0
- package/src/execution/engine/model-prompt.ts +158 -0
- package/src/execution/engine/paths.ts +42 -0
- package/src/execution/engine/port.ts +153 -0
- package/src/execution/engine/registry.ts +133 -0
- package/src/execution/engine/routing.ts +218 -0
- package/src/execution/engine/types.ts +309 -0
- package/src/execution/execute-options-mapper.ts +115 -0
- package/src/execution/execution-record.ts +984 -0
- package/src/execution/finalize-record.ts +254 -0
- package/src/execution/finalized-marker.ts +70 -0
- package/src/execution/get-state-handshake.ts +104 -0
- package/src/execution/host-mode.ts +56 -0
- package/src/execution/idle-gc.ts +47 -0
- package/src/execution/lifecycle-manager.ts +513 -0
- package/src/execution/lifecycle-predicates.ts +65 -0
- package/src/execution/manifest-store.ts +256 -0
- package/src/execution/model-config-service.ts +250 -0
- package/src/execution/model-resolver.ts +248 -0
- package/src/execution/notifier.ts +372 -0
- package/src/execution/notify-ledger.ts +580 -0
- package/src/execution/output-collector.ts +228 -0
- package/src/execution/path-encoding.ts +60 -0
- package/src/execution/pi-invocation.ts +120 -0
- package/src/execution/record-entry.ts +132 -0
- package/src/execution/record-store.ts +1265 -0
- package/src/execution/relay-env.ts +37 -0
- package/src/execution/session-context-resolver.ts +64 -0
- package/src/execution/session-file-gc.ts +120 -0
- package/src/execution/session-pending.ts +170 -0
- package/src/execution/session-reconstructor.ts +678 -0
- package/src/execution/session-runner.ts +1789 -0
- package/src/execution/sessions-index.ts +304 -0
- package/src/execution/spawn-event-adapter.ts +363 -0
- package/src/execution/stdin-writer.ts +198 -0
- package/src/execution/stream-sink.ts +126 -0
- package/src/execution/subagent-service.ts +2268 -0
- package/src/execution/subprocess-agent-runner.ts +317 -0
- package/src/execution/temp-prompt.ts +62 -0
- package/src/execution/tombstone-store.ts +72 -0
- package/src/execution/turn-limiter.ts +102 -0
- package/src/execution/types.ts +1023 -0
- package/src/execution/ui-channels.ts +216 -0
- package/src/execution/ui-interaction-model.ts +48 -0
- package/src/execution/ui-request-handler-factory.ts +243 -0
- package/src/execution/ui-request-observability.ts +81 -0
- package/src/execution/ui-request-queue.ts +184 -0
- package/src/execution/worktree-manager.ts +688 -0
- package/src/execution/worktree-registry.ts +279 -0
- package/src/index.ts +87 -0
- package/src/orchestration/__tests__/__fixtures__/worker-template.snapshot.txt +349 -0
- package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +202 -0
- package/src/orchestration/__tests__/agent-call-stream.test.ts +152 -0
- package/src/orchestration/__tests__/args-validator.test.ts +143 -0
- package/src/orchestration/__tests__/config-loader.test.ts +503 -0
- package/src/orchestration/__tests__/error-recovery-handlers.test.ts +809 -0
- package/src/orchestration/__tests__/error-recovery-postmessage-defense.test.ts +404 -0
- package/src/orchestration/__tests__/error-recovery-serialize-failed-result.test.ts +56 -0
- package/src/orchestration/__tests__/error-recovery-workflow-call.test.ts +166 -0
- package/src/orchestration/__tests__/execute-agent-call.test.ts +451 -0
- package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +600 -0
- package/src/orchestration/__tests__/lifecycle-runid-injection.test.ts +96 -0
- package/src/orchestration/__tests__/lifecycle.test.ts +659 -0
- package/src/orchestration/__tests__/non-cloneable-return-e2e.test.ts +95 -0
- package/src/orchestration/__tests__/review-fix-loop-scriptpath-failfast.test.ts +183 -0
- package/src/orchestration/__tests__/script-lint.test.ts +831 -0
- package/src/orchestration/__tests__/skill-discovery.test.ts +210 -0
- package/src/orchestration/__tests__/test-mocks.ts +197 -0
- package/src/orchestration/__tests__/worker-exit-without-result.test.ts +368 -0
- package/src/orchestration/__tests__/worker-host.test.ts +120 -0
- package/src/orchestration/__tests__/worker-returnmeta-passthrough.test.ts +164 -0
- package/src/orchestration/__tests__/worker-script-builder-runtime.test.ts +563 -0
- package/src/orchestration/__tests__/worker-script-builder.test.ts +309 -0
- package/src/orchestration/__tests__/worker-script-template-snapshot.test.ts +129 -0
- package/src/orchestration/__tests__/workflow-nesting-e2e.test.ts +317 -0
- package/src/orchestration/__tests__/workflow-script-lint-memo.test.ts +110 -0
- package/src/orchestration/agent-opts-resolver.ts +174 -0
- package/src/orchestration/args-validator.ts +127 -0
- package/src/orchestration/config-loader.ts +316 -0
- package/src/orchestration/error-recovery.ts +1018 -0
- package/src/orchestration/execute-agent-call.ts +256 -0
- package/src/orchestration/launcher.ts +455 -0
- package/src/orchestration/lifecycle.ts +399 -0
- package/src/orchestration/models/__tests__/budget.test.ts +307 -0
- package/src/orchestration/models/agent-call.ts +83 -0
- package/src/orchestration/models/budget.ts +118 -0
- package/src/orchestration/models/ports.ts +164 -0
- package/src/orchestration/models/run-runtime.ts +104 -0
- package/src/orchestration/models/run-spec.ts +83 -0
- package/src/orchestration/models/run-state.ts +44 -0
- package/src/orchestration/models/trace.ts +183 -0
- package/src/orchestration/models/types.ts +301 -0
- package/src/orchestration/models/workflow-run.ts +254 -0
- package/src/orchestration/models/workflow-script-registry.ts +35 -0
- package/src/orchestration/models/workflow-script.ts +117 -0
- package/src/orchestration/script-lint.ts +766 -0
- package/src/orchestration/skill-discovery.ts +135 -0
- package/src/orchestration/worker-handle.ts +115 -0
- package/src/orchestration/worker-host.ts +98 -0
- package/src/orchestration/worker-script-builder.ts +421 -0
- package/src/orchestration/workflow-files.ts +85 -0
- package/src/orchestration/workflow-script-registry-impl.ts +133 -0
- package/src/shared/__tests__/agent-ref.test.ts +34 -0
- package/src/shared/__tests__/meta-parser.test.ts +304 -0
- package/src/shared/__tests__/model-ref.test.ts +306 -0
- package/src/shared/__tests__/resource-discovery-manifest-cache.test.ts +288 -0
- package/src/shared/__tests__/resource-discovery.test.ts +749 -0
- package/src/shared/__tests__/resource-meta.test.ts +51 -0
- package/src/shared/__tests__/schema-jsonify.test.ts +81 -0
- package/src/shared/__tests__/timer-delay.test.ts +61 -0
- package/src/shared/agent-event.ts +13 -0
- package/src/shared/agent-ref.ts +57 -0
- package/src/shared/meta-parser.ts +261 -0
- package/src/shared/model-ref.ts +286 -0
- package/src/shared/resource-discovery.ts +835 -0
- package/src/shared/resource-meta.ts +65 -0
- package/src/shared/schema-env.ts +44 -0
- package/src/shared/schema-jsonify.ts +58 -0
- package/src/shared/timer-delay.ts +54 -0
- package/src/shared/xml-injection.ts +35 -0
- package/workflows/README.md +81 -0
- package/workflows/_shared/agent-refs.cjs +40 -0
- package/workflows/chain.js +137 -0
- package/workflows/map-reduce.js +180 -0
- package/workflows/parallel.js +154 -0
- package/workflows/review-fix-loop-utils.cjs +1542 -0
- package/workflows/review-fix-loop.js +1605 -0
- package/workflows/scatter-gather.js +184 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
// src/execution/engine/common/errors.ts
|
|
2
|
+
//
|
|
3
|
+
// 引擎层错误 SSOT(P2 公共降级层)。设计权威源:
|
|
4
|
+
// docs/architecture/subagent-engine-abstraction.md §3.3.3 错误规格全表(11 条)。
|
|
5
|
+
//
|
|
6
|
+
// 为什么集中一处:错误文案契约(code + 恢复指引)被三层消费——公共降级层
|
|
7
|
+
// (prompt_too_large / nested_spawn_rejected / engine_timeout)、后续 wave 的路由与
|
|
8
|
+
// 探针(engine_not_found / engine_probe_failed / model_not_available)、引擎适配器
|
|
9
|
+
// (engine_run_failed / engine_session_not_resumable)。散落各处会漂移成同一错误
|
|
10
|
+
// 多种文案,GUI 无法按 code 分流。
|
|
11
|
+
//
|
|
12
|
+
// 与 registry.ts 的 EngineNotFoundError 的关系:那是 P1 随注册表落地的
|
|
13
|
+
// engine_not_found 错误类(getEngine 抛出),本文件不复制其类定义、只对齐 code
|
|
14
|
+
// 字面量——后续 wave 统一收敛时以本表为 SSOT。
|
|
15
|
+
|
|
16
|
+
// ============================================================
|
|
17
|
+
// 错误码全集(§3.3.3 表 code 列,顺序与设计文档一致)
|
|
18
|
+
// ============================================================
|
|
19
|
+
|
|
20
|
+
export const ENGINE_ERROR_CODES = [
|
|
21
|
+
"engine_not_found",
|
|
22
|
+
"engine_probe_failed",
|
|
23
|
+
"engine_credential_missing",
|
|
24
|
+
"nested_spawn_rejected",
|
|
25
|
+
"schema_emulation_failed",
|
|
26
|
+
"engine_timeout",
|
|
27
|
+
"engine_capability_unsupported",
|
|
28
|
+
"engine_session_not_resumable",
|
|
29
|
+
"model_not_available",
|
|
30
|
+
"prompt_too_large",
|
|
31
|
+
"engine_run_failed",
|
|
32
|
+
] as const;
|
|
33
|
+
|
|
34
|
+
export type EngineErrorCode = (typeof ENGINE_ERROR_CODES)[number];
|
|
35
|
+
|
|
36
|
+
/** unknown → EngineErrorCode 收窄(外部输入携带错误码时的运行时 guard)。 */
|
|
37
|
+
export function isEngineErrorCode(value: unknown): value is EngineErrorCode {
|
|
38
|
+
return typeof value === "string" && (ENGINE_ERROR_CODES as readonly string[]).includes(value);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// ============================================================
|
|
42
|
+
// 错误类(code + 恢复指引的结构化载体)
|
|
43
|
+
// ============================================================
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 引擎层结构化错误。message 恒为 `<code>: <detail>` 前缀格式(AgentOutcome.error
|
|
47
|
+
* 的错误码前缀约定,§3.3.5);recovery 指向恢复动作(全局规则:错误信息必须可操作)。
|
|
48
|
+
*/
|
|
49
|
+
export class EngineError extends Error {
|
|
50
|
+
readonly code: EngineErrorCode;
|
|
51
|
+
/** 恢复指引:指向具体下一步(命令 / 配置路径 / 替代方案),非安慰性文案。 */
|
|
52
|
+
readonly recovery: string;
|
|
53
|
+
|
|
54
|
+
constructor(code: EngineErrorCode, detail: string, recovery: string) {
|
|
55
|
+
super(`${code}: ${detail}`);
|
|
56
|
+
this.name = "EngineError";
|
|
57
|
+
this.code = code;
|
|
58
|
+
this.recovery = recovery;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** 结构化投影(InteractResult.code/message 与 GUI 警告条共用形态)。 */
|
|
62
|
+
toStructured(): { code: EngineErrorCode; message: string; recovery: string } {
|
|
63
|
+
return { code: this.code, message: this.message, recovery: this.recovery };
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// ============================================================
|
|
68
|
+
// 默认恢复指引模板(§3.3.3 恢复指引列的静态部分)
|
|
69
|
+
// ============================================================
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* 11 条错误的默认恢复指引。Record<EngineErrorCode, string> 使 TS 强制全集覆盖——
|
|
73
|
+
* 新增错误码漏写模板会在此处编译失败,而不是运行时空指引。
|
|
74
|
+
* 含动态参数的恢复指引(版本命令 / 模型清单 / 字节数)用下方具名构造器,不走此表。
|
|
75
|
+
*/
|
|
76
|
+
export const DEFAULT_RECOVERY_HINTS: Record<EngineErrorCode, string> = {
|
|
77
|
+
engine_not_found:
|
|
78
|
+
"Check the engine id in the agent .md frontmatter (engine: field) against the registered engine list, " +
|
|
79
|
+
"fix the typo, or install/register the engine first.",
|
|
80
|
+
engine_probe_failed:
|
|
81
|
+
"Confirm the engine version (e.g. `<engine> --version`), then re-run the engine probe. " +
|
|
82
|
+
"For contract drift, see docs/research/agent-engine-*.md for the expected output format.",
|
|
83
|
+
engine_credential_missing:
|
|
84
|
+
"Configure the engine credentials (see the engine credential section of docs/research/agent-engine-*.md), " +
|
|
85
|
+
"then retry — the preparer cannot synthesize credentials it has no source for.",
|
|
86
|
+
nested_spawn_rejected:
|
|
87
|
+
"Subagents must not spawn further subagents (unbounded recursion guard). " +
|
|
88
|
+
"Do the work directly inside the current task instead of delegating.",
|
|
89
|
+
schema_emulation_failed:
|
|
90
|
+
"The model output failed JSON extraction or schema validation. Retry once with a strengthened prompt " +
|
|
91
|
+
"(buildSchemaEmulationSegment output + the error tail); if it still fails, relax the schema or switch to a " +
|
|
92
|
+
"schema-native engine (engine: pi).",
|
|
93
|
+
engine_timeout:
|
|
94
|
+
"The engine was killed by the host timeout chain. Inspect the captured stdout tail, then re-run with a larger " +
|
|
95
|
+
"timeout, a narrower task, or `engine: pi`.",
|
|
96
|
+
engine_capability_unsupported:
|
|
97
|
+
"This engine declares the capability unsupported. Use a single-shot call instead of interactive steering, " +
|
|
98
|
+
"or dispatch with `engine: pi` which supports it.",
|
|
99
|
+
engine_session_not_resumable:
|
|
100
|
+
"Idle-process reuse does not survive a main-session reload. Use a cold resume path " +
|
|
101
|
+
"(engine --resume / --session with the recorded session reference), or start a new subagent.",
|
|
102
|
+
model_not_available:
|
|
103
|
+
"The requested model is not resolvable in this engine's provider system. Pick a model from the engine's " +
|
|
104
|
+
"available model list — the host never swaps engines implicitly on model mismatch.",
|
|
105
|
+
prompt_too_large:
|
|
106
|
+
"Shorten the task text, move the persona to the file channel, or use an engine with a stdin prompt channel.",
|
|
107
|
+
engine_run_failed:
|
|
108
|
+
"The engine process failed at runtime (parse failure / non-zero exit / contract drift). " +
|
|
109
|
+
"Check the captured stdout tail and exit code, confirm the engine version, re-run the probe, or retry with `engine: pi`.",
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
// ============================================================
|
|
113
|
+
// P2 消费的具名构造器(动态参数进 detail/recovery)
|
|
114
|
+
// ============================================================
|
|
115
|
+
|
|
116
|
+
/** 错误回显长度上限(截断长输出,避免错误消息爆炸——对齐 structured-output echo 上限量级)。 */
|
|
117
|
+
const DETAIL_ECHO_MAX_CHARS = 200;
|
|
118
|
+
|
|
119
|
+
/** truncate(text, max):尾部截断 + 省略号标记(模板共用)。 */
|
|
120
|
+
function truncate(text: string, max: number): string {
|
|
121
|
+
return text.length <= max ? text : `${text.slice(0, max)}...`;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* prompt_too_large(persona-router 的 argv 预算拦截消费):仅 argv 投递的引擎在
|
|
126
|
+
* prepare 期报——禁止 spawn 后撞 E2BIG 才失败(§3.3.3 第 10 行)。
|
|
127
|
+
*/
|
|
128
|
+
export function promptTooLargeError(actualBytes: number, limitBytes: number): EngineError {
|
|
129
|
+
return new EngineError(
|
|
130
|
+
"prompt_too_large",
|
|
131
|
+
`estimated argv size ${actualBytes} bytes exceeds the ${limitBytes}-byte budget`,
|
|
132
|
+
DEFAULT_RECOVERY_HINTS.prompt_too_large,
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** nested_spawn_rejected(nesting-guard 消费):文案说明防护规则 + 指向 task 内自行完成。 */
|
|
137
|
+
export function nestedSpawnRejectedError(): EngineError {
|
|
138
|
+
return new EngineError(
|
|
139
|
+
"nested_spawn_rejected",
|
|
140
|
+
"this process is already a subagent (XYZ_AGENT_SUBAGENT=1)",
|
|
141
|
+
DEFAULT_RECOVERY_HINTS.nested_spawn_rejected,
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/** stdout 尾部回显上限(engine_timeout / engine_run_failed 的错误规格载体系数)。 */
|
|
146
|
+
export const STDOUT_TAIL_ECHO_CHARS = 2000;
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* engine_timeout 的 outcome.error 文案(kill-chain 的 synthesizeTimeoutOutcome 消费):
|
|
150
|
+
* 含 stdout 尾部 2000 字 + 「可用 engine: pi 重跑」建议(§3.3.3 第 6 行)。
|
|
151
|
+
*/
|
|
152
|
+
export function engineTimeoutDetail(stdoutTail: string): string {
|
|
153
|
+
return (
|
|
154
|
+
`host timeout chain exhausted (SIGTERM -> grace -> SIGKILL). ` +
|
|
155
|
+
`Stdout tail (last ${STDOUT_TAIL_ECHO_CHARS} chars): ${truncate(stdoutTail, STDOUT_TAIL_ECHO_CHARS)}. ` +
|
|
156
|
+
`Recovery: ${DEFAULT_RECOVERY_HINTS.engine_timeout}`
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* engine_run_failed 的 outcome.error 文案:含 stdout 尾部 2000 字 + exit code +
|
|
162
|
+
* 恢复指引(版本确认 + 探针重跑 / engine: pi 重跑,§3.3.3 第 11 行)。
|
|
163
|
+
*/
|
|
164
|
+
export function engineRunFailedDetail(reason: string, exitCode: number | null, stdoutTail: string): string {
|
|
165
|
+
const exit = exitCode === null ? "killed by signal" : `exit code ${exitCode}`;
|
|
166
|
+
return (
|
|
167
|
+
`engine failed at runtime: ${reason} (${exit}). ` +
|
|
168
|
+
`Stdout tail (last ${STDOUT_TAIL_ECHO_CHARS} chars): ${truncate(stdoutTail, STDOUT_TAIL_ECHO_CHARS)}. ` +
|
|
169
|
+
`Recovery: ${DEFAULT_RECOVERY_HINTS.engine_run_failed}`
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* schema_emulation_failed 的终报文案(宿主编排层「重试一次仍失败」后消费):
|
|
175
|
+
* 与 structured-output 的重试语义对齐(重试一次 → 报错含原始输出尾部)。
|
|
176
|
+
*/
|
|
177
|
+
export function schemaEmulationFailedDetail(error: string, tail: string): string {
|
|
178
|
+
return (
|
|
179
|
+
`structured output emulation failed after tolerant extraction and one host-side retry: ${error}. ` +
|
|
180
|
+
`Raw output tail: ${truncate(tail, DETAIL_ECHO_MAX_CHARS)}. ` +
|
|
181
|
+
`Recovery: ${DEFAULT_RECOVERY_HINTS.schema_emulation_failed}`
|
|
182
|
+
);
|
|
183
|
+
}
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
// src/execution/engine/common/event-journal.ts
|
|
2
|
+
//
|
|
3
|
+
// 宿主 event journal(P2 公共降级层)。设计权威源:
|
|
4
|
+
// docs/architecture/subagent-engine-abstraction.md D6(第②级归属宿主——host 统一落盘
|
|
5
|
+
// 则全引擎免费获得、格式唯一)+ §3.3.6 event journal 格式(JSONL 中立 v1)。
|
|
6
|
+
//
|
|
7
|
+
// 为什么 host 落盘而非各 adapter 缓存:adapter 各自缓存会演变出六种格式;host 消费
|
|
8
|
+
// onEvent 统一落盘,read 第②级(journal 重放)与探针 golden 语料共用同一份产物。
|
|
9
|
+
//
|
|
10
|
+
// 写入纪律(§3.3.6):onEvent 回调内追加写(有界缓冲 + 批量 flush),run 终态后
|
|
11
|
+
// flush 并 fsync 一次。journal 不随池删(D5),生命周期跟随 record。
|
|
12
|
+
//
|
|
13
|
+
// 失败语义:journal 是降级链第②级(尽力而为的数据源)——写失败不炸主流程:
|
|
14
|
+
// warn 一次 + 置 failed,后续 append 丢弃、close 立即返回(不静默:warn 有留痕)。
|
|
15
|
+
|
|
16
|
+
import { appendFile, mkdir, open } from "node:fs/promises";
|
|
17
|
+
import { readFileSync } from "node:fs";
|
|
18
|
+
import { dirname } from "node:path";
|
|
19
|
+
|
|
20
|
+
import { getLogger } from "../../../core/logger.ts";
|
|
21
|
+
|
|
22
|
+
import type { AgentEvent } from "../../types.ts";
|
|
23
|
+
|
|
24
|
+
const logger = getLogger("subagents");
|
|
25
|
+
|
|
26
|
+
// ============================================================
|
|
27
|
+
// 中立行格式(§3.3.6 v1)
|
|
28
|
+
// ============================================================
|
|
29
|
+
|
|
30
|
+
/** journal 单行(JSONL)。seq 是 host 侧单调递增序号——重放顺序权威。 */
|
|
31
|
+
export interface JournalLine {
|
|
32
|
+
v: 1;
|
|
33
|
+
/** host 落盘时刻(Date.now(),ms)。 */
|
|
34
|
+
ts: number;
|
|
35
|
+
/** = RunContext.taskId = record.id(journal 文件名与池引用计数 key)。 */
|
|
36
|
+
taskId: string;
|
|
37
|
+
engineId: string;
|
|
38
|
+
seq: number;
|
|
39
|
+
/** AgentEvent 原样(onEvent 回调对象的 JSON.stringify 直接产物,无二次变换)。 */
|
|
40
|
+
event: AgentEvent;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// ============================================================
|
|
44
|
+
// JournalWriter
|
|
45
|
+
// ============================================================
|
|
46
|
+
|
|
47
|
+
/** flush 触发的缓冲阈值:行数与字节数任一到达即批量落盘(有界缓冲)。 */
|
|
48
|
+
const FLUSH_THRESHOLD_LINES = 64;
|
|
49
|
+
// eslint-disable-next-line no-magic-numbers -- 32KB = 32 * 1024 bytes 缓冲字节换算常数
|
|
50
|
+
const FLUSH_THRESHOLD_BYTES = 32 * 1024;
|
|
51
|
+
|
|
52
|
+
/** FileHandle 的结构子集(close 期 fsync 用;注入 fake 可测)。 */
|
|
53
|
+
export interface FileHandleLike {
|
|
54
|
+
sync(): Promise<void>;
|
|
55
|
+
close(): Promise<void>;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** writer 的文件系统依赖面(结构接口:测试注入 fake,免 vi.mock 整个 fs 模块)。 */
|
|
59
|
+
export interface JournalFsDeps {
|
|
60
|
+
mkdir(path: string, opts: { recursive: boolean }): Promise<unknown>;
|
|
61
|
+
appendFile(path: string, data: string): Promise<void>;
|
|
62
|
+
open(path: string, flags: string): Promise<FileHandleLike>;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const defaultFs: JournalFsDeps = {
|
|
66
|
+
mkdir: (p, o) => mkdir(p, o),
|
|
67
|
+
appendFile: (p, d) => appendFile(p, d, "utf8"),
|
|
68
|
+
open: (p, f) => open(p, f),
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
/** JournalWriter 构造参数。 */
|
|
72
|
+
export interface JournalWriterOpts {
|
|
73
|
+
/** journal 文件绝对路径(经 paths.ts resolveJournalPath 派生,禁自拼)。 */
|
|
74
|
+
path: string;
|
|
75
|
+
taskId: string;
|
|
76
|
+
engineId: string;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* 追加写 writer:append 同步入队(onEvent 是同步回调,不阻塞事件流),批量异步
|
|
81
|
+
* flush;close = flush 全部 + fsync 一次(§3.3.6 写入纪律)。
|
|
82
|
+
*
|
|
83
|
+
* 文件惰性创建:首个 flush 才 mkdir + appendFile——无事件的任务不产生空 journal。
|
|
84
|
+
*/
|
|
85
|
+
export class JournalWriter {
|
|
86
|
+
private readonly opts: JournalWriterOpts;
|
|
87
|
+
private readonly fs: JournalFsDeps;
|
|
88
|
+
private readonly warn: (msg: string) => void;
|
|
89
|
+
|
|
90
|
+
private buffer: string[] = [];
|
|
91
|
+
private bufferedBytes = 0;
|
|
92
|
+
private seq = 0;
|
|
93
|
+
/** 串行化异步写(promise 链),防交错 append。 */
|
|
94
|
+
private chain: Promise<void> = Promise.resolve();
|
|
95
|
+
private failed = false;
|
|
96
|
+
private closed = false;
|
|
97
|
+
/** 是否成功落过盘——close 的 fsync 只对已存在的文件做(无事件任务不产生空文件)。 */
|
|
98
|
+
private wrote = false;
|
|
99
|
+
|
|
100
|
+
constructor(opts: JournalWriterOpts, fs: JournalFsDeps = defaultFs, warn: (msg: string) => void = defaultWarn) {
|
|
101
|
+
this.opts = opts;
|
|
102
|
+
this.fs = fs;
|
|
103
|
+
this.warn = warn;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** 追加一个事件(同步入队;缓冲达阈值自动排队 flush)。closed/failed 后丢弃。 */
|
|
107
|
+
append(event: AgentEvent): void {
|
|
108
|
+
if (this.failed || this.closed) return;
|
|
109
|
+
const line: JournalLine = {
|
|
110
|
+
v: 1,
|
|
111
|
+
ts: Date.now(),
|
|
112
|
+
taskId: this.opts.taskId,
|
|
113
|
+
engineId: this.opts.engineId,
|
|
114
|
+
seq: this.seq++,
|
|
115
|
+
event,
|
|
116
|
+
};
|
|
117
|
+
const serialized = JSON.stringify(line);
|
|
118
|
+
this.buffer.push(serialized);
|
|
119
|
+
this.bufferedBytes += serialized.length;
|
|
120
|
+
if (this.buffer.length >= FLUSH_THRESHOLD_LINES || this.bufferedBytes >= FLUSH_THRESHOLD_BYTES) {
|
|
121
|
+
void this.flush();
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** 把缓冲写入磁盘(串行排队;等待此前所有排队写完成)。 */
|
|
126
|
+
flush(): Promise<void> {
|
|
127
|
+
if (this.failed || this.buffer.length === 0) return this.chain;
|
|
128
|
+
const chunk = `${this.buffer.join("\n")}\n`;
|
|
129
|
+
this.buffer = [];
|
|
130
|
+
this.bufferedBytes = 0;
|
|
131
|
+
this.chain = this.chain.then(() => this.writeChunk(chunk));
|
|
132
|
+
return this.chain;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** run 终态后调用:flush 全部 + fsync 一次 + 关闭(幂等)。 */
|
|
136
|
+
async close(): Promise<void> {
|
|
137
|
+
if (this.closed) return;
|
|
138
|
+
this.closed = true;
|
|
139
|
+
await this.flush();
|
|
140
|
+
if (this.failed || !this.wrote) return;
|
|
141
|
+
// fsync 一次(§3.3.6):进程崩溃后已 flush 的行不丢——record 读第②级的一致性依据
|
|
142
|
+
this.chain = this.chain.then(async () => {
|
|
143
|
+
const fh = await this.fs.open(this.opts.path, "r");
|
|
144
|
+
try {
|
|
145
|
+
await fh.sync();
|
|
146
|
+
} finally {
|
|
147
|
+
await fh.close();
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
await this.chain;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** 是否已写失败(降级诊断用;failed 后 journal 不可作为②级数据源)。 */
|
|
154
|
+
get isFailed(): boolean {
|
|
155
|
+
return this.failed;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* 重定向落盘路径(对齐点③:journal 路径权威 = 引擎声明的池 key)。
|
|
160
|
+
* 仅在尚未落盘(wrote=false)时允许——已 flush 过的文件搬家会制造两份半截 journal,
|
|
161
|
+
* 重放语义破坏;已落盘时 warn 拒绝(不静默)。事件在重定向前到达的场景由调用方
|
|
162
|
+
* 契约保证(RunContext.onPoolResolved 注释:引擎须在首个事件 emit 前回调)。
|
|
163
|
+
*/
|
|
164
|
+
retarget(path: string): void {
|
|
165
|
+
if (this.closed || this.failed) return;
|
|
166
|
+
if (this.wrote) {
|
|
167
|
+
this.warn(
|
|
168
|
+
`[event-journal] retarget ignored for task ${this.opts.taskId}: journal already flushed to ` +
|
|
169
|
+
`${this.opts.path} (events must not precede onPoolResolved)`,
|
|
170
|
+
);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
this.opts.path = path;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/** 当前落盘路径(handle.journalPath 回填数据源)。 */
|
|
177
|
+
get path(): string {
|
|
178
|
+
return this.opts.path;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
private async writeChunk(chunk: string): Promise<void> {
|
|
182
|
+
try {
|
|
183
|
+
await this.fs.mkdir(dirname(this.opts.path), { recursive: true });
|
|
184
|
+
await this.fs.appendFile(this.opts.path, chunk);
|
|
185
|
+
this.wrote = true;
|
|
186
|
+
} catch (err) {
|
|
187
|
+
// 尽力而为语义:一次写失败即永久放弃(重试追写会产生乱序行),warn 留痕不静默
|
|
188
|
+
this.failed = true;
|
|
189
|
+
this.buffer = [];
|
|
190
|
+
this.warn(
|
|
191
|
+
`[event-journal] write failed, journal for task ${this.opts.taskId} is unavailable ` +
|
|
192
|
+
`(read falls back to lower tiers): ${err instanceof Error ? err.message : String(err)}`,
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function defaultWarn(msg: string): void {
|
|
199
|
+
logger.warn(msg);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// ============================================================
|
|
203
|
+
// 重放
|
|
204
|
+
// ============================================================
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* 重放 journal:读取路径下全部事件,重放即得 AgentEvent 流(read 第②级)。
|
|
208
|
+
*
|
|
209
|
+
* - 文件不存在 → [](降级链语义:②级不可达不算错误,调用方落 ③级);
|
|
210
|
+
* - 损坏行跳过(追加写产物末行可能截断;跳过优于整体失败——设计 C5「三级都不 throw」);
|
|
211
|
+
* - 按 seq 稳定排序后返回(重放顺序权威是 seq,不依赖文件行序的隐式保证,§3.3.6)。
|
|
212
|
+
*/
|
|
213
|
+
export function replayJournal(path: string): AgentEvent[] {
|
|
214
|
+
let raw: string;
|
|
215
|
+
try {
|
|
216
|
+
raw = readFileSync(path, "utf8");
|
|
217
|
+
} catch {
|
|
218
|
+
return [];
|
|
219
|
+
}
|
|
220
|
+
const lines: JournalLine[] = [];
|
|
221
|
+
for (const row of raw.split("\n")) {
|
|
222
|
+
const trimmed = row.trim();
|
|
223
|
+
if (trimmed === "") continue;
|
|
224
|
+
const parsed = parseLine(trimmed);
|
|
225
|
+
if (parsed !== undefined) lines.push(parsed);
|
|
226
|
+
}
|
|
227
|
+
lines.sort((a, b) => a.seq - b.seq);
|
|
228
|
+
return lines.map((l) => l.event);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/** 单行 parse + 结构 guard(v=1 + event 形状最小判别:object 且 type 为 string)。 */
|
|
232
|
+
function parseLine(trimmed: string): JournalLine | undefined {
|
|
233
|
+
let parsed: unknown;
|
|
234
|
+
try {
|
|
235
|
+
parsed = JSON.parse(trimmed);
|
|
236
|
+
} catch {
|
|
237
|
+
return undefined;
|
|
238
|
+
}
|
|
239
|
+
if (typeof parsed !== "object" || parsed === null) return undefined;
|
|
240
|
+
const rec = parsed as Record<string, unknown>;
|
|
241
|
+
const event = rec.event;
|
|
242
|
+
if (rec.v !== 1 || typeof rec.ts !== "number" || typeof rec.seq !== "number") return undefined;
|
|
243
|
+
if (typeof event !== "object" || event === null || typeof (event as Record<string, unknown>).type !== "string") {
|
|
244
|
+
return undefined;
|
|
245
|
+
}
|
|
246
|
+
return {
|
|
247
|
+
v: 1,
|
|
248
|
+
ts: rec.ts,
|
|
249
|
+
taskId: typeof rec.taskId === "string" ? rec.taskId : "",
|
|
250
|
+
engineId: typeof rec.engineId === "string" ? rec.engineId : "",
|
|
251
|
+
seq: rec.seq,
|
|
252
|
+
event: event as AgentEvent,
|
|
253
|
+
};
|
|
254
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// src/execution/engine/common/journal-replay.ts
|
|
2
|
+
//
|
|
3
|
+
// read 第②级(宿主 event journal 重放)的公共实现(P4,对齐点①接线)。设计权威源:
|
|
4
|
+
// docs/architecture/subagent-engine-abstraction.md D6 + §3.3.6「重放等价性」——
|
|
5
|
+
// journal 重放与 live 通路共用同一 reducer(updateFromEvent 范式),不引入第二套
|
|
6
|
+
// 解析器;conformance C5 断言重放 turns 与 live 一致。
|
|
7
|
+
//
|
|
8
|
+
// 为什么放 common:zcode/pi 的 read() ②级降级是同一段逻辑(replayJournal 拿事件流 →
|
|
9
|
+
// live reducer 累积 turns → 投影 SessionView)——放引擎各自实现会漂移出两份形状。
|
|
10
|
+
|
|
11
|
+
import { createRecord, updateFromEvent } from "../../execution-record.ts";
|
|
12
|
+
import type { AgentEvent } from "../../types.ts";
|
|
13
|
+
import type { EngineHandle, SessionView } from "../types.ts";
|
|
14
|
+
import { replayJournal } from "./event-journal.ts";
|
|
15
|
+
import { aggregateUsage, toReplayedTurn } from "./session-view-projection.ts";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* journal → SessionView(read 第②级)。
|
|
19
|
+
* 返回 undefined = ②级不可达(journal 路径缺省 / 文件不存在 / 无事件),调用方落 ③级。
|
|
20
|
+
* coarse 引擎(zcode)journal 只含合成事件,重放退化为摘要级——D6 已声明的保真度
|
|
21
|
+
* 下限,非缺陷。
|
|
22
|
+
*/
|
|
23
|
+
export function replayJournalToSessionView(
|
|
24
|
+
handle: EngineHandle,
|
|
25
|
+
engineId: string,
|
|
26
|
+
): SessionView | undefined {
|
|
27
|
+
const journalPath = handle.data.journalPath;
|
|
28
|
+
if (journalPath === undefined) return undefined;
|
|
29
|
+
const events = replayJournal(journalPath);
|
|
30
|
+
if (events.length === 0) return undefined;
|
|
31
|
+
return eventsToSessionView(events, engineId, sessionIdFromHandle(handle));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** 事件流 → SessionView(live reducer 累积 turns——重放等价性的实现体)。 */
|
|
35
|
+
export function eventsToSessionView(
|
|
36
|
+
events: readonly AgentEvent[],
|
|
37
|
+
engineId: string,
|
|
38
|
+
sessionId?: string,
|
|
39
|
+
): SessionView {
|
|
40
|
+
const record = createRecord("journal-replay", {
|
|
41
|
+
agent: "journal-replay",
|
|
42
|
+
model: "",
|
|
43
|
+
mode: "background",
|
|
44
|
+
task: "",
|
|
45
|
+
slug: "",
|
|
46
|
+
startedAt: 0,
|
|
47
|
+
});
|
|
48
|
+
for (const ev of events) updateFromEvent(record, ev);
|
|
49
|
+
return {
|
|
50
|
+
engineId,
|
|
51
|
+
...(sessionId !== undefined ? { sessionId } : {}),
|
|
52
|
+
turns: record.turns.map(toReplayedTurn),
|
|
53
|
+
usage: aggregateUsage(record.turns),
|
|
54
|
+
source: "journal",
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** handle.sessionRef 的 sessionId 提取(引擎自定义键,运行时 guard)。 */
|
|
59
|
+
function sessionIdFromHandle(handle: EngineHandle): string | undefined {
|
|
60
|
+
const v = handle.data.sessionRef["sessionId"];
|
|
61
|
+
return typeof v === "string" ? v : undefined;
|
|
62
|
+
}
|