@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,198 @@
|
|
|
1
|
+
// src/execution/stdin-writer.ts
|
|
2
|
+
//
|
|
3
|
+
// 向 rpc 子进程 stdin 写入命令的 helper 集合。
|
|
4
|
+
//
|
|
5
|
+
// pi --mode rpc 通过 stdin 的 JSON RpcCommand / RpcExtensionUIResponse 驱动:
|
|
6
|
+
// - extension_ui_response(主进程回答子进程的 UI 请求,如 ask_user)
|
|
7
|
+
// - prompt(驱动子进程开始处理 task)
|
|
8
|
+
// 两者共用 child.stdin.write + 背压检查,提取到此模块统一维护。
|
|
9
|
+
|
|
10
|
+
import type { ChildProcess } from "node:child_process";
|
|
11
|
+
import * as crypto from "node:crypto";
|
|
12
|
+
|
|
13
|
+
import { getLogger } from "../core/logger.ts";
|
|
14
|
+
|
|
15
|
+
import type { UiResponse } from "./dialog-queue.ts";
|
|
16
|
+
|
|
17
|
+
const logger = getLogger("subagents");
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* EPIPE 连续失败计数器(record.id → 连续 EPIPE 次数)。
|
|
21
|
+
*
|
|
22
|
+
* [v4 A-1] 计数器从 subagent-service.ts 迁移到本模块(stdin 错误域)。迁移原因:
|
|
23
|
+
* session-runner.ts 已被 subagent-service.ts import(runSpawn 等),若 session-runner
|
|
24
|
+
* 反向 import subagent-service 的 helper 会循环依赖。stdin-writer 不 import 两者,
|
|
25
|
+
* 是 stdin 域中立模块,epipe 计数属 stdin 错误域,职责合理。
|
|
26
|
+
*
|
|
27
|
+
* 错误处理两半面共用本计数器(合并计数,防 spawn→EPIPE→resume 死循环):
|
|
28
|
+
* ① 同步 write 抛错(writeStdinLine throw → deliverMessage catch 递增)
|
|
29
|
+
* ② 异步 stream 'error' event(session-runner.ts child.stdin.on('error') 递增)
|
|
30
|
+
*/
|
|
31
|
+
const epipeConsecutiveFailures = new Map<string, number>();
|
|
32
|
+
|
|
33
|
+
/** 连续 EPIPE 失败阈值:达到即不再尝试 resume(避免无限 spawn → EPIPE → resume 循环)。 */
|
|
34
|
+
export const EPIPE_FAILURE_THRESHOLD = 2;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* 递增 recordId 的 EPIPE 连续失败计数,返回递增后的新计数。
|
|
38
|
+
* 同步 writeStdinLine throw 与异步 child.stdin 'error' event 共用此入口(合并计数)。
|
|
39
|
+
*/
|
|
40
|
+
export function recordEpipeFailure(recordId: string): number {
|
|
41
|
+
const count = (epipeConsecutiveFailures.get(recordId) ?? 0) + 1;
|
|
42
|
+
epipeConsecutiveFailures.set(recordId, count);
|
|
43
|
+
return count;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** 成功写入时清零某 record 的 EPIPE 连续失败计数(热路径成功 → 重置,允许后续重新计数)。 */
|
|
47
|
+
export function clearEpipeFailure(recordId: string): void {
|
|
48
|
+
epipeConsecutiveFailures.delete(recordId);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** dispose 时清空所有 EPIPE 计数(防跨 session 泄漏)。 */
|
|
52
|
+
export function resetAllEpipeFailures(): void {
|
|
53
|
+
epipeConsecutiveFailures.clear();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* 按 UiResponse 形状构造 Pi 原生 extension_ui_response 并写 stdin。
|
|
58
|
+
*
|
|
59
|
+
* SR-5:ack(fire-and-forget)不写 stdin——Pi 对 fire-and-forget method 不期待响应,
|
|
60
|
+
* 写入会触发协议错配。其他三种 shape(value/confirmed/cancelled)按对应字段写。
|
|
61
|
+
*
|
|
62
|
+
* [R1] 背压检查:child.stdin.write 返回 false 时记 warn(不阻塞,内核缓冲会随后排空)。
|
|
63
|
+
* [R2] 序列化在本函数内逐分支完成。JSON.stringify 可能抛错(out.value 含循环引用 /
|
|
64
|
+
* BigInt 等不可序列化结构),try/catch 降级为 cancelled——宁可取消单次 dialog 也不让
|
|
65
|
+
* 父进程崩溃(UI 请求通道不应被脏数据拖垮)。
|
|
66
|
+
*
|
|
67
|
+
* @param child 子进程(stdin 写入响应)
|
|
68
|
+
* @param id 请求 id(关联 response)
|
|
69
|
+
* @param out UiResponse({value}/{confirmed}/{cancelled}/{ack})
|
|
70
|
+
* @param signal abort signal(已 aborted 时跳过写入)
|
|
71
|
+
*/
|
|
72
|
+
export function respond(child: ChildProcess, id: string, out: UiResponse, signal?: AbortSignal): void {
|
|
73
|
+
if (signal?.aborted) return;
|
|
74
|
+
let line: string | undefined;
|
|
75
|
+
try {
|
|
76
|
+
if ("value" in out) line = JSON.stringify({ type: "extension_ui_response", id, value: out.value });
|
|
77
|
+
else if ("confirmed" in out) line = JSON.stringify({ type: "extension_ui_response", id, confirmed: out.confirmed });
|
|
78
|
+
else if ("cancelled" in out) line = JSON.stringify({ type: "extension_ui_response", id, cancelled: true });
|
|
79
|
+
} catch (err) {
|
|
80
|
+
// [R2] out.value 含循环引用/BigInt 等不可序列化结构——降级 cancelled,避免父进程崩溃。
|
|
81
|
+
logger.warn(`[subagents] JSON.stringify failed for ui response ${id}, degrading to cancelled`, {
|
|
82
|
+
detail: err instanceof Error ? err.message : String(err),
|
|
83
|
+
});
|
|
84
|
+
line = JSON.stringify({ type: "extension_ui_response", id, cancelled: true });
|
|
85
|
+
}
|
|
86
|
+
// ack: fire-and-forget,不写 stdin(SR-5)
|
|
87
|
+
if (line === undefined) return;
|
|
88
|
+
writeStdinLine(child, line, `ui response for request ${id}`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* spawn 后向 rpc 子进程 stdin 写 prompt 命令,驱动 agent 开始处理 task。
|
|
93
|
+
*
|
|
94
|
+
* pi 的 runRpcMode 只通过 stdin RpcCommand 驱动——positional task arg / -p flag
|
|
95
|
+
* 在 rpc mode 下被 resolveAppMode 无视。必须在 spawn 后主动喂 prompt 命令,
|
|
96
|
+
* 否则子进程阻塞等 stdin、永不进入推理(totalTokens 恒 0)。
|
|
97
|
+
*
|
|
98
|
+
* 时机:spawn 后立即写。stdin 是 pipe,内核缓冲保证数据不丢;
|
|
99
|
+
* pi 在 await rebindSession() 后才挂 stdin reader(rpc-mode.ts:778-781),
|
|
100
|
+
* reader 处理 prompt 时 session 已就绪。
|
|
101
|
+
*
|
|
102
|
+
* [V2 决策 3] chatMode 续聊热路径用 prompt + streamingBehavior 统一投递(替代 steer/followUp
|
|
103
|
+
* 命令),pi 权威裁决 busy/idle(设计 F3/F4):busy 时 followUp 入队/steer 抢占;idle 时
|
|
104
|
+
* streamingBehavior 被忽略、直接开新 turn。不传 streamingBehavior(首帧 prompt / 旧调用方)
|
|
105
|
+
* 行为完全不变——向后兼容。
|
|
106
|
+
*
|
|
107
|
+
* @param child 子进程(stdin 写入 prompt 命令)
|
|
108
|
+
* @param task 完整 task 文本(含 schema 指令)
|
|
109
|
+
* @param options.streamingBehavior V2 统一投递语义:`"followUp"`(排队,当前轮后处理)/ `"steer"`(抢占,立即中断 streaming)。
|
|
110
|
+
* 省略时不写入该字段(首帧 prompt / 非 chatMode 调用方,行为不变)。
|
|
111
|
+
*/
|
|
112
|
+
export function sendPromptCommand(
|
|
113
|
+
child: ChildProcess,
|
|
114
|
+
task: string,
|
|
115
|
+
options?: { streamingBehavior?: "followUp" | "steer" },
|
|
116
|
+
): void {
|
|
117
|
+
if (!child.stdin || child.stdin.destroyed) return;
|
|
118
|
+
const payload: Record<string, unknown> = {
|
|
119
|
+
id: crypto.randomUUID(),
|
|
120
|
+
type: "prompt",
|
|
121
|
+
message: task,
|
|
122
|
+
};
|
|
123
|
+
if (options?.streamingBehavior) {
|
|
124
|
+
payload.streamingBehavior = options.streamingBehavior;
|
|
125
|
+
}
|
|
126
|
+
writeStdinLine(child, JSON.stringify(payload), "prompt command");
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* [review 修复 round2] 已删除 sendFollowUpCommand / sendSteerCommand——deliverToRunning
|
|
131
|
+
* (busy 投递死机制,S2 删除)的唯一消费方移除后两函数成零生产调用方死 export。
|
|
132
|
+
* busy 投递语义由 prompt + streamingBehavior(sendPromptCommand 的
|
|
133
|
+
* options.streamingBehavior: "followUp" | "steer",pi 权威裁决)承担。
|
|
134
|
+
*/
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* 向 rpc 子进程 stdin 写 get_state 命令,查询 sessionFile/sessionId。
|
|
138
|
+
*
|
|
139
|
+
* FR-4: RPC get_state 握手。当 stdout header 未携带 sessionFile 时,
|
|
140
|
+
* 通过此命令向子进程查询当前 session 状态。子进程收到后返回
|
|
141
|
+
* {type:"response", command:"get_state", success:true, data:{sessionFile, sessionId}}。
|
|
142
|
+
*
|
|
143
|
+
* @param child 子进程(stdin 写入 get_state 命令)
|
|
144
|
+
* @returns 请求 id(用于匹配 response)
|
|
145
|
+
*/
|
|
146
|
+
export function sendGetStateCommand(child: ChildProcess): string {
|
|
147
|
+
const id = crypto.randomUUID();
|
|
148
|
+
const command = JSON.stringify({
|
|
149
|
+
id,
|
|
150
|
+
type: "get_state",
|
|
151
|
+
});
|
|
152
|
+
writeStdinLine(child, command, "get_state command");
|
|
153
|
+
return id;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* 向子进程 stdin 写一行(自动补换行),带背压检查 + EPIPE 检测。
|
|
158
|
+
*
|
|
159
|
+
* [R1] write 返回 false 时记 warn(不阻塞,内核缓冲会随后排空)。
|
|
160
|
+
* [R3] write 抛 EPIPE / ERR_STREAM_DESTROYED 时 throw 含 EPIPE 关键词的 Error,
|
|
161
|
+
* 让上层(deliverMessage)能捕获并自动转冷路径 resume。
|
|
162
|
+
* stdin 已关闭/销毁时跳过——respond 已检查 signal,sendPromptCommand 已检查 destroyed。
|
|
163
|
+
*
|
|
164
|
+
* @param child 子进程
|
|
165
|
+
* @param line JSON 行(不含换行)
|
|
166
|
+
* @param warnTag warn 日志的语义标记
|
|
167
|
+
* @throws Error 含 "EPIPE" 关键词——stdin 管道已断(子进程已退出 / stdin 被销毁)
|
|
168
|
+
*/
|
|
169
|
+
function writeStdinLine(child: ChildProcess, line: string, warnTag: string): void {
|
|
170
|
+
if (!child.stdin || child.stdin.destroyed) return;
|
|
171
|
+
try {
|
|
172
|
+
const ok = child.stdin.write(line + "\n");
|
|
173
|
+
if (!ok) logger.warn(`[subagents] stdin backpressure on ${warnTag}`);
|
|
174
|
+
} catch (err) {
|
|
175
|
+
// [R3] EPIPE / ERR_STREAM_DESTROYED:stdin 管道已断,子进程已退出或 stdin 被销毁。
|
|
176
|
+
// [v4 A-1] 错误处理两半面:① 同步 write 抛错(本 catch)——上层 deliverMessage 捕获后
|
|
177
|
+
// 调 recordEpipeFailure 递增计数;② 异步 stream 'error' event(session-runner.ts 的
|
|
178
|
+
// child.stdin.on('error') listener)。两者共用本模块 export 的 recordEpipeFailure
|
|
179
|
+
// helper 合并计数(防 spawn→EPIPE→resume 死循环)。
|
|
180
|
+
// throw 让上层(deliverMessage)捕获并自动转冷路径 resume + 消息重放。
|
|
181
|
+
if (
|
|
182
|
+
err !== null &&
|
|
183
|
+
typeof err === "object" &&
|
|
184
|
+
"code" in err &&
|
|
185
|
+
((err as NodeJS.ErrnoException).code === "EPIPE" ||
|
|
186
|
+
(err as NodeJS.ErrnoException).code === "ERR_STREAM_DESTROYED")
|
|
187
|
+
) {
|
|
188
|
+
throw new Error(
|
|
189
|
+
`[subagents] EPIPE on stdin write (${warnTag}): pipe broken, child process likely exited. ` +
|
|
190
|
+
`Recovery: treat as dead process and resume via cold path.`,
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
// 非 EPIPE 错误(不应发生,但兜底降级为 warn 不崩溃)
|
|
194
|
+
logger.warn(`[subagents] unexpected stdin write error on ${warnTag}`, {
|
|
195
|
+
detail: err instanceof Error ? err.message : String(err),
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* subagent text_delta streaming sink。
|
|
3
|
+
*
|
|
4
|
+
* background subagent 执行期间,session-runner 的 agentEvent 出口把每个 text_delta
|
|
5
|
+
* 传到 SubagentStream.onDelta。本模块做 100ms 时间窗合并后,通过 StreamSink.setWidget
|
|
6
|
+
* 转发到 RPC stdout(经 ctx.ui.setWidget → extension_ui_request 通道)。
|
|
7
|
+
*
|
|
8
|
+
* SubagentStream 是一个生命周期对象——内聚 buffer/timer 状态 + onDelta/dispose 方法。
|
|
9
|
+
* 调用方(subagent-service)创建后只需在 text_delta 时调 onDelta、终态时调 dispose,
|
|
10
|
+
* 不需要拆散 push/clear 两个函数跨层透传。
|
|
11
|
+
*
|
|
12
|
+
* 设计要点:
|
|
13
|
+
* - leading edge:第一个 delta 立即 flush(前端尽快看到开始)
|
|
14
|
+
* - trailing edge:后续 delta 追加 buffer,timer 到期后 flush
|
|
15
|
+
* - 每次 flush 把 buffer 的累积文本 split("\n") 截尾 MAX_WIDGET_LINES 行传给 setWidget
|
|
16
|
+
* - dispose 清除 widget + 清 timer
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import type { ExtensionMode } from "./host-mode.ts";
|
|
20
|
+
import { resolveHostMode } from "./host-mode.ts";
|
|
21
|
+
import { isRelayActive } from "./relay-env.ts";
|
|
22
|
+
|
|
23
|
+
/** UI streaming sink 的最小接口(ctx.ui.setWidget 的 duck-typed 子集)。
|
|
24
|
+
*
|
|
25
|
+
* 当前只有一个 adapter(index.ts session_start 包装 ctx.ui.setWidget)。
|
|
26
|
+
* 保留接口而非裸函数类型,因为 StreamSink 的语义是「UI sink 契约」——
|
|
27
|
+
* 测试 mock 和未来可能的第二 sink(如写文件)都走此契约。 */
|
|
28
|
+
export interface StreamSink {
|
|
29
|
+
setWidget(key: string, lines: string[] | undefined): void;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** delta 合并窗口时间(ms)。 */
|
|
33
|
+
const STREAM_FLUSH_MS = 100;
|
|
34
|
+
|
|
35
|
+
/** widget 发送的最大行数上限。
|
|
36
|
+
*
|
|
37
|
+
* flush 把 buffer 累积全文 split 后经 setWidget RPC 通道整包发送——长输出 subagent
|
|
38
|
+
* (数百 KB)下每 100ms 一次 O(当前总量) 的序列化+传输,累计 O(n²)。widget 是实时
|
|
39
|
+
* 预览(完整输出在 record/eventLog 与 session 文件),只保留尾部行即可;超限时以
|
|
40
|
+
* 一行 truncated 提示替代被裁掉的头部。 */
|
|
41
|
+
const MAX_WIDGET_LINES = 200;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* subagent text_delta streaming 生命周期对象。
|
|
45
|
+
*
|
|
46
|
+
* 创建后:
|
|
47
|
+
* - `onDelta(delta)`:session-runner 每次 text_delta 调
|
|
48
|
+
* - `dispose()`:subagent 终态时调,清除 widget + 清 timer
|
|
49
|
+
*
|
|
50
|
+
* buffer/timer 状态全部内聚在此对象,调用方不需要关心合并逻辑。
|
|
51
|
+
*/
|
|
52
|
+
export class SubagentStream {
|
|
53
|
+
private readonly widgetKey: string;
|
|
54
|
+
private readonly sink: StreamSink;
|
|
55
|
+
private buffer = "";
|
|
56
|
+
private timer: ReturnType<typeof setTimeout> | undefined;
|
|
57
|
+
private hasFlushed = false;
|
|
58
|
+
private disposed = false;
|
|
59
|
+
|
|
60
|
+
constructor(recordId: string, sink: StreamSink) {
|
|
61
|
+
this.widgetKey = `subagent-stream-${recordId}`;
|
|
62
|
+
this.sink = sink;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** 接收一个 text_delta 增量。空串静默丢弃(不消耗 leading edge)。 */
|
|
66
|
+
onDelta(delta: string): void {
|
|
67
|
+
if (this.disposed || delta.length === 0) return;
|
|
68
|
+
this.buffer += delta;
|
|
69
|
+
if (!this.hasFlushed) {
|
|
70
|
+
// leading edge:第一个 delta 立即 flush
|
|
71
|
+
this.hasFlushed = true;
|
|
72
|
+
this.flush();
|
|
73
|
+
} else if (this.timer === undefined) {
|
|
74
|
+
// trailing edge:后续 delta 经 timer 合并
|
|
75
|
+
this.timer = setTimeout(() => this.flush(), STREAM_FLUSH_MS);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** 终态清理:清除 widget + 清 timer(幂等)。 */
|
|
80
|
+
dispose(): void {
|
|
81
|
+
if (this.disposed) return;
|
|
82
|
+
this.disposed = true;
|
|
83
|
+
if (this.timer !== undefined) {
|
|
84
|
+
clearTimeout(this.timer);
|
|
85
|
+
this.timer = undefined;
|
|
86
|
+
}
|
|
87
|
+
this.sink.setWidget(this.widgetKey, undefined);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
private flush(): void {
|
|
91
|
+
this.timer = undefined;
|
|
92
|
+
if (this.buffer.length === 0 || this.disposed) return;
|
|
93
|
+
const lines = this.buffer.split("\n");
|
|
94
|
+
if (lines.length <= MAX_WIDGET_LINES) {
|
|
95
|
+
this.sink.setWidget(this.widgetKey, lines);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const dropped = lines.length - MAX_WIDGET_LINES;
|
|
99
|
+
this.sink.setWidget(this.widgetKey, [
|
|
100
|
+
`(... ${dropped} earlier lines truncated, full output in /subagents detail)`,
|
|
101
|
+
...lines.slice(dropped),
|
|
102
|
+
]);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* background stream 创建策略(widget 私货通道退役步骤 2,E 方案 §6.3)。
|
|
108
|
+
*
|
|
109
|
+
* GUI(mode=rpc)+ relay 激活时不创建——drawer 实时改由 runtime tee 供数
|
|
110
|
+
* (session.subagentEntriesAppended 帧),extension 停发 setWidget 私货,主 pi stdout
|
|
111
|
+
* 卸载。TUI(widget 行是 TUI 用户的实时预览)与 relay 未激活环境(独立 pi / 无
|
|
112
|
+
* xyz-agent runtime)原样创建——universal 包自足性不绑架。
|
|
113
|
+
*
|
|
114
|
+
* env/mode 显式入参而非内部读 process.env:调用方语义(本 record 的宿主形态)一次
|
|
115
|
+
* 确定,测试可注入,函数保持纯判定。
|
|
116
|
+
*/
|
|
117
|
+
export function createBackgroundStream(
|
|
118
|
+
recordId: string,
|
|
119
|
+
sink: StreamSink | null,
|
|
120
|
+
mode: ExtensionMode | undefined,
|
|
121
|
+
env: NodeJS.ProcessEnv | Record<string, string | undefined>,
|
|
122
|
+
): SubagentStream | undefined {
|
|
123
|
+
if (sink === null) return undefined;
|
|
124
|
+
if (isRelayActive(env) && resolveHostMode(mode) === "gui") return undefined;
|
|
125
|
+
return new SubagentStream(recordId, sink);
|
|
126
|
+
}
|