@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,228 @@
|
|
|
1
|
+
// src/core/output-collector.ts
|
|
2
|
+
//
|
|
3
|
+
// 结果收集器(Record + CollectResultArgs → AgentResult)。
|
|
4
|
+
//
|
|
5
|
+
// 收口设计(2026-06-22):collectResult 全部从 record 读——
|
|
6
|
+
// text ← getFullText(record)(聚合 turns[].text,不再读 session.messages)
|
|
7
|
+
// turns ← record.turnCount
|
|
8
|
+
// toolCalls ← getAllToolCalls(record)(扁平化 turns[].toolCalls)
|
|
9
|
+
// usage ← getTotalUsage(record)(聚合 turns[].usageDelta)
|
|
10
|
+
//
|
|
11
|
+
// 基础层模块:依赖 execution-record(派生函数)+ types。
|
|
12
|
+
|
|
13
|
+
import type {
|
|
14
|
+
AgentResult,
|
|
15
|
+
ExecutionRecord,
|
|
16
|
+
ToolCall,
|
|
17
|
+
} from "./types.ts";
|
|
18
|
+
import {
|
|
19
|
+
getAllToolCalls,
|
|
20
|
+
getFullText,
|
|
21
|
+
getTotalUsage,
|
|
22
|
+
} from "./execution-record.ts";
|
|
23
|
+
// [F-R1] 值引用 stale-context 分诊 pattern 表(SSOT 在 execute-agent-call,消费点
|
|
24
|
+
// isStaleContextErrorMsg 同源)。execution → orchestration 值引用有先例
|
|
25
|
+
// (agent-registry.ts → script-lint.ts),且 execute-agent-call 对 execution 仅剩
|
|
26
|
+
// type-only import(已擦除),无运行时循环。
|
|
27
|
+
// [MF-1] 同向引用确定性失败标记前缀(SSOT 同在 execute-agent-call,同一布局理由)。
|
|
28
|
+
import {
|
|
29
|
+
DETERMINISTIC_SCHEMA_FAILURE_PREFIX,
|
|
30
|
+
STALE_CONTEXT_PATTERNS,
|
|
31
|
+
} from "../orchestration/execute-agent-call.ts";
|
|
32
|
+
|
|
33
|
+
// ============================================================
|
|
34
|
+
// Result 收集
|
|
35
|
+
// ============================================================
|
|
36
|
+
|
|
37
|
+
/** collectResult 的入参(session 身份 + 执行控制字段,执行内容从 record 读)。 */
|
|
38
|
+
export interface CollectResultArgs {
|
|
39
|
+
startTime: number;
|
|
40
|
+
success: boolean;
|
|
41
|
+
error: string | undefined;
|
|
42
|
+
sessionId: string;
|
|
43
|
+
sessionFile: string | undefined;
|
|
44
|
+
/**
|
|
45
|
+
* [F-1] 本次执行是否要求结构化产出(opts.schema 或 opts.schemaEnv 任一存在)。
|
|
46
|
+
* true 且 run 结束仍无有效 parsedOutput 时:结果不得静默 success——置 success=false
|
|
47
|
+
* 并把三态失败归因写进 error(上层 executeAgentCall 只看 error 判 completed/failed)。
|
|
48
|
+
* 缺省 false(非 schema 模式 parsedOutput===undefined 是正常态,不动成败)。
|
|
49
|
+
*/
|
|
50
|
+
schemaExpected?: boolean;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** structured-output tool 名(与 structured-output 扩展 TOOL_NAME 一致,见 session-runner.ts)。 */
|
|
54
|
+
const STRUCTURED_OUTPUT_TOOL = "structured-output";
|
|
55
|
+
|
|
56
|
+
/** F-1 失败摘要截断长度(字符):错误详情拼进 run 结果 error 字段,防大 payload 撑爆。 */
|
|
57
|
+
const FAILED_SO_SUMMARY_MAX_CHARS = 300;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* 从 toolCalls 提取 structured-output 的 result.details(schema 模式产出)。
|
|
61
|
+
* schema enforcement 保证 agent 调过该 tool(漏调会 steer 重试);这里只做逆向提取。
|
|
62
|
+
* 未调或无 details 返回 undefined。
|
|
63
|
+
*
|
|
64
|
+
* [F-1 失败吞没修复] isError:true 的调用一律跳过——失败调用的 details(pi 失败
|
|
65
|
+
* 路径默认 {})不是通过 schema 校验的产出,把它当 parsedOutput 会让 gate 终止/
|
|
66
|
+
* 模型自弃的 run 以 parsedOutput={} 静默 completed。isError 字段缺失(旧 record/
|
|
67
|
+
* 进行中调用)不误伤——仅显式 true 跳过。
|
|
68
|
+
*
|
|
69
|
+
* 导出以便直接单测(纯函数契约)。
|
|
70
|
+
*/
|
|
71
|
+
export function extractParsedOutput(toolCalls: ToolCall[]): unknown {
|
|
72
|
+
for (let i = toolCalls.length - 1; i >= 0; i--) {
|
|
73
|
+
const tc = toolCalls[i]!;
|
|
74
|
+
if (tc.toolName === STRUCTURED_OUTPUT_TOOL && tc.isError !== true && tc.result?.details !== undefined) {
|
|
75
|
+
return tc.result.details;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* [F-R1] 中和动态错误摘要中的 stale-context 命中词:对每个 STALE_CONTEXT_PATTERNS
|
|
83
|
+
* 做大小写不敏感的子串替换为 "[redacted]"(分诊 isStaleContextErrorMsg 是
|
|
84
|
+
* toLowerCase 后的子串匹配,故中和也必须大小写不敏感)。
|
|
85
|
+
*
|
|
86
|
+
* 为何只中和动态段(summarizeToolContent 产物)、不中和固定前缀:前缀是本模块
|
|
87
|
+
* 静态文案,已逐字核对无任何 pattern 命中,且由 output-collector.test.ts 的
|
|
88
|
+
* "messages avoid STALE_CONTEXT_PATTERNS substrings" 用例锁定;动态段是
|
|
89
|
+
* 模型/provider 的原始错误文本(可含 "aborted"/"ctx is stale" 等),不受本模块
|
|
90
|
+
* 控制。不中和的话,拼接结果经 collectResult → result.error 流到
|
|
91
|
+
* execute-agent-call 的 isStaleContextErrorMsg 分诊,SO 失败归因被误诊为
|
|
92
|
+
* stale-context → 跳过重试。
|
|
93
|
+
*
|
|
94
|
+
* 导出以便直接单测(纯函数契约)。
|
|
95
|
+
*/
|
|
96
|
+
export function neutralizeStalePatterns(text: string): string {
|
|
97
|
+
let out = text;
|
|
98
|
+
for (const pattern of STALE_CONTEXT_PATTERNS) {
|
|
99
|
+
// pattern 当前均为纯小写词/短语(无 regex 元字符),escape 仅为防未来 pattern
|
|
100
|
+
// 演化引入元字符时静默改变语义。
|
|
101
|
+
const escaped = pattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
102
|
+
out = out.replace(new RegExp(escaped, "gi"), "[redacted]");
|
|
103
|
+
}
|
|
104
|
+
return out;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* schema 模式下无有效 parsedOutput 时的三态失败归因(F-1)。
|
|
109
|
+
*
|
|
110
|
+
* 返回 undefined 表示 toolCalls 里有可用的 parsedOutput(无需归因)。
|
|
111
|
+
* 三态判定优先级:校验失败(有 isError 调用)> 从未调用 SO tool > 调用过但无 details。
|
|
112
|
+
*
|
|
113
|
+
* [MF-1] 三态可重试性矩阵(标记 SSOT 与消费端判定见 execute-agent-call 的
|
|
114
|
+
* DETERMINISTIC_SCHEMA_FAILURE_PREFIX / isDeterministicSchemaFailureMsg):
|
|
115
|
+
* | 归因态 | 带标记 | 可重试性 | 理由 |
|
|
116
|
+
* |------------------------------|-------|---------|------|
|
|
117
|
+
* | ① 从未调用 SO tool | 是 | 不可重试 | 缺 extension 是环境确定性(C1 安装盲区),同环境重试必同结果 |
|
|
118
|
+
* | ② SO 调用 isError(gate 终止/不可满足 schema) | 是 | 不可重试 | 同 schema 重试必同结果(第五轮实测 retry 放大回归:3 attempts/4 子进程/235s) |
|
|
119
|
+
* | ③ 调用过但无 details | 否 | 可重试 | 可能瞬态(details 提取/序列化异常),保留既有重试语义 |
|
|
120
|
+
*
|
|
121
|
+
* 文案约束:不得命中 execute-agent-call 的 STALE_CONTEXT_PATTERNS("aborted" 等
|
|
122
|
+
* 子串)——命中会被误诊为 stale-context 跳过重试。固定前缀(含 MF-1 标记词)静态
|
|
123
|
+
* 无命中(测试锁定);动态段经 neutralizeStalePatterns 中和(F-R1)。
|
|
124
|
+
*
|
|
125
|
+
* 导出以便直接单测(纯函数契约)。
|
|
126
|
+
*/
|
|
127
|
+
export function describeMissingParsedOutput(toolCalls: ToolCall[]): string | undefined {
|
|
128
|
+
if (extractParsedOutput(toolCalls) !== undefined) return undefined;
|
|
129
|
+
const soCalls = toolCalls.filter((tc) => tc.toolName === STRUCTURED_OUTPUT_TOOL);
|
|
130
|
+
if (soCalls.length === 0) {
|
|
131
|
+
// 覆盖独立安装盲区(C1):schema enforcement 依赖 SO extension 注册 tool,
|
|
132
|
+
// 未安装时 agent 无工具可调、steer 无法生效——只能在这里事后暴露。
|
|
133
|
+
// [MF-1] 态① 带确定性标记:缺 extension 是环境确定性,不重试。
|
|
134
|
+
return (
|
|
135
|
+
`${DETERMINISTIC_SCHEMA_FAILURE_PREFIX} ` +
|
|
136
|
+
"Agent finished without producing a structured output: the structured-output tool was never called. " +
|
|
137
|
+
"Recovery: verify the structured-output extension is installed and enabled for this agent, " +
|
|
138
|
+
"and that the agent's final answer conforms to the requested schema."
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
const failed = soCalls.filter((tc) => tc.isError === true);
|
|
142
|
+
if (failed.length > 0) {
|
|
143
|
+
const last = failed[failed.length - 1]!;
|
|
144
|
+
// [F-R1] 先截断后中和:截断边界把 pattern 切断时不产生新命中(半截词本就
|
|
145
|
+
// 匹配不到分诊子串),完整落入截断窗口的 pattern 一定被中和。
|
|
146
|
+
const lastErrorSummary = neutralizeStalePatterns(summarizeToolContent(last.result?.content));
|
|
147
|
+
// [F-R4] 失败原因分类:isError 只说明「调用失败」,原因未必是 schema 校验
|
|
148
|
+
// (provider 错误/pi abort/扩展内部错误同样走 isError),硬编码
|
|
149
|
+
// "(schema validation)" 会误导排障。按最后错误的实际内容分类——权威锚点是
|
|
150
|
+
// structured-output 扩展校验失败的固定文案前缀 "Schema validation failed: ..."
|
|
151
|
+
//(structured-output/src/execute.ts),大小写不敏感匹配;其余归为 execution
|
|
152
|
+
// failure。在已中和的摘要上分类:中和仅替换 stale 词,与校验词无交集。
|
|
153
|
+
const failureKind = lastErrorSummary.toLowerCase().includes("validation failed")
|
|
154
|
+
? "schema validation"
|
|
155
|
+
: "execution failure";
|
|
156
|
+
// [MF-1] 态② 带确定性标记:gate 终止/不可满足 schema 同 schema 重试必同结果。
|
|
157
|
+
// 注:failureKind=execution failure(provider 瞬态错误)同样不重试——isError 态
|
|
158
|
+
// 整体从重试面摘除(实测回归即此态循环烧钱),瞬态恢复交由上层 workflow 编排。
|
|
159
|
+
return (
|
|
160
|
+
`${DETERMINISTIC_SCHEMA_FAILURE_PREFIX} ` +
|
|
161
|
+
`Agent finished without a valid structured output: ${failed.length} structured-output call(s) failed ` +
|
|
162
|
+
`(${failureKind}). Last error: ${lastErrorSummary}`
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
return (
|
|
166
|
+
"Agent finished without a valid structured output: structured-output was called but none of the " +
|
|
167
|
+
"successful calls carried result details."
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/** 从 tool result.content 提取可读错误文本([{type:"text",text}] 形态,防御未知形状)。 */
|
|
172
|
+
function summarizeToolContent(content: unknown): string {
|
|
173
|
+
let summary = "(no detail)";
|
|
174
|
+
if (Array.isArray(content)) {
|
|
175
|
+
const texts = content
|
|
176
|
+
.map((item) => (item && typeof item === "object" && "text" in item ? String((item as { text: unknown }).text) : ""))
|
|
177
|
+
.filter((t) => t !== "");
|
|
178
|
+
if (texts.length > 0) summary = texts.join(" ");
|
|
179
|
+
} else if (typeof content === "string" && content !== "") {
|
|
180
|
+
summary = content;
|
|
181
|
+
}
|
|
182
|
+
return summary.length > FAILED_SO_SUMMARY_MAX_CHARS
|
|
183
|
+
? `${summary.slice(0, FAILED_SO_SUMMARY_MAX_CHARS)}...`
|
|
184
|
+
: summary;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* 从 record + args 组装 AgentResult。每个字段来源单一且收口于 record:
|
|
189
|
+
* text ← getFullText(record)(聚合 turns[].text,单一数据源)
|
|
190
|
+
* turns ← record.turnCount
|
|
191
|
+
* toolCalls ← getAllToolCalls(record)(扁平化 turns[].toolCalls)
|
|
192
|
+
* usage ← getTotalUsage(record)(聚合 turns[].usageDelta,全零则 undefined)
|
|
193
|
+
* parsedOutput ← extractParsedOutput(toolCalls)
|
|
194
|
+
*
|
|
195
|
+
* startTime 算 durationMs。
|
|
196
|
+
*
|
|
197
|
+
* success 双来源判定(调用方传入):
|
|
198
|
+
* ① session.prompt() 抛错 → args.success=false
|
|
199
|
+
* ② prompt 成功但 record.lastError 非空(message_end stopReason=error)→ success=false
|
|
200
|
+
*/
|
|
201
|
+
export function collectResult(
|
|
202
|
+
record: ExecutionRecord,
|
|
203
|
+
args: CollectResultArgs,
|
|
204
|
+
): AgentResult {
|
|
205
|
+
const toolCalls = getAllToolCalls(record);
|
|
206
|
+
const parsedOutput = extractParsedOutput(toolCalls);
|
|
207
|
+
const result: AgentResult = {
|
|
208
|
+
text: getFullText(record),
|
|
209
|
+
turns: record.turnCount,
|
|
210
|
+
durationMs: Date.now() - args.startTime,
|
|
211
|
+
success: args.success,
|
|
212
|
+
error: args.error,
|
|
213
|
+
sessionId: args.sessionId,
|
|
214
|
+
toolCalls,
|
|
215
|
+
usage: getTotalUsage(record),
|
|
216
|
+
sessionFile: args.sessionFile,
|
|
217
|
+
parsedOutput,
|
|
218
|
+
};
|
|
219
|
+
// [F-1 失败吞没修复] schema 模式下 run 结束仍无有效 parsedOutput 时不得静默
|
|
220
|
+
// success:只在「本将成功」的路径上标注(success=false 的路径已有真实 error/
|
|
221
|
+
// abort 语义,不覆写)。error 经 mapToWorkflowAgentResult(仅 !success 透传)
|
|
222
|
+
// → executeAgentCall(error!==undefined 即 failed)逐层可见。
|
|
223
|
+
if (args.schemaExpected === true && result.success && parsedOutput === undefined) {
|
|
224
|
+
result.success = false;
|
|
225
|
+
result.error = describeMissingParsedOutput(toolCalls) ?? result.error;
|
|
226
|
+
}
|
|
227
|
+
return result;
|
|
228
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// src/core/path-encoding.ts
|
|
2
|
+
//
|
|
3
|
+
// cwd → 安全目录名的编码逻辑。Core 叶子原语(零依赖)。
|
|
4
|
+
//
|
|
5
|
+
// 被 session-runner(subagent session 持久化目录)与 session-file-gc(清理过期
|
|
6
|
+
// session 文件)共用——两处需要相同的编码,否则同一 cwd 会落到两个不同目录。
|
|
7
|
+
|
|
8
|
+
import * as path from "node:path";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* cwd → 安全目录名。复用 Pi SDK getDefaultSessionDir 的编码逻辑:
|
|
12
|
+
* 去开头单个分隔符,全量替换剩余分隔符/冒号为 `-`,首尾补 `--`。
|
|
13
|
+
* 例:`/Users/x/proj` → `--Users-x-proj--`。
|
|
14
|
+
*/
|
|
15
|
+
export function encodeCwd(cwd: string): string {
|
|
16
|
+
return "--" + cwd.replace(/^[/\\]/, "").replace(/[/\\:]/g, "-") + "--";
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 获取 subagent session 持久化目录路径。
|
|
21
|
+
*
|
|
22
|
+
* D-004: 用主 cwd 编码——保证同一主 cwd 下所有 subagent 的 session 文件
|
|
23
|
+
* 存放在同一目录,便于 session-file-gc 统一清理。
|
|
24
|
+
* [MF-3] worktree 模式下调用方必须传树根 cwd(ROOT mainCwd,经 PI_SUBAGENT_ROOT_CWD
|
|
25
|
+
* 贯穿),不能传子进程自身的 checkout 路径——否则深层 record 落盘到 enc(worktree) 段,
|
|
26
|
+
* ROOT 磁盘重建扫不到(全树可见性断裂)。根进程传自身 cwd(行为不变)。
|
|
27
|
+
*
|
|
28
|
+
* @param agentDir agent 配置目录(如 ~/.pi/agent)
|
|
29
|
+
* @param mainCwd 树根主 agent 的工作目录(非 subagent 的 effectiveCwd;worktree 模式下
|
|
30
|
+
* 是 ROOT 的 cwd,不是 checkout 路径)
|
|
31
|
+
* @returns session 持久化目录绝对路径
|
|
32
|
+
*/
|
|
33
|
+
export function getSubagentSessionDir(agentDir: string, mainCwd: string): string {
|
|
34
|
+
// [MF#1] 保持既有布局 subagents/<enc>/sessions/——曾改为 subagents/sessions/<enc>/ 会让
|
|
35
|
+
// 升级用户的既有 session 文件全部落到扫描目录外(历史记录消失 + GC 扫不到,双重 orphan)。
|
|
36
|
+
// 本分支未发布,回退到既有布局即无需迁移、无数据丢失。
|
|
37
|
+
return path.join(agentDir, "subagents", encodeCwd(mainCwd), "sessions");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* 获取 subagent records(manifest)持久化目录路径。
|
|
42
|
+
*
|
|
43
|
+
* 与 getSubagentSessionDir 同用 encodeCwd(mainCwd),保证 records 与 sessions 在同一
|
|
44
|
+
* <enc> 段下物理相邻。
|
|
45
|
+
* [MF-3] 调用方必须与 getSubagentSessionDir 传同一编码键(进程内 init.cwd /
|
|
46
|
+
* buildSessionRunnerContext.mainCwd / record.worktreeHandle.mainCwd 恒等;worktree 模式
|
|
47
|
+
* 跨进程时统一用贯穿的 ROOT cwd)——sessions 与 records 两套目录同段,GC/重建才不会
|
|
48
|
+
* 互相找不到(enc 段不变量)。
|
|
49
|
+
*
|
|
50
|
+
* D-004 同源:用主 cwd 编码做物理隔离,使 session-file-gc 按 <enc>/records/ 子目录
|
|
51
|
+
* 匹配 manifest .json 时天然限定在当前 cwd 范围内,不会越界清理其他 cwd 的 manifest。
|
|
52
|
+
*
|
|
53
|
+
* @param agentDir agent 配置目录(如 ~/.pi/agent)
|
|
54
|
+
* @param mainCwd 树根主 agent 的工作目录(非 subagent 的 effectiveCwd;worktree 模式下
|
|
55
|
+
* 是 ROOT 的 cwd,不是 checkout 路径)
|
|
56
|
+
* @returns records 持久化目录绝对路径
|
|
57
|
+
*/
|
|
58
|
+
export function getSubagentRecordsDir(agentDir: string, mainCwd: string): string {
|
|
59
|
+
return path.join(agentDir, "subagents", encodeCwd(mainCwd), "records");
|
|
60
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// src/execution/pi-invocation.ts
|
|
2
|
+
//
|
|
3
|
+
// 定位 pi 二进制并组装 spawn 调用。Core 叶子原语(仅依赖 node 内置)。
|
|
4
|
+
//
|
|
5
|
+
// spawn 改造(in-process → spawn pi --mode json)的基座模块。
|
|
6
|
+
// 被 runSpawn(session-runner)调用,决定子进程用哪个命令启动。
|
|
7
|
+
//
|
|
8
|
+
// 移植自 nicobailon subagent example 的 getPiInvocation,处理三种运行时:
|
|
9
|
+
// 1. bun bundle(/$bunfs/root/ 虚拟脚本)→ 退化到 pi-in-PATH
|
|
10
|
+
// 2. 有真实脚本路径(node + script)→ node <script> <args>
|
|
11
|
+
// 3. node/bun generic runtime(无脚本)→ pi <args>(依赖 PATH)
|
|
12
|
+
//
|
|
13
|
+
// 注意:pi 在扩展进程内运行时 process.execPath 是 node/bun,process.argv[1]
|
|
14
|
+
// 是 pi 的入口脚本。子进程需要复现同样的启动方式才能保证扩展/配置一致加载。
|
|
15
|
+
|
|
16
|
+
import * as fs from "node:fs";
|
|
17
|
+
import * as path from "node:path";
|
|
18
|
+
|
|
19
|
+
import { isRelayActive, RELAY_ENV_NODE, RELAY_ENV_SCRIPT } from "./relay-env.ts";
|
|
20
|
+
|
|
21
|
+
/** spawn 调用描述符:command + args(透传给 child_process.spawn)。 */
|
|
22
|
+
export interface PiInvocation {
|
|
23
|
+
/** 可执行文件路径(node/bun/pi 二进制)。 */
|
|
24
|
+
command: string;
|
|
25
|
+
/** 命令行参数(可能含 [scriptPath, ...userArgs] 或直接 [...userArgs])。 */
|
|
26
|
+
args: string[];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** getPiInvocation 可选项。 */
|
|
30
|
+
export interface PiInvocationOptions {
|
|
31
|
+
/**
|
|
32
|
+
* false = 强制直连 spawn 真实 pi(不经 relay 代理)。唯一现役消费点是 PiEngine.probe
|
|
33
|
+
* ——探针意图是 pi 本体可解析性,经 relay 探到的是 runtime 健康,语义错位(E 方案 §5.1)。
|
|
34
|
+
* 缺省(undefined / true)时按 relay env 激活判定走代理。
|
|
35
|
+
*/
|
|
36
|
+
relay?: boolean;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* bun 虚拟文件系统前缀。bun bundle 模式下 process.argv[1] 形如
|
|
41
|
+
* /$bunfs/root/pi——这不是磁盘上的真实文件,不能直接 spawn。
|
|
42
|
+
*/
|
|
43
|
+
const BUN_VIRTUAL_PREFIX = "/$bunfs/root/";
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 判断 execPath 的 basename 是否为通用运行时(node/bun)。
|
|
47
|
+
* 通用运行时需要脚本路径才能启动 pi;非通用(如 pi 的 standalone binary)可直接执行。
|
|
48
|
+
*/
|
|
49
|
+
function isGenericRuntime(execPath: string): boolean {
|
|
50
|
+
const execName = path.basename(execPath).toLowerCase();
|
|
51
|
+
return /^(node|bun)(\.exe)?$/.test(execName);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* 组装 pi 子进程的 spawn 调用。
|
|
56
|
+
*
|
|
57
|
+
* @param userArgs pi CLI 参数(如 ["--mode", "rpc", "--session-dir", "..."])
|
|
58
|
+
* @param opts 可选项(relay:false 强制直连——probe 用,见 PiInvocationOptions)
|
|
59
|
+
* @returns spawn 描述符(command + 完整 args)
|
|
60
|
+
*
|
|
61
|
+
* 决策链(按优先级):
|
|
62
|
+
* 0. relay 激活(三 env 齐备且未显式禁用)→ <RELAY_NODE> <RELAY_SCRIPT> <userArgs>
|
|
63
|
+
* (E 方案 §5.1:xyz-agent runtime 存在时经代理 spawn,改的是进程拓扑不是 pi 语义)
|
|
64
|
+
* 1. process.argv[1] 是真实磁盘文件且非 bun 虚拟路径 → <execPath> <argv[1]> <userArgs>
|
|
65
|
+
* (复现当前 pi 进程的启动方式,确保扩展/配置/版本一致)
|
|
66
|
+
* 2. execPath 非通用运行时(pi standalone binary)→ <execPath> <userArgs>
|
|
67
|
+
* 3. 通用运行时但无可用脚本路径 → "pi" <userArgs>(依赖 PATH 中可找到 pi)
|
|
68
|
+
*/
|
|
69
|
+
// [perf] 决策链只依赖 process.argv[1] / process.execPath(进程内恒定),其中唯一的
|
|
70
|
+
// 磁盘探测(existsSync)结果 memo 一次——每次 spawn 免重复 syscall。memo 键含
|
|
71
|
+
// argv[1] 值:测试 mock 切换 argv[1] 模拟不同运行时时自动失效重算。
|
|
72
|
+
let scriptExistsCache: { script: string | undefined; exists: boolean } | undefined;
|
|
73
|
+
|
|
74
|
+
/** process.argv[1] 是真实磁盘脚本(非 bun 虚拟路径)且存在。 */
|
|
75
|
+
function currentScriptExists(): boolean {
|
|
76
|
+
const currentScript = process.argv[1];
|
|
77
|
+
if (scriptExistsCache === undefined || scriptExistsCache.script !== currentScript) {
|
|
78
|
+
scriptExistsCache = {
|
|
79
|
+
script: currentScript,
|
|
80
|
+
exists:
|
|
81
|
+
currentScript !== undefined &&
|
|
82
|
+
!currentScript.startsWith(BUN_VIRTUAL_PREFIX) &&
|
|
83
|
+
fs.existsSync(currentScript),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
return scriptExistsCache.exists;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function getPiInvocation(userArgs: string[], opts?: PiInvocationOptions): PiInvocation {
|
|
90
|
+
const currentScript = process.argv[1];
|
|
91
|
+
const isBunVirtualScript = currentScript?.startsWith(BUN_VIRTUAL_PREFIX);
|
|
92
|
+
|
|
93
|
+
// 分支 0(前置):relay 激活(E 方案 §5.1)——runtime 注入三 env 齐备且未显式禁用时,
|
|
94
|
+
// spawn 目标切换为 <RELAY_NODE> <RELAY_SCRIPT> <原 pi spawnArgs>,形态与分支 1「node +
|
|
95
|
+
// script」同构(command 是执行器、args[0] 是脚本)。ELECTRON_RUN_AS_NODE 不在此补:
|
|
96
|
+
// 打包态执行器为 Electron 时由 runtime 与三 env 同点注入主 pi 进程 env(E-2
|
|
97
|
+
// getRelaySpawnEnv),本进程 {...process.env} 继承即达代理进程,extension 不重复判定。
|
|
98
|
+
// isRelayActive 已保证三 env 非空,下方取局部变量仅为 TS 收窄(isRelayActive 的
|
|
99
|
+
// 收窄不跨函数边界传导)。
|
|
100
|
+
if (opts?.relay !== false && isRelayActive(process.env)) {
|
|
101
|
+
const relayNode = process.env[RELAY_ENV_NODE];
|
|
102
|
+
const relayScript = process.env[RELAY_ENV_SCRIPT];
|
|
103
|
+
if (relayNode !== undefined && relayScript !== undefined) {
|
|
104
|
+
return { command: relayNode, args: [relayScript, ...userArgs] };
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// 分支 1:有真实脚本路径 → 复现启动方式(node <pi-script> <args>)
|
|
109
|
+
if (currentScript && !isBunVirtualScript && currentScriptExists()) {
|
|
110
|
+
return { command: process.execPath, args: [currentScript, ...userArgs] };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// 分支 2:非通用运行时(pi 自带 binary)→ 直接执行
|
|
114
|
+
if (!isGenericRuntime(process.execPath)) {
|
|
115
|
+
return { command: process.execPath, args: userArgs };
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// 分支 3:通用运行时但脚本不可用 → 依赖 PATH
|
|
119
|
+
return { command: "pi", args: userArgs };
|
|
120
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
// src/execution/record-entry.ts
|
|
2
|
+
//
|
|
3
|
+
// W16 [D4]:subagent record 自描述持久化 entry 的形态权威。
|
|
4
|
+
//
|
|
5
|
+
// pi 文件(session JSONL)是扩展数据持久化权威:record 状态每次迁移都经
|
|
6
|
+
// pi.appendEntry 落一条自描述完整快照(字段即 SubagentRecord),读取方无需
|
|
7
|
+
// 逆向解析 toolCall/toolResult。内存 record-store 保持运行时权威,entry 是
|
|
8
|
+
// 重建源(两者不冲突)。
|
|
9
|
+
//
|
|
10
|
+
// customType 与既有 `subagent-identity`(session 文件首行身份 entry)同族命名
|
|
11
|
+
//(连字符风格);写点见 record-store.ts 的状态迁移点(register/archive/
|
|
12
|
+
// reportRecordTransition),custom entry 由 pi 写进 session JSONL,不进 LLM context。
|
|
13
|
+
|
|
14
|
+
import type {
|
|
15
|
+
AgentEventLogEntry,
|
|
16
|
+
ClosedReason,
|
|
17
|
+
DisplayItem,
|
|
18
|
+
ExecutionMode,
|
|
19
|
+
ExecutionStatus,
|
|
20
|
+
SubagentRecord,
|
|
21
|
+
} from "./types.ts";
|
|
22
|
+
|
|
23
|
+
/** 自描述 record entry 的 customType。写点字面量与本常量的等值由
|
|
24
|
+
* __tests__/record-store.test.ts 断言钉住(消费方引用本常量,勿用裸字符串)。 */
|
|
25
|
+
export const SUBAGENT_RECORD_CUSTOM_TYPE = "subagent-record";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* `subagent-record` entry 的 data schema(v1)。
|
|
29
|
+
*
|
|
30
|
+
* = 完整 SubagentRecord 快照(GUI 侧列表/详情需要的全部持久化字段)+ 版本号。
|
|
31
|
+
* 显式排除三个非持久化字段(与 SubagentRecord 的差集):
|
|
32
|
+
* - currentActivity:running 时的瞬时流态,重开 session 无重建价值;
|
|
33
|
+
* - externalInstance:跨重启探活态(pid/startedAt),由 .alive sidecar 重建;
|
|
34
|
+
* - worktreeHandle:不可 JSON 序列化的运行时句柄(布尔投影 worktree 保留)。
|
|
35
|
+
*
|
|
36
|
+
* undefined 字段经 JSON.stringify 自然缺省(与 SubagentRecord 重建侧语义一致)。
|
|
37
|
+
*/
|
|
38
|
+
export interface SubagentRecordEntryData {
|
|
39
|
+
/** schema 版本(W16 起 v1)。消费方按 v 判别解析,不认识的版本跳过而非猜测。 */
|
|
40
|
+
v: 1;
|
|
41
|
+
id: string;
|
|
42
|
+
agent: string;
|
|
43
|
+
/** 任务提示词(详情面板置顶展示)。 */
|
|
44
|
+
task: string;
|
|
45
|
+
/** 短标签(≤35 字符)。 */
|
|
46
|
+
slug: string;
|
|
47
|
+
status: ExecutionStatus;
|
|
48
|
+
/** L2 关闭原因(仅 status="closed" 时有意义)。 */
|
|
49
|
+
closedReason?: ClosedReason;
|
|
50
|
+
mode: ExecutionMode;
|
|
51
|
+
startedAt: number;
|
|
52
|
+
/** 根 Pi session ID(session 隔离过滤用)。 */
|
|
53
|
+
rootSessionId: string | undefined;
|
|
54
|
+
/** 直接父 subagent record ID(层级树构建用)。顶层为 undefined。 */
|
|
55
|
+
parentRecordId: string | undefined;
|
|
56
|
+
/** subagent 递归深度。顶层 = 0。 */
|
|
57
|
+
depth: number;
|
|
58
|
+
endedAt: number | undefined;
|
|
59
|
+
/** turn 计数。 */
|
|
60
|
+
turns: number;
|
|
61
|
+
totalTokens: number;
|
|
62
|
+
model: string;
|
|
63
|
+
thinkingLevel: string | undefined;
|
|
64
|
+
/** 详情事件日志(/subagents 详情面板)。 */
|
|
65
|
+
eventLog: AgentEventLogEntry[];
|
|
66
|
+
/** 从 turns[] 派生的展示项。 */
|
|
67
|
+
displayItems: DisplayItem[];
|
|
68
|
+
result?: string;
|
|
69
|
+
error?: string;
|
|
70
|
+
sessionFile?: string;
|
|
71
|
+
/** [MF#3] worktree 模式改动 patch 文件路径。 */
|
|
72
|
+
patchFile?: string;
|
|
73
|
+
/** 创建时是否启用 worktree 隔离。 */
|
|
74
|
+
worktree?: boolean;
|
|
75
|
+
/** 对话轮次计数(仅 chatMode 有意义;round+1 由轮终迁移写点携带)。 */
|
|
76
|
+
round?: number;
|
|
77
|
+
/**
|
|
78
|
+
* 对话模式标志(residual-fixes):chat 与否——GUI 侧 done/waiting 细分判据
|
|
79
|
+
* (one-shot 轮终 chatMode=false + result 有值 → 完成态)。register 起写入显式值
|
|
80
|
+
* (one-shot 为显式 false);v1 前存量 entry 缺省,消费端按保守方向处理。
|
|
81
|
+
*/
|
|
82
|
+
chatMode?: boolean;
|
|
83
|
+
/** 执行态信号(residual-fixes):true = 无活进程驱动的 running(轮终/孤儿兜底)。 */
|
|
84
|
+
resumable?: boolean;
|
|
85
|
+
/**
|
|
86
|
+
* 实际执行引擎 id(P4 路由留痕,D9①)。缺省(存量 entry)= pi 投影,消费方零迁移。
|
|
87
|
+
*/
|
|
88
|
+
engine?: string;
|
|
89
|
+
/** 引擎 fallback 留痕(probe 失败路由回默认引擎)。GUI 警告条数据源。 */
|
|
90
|
+
engineFallback?: { from: string; reason: string };
|
|
91
|
+
/**
|
|
92
|
+
* 引擎自描述定位符(U1:read 降级链①②级数据源)。引擎无关——sessionRef 整体
|
|
93
|
+
* 透传不枚举内部键(zcode = { sessionId, dbPath });缺省 = pi(存量 entry 零迁移)。
|
|
94
|
+
*/
|
|
95
|
+
engineHandle?: { sessionRef: Record<string, string>; journalPath?: string; poolKey: string };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** SubagentRecord → 自描述 entry data(快照投影,不 mutate 源)。 */
|
|
99
|
+
export function toSubagentRecordEntry(record: SubagentRecord): SubagentRecordEntryData {
|
|
100
|
+
return {
|
|
101
|
+
v: 1,
|
|
102
|
+
id: record.id,
|
|
103
|
+
agent: record.agent,
|
|
104
|
+
task: record.task,
|
|
105
|
+
slug: record.slug,
|
|
106
|
+
status: record.status,
|
|
107
|
+
closedReason: record.closedReason,
|
|
108
|
+
mode: record.mode,
|
|
109
|
+
startedAt: record.startedAt,
|
|
110
|
+
rootSessionId: record.rootSessionId,
|
|
111
|
+
parentRecordId: record.parentRecordId,
|
|
112
|
+
depth: record.depth,
|
|
113
|
+
endedAt: record.endedAt,
|
|
114
|
+
turns: record.turns,
|
|
115
|
+
totalTokens: record.totalTokens,
|
|
116
|
+
model: record.model,
|
|
117
|
+
thinkingLevel: record.thinkingLevel,
|
|
118
|
+
eventLog: record.eventLog,
|
|
119
|
+
displayItems: record.displayItems,
|
|
120
|
+
result: record.result,
|
|
121
|
+
error: record.error,
|
|
122
|
+
sessionFile: record.sessionFile,
|
|
123
|
+
patchFile: record.patchFile,
|
|
124
|
+
worktree: record.worktree,
|
|
125
|
+
round: record.round,
|
|
126
|
+
chatMode: record.chatMode,
|
|
127
|
+
resumable: record.resumable,
|
|
128
|
+
engine: record.engine,
|
|
129
|
+
engineFallback: record.engineFallback,
|
|
130
|
+
engineHandle: record.engineHandle,
|
|
131
|
+
};
|
|
132
|
+
}
|