@zhushanwen/subagent-core 0.6.0 → 0.7.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 +1 -1
- package/dist/chunk-KXVBIVOU.js +16 -0
- package/dist/chunk-T2SYBW3I.js +24 -0
- package/dist/chunk-VURUAGMM.js +2305 -0
- package/dist/{types-C3fE3R9x.d.cts → engine-discovery-scan-ocpM8FmI.d.cts} +770 -668
- package/dist/{types-C3fE3R9x.d.ts → engine-discovery-scan-ocpM8FmI.d.ts} +770 -668
- package/dist/execution/engine/engine-discovery-scan.cjs +2210 -0
- package/dist/execution/engine/engine-discovery-scan.d.cts +4 -0
- package/dist/execution/engine/engine-discovery-scan.d.ts +4 -0
- package/dist/execution/engine/engine-discovery-scan.js +20 -0
- package/dist/execution/engine/paths.cjs +6 -23
- package/dist/execution/engine/paths.d.cts +1 -8
- package/dist/execution/engine/paths.d.ts +1 -8
- package/dist/execution/engine/paths.js +1 -1
- package/dist/execution/relay-env.cjs +12 -28
- package/dist/execution/relay-env.d.cts +1 -33
- package/dist/execution/relay-env.d.ts +1 -33
- package/dist/execution/relay-env.js +5 -3
- package/dist/index.cjs +14045 -16059
- package/dist/index.d.cts +1035 -1579
- package/dist/index.d.ts +1035 -1579
- package/dist/index.js +9838 -13800
- package/dist.bundle/index.cjs +28875 -30323
- package/package.json +20 -26
- package/src/__tests__/record-store-last-line.test.ts +16 -7
- package/src/core/error-message.ts +7 -6
- package/src/core/host-services.ts +8 -2
- package/src/core/notify-ports.ts +17 -2
- package/src/execution/__tests__/chat-engine-routing.test.ts +62 -28
- package/src/execution/__tests__/chat-round-first-round-watchdog.test.ts +255 -0
- package/src/execution/__tests__/collect-coordinator-service.test.ts +36 -47
- package/src/execution/__tests__/collect-mixed-dispatch.test.ts +20 -53
- package/src/execution/__tests__/delivery-methods.test.ts +179 -237
- package/src/execution/__tests__/execute-and-await-worktree.test.ts +0 -2
- package/src/execution/__tests__/execute-nesting.test.ts +20 -13
- package/src/execution/__tests__/explicit-agent-ref-guard.test.ts +20 -33
- package/src/execution/__tests__/gc-timer.test.ts +7 -22
- package/src/execution/__tests__/get-record-for-action-restart.test.ts +20 -10
- package/src/execution/__tests__/helpers/fake-engine-port.ts +187 -0
- package/src/execution/__tests__/helpers/spawn-mock.ts +36 -9
- package/src/execution/__tests__/helpers/subagent-service-mocks.ts +1 -1
- package/src/execution/__tests__/idle-gc.test.ts +200 -0
- package/src/execution/__tests__/lifecycle-predicates.test.ts +26 -21
- package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +5 -2
- package/src/execution/__tests__/reconcile-sweep.test.ts +200 -0
- package/src/execution/__tests__/record-store.test.ts +60 -6
- package/src/execution/__tests__/recursive-visibility-baseline.test.ts +20 -13
- package/src/execution/__tests__/round-supervisor.test.ts +293 -0
- package/src/execution/__tests__/session-pending.test.ts +119 -17
- package/src/execution/__tests__/stream-sink-retirement.test.ts +10 -10
- package/src/execution/__tests__/subagent-service-multiproc-guard.test.ts +1 -11
- package/src/execution/__tests__/subagent-service-notify-gate.test.ts +33 -30
- package/src/execution/__tests__/subagent-service-parent-guard.test.ts +2 -9
- package/src/execution/__tests__/subagent-service-recovery-bounds.test.ts +59 -129
- package/src/execution/__tests__/subagent-service.test.ts +2 -2
- package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +109 -7
- package/src/execution/__tests__/subprocess-agent-runner.test.ts +108 -36
- package/src/execution/__tests__/sync-collect-recovery.test.ts +21 -36
- package/src/execution/__tests__/workflow-state-root.test.ts +232 -0
- package/src/execution/agent-registry.ts +6 -2
- package/src/execution/dialog-queue.ts +6 -73
- package/src/execution/engine/__tests__/common/capability-gate.test.ts +115 -15
- package/src/execution/engine/__tests__/common/errors.test.ts +11 -18
- package/src/execution/engine/__tests__/common/kill-chain.test.ts +7 -0
- package/src/execution/engine/__tests__/common/nesting-guard.test.ts +9 -3
- package/src/execution/engine/__tests__/common/session-view-service.test.ts +90 -3
- package/src/execution/engine/__tests__/conformance/H9-test-disposition.md +116 -0
- package/src/execution/engine/__tests__/conformance/__fixtures__/engine-protocol/fake-engine-protocol.mjs +377 -0
- package/src/execution/engine/__tests__/conformance/__fixtures__/engine-protocol/recorded.fixture.json +331 -0
- package/src/execution/engine/__tests__/conformance/__fixtures__/engine-protocol/smoke-run.fixture.json +213 -0
- package/src/execution/engine/__tests__/conformance/chat-round-protocol.test.ts +230 -0
- package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +69 -42
- package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +4 -81
- package/src/execution/engine/__tests__/conformance/contract.probe.test.ts +67 -44
- package/src/execution/engine/__tests__/conformance/contract.read-degradation.test.ts +81 -54
- package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +133 -70
- package/src/execution/engine/__tests__/conformance/engine-crash.test.ts +143 -0
- package/src/execution/engine/__tests__/conformance/fake-engine-capabilities.ts +19 -0
- package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +7 -2
- package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +6 -5
- package/src/execution/engine/__tests__/conformance/protocol-blackbox.test.ts +398 -0
- package/src/execution/engine/__tests__/conformance/registry-fork-filter.test.ts +221 -0
- package/src/execution/engine/__tests__/conformance/round-liveness-supervisor.test.ts +302 -0
- package/src/execution/engine/__tests__/conformance/static-spawn-guard.test.ts +58 -0
- package/src/execution/engine/__tests__/engine-discovery-scan.test.ts +558 -0
- package/src/execution/engine/__tests__/host-task-spec.test.ts +45 -0
- package/src/execution/engine/__tests__/model-ref-split.test.ts +74 -0
- package/src/execution/engine/__tests__/registry.test.ts +206 -1
- package/src/execution/engine/__tests__/routing.test.ts +97 -0
- package/src/execution/engine/__tests__/run-failure-worktree-cleanup.test.ts +97 -0
- package/src/execution/engine/client/__tests__/__fixtures__/fake-engine.mjs +294 -0
- package/src/execution/engine/client/__tests__/engine-client.test.ts +516 -0
- package/src/execution/engine/client/__tests__/mirror.test.ts +67 -0
- package/src/execution/engine/client/__tests__/pid-file.test.ts +257 -0
- package/src/execution/engine/client/__tests__/protocol-closure.test.ts +95 -0
- package/src/execution/engine/client/__tests__/remote-engine.test.ts +457 -0
- package/src/execution/engine/client/client-options.ts +103 -0
- package/src/execution/engine/client/engine-client.ts +687 -0
- package/src/execution/engine/client/mirror.ts +167 -0
- package/src/execution/engine/client/pid-file.ts +392 -0
- package/src/execution/engine/client/reaper.ts +95 -0
- package/src/execution/engine/client/remote-engine.ts +441 -0
- package/src/execution/engine/client/reverse-router.ts +255 -0
- package/src/execution/engine/common/capability-gate.ts +109 -22
- package/src/execution/engine/common/errors.ts +9 -25
- package/src/execution/engine/common/event-journal.ts +4 -50
- package/src/execution/engine/common/journal-replay.ts +3 -1
- package/src/execution/engine/common/kill-chain.ts +18 -251
- package/src/execution/engine/common/nesting-guard.ts +18 -114
- package/src/execution/engine/common/pool-manager.ts +4 -0
- package/src/execution/engine/common/session-view-service.ts +56 -84
- package/src/execution/engine/config.ts +151 -0
- package/src/execution/engine/d8-compat.ts +346 -0
- package/src/execution/engine/engine-discovery-roots.ts +107 -0
- package/src/execution/engine/engine-discovery-scan.ts +269 -0
- package/src/execution/engine/engine-discovery.ts +30 -7
- package/src/execution/engine/engine-inspect-package.ts +282 -0
- package/src/execution/engine/engine-manifest.ts +244 -0
- package/src/execution/engine/host/__tests__/host-askuser-endpoint.test.ts +123 -0
- package/src/execution/engine/host/__tests__/host-bridge.test.ts +135 -0
- package/src/execution/engine/host/__tests__/spawned-children.test.ts +73 -0
- package/src/execution/engine/host/host-bridge.ts +150 -0
- package/src/execution/engine/host/host-ui-endpoint.ts +47 -0
- package/src/execution/engine/host/pi-host-binding.ts +91 -0
- package/src/execution/engine/host/spawned-children.ts +139 -0
- package/src/execution/engine/host-task-spec.ts +29 -2
- package/src/execution/engine/model-validation.ts +55 -2
- package/src/execution/engine/paths.ts +16 -41
- package/src/execution/engine/port.ts +48 -2
- package/src/execution/engine/registry.ts +153 -34
- package/src/execution/engine/routing.ts +225 -52
- package/src/execution/engine/types.ts +25 -200
- package/src/execution/finalize-record.ts +25 -0
- package/src/execution/idle-gc.ts +89 -14
- package/src/execution/lifecycle-manager.ts +10 -7
- package/src/execution/lifecycle-predicates.ts +10 -8
- package/src/execution/record-store.ts +29 -2
- package/src/execution/relay-env.ts +19 -36
- package/src/execution/round-supervisor/domain.ts +89 -0
- package/src/execution/round-supervisor/index.ts +33 -0
- package/src/execution/round-supervisor/notify-accounting.ts +87 -0
- package/src/execution/round-supervisor/reconcile-sweep.ts +235 -0
- package/src/execution/round-supervisor/service-binding.test.ts +661 -0
- package/src/execution/round-supervisor/service-binding.ts +273 -0
- package/src/execution/round-supervisor/supervisor.ts +426 -0
- package/src/execution/session-pending.ts +68 -74
- package/src/execution/settled-watchdog.ts +39 -0
- package/src/execution/subagent-service.ts +746 -400
- package/src/execution/subprocess-agent-runner.ts +16 -8
- package/src/execution/types.ts +41 -117
- package/src/execution/ui-channels.ts +13 -214
- package/src/execution/ui-request-handler-factory.ts +7 -4
- package/src/execution/ui-request-observability.ts +2 -2
- package/src/execution/workflow-state-root.ts +67 -0
- package/src/execution/worktree-git-ops.ts +5 -0
- package/src/execution/worktree-manager.ts +11 -1
- package/src/index.ts +55 -26
- package/src/orchestration/__tests__/execute-agent-call.test.ts +1 -1
- package/src/orchestration/execute-agent-call.ts +1 -1
- package/src/orchestration/file-run-store.ts +144 -59
- package/src/orchestration/models/types.ts +43 -42
- package/src/shared/zcode-model-ref.ts +31 -0
- package/dist/chunk-43ONBFZX.js +0 -240
- package/dist/chunk-A4IVZWVX.js +0 -31
- package/dist/chunk-APZY4IME.js +0 -27
- package/dist/chunk-V3VHZ2VX.js +0 -59
- package/dist/execution/engine/engines/zcode/constants.cjs +0 -107
- package/dist/execution/engine/engines/zcode/constants.d.cts +0 -135
- package/dist/execution/engine/engines/zcode/constants.d.ts +0 -135
- package/dist/execution/engine/engines/zcode/constants.js +0 -54
- package/dist/execution/engine/engines/zcode/reader.cjs +0 -276
- package/dist/execution/engine/engines/zcode/reader.d.cts +0 -21
- package/dist/execution/engine/engines/zcode/reader.d.ts +0 -21
- package/dist/execution/engine/engines/zcode/reader.js +0 -9
- package/src/__tests__/append-system-prompt-assembly.test.ts +0 -243
- package/src/__tests__/fr4-get-state-handshake.test.ts +0 -125
- package/src/__tests__/session-runner.test.ts +0 -69
- package/src/execution/__tests__/ask-user-transit-e2e.test.ts +0 -490
- package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +0 -191
- package/src/execution/__tests__/descendant-sweep-guards.test.ts +0 -220
- package/src/execution/__tests__/descendant-sweep.test.ts +0 -269
- package/src/execution/__tests__/engine-model-validation.test.ts +0 -741
- package/src/execution/__tests__/epipe-fallback.test.ts +0 -248
- package/src/execution/__tests__/execution-runtime-face.test.ts +0 -272
- package/src/execution/__tests__/get-state-handshake.test.ts +0 -127
- package/src/execution/__tests__/helpers/session-runner-mocks.ts +0 -113
- package/src/execution/__tests__/keep-alive-no-progress.test.ts +0 -280
- package/src/execution/__tests__/kill-all-escalation.test.ts +0 -196
- package/src/execution/__tests__/max-turns-to-watchdog-ms.test.ts +0 -113
- package/src/execution/__tests__/output-collector.test.ts +0 -469
- package/src/execution/__tests__/pi-invocation.test.ts +0 -166
- package/src/execution/__tests__/recursive-visibility-env.test.ts +0 -149
- package/src/execution/__tests__/rpc-mode.test.ts +0 -89
- package/src/execution/__tests__/run-and-finalize-anchoring.test.ts +0 -387
- package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +0 -277
- package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +0 -254
- package/src/execution/__tests__/run-spawn-edges.test.ts +0 -1079
- package/src/execution/__tests__/run-spawn-integration.test.ts +0 -933
- package/src/execution/__tests__/run-spawn-resume.test.ts +0 -322
- package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +0 -196
- package/src/execution/__tests__/run-spawn-stdout-callback-throw.test.ts +0 -207
- package/src/execution/__tests__/service-kill-escalation.test.ts +0 -91
- package/src/execution/__tests__/session-runner-branch-cache-lru.test.ts +0 -110
- package/src/execution/__tests__/session-runner-close-prune.test.ts +0 -181
- package/src/execution/__tests__/session-runner-dispatch.test.ts +0 -489
- package/src/execution/__tests__/session-runner-epipe.test.ts +0 -179
- package/src/execution/__tests__/session-runner-heartbeat-idle-fallback.test.ts +0 -227
- package/src/execution/__tests__/session-runner-lifecycle-helpers.test.ts +0 -290
- package/src/execution/__tests__/session-runner-schema-env.test.ts +0 -352
- package/src/execution/__tests__/settled-watchdog.test.ts +0 -524
- package/src/execution/__tests__/spawn-args.test.ts +0 -446
- package/src/execution/__tests__/spawn-event-adapter-rpc.test.ts +0 -192
- package/src/execution/__tests__/spawn-event-adapter.test.ts +0 -167
- package/src/execution/__tests__/spawn-worktree-guidance.test.ts +0 -208
- package/src/execution/__tests__/spawned-children.test.ts +0 -236
- package/src/execution/__tests__/start-sync-model-guard.test.ts +0 -150
- package/src/execution/__tests__/stdin-writer.test.ts +0 -464
- package/src/execution/__tests__/subagent-service-message-close.test.ts +0 -693
- package/src/execution/__tests__/temp-prompt.test.ts +0 -53
- package/src/execution/__tests__/timeout-integration.test.ts +0 -616
- package/src/execution/__tests__/turn-limiter-semantics.test.ts +0 -194
- package/src/execution/__tests__/turn-limiter.test.ts +0 -65
- package/src/execution/__tests__/ui-request-handler.test.ts +0 -205
- package/src/execution/__tests__/ui-request-queue.test.ts +0 -298
- package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +0 -230
- package/src/execution/engine/__tests__/common/schema-emulation.test.ts +0 -128
- package/src/execution/engine/__tests__/common/session-view-service-zcode-dbpath.test.ts +0 -149
- package/src/execution/engine/__tests__/conformance/__fixtures__/pi-golden-events.json +0 -28
- package/src/execution/engine/__tests__/conformance/zcode-appserver-harness.ts +0 -128
- package/src/execution/engine/__tests__/paths.test.ts +0 -39
- package/src/execution/engine/common/schema-emulation.ts +0 -189
- package/src/execution/engine/common/session-view-projection.ts +0 -51
- package/src/execution/engine/engines/pi/__tests__/pi-engine.test.ts +0 -615
- package/src/execution/engine/engines/pi/__tests__/reader.test.ts +0 -155
- package/src/execution/engine/engines/pi/__tests__/spawn-opts-direct.test.ts +0 -257
- package/src/execution/engine/engines/pi/argv-mirror.ts +0 -135
- package/src/execution/engine/engines/pi/get-state-handshake.ts +0 -179
- package/src/execution/engine/engines/pi/output-collector.ts +0 -317
- package/src/execution/engine/engines/pi/pi-engine.ts +0 -811
- package/src/execution/engine/engines/pi/pi-invocation.ts +0 -120
- package/src/execution/engine/engines/pi/reader.ts +0 -59
- package/src/execution/engine/engines/pi/registration.ts +0 -37
- package/src/execution/engine/engines/pi/session-runner.ts +0 -2840
- package/src/execution/engine/engines/pi/spawn-event-adapter.ts +0 -404
- package/src/execution/engine/engines/pi/stdin-writer.ts +0 -199
- package/src/execution/engine/engines/pi/temp-prompt.ts +0 -62
- package/src/execution/engine/engines/pi/turn-limiter.ts +0 -102
- package/src/execution/engine/engines/zcode/__tests__/__fixtures__/fake-appserver.mjs +0 -301
- package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-appserver.json +0 -36
- package/src/execution/engine/engines/zcode/__tests__/appserver-launcher.test.ts +0 -321
- package/src/execution/engine/engines/zcode/__tests__/connection.test.ts +0 -473
- package/src/execution/engine/engines/zcode/__tests__/parser.test.ts +0 -43
- package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +0 -124
- package/src/execution/engine/engines/zcode/__tests__/reader.test.ts +0 -210
- package/src/execution/engine/engines/zcode/__tests__/registration.test.ts +0 -71
- package/src/execution/engine/engines/zcode/__tests__/session-channel-dispose-harvest.test.ts +0 -247
- package/src/execution/engine/engines/zcode/__tests__/session-channel-turn-timers.test.ts +0 -451
- package/src/execution/engine/engines/zcode/__tests__/session-channel.test.ts +0 -792
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-appserver.test.ts +0 -782
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-degrade.test.ts +0 -168
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-dispose.test.ts +0 -210
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-retry.test.ts +0 -353
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-status.test.ts +0 -282
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-timeout.test.ts +0 -372
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +0 -145
- package/src/execution/engine/engines/zcode/appserver-launcher.ts +0 -167
- package/src/execution/engine/engines/zcode/connection.ts +0 -598
- package/src/execution/engine/engines/zcode/constants.ts +0 -176
- package/src/execution/engine/engines/zcode/golden-sample.ts +0 -47
- package/src/execution/engine/engines/zcode/parser.ts +0 -102
- package/src/execution/engine/engines/zcode/preparer.ts +0 -235
- package/src/execution/engine/engines/zcode/reader.ts +0 -381
- package/src/execution/engine/engines/zcode/registration.ts +0 -37
- package/src/execution/engine/engines/zcode/session-channel.ts +0 -968
- package/src/execution/engine/engines/zcode/zcode-engine.ts +0 -1431
- package/src/execution/round-settlement.ts +0 -93
- package/src/execution/ui-request-queue.ts +0 -215
- package/src/shared/schema-env.ts +0 -44
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
// src/execution/engine/client/reverse-router.ts
|
|
2
|
+
//
|
|
3
|
+
// 反向请求(帧④)路由器(EngineClient 的内部模块,从 engine-client.ts 拆出——
|
|
4
|
+
// max-lines 纪律 + 职责域独立:超时域二分(R9-2/R9-2b)的全部 core 侧语义都
|
|
5
|
+
// 落在本文件)。
|
|
6
|
+
//
|
|
7
|
+
// 超时域划分(impl-plan §2.2 / 设计 §3.3 帧④注释):
|
|
8
|
+
// - 快答数据面(host/log / host/streamDelta / host/poolResolved / host/handleReady /
|
|
9
|
+
// host/childSpawned / host/childStateChanged):分发 + 回 {ok:true},10s 应答守卫
|
|
10
|
+
// ——10s 未答 = 引擎故障 → 杀进程 + 在途 run 失败(REVERSE_REQUEST_TIMEOUT_MS);
|
|
11
|
+
// - 人机交互面(host/askUser / host/permission):ack 两阶段——收即回 {ack:true},
|
|
12
|
+
// handler 结果异步补帧②,**不计时**(R9-2:已 ack 的等待不参与任何 in-flight
|
|
13
|
+
// 超时,ADR-0047 静默 ≠ 卡死);未注入 handler → {unsupported:true};
|
|
14
|
+
// - 未知 host/* 通道 → {unsupported:true}(引擎自行降级,不重试)。
|
|
15
|
+
|
|
16
|
+
import {
|
|
17
|
+
getLogger,
|
|
18
|
+
REVERSE_CHANNEL_TIMEOUT_CLASS,
|
|
19
|
+
REVERSE_REQUEST_TIMEOUT_MS,
|
|
20
|
+
type HostAskUserParams,
|
|
21
|
+
type HostChildSpawnedParams,
|
|
22
|
+
type HostChildStateChangedParams,
|
|
23
|
+
type HostHandleReadyParams,
|
|
24
|
+
type HostLogParams,
|
|
25
|
+
type HostPermissionParams,
|
|
26
|
+
type HostPoolResolvedParams,
|
|
27
|
+
type HostRoundLifecycleParams,
|
|
28
|
+
type HostStreamDeltaParams,
|
|
29
|
+
type UiRequest,
|
|
30
|
+
} from "@zhushanwen/subagent-engine-sdk";
|
|
31
|
+
|
|
32
|
+
import type { SpawnedChildrenMirror } from "./mirror.ts";
|
|
33
|
+
import type { RunRoute } from "./engine-client.ts";
|
|
34
|
+
|
|
35
|
+
const logger = getLogger("subagents");
|
|
36
|
+
|
|
37
|
+
/** 路由器依赖面(EngineClient 注入;全部单向引用,无回环持有)。 */
|
|
38
|
+
export interface ReverseRouterDeps {
|
|
39
|
+
engineId: string;
|
|
40
|
+
/** host/askUser 应答端([D4-④] subagent-service init.uiRequestHandler 注入点)。 */
|
|
41
|
+
uiRequestHandler?: (req: UiRequest) => Promise<unknown>;
|
|
42
|
+
/** host/permission 应答端(v1 骨架注入点)。 */
|
|
43
|
+
permissionHandler?: (params: HostPermissionParams) => Promise<unknown>;
|
|
44
|
+
/** host/log 落宿主日志(缺省 SDK logger facade)。 */
|
|
45
|
+
log?: (params: HostLogParams) => void;
|
|
46
|
+
/** run 作用域通知路由表(EngineClient 持有,EngineClient 生命周期内同一引用)。 */
|
|
47
|
+
runRoutes: Map<string, RunRoute>;
|
|
48
|
+
/** [W3 v1.x] chat 轮次路由表(recordId 键;EngineClient 持有,同上)。 */
|
|
49
|
+
recordRoutes: Map<string, RunRoute>;
|
|
50
|
+
/** childSpawned/childStateChanged 的镜像落点。 */
|
|
51
|
+
mirror: SpawnedChildrenMirror;
|
|
52
|
+
/** handleReady 的 partial handle 回填(崩溃合成 handle 数据源)。 */
|
|
53
|
+
setPartialHandle: (partial: { sessionRef: Record<string, string>; poolKey: string }) => void;
|
|
54
|
+
/** 帧②应答出口。 */
|
|
55
|
+
sendResponse: (id: string, result: unknown) => boolean;
|
|
56
|
+
/** 引擎故障拉起杀链(killAll)。 */
|
|
57
|
+
failEngine: (reason: string) => Promise<void>;
|
|
58
|
+
/** 客户端是否已停机(停机后不再写帧)。 */
|
|
59
|
+
isDisposed: () => boolean;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** 帧④入口(EngineClient.handleLine 委托)。 */
|
|
63
|
+
export function routeReverseRequest(deps: ReverseRouterDeps, frame: { id: string; method: string; params: unknown }): void {
|
|
64
|
+
if (frame.method === "host/askUser") {
|
|
65
|
+
handleInteractionRequest(deps, frame, deps.uiRequestHandler, (params) => (params as HostAskUserParams).request as UiRequest);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (frame.method === "host/permission") {
|
|
69
|
+
handleInteractionRequest(deps, frame, deps.permissionHandler, (params) => params as HostPermissionParams);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const timeoutClass = (REVERSE_CHANNEL_TIMEOUT_CLASS as Record<string, string | undefined>)[frame.method];
|
|
73
|
+
if (timeoutClass === "data-plane") {
|
|
74
|
+
handleDataPlaneRequest(deps, frame);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
deps.sendResponse(frame.id, { unsupported: true });
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* 人机交互面 ack 两阶段(R9-2):先回 {ack:true},handler 结果异步补帧②。
|
|
82
|
+
* **不计时**——已 ack 的等待属人机交互异步等待,不参与任何 in-flight 超时;
|
|
83
|
+
* handler 永不 resolve(用户不答)也不判引擎故障。handler 抛错兜底
|
|
84
|
+
* {cancelled:true}(dialog-queue 应答链同款语义)。
|
|
85
|
+
*/
|
|
86
|
+
function handleInteractionRequest<P>(
|
|
87
|
+
deps: ReverseRouterDeps,
|
|
88
|
+
frame: { id: string; method: string; params: unknown },
|
|
89
|
+
handler: ((input: P) => Promise<unknown>) | undefined,
|
|
90
|
+
extract: (params: unknown) => P,
|
|
91
|
+
): void {
|
|
92
|
+
if (handler === undefined) {
|
|
93
|
+
deps.sendResponse(frame.id, { unsupported: true });
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
deps.sendResponse(frame.id, { ack: true });
|
|
97
|
+
let input: P;
|
|
98
|
+
try {
|
|
99
|
+
input = extract(frame.params);
|
|
100
|
+
} catch {
|
|
101
|
+
deps.sendResponse(frame.id, { cancelled: true });
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
void (async () => {
|
|
105
|
+
try {
|
|
106
|
+
const result = await handler(input);
|
|
107
|
+
if (!deps.isDisposed()) deps.sendResponse(frame.id, result);
|
|
108
|
+
} catch (err) {
|
|
109
|
+
logger.warn(
|
|
110
|
+
`[engine-client:${deps.engineId}] ${frame.method} handler failed, answering cancelled: ${
|
|
111
|
+
err instanceof Error ? err.message : String(err)
|
|
112
|
+
}`,
|
|
113
|
+
);
|
|
114
|
+
if (!deps.isDisposed()) deps.sendResponse(frame.id, { cancelled: true });
|
|
115
|
+
}
|
|
116
|
+
})();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* 快答数据面(R9-2 二分):分发 + 回 {ok:true},全程受 10s 应答守卫——10s 未答 =
|
|
121
|
+
* 引擎故障 → 杀进程 + 在途 run 失败。当前各通道分发都是快操作;守卫覆盖的是
|
|
122
|
+
* 「handler 返回的 promise 挂住」的演化面(挂起 = 宿主消费方死锁,须 fail-fast
|
|
123
|
+
* 拉起杀链,防止 core 被单通道拖死)。分发抛错不判引擎故障(宿主回调 bug 不该
|
|
124
|
+
* 杀引擎),仍回 {ok:true} + warn 留痕。
|
|
125
|
+
*/
|
|
126
|
+
function handleDataPlaneRequest(deps: ReverseRouterDeps, frame: { id: string; method: string; params: unknown }): void {
|
|
127
|
+
let settled = false;
|
|
128
|
+
const guardTimer = setTimeout(() => {
|
|
129
|
+
if (settled) return;
|
|
130
|
+
logger.error(
|
|
131
|
+
`[engine-client:${deps.engineId}] data-plane reverse request ${frame.method} `
|
|
132
|
+
+ `unanswered for ${REVERSE_REQUEST_TIMEOUT_MS}ms — treating as engine fault`,
|
|
133
|
+
);
|
|
134
|
+
void deps.failEngine(
|
|
135
|
+
`data-plane reverse request ${frame.method} unanswered for ${REVERSE_REQUEST_TIMEOUT_MS}ms (engine fault)`,
|
|
136
|
+
);
|
|
137
|
+
}, REVERSE_REQUEST_TIMEOUT_MS);
|
|
138
|
+
void Promise.resolve()
|
|
139
|
+
.then(() => dispatchDataPlane(deps, frame.method, frame.params))
|
|
140
|
+
.then(
|
|
141
|
+
() => {
|
|
142
|
+
settled = true;
|
|
143
|
+
clearTimeout(guardTimer);
|
|
144
|
+
deps.sendResponse(frame.id, { ok: true });
|
|
145
|
+
},
|
|
146
|
+
(err: unknown) => {
|
|
147
|
+
settled = true;
|
|
148
|
+
clearTimeout(guardTimer);
|
|
149
|
+
logger.warn(
|
|
150
|
+
`[engine-client:${deps.engineId}] ${frame.method} dispatch failed (answering ok, host-side bug): ${
|
|
151
|
+
err instanceof Error ? err.message : String(err)
|
|
152
|
+
}`,
|
|
153
|
+
);
|
|
154
|
+
deps.sendResponse(frame.id, { ok: true });
|
|
155
|
+
},
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/** 数据面单通道分发器(params 形态自证——发帧前引擎侧自检,分发层只做强转)。 */
|
|
160
|
+
type DataPlaneHandler = (deps: ReverseRouterDeps, params: unknown) => Promise<void> | void;
|
|
161
|
+
|
|
162
|
+
/** method → 分发器表(表外 method = 无操作;路由面准入已由 REVERSE_CHANNEL_TIMEOUT_CLASS 收敛为 data-plane)。 */
|
|
163
|
+
const DATA_PLANE_HANDLERS: Record<string, DataPlaneHandler> = {
|
|
164
|
+
"host/log": (deps, params) => dispatchLog(deps, params as HostLogParams),
|
|
165
|
+
"host/streamDelta": (deps, params) => dispatchStreamDelta(deps, params as HostStreamDeltaParams),
|
|
166
|
+
"host/roundLifecycle": (deps, params) => dispatchRoundLifecycle(deps, params as HostRoundLifecycleParams),
|
|
167
|
+
"host/poolResolved": (deps, params) => dispatchPoolResolved(deps, params as HostPoolResolvedParams),
|
|
168
|
+
"host/handleReady": (deps, params) => dispatchHandleReady(deps, params as HostHandleReadyParams),
|
|
169
|
+
"host/childSpawned": (deps, params) => dispatchChildSpawned(deps, params as HostChildSpawnedParams),
|
|
170
|
+
"host/childStateChanged": (deps, params) => dispatchChildStateChanged(deps, params as HostChildStateChangedParams),
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
async function dispatchDataPlane(deps: ReverseRouterDeps, method: string, params: unknown): Promise<void> {
|
|
174
|
+
await DATA_PLANE_HANDLERS[method]?.(deps, params);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function dispatchLog(deps: ReverseRouterDeps, p: HostLogParams): void {
|
|
178
|
+
if (deps.log !== undefined) deps.log(p);
|
|
179
|
+
else logger[p.level](`[engine:${p.component}] ${p.message}`, p.data);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
async function dispatchStreamDelta(deps: ReverseRouterDeps, p: HostStreamDeltaParams): Promise<void> {
|
|
183
|
+
// [W3 v1.x 接线(W1 偏差 #1 的替换落地)] 关联键分路(D1-A):
|
|
184
|
+
// - recordId 键 = chat 续聊轮 delta(interact 发起,无独立 runId)→ recordRoutes;
|
|
185
|
+
// - runId 键 = run 域轮(含 run 会话形态首轮)→ runRoutes(v1 现状不变)。
|
|
186
|
+
// 无注册路由 = 该轮宿主消费面未挂(诊断形态)——静默丢弃(数据面已 ack,
|
|
187
|
+
// 引擎侧不重发;路由缺席非引擎故障)。
|
|
188
|
+
if (p.recordId !== undefined) {
|
|
189
|
+
await deps.recordRoutes.get(p.recordId)?.onStreamDelta?.(p.delta);
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
await deps.runRoutes.get(p.runId)?.onStreamDelta?.(p.delta);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
async function dispatchRoundLifecycle(deps: ReverseRouterDeps, p: HostRoundLifecycleParams): Promise<void> {
|
|
196
|
+
// [W3 v1.x] 第 9 反向通道消费(settled/idle/failed 三相位 × runId|recordId 键)。
|
|
197
|
+
// 相位语义(arm/disarm/交棒/失败分诊)归宿主编排层——本路由只做键分发,
|
|
198
|
+
// 消费方 = RunContext.onRoundLifecycle(首轮 runId 键)与 registerChatRoundRoute
|
|
199
|
+
// 路由(续聊轮 recordId 键)。载荷形状自证(isHostRoundLifecycleParams)归
|
|
200
|
+
// 引擎侧发帧前自检 + 消费方,分发层不重复判别(与 streamDelta 一致的薄分发)。
|
|
201
|
+
if (p.recordId !== undefined) {
|
|
202
|
+
await deps.recordRoutes.get(p.recordId)?.onRoundLifecycle?.(p);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
await deps.runRoutes.get(p.runId)?.onRoundLifecycle?.(p);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
async function dispatchPoolResolved(deps: ReverseRouterDeps, p: HostPoolResolvedParams): Promise<void> {
|
|
209
|
+
await deps.runRoutes.get(p.runId)?.onPoolResolved?.(p.poolKey);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
async function dispatchHandleReady(deps: ReverseRouterDeps, p: HostHandleReadyParams): Promise<void> {
|
|
213
|
+
deps.setPartialHandle({ sessionRef: p.sessionRef, poolKey: p.poolKey });
|
|
214
|
+
await deps.runRoutes.get(p.runId)?.onHandleReady?.({
|
|
215
|
+
sessionRef: p.sessionRef,
|
|
216
|
+
poolKey: p.poolKey,
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function dispatchChildSpawned(deps: ReverseRouterDeps, p: HostChildSpawnedParams): void {
|
|
221
|
+
deps.mirror.recordSpawned(p.pid, p.recordId);
|
|
222
|
+
// POSIX 运行时组探测(W10 / A3 前提②):任务子进程应与引擎同组(收割 =
|
|
223
|
+
// 引擎进程组级 kill(-enginePid))。kill(-pid, 0) 成功 ⟺ 该 pid 自成进程组
|
|
224
|
+
// (setsid/detached 后代)⟺ 不在引擎收割组内 → 告警留痕(不判 fail——
|
|
225
|
+
// detached 后代是设计 §3.9 已接受代价)。Windows 无外部判据(无 kill(-pid,0)
|
|
226
|
+
// 等价物),仅 SDK 层 spawnEngineChild 形态保证,真机面挂 A3 手动门。
|
|
227
|
+
if (process.platform !== "win32" && typeof p.pid === "number") {
|
|
228
|
+
try {
|
|
229
|
+
process.kill(-p.pid, 0);
|
|
230
|
+
logger.warn(
|
|
231
|
+
`[engine-client:${deps.engineId}] childSpawned pid ${p.pid} leads its own process group `
|
|
232
|
+
+ `(not in the engine harvest group — one-generation children + in-group descendants `
|
|
233
|
+
+ `only; engine-detached descendants are an accepted cost per design §3.9)`,
|
|
234
|
+
);
|
|
235
|
+
} catch (err) {
|
|
236
|
+
// ESRCH = pid 非组长 = 在引擎组内(预期形态);其余 errno 同按预期形态
|
|
237
|
+
// debug 留痕(组探测异常排查时的最低可见性,不判 fail)。
|
|
238
|
+
logger.debug(
|
|
239
|
+
`[engine-client:${deps.engineId}] childSpawned pid ${p.pid} group probe settled ` +
|
|
240
|
+
`(${err instanceof Error ? err.message : String(err)})`,
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function dispatchChildStateChanged(deps: ReverseRouterDeps, p: HostChildStateChangedParams): void {
|
|
247
|
+
deps.mirror.recordStateChanged({
|
|
248
|
+
pid: p.pid,
|
|
249
|
+
recordId: p.recordId,
|
|
250
|
+
state: p.state,
|
|
251
|
+
killed: p.killed,
|
|
252
|
+
exitCode: p.exitCode,
|
|
253
|
+
signal: p.signal,
|
|
254
|
+
});
|
|
255
|
+
}
|
|
@@ -1,26 +1,49 @@
|
|
|
1
1
|
// src/execution/engine/common/capability-gate.ts
|
|
2
2
|
//
|
|
3
3
|
// [D3-④ 预检 capabilities 化] 调用前预检的唯一实现(capabilities 驱动,无引擎 id
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
4
|
+
// 特判)。设计权威源(现行):docs/design/subagent-engine-protocolization.md §3.3
|
|
5
|
+
// 「能力位」段(manifest 权威 + 方向判定表)+ 历史源 docs/design/subagent-dual-track-
|
|
6
|
+
// convergence.md §3.3 D3-④ + r3 裁定(EngineCapabilities 新增 maxTurns 能力位)+
|
|
7
|
+
// 错误规格(engine_capability_unsupported / engine_capability_mismatch)。
|
|
7
8
|
//
|
|
8
9
|
// 判据形态:每个引擎拦截「自己 capabilities 声明不支持的能力」——
|
|
9
10
|
// - conversation → capabilities.conversation === 'unsupported'
|
|
10
11
|
// - fork/forkFromSessionFile → session 分叉通道族全缺(steer 与 conversation 均
|
|
11
|
-
// 'unsupported'
|
|
12
|
+
// 'unsupported',OR 语义任一可用即放行,见下方 fork 判据说明)
|
|
12
13
|
// - maxTurns → capabilities.maxTurns === false(r3 扩位)
|
|
13
14
|
// - worktree(boolean true 或 WorktreeHandle)→ capabilities.sandbox === 'none'
|
|
14
15
|
//
|
|
16
|
+
// [W3 协议化能力位方向判定(设计 §3.3 能力位表)] capabilities 的同步源 = manifest
|
|
17
|
+
// 快照(注册期读,非握手缓存)。被 gate 四类判据涉及的能力位(conversation /
|
|
18
|
+
// steer+conversation / maxTurns / sandbox)**manifest 是权威契约**,双向处置:
|
|
19
|
+
// - **少声明**(任务要求的能力 manifest 未声明)→ 本文件同步拒
|
|
20
|
+
// engine_capability_unsupported;恢复指引 = 「修 manifest / 升级引擎包」——不写
|
|
21
|
+
// 「先派一次任务触发握手」(gate 读 manifest,握手不参与同步判据,那个指引是空转);
|
|
22
|
+
// - **多声明**(manifest 声明支持而引擎实际不支持)→ gate 读不到(同步面只有
|
|
23
|
+
// manifest),由首个 run 的协议握手 `initialize` 发现 → engine_capability_mismatch
|
|
24
|
+
// 该 run 失败 + record 标 failed + **清理 run 前已建的前置副作用**(worktree:
|
|
25
|
+
// executeViaEngine 在 kickOffEngineRun 前创建,经 finalizeFailed → finalizeRecord
|
|
26
|
+
// Step 3b cleanupWorktreeIfBound 清理)。判定函数 = 本文件
|
|
27
|
+
// assertGateCapabilitiesMatched(core 侧判据;协议客户端握手尾接线归 client/ 领地)。
|
|
28
|
+
// - **非 gate 位**(personaInjection / eventGranularity / sessionRead / resume /
|
|
29
|
+
// interrupt / permissionMode / schemaEnforcement)不一致(无论强弱)→ 一律 warn
|
|
30
|
+
// 留痕不阻断(诊断面 = EngineClient.warnOnManifestDiagnostics)。
|
|
31
|
+
//
|
|
15
32
|
// 调用点仍是两处(单点的是实现,不是调用点):
|
|
16
33
|
// - chat 域:executeViaEngine 同步段、record 创建前(engine.capabilities() 同步可得,
|
|
17
34
|
// 承接「全部同步拒绝发生在 record 创建前、不产生孤儿 record」不变量);
|
|
18
35
|
// - workflow 域:SAR.run 路由后、engine.run 前(同模块调用)。
|
|
19
36
|
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
//
|
|
37
|
+
// 行为变化声明:唯一有意行为变化 = workflow 域 zcode+worktree 由漏拦变拦截(修复
|
|
38
|
+
// 双轨清单 #7 的跨域缺口);pi 的 maxTurns/fork/conversation/worktree 等既有合法
|
|
39
|
+
// 能力零拦截(V4⑤ 反向守护)。[W3] recovery 文案随协议化变更:恢复指引主指向
|
|
40
|
+
// 「修 manifest / 升级引擎包」(引擎包是能力声明的载体,换引擎不再是缺省指引——
|
|
41
|
+
// 协议化后不存在「内置 pi 恒可用」兜底)。
|
|
42
|
+
|
|
43
|
+
// [W3 v1.x] conversation gate 判据单源 = SDK 具名构造器(W1 交接防漂移项:core 内联
|
|
44
|
+
// 文案与引擎侧 assertChatConversationSupported 双份文案的漂移面消除——同一构造器
|
|
45
|
+
// 两侧消费,错误码/恢复指引契约单一权威)。
|
|
46
|
+
import { engineConversationUnsupportedError } from "@zhushanwen/subagent-engine-sdk";
|
|
24
47
|
|
|
25
48
|
import { EngineError } from "./errors.ts";
|
|
26
49
|
import type { EngineCapabilities } from "../types.ts";
|
|
@@ -38,17 +61,20 @@ export interface TaskShapeForGate {
|
|
|
38
61
|
maxTurns?: number;
|
|
39
62
|
}
|
|
40
63
|
|
|
64
|
+
/** 恢复指引公共尾段(W3 协议化口径:能力声明的修复通道 = manifest / 引擎包升级)。 */
|
|
65
|
+
const MANIFEST_RECOVERY_TAIL = "修 manifest capabilities / 升级引擎包(若引擎实际支持该能力)";
|
|
66
|
+
|
|
41
67
|
/**
|
|
42
68
|
* 调用前预检:任务形状中的能力参数对引擎 capabilities 逐一对照,声明不支持即抛
|
|
43
69
|
* EngineError(engine_capability_unsupported)——同步 throw、进程/record 创建前,文案
|
|
44
|
-
* 含 capabilities
|
|
70
|
+
* 含 capabilities 依据与恢复指引(修 manifest / 升级引擎包 / 调整任务参数)。
|
|
45
71
|
*
|
|
46
72
|
* fork 判据说明(借位裁定):fork 依赖父 session 上下文继承(父会话文件作为分叉源),
|
|
47
73
|
* 引擎具备该语义的能力面信号 = 会话分叉/交互通道族(steer 或 conversation 任一非
|
|
48
|
-
* 'unsupported'
|
|
49
|
-
* 'unsupported'(argv-only spawn 单轮,无父 session
|
|
50
|
-
*
|
|
51
|
-
*
|
|
74
|
+
* 'unsupported',**OR 语义任一可用即放行**)。pi conversation='native'(chatMode idle
|
|
75
|
+
* 复用)→ 放行;zcode 双 'unsupported'(argv-only spawn 单轮,无父 session 分叉通道)
|
|
76
|
+
* → 拒绝。仅凭 steer 判会误拦 pi(pi 的 steer 声明 'unsupported'——RPC 有但 spawn
|
|
77
|
+
* 链路未接通,与 fork 的初始上下文继承是两条轴),故取通道族任一可用即支持的分寸。
|
|
52
78
|
*/
|
|
53
79
|
export function assertTaskShapeSupported(
|
|
54
80
|
engineId: string,
|
|
@@ -56,12 +82,11 @@ export function assertTaskShapeSupported(
|
|
|
56
82
|
task: TaskShapeForGate,
|
|
57
83
|
): void {
|
|
58
84
|
if (task.conversation === true && caps.conversation === "unsupported") {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
);
|
|
85
|
+
// [W1 交接防漂移项落地] 文案/错误码/恢复指引单源 = SDK engineConversationUnsupportedError
|
|
86
|
+
// (引擎侧 server.run chat gate 消费同一构造器——A6 双向负向面两侧同文案)。
|
|
87
|
+
// 错误载体类型 EngineError → EngineSdkError(code/recovery/message 前缀契约不变,
|
|
88
|
+
// name 变化不影响消费方——无 instanceof EngineError 判据,code 字段分流)。
|
|
89
|
+
throw engineConversationUnsupportedError(engineId);
|
|
65
90
|
}
|
|
66
91
|
if (task.fork === true || task.forkFromSessionFile !== undefined) {
|
|
67
92
|
if (caps.steer === "unsupported" && caps.conversation === "unsupported") {
|
|
@@ -69,7 +94,7 @@ export function assertTaskShapeSupported(
|
|
|
69
94
|
"engine_capability_unsupported",
|
|
70
95
|
`engine '${engineId}' 不支持 fork${task.forkFromSessionFile !== undefined ? "(fork-from 同为父 session 上下文继承)" : ""}(fork 依赖父 session 上下文继承,` +
|
|
71
96
|
`capabilities.steer = '${caps.steer}' / conversation = '${caps.conversation}'——引擎无父 session 分叉通道)`,
|
|
72
|
-
`把所需父上下文写进 task 正文后不传 fork
|
|
97
|
+
`把所需父上下文写进 task 正文后不传 fork,或 ${MANIFEST_RECOVERY_TAIL}`,
|
|
73
98
|
);
|
|
74
99
|
}
|
|
75
100
|
}
|
|
@@ -78,7 +103,7 @@ export function assertTaskShapeSupported(
|
|
|
78
103
|
"engine_capability_unsupported",
|
|
79
104
|
`engine '${engineId}' 不支持 maxTurns(capabilities.maxTurns = false,轮数上限依赖 turn_end 事件流,` +
|
|
80
105
|
`本引擎无此语义——静默丢弃会造成「传了上限却失控」的假象)`,
|
|
81
|
-
`去掉 maxTurns
|
|
106
|
+
`去掉 maxTurns 参数重派,或 ${MANIFEST_RECOVERY_TAIL}`,
|
|
82
107
|
);
|
|
83
108
|
}
|
|
84
109
|
if ((task.worktree === true || typeof task.worktree === "object") && caps.sandbox === "none") {
|
|
@@ -86,7 +111,69 @@ export function assertTaskShapeSupported(
|
|
|
86
111
|
"engine_capability_unsupported",
|
|
87
112
|
`engine '${engineId}' 不支持 worktree 隔离(capabilities.sandbox = 'none',` +
|
|
88
113
|
`引擎未接文件系统隔离层)`,
|
|
89
|
-
|
|
114
|
+
`去掉 worktree 参数(在 parent cwd 执行),或 ${MANIFEST_RECOVERY_TAIL}`,
|
|
90
115
|
);
|
|
91
116
|
}
|
|
92
117
|
}
|
|
118
|
+
|
|
119
|
+
// ============================================================
|
|
120
|
+
// 能力位方向判定②:manifest 多声明 → run 期握手发现(engine_capability_mismatch)
|
|
121
|
+
// ============================================================
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* manifest vs `initialize` 应答的 gate 位方向判定(设计 §3.3 能力位表「多声明」行)。
|
|
125
|
+
*
|
|
126
|
+
* 只判被 gate 四类判据涉及的能力位中「manifest 声明可用、引擎应答不支持」的多声明
|
|
127
|
+
* 方向(少声明方向在派发前已被 assertTaskShapeSupported 同步拦,握手不会发生——gate
|
|
128
|
+
* 先行的结构性结果);命中抛 EngineError(engine_capability_mismatch),由首个 run 的
|
|
129
|
+
* 协议路径转化为该 run 失败 + record 标 failed + 清理前置副作用(契约变更⑤)。
|
|
130
|
+
* 非 gate 位不一致不进本判定(无论强弱一律 warn 留痕,归 EngineClient 诊断面)。
|
|
131
|
+
*
|
|
132
|
+
* 各 gate 位的「manifest 可用」取值语义与 assertTaskShapeSupported 逐条对偶:
|
|
133
|
+
* conversation 应答 'unsupported' 而 manifest 非 'unsupported' → mismatch;
|
|
134
|
+
* fork 通道族应答双 'unsupported' 而 manifest 任一可用 → mismatch(OR 对偶);
|
|
135
|
+
* maxTurns 应答 false 而 manifest true → mismatch;
|
|
136
|
+
* sandbox 应答 'none' 而 manifest 非 'none' → mismatch。
|
|
137
|
+
*
|
|
138
|
+
* 接线位置(领地边界声明):本函数是 core 侧判据单源;协议客户端在首个 run 前握手
|
|
139
|
+
* 后(EngineClient.initialize 应答 → RemoteEngine.run 发 run 帧前)调用——client/ 为
|
|
140
|
+
* W2 已交付领地,接线归后续单元(W8/W10),不属本文件。
|
|
141
|
+
*/
|
|
142
|
+
export function assertGateCapabilitiesMatched(
|
|
143
|
+
engineId: string,
|
|
144
|
+
manifestCaps: EngineCapabilities,
|
|
145
|
+
answeredCaps: EngineCapabilities,
|
|
146
|
+
): void {
|
|
147
|
+
if (
|
|
148
|
+
manifestCaps.conversation !== "unsupported" &&
|
|
149
|
+
answeredCaps.conversation === "unsupported"
|
|
150
|
+
) {
|
|
151
|
+
throw gateMismatchError(engineId, "conversation", manifestCaps.conversation, answeredCaps.conversation);
|
|
152
|
+
}
|
|
153
|
+
const manifestForkCapable = manifestCaps.steer !== "unsupported" || manifestCaps.conversation !== "unsupported";
|
|
154
|
+
const answeredForkCapable = answeredCaps.steer !== "unsupported" || answeredCaps.conversation !== "unsupported";
|
|
155
|
+
if (manifestForkCapable && !answeredForkCapable) {
|
|
156
|
+
throw gateMismatchError(
|
|
157
|
+
engineId,
|
|
158
|
+
"fork(steer/conversation 通道族)",
|
|
159
|
+
`steer=${manifestCaps.steer}/conversation=${manifestCaps.conversation}`,
|
|
160
|
+
`steer=${answeredCaps.steer}/conversation=${answeredCaps.conversation}`,
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
if (manifestCaps.maxTurns === true && answeredCaps.maxTurns === false) {
|
|
164
|
+
throw gateMismatchError(engineId, "maxTurns", String(manifestCaps.maxTurns), String(answeredCaps.maxTurns));
|
|
165
|
+
}
|
|
166
|
+
if (manifestCaps.sandbox !== "none" && answeredCaps.sandbox === "none") {
|
|
167
|
+
throw gateMismatchError(engineId, "sandbox(worktree)", manifestCaps.sandbox, answeredCaps.sandbox);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/** engine_capability_mismatch 的统一构造(manifest 权威 + 恢复指引 = 修 manifest / 升级引擎包)。 */
|
|
172
|
+
function gateMismatchError(engineId: string, cap: string, declared: string, answered: string): EngineError {
|
|
173
|
+
return new EngineError(
|
|
174
|
+
"engine_capability_mismatch",
|
|
175
|
+
`engine '${engineId}' manifest 声明的能力位 '${cap}'(${declared})与引擎 initialize 应答不符(${answered})` +
|
|
176
|
+
`——manifest 多声明,任务按 gate 判据放行后引擎无法兑现`,
|
|
177
|
+
`修 manifest capabilities(与引擎实际能力对齐)或升级引擎包;若任务不再需要该能力,调整任务参数后重派`,
|
|
178
|
+
);
|
|
179
|
+
}
|
|
@@ -25,6 +25,7 @@ export const ENGINE_ERROR_CODES = [
|
|
|
25
25
|
"schema_emulation_failed",
|
|
26
26
|
"engine_timeout",
|
|
27
27
|
"engine_capability_unsupported",
|
|
28
|
+
"engine_capability_mismatch",
|
|
28
29
|
"engine_session_not_resumable",
|
|
29
30
|
"model_not_available",
|
|
30
31
|
"prompt_too_large",
|
|
@@ -94,8 +95,11 @@ export const DEFAULT_RECOVERY_HINTS: Record<EngineErrorCode, string> = {
|
|
|
94
95
|
"The engine was killed by the host timeout chain. Inspect the captured stdout tail, then re-run with a larger " +
|
|
95
96
|
"timeout, a narrower task, or `engine: pi`.",
|
|
96
97
|
engine_capability_unsupported:
|
|
97
|
-
"This engine declares the capability unsupported.
|
|
98
|
-
"or
|
|
98
|
+
"This engine declares the capability unsupported. Adjust the task parameters, " +
|
|
99
|
+
"or fix the manifest capabilities / upgrade the engine package if it actually supports it.",
|
|
100
|
+
engine_capability_mismatch:
|
|
101
|
+
"The engine manifest declares a capability its initialize handshake did not confirm. " +
|
|
102
|
+
"Fix the manifest capabilities (align with actual engine behavior) or upgrade the engine package.",
|
|
99
103
|
engine_session_not_resumable:
|
|
100
104
|
"Idle-process reuse does not survive a main-session reload. Use a cold resume path " +
|
|
101
105
|
"(engine --resume / --session with the recorded session reference), or start a new subagent.",
|
|
@@ -113,9 +117,6 @@ export const DEFAULT_RECOVERY_HINTS: Record<EngineErrorCode, string> = {
|
|
|
113
117
|
// P2 消费的具名构造器(动态参数进 detail/recovery)
|
|
114
118
|
// ============================================================
|
|
115
119
|
|
|
116
|
-
/** 错误回显长度上限(截断长输出,避免错误消息爆炸——对齐 structured-output echo 上限量级)。 */
|
|
117
|
-
const DETAIL_ECHO_MAX_CHARS = 200;
|
|
118
|
-
|
|
119
120
|
/** truncate(text, max):尾部截断 + 省略号标记(模板共用)。 */
|
|
120
121
|
function truncate(text: string, max: number): string {
|
|
121
122
|
return text.length <= max ? text : `${text.slice(0, max)}...`;
|
|
@@ -133,15 +134,6 @@ export function promptTooLargeError(actualBytes: number, limitBytes: number): En
|
|
|
133
134
|
);
|
|
134
135
|
}
|
|
135
136
|
|
|
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
137
|
/** stdout 尾部回显上限(engine_timeout / engine_run_failed 的错误规格载体系数)。 */
|
|
146
138
|
export const STDOUT_TAIL_ECHO_CHARS = 2000;
|
|
147
139
|
|
|
@@ -170,14 +162,6 @@ export function engineRunFailedDetail(reason: string, exitCode: number | null, s
|
|
|
170
162
|
);
|
|
171
163
|
}
|
|
172
164
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
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
|
-
}
|
|
165
|
+
// schema_emulation_failed 的终报文案(schemaEmulationFailedDetail)已随 schema-emulation
|
|
166
|
+
// 死镜像收口删除:活体单源 SDK error-codes.ts(emulated 引擎的宿主编排层经 SDK 消费),
|
|
167
|
+
// core 侧此前仅剩自身测试引用(test-only)。
|
|
@@ -14,7 +14,6 @@
|
|
|
14
14
|
// warn 一次 + 置 failed,后续 append 丢弃、close 立即返回(不静默:warn 有留痕)。
|
|
15
15
|
|
|
16
16
|
import { appendFile, mkdir, open } from "node:fs/promises";
|
|
17
|
-
import { readFileSync } from "node:fs";
|
|
18
17
|
import { dirname } from "node:path";
|
|
19
18
|
|
|
20
19
|
import { getLogger } from "../../../core/logger.ts";
|
|
@@ -203,52 +202,7 @@ function defaultWarn(msg: string): void {
|
|
|
203
202
|
// 重放
|
|
204
203
|
// ============================================================
|
|
205
204
|
|
|
206
|
-
|
|
207
|
-
|
|
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
|
-
}
|
|
205
|
+
// replayJournal/parseLine 已收编 SDK journal-io(S4 簇 6:zcode 引擎包不能 import
|
|
206
|
+
// core,双包逐字等价副本单源落 SDK;此处 re-export 保 journal-replay.ts /
|
|
207
|
+
// session-view-service.ts 消费路径零改动)。行格式权威仍 §3.3.6,行为逐字等价。
|
|
208
|
+
export { replayJournal } from "@zhushanwen/subagent-engine-sdk";
|
|
@@ -10,9 +10,11 @@
|
|
|
10
10
|
|
|
11
11
|
import { createRecord, updateFromEvent } from "../../execution-record.ts";
|
|
12
12
|
import type { AgentEvent } from "../../types.ts";
|
|
13
|
+
// aggregateUsage / toReplayedTurn 单源 SDK(自 session-view-projection.ts 逐字等价
|
|
14
|
+
// 迁入后收口——双活副本删除,live ≡ replay 的投影语义不再靠双份手工同步)。
|
|
15
|
+
import { aggregateUsage, toReplayedTurn } from "@zhushanwen/subagent-engine-sdk";
|
|
13
16
|
import type { EngineHandle, SessionView } from "../types.ts";
|
|
14
17
|
import { replayJournal } from "./event-journal.ts";
|
|
15
|
-
import { aggregateUsage, toReplayedTurn } from "./session-view-projection.ts";
|
|
16
18
|
|
|
17
19
|
/**
|
|
18
20
|
* journal → SessionView(read 第②级)。
|