pi-workflow-engine 0.9.0 → 0.10.1
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/.pi/extensions/pi-workflow-engine/index.ts +136 -26
- package/.pi/extensions/pi-workflow-engine/src/agent-runner.ts +257 -23
- package/.pi/extensions/pi-workflow-engine/src/budget.ts +46 -0
- package/.pi/extensions/pi-workflow-engine/src/cancellation.ts +7 -0
- package/.pi/extensions/pi-workflow-engine/src/concurrency.ts +83 -23
- package/.pi/extensions/pi-workflow-engine/src/diff-capture.ts +15 -69
- package/.pi/extensions/pi-workflow-engine/src/engine.ts +24 -2
- package/.pi/extensions/pi-workflow-engine/src/journal.ts +200 -0
- package/.pi/extensions/pi-workflow-engine/src/options.ts +27 -1
- package/.pi/extensions/pi-workflow-engine/src/process-runner.ts +96 -0
- package/.pi/extensions/pi-workflow-engine/src/types.ts +59 -4
- package/.pi/extensions/pi-workflow-engine/src/ui/workflow-result-renderer.ts +81 -13
- package/.pi/extensions/pi-workflow-engine/src/workflow-advisory-utils.ts +14 -5
- package/.pi/extensions/pi-workflow-engine/src/worktree.ts +238 -0
- package/.pi/extensions/pi-workflow-engine/workflows/code-review.ts +10 -5
- package/.pi/extensions/pi-workflow-engine/workflows/diagnose.ts +12 -8
- package/.pi/extensions/pi-workflow-engine/workflows/perf-review.ts +6 -2
- package/.pi/extensions/pi-workflow-engine/workflows/refactor-scout.ts +6 -2
- package/README.md +10 -1
- package/USAGE.md +50 -8
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ Use `dynamax` when a task needs several independent passes: review from differen
|
|
|
8
8
|
|
|
9
9
|
The package ships no bundled runtime dependencies. It uses the pi SDK and pi's bundled core packages, so installing it does not pull in a second agent stack.
|
|
10
10
|
|
|
11
|
-
The built-in workflows are advisory. They inspect, verify, and report; they do not edit files.
|
|
11
|
+
The built-in workflows are advisory by default. They inspect, verify, and report; they do not edit files. Workflow authors can opt individual subagents into disposable git worktrees when they want reviewable patches instead of direct edits.
|
|
12
12
|
|
|
13
13
|
## Install
|
|
14
14
|
|
|
@@ -134,9 +134,13 @@ Useful flags:
|
|
|
134
134
|
/workflow code-review --result-viewer
|
|
135
135
|
/workflow code-review --no-result-viewer
|
|
136
136
|
/workflow code-review --concurrency=4
|
|
137
|
+
/workflow code-review --budget=50000
|
|
138
|
+
/workflow code-review --resume <run-id>
|
|
137
139
|
/workflow code-review --refresh
|
|
138
140
|
```
|
|
139
141
|
|
|
142
|
+
Every workflow result includes a run id. If a long run is interrupted, rerun the same workflow with `--resume <run-id>` to replay matching completed `agent()` calls from the journal and run only the first changed or missing call onward. Resume is deterministic-prefix based: keep prompts and agent options stable if you want cache hits.
|
|
143
|
+
|
|
140
144
|
The code-review workflow can open an interactive findings viewer. Select findings and hand them back to the parent agent for minimal fixes, or ask it to raise GitHub PR comments when `gh` is authenticated and PR context is available.
|
|
141
145
|
|
|
142
146
|
For the full command guide, see [USAGE.md](USAGE.md).
|
|
@@ -202,10 +206,15 @@ Inline workflows are passed to the `workflow` tool as a script string. They are
|
|
|
202
206
|
- Each `agent()` runs an in-process pi `AgentSession` with `SessionManager.inMemory()`.
|
|
203
207
|
- Workflow results aggregate the finalized assistant usage from those subagent sessions before disposal and show token/cost totals separately from pi's host-session footer accounting.
|
|
204
208
|
- Structured output uses a terminating tool whose `parameters` is your schema. pi validates the call; the engine captures the args. There is no JSON scraping.
|
|
209
|
+
- A schema agent that finishes without calling `final_answer` is re-prompted once before returning `null`.
|
|
210
|
+
- Runs write completed `agent()` results to `.pi/.workflow-runs/<run-id>.jsonl`; `--resume <run-id>` replays the longest unchanged prefix and writes a fresh journal for the resumed run.
|
|
211
|
+
- `agent(..., { isolation: "worktree" })` runs in a disposable git worktree and returns `{ result, patch, changed }`; the user working tree is not mutated.
|
|
205
212
|
- A single run-level semaphore caps concurrent agents, so nested `parallel`, `pipeline`, and `workflow()` calls stay bounded.
|
|
213
|
+
- `parallel()` and `pipeline()` are fail-soft: recoverable branch failures, including budget backstops, become `null` slots while survivors continue. A genuine run abort still rejects.
|
|
206
214
|
- Built-in workflows stay statically imported so they share pi's bundled `typebox` identity.
|
|
207
215
|
- Set `thinkingLevel` per fan-out agent. Otherwise many subagents can inherit an expensive global reasoning level.
|
|
208
216
|
- Subagents receive no skills by default. Opt in per agent with `skills: ["skill-name"]`; clear prompt text like `include skill name` also works when `skills` is omitted.
|
|
217
|
+
- `tools` is a strict allowlist for subagents. Use `toolHints: ["search"]` to dynamically expose installed grep/find/search-like tools such as `ast-grep`, `mgrep`, `ffgrep`, or `fffind` without hard-coding a specific extension.
|
|
209
218
|
- Set `model` per agent only when needed: bare ids are Anthropic shorthand, and `provider/id` targets other providers.
|
|
210
219
|
Omitted models inherit the host/session default; malformed or unknown explicit refs fail fast.
|
|
211
220
|
|
package/USAGE.md
CHANGED
|
@@ -18,7 +18,7 @@ From inside a repo:
|
|
|
18
18
|
/workflow perf-review "workflow startup latency"
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
The built-in workflows are advisory. They inspect, verify, and report; they do **not** edit files.
|
|
21
|
+
The built-in workflows are advisory by default. They inspect, verify, and report; they do **not** edit files. Saved or inline workflows can opt individual agents into disposable git worktrees when they need reviewable patches.
|
|
22
22
|
|
|
23
23
|
Useful flags:
|
|
24
24
|
|
|
@@ -28,6 +28,8 @@ Useful flags:
|
|
|
28
28
|
/workflow code-review --result-viewer # explicitly open the findings viewer
|
|
29
29
|
/workflow code-review --review-viewer # alias for --result-viewer
|
|
30
30
|
/workflow code-review --concurrency=4 # cap concurrent subagents
|
|
31
|
+
/workflow code-review --budget=50000 # output-token ceiling for subagents
|
|
32
|
+
/workflow code-review --resume <run-id> # replay matching completed agent calls
|
|
31
33
|
/workflow code-review --refresh # rediscover newly added workflow files
|
|
32
34
|
```
|
|
33
35
|
|
|
@@ -104,12 +106,25 @@ During a run, pi shows live phases and subagent status. Use `--inspect` if you w
|
|
|
104
106
|
|
|
105
107
|
Code-review findings are rendered as a formatted result message by default. pi no longer asks whether to open the findings viewer. Use `--result-viewer` or `--review-viewer` when you want to inspect findings interactively, press `enter` to expand/collapse the nicely formatted finding text, and use `1`-`9` to jump directly to a visible finding.
|
|
106
108
|
|
|
109
|
+
### Resume a run
|
|
110
|
+
|
|
111
|
+
Every workflow result includes a run id. Resume with:
|
|
112
|
+
|
|
113
|
+
```text
|
|
114
|
+
/workflow code-review --resume <run-id> HEAD~3
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
The `workflow` tool exposes the same feature as `resumeFromRunId`. Resume replays completed `agent()` results from `.pi/.workflow-runs/<run-id>.jsonl` while the agent call index and prompt/options hash still match. After the first missing or changed call, the rest of the run executes live and writes a new journal under the new run id. Cached results do not add usage or budget spend for the resumed run.
|
|
118
|
+
|
|
119
|
+
Resume only caches completed `agent()` calls. It does not snapshot arbitrary workflow local variables or in-flight tool work. Keep prompts and agent options deterministic across reruns if you want cache hits.
|
|
120
|
+
|
|
107
121
|
## Author a saved workflow
|
|
108
122
|
|
|
109
123
|
Saved workflows are TypeScript modules with `meta` plus a default async function:
|
|
110
124
|
|
|
111
125
|
```ts
|
|
112
126
|
import { Type } from "typebox";
|
|
127
|
+
import { compactResults } from "../src/concurrency.ts";
|
|
113
128
|
import type { WorkflowApi, WorkflowMeta } from "../src/types.ts";
|
|
114
129
|
|
|
115
130
|
export const meta: WorkflowMeta = {
|
|
@@ -120,13 +135,17 @@ export const meta: WorkflowMeta = {
|
|
|
120
135
|
const Finding = Type.Object({
|
|
121
136
|
summary: Type.String(),
|
|
122
137
|
});
|
|
138
|
+
const SEARCH_TOOLS = ["read", "bash", "grep", "find", "ls"];
|
|
139
|
+
const SEARCH_TOOL_HINTS = ["search"] as const;
|
|
123
140
|
|
|
124
141
|
export default async function run({ agent, parallel, phase, args }: WorkflowApi) {
|
|
125
142
|
phase("Find");
|
|
126
|
-
const findings =
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
143
|
+
const findings = compactResults(
|
|
144
|
+
await parallel([
|
|
145
|
+
() => agent(`Find correctness issues: ${args}`, { schema: Finding, tools: SEARCH_TOOLS, toolHints: SEARCH_TOOL_HINTS, thinkingLevel: "low" }),
|
|
146
|
+
() => agent(`Find edge cases: ${args}`, { schema: Finding, tools: SEARCH_TOOLS, toolHints: SEARCH_TOOL_HINTS, thinkingLevel: "low" }),
|
|
147
|
+
]),
|
|
148
|
+
);
|
|
130
149
|
|
|
131
150
|
phase("Synthesize");
|
|
132
151
|
return agent(`Summarize: ${JSON.stringify(findings)}`, { thinkingLevel: "medium" });
|
|
@@ -138,18 +157,39 @@ Core primitives:
|
|
|
138
157
|
| Primitive | What it does |
|
|
139
158
|
| --- | --- |
|
|
140
159
|
| `agent(prompt, opts)` | Runs one isolated subagent. With `schema`, returns validated structured data. |
|
|
141
|
-
| `parallel(thunks)` | Runs thunks concurrently and waits for all. |
|
|
142
|
-
| `pipeline(items, ...stages)` | Runs each item through stages independently
|
|
160
|
+
| `parallel(thunks)` | Runs thunks concurrently and waits for all; recoverable failures become `null` slots. |
|
|
161
|
+
| `pipeline(items, ...stages)` | Runs each item through stages independently; a failed item becomes `null`. |
|
|
143
162
|
| `phase(title)` / `log(message)` | Updates workflow progress UI. |
|
|
144
163
|
| `progress(event)` | Emits counters, summaries, and lane items. |
|
|
145
164
|
| `workflow(ref, args?)` | Runs another workflow inline as a sub-step and returns its result. |
|
|
146
165
|
|
|
147
166
|
Set `thinkingLevel` on fan-out agents. Otherwise many subagents can inherit an expensive global reasoning level.
|
|
148
167
|
|
|
168
|
+
`tools` is a strict allowlist. If you set `tools: ["read", "bash"]`, extension tools such as `ast-grep`, `mgrep`, `fffind`, or `ffgrep` are hidden from that subagent. Add `toolHints: ["search"]` to dynamically expose installed grep/find/search-like tools while keeping the concrete base allowlist portable. The built-in advisory workflows use `tools: ["read", "bash", "grep", "find", "ls"]` plus `toolHints: ["search"]`.
|
|
169
|
+
|
|
149
170
|
Subagents receive no skills by default. Opt in per agent with `skills: ["skill-name"]`; if `tools` is also restricted, the engine automatically keeps `read` available so the subagent can load the selected `SKILL.md`. When `skills` is omitted, clear prompt text such as `/skill:name`, `include skill name`, or `use the name skill` is also treated as an opt-in. Pass `skills: []` to suppress that inference.
|
|
150
171
|
|
|
151
172
|
Set `model` only when a subagent should use a specific model. Bare ids keep the Anthropic shorthand; `provider/id` targets built-in, custom, or local providers. Omitted models inherit the host/session default; malformed or unknown explicit refs fail fast.
|
|
152
173
|
|
|
174
|
+
### Mutating agents in worktrees
|
|
175
|
+
|
|
176
|
+
Use `isolation: "worktree"` only for agents that should edit files. The agent runs in a detached git worktree, the engine captures its net patch, then the worktree is removed. The user's working tree is not changed.
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
const edit = await agent("Rename this helper and update its call sites.", {
|
|
180
|
+
tools: ["read", "bash", "edit", "grep", "find", "ls"],
|
|
181
|
+
isolation: "worktree",
|
|
182
|
+
thinkingLevel: "medium",
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
if (edit.changed) {
|
|
186
|
+
return { summary: "Patch ready for review.", patch: edit.patch };
|
|
187
|
+
}
|
|
188
|
+
return { summary: edit.result };
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Isolated agents require the workflow `cwd` to be inside a git work tree. Outside git, the agent fails fast rather than silently mutating the shared directory. The return value is `{ result, patch, changed }`, where `result` is the normal text or structured `agent()` result and `patch` is a `git diff HEAD` patch. Worktree setup costs disk and git process time, so keep it opt-in for mutating/parallel-edit stages.
|
|
192
|
+
|
|
153
193
|
### Compose workflows
|
|
154
194
|
|
|
155
195
|
`workflow(ref, args?)` runs a registered workflow by name as a sub-step, returning its result. The child shares the parent run's concurrency cap, abort signal, and perf timing, and its phases nest under `<name> ▸ <phase>` in the live UI.
|
|
@@ -161,7 +201,7 @@ export default async function run({ workflow }: WorkflowApi) {
|
|
|
161
201
|
}
|
|
162
202
|
```
|
|
163
203
|
|
|
164
|
-
Nesting is one level only: calling `workflow()` from inside a sub-workflow rejects. Resolution throws on an unknown name
|
|
204
|
+
Nesting is one level only: calling `workflow()` from inside a sub-workflow rejects. Resolution throws on an unknown name. Inside `parallel()` or `pipeline()`, recoverable branch errors become `null` results, so filter nulls before synthesis; a genuine run abort still rejects.
|
|
165
205
|
|
|
166
206
|
### Where workflows live
|
|
167
207
|
|
|
@@ -218,6 +258,7 @@ Only tune these when a workflow is too slow, too expensive, or too noisy:
|
|
|
218
258
|
| --- | --- |
|
|
219
259
|
| `--concurrency=N` / `PI_WORKFLOW_CONCURRENCY=N` | Cap concurrent subagents. Default is `min(8, max(2, CPU count))`. |
|
|
220
260
|
| `--parallel-limit=N` / `PI_WORKFLOW_PARALLEL_SUBMISSION_LIMIT=N` | Limit eager `parallel()` submission. |
|
|
261
|
+
| `--budget=N` / `PI_WORKFLOW_BUDGET=N` | Set an output-token ceiling for completed subagents. `agent()` throws `WorkflowBudgetExceededError` before starting another agent once the ceiling is reached; agents already running may overshoot because the engine does not reserve per-agent estimates. |
|
|
221
262
|
| `--perf` / `PI_WORKFLOW_PERF=1` | Include internal timing aggregates. Usage/cost totals are reported separately from perf. |
|
|
222
263
|
| `PI_WORKFLOW_LANE_ITEM_LIMIT=N` | Cap retained progress lane items. |
|
|
223
264
|
|
|
@@ -226,4 +267,5 @@ Only tune these when a workflow is too slow, too expensive, or too noisy:
|
|
|
226
267
|
- **Unknown workflow**: confirm the extension is loaded with `pi list`; use `--refresh` for new drop-ins.
|
|
227
268
|
- **Inline compile error**: check the inline rules above.
|
|
228
269
|
- **Slow run**: lower fan-out, set `thinkingLevel`, or reduce `--concurrency`.
|
|
270
|
+
- **Budget exhausted**: narrow the target, raise `--budget`, reduce fan-out/concurrency, or guard custom loops with `api.budget.remaining()`.
|
|
229
271
|
- **Duplicate command/tool warnings while developing**: avoid loading both the global package and the working copy.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-workflow-engine",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Zero-dependency Dynamax workflows for pi: live parallel subagents, typed handoffs, synthesized results.",
|
|
6
6
|
"keywords": [
|
|
@@ -49,14 +49,14 @@
|
|
|
49
49
|
"prepublishOnly": "tsgo --noEmit && bun run test"
|
|
50
50
|
},
|
|
51
51
|
"peerDependencies": {
|
|
52
|
-
"@earendil-works/pi-agent-core": "
|
|
53
|
-
"@earendil-works/pi-ai": "
|
|
54
|
-
"@earendil-works/pi-coding-agent": "
|
|
55
|
-
"@earendil-works/pi-tui": "
|
|
56
|
-
"typebox": "
|
|
52
|
+
"@earendil-works/pi-agent-core": "0.79.10",
|
|
53
|
+
"@earendil-works/pi-ai": "0.79.10",
|
|
54
|
+
"@earendil-works/pi-coding-agent": "0.79.10",
|
|
55
|
+
"@earendil-works/pi-tui": "0.79.10",
|
|
56
|
+
"typebox": "1.3.0"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
|
-
"@types/node": "^22",
|
|
60
|
-
"@typescript/native-preview": "^7.0.0-dev.
|
|
59
|
+
"@types/node": "^22.20.0",
|
|
60
|
+
"@typescript/native-preview": "^7.0.0-dev.20260623.1"
|
|
61
61
|
}
|
|
62
62
|
}
|