@zhushanwen/pi-subagent-workflow 0.1.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/agents/context-builder.md +17 -0
- package/agents/general-purpose.md +16 -0
- package/agents/oracle.md +17 -0
- package/agents/planner.md +17 -0
- package/agents/researcher.md +17 -0
- package/agents/reviewer.md +17 -0
- package/agents/scout.md +17 -0
- package/agents/worker.md +16 -0
- package/examples/README.md +43 -0
- package/examples/chain.example.js +92 -0
- package/examples/map-reduce.example.js +99 -0
- package/examples/parallel.example.js +82 -0
- package/examples/scatter-gather.example.js +106 -0
- package/index.ts +1 -0
- package/package.json +66 -0
- package/skills/workflow-script-format/SKILL.md +328 -0
- package/src/execution/__tests__/agent-registry.test.ts +164 -0
- package/src/execution/__tests__/agent-result-mapper.test.ts +128 -0
- package/src/execution/__tests__/alive-store.test.ts +147 -0
- package/src/execution/__tests__/bg-notify-render.test.ts +256 -0
- package/src/execution/__tests__/concurrency-pool.test.ts +217 -0
- package/src/execution/__tests__/config.test.ts +110 -0
- package/src/execution/__tests__/crash-recovery.test.ts +311 -0
- package/src/execution/__tests__/execute-nesting.test.ts +359 -0
- package/src/execution/__tests__/execute-options-mapper.test.ts +138 -0
- package/src/execution/__tests__/execution-record.test.ts +959 -0
- package/src/execution/__tests__/finalized-marker.test.ts +82 -0
- package/src/execution/__tests__/format-schema-instruction.test.ts +135 -0
- package/src/execution/__tests__/format.test.ts +320 -0
- package/src/execution/__tests__/helpers/mock-extension-api.ts +30 -0
- package/src/execution/__tests__/list-component.test.ts +347 -0
- package/src/execution/__tests__/model-resolver.test.ts +356 -0
- package/src/execution/__tests__/output-collector.test.ts +61 -0
- package/src/execution/__tests__/path-encoding.test.ts +75 -0
- package/src/execution/__tests__/pi-invocation.test.ts +73 -0
- package/src/execution/__tests__/record-store.test.ts +545 -0
- package/src/execution/__tests__/run-spawn-edges.test.ts +439 -0
- package/src/execution/__tests__/run-spawn-integration.test.ts +897 -0
- package/src/execution/__tests__/sdk-contract.test.ts +272 -0
- package/src/execution/__tests__/session-context-resolver.test.ts +167 -0
- package/src/execution/__tests__/session-file-gc.test.ts +247 -0
- package/src/execution/__tests__/session-reconstructor.test.ts +359 -0
- package/src/execution/__tests__/session-runner-schema-env.test.ts +314 -0
- package/src/execution/__tests__/session-start-reaper.test.ts +227 -0
- package/src/execution/__tests__/spawn-args.test.ts +244 -0
- package/src/execution/__tests__/spawn-event-adapter.test.ts +167 -0
- package/src/execution/__tests__/subagent-service.test.ts +678 -0
- package/src/execution/__tests__/subprocess-agent-runner.test.ts +389 -0
- package/src/execution/__tests__/temp-prompt.test.ts +53 -0
- package/src/execution/__tests__/timeout-integration.test.ts +381 -0
- package/src/execution/__tests__/tombstone-store.test.ts +73 -0
- package/src/execution/__tests__/tool-action.test.ts +330 -0
- package/src/execution/__tests__/turn-limiter.test.ts +65 -0
- package/src/execution/__tests__/worktree-manager.test.ts +423 -0
- package/src/execution/__tests__/worktree-registry.test.ts +161 -0
- package/src/execution/agent-registry.ts +252 -0
- package/src/execution/agent-result-mapper.ts +84 -0
- package/src/execution/alive-store.ts +92 -0
- package/src/execution/best-effort.ts +30 -0
- package/src/execution/concurrency-pool.ts +84 -0
- package/src/execution/config.ts +73 -0
- package/src/execution/execute-options-mapper.ts +86 -0
- package/src/execution/execution-record.ts +778 -0
- package/src/execution/finalized-marker.ts +51 -0
- package/src/execution/model-config-service.ts +225 -0
- package/src/execution/model-resolver.ts +247 -0
- package/src/execution/notifier.ts +168 -0
- package/src/execution/output-collector.ts +88 -0
- package/src/execution/path-encoding.ts +34 -0
- package/src/execution/pi-invocation.ts +70 -0
- package/src/execution/record-store.ts +350 -0
- package/src/execution/session-context-resolver.ts +64 -0
- package/src/execution/session-file-gc.ts +98 -0
- package/src/execution/session-reconstructor.ts +450 -0
- package/src/execution/session-runner.ts +725 -0
- package/src/execution/spawn-event-adapter.ts +150 -0
- package/src/execution/subagent-service.ts +973 -0
- package/src/execution/subprocess-agent-runner.ts +108 -0
- package/src/execution/temp-prompt.ts +57 -0
- package/src/execution/tombstone-store.ts +72 -0
- package/src/execution/turn-limiter.ts +88 -0
- package/src/execution/types.ts +634 -0
- package/src/execution/worktree-manager.ts +285 -0
- package/src/execution/worktree-registry.ts +144 -0
- package/src/index.ts +454 -0
- package/src/interface/bg-notify-render.ts +286 -0
- package/src/interface/commands.ts +157 -0
- package/src/interface/format.ts +501 -0
- package/src/interface/gui-adapter.ts +136 -0
- package/src/interface/helpers.ts +110 -0
- package/src/interface/list-component.ts +643 -0
- package/src/interface/list-shared.ts +84 -0
- package/src/interface/list-view.ts +373 -0
- package/src/interface/reentry-guard.ts +30 -0
- package/src/interface/subagent-actions.ts +294 -0
- package/src/interface/subagent-tool.ts +294 -0
- package/src/interface/subagents.ts +30 -0
- package/src/interface/tool-render.ts +333 -0
- package/src/interface/tool-workflow-script.ts +351 -0
- package/src/interface/tool-workflow.ts +485 -0
- package/src/interface/views/WorkflowsView.ts +944 -0
- package/src/interface/views/detail-content.ts +298 -0
- package/src/interface/views/format.ts +320 -0
- package/src/orchestration/__tests__/concurrency-gate.test.ts +125 -0
- package/src/orchestration/__tests__/config-loader.test.ts +381 -0
- package/src/orchestration/__tests__/error-recovery-handlers.test.ts +332 -0
- package/src/orchestration/__tests__/error-recovery-workflow-call.test.ts +166 -0
- package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +248 -0
- package/src/orchestration/__tests__/lifecycle.test.ts +385 -0
- package/src/orchestration/__tests__/script-lint.test.ts +347 -0
- package/src/orchestration/__tests__/worker-script-builder.test.ts +42 -0
- package/src/orchestration/__tests__/workflow-nesting-e2e.test.ts +319 -0
- package/src/orchestration/agent-opts-resolver.ts +128 -0
- package/src/orchestration/concurrency-gate.ts +69 -0
- package/src/orchestration/config-loader.ts +313 -0
- package/src/orchestration/error-recovery.ts +578 -0
- package/src/orchestration/execute-agent-call.ts +174 -0
- package/src/orchestration/jsonl-run-store.ts +292 -0
- package/src/orchestration/launcher.ts +368 -0
- package/src/orchestration/lifecycle.ts +373 -0
- package/src/orchestration/models/__tests__/budget.test.ts +367 -0
- package/src/orchestration/models/agent-call.ts +76 -0
- package/src/orchestration/models/budget.ts +148 -0
- package/src/orchestration/models/ports.ts +165 -0
- package/src/orchestration/models/run-runtime.ts +91 -0
- package/src/orchestration/models/run-spec.ts +54 -0
- package/src/orchestration/models/run-state.ts +44 -0
- package/src/orchestration/models/trace.ts +102 -0
- package/src/orchestration/models/types.ts +242 -0
- package/src/orchestration/models/workflow-run.ts +275 -0
- package/src/orchestration/models/workflow-script-registry.ts +32 -0
- package/src/orchestration/models/workflow-script.ts +90 -0
- package/src/orchestration/node-ops.ts +192 -0
- package/src/orchestration/script-lint.ts +387 -0
- package/src/orchestration/skill-discovery.ts +60 -0
- package/src/orchestration/worker-handle.ts +115 -0
- package/src/orchestration/worker-host.ts +93 -0
- package/src/orchestration/worker-script-builder.ts +281 -0
- package/src/orchestration/workflow-files.ts +85 -0
- package/src/orchestration/workflow-script-registry-impl.ts +128 -0
- package/src/shared/__tests__/resource-discovery.test.ts +226 -0
- package/src/shared/agent-event.ts +13 -0
- package/src/shared/resource-discovery.ts +535 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow Extension — Engine Ports + 编排层共享类型
|
|
3
|
+
*
|
|
4
|
+
* 3 个注入 Port(AgentRunner / RunStore / WorkerHost)——Engine 定义、Infra 实现,
|
|
5
|
+
* 是真需要 mock 测试的依赖(子进程/文件系统/线程)。
|
|
6
|
+
*
|
|
7
|
+
* 编排层共享类型(WorkerHandlers / LifecycleDeps)——打破 lifecycle ↔
|
|
8
|
+
* error-recovery ↔ node-ops 循环依赖:3 个 engine 函数文件各自独立,共用同一组
|
|
9
|
+
* 依赖签名(D-12)。
|
|
10
|
+
*
|
|
11
|
+
* 层归属:Engine。零 infra 依赖(AC-1)。
|
|
12
|
+
*/
|
|
13
|
+
import type { AgentEvent } from "../../shared/agent-event.ts";
|
|
14
|
+
import type { AgentRegistry } from "../../execution/agent-registry.ts";
|
|
15
|
+
import type { WorkerHandle } from "../worker-handle.ts";
|
|
16
|
+
import type { RunSpec } from "./run-spec.ts";
|
|
17
|
+
import type { AgentCallOpts, AgentResult } from "./types.ts";
|
|
18
|
+
import type { WorkflowRun } from "./workflow-run.ts";
|
|
19
|
+
|
|
20
|
+
// ── Port 1: AgentRunner ───────────────────────────────────────
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Agent 子进程执行 port。Infra 实现:SubprocessAgentRunner。
|
|
24
|
+
*
|
|
25
|
+
* run 执行单次 agent 调用(委托 SubagentService.executeAndAwait),返回结构化结果。
|
|
26
|
+
* signal 用于 abort 传播。
|
|
27
|
+
*
|
|
28
|
+
* onEvent(可选):强类型 AgentEvent 回调,供调用方实时更新 live record 供 TUI 展示进度。
|
|
29
|
+
* 不传则不回调(向后兼容;现有调用点不传不受影响)。
|
|
30
|
+
*
|
|
31
|
+
* D-005: onEvent 签名从 raw Record<string,unknown> 升级为 AgentEvent——委托后不再有
|
|
32
|
+
* raw JSONL 中间层(executeAndAwait 直接出 AgentEvent,session-runner handleSdkEvent 出口)。
|
|
33
|
+
*/
|
|
34
|
+
export interface AgentRunner {
|
|
35
|
+
run(opts: AgentCallOpts, signal: AbortSignal, onEvent?: (event: AgentEvent) => void): Promise<AgentResult>;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// ── Port 2: RunStore ──────────────────────────────────────────
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* WorkflowRun 持久化 port。Infra 实现:JsonlRunStore。
|
|
42
|
+
*
|
|
43
|
+
* save 在每次状态变更后持久化整个 WorkflowRun(聚合根);
|
|
44
|
+
* loadAll 在 session_start 时重水合(D-5:JSONL 不向后兼容旧 session,旧格式返回空)。
|
|
45
|
+
*/
|
|
46
|
+
export interface RunStore {
|
|
47
|
+
save(run: WorkflowRun): Promise<void>;
|
|
48
|
+
loadAll(): Promise<WorkflowRun[]>;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// ── Port 3: WorkerHost ────────────────────────────────────────
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Worker 线程启动 port。Infra 实现:WorkerHostImpl。
|
|
55
|
+
*
|
|
56
|
+
* start 创建一个 Worker thread 运行 workflow 脚本,返回 WorkerHandle。
|
|
57
|
+
* handlers 绑定 message/error/exit 回调(见 WorkerHandlers)。
|
|
58
|
+
*/
|
|
59
|
+
export interface WorkerHost {
|
|
60
|
+
start(
|
|
61
|
+
spec: RunSpec,
|
|
62
|
+
args: Record<string, unknown>,
|
|
63
|
+
handlers: WorkerHandlers,
|
|
64
|
+
): WorkerHandle;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// ── 编排层共享类型 1: WorkerHandlers ───────────────────────────
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Worker 线程事件回调集合——WorkerHost.start 的入参,由 lifecycle
|
|
71
|
+
* 构造并注入。3 个 engine 文件(lifecycle / error-recovery / node-ops)共用此签名,
|
|
72
|
+
* 避免各自定义形状不一致的 handler bag(打破循环依赖)。
|
|
73
|
+
*
|
|
74
|
+
* 所有回调返回 Promise——允许 engine 层在回调内做 await persistState 等异步操作。
|
|
75
|
+
*/
|
|
76
|
+
export interface WorkerHandlers {
|
|
77
|
+
/** Worker → Main 的业务消息(agent-call / return / error / log)。 */
|
|
78
|
+
onMessage(raw: unknown): Promise<void>;
|
|
79
|
+
/** Worker 线程 uncaught error。 */
|
|
80
|
+
onError(err: Error): Promise<void>;
|
|
81
|
+
/** Worker 线程 exit(含 code,用于区分正常退出 vs 崩溃)。handle 用于竞态防护 G-025。 */
|
|
82
|
+
onExit(code: number, handle: WorkerHandle): Promise<void>;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// ── 编排层共享类型 2: LifecycleDeps ────────────────────────────
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* lifecycle / error-recovery / node-ops 3 个 engine 函数文件的共同依赖 bag。
|
|
89
|
+
*
|
|
90
|
+
* 取代旧 4 个 Context factory(errorHandlerContext / agentCallContext /
|
|
91
|
+
* budgetCallbacks / 旧 terminate bag,AC-2 目标)。函数签名 `(deps: LifecycleDeps, ...)`
|
|
92
|
+
* 让每个 free function 自包含依赖,无需 God Facade 中介。
|
|
93
|
+
*
|
|
94
|
+
* - store: 持久化(RunStore port)
|
|
95
|
+
* - workerHost: 启动 worker(WorkerHost port)
|
|
96
|
+
* - runner: 执行 agent(AgentRunner port)
|
|
97
|
+
* - runs: 内存中的活动 run 聚合根索引(runId → WorkflowRun),替代旧 6 张并行 map
|
|
98
|
+
* - onRunDone?: run 到达 done 终态时的回调(C-4 修复,可选)。由 Interface 层
|
|
99
|
+
* factory 注入(notifyDone —— 唤醒 parent agent 消费结果)。Engine 层不依赖
|
|
100
|
+
* Pi SDK,通过 callback 把完成信号外推到 Interface 层。所有 transition("done", ...)
|
|
101
|
+
* 路径(handleReturn / handleWorkerError / handleScriptError / abortRun /
|
|
102
|
+
* dispatchAgentCall budget 终止)调完 transition + save 后触发本回调。
|
|
103
|
+
*/
|
|
104
|
+
export interface LifecycleDeps {
|
|
105
|
+
store: RunStore;
|
|
106
|
+
workerHost: WorkerHost;
|
|
107
|
+
runner: AgentRunner;
|
|
108
|
+
runs: Map<string, WorkflowRun>;
|
|
109
|
+
/** run 到达 done 终态时的回调(C-4 修复,可选)。Interface 层注入 notifyDone。 */
|
|
110
|
+
onRunDone?: (run: WorkflowRun) => void;
|
|
111
|
+
/**
|
|
112
|
+
* 跨扩展事件总线(pending-notifications register/unregister 信号灯)。
|
|
113
|
+
*
|
|
114
|
+
* runWorkflow 启动时 emit pending:register;所有 transition("done") 路径 emit
|
|
115
|
+
* pending:unregister。两处均通过本端口(Engine 不直接依赖 Pi SDK)。可选——
|
|
116
|
+
* 无 pending-notifications 扩展时 no-op(向后兼容)。
|
|
117
|
+
*/
|
|
118
|
+
eventBus?: { emit(channel: string, data: unknown): void };
|
|
119
|
+
/**
|
|
120
|
+
* 调试日志端口(Engine 不直接依赖 Pi SDK)。Interface 层注入实现。
|
|
121
|
+
* 关键路径记录 run 启动、保存、pending 注册/注销,便于排查异步操作状态。
|
|
122
|
+
*/
|
|
123
|
+
log?: (level: "debug" | "info" | "warn" | "error", component: string, message: string, data?: unknown) => void;
|
|
124
|
+
/**
|
|
125
|
+
* BL-1:agent/skill/schema 解析依赖(per-session,可选)。
|
|
126
|
+
*
|
|
127
|
+
* Interface 层 factory 在 session_start 注入:agentRegistry(扫描 .agents/agents 等
|
|
128
|
+
* 7 路径)、sessionDir(临时文件根)、activeTempFiles(session_shutdown 回收集合)。
|
|
129
|
+
* error-recovery.dispatchAgentCall 用这 3 项调 resolveAgentOpts,把
|
|
130
|
+
* `agent({agent,skill,schema})` 的 inline override 解析成 systemPromptFiles /
|
|
131
|
+
* skillPath / schemaEnv,否则 pi 子进程只收到原始 prompt(D-12 重构误删导致回归)。
|
|
132
|
+
* 全部可选——测试 makeDeps 工厂无需改。
|
|
133
|
+
*/
|
|
134
|
+
agentRegistry?: AgentRegistry;
|
|
135
|
+
sessionDir?: string;
|
|
136
|
+
activeTempFiles?: Set<string>;
|
|
137
|
+
/**
|
|
138
|
+
* D-12 regression fix (round-2 #2):rebuildRuntime 重新调度 run 级墙钟预算计时器。
|
|
139
|
+
*
|
|
140
|
+
* worker/script 错误重试走 replaceRuntime,旧 RunRuntime 的 release 会 clearTimeout
|
|
141
|
+
* 旧计时器(run-runtime.release)。新 runtime 必须重排 scheduleTimeBudget,否则带
|
|
142
|
+
* budgetTimeMs 的 run 命中一次错误重试后时间预算静默失效(直到下次 pause/resume 才重排)。
|
|
143
|
+
* 由 Interface 层 factory 注入——闭包捕获 deps,内部调 lifecycle.scheduleTimeBudget。
|
|
144
|
+
*
|
|
145
|
+
* 可选——旧测试 deps 不注入时 rebuildRuntime 不重排计时器(兼容,不影响无时间预算的 run)。
|
|
146
|
+
*/
|
|
147
|
+
scheduleTimeBudget?: (
|
|
148
|
+
runId: string,
|
|
149
|
+
budgetTimeMs: number,
|
|
150
|
+
) => ReturnType<typeof setTimeout> | undefined;
|
|
151
|
+
/**
|
|
152
|
+
* workflow() 嵌套调用回调(可选)。Worker 脚本内调 workflow(name, args) 时触发。
|
|
153
|
+
*
|
|
154
|
+
* 由 Interface 层 makeDeps 注入(闭包捕获 registry + deps)。Engine 层的
|
|
155
|
+
* error-recovery.handleWorkerMessage 收到 workflow-call 消息后调本回调,
|
|
156
|
+
* 拿到子 workflow 执行结果后 postMessage(workflow-result) 回 worker。
|
|
157
|
+
*
|
|
158
|
+
* 不注入时 workflow() 返回 error result(向后兼容,不影响非嵌套场景)。
|
|
159
|
+
*/
|
|
160
|
+
onWorkflowCall?: (
|
|
161
|
+
name: string,
|
|
162
|
+
args: Record<string, unknown>,
|
|
163
|
+
parentRun: WorkflowRun,
|
|
164
|
+
) => Promise<unknown>;
|
|
165
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow Extension — Run Runtime
|
|
3
|
+
*
|
|
4
|
+
* 聚合内运行时资源(仅 status==="running" 时存在)。技术资源聚合,
|
|
5
|
+
* Engine 层类型,持 WorkerHandle / ConcurrencyGate 具体类(D-12 不造 interface)。
|
|
6
|
+
*
|
|
7
|
+
* 职责:封装一次 running-segment 的所有技术资源(worker 线程 + 并发信号量 +
|
|
8
|
+
* abort controller),统一 release 入口(AC-2:单 release 替代多 boolean flag)。
|
|
9
|
+
*
|
|
10
|
+
* pause/resume 生命周期(G3-001):
|
|
11
|
+
* - pause 时 WorkflowRun.releaseRuntime 使整个 RunRuntime 丢弃(runtime=undefined)
|
|
12
|
+
* - resume 时 WorkflowRun.assignRuntime(new RunRuntime(...)) 全部重建
|
|
13
|
+
* - 原因:AbortController 一次性语义决定 controller 无法跨 pause/resume 复用,
|
|
14
|
+
* gate 队列也在 worker 重跑脚本 + callCache replay 时清空无影响——所以整个
|
|
15
|
+
* RunRuntime 重建最简单、语义最清晰。
|
|
16
|
+
*
|
|
17
|
+
* 参考:domain-models.md §10、clarification.md G3-001。
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { ConcurrencyGate } from "../concurrency-gate.ts";
|
|
21
|
+
import { WorkerHandle } from "../worker-handle.ts";
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* release mode 枚举——调用方表达意图。
|
|
25
|
+
*
|
|
26
|
+
* 注:pause 与 terminal 在 RunRuntime 内部行为等价(都全释放 worker + controller)。
|
|
27
|
+
* 保留枚举为可读性——调用方语义清晰(lifecycle pauseRun 传 "pause",
|
|
28
|
+
* terminateRun 传 "terminal"),且为未来细分留余地。
|
|
29
|
+
*/
|
|
30
|
+
export type ReleaseMode = "pause" | "terminal";
|
|
31
|
+
|
|
32
|
+
// ── RunRuntime ───────────────────────────────────────────────
|
|
33
|
+
|
|
34
|
+
export class RunRuntime {
|
|
35
|
+
/** Worker 线程句柄。 */
|
|
36
|
+
readonly worker: WorkerHandle;
|
|
37
|
+
/** 并发信号量。 */
|
|
38
|
+
readonly gate: ConcurrencyGate;
|
|
39
|
+
/** per-running-segment AbortController(一次性,无法复用——G3-001)。 */
|
|
40
|
+
readonly controller: AbortController;
|
|
41
|
+
/** Run 级墙钟时间预算计时器(spec.budgetTimeMs > 0 时由 lifecycle 调度,
|
|
42
|
+
* 到期 abortRun time_limited)。release 时清理,避免 pause/abort 后孤儿计时器
|
|
43
|
+
* 仍触发(resume 会重新调度一个全新的计时器,旧的不应残留)。 */
|
|
44
|
+
readonly timeBudgetTimer?: ReturnType<typeof setTimeout>;
|
|
45
|
+
/** 防止 release 重复执行(幂等)。 */
|
|
46
|
+
private released = false;
|
|
47
|
+
|
|
48
|
+
constructor(
|
|
49
|
+
worker: WorkerHandle,
|
|
50
|
+
gate: ConcurrencyGate,
|
|
51
|
+
controller: AbortController,
|
|
52
|
+
timeBudgetTimer?: ReturnType<typeof setTimeout>,
|
|
53
|
+
) {
|
|
54
|
+
this.worker = worker;
|
|
55
|
+
this.gate = gate;
|
|
56
|
+
this.controller = controller;
|
|
57
|
+
this.timeBudgetTimer = timeBudgetTimer;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* 释放所有资源:terminate worker + abort controller。
|
|
62
|
+
*
|
|
63
|
+
* 幂等——重复调用安全(第二次起 no-op,released flag 守卫)。
|
|
64
|
+
* 调用后此 RunRuntime 应被调用方丢弃(WorkflowRun.runtime = undefined),
|
|
65
|
+
* resume/retry 时由 assignRuntime/replaceRuntime 注入新实例(G3-001)。
|
|
66
|
+
*
|
|
67
|
+
* worker.terminate 本身幂等,controller.abort 本身幂等
|
|
68
|
+
* (重复 abort 无副作用),但 released flag 让本方法语义更明确:
|
|
69
|
+
* 「释放过一次的 runtime 不再释放第二次」。
|
|
70
|
+
*
|
|
71
|
+
* @param mode pause | terminal —— 当前等价,保留为调用方表达意图
|
|
72
|
+
*/
|
|
73
|
+
release(_mode: ReleaseMode): void {
|
|
74
|
+
if (this.released) return;
|
|
75
|
+
this.released = true;
|
|
76
|
+
// 清理 run 级时间预算计时器——pause/abort/replaceRuntime 后它不应再触发
|
|
77
|
+
// (resume 会调度全新计时器;孤儿触发会把已 paused/aborted 的 run 误转 done)。
|
|
78
|
+
if (this.timeBudgetTimer) clearTimeout(this.timeBudgetTimer);
|
|
79
|
+
// worker.terminate 异步但幂等——不 await(release 是同步签名,调用方
|
|
80
|
+
// 不应被底层线程关闭阻塞;worker 收到 terminate 后自行清理)。
|
|
81
|
+
void this.worker.terminate();
|
|
82
|
+
// controller.abort 触发 listener(kill agent subprocess、pause workflow)。
|
|
83
|
+
// 一次性语义——已 aborted 的 controller 重复 abort 无副作用。
|
|
84
|
+
this.controller.abort();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** 是否已 release(测试 + 诊断用)。 */
|
|
88
|
+
get isReleased(): boolean {
|
|
89
|
+
return this.released;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow Extension — RunSpec 值对象
|
|
3
|
+
*
|
|
4
|
+
* 单次 workflow run 的不可变规格(domain-models.md §2)。
|
|
5
|
+
*
|
|
6
|
+
* 设计:
|
|
7
|
+
* - 全部字段 readonly——run 一旦创建,规格不可改(状态变化走 RunState)
|
|
8
|
+
* - scriptSource 是已 strip `export const meta` 的可执行源(WorkflowScript.toExecutable)
|
|
9
|
+
* - budgetTokens/budgetTimeMs 是上限(可选,未设 = 不限制)
|
|
10
|
+
*
|
|
11
|
+
* 层归属:Engine。
|
|
12
|
+
*
|
|
13
|
+
* 参考:domain-models.md §2。
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import type { Budget } from "./budget.ts";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* RunSpec——一次 workflow run 的不可变输入规格。
|
|
20
|
+
*
|
|
21
|
+
* 作为 RunStore 持久化的一部分(WorkflowRun.spec),跨 session pause/resume 时
|
|
22
|
+
* 需要 scriptSource/args 重建 worker(G3-001)。
|
|
23
|
+
*/
|
|
24
|
+
export interface RunSpec {
|
|
25
|
+
/** 已 strip export 的可执行源(WorkflowScript.toExecutable 产物)。 */
|
|
26
|
+
readonly scriptSource: string;
|
|
27
|
+
/** 调用方传入的参数(worker 内通过 $ARGS 访问)。 */
|
|
28
|
+
readonly args: Record<string, unknown>;
|
|
29
|
+
/** Token 预算上限(未设或 0 = 不限制,见 Budget 守卫)。 */
|
|
30
|
+
readonly budgetTokens?: number;
|
|
31
|
+
/** 时间预算上限(ms,wall-clock,由 lifecycle.scheduleTimeBudget 调度)。 */
|
|
32
|
+
readonly budgetTimeMs?: number;
|
|
33
|
+
/**
|
|
34
|
+
* 父 Budget 共享引用(嵌套 workflow() 时由 executeNestedWorkflow 传入)。
|
|
35
|
+
*
|
|
36
|
+
* 设置时 lifecycle.runWorkflow 直接复用此 Budget 实例,而非 new 一个独立 Budget——
|
|
37
|
+
* 子 run 的 consume 直接反映到父 Budget,消除并行嵌套下的超支窗口(F-7 方案 B)。
|
|
38
|
+
* 顶层 run 无此字段(budgetTokens 走独立 Budget 构造)。
|
|
39
|
+
*/
|
|
40
|
+
readonly budgetRef?: Budget;
|
|
41
|
+
/** 脚本名(meta.name 或文件名 stem)。 */
|
|
42
|
+
readonly scriptName: string;
|
|
43
|
+
/** 脚本文件绝对路径(用于诊断/日志)。 */
|
|
44
|
+
readonly scriptPath: string;
|
|
45
|
+
/** 人类可读描述(meta.description)。 */
|
|
46
|
+
readonly description?: string;
|
|
47
|
+
/**
|
|
48
|
+
* 父 workflow 调用链(嵌套 workflow() 时自动填充,循环检测用)。
|
|
49
|
+
*
|
|
50
|
+
* 顶层 run 无此字段。子 run 的 chain = [...parentChain, parentScriptName]。
|
|
51
|
+
* executeNestedWorkflow 检查目标 name 是否已在 chain 中,防止 A→B→A 死循环。
|
|
52
|
+
*/
|
|
53
|
+
readonly parentWorkflowChain?: readonly string[];
|
|
54
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow Extension — RunState 值对象
|
|
3
|
+
*
|
|
4
|
+
* 单次 workflow run 的可持久化状态(domain-models.md §3)。
|
|
5
|
+
*
|
|
6
|
+
* 设计:
|
|
7
|
+
* - status/reason/budget/calls/trace/errorLogs 是可变字段(运行中持续更新)
|
|
8
|
+
* - error/scriptResult 仅终态有值(done 时)
|
|
9
|
+
* - 与 RunSpec 的区别:RunSpec 不可变(输入),RunState 可变(执行快照)
|
|
10
|
+
*
|
|
11
|
+
* 层归属:Engine。
|
|
12
|
+
*
|
|
13
|
+
* 参考:domain-models.md §3。
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import type { AgentCall } from "./agent-call.ts";
|
|
17
|
+
import type { Budget } from "./budget.ts";
|
|
18
|
+
import type { Trace } from "./trace.ts";
|
|
19
|
+
import type { DoneReason, RunStatus, WorkerLogEntry } from "./types.ts";
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* RunState——一次 run 的可持久化执行状态。
|
|
23
|
+
*
|
|
24
|
+
* 持久化由 RunStore.save(WorkflowRun) 触发(WorkflowRun 持 RunState)。
|
|
25
|
+
* 跨 session pause/resume 时,RunState 从 JSONL 重水合(callCache 保留,worker 重建)。
|
|
26
|
+
*/
|
|
27
|
+
export interface RunState {
|
|
28
|
+
/** 当前状态(running/paused/done)。 */
|
|
29
|
+
status: RunStatus;
|
|
30
|
+
/** 终态原因(done 时必有)。 */
|
|
31
|
+
reason?: DoneReason;
|
|
32
|
+
/** Token/cost 预算(含 usedTokens/usedCost 累积)。 */
|
|
33
|
+
budget: Budget;
|
|
34
|
+
/** 按 callId 索引的 agent 调用集合(含 result,跨 pause/resume 存活)。 */
|
|
35
|
+
calls: Map<number, AgentCall>;
|
|
36
|
+
/** 执行追踪事件流(唯一来源 D-10)。 */
|
|
37
|
+
trace: Trace;
|
|
38
|
+
/** Worker console.* 捕获条目(run 级诊断,仅展示在 TUI widget)。 */
|
|
39
|
+
errorLogs: WorkerLogEntry[];
|
|
40
|
+
/** done && reason !== completed 时可有(失败/中止/预算超限的原因)。 */
|
|
41
|
+
error?: string;
|
|
42
|
+
/** done && reason === completed 时有(脚本 execute 返回值)。 */
|
|
43
|
+
scriptResult?: unknown;
|
|
44
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow Extension — Trace 值对象
|
|
3
|
+
*
|
|
4
|
+
* 执行追踪事件流(D-10 单一来源)。纯 append-only + 单字段 update。
|
|
5
|
+
*
|
|
6
|
+
* 设计:
|
|
7
|
+
* - trace 节点存储 + 变更逻辑收敛为值对象(外部不能直接打洞 nodes 数组)。
|
|
8
|
+
* - update 只改单个 node 的 status/result/error/completedAt/sessionId(TracePatch)。
|
|
9
|
+
* - callId 不存在时 update no-op(防御性,避免 race 下抛错)。
|
|
10
|
+
* - 持久化(appendEntry)与事件通知(emit)不在本值对象内——它们由 engine 函数
|
|
11
|
+
* 在调用 update 前后负责(值对象只管数据形状,不管 IO)。
|
|
12
|
+
*
|
|
13
|
+
* 层归属:Engine。
|
|
14
|
+
*
|
|
15
|
+
* 参考:domain-models.md §6(字段/不变式)。
|
|
16
|
+
*/
|
|
17
|
+
import type { ExecutionTraceNode, TracePatch } from "./types.ts";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Trace 值对象(事件流,唯一来源 D-10)。
|
|
21
|
+
*
|
|
22
|
+
* 不变式:
|
|
23
|
+
* - nodes 只增不改索引顺序(append-only)
|
|
24
|
+
* - update 只改单个 node 的 status/result/error/completedAt/sessionId
|
|
25
|
+
* - 不含 verifyStrategy(G-020 删除,不迁移)
|
|
26
|
+
*/
|
|
27
|
+
export class Trace {
|
|
28
|
+
private readonly nodes: ExecutionTraceNode[] = [];
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* 从已有节点数组重建 Trace(用于 RunStore 反序列化重水合)。
|
|
32
|
+
*
|
|
33
|
+
* 防御性拷贝——传入数组不被持有,外部 mutation 不影响 Trace。
|
|
34
|
+
* 不验证节点顺序/唯一性(调用方保证快照来源可信)。
|
|
35
|
+
*/
|
|
36
|
+
static fromArray(nodes: readonly ExecutionTraceNode[]): Trace {
|
|
37
|
+
const trace = new Trace();
|
|
38
|
+
for (const node of nodes) {
|
|
39
|
+
trace.nodes.push({ ...node });
|
|
40
|
+
}
|
|
41
|
+
return trace;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Append a trace node(append-only,不改已有节点)。 */
|
|
45
|
+
append(node: ExecutionTraceNode): void {
|
|
46
|
+
this.nodes.push(node);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Update a trace node by stepIndex (callId) with a partial patch.
|
|
51
|
+
*
|
|
52
|
+
* 只改 patch 中提供的字段(status/result/error/completedAt/sessionId)。
|
|
53
|
+
* stepIndex 不存在时 no-op(防御性——agent 完成/失败回调可能晚于 run 终止到达)。
|
|
54
|
+
*/
|
|
55
|
+
update(stepIndex: number, patch: TracePatch): void {
|
|
56
|
+
const node = this.findByStepIndex(stepIndex);
|
|
57
|
+
if (!node) return; // no-op: 不存在不抛错(D-10 防御性)
|
|
58
|
+
|
|
59
|
+
if (patch.status !== undefined) node.status = patch.status;
|
|
60
|
+
if (patch.result !== undefined) node.result = patch.result;
|
|
61
|
+
if (patch.error !== undefined) node.error = patch.error;
|
|
62
|
+
if (patch.completedAt !== undefined) node.completedAt = patch.completedAt;
|
|
63
|
+
if (patch.sessionId !== undefined) node.sessionId = patch.sessionId;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** 查找指定 stepIndex 的节点(首个匹配,trace 中 stepIndex 应唯一)。 */
|
|
67
|
+
private findByStepIndex(stepIndex: number): ExecutionTraceNode | undefined {
|
|
68
|
+
for (const node of this.nodes) {
|
|
69
|
+
if (node.stepIndex === stepIndex) return node;
|
|
70
|
+
}
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** 按节点引用删除(仅用于测试或 run 重建场景;正常运行不调用)。 */
|
|
75
|
+
find(stepIndex: number): ExecutionTraceNode | undefined {
|
|
76
|
+
return this.findByStepIndex(stepIndex);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* 按 stepIndex 移除节点(仅 pause 清理在飞 call 用)。
|
|
81
|
+
*
|
|
82
|
+
* 正常运行不调用(append-only 不变式)。仅 lifecycle.pauseRun 清理被 abort 的
|
|
83
|
+
* 在飞 call 时用——移除其 trace 节点,让 resume 重发 agent-call 时 append 全新
|
|
84
|
+
* 节点走全新执行路径(避免 stale "running" 节点残留 + trace.update 命中旧节点
|
|
85
|
+
* 导致新节点 orphan)。stepIndex 不存在时 no-op(防御性)。
|
|
86
|
+
*/
|
|
87
|
+
removeByStepIndex(stepIndex: number): void {
|
|
88
|
+
const idx = this.nodes.findIndex((n) => n.stepIndex === stepIndex);
|
|
89
|
+
if (idx === -1) return;
|
|
90
|
+
this.nodes.splice(idx, 1);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** readonly 视图——外部不应直接 mutate(不变式保护)。 */
|
|
94
|
+
toArray(): readonly ExecutionTraceNode[] {
|
|
95
|
+
return this.nodes;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** 当前节点数。 */
|
|
99
|
+
get length(): number {
|
|
100
|
+
return this.nodes.length;
|
|
101
|
+
}
|
|
102
|
+
}
|