@zhushanwen/pi-subagent-workflow 8.4.0 → 8.6.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/package.json +22 -7
- package/relay/relay.mjs +390 -0
- package/skills/subagent-ext-config/SKILL.md +80 -0
- package/src/execution/__tests__/agent-registry.test.ts +110 -0
- package/src/execution/__tests__/bg-notify-render.test.ts +73 -0
- package/src/execution/__tests__/chat-engine-routing.test.ts +601 -0
- package/src/execution/__tests__/delivery-methods.test.ts +38 -1
- package/src/execution/__tests__/execute-options-mapper.test.ts +11 -0
- package/src/execution/__tests__/execution-record.test.ts +237 -1
- package/src/execution/__tests__/explicit-agent-ref-guard.test.ts +171 -0
- package/src/execution/__tests__/format-schema-instruction.test.ts +63 -32
- package/src/execution/__tests__/helpers/spawn-mock.ts +4 -0
- package/src/execution/__tests__/index-session-start.test.ts +86 -7
- package/src/execution/__tests__/lifecycle-manager.test.ts +46 -0
- package/src/execution/__tests__/list-fields.test.ts +45 -14
- package/src/execution/__tests__/model-resolver.test.ts +57 -5
- package/src/execution/__tests__/notifier-flush.test.ts +64 -26
- package/src/execution/__tests__/notify-ledger.test.ts +826 -0
- package/src/execution/__tests__/output-collector.test.ts +299 -2
- package/src/execution/__tests__/pi-invocation.test.ts +62 -1
- package/src/execution/__tests__/relay-agent.test.ts +448 -0
- package/src/execution/__tests__/relay-env.test.ts +42 -0
- package/src/execution/__tests__/rpc-mode.test.ts +1 -1
- package/src/execution/__tests__/run-spawn-edges.test.ts +44 -1
- package/src/execution/__tests__/run-spawn-stdout-callback-throw.test.ts +199 -0
- package/src/execution/__tests__/session-runner-schema-env.test.ts +39 -0
- package/src/execution/__tests__/spawn-args.test.ts +37 -26
- package/src/execution/__tests__/start-sync-model-guard.test.ts +150 -0
- package/src/execution/__tests__/startup-config-declaration.test.ts +35 -0
- package/src/execution/__tests__/stream-sink-retirement.test.ts +261 -0
- package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +310 -0
- package/src/execution/__tests__/subprocess-agent-runner.test.ts +147 -6
- package/src/execution/__tests__/timeout-integration.test.ts +220 -2
- package/src/execution/__tests__/tool-action.test.ts +92 -1
- package/src/execution/agent-registry.ts +16 -0
- package/src/execution/argv-mirror.ts +5 -1
- package/src/execution/concurrency-pool.ts +1 -1
- package/src/execution/config.ts +25 -2
- package/src/execution/engine/__tests__/common/data-dir.test.ts +53 -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/contract.relay.test.ts +342 -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__/engines-declaration.test.ts +36 -0
- package/src/execution/engine/__tests__/model-prompt.test.ts +85 -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 +62 -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 +64 -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 +59 -0
- package/src/execution/engine/paths.ts +42 -0
- package/src/execution/engine/port.ts +153 -0
- package/src/execution/engine/registry.ts +123 -0
- package/src/execution/engine/routing.ts +218 -0
- package/src/execution/engine/types.ts +309 -0
- package/src/execution/execute-options-mapper.ts +13 -8
- package/src/execution/execution-record.ts +66 -1
- package/src/execution/lifecycle-manager.ts +23 -1
- package/src/execution/model-config-service.ts +16 -1
- package/src/execution/model-resolver.ts +37 -59
- package/src/execution/notifier.ts +105 -35
- package/src/execution/notify-ledger.ts +580 -0
- package/src/execution/output-collector.ts +143 -3
- package/src/execution/pi-invocation.ts +32 -2
- package/src/execution/record-entry.ts +14 -0
- package/src/execution/record-store.ts +34 -0
- package/src/execution/relay-env.ts +37 -0
- package/src/execution/session-runner.ts +328 -71
- package/src/execution/stream-sink.ts +26 -0
- package/src/execution/subagent-service.ts +273 -13
- package/src/execution/subprocess-agent-runner.ts +210 -14
- package/src/execution/types.ts +124 -5
- package/src/execution/ui-request-queue.ts +14 -4
- package/src/index.ts +99 -1
- package/src/interface/__tests__/subagent-tool-path-guard.test.ts +157 -0
- package/src/interface/__tests__/subagent-tool-prompt.test.ts +12 -0
- package/src/interface/bg-notify-render.ts +33 -12
- package/src/interface/helpers.ts +2 -2
- package/src/interface/subagent-actions.ts +29 -9
- package/src/interface/subagent-tool-schema.ts +156 -0
- package/src/interface/subagent-tool.ts +56 -119
- package/src/interface/subagents.ts +2 -2
- package/src/orchestration/__tests__/__fixtures__/worker-template.snapshot.txt +19 -3
- package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +0 -6
- package/src/orchestration/__tests__/agent-call-stream.test.ts +0 -5
- package/src/orchestration/__tests__/error-recovery-handlers.test.ts +89 -4
- package/src/orchestration/__tests__/execute-agent-call.test.ts +137 -0
- package/src/orchestration/__tests__/jsonl-run-store-corrupt-entry.test.ts +150 -0
- package/src/orchestration/__tests__/jsonl-run-store-retention.test.ts +202 -0
- package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +326 -3
- package/src/orchestration/__tests__/lifecycle.test.ts +41 -7
- package/src/orchestration/__tests__/non-cloneable-return-e2e.test.ts +95 -0
- package/src/orchestration/__tests__/review-fix-loop-e2e.test.ts +57 -3
- package/src/orchestration/__tests__/skill-discovery.test.ts +44 -0
- package/src/orchestration/__tests__/worker-exit-without-result.test.ts +368 -0
- package/src/orchestration/__tests__/worker-script-builder-runtime.test.ts +43 -0
- package/src/orchestration/__tests__/worker-script-template-snapshot.test.ts +22 -3
- package/src/orchestration/agent-opts-resolver.ts +104 -23
- package/src/orchestration/error-recovery.ts +189 -33
- package/src/orchestration/execute-agent-call.ts +39 -0
- package/src/orchestration/jsonl-run-store.ts +121 -7
- package/src/orchestration/launcher.ts +60 -15
- package/src/orchestration/lifecycle.ts +10 -7
- package/src/orchestration/models/__tests__/budget.test.ts +1 -61
- package/src/orchestration/models/budget.ts +5 -35
- package/src/orchestration/models/run-runtime.ts +24 -9
- package/src/orchestration/models/types.ts +16 -0
- package/src/orchestration/script-lint.ts +1 -1
- package/src/orchestration/skill-discovery.ts +31 -8
- package/src/orchestration/worker-script-builder.ts +19 -3
- package/src/shared/__tests__/model-ref.test.ts +306 -0
- package/src/shared/__tests__/schema-jsonify.test.ts +1 -1
- package/src/shared/__tests__/timer-delay.test.ts +61 -0
- package/src/shared/meta-parser.ts +5 -1
- package/src/shared/model-ref.ts +286 -0
- package/src/shared/resource-meta.ts +5 -0
- package/src/shared/schema-env.ts +44 -0
- package/src/shared/schema-jsonify.ts +6 -4
- package/src/shared/timer-delay.ts +54 -0
- package/workflows/review-fix-loop-utils.cjs +9 -7
- package/workflows/review-fix-loop.js +20 -12
- package/src/orchestration/__tests__/concurrency-gate.test.ts +0 -125
- package/src/orchestration/concurrency-gate.ts +0 -69
|
@@ -8,7 +8,9 @@
|
|
|
8
8
|
// 接线层级:
|
|
9
9
|
// [跨模块 port] implements AgentRunner(orchestration/models/ports.ts)
|
|
10
10
|
// [模块内直调] mapToExecuteOptions + mergeTimeoutSignal(execute-options-mapper)
|
|
11
|
-
// [
|
|
11
|
+
// [P4 路由层] engine/routing.ts routeEngine(三层优先级 + probe + fallback 三守卫,D9)
|
|
12
|
+
// [引擎层] EnginePort.run(pi = 本地 DI 绑定实例;非 pi = registry.getEngine 动态获取)
|
|
13
|
+
// [模块内直调] this.subagentService.executeAndAwait(PiEngine 内部委托目标)
|
|
12
14
|
//
|
|
13
15
|
// 设计基线:
|
|
14
16
|
// D-A2(映射归 adapter)/ D-A8(onEvent 桥接)/ D-A9(timeoutMs 合并 signal)/
|
|
@@ -17,8 +19,20 @@
|
|
|
17
19
|
import type { AgentRunner } from "../orchestration/models/ports.ts";
|
|
18
20
|
import type { AgentCallOpts, AgentResult } from "../orchestration/models/types.ts";
|
|
19
21
|
import type { AgentEvent } from "../shared/agent-event.ts";
|
|
22
|
+
import { getEngineDataDir } from "./engine/common/data-dir.ts";
|
|
23
|
+
import { JournalWriter } from "./engine/common/event-journal.ts";
|
|
24
|
+
import { createPiEngine, PI_POOL_KEY } from "./engine/engines/pi/registration.ts";
|
|
25
|
+
import { executeOptionsToTaskSpec } from "./engine/engines/pi/task-spec-mapper.ts";
|
|
26
|
+
import { resolveJournalPath } from "./engine/paths.ts";
|
|
27
|
+
import type { EnginePort, RunContext } from "./engine/port.ts";
|
|
28
|
+
import { routeEngine, resolveEngineRouting, type EngineRouteResult, type EngineRoutingInput } from "./engine/routing.ts";
|
|
29
|
+
import { getEngine, hasEngine, listEngines } from "./engine/registry.ts";
|
|
30
|
+
import type { AgentOutcome, EngineHandle } from "./engine/types.ts";
|
|
20
31
|
import { mapToExecuteOptions, mergeTimeoutSignal } from "./execute-options-mapper.ts";
|
|
32
|
+
import { getModelConfigService } from "./model-config-service.ts";
|
|
21
33
|
import type { ModelInfo } from "./model-resolver.ts";
|
|
34
|
+
import { modelRefFromVerified } from "../shared/model-ref";
|
|
35
|
+
import { registerSpawnedChildForRecord } from "./session-runner.ts";
|
|
22
36
|
import type { SubagentStream } from "./stream-sink.ts";
|
|
23
37
|
import type { SubagentService } from "./subagent-service.ts";
|
|
24
38
|
import type { ExecuteOptions } from "./types.ts";
|
|
@@ -51,14 +65,27 @@ export interface SubprocessAgentRunnerDeps {
|
|
|
51
65
|
* - result 形状不变(workflow AgentResult: content/parsedOutput/usage/error/toolCalls)
|
|
52
66
|
* - 不 reject——失败信息入 result.error(与 executeAgentCall 契约一致)
|
|
53
67
|
* - timeoutMs 合并 signal(D-A9);onEvent 桥接 AgentEvent→workflow liveRecord(D-A8)
|
|
68
|
+
*
|
|
69
|
+
* [P1 引擎接线] 执行经 EnginePort。pi 引擎绑定本 SAR 的服务引用(per-session DI——
|
|
70
|
+
* 单测注入 mock 时全局单例不可见;生产环境两者是同一进程单例对象),行为零变化;
|
|
71
|
+
* 非 pi 引擎(P4 路由可达:frontmatter/调用参数/全局默认指定)经 registry.getEngine
|
|
72
|
+
* 动态获取——「引擎身份」的归属边界在注册表,SAR 不感知具体引擎实现。
|
|
73
|
+
*
|
|
74
|
+
* [P4 配置路由] 每次运行经 engine/routing.ts 解析三层优先级(调用参数 opts.engine >
|
|
75
|
+
* agent frontmatter engine > 全局默认 'pi')+ probe + fallback 三守卫(D9)。路由失败
|
|
76
|
+
* (engine_not_found / engine_probe_failed / model_not_available)不 reject,入
|
|
77
|
+
* result.error——与 executeAgentCall 契约一致。
|
|
54
78
|
*/
|
|
55
79
|
export class SubprocessAgentRunner implements AgentRunner {
|
|
56
80
|
private readonly subagentService: SubagentService;
|
|
57
81
|
private ctxModel: ModelInfo | undefined;
|
|
82
|
+
/** pi 引擎(per-session DI 绑定,缺省执行路径——见类注释)。 */
|
|
83
|
+
private readonly piEngine: EnginePort;
|
|
58
84
|
|
|
59
85
|
constructor(deps: SubprocessAgentRunnerDeps) {
|
|
60
86
|
this.subagentService = deps.subagentService;
|
|
61
87
|
this.ctxModel = deps.ctxModel;
|
|
88
|
+
this.piEngine = createPiEngine(() => this.subagentService);
|
|
62
89
|
}
|
|
63
90
|
|
|
64
91
|
/**
|
|
@@ -72,13 +99,16 @@ export class SubprocessAgentRunner implements AgentRunner {
|
|
|
72
99
|
}
|
|
73
100
|
|
|
74
101
|
/**
|
|
75
|
-
* 执行单次 agent
|
|
102
|
+
* 执行单次 agent 调用:路由(P4)→ EnginePort.run → PiEngine 委托
|
|
103
|
+
* SubagentService.executeAndAwait。
|
|
76
104
|
*
|
|
77
105
|
* 接线链路:
|
|
78
|
-
* mergeTimeoutSignal → mapToExecuteOptions →
|
|
79
|
-
*
|
|
106
|
+
* routeEngine(三层 + probe + 守卫)→ mergeTimeoutSignal → mapToExecuteOptions →
|
|
107
|
+
* AgentTaskSpec → engine.run(PiEngine:spec → ExecuteOptions 还原 + engine 留痕)→
|
|
108
|
+
* executeAndAwait → AgentOutcome → AgentResult
|
|
80
109
|
*
|
|
81
110
|
* 错误处理:不 reject。
|
|
111
|
+
* - 路由失败(未注册 id / probe 失败 + 守卫或 strict)→ AgentResult.error(错误码前缀)
|
|
82
112
|
* - executeAndAwait 内部失败 → 返回 AgentResult(success:false) → 已映射 error 字段
|
|
83
113
|
* - executeAndAwait throw(嵌套超限 BC-12)→ catch → AgentResult.error
|
|
84
114
|
* - spawn 级失败已由 runSpawn 内部收口为 failed AgentResult(不逃逸)
|
|
@@ -91,22 +121,118 @@ export class SubprocessAgentRunner implements AgentRunner {
|
|
|
91
121
|
): Promise<AgentResult> {
|
|
92
122
|
const startedAt = Date.now();
|
|
93
123
|
|
|
124
|
+
// ── P4 路由:三层优先级 + probe + fallback 三守卫(D9①/D7)──
|
|
125
|
+
// 路由在最前——引擎身份决定 journal 路径与后续一切执行面;失败(未注册 id /
|
|
126
|
+
// probe 失败 + strict/守卫)按「不 reject」契约转 result.error。
|
|
127
|
+
// pi 快路径同步短路(不经 routeEngine 的 await):pi 恒免探、无 fallback 可言、
|
|
128
|
+
// engineFor('pi') 本地 DI 绑定恒可用——不引入微任务边界,缺省路径时序与 P1 接线
|
|
129
|
+
// 前完全一致(下游依赖「run 内首个 await 前已触达 executeAndAwait」的时序契约)。
|
|
130
|
+
let routingInput: EngineRoutingInput;
|
|
131
|
+
let route: EngineRouteResult;
|
|
132
|
+
try {
|
|
133
|
+
routingInput = this.buildRoutingInput(opts);
|
|
134
|
+
const routing = resolveEngineRouting(routingInput);
|
|
135
|
+
if (routing.engineId === "pi") {
|
|
136
|
+
route = {
|
|
137
|
+
engine: this.piEngine,
|
|
138
|
+
engineId: "pi",
|
|
139
|
+
requestedEngineId: "pi",
|
|
140
|
+
source: routing.source,
|
|
141
|
+
};
|
|
142
|
+
} else {
|
|
143
|
+
route = await routeEngine({
|
|
144
|
+
routing: routingInput,
|
|
145
|
+
taskModel: opts.model,
|
|
146
|
+
strict: getModelConfigService()?.getGlobalConfig().engineRouting?.strict === true,
|
|
147
|
+
probe: (engineId) => this.engineFor(engineId).probe(),
|
|
148
|
+
getEngineFn: (engineId) => this.engineFor(engineId),
|
|
149
|
+
// pi 经本地 DI 绑定恒可用(不依赖 registry 全局注册态——SAR 持有服务引用),
|
|
150
|
+
// has/list 注入同一口径,engine_not_found 文案不会把本地 pi 漏报成未注册
|
|
151
|
+
hasEngineFn: (engineId) => engineId === "pi" || hasEngine(engineId),
|
|
152
|
+
listEnginesFn: () => (hasEngine("pi") ? listEngines() : ["pi", ...listEngines()]),
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
} catch (err) {
|
|
156
|
+
// buildRoutingInput 的 agent 解析期校验(未注册 frontmatter engine)与路由失败
|
|
157
|
+
// (probe + strict/守卫)一并在此收口——「不 reject」契约
|
|
158
|
+
return errorResult(err, startedAt);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// ── P2 event journal 接线(设计 D6 第②级;对齐点③:路径权威 = 引擎池 key)──
|
|
162
|
+
// host 在 onEvent 回调内统一落盘(全引擎免费获得②级数据源)。初始 poolKey 用 pi
|
|
163
|
+
// 缺省占位(pi 恒 'shared');非池化稳定引擎(zcode)在 prepare 期经
|
|
164
|
+
// RunContext.onPoolResolved 声明实际池 key → writer.retarget——保证 journal 落盘
|
|
165
|
+
// 路径与 handle.poolKey 同源(handle.journalPath 由本方法 run 返回后回填)。
|
|
166
|
+
//
|
|
167
|
+
// taskId 为宿主侧任务标识(journal 文件名与池引用计数 key)——executeAndAwait
|
|
168
|
+
// 不外露内部 record id(取真实 id 需 hook record store 且改 createRecordForMode
|
|
169
|
+
// 签名,影响面大;P4 决策:保留占位,`sa-` 前缀与 record id 同构。影响面:record
|
|
170
|
+
// GC 时无法按 taskId 联动删 journal(journal 依赖 30 天 TTL 自然回收),read ②级
|
|
171
|
+
// 经 handle.journalPath 自描述定位不受影响)。
|
|
172
|
+
const taskId = `sa-${crypto.randomUUID()}`;
|
|
173
|
+
const journal = new JournalWriter({
|
|
174
|
+
path: resolveJournalPath(getEngineDataDir(), route.engineId, PI_POOL_KEY, taskId),
|
|
175
|
+
taskId,
|
|
176
|
+
engineId: route.engineId,
|
|
177
|
+
});
|
|
178
|
+
const retargetJournal = (poolKey: string): void => {
|
|
179
|
+
journal.retarget(resolveJournalPath(getEngineDataDir(), route.engineId, poolKey, taskId));
|
|
180
|
+
};
|
|
181
|
+
// 包装:先写 journal 再转发原 onEvent(原 onEvent 未传时也恒传包装版——
|
|
182
|
+
// 下游 onEvent 通道是事件生成后的纯转发,无行为分支,仅多一次入队)
|
|
183
|
+
const journalingOnEvent = (event: AgentEvent): void => {
|
|
184
|
+
journal.append(event);
|
|
185
|
+
onEvent?.(event);
|
|
186
|
+
};
|
|
187
|
+
|
|
94
188
|
try {
|
|
95
|
-
// ──
|
|
189
|
+
// ── [U1 D2] RunContext.modelRef 接入:ctxModel 继承路径的孪生守卫 ──
|
|
190
|
+
// ctxModel 是运行时已验证的 ModelInfo(豁免 registry 存在性复查),但继承产出的
|
|
191
|
+
// canonical 串与显式入参走同一个 pi pattern 引擎,孪生守卫同等适用(modelRefFromVerified)。
|
|
192
|
+
// 守卫在 engine.run 之前同步拒绝:含孪生 registry 下不产生任何 record/spawn,
|
|
193
|
+
// 失败走下方 catch → errorResult(错误文案含恢复指引)。
|
|
194
|
+
// RunContext 类型本身定义在 engine/port.ts(跨模块 port,不在本单元领地),
|
|
195
|
+
// 故接入点为构造 runCtx 前的守卫调用;pi 链路下游 resolveModel 的 ctxModel 分支
|
|
196
|
+
// 有同一守卫(model-resolver.ts),两处共用同一入口函数。
|
|
197
|
+
if (this.ctxModel) {
|
|
198
|
+
const modelService = getModelConfigService();
|
|
199
|
+
if (modelService) modelRefFromVerified(this.ctxModel, modelService.getModelRegistry());
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// ── D-A9: timeoutMs 合并 signal(超时 abort 带 HOST_TIMEOUT_ABORT_REASON 标记)──
|
|
96
203
|
const mergedSignal = mergeTimeoutSignal(signal, opts.timeoutMs);
|
|
97
204
|
|
|
98
205
|
// ── D-A2 + D-008: AgentCallOpts → ExecuteOptions 映射 ──
|
|
99
206
|
const mappedOpts: ExecuteOptions = mapToExecuteOptions(opts, this.ctxModel);
|
|
100
207
|
|
|
101
|
-
// ──
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
208
|
+
// ── P1/P4 引擎接线:EnginePort.run ──
|
|
209
|
+
const runCtx: RunContext = {
|
|
210
|
+
taskId,
|
|
211
|
+
poolKey: PI_POOL_KEY,
|
|
212
|
+
signal: mergedSignal,
|
|
213
|
+
onEvent: journalingOnEvent,
|
|
214
|
+
ctxModel: this.ctxModel,
|
|
215
|
+
...(route.engineFallback !== undefined ? { engineFallback: route.engineFallback } : {}),
|
|
216
|
+
onPoolResolved: retargetJournal,
|
|
217
|
+
// [U0 D10] 终止链路径①:引擎 spawn 的子进程注册进 session-runner 的
|
|
218
|
+
// spawnedChildren 记账(dispose killAll 收割兜底对 workflow 域引擎任务生效);
|
|
219
|
+
// taskId('sa-' 前缀)即记账 key,与 chat 域 kickOffEngineRun 的 record.id 同构
|
|
220
|
+
onChildSpawned: (child) => registerSpawnedChildForRecord(taskId, child),
|
|
221
|
+
...(stream !== undefined ? { stream } : {}),
|
|
222
|
+
// 解耦形态(有 schemaEnv 无 schema)的兜底通道——耦合形态下引擎从 task.schema
|
|
223
|
+
// 派生等值,此值被忽略(见 RunContext.schemaEnv 注释)
|
|
224
|
+
...(mappedOpts.schemaEnv !== undefined ? { schemaEnv: mappedOpts.schemaEnv } : {}),
|
|
225
|
+
};
|
|
226
|
+
const { handle, outcome } = await route.engine.run(
|
|
227
|
+
// 泛化为中立声明(PiEngine 内部再还原回 ExecuteOptions——往返保真,
|
|
228
|
+
// 由 engines/pi/__tests__/task-spec-mapper.test.ts 逐字段锁定)
|
|
229
|
+
executeOptionsToTaskSpec(mappedOpts),
|
|
230
|
+
runCtx,
|
|
231
|
+
);
|
|
232
|
+
// handle.journalPath 回填(§3.3.6:read ②级的自描述定位符——运行期落盘路径
|
|
233
|
+
// 权威在 writer,handle 记录最终路径供跨重启 read 消费)
|
|
234
|
+
backfillJournalPath(handle, journal.path);
|
|
235
|
+
return outcomeToRunnerResult(outcome);
|
|
110
236
|
} catch (err) {
|
|
111
237
|
// executeAndAwait throw(嵌套超限 ForkDepthExceededError,BC-12)或未预期异常 → 不 reject,入 error。
|
|
112
238
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -116,6 +242,76 @@ export class SubprocessAgentRunner implements AgentRunner {
|
|
|
116
242
|
error: message,
|
|
117
243
|
toolCalls: [],
|
|
118
244
|
};
|
|
245
|
+
} finally {
|
|
246
|
+
// run 终态后 flush + fsync 一次(§3.3.6 写入纪律);写失败已由 writer 内部
|
|
247
|
+
// warn + failed 收口,close 不抛(journal 是②级尽力而为数据源)
|
|
248
|
+
await journal.close();
|
|
119
249
|
}
|
|
120
250
|
}
|
|
251
|
+
|
|
252
|
+
// ── 内部 ──
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* 引擎获取:pi 走 per-session DI 绑定(mock 语义 + 生产同单例,P1 行为零变化);
|
|
256
|
+
* 非 pi 经 registry.getEngine 动态获取(P4:引擎身份归属注册表,未注册 id 抛
|
|
257
|
+
* EngineNotFoundError——路由期已前置校验,这里是防御性兜底)。
|
|
258
|
+
*/
|
|
259
|
+
private engineFor(engineId: string): EnginePort {
|
|
260
|
+
if (engineId === "pi") return this.piEngine;
|
|
261
|
+
return getEngine(engineId);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* 三层路由输入装配(D9):调用参数(opts.engine,workflow step 级透传)> agent
|
|
266
|
+
* frontmatter(ModelConfigService.getAgentConfig——loadByPath mtime 缓存,幂等)>
|
|
267
|
+
* 全局默认(config.json defaultEngine)。单例未就绪(session_start 前/测试 mock)
|
|
268
|
+
* 时各层缺省——落内置 'pi'。
|
|
269
|
+
*/
|
|
270
|
+
private buildRoutingInput(opts: AgentCallOpts): EngineRoutingInput {
|
|
271
|
+
const service = getModelConfigService();
|
|
272
|
+
const agentEngine =
|
|
273
|
+
opts.agent !== undefined && opts.agent !== "" ? service?.getAgentConfig(opts.agent)?.engine : undefined;
|
|
274
|
+
const globalDefault = service?.getGlobalConfig().defaultEngine;
|
|
275
|
+
return {
|
|
276
|
+
...(opts.engine !== undefined && opts.engine !== "" ? { callEngine: opts.engine } : {}),
|
|
277
|
+
...(agentEngine !== undefined && agentEngine !== "" ? { agentEngine } : {}),
|
|
278
|
+
...(globalDefault !== undefined && globalDefault !== "" ? { globalDefaultEngine: globalDefault } : {}),
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/** 路由期错误 → AgentResult.error(错误码前缀格式保留——engine_not_found 等)。 */
|
|
284
|
+
function errorResult(err: unknown, startedAt: number): AgentResult {
|
|
285
|
+
return {
|
|
286
|
+
content: "",
|
|
287
|
+
durationMs: Date.now() - startedAt,
|
|
288
|
+
error: err instanceof Error ? err.message : String(err),
|
|
289
|
+
toolCalls: [],
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/** handle.journalPath 回填(一次写者:SAR 是 handle 的首个消费者)。 */
|
|
294
|
+
function backfillJournalPath(handle: EngineHandle, journalPath: string): void {
|
|
295
|
+
handle.data.journalPath = journalPath;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* AgentOutcome → workflow AgentResult:剥离引擎层新增字段(engineId/engineFallback/
|
|
300
|
+
* exitCode——engineFallback 经 record(pi 路径)/outcome(zcode 路径)留痕,GUI 投影
|
|
301
|
+
* 通道在后续 wave 接线,workflow 引擎不消费)。其余字段由 PiEngine 从 executeAndAwait
|
|
302
|
+
* 的返回值逐字段映射而来,字段全集完整性由 pi-engine 单测锁定(缺字段会在该处转红,
|
|
303
|
+
* 不会静默丢失)。
|
|
304
|
+
*/
|
|
305
|
+
function outcomeToRunnerResult(outcome: AgentOutcome): AgentResult {
|
|
306
|
+
return {
|
|
307
|
+
content: outcome.content,
|
|
308
|
+
parsedOutput: outcome.parsedOutput,
|
|
309
|
+
usage: outcome.usage,
|
|
310
|
+
durationMs: outcome.durationMs,
|
|
311
|
+
error: outcome.error,
|
|
312
|
+
sessionId: outcome.sessionId,
|
|
313
|
+
sessionFile: outcome.sessionFile,
|
|
314
|
+
worktreePath: outcome.worktreePath,
|
|
315
|
+
toolCalls: outcome.toolCalls,
|
|
316
|
+
};
|
|
121
317
|
}
|
package/src/execution/types.ts
CHANGED
|
@@ -61,6 +61,37 @@ export type ExecutionStatus = "running" | "closed";
|
|
|
61
61
|
*/
|
|
62
62
|
export type ClosedReason = 'parent-shutdown' | 'parent-fork' | 'parent-new' | 'user-close' | 'cancelled' | 'gc';
|
|
63
63
|
|
|
64
|
+
/** ClosedReason 全枚举值(运行时守卫用——防御性解析外部输入时校验成员资格)。 */
|
|
65
|
+
export const CLOSED_REASONS: readonly ClosedReason[] = [
|
|
66
|
+
'parent-shutdown',
|
|
67
|
+
'parent-fork',
|
|
68
|
+
'parent-new',
|
|
69
|
+
'user-close',
|
|
70
|
+
'cancelled',
|
|
71
|
+
'gc',
|
|
72
|
+
];
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* 终态三态对外语义(U3 C-outcome 一等披露)。
|
|
76
|
+
*
|
|
77
|
+
* 由 completeRecord 唯一写入点按 deriveOutcome 一次计算(判定顺序:cancelled 优先
|
|
78
|
+
* → error 非空 → completed),消费方(project/list/notify 文案/渲染器)只读本字段,
|
|
79
|
+
* 不再各自手写成败推导 switch(三处同构 switch 已随 U3 收敛删除)。
|
|
80
|
+
*
|
|
81
|
+
* [D6 显式取舍] parent-shutdown/parent-fork/parent-new 合成关闭(subagent-service
|
|
82
|
+
* disposeAllRecords 合成 result 恒写 error:"closed due to ...")落 "failed"——语义为
|
|
83
|
+
* 「父进程关闭时子 agent 未完成即失败」,选定行为而非疏漏,勿当 bug 改回 cancelled。
|
|
84
|
+
*/
|
|
85
|
+
export type ExecutionOutcome = "completed" | "failed" | "cancelled";
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* 对外投影的 outcome 联合:含历史 record(outcome 字段诞生前的存量数据)兼容态。
|
|
89
|
+
* 投影层(projectOutcome 唯一出口)对无 outcome 字段的 closed record 按
|
|
90
|
+
* deriveOutcome(closedReason, error) 兜底派生;"closed-legacy" 预留给连派生输入都
|
|
91
|
+
* 不足以判读的存量形态,消费方必须处理该成员(不得因未知值崩溃)。
|
|
92
|
+
*/
|
|
93
|
+
export type ProjectedOutcome = ExecutionOutcome | "closed-legacy";
|
|
94
|
+
|
|
64
95
|
/**
|
|
65
96
|
* 对外四态(设计决策 10 细则 3):内部 ExecutionStatus(v4 B-1 两态)收敛为 agent
|
|
66
97
|
* 可理解的状态语义。真实映射只有两条:
|
|
@@ -88,6 +119,15 @@ export type ExecutionMode = "background";
|
|
|
88
119
|
*
|
|
89
120
|
* 设计:AgentEvent 携带 updateFromEvent 收口进 record 所需的**全部数据**——
|
|
90
121
|
* tool_end 带 result(供 turn.toolCalls 存完整 ToolCall),无需翻译层旁路累积。
|
|
122
|
+
*
|
|
123
|
+
* ACP 词汇对照(D11 注记级校准,零行为变更;新引擎实现者按本表对齐语义,
|
|
124
|
+
* 详见 docs/architecture/subagent-engine-gui-visibility.md §3.3 D11):
|
|
125
|
+
* text_delta / thinking_delta ↔ ACP content blocks(text / thinking)
|
|
126
|
+
* tool_start / tool_end ↔ ACP tool_call / tool_call_update
|
|
127
|
+
* turn_end / message_end ↔ ACP prompt turn 终态(stop_reason + usage)
|
|
128
|
+
* compaction ↔ ACP session/compaction
|
|
129
|
+
* 本协议以 pi 为语义锚点(D3)——命名不迁移,对照表仅保证未来 AcpEngine 适配器
|
|
130
|
+
* 与跨引擎 trace 映射的翻译成本最低。
|
|
91
131
|
*/
|
|
92
132
|
export type AgentEvent =
|
|
93
133
|
| { type: "tool_start"; toolName: string; args?: unknown }
|
|
@@ -384,6 +424,23 @@ export interface ExecutionRecord {
|
|
|
384
424
|
* 向后兼容:旧 record 无此字段,按默认值处理。
|
|
385
425
|
*/
|
|
386
426
|
readonly idleTimeoutMs?: number;
|
|
427
|
+
/**
|
|
428
|
+
* 实际执行引擎 id(P4 路由留痕,D9①)。创建时确定不可变;缺省(存量 record)
|
|
429
|
+
* = pi 投影(消费方零迁移)。持久化经 subagent-record entry。
|
|
430
|
+
*/
|
|
431
|
+
readonly engine?: string;
|
|
432
|
+
/**
|
|
433
|
+
* 引擎 fallback 留痕(D9①:probe 失败路由回默认引擎)。GUI 警告条数据源;
|
|
434
|
+
* 缺省 = 无 fallback。持久化经 subagent-record entry。
|
|
435
|
+
*/
|
|
436
|
+
readonly engineFallback?: { from: string; reason: string };
|
|
437
|
+
/**
|
|
438
|
+
* 引擎自描述定位符(U2:非 pi run resolve 后回填、终态迁移落 entry 前——run 前
|
|
439
|
+
* 缺省不可用)。sessionRef 整体透传(失败终态 sessionId 缺失时仍回填已有部分,
|
|
440
|
+
* 读侧①级降②级的防御形态);journalPath 为 retarget 后实际落盘路径。pi 分支不
|
|
441
|
+
* 回填(sessionFile 即定位符)。持久化经 subagent-record entry。
|
|
442
|
+
*/
|
|
443
|
+
engineHandle?: { sessionRef: Record<string, string>; journalPath?: string; poolKey: string };
|
|
387
444
|
|
|
388
445
|
// ── 状态(实时更新)──
|
|
389
446
|
status: ExecutionStatus;
|
|
@@ -391,6 +448,12 @@ export interface ExecutionRecord {
|
|
|
391
448
|
* 由 tryTransition(record, "closed", reason) 写入;投影层按需派生对外语义。
|
|
392
449
|
* 向后兼容:旧 record 无此字段,按 gc 处理(通用完成/失败)。 */
|
|
393
450
|
closedReason?: ClosedReason;
|
|
451
|
+
/**
|
|
452
|
+
* 终态三态对外语义(U3 C-outcome)。completeRecord 唯一写入点按 deriveOutcome
|
|
453
|
+
* 一次计算,消费方只读本字段不再自行推导。向后兼容:旧 record / 磁盘重建
|
|
454
|
+
* record 无此字段,投影层按 projectOutcome 兜底(closed-legacy 语义)。
|
|
455
|
+
*/
|
|
456
|
+
outcome?: ExecutionOutcome;
|
|
394
457
|
/** 完整执行内容,按 turn 组织。createRecord 初始化为 [空 turn]。 */
|
|
395
458
|
turns: Turn[];
|
|
396
459
|
/** turn 计数(= turns.filter(closed).length,冗余存储供投影直接读)。 */
|
|
@@ -494,6 +557,11 @@ export interface ExecutionRecord {
|
|
|
494
557
|
*/
|
|
495
558
|
export interface SubagentToolDetails {
|
|
496
559
|
status: ExecutionStatus;
|
|
560
|
+
/**
|
|
561
|
+
* 终态三态对外语义(U3 C-outcome,projectOutcome 唯一出口)。running → undefined;
|
|
562
|
+
* 历史数据无 outcome 字段时兜底派生(见 ProjectedOutcome)。
|
|
563
|
+
*/
|
|
564
|
+
outcome?: ProjectedOutcome;
|
|
497
565
|
mode: ExecutionMode;
|
|
498
566
|
agent: string;
|
|
499
567
|
model: string;
|
|
@@ -538,6 +606,10 @@ export interface ExecuteOptions {
|
|
|
538
606
|
schema?: Record<string, unknown>;
|
|
539
607
|
/** D-A6 bridge: workflow schemaEnv 经 ExecuteOptions 透传到 runSpawn childEnv。 */
|
|
540
608
|
schemaEnv?: string;
|
|
609
|
+
/**
|
|
610
|
+
* Turn 上限 limiter。显式 0/负 = 显式不限:压过 SPAWN_WATCHDOG_ENV 兑底不挂
|
|
611
|
+
* watchdog(SP-6 参数 > env,U5);undefined 未传才由 env 兑底。
|
|
612
|
+
*/
|
|
541
613
|
maxTurns?: number;
|
|
542
614
|
graceTurns?: number;
|
|
543
615
|
/** sync 模式来自 Pi tool 框架;background 模式 hub 忽略,自建 controller。 */
|
|
@@ -561,8 +633,19 @@ export interface ExecuteOptions {
|
|
|
561
633
|
/**
|
|
562
634
|
* 空闲超时毫秒数(仅 conversation 模式有意义)。覆盖默认 5min idle timeout。
|
|
563
635
|
* 优先级:参数 > env XYZ_SUBAGENT_IDLE_TIMEOUT_MS > 默认 300000ms。
|
|
636
|
+
* 显式传 0/负数 = 禁用 idle GC(不挂 timer;旧实现 0 会落成 setTimeout(0) 立即 kill)。
|
|
564
637
|
*/
|
|
565
638
|
idleTimeoutMs?: number;
|
|
639
|
+
/**
|
|
640
|
+
* 实际执行引擎 id(P4 路由留痕):pi 引擎由 PiEngine.run 在还原 opts 时写入;
|
|
641
|
+
* 缺省(历史调用方不设)= pi 投影。createRecordForMode 读入 record identity。
|
|
642
|
+
*/
|
|
643
|
+
engine?: string;
|
|
644
|
+
/**
|
|
645
|
+
* 引擎 fallback 留痕(D9①:probe 失败路由回默认引擎时由路由层写入)。
|
|
646
|
+
* from = 请求引擎 id,reason 恒 'engine_probe_failed'(GUI 警告条数据源)。
|
|
647
|
+
*/
|
|
648
|
+
engineFallback?: { from: string; reason: string };
|
|
566
649
|
// 注:fork 深度不从外部传入(曾暴露 parentForkDepth,改用 ALS 后 execute 内部从调用链派生,
|
|
567
650
|
// 公开字段成为死字段误导调用方,已移除)。深度限制检查见 session-runner.ts 内部 RunOptions.parentForkDepth
|
|
568
651
|
// (与历史残留的 types.ts RunOptions 同名不同 interface——后者已删除)。
|
|
@@ -607,10 +690,13 @@ export interface SubagentListItem {
|
|
|
607
690
|
/** 可冷路径 resume(running 且无活进程句柄)。[v4 A-6] B-1「可续聊」对外表达,
|
|
608
691
|
* agent 据 list 判断哪些 running subagent 实际可续聊(vs 正在忙)。 */
|
|
609
692
|
resumable?: boolean;
|
|
610
|
-
/**
|
|
611
|
-
*
|
|
612
|
-
*
|
|
613
|
-
|
|
693
|
+
/**
|
|
694
|
+
* 终态三态对外语义(U3 C-outcome 一等披露,projectOutcome 唯一出口):
|
|
695
|
+
* completed / failed / cancelled,历史 record 无 outcome 字段时兜底派生,
|
|
696
|
+
* 不可判读的存量形态为 "closed-legacy"。GUI pane / agent 据此判读成败,
|
|
697
|
+
* 无需翻 error 字段原文(S5)。
|
|
698
|
+
*/
|
|
699
|
+
outcome?: ProjectedOutcome;
|
|
614
700
|
}
|
|
615
701
|
|
|
616
702
|
/** background 启动的内层响应(挂在 SubagentToolResult.bgResponse)。 */
|
|
@@ -619,6 +705,19 @@ export interface BgResponse {
|
|
|
619
705
|
mode: "background";
|
|
620
706
|
/** 启动提示文案("detached, will notify on completion")。 */
|
|
621
707
|
message: string;
|
|
708
|
+
/**
|
|
709
|
+
* 终态三态语义(U3 C-outcome 对外 JSON 契约完备位)。start 时点 record 尚未终态,
|
|
710
|
+
* 恒 undefined(JSON.stringify 落键省略);终态成败语义经 list items[].outcome
|
|
711
|
+
* 披露。旧字段 status/mode/message 原样保留(向后兼容)。
|
|
712
|
+
*/
|
|
713
|
+
outcome?: ProjectedOutcome;
|
|
714
|
+
/**
|
|
715
|
+
* 通知投递契约回显位(U1 预置,U2 通知账本的契约声明)。恒值
|
|
716
|
+
* "ledger+at-least-once":主 agent 在当前 run 结束或有限延迟内收到完成通知,
|
|
717
|
+
* 送达保证为 at-least-once + notifyId 幂等可识别。字段与填充由 U1 负责,
|
|
718
|
+
* 值语义由 U2(execution/notify-ledger.ts)兑现。
|
|
719
|
+
*/
|
|
720
|
+
notifyContract: "ledger+at-least-once";
|
|
622
721
|
}
|
|
623
722
|
|
|
624
723
|
/** list 的内层响应(挂在 SubagentToolResult.listResponse)。 */
|
|
@@ -661,7 +760,7 @@ export interface CloseResponse {
|
|
|
661
760
|
* - close → closeResponse(subagentId 有值;sessionFile 无意义,可为 null)
|
|
662
761
|
*/
|
|
663
762
|
export type SubagentToolResult =
|
|
664
|
-
| { action: "start"; subagentId: string; sessionFile: string | null; slug: string; bgResponse: BgResponse; __gui__?: GuiRenderResult }
|
|
763
|
+
| { action: "start"; subagentId: string; sessionFile: string | null; slug: string; /** registry 全等回显(U1):放行即与 registry 条目全等,"provider/id" 形态。 */ model: string; bgResponse: BgResponse; __gui__?: GuiRenderResult }
|
|
665
764
|
| { action: "list"; subagentId: null; sessionFile: null; listResponse: ListResponse; __gui__?: GuiRenderResult }
|
|
666
765
|
| { action: "cancel"; subagentId: string; sessionFile: null; cancelResponse: CancelResponse; __gui__?: GuiRenderResult }
|
|
667
766
|
| { action: "message"; subagentId: string; sessionFile: null; messageResponse: MessageResponse; __gui__?: GuiRenderResult }
|
|
@@ -731,6 +830,19 @@ export interface SubagentRecord {
|
|
|
731
830
|
externalInstance?: AliveMarker;
|
|
732
831
|
/** fork 模式下的 worktree handle。 */
|
|
733
832
|
worktreeHandle?: WorktreeHandle;
|
|
833
|
+
/**
|
|
834
|
+
* 实际执行引擎 id(P4 路由留痕)。缺省 = pi 投影(存量 record 零迁移);
|
|
835
|
+
* GUI 警告条/引擎标记的数据源之一。
|
|
836
|
+
*/
|
|
837
|
+
engine?: string;
|
|
838
|
+
/** 引擎 fallback 留痕(D9①:probe 失败路由回默认引擎)。GUI 警告条数据源。 */
|
|
839
|
+
engineFallback?: { from: string; reason: string };
|
|
840
|
+
/**
|
|
841
|
+
* 引擎自描述定位符(U1:EngineHandleData 的持久化消费面子集,引擎无关——
|
|
842
|
+
* sessionRef 整体透传不枚举内部键)。read 降级链①②级的数据源(runtime
|
|
843
|
+
* subagent-engine-history);缺省 = pi(走 JSONL 直读链)。
|
|
844
|
+
*/
|
|
845
|
+
engineHandle?: { sessionRef: Record<string, string>; journalPath?: string; poolKey: string };
|
|
734
846
|
}
|
|
735
847
|
|
|
736
848
|
// ============================================================
|
|
@@ -747,6 +859,13 @@ export interface SubagentRecord {
|
|
|
747
859
|
export interface SubagentsGlobalConfig {
|
|
748
860
|
version: number;
|
|
749
861
|
maxConcurrent: number;
|
|
862
|
+
/**
|
|
863
|
+
* 全局默认执行引擎(D9 三层优先级的最底层:调用参数 > agent frontmatter > 本值)。
|
|
864
|
+
* 缺省 'pi'(P4 路由层 DEFAULT_ENGINE_ID)。加载期只做类型校验,注册表校验归路由层。
|
|
865
|
+
*/
|
|
866
|
+
defaultEngine?: string;
|
|
867
|
+
/** 引擎路由策略(D9①):strict=true 时一切 probe 失败直接报错(不 fallback)。 */
|
|
868
|
+
engineRouting?: { strict: boolean };
|
|
750
869
|
}
|
|
751
870
|
|
|
752
871
|
// ============================================================
|
|
@@ -55,10 +55,20 @@ export function createUiRequestQueue(
|
|
|
55
55
|
if (processing || queue.length === 0 || closed) return;
|
|
56
56
|
processing = true;
|
|
57
57
|
const { id, request, signal } = queue.shift()!;
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
// [F2] .catch 在 .finally 之前:handleUiRequest 是 async 函数,任何同步异常(parseChannel
|
|
59
|
+
// 解析 throw / respond → writeStdinLine 的 EPIPE 同步 throw / catch 分支内 respond 再次
|
|
60
|
+
// throw)都会变成 rejection。旧链只有 .finally——rejection 穿透后无人接 →
|
|
61
|
+
// unhandledRejection(Node 15+ 默认 mode=throw)可崩父进程。记 error 后吞掉,
|
|
62
|
+
// .finally 照常释放 processing 推进队列(单个请求失败不阻塞后续 UI 请求)。
|
|
63
|
+
handleUiRequest(child, id, request, ctx, signal)
|
|
64
|
+
.catch((err: unknown) => {
|
|
65
|
+
const m = err instanceof Error ? err.message : String(err);
|
|
66
|
+
logger.error(`[subagents] ui request ${id} (${request.method}) failed unexpectedly: ${m}`);
|
|
67
|
+
})
|
|
68
|
+
.finally(() => {
|
|
69
|
+
processing = false;
|
|
70
|
+
processNext();
|
|
71
|
+
});
|
|
62
72
|
}
|
|
63
73
|
|
|
64
74
|
// [R3] 子进程退出时 abort 所有 pending handler,队列不再阻塞
|