@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
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
// src/execution/engine/engines/pi/get-state-handshake.ts
|
|
2
|
-
//
|
|
3
|
-
// FR-4: get_state RPC 握手逻辑。
|
|
4
|
-
//
|
|
5
|
-
// 从 session-runner.ts 提取(保持文件 < 1000 行)。职责单一:通过 get_state RPC
|
|
6
|
-
// 查询子进程 sessionFile/sessionId,带超时重试。session-runner spawn 后无条件调用。
|
|
7
|
-
//
|
|
8
|
-
// 设计要点:
|
|
9
|
-
// - 重试节奏:单次超时 GET_STATE_TIMEOUT_MS(2s)后,等 GET_STATE_RETRY_INTERVAL_MS(500ms)
|
|
10
|
-
// 再发起下一次 get_state,最多 GET_STATE_MAX_RETRIES(3)次。修复点:旧实现超时后
|
|
11
|
-
// 立即递归 tryOnce(),GET_STATE_RETRY_INTERVAL_MS 声明了却从未使用(eslint error 阻断),
|
|
12
|
-
// 现在让常量名与行为一致——重试前真的等间隔。
|
|
13
|
-
// - 加速路径:sessionFile 一旦拿到立即 resolve(不等剩余重试)。
|
|
14
|
-
// - 全部超时:resolve 空对象(调用方走兜底查找)。
|
|
15
|
-
|
|
16
|
-
import type { ChildProcess } from "node:child_process";
|
|
17
|
-
|
|
18
|
-
import { sendGetStateCommand } from "./stdin-writer.ts";
|
|
19
|
-
|
|
20
|
-
/** FR-4: get_state RPC 握手最大重试次数。 */
|
|
21
|
-
const GET_STATE_MAX_RETRIES = 3;
|
|
22
|
-
/** FR-4: get_state RPC 握手重试间隔(ms)——单次超时后等待此间隔再重试。 */
|
|
23
|
-
const GET_STATE_RETRY_INTERVAL_MS = 500;
|
|
24
|
-
/** FR-4: get_state RPC 握手单次超时(ms)。 */
|
|
25
|
-
const GET_STATE_TIMEOUT_MS = 2000;
|
|
26
|
-
|
|
27
|
-
/** get_state 握手结果。 */
|
|
28
|
-
export interface GetStateResult {
|
|
29
|
-
sessionFile?: string;
|
|
30
|
-
sessionId?: string;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* get_state response 监听器注册函数形态(stdout pump / 测试注入)。
|
|
35
|
-
*
|
|
36
|
-
* 返回值:注销函数(从监听表移除该 resolver),可省略——performGetStateHandshake
|
|
37
|
-
* 忽略返回值(既有语义:迟到 response 靠 resolved 标志自弃,条目由 close 统一清);
|
|
38
|
-
* requestGetStateOnce 消费返回值做单次请求的自清理(不依赖 close 兜底)。
|
|
39
|
-
*/
|
|
40
|
-
export type AddGetStateResponseListener = (
|
|
41
|
-
id: string,
|
|
42
|
-
resolver: (data: unknown) => void,
|
|
43
|
-
) => void | (() => void);
|
|
44
|
-
|
|
45
|
-
/** 从 get_state response data 提取 sessionFile/sessionId(提取规则单一来源,握手与惰性重试共用)。 */
|
|
46
|
-
function extractGetStateFields(data: unknown, into: GetStateResult): void {
|
|
47
|
-
if (data && typeof data === "object") {
|
|
48
|
-
const d = data as Record<string, unknown>;
|
|
49
|
-
if (typeof d.sessionFile === "string" && d.sessionFile.length > 0) {
|
|
50
|
-
into.sessionFile = d.sessionFile;
|
|
51
|
-
}
|
|
52
|
-
if (typeof d.sessionId === "string" && d.sessionId.length > 0) {
|
|
53
|
-
into.sessionId = d.sessionId;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* FR-4: 通过 get_state RPC 查询子进程获取 sessionFile/sessionId。
|
|
60
|
-
*
|
|
61
|
-
* 当 stdout header 未获取到 sessionFile 时,尝试通过 get_state RPC 查询。
|
|
62
|
-
* 最多重试 GET_STATE_MAX_RETRIES 次,单次超时 GET_STATE_TIMEOUT_MS 后等待
|
|
63
|
-
* GET_STATE_RETRY_INTERVAL_MS 再发起下一次重试。
|
|
64
|
-
*
|
|
65
|
-
* @param child 子进程(stdin 写入 get_state 命令)
|
|
66
|
-
* @param addResponseListener 注册 response 监听器的函数(stdout pump 中调用)
|
|
67
|
-
* @returns 握手结果(可能为空——所有重试均超时/失败)
|
|
68
|
-
*/
|
|
69
|
-
export function performGetStateHandshake(
|
|
70
|
-
child: ChildProcess,
|
|
71
|
-
addResponseListener: AddGetStateResponseListener,
|
|
72
|
-
): Promise<GetStateResult> {
|
|
73
|
-
return new Promise<GetStateResult>((resolve) => {
|
|
74
|
-
const collected: GetStateResult = {};
|
|
75
|
-
let attempts = 0;
|
|
76
|
-
let resolved = false;
|
|
77
|
-
|
|
78
|
-
function tryOnce(): void {
|
|
79
|
-
if (resolved) return;
|
|
80
|
-
attempts++;
|
|
81
|
-
const reqId = sendGetStateCommand(child);
|
|
82
|
-
|
|
83
|
-
// [#15] 本次 tryOnce 私有的 timer(2s 超时 + 超时后派生的 retry)。
|
|
84
|
-
// 关键:response 回调通过闭包引用的是"本次 tryOnce 对应的 timer",而非某个
|
|
85
|
-
// 外层共享变量——即便后续 tryOnce(#2) 重新发起请求,旧 reqId 的迟到 response 回调
|
|
86
|
-
// 闭包仍指向它自己那次 tryOnce 的 timer,不会误清新 reqId 的 timer。retry 句柄也
|
|
87
|
-
// 一并捕获,response 到达时同步取消"已在排队但尚未触发的下一次重试"。
|
|
88
|
-
let pendingRetry: ReturnType<typeof setTimeout> | undefined;
|
|
89
|
-
const timer: ReturnType<typeof setTimeout> = setTimeout(() => {
|
|
90
|
-
pendingRetry = undefined;
|
|
91
|
-
// 单次超时:等待间隔后重试,或放弃
|
|
92
|
-
if (attempts < GET_STATE_MAX_RETRIES && !resolved) {
|
|
93
|
-
// [Bug fix] 旧实现直接 tryOnce() 立即重试,GET_STATE_RETRY_INTERVAL_MS 声明却
|
|
94
|
-
// 从未使用(eslint error 阻断 commit)。现在重试前等待间隔,让常量名与行为一致。
|
|
95
|
-
pendingRetry = setTimeout(() => tryOnce(), GET_STATE_RETRY_INTERVAL_MS);
|
|
96
|
-
pendingRetry.unref();
|
|
97
|
-
} else if (!resolved) {
|
|
98
|
-
resolved = true;
|
|
99
|
-
resolve(collected);
|
|
100
|
-
}
|
|
101
|
-
}, GET_STATE_TIMEOUT_MS);
|
|
102
|
-
timer.unref();
|
|
103
|
-
|
|
104
|
-
addResponseListener(reqId, (data: unknown) => {
|
|
105
|
-
if (resolved) return;
|
|
106
|
-
// [#15] 闭包清理本次 tryOnce 的 timer(2s 超时 + 排队中的 retry),不碰其他 reqId 的 timer。
|
|
107
|
-
clearTimeout(timer);
|
|
108
|
-
if (pendingRetry) clearTimeout(pendingRetry);
|
|
109
|
-
extractGetStateFields(data, collected);
|
|
110
|
-
// sessionFile 已获取——立即 resolve(无需更多重试)
|
|
111
|
-
if (collected.sessionFile) {
|
|
112
|
-
resolved = true;
|
|
113
|
-
resolve(collected);
|
|
114
|
-
}
|
|
115
|
-
// 否则等待超时重试
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
tryOnce();
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* [T1/RC-1] 单次 get_state 请求(agent_end 决策点惰性回补专用)。
|
|
125
|
-
*
|
|
126
|
-
* 与 performGetStateHandshake 的关系:复用同一消息构造(sendGetStateCommand)与同一
|
|
127
|
-
* 字段提取(extractGetStateFields),但**不做重试循环、不 share 握手语义**——调用方
|
|
128
|
-
* (session-runner agent_end 处置)在子进程 idle 时现场补一次查询(探针 P-T1 实证
|
|
129
|
-
* 应答 0.3-0.4ms),超时/失败即放弃,由调用方走既有保守分支(行为不劣化)。
|
|
130
|
-
*
|
|
131
|
-
* 结果契约与 performGetStateHandshake 一致:resolve GetStateResult(可能为空对象),
|
|
132
|
-
* 永不 reject——stdin 已断(EPIPE/ERR_STREAM_DESTROYED)的同步写失败按「回补失败」
|
|
133
|
-
* 处理 resolve 空对象,调用方无需 try/catch。
|
|
134
|
-
*
|
|
135
|
-
* 自清理:超时或 response 到达后从监听表移除本请求的 resolver(消费注册器的返回值),
|
|
136
|
-
* 不留迟到条目;注册器不返回注销函数时退化为 no-op(与握手同形态,靠 close 统一清)。
|
|
137
|
-
*
|
|
138
|
-
* @param child 子进程(stdin 写入 get_state 命令)
|
|
139
|
-
* @param addResponseListener 注册 response 监听器的函数(stdout pump 中调用)
|
|
140
|
-
* @param timeoutMs 单次超时(决策点预算 1s 量级;P-T1 实测 idle 应答亚毫秒)
|
|
141
|
-
*/
|
|
142
|
-
export function requestGetStateOnce(
|
|
143
|
-
child: ChildProcess,
|
|
144
|
-
addResponseListener: AddGetStateResponseListener,
|
|
145
|
-
timeoutMs: number,
|
|
146
|
-
): Promise<GetStateResult> {
|
|
147
|
-
return new Promise<GetStateResult>((resolve) => {
|
|
148
|
-
let settled = false;
|
|
149
|
-
let removeListener: () => void = () => {};
|
|
150
|
-
|
|
151
|
-
const finish = (r: GetStateResult): void => {
|
|
152
|
-
if (settled) return;
|
|
153
|
-
settled = true;
|
|
154
|
-
clearTimeout(timer);
|
|
155
|
-
removeListener();
|
|
156
|
-
resolve(r);
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
let reqId: string;
|
|
160
|
-
try {
|
|
161
|
-
reqId = sendGetStateCommand(child);
|
|
162
|
-
} catch {
|
|
163
|
-
// stdin 已断等同步写失败 = 回补失败,空结果走调用方保守分支(同超时语义)
|
|
164
|
-
resolve({});
|
|
165
|
-
return;
|
|
166
|
-
}
|
|
167
|
-
removeListener =
|
|
168
|
-
addResponseListener(reqId, (data: unknown) => {
|
|
169
|
-
const r: GetStateResult = {};
|
|
170
|
-
extractGetStateFields(data, r);
|
|
171
|
-
// response 已到达:无论是否含目标字段都不再等(单次语义,无重试)
|
|
172
|
-
finish(r);
|
|
173
|
-
}) ?? (() => {});
|
|
174
|
-
// [#15] 同款时序模式:timer 在 resolver 注册后创建,resolver/finish 闭包引用它——
|
|
175
|
-
// 两者都只在 timer 初始化之后才可能被调用(response 到达是异步事件)。
|
|
176
|
-
const timer: ReturnType<typeof setTimeout> = setTimeout(() => finish({}), timeoutMs);
|
|
177
|
-
timer.unref();
|
|
178
|
-
});
|
|
179
|
-
}
|
|
@@ -1,317 +0,0 @@
|
|
|
1
|
-
// src/execution/engine/engines/pi/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
|
-
// AgentFailureKind 类型 SSOT 在 orchestration/models/types.ts(消费语义「unknown=
|
|
24
|
-
// 可重试」与其文档同源);type-only 引用,编译期擦除,零运行时依赖。
|
|
25
|
-
import type { AgentFailureKind } from "../../../../orchestration/models/types.ts";
|
|
26
|
-
// [D5-③ 词表归属声明] 分诊识别词表(STALE_CONTEXT_PATTERNS /
|
|
27
|
-
// DETERMINISTIC_SCHEMA_FAILURE_PREFIX)SSOT 在本模块(产出侧包内单点识别)——
|
|
28
|
-
// collectResult 识别 pi 错误文案后写 AgentResult.failureKind 结构化字段,消费侧
|
|
29
|
-
// (execute-agent-call)只读字段分诊、不再扫文案子串。文案词表依存并未消除,而是
|
|
30
|
-
// 从「跨模块消费 seam」收窄为「产出侧包内单点识别」;词表漂移的失效模式是
|
|
31
|
-
// failureKind=unknown → 保守重试(安全默认),不再是静默漏诊。
|
|
32
|
-
// (原 SSOT 在 execute-agent-call,2026-09 D5-③ 迁入——execution → orchestration
|
|
33
|
-
// 的值引用随之消除,方向反转为测试/消费侧零依赖。)
|
|
34
|
-
|
|
35
|
-
// ============================================================
|
|
36
|
-
// 失败分诊词表(D5-③,产出侧单点)
|
|
37
|
-
// ============================================================
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Stale context 检测模式(P1-5;W4b 对齐 pi 0.84.x 真实文案)。
|
|
41
|
-
*
|
|
42
|
-
* pi session context 被 compact/cancel 时报告的模式。这种情况下重试无意义——
|
|
43
|
-
* 同样的 call 会再次失败。分诊产出 failureKind="stale_context"(消费侧不重试)。
|
|
44
|
-
*
|
|
45
|
-
* W4b:原 "stale context"/"stalecontext" 与 pi 真实文案零匹配(真实文案为
|
|
46
|
-
* "This extension ctx is stale after session replacement or reload. ..."
|
|
47
|
-
* ——runner.ts:544(dist runner.js:352),词序是 "ctx is stale" 而非 "stale
|
|
48
|
-
* context"),stale 分诊对真实文案失效。现对齐:
|
|
49
|
-
* - "ctx is stale":真实文案核心子串(词序修正)
|
|
50
|
-
* - "stale after session replacement":scheduler 已验证 marker(runtime.ts
|
|
51
|
-
* STALE_CTX_MARKER,同文案锚定)
|
|
52
|
-
* - "context canceled"/"aborted":保留——abort 族错误同样不重试(signal.aborted
|
|
53
|
-
* 分支的先行分诊,防边界竞态漏网),删除会放宽重试语义。
|
|
54
|
-
*/
|
|
55
|
-
export const STALE_CONTEXT_PATTERNS = [
|
|
56
|
-
"ctx is stale",
|
|
57
|
-
"stale after session replacement",
|
|
58
|
-
"context canceled",
|
|
59
|
-
"aborted",
|
|
60
|
-
] as const;
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* 判断错误信息是否表示 stale/canceled pi session context。
|
|
64
|
-
* 命中时分诊 failureKind="stale_context"——重试只会再次失败(P1-5)。
|
|
65
|
-
*/
|
|
66
|
-
export function isStaleContextErrorMsg(msg: string | undefined): boolean {
|
|
67
|
-
if (!msg) return false;
|
|
68
|
-
const lower = msg.toLowerCase();
|
|
69
|
-
return STALE_CONTEXT_PATTERNS.some((p) => lower.includes(p));
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* [MF-1] 确定性 schema 失败标记(error 文本前缀,产出方 = 本模块的
|
|
74
|
-
* describeMissingParsedOutput)。
|
|
75
|
-
*
|
|
76
|
-
* 标记词逐字核对不命中 STALE_CONTEXT_PATTERNS 任一 pattern 与
|
|
77
|
-
* isStaleContextErrorMsg 的子串匹配(否则归因 error 被误诊 stale-context,
|
|
78
|
-
* 虽然同样不重试但归因语义被污染;output-collector.test 有交叉锁定)。
|
|
79
|
-
*
|
|
80
|
-
* 三态可重试性矩阵(F-1 归因):
|
|
81
|
-
* | 归因态 | 带本标记 | 分诊 | 可重试性 | 理由 |
|
|
82
|
-
* |----------------------------|---------|---------------------|---------|------|
|
|
83
|
-
* | ① 从未调用 SO tool | 是 | schema_deterministic | 不可重试 | 缺 extension 是环境确定性(C1 安装盲区),同环境重试必同结果 |
|
|
84
|
-
* | ② SO 调用 isError(gate 终止/不可满足 schema) | 是 | schema_deterministic | 不可重试 | 同 schema 重试必同结果(第五轮实测:3 attempts/4 子进程/235s 纯烧钱) |
|
|
85
|
-
* | ③ 调用过但无 details | 否 | unknown | 可重试 | 可能瞬态(details 提取/序列化异常),保留既有重试语义 |
|
|
86
|
-
*/
|
|
87
|
-
export const DETERMINISTIC_SCHEMA_FAILURE_PREFIX = "Structured output failed deterministically:";
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* [MF-1] 判断错误信息是否为确定性 schema 失败(命中标记前缀)。
|
|
91
|
-
* 命中时分诊 failureKind="schema_deterministic"——同 schema 重试必同结果
|
|
92
|
-
* (矩阵见 DETERMINISTIC_SCHEMA_FAILURE_PREFIX)。
|
|
93
|
-
*/
|
|
94
|
-
export function isDeterministicSchemaFailureMsg(msg: string | undefined): boolean {
|
|
95
|
-
if (!msg) return false;
|
|
96
|
-
return msg.includes(DETERMINISTIC_SCHEMA_FAILURE_PREFIX);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* [D5-③] 错误文案 → 结构化失败分诊标签(产出侧唯一识别点)。
|
|
101
|
-
*
|
|
102
|
-
* 判定优先级与收敛前的消费侧子串分诊一致(stale 在前):标记词与 stale 词表
|
|
103
|
-
* 零交集(交叉锁定测试守护),两序等价。未命中任何词表 → unknown——消费侧
|
|
104
|
-
* 默认退避重试(语义守恒,r1 MF4)。
|
|
105
|
-
*/
|
|
106
|
-
export function classifyFailureKind(
|
|
107
|
-
msg: string | undefined,
|
|
108
|
-
): AgentFailureKind | undefined {
|
|
109
|
-
if (msg === undefined) return undefined;
|
|
110
|
-
if (isStaleContextErrorMsg(msg)) return "stale_context";
|
|
111
|
-
if (isDeterministicSchemaFailureMsg(msg)) return "schema_deterministic";
|
|
112
|
-
return "unknown";
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// ============================================================
|
|
116
|
-
// Result 收集
|
|
117
|
-
// ============================================================
|
|
118
|
-
|
|
119
|
-
/** collectResult 的入参(session 身份 + 执行控制字段,执行内容从 record 读)。 */
|
|
120
|
-
export interface CollectResultArgs {
|
|
121
|
-
startTime: number;
|
|
122
|
-
success: boolean;
|
|
123
|
-
error: string | undefined;
|
|
124
|
-
sessionId: string;
|
|
125
|
-
sessionFile: string | undefined;
|
|
126
|
-
/**
|
|
127
|
-
* [F-1] 本次执行是否要求结构化产出(opts.schema 或 opts.schemaEnv 任一存在)。
|
|
128
|
-
* true 且 run 结束仍无有效 parsedOutput 时:结果不得静默 success——置 success=false
|
|
129
|
-
* 并把三态失败归因写进 error(上层 executeAgentCall 只看 error 判 completed/failed)。
|
|
130
|
-
* 缺省 false(非 schema 模式 parsedOutput===undefined 是正常态,不动成败)。
|
|
131
|
-
*/
|
|
132
|
-
schemaExpected?: boolean;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/** structured-output tool 名(与 structured-output 扩展 TOOL_NAME 一致,见 session-runner.ts)。 */
|
|
136
|
-
const STRUCTURED_OUTPUT_TOOL = "structured-output";
|
|
137
|
-
|
|
138
|
-
/** F-1 失败摘要截断长度(字符):错误详情拼进 run 结果 error 字段,防大 payload 撑爆。 */
|
|
139
|
-
const FAILED_SO_SUMMARY_MAX_CHARS = 300;
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* 从 toolCalls 提取 structured-output 的 result.details(schema 模式产出)。
|
|
143
|
-
* schema enforcement 保证 agent 调过该 tool(漏调会 steer 重试);这里只做逆向提取。
|
|
144
|
-
* 未调或无 details 返回 undefined。
|
|
145
|
-
*
|
|
146
|
-
* [F-1 失败吞没修复] isError:true 的调用一律跳过——失败调用的 details(pi 失败
|
|
147
|
-
* 路径默认 {})不是通过 schema 校验的产出,把它当 parsedOutput 会让 gate 终止/
|
|
148
|
-
* 模型自弃的 run 以 parsedOutput={} 静默 completed。isError 字段缺失(旧 record/
|
|
149
|
-
* 进行中调用)不误伤——仅显式 true 跳过。
|
|
150
|
-
*
|
|
151
|
-
* 导出以便直接单测(纯函数契约)。
|
|
152
|
-
*/
|
|
153
|
-
export function extractParsedOutput(toolCalls: ToolCall[]): unknown {
|
|
154
|
-
for (let i = toolCalls.length - 1; i >= 0; i--) {
|
|
155
|
-
const tc = toolCalls[i]!;
|
|
156
|
-
if (tc.toolName === STRUCTURED_OUTPUT_TOOL && tc.isError !== true && tc.result?.details !== undefined) {
|
|
157
|
-
return tc.result.details;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
return undefined;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* [F-R1] 中和动态错误摘要中的 stale-context 命中词:对每个 STALE_CONTEXT_PATTERNS
|
|
165
|
-
* 做大小写不敏感的子串替换为 "[redacted]"(分诊 isStaleContextErrorMsg 是
|
|
166
|
-
* toLowerCase 后的子串匹配,故中和也必须大小写不敏感)。
|
|
167
|
-
*
|
|
168
|
-
* 为何只中和动态段(summarizeToolContent 产物)、不中和固定前缀:前缀是本模块
|
|
169
|
-
* 静态文案,已逐字核对无任何 pattern 命中,且由 output-collector.test.ts 的
|
|
170
|
-
* "messages avoid STALE_CONTEXT_PATTERNS substrings" 用例锁定;动态段是
|
|
171
|
-
* 模型/provider 的原始错误文本(可含 "aborted"/"ctx is stale" 等),不受本模块
|
|
172
|
-
* 控制。不中和的话,拼接结果经 collectResult 的 classifyFailureKind 分诊会被
|
|
173
|
-
* 误标为 stale_context(SO 失败归因被误诊),终态虽同样不重试但归因语义被污染。
|
|
174
|
-
*
|
|
175
|
-
* 导出以便直接单测(纯函数契约)。
|
|
176
|
-
*/
|
|
177
|
-
export function neutralizeStalePatterns(text: string): string {
|
|
178
|
-
let out = text;
|
|
179
|
-
for (const pattern of STALE_CONTEXT_PATTERNS) {
|
|
180
|
-
// pattern 当前均为纯小写词/短语(无 regex 元字符),escape 仅为防未来 pattern
|
|
181
|
-
// 演化引入元字符时静默改变语义。
|
|
182
|
-
const escaped = pattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
183
|
-
out = out.replace(new RegExp(escaped, "gi"), "[redacted]");
|
|
184
|
-
}
|
|
185
|
-
return out;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* schema 模式下无有效 parsedOutput 时的三态失败归因(F-1)。
|
|
190
|
-
*
|
|
191
|
-
* 返回 undefined 表示 toolCalls 里有可用的 parsedOutput(无需归因)。
|
|
192
|
-
* 三态判定优先级:校验失败(有 isError 调用)> 从未调用 SO tool > 调用过但无 details。
|
|
193
|
-
*
|
|
194
|
-
* [MF-1] 三态可重试性矩阵(标记 SSOT 与分类判定均在本模块——D5-③ 收敛为产出侧
|
|
195
|
-
* 单点,消费端 execute-agent-call 只读 failureKind 字段):
|
|
196
|
-
* | 归因态 | 带标记 | 可重试性 | 理由 |
|
|
197
|
-
* |------------------------------|-------|---------|------|
|
|
198
|
-
* | ① 从未调用 SO tool | 是 | 不可重试 | 缺 extension 是环境确定性(C1 安装盲区),同环境重试必同结果 |
|
|
199
|
-
* | ② SO 调用 isError(gate 终止/不可满足 schema) | 是 | 不可重试 | 同 schema 重试必同结果(第五轮实测 retry 放大回归:3 attempts/4 子进程/235s) |
|
|
200
|
-
* | ③ 调用过但无 details | 否 | 可重试 | 可能瞬态(details 提取/序列化异常),保留既有重试语义 |
|
|
201
|
-
*
|
|
202
|
-
* 文案约束:不得命中本模块的 STALE_CONTEXT_PATTERNS("aborted" 等
|
|
203
|
-
* 子串)——命中会被 classifyFailureKind 误标 stale_context。固定前缀(含 MF-1 标记词)静态
|
|
204
|
-
* 无命中(测试锁定);动态段经 neutralizeStalePatterns 中和(F-R1)。
|
|
205
|
-
*
|
|
206
|
-
* 导出以便直接单测(纯函数契约)。
|
|
207
|
-
*/
|
|
208
|
-
export function describeMissingParsedOutput(toolCalls: ToolCall[]): string | undefined {
|
|
209
|
-
if (extractParsedOutput(toolCalls) !== undefined) return undefined;
|
|
210
|
-
const soCalls = toolCalls.filter((tc) => tc.toolName === STRUCTURED_OUTPUT_TOOL);
|
|
211
|
-
if (soCalls.length === 0) {
|
|
212
|
-
// 覆盖独立安装盲区(C1):schema enforcement 依赖 SO extension 注册 tool,
|
|
213
|
-
// 未安装时 agent 无工具可调、steer 无法生效——只能在这里事后暴露。
|
|
214
|
-
// [MF-1] 态① 带确定性标记:缺 extension 是环境确定性,不重试。
|
|
215
|
-
return (
|
|
216
|
-
`${DETERMINISTIC_SCHEMA_FAILURE_PREFIX} ` +
|
|
217
|
-
"Agent finished without producing a structured output: the structured-output tool was never called. " +
|
|
218
|
-
"Recovery: verify the structured-output extension is installed and enabled for this agent, " +
|
|
219
|
-
"and that the agent's final answer conforms to the requested schema."
|
|
220
|
-
);
|
|
221
|
-
}
|
|
222
|
-
const failed = soCalls.filter((tc) => tc.isError === true);
|
|
223
|
-
if (failed.length > 0) {
|
|
224
|
-
const last = failed[failed.length - 1]!;
|
|
225
|
-
// [F-R1] 先截断后中和:截断边界把 pattern 切断时不产生新命中(半截词本就
|
|
226
|
-
// 匹配不到分诊子串),完整落入截断窗口的 pattern 一定被中和。
|
|
227
|
-
const lastErrorSummary = neutralizeStalePatterns(summarizeToolContent(last.result?.content));
|
|
228
|
-
// [F-R4] 失败原因分类:isError 只说明「调用失败」,原因未必是 schema 校验
|
|
229
|
-
// (provider 错误/pi abort/扩展内部错误同样走 isError),硬编码
|
|
230
|
-
// "(schema validation)" 会误导排障。按最后错误的实际内容分类——权威锚点是
|
|
231
|
-
// structured-output 扩展校验失败的固定文案前缀 "Schema validation failed: ..."
|
|
232
|
-
//(structured-output/src/execute.ts),大小写不敏感匹配;其余归为 execution
|
|
233
|
-
// failure。在已中和的摘要上分类:中和仅替换 stale 词,与校验词无交集。
|
|
234
|
-
const failureKind = lastErrorSummary.toLowerCase().includes("validation failed")
|
|
235
|
-
? "schema validation"
|
|
236
|
-
: "execution failure";
|
|
237
|
-
// [MF-1] 态② 带确定性标记:gate 终止/不可满足 schema 同 schema 重试必同结果。
|
|
238
|
-
// 注:failureKind=execution failure(provider 瞬态错误)同样不重试——isError 态
|
|
239
|
-
// 整体从重试面摘除(实测回归即此态循环烧钱),瞬态恢复交由上层 workflow 编排。
|
|
240
|
-
return (
|
|
241
|
-
`${DETERMINISTIC_SCHEMA_FAILURE_PREFIX} ` +
|
|
242
|
-
`Agent finished without a valid structured output: ${failed.length} structured-output call(s) failed ` +
|
|
243
|
-
`(${failureKind}). Last error: ${lastErrorSummary}`
|
|
244
|
-
);
|
|
245
|
-
}
|
|
246
|
-
return (
|
|
247
|
-
"Agent finished without a valid structured output: structured-output was called but none of the " +
|
|
248
|
-
"successful calls carried result details."
|
|
249
|
-
);
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
/** 从 tool result.content 提取可读错误文本([{type:"text",text}] 形态,防御未知形状)。 */
|
|
253
|
-
function summarizeToolContent(content: unknown): string {
|
|
254
|
-
let summary = "(no detail)";
|
|
255
|
-
if (Array.isArray(content)) {
|
|
256
|
-
const texts = content
|
|
257
|
-
.map((item) => (item && typeof item === "object" && "text" in item ? String((item as { text: unknown }).text) : ""))
|
|
258
|
-
.filter((t) => t !== "");
|
|
259
|
-
if (texts.length > 0) summary = texts.join(" ");
|
|
260
|
-
} else if (typeof content === "string" && content !== "") {
|
|
261
|
-
summary = content;
|
|
262
|
-
}
|
|
263
|
-
return summary.length > FAILED_SO_SUMMARY_MAX_CHARS
|
|
264
|
-
? `${summary.slice(0, FAILED_SO_SUMMARY_MAX_CHARS)}...`
|
|
265
|
-
: summary;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
/**
|
|
269
|
-
* 从 record + args 组装 AgentResult。每个字段来源单一且收口于 record:
|
|
270
|
-
* text ← getFullText(record)(聚合 turns[].text,单一数据源)
|
|
271
|
-
* turns ← record.turnCount
|
|
272
|
-
* toolCalls ← getAllToolCalls(record)(扁平化 turns[].toolCalls)
|
|
273
|
-
* usage ← getTotalUsage(record)(聚合 turns[].usageDelta,全零则 undefined)
|
|
274
|
-
* parsedOutput ← extractParsedOutput(toolCalls)
|
|
275
|
-
*
|
|
276
|
-
* startTime 算 durationMs。
|
|
277
|
-
*
|
|
278
|
-
* success 双来源判定(调用方传入):
|
|
279
|
-
* ① session.prompt() 抛错 → args.success=false
|
|
280
|
-
* ② prompt 成功但 record.lastError 非空(message_end stopReason=error)→ success=false
|
|
281
|
-
*/
|
|
282
|
-
export function collectResult(
|
|
283
|
-
record: ExecutionRecord,
|
|
284
|
-
args: CollectResultArgs,
|
|
285
|
-
): AgentResult {
|
|
286
|
-
const toolCalls = getAllToolCalls(record);
|
|
287
|
-
const parsedOutput = extractParsedOutput(toolCalls);
|
|
288
|
-
const result: AgentResult = {
|
|
289
|
-
text: getFullText(record),
|
|
290
|
-
turns: record.turnCount,
|
|
291
|
-
durationMs: Date.now() - args.startTime,
|
|
292
|
-
success: args.success,
|
|
293
|
-
error: args.error,
|
|
294
|
-
sessionId: args.sessionId,
|
|
295
|
-
toolCalls,
|
|
296
|
-
usage: getTotalUsage(record),
|
|
297
|
-
sessionFile: args.sessionFile,
|
|
298
|
-
parsedOutput,
|
|
299
|
-
};
|
|
300
|
-
// [F-1 失败吞没修复] schema 模式下 run 结束仍无有效 parsedOutput 时不得静默
|
|
301
|
-
// success:只在「本将成功」的路径上标注(success=false 的路径已有真实 error/
|
|
302
|
-
// abort 语义,不覆写)。error 经 mapToWorkflowAgentResult(仅 !success 透传)
|
|
303
|
-
// → executeAgentCall(error!==undefined 即 failed)逐层可见。
|
|
304
|
-
if (args.schemaExpected === true && result.success && parsedOutput === undefined) {
|
|
305
|
-
result.success = false;
|
|
306
|
-
result.error = describeMissingParsedOutput(toolCalls) ?? result.error;
|
|
307
|
-
}
|
|
308
|
-
// [D5-③] 失败分诊结构化:error 最终确定后(含 F-1 归因覆写)一次分类写入。
|
|
309
|
-
// 消费侧(executeAgentCall)读 failureKind 字段分诊,不再扫 error 文案子串;
|
|
310
|
-
// 缺省(成功路径/上游未写)= unknown = 可重试(语义守恒)。H4 合成文案
|
|
311
|
-
// (agent-result-mapper 对 !success && !error 的 abort fallback)在此之后产生,
|
|
312
|
-
// 不经本分类——该场景 signal.aborted 检查兜底,不依赖分诊。
|
|
313
|
-
if (result.error !== undefined) {
|
|
314
|
-
result.failureKind = classifyFailureKind(result.error);
|
|
315
|
-
}
|
|
316
|
-
return result;
|
|
317
|
-
}
|