@osolmaz/pi-workflows 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/LICENSE +21 -0
- package/README.md +182 -0
- package/dist/extension/executor.d.ts +58 -0
- package/dist/extension/executor.js +201 -0
- package/dist/extension/executor.js.map +1 -0
- package/dist/extension/index.d.ts +17 -0
- package/dist/extension/index.js +504 -0
- package/dist/extension/index.js.map +1 -0
- package/dist/extension/widget.d.ts +21 -0
- package/dist/extension/widget.js +142 -0
- package/dist/extension/widget.js.map +1 -0
- package/dist/render/ansi.d.ts +16 -0
- package/dist/render/ansi.js +42 -0
- package/dist/render/ansi.js.map +1 -0
- package/dist/render/canvas.d.ts +40 -0
- package/dist/render/canvas.js +177 -0
- package/dist/render/canvas.js.map +1 -0
- package/dist/render/format.d.ts +3 -0
- package/dist/render/format.js +17 -0
- package/dist/render/format.js.map +1 -0
- package/dist/render/graph-render.d.ts +22 -0
- package/dist/render/graph-render.js +520 -0
- package/dist/render/graph-render.js.map +1 -0
- package/dist/render/graph.d.ts +46 -0
- package/dist/render/graph.js +272 -0
- package/dist/render/graph.js.map +1 -0
- package/dist/viewer/cli.d.ts +10 -0
- package/dist/viewer/cli.js +132 -0
- package/dist/viewer/cli.js.map +1 -0
- package/dist/viewer/render.d.ts +19 -0
- package/dist/viewer/render.js +162 -0
- package/dist/viewer/render.js.map +1 -0
- package/dist/viewer/tui.d.ts +11 -0
- package/dist/viewer/tui.js +140 -0
- package/dist/viewer/tui.js.map +1 -0
- package/dist/viewer/watch.d.ts +9 -0
- package/dist/viewer/watch.js +46 -0
- package/dist/viewer/watch.js.map +1 -0
- package/dist/workflows/decision.d.ts +25 -0
- package/dist/workflows/decision.js +96 -0
- package/dist/workflows/decision.js.map +1 -0
- package/dist/workflows/definition.d.ts +9 -0
- package/dist/workflows/definition.js +61 -0
- package/dist/workflows/definition.js.map +1 -0
- package/dist/workflows/engine.d.ts +65 -0
- package/dist/workflows/engine.js +574 -0
- package/dist/workflows/engine.js.map +1 -0
- package/dist/workflows/errors.d.ts +9 -0
- package/dist/workflows/errors.js +24 -0
- package/dist/workflows/errors.js.map +1 -0
- package/dist/workflows/graph.d.ts +17 -0
- package/dist/workflows/graph.js +127 -0
- package/dist/workflows/graph.js.map +1 -0
- package/dist/workflows/index.d.ts +11 -0
- package/dist/workflows/index.js +11 -0
- package/dist/workflows/index.js.map +1 -0
- package/dist/workflows/json.d.ts +14 -0
- package/dist/workflows/json.js +134 -0
- package/dist/workflows/json.js.map +1 -0
- package/dist/workflows/loader.d.ts +28 -0
- package/dist/workflows/loader.js +94 -0
- package/dist/workflows/loader.js.map +1 -0
- package/dist/workflows/schema.d.ts +7 -0
- package/dist/workflows/schema.js +176 -0
- package/dist/workflows/schema.js.map +1 -0
- package/dist/workflows/shell.d.ts +9 -0
- package/dist/workflows/shell.js +177 -0
- package/dist/workflows/shell.js.map +1 -0
- package/dist/workflows/store.d.ts +35 -0
- package/dist/workflows/store.js +181 -0
- package/dist/workflows/store.js.map +1 -0
- package/dist/workflows/text.d.ts +10 -0
- package/dist/workflows/text.js +32 -0
- package/dist/workflows/text.js.map +1 -0
- package/dist/workflows/types.d.ts +280 -0
- package/dist/workflows/types.js +2 -0
- package/dist/workflows/types.js.map +1 -0
- package/docs/development.md +130 -0
- package/docs/run-bundles.md +114 -0
- package/docs/workflows.md +311 -0
- package/examples/workflows/autoimplement.workflow.ts +92 -0
- package/examples/workflows/autoresearch.workflow.ts +139 -0
- package/examples/workflows/branch.workflow.ts +63 -0
- package/examples/workflows/echo.workflow.ts +23 -0
- package/examples/workflows/elegant-solution.workflow.ts +95 -0
- package/examples/workflows/shell.workflow.ts +31 -0
- package/examples/workflows/two-turn.workflow.ts +64 -0
- package/package.json +80 -0
- package/src/extension/executor.ts +251 -0
- package/src/extension/index.ts +627 -0
- package/src/extension/widget.ts +183 -0
- package/src/render/ansi.ts +47 -0
- package/src/render/canvas.ts +196 -0
- package/src/render/format.ts +19 -0
- package/src/render/graph-render.ts +738 -0
- package/src/render/graph.ts +341 -0
- package/src/viewer/cli.ts +150 -0
- package/src/viewer/render.ts +236 -0
- package/src/viewer/tui.ts +159 -0
- package/src/viewer/watch.ts +55 -0
- package/src/workflows/decision.ts +127 -0
- package/src/workflows/definition.ts +104 -0
- package/src/workflows/engine.ts +793 -0
- package/src/workflows/errors.ts +27 -0
- package/src/workflows/graph.ts +161 -0
- package/src/workflows/index.ts +76 -0
- package/src/workflows/json.ts +155 -0
- package/src/workflows/loader.ts +123 -0
- package/src/workflows/schema.ts +218 -0
- package/src/workflows/shell.ts +199 -0
- package/src/workflows/store.ts +234 -0
- package/src/workflows/text.ts +34 -0
- package/src/workflows/types.ts +318 -0
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
export type MaybePromise<T> = T | Promise<T>;
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Context passed to node callbacks (prompt builders, compute/action runners,
|
|
5
|
+
* validators). `outputs` maps node ids to their accepted outputs; `results`
|
|
6
|
+
* maps node ids to the full result record of their latest attempt.
|
|
7
|
+
*/
|
|
8
|
+
export type WorkflowNodeContext<TInput = unknown> = {
|
|
9
|
+
input: TInput;
|
|
10
|
+
outputs: Record<string, unknown>;
|
|
11
|
+
results: Record<string, WorkflowNodeResult>;
|
|
12
|
+
state: WorkflowRunState;
|
|
13
|
+
/**
|
|
14
|
+
* Aborted when the node times out or the run is cancelled. Long-running
|
|
15
|
+
* callbacks should observe it (pass it to fetch/spawn or check
|
|
16
|
+
* `signal.aborted`) so side effects stop when the engine gives up on the
|
|
17
|
+
* node.
|
|
18
|
+
*/
|
|
19
|
+
signal: AbortSignal;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type WorkflowNodeCommon = {
|
|
23
|
+
/** Per-node timeout. Falls back to the engine default (15 minutes). */
|
|
24
|
+
timeoutMs?: number;
|
|
25
|
+
/** Short human-readable label shown in the viewer while the node runs. */
|
|
26
|
+
statusDetail?: string;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Edges route between nodes. A node has at most one outgoing edge: either a
|
|
31
|
+
* plain `to` edge or a `switch` edge that routes on a JSON path into the
|
|
32
|
+
* node's output (`$.field`, `$output.field`) or result (`$result.outcome`).
|
|
33
|
+
*/
|
|
34
|
+
export type WorkflowEdge =
|
|
35
|
+
| {
|
|
36
|
+
from: string;
|
|
37
|
+
to: string;
|
|
38
|
+
}
|
|
39
|
+
| {
|
|
40
|
+
from: string;
|
|
41
|
+
switch: {
|
|
42
|
+
on: string;
|
|
43
|
+
cases: Record<string, string>;
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* A model-shaped step. The engine sends the prompt into the pi conversation
|
|
49
|
+
* and the model completes the step by calling the `workflow` tool with a JSON
|
|
50
|
+
* output. `expectedOutput` is appended to the step contract so the model
|
|
51
|
+
* knows what shape to submit. `validate` may reject (throw) or normalize the
|
|
52
|
+
* submitted output; rejections are surfaced to the model so it can retry
|
|
53
|
+
* within the same step.
|
|
54
|
+
*/
|
|
55
|
+
export type AgentNodeDefinition = WorkflowNodeCommon & {
|
|
56
|
+
nodeType: "agent";
|
|
57
|
+
prompt: (context: WorkflowNodeContext) => MaybePromise<string>;
|
|
58
|
+
expectedOutput?: string;
|
|
59
|
+
validate?: (output: unknown, context: WorkflowNodeContext) => MaybePromise<unknown>;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
/** A pure local function: shape inputs, route, format, derive values. */
|
|
63
|
+
export type ComputeNodeDefinition = WorkflowNodeCommon & {
|
|
64
|
+
nodeType: "compute";
|
|
65
|
+
run: (context: WorkflowNodeContext) => MaybePromise<unknown>;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/** A deterministic runtime-owned step implemented as a local function. */
|
|
69
|
+
export type FunctionActionNodeDefinition = WorkflowNodeCommon & {
|
|
70
|
+
nodeType: "action";
|
|
71
|
+
run: (context: WorkflowNodeContext) => MaybePromise<unknown>;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export type ShellActionExecution = {
|
|
75
|
+
command: string;
|
|
76
|
+
args?: string[];
|
|
77
|
+
cwd?: string;
|
|
78
|
+
env?: Record<string, string>;
|
|
79
|
+
stdin?: string;
|
|
80
|
+
shell?: boolean | string;
|
|
81
|
+
allowNonZeroExit?: boolean;
|
|
82
|
+
timeoutMs?: number;
|
|
83
|
+
/** Cap on captured stdout/stderr each, default 1,000,000 characters. */
|
|
84
|
+
maxOutputChars?: number;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export type ShellActionResult = {
|
|
88
|
+
command: string;
|
|
89
|
+
args: string[];
|
|
90
|
+
cwd: string;
|
|
91
|
+
stdout: string;
|
|
92
|
+
stderr: string;
|
|
93
|
+
exitCode: number | null;
|
|
94
|
+
signal: NodeJS.Signals | null;
|
|
95
|
+
durationMs: number;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
/** A deterministic runtime-owned step implemented as a shell command. */
|
|
99
|
+
export type ShellActionNodeDefinition = WorkflowNodeCommon & {
|
|
100
|
+
nodeType: "action";
|
|
101
|
+
exec: (context: WorkflowNodeContext) => MaybePromise<ShellActionExecution>;
|
|
102
|
+
parse?: (result: ShellActionResult, context: WorkflowNodeContext) => MaybePromise<unknown>;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
export type ActionNodeDefinition = FunctionActionNodeDefinition | ShellActionNodeDefinition;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* A pause point. The run terminates with status `waiting` so a human (or an
|
|
109
|
+
* external trigger) can decide how to continue. The optional `run` callback
|
|
110
|
+
* produces the checkpoint's output before the run pauses.
|
|
111
|
+
*/
|
|
112
|
+
export type CheckpointNodeDefinition = WorkflowNodeCommon & {
|
|
113
|
+
nodeType: "checkpoint";
|
|
114
|
+
summary?: string;
|
|
115
|
+
run?: (context: WorkflowNodeContext) => MaybePromise<unknown>;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
export type WorkflowNodeDefinition =
|
|
119
|
+
| AgentNodeDefinition
|
|
120
|
+
| ComputeNodeDefinition
|
|
121
|
+
| ActionNodeDefinition
|
|
122
|
+
| CheckpointNodeDefinition;
|
|
123
|
+
|
|
124
|
+
export type WorkflowPresentationContext = {
|
|
125
|
+
/** Final persisted state of the workflow run. */
|
|
126
|
+
state: WorkflowRunState;
|
|
127
|
+
/** Convenience alias for `state.finalOutput`. */
|
|
128
|
+
finalOutput: unknown;
|
|
129
|
+
/** Aborted if a new run starts, the session closes, or prompt generation times out. */
|
|
130
|
+
signal: AbortSignal;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
export type WorkflowDefinition = {
|
|
134
|
+
name: string;
|
|
135
|
+
/** Optional human-readable run title (static or derived from input). */
|
|
136
|
+
title?:
|
|
137
|
+
| string
|
|
138
|
+
| ((context: { input: unknown; workflowName: string }) => MaybePromise<string | undefined>);
|
|
139
|
+
/**
|
|
140
|
+
* Optional instructions for a normal assistant response after the run ends.
|
|
141
|
+
* The Pi extension resolves this only after the final state is persisted;
|
|
142
|
+
* the engine and run bundle remain presentation-agnostic.
|
|
143
|
+
*/
|
|
144
|
+
presentationPrompt?:
|
|
145
|
+
| string
|
|
146
|
+
| ((context: WorkflowPresentationContext) => MaybePromise<string | undefined>);
|
|
147
|
+
startAt: string;
|
|
148
|
+
nodes: Record<string, WorkflowNodeDefinition>;
|
|
149
|
+
edges: WorkflowEdge[];
|
|
150
|
+
/** Guard against unbounded loops. Defaults to the engine's maxSteps. */
|
|
151
|
+
maxSteps?: number;
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
export type WorkflowNodeOutcome = "ok" | "timed_out" | "failed" | "cancelled";
|
|
155
|
+
|
|
156
|
+
export type WorkflowNodeResult = {
|
|
157
|
+
attemptId: string;
|
|
158
|
+
nodeId: string;
|
|
159
|
+
nodeType: WorkflowNodeDefinition["nodeType"];
|
|
160
|
+
outcome: WorkflowNodeOutcome;
|
|
161
|
+
startedAt: string;
|
|
162
|
+
finishedAt: string;
|
|
163
|
+
durationMs: number;
|
|
164
|
+
output?: unknown;
|
|
165
|
+
error?: string;
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
export type WorkflowActionReceipt = {
|
|
169
|
+
actionType: "shell" | "function";
|
|
170
|
+
command?: string;
|
|
171
|
+
args?: string[];
|
|
172
|
+
cwd?: string;
|
|
173
|
+
exitCode?: number | null;
|
|
174
|
+
signal?: NodeJS.Signals | null;
|
|
175
|
+
durationMs?: number;
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
export type WorkflowStepRecord = {
|
|
179
|
+
attemptId: string;
|
|
180
|
+
nodeId: string;
|
|
181
|
+
nodeType: WorkflowNodeDefinition["nodeType"];
|
|
182
|
+
outcome: WorkflowNodeOutcome;
|
|
183
|
+
startedAt: string;
|
|
184
|
+
finishedAt: string;
|
|
185
|
+
promptText: string | null;
|
|
186
|
+
output: unknown;
|
|
187
|
+
error?: string;
|
|
188
|
+
action?: WorkflowActionReceipt;
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
export type WorkflowRunStatus =
|
|
192
|
+
| "running"
|
|
193
|
+
| "waiting"
|
|
194
|
+
| "completed"
|
|
195
|
+
| "failed"
|
|
196
|
+
| "timed_out"
|
|
197
|
+
| "cancelled";
|
|
198
|
+
|
|
199
|
+
export type WorkflowRunState = {
|
|
200
|
+
runId: string;
|
|
201
|
+
workflowName: string;
|
|
202
|
+
runTitle?: string;
|
|
203
|
+
workflowPath?: string;
|
|
204
|
+
startedAt: string;
|
|
205
|
+
finishedAt?: string;
|
|
206
|
+
updatedAt: string;
|
|
207
|
+
status: WorkflowRunStatus;
|
|
208
|
+
input: unknown;
|
|
209
|
+
outputs: Record<string, unknown>;
|
|
210
|
+
results: Record<string, WorkflowNodeResult>;
|
|
211
|
+
steps: WorkflowStepRecord[];
|
|
212
|
+
currentNode?: string;
|
|
213
|
+
currentAttemptId?: string;
|
|
214
|
+
currentNodeType?: WorkflowNodeDefinition["nodeType"];
|
|
215
|
+
currentNodeStartedAt?: string;
|
|
216
|
+
statusDetail?: string;
|
|
217
|
+
/** True while the run is held at a step boundary by a pause request. */
|
|
218
|
+
paused?: boolean;
|
|
219
|
+
waitingOn?: string;
|
|
220
|
+
finalOutput?: unknown;
|
|
221
|
+
error?: string;
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
export type WorkflowNodeSnapshot = {
|
|
225
|
+
nodeType: WorkflowNodeDefinition["nodeType"];
|
|
226
|
+
timeoutMs?: number;
|
|
227
|
+
statusDetail?: string;
|
|
228
|
+
summary?: string;
|
|
229
|
+
expectedOutput?: string;
|
|
230
|
+
actionExecution?: "function" | "shell";
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
export type WorkflowDefinitionSnapshot = {
|
|
234
|
+
schema: "pi-workflows.definition-snapshot.v1";
|
|
235
|
+
name: string;
|
|
236
|
+
startAt: string;
|
|
237
|
+
nodes: Record<string, WorkflowNodeSnapshot>;
|
|
238
|
+
edges: WorkflowEdge[];
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
export type WorkflowTraceEvent = {
|
|
242
|
+
seq: number;
|
|
243
|
+
at: string;
|
|
244
|
+
scope: "run" | "node" | "agent" | "action";
|
|
245
|
+
type: string;
|
|
246
|
+
runId: string;
|
|
247
|
+
nodeId?: string;
|
|
248
|
+
attemptId?: string;
|
|
249
|
+
payload: Record<string, unknown>;
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
export type WorkflowTraceEventDraft = Omit<WorkflowTraceEvent, "seq" | "at" | "runId">;
|
|
253
|
+
|
|
254
|
+
export type WorkflowRunManifest = {
|
|
255
|
+
schema: "pi-workflows.run-bundle.v1";
|
|
256
|
+
runId: string;
|
|
257
|
+
workflowName: string;
|
|
258
|
+
runTitle?: string;
|
|
259
|
+
workflowPath?: string;
|
|
260
|
+
startedAt: string;
|
|
261
|
+
finishedAt?: string;
|
|
262
|
+
status: WorkflowRunStatus;
|
|
263
|
+
traceSchema: "pi-workflows.trace-event.v1";
|
|
264
|
+
paths: {
|
|
265
|
+
workflow: string;
|
|
266
|
+
state: string;
|
|
267
|
+
trace: string;
|
|
268
|
+
};
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
export type WorkflowRunResult = {
|
|
272
|
+
runDir: string;
|
|
273
|
+
state: WorkflowRunState;
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
/** The step contract handed to the executor alongside the prompt. */
|
|
277
|
+
export type AgentStepContract = {
|
|
278
|
+
runId: string;
|
|
279
|
+
workflowName: string;
|
|
280
|
+
nodeId: string;
|
|
281
|
+
attemptId: string;
|
|
282
|
+
expectedOutput?: string;
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
export type AgentStepRequest = {
|
|
286
|
+
contract: AgentStepContract;
|
|
287
|
+
prompt: string;
|
|
288
|
+
/**
|
|
289
|
+
* Validate a submission from the model. Returns the normalized output or an
|
|
290
|
+
* error message the executor should surface to the model for retry.
|
|
291
|
+
*/
|
|
292
|
+
accept: (output: unknown) => Promise<{ ok: true; value: unknown } | { ok: false; error: string }>;
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
export type AgentStepSubmission = {
|
|
296
|
+
output: unknown;
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Runs one agent step to completion. Implementations deliver the prompt to
|
|
301
|
+
* the model and resolve once a submission has been accepted via `accept`.
|
|
302
|
+
* Must reject with an `AbortError`-like error when `signal` aborts.
|
|
303
|
+
*/
|
|
304
|
+
export interface AgentStepExecutor {
|
|
305
|
+
runAgentStep(request: AgentStepRequest, signal: AbortSignal): Promise<AgentStepSubmission>;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
export type WorkflowEngineOptions = {
|
|
309
|
+
executor: AgentStepExecutor;
|
|
310
|
+
/** Root directory for run bundles. Defaults to `~/.pi/agent/workflows/runs`. */
|
|
311
|
+
outputRoot?: string;
|
|
312
|
+
/** Default per-node timeout. Defaults to 15 minutes. */
|
|
313
|
+
defaultNodeTimeoutMs?: number;
|
|
314
|
+
/** Guard against unbounded graph loops. Defaults to 100 executed steps. */
|
|
315
|
+
maxSteps?: number;
|
|
316
|
+
/** Observer invoked after every persisted trace event. */
|
|
317
|
+
onEvent?: (event: WorkflowTraceEvent, state: WorkflowRunState) => void;
|
|
318
|
+
};
|