pi-workflow-engine 0.11.0 → 0.12.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/.pi/extensions/pi-workflow-engine/index.ts +255 -97
- package/.pi/extensions/pi-workflow-engine/src/advisory-schema.ts +0 -4
- package/.pi/extensions/pi-workflow-engine/src/agent-attempt.ts +3 -1
- package/.pi/extensions/pi-workflow-engine/src/agent-limits.ts +35 -0
- package/.pi/extensions/pi-workflow-engine/src/agent-replay.ts +27 -4
- package/.pi/extensions/pi-workflow-engine/src/agent-retry.ts +116 -0
- package/.pi/extensions/pi-workflow-engine/src/agent-runner-types.ts +49 -45
- package/.pi/extensions/pi-workflow-engine/src/agent-runner.ts +95 -26
- package/.pi/extensions/pi-workflow-engine/src/agent-session-providers.ts +50 -0
- package/.pi/extensions/pi-workflow-engine/src/agent-session.ts +158 -203
- package/.pi/extensions/pi-workflow-engine/src/agent-skills.ts +48 -42
- package/.pi/extensions/pi-workflow-engine/src/agent-workspace.ts +11 -3
- package/.pi/extensions/pi-workflow-engine/src/background-workflow-tool.ts +75 -0
- package/.pi/extensions/pi-workflow-engine/src/background-workflows.ts +492 -0
- package/.pi/extensions/pi-workflow-engine/src/budget.ts +3 -3
- package/.pi/extensions/pi-workflow-engine/src/cancellation.ts +38 -0
- package/.pi/extensions/pi-workflow-engine/src/command-completions.ts +36 -0
- package/.pi/extensions/pi-workflow-engine/src/concurrency.ts +70 -4
- package/.pi/extensions/pi-workflow-engine/src/diff-capture.ts +16 -130
- package/.pi/extensions/pi-workflow-engine/src/discovery.ts +9 -5
- package/.pi/extensions/pi-workflow-engine/src/dynamax.ts +109 -60
- package/.pi/extensions/pi-workflow-engine/src/engine.ts +166 -18
- package/.pi/extensions/pi-workflow-engine/src/filesystem-error.ts +4 -0
- package/.pi/extensions/pi-workflow-engine/src/inline-workflow.ts +2 -2
- package/.pi/extensions/pi-workflow-engine/src/journal.ts +12 -6
- package/.pi/extensions/pi-workflow-engine/src/model-profile-command.ts +167 -0
- package/.pi/extensions/pi-workflow-engine/src/model-profiles.ts +310 -0
- package/.pi/extensions/pi-workflow-engine/src/options.ts +88 -1
- package/.pi/extensions/pi-workflow-engine/src/pi-compat.ts +32 -0
- package/.pi/extensions/pi-workflow-engine/src/progress-types.ts +50 -0
- package/.pi/extensions/pi-workflow-engine/src/progress.ts +72 -117
- package/.pi/extensions/pi-workflow-engine/src/provider-usage-limit.ts +189 -0
- package/.pi/extensions/pi-workflow-engine/src/research-contract.ts +89 -0
- package/.pi/extensions/pi-workflow-engine/src/research-evidence.ts +289 -0
- package/.pi/extensions/pi-workflow-engine/src/resume-context.ts +74 -38
- package/.pi/extensions/pi-workflow-engine/src/review/code-review-orchestration.ts +49 -0
- package/.pi/extensions/pi-workflow-engine/src/review/review-report.ts +1 -1
- package/.pi/extensions/pi-workflow-engine/src/review/review-results-flow.ts +2 -1
- package/.pi/extensions/pi-workflow-engine/src/review/review-results-viewer.ts +11 -30
- package/.pi/extensions/pi-workflow-engine/src/review/review-session-coordinator.ts +5 -5
- package/.pi/extensions/pi-workflow-engine/src/review/review-snapshot.ts +3 -4
- package/.pi/extensions/pi-workflow-engine/src/review-diff-target.ts +130 -0
- package/.pi/extensions/pi-workflow-engine/src/session-identity.ts +6 -0
- package/.pi/extensions/pi-workflow-engine/src/structured-output.ts +32 -0
- package/.pi/extensions/pi-workflow-engine/src/tool-capabilities.ts +44 -0
- package/.pi/extensions/pi-workflow-engine/src/tool-source-identity.ts +1 -4
- package/.pi/extensions/pi-workflow-engine/src/tree-fingerprint.ts +1 -4
- package/.pi/extensions/pi-workflow-engine/src/types.ts +49 -15
- package/.pi/extensions/pi-workflow-engine/src/ui/dynamax-editor-decoration.ts +220 -0
- package/.pi/extensions/pi-workflow-engine/src/ui/workflow-format.ts +26 -6
- package/.pi/extensions/pi-workflow-engine/src/ui/workflow-inspector.ts +88 -46
- package/.pi/extensions/pi-workflow-engine/src/ui/workflow-result-renderer.ts +2 -1
- package/.pi/extensions/pi-workflow-engine/src/ui/workflow-viewer-layout.ts +51 -0
- package/.pi/extensions/pi-workflow-engine/src/ui/workflow-widget.ts +12 -67
- package/.pi/extensions/pi-workflow-engine/src/usage.ts +124 -16
- package/.pi/extensions/pi-workflow-engine/src/workflow-advisory-utils.ts +23 -3
- package/.pi/extensions/pi-workflow-engine/src/workflow-execution.ts +1 -1
- package/.pi/extensions/pi-workflow-engine/src/workflow-run-background.ts +72 -0
- package/.pi/extensions/pi-workflow-engine/src/workflow-run-controller.ts +354 -0
- package/.pi/extensions/pi-workflow-engine/src/workflow-run-history.ts +162 -0
- package/.pi/extensions/pi-workflow-engine/src/workflow-run-record.ts +632 -0
- package/.pi/extensions/pi-workflow-engine/src/workflow-run-store.ts +172 -0
- package/.pi/extensions/pi-workflow-engine/src/workflow-usage-limit-scheduler.ts +80 -0
- package/.pi/extensions/pi-workflow-engine/src/workflows.ts +2 -0
- package/.pi/extensions/pi-workflow-engine/src/worktree.ts +40 -3
- package/.pi/extensions/pi-workflow-engine/workflows/code-review.ts +18 -42
- package/.pi/extensions/pi-workflow-engine/workflows/diagnose.ts +10 -17
- package/.pi/extensions/pi-workflow-engine/workflows/perf-review.ts +8 -15
- package/.pi/extensions/pi-workflow-engine/workflows/refactor-scout.ts +8 -15
- package/.pi/extensions/pi-workflow-engine/workflows/research.ts +170 -0
- package/README.md +72 -141
- package/USAGE.md +211 -17
- package/package.json +1 -1
|
@@ -2,13 +2,14 @@ import { Type } from "typebox";
|
|
|
2
2
|
import {
|
|
3
3
|
AdvisoryReportSchema,
|
|
4
4
|
type AdvisoryCandidate,
|
|
5
|
-
type AdvisoryReport,
|
|
6
5
|
type AdvisoryVerdict,
|
|
7
6
|
} from "../src/advisory-schema.ts";
|
|
8
7
|
import {
|
|
9
8
|
backfillAdvisoryFindings,
|
|
9
|
+
emptyAdvisoryReport,
|
|
10
10
|
formatEvidence,
|
|
11
11
|
formatLocation,
|
|
12
|
+
publishVerifiedKeptProgress,
|
|
12
13
|
runLensVerificationPipeline,
|
|
13
14
|
DEFAULT_ADVISORY_TOOL_HINTS,
|
|
14
15
|
DEFAULT_ADVISORY_TOOLS,
|
|
@@ -79,11 +80,11 @@ export default async function run(api: WorkflowApi): Promise<unknown> {
|
|
|
79
80
|
"Inspect repository structure, the target path or module, and relevant AGENTS.md / project docs conventions. " +
|
|
80
81
|
"Return the concrete files that should be considered, a short summary, and any conventions that affect refactor advice. " +
|
|
81
82
|
`This workflow will fan out across ${REFACTOR_LENSES.length} lenses with up to ${PER_LENS} candidates per lens. Structured output only.`,
|
|
82
|
-
{ phase: "Scope", label: "scope", tools: TOOLS, toolHints: TOOL_HINTS,
|
|
83
|
+
{ phase: "Scope", label: "scope", tools: TOOLS, toolHints: TOOL_HINTS, profile: "medium", schema: ScopeSchema },
|
|
83
84
|
);
|
|
84
85
|
|
|
85
86
|
if (!scope || scope.files.length === 0) {
|
|
86
|
-
return
|
|
87
|
+
return emptyAdvisoryReport(
|
|
87
88
|
"No files were identified for refactor scouting.",
|
|
88
89
|
["Provide a target path, module, or subsystem to scout for refactor opportunities."],
|
|
89
90
|
makeStats(0, 0),
|
|
@@ -136,14 +137,10 @@ export default async function run(api: WorkflowApi): Promise<unknown> {
|
|
|
136
137
|
const verified = pipelineResult.verified;
|
|
137
138
|
const surviving = verified.filter((finding) => finding.verdict !== "REFUTED");
|
|
138
139
|
const stats = makeStats(verified.length, surviving.length);
|
|
139
|
-
|
|
140
|
-
progress({ type: "counter", key: "kept", label: "kept", value: surviving.length });
|
|
141
|
-
progress({ type: "summary", key: "verified", value: verified.length });
|
|
142
|
-
progress({ type: "summary", key: "kept", value: surviving.length });
|
|
143
|
-
log(`${verified.length} verified → ${surviving.length} kept`);
|
|
140
|
+
publishVerifiedKeptProgress({ progress, log }, verified.length, surviving.length);
|
|
144
141
|
|
|
145
142
|
if (surviving.length === 0) {
|
|
146
|
-
return
|
|
143
|
+
return emptyAdvisoryReport("No refactor opportunities survived verification.", ["Leave the scoped code unchanged unless a human reviewer has additional context."], stats);
|
|
147
144
|
}
|
|
148
145
|
|
|
149
146
|
phase("Synthesize");
|
|
@@ -166,13 +163,13 @@ export default async function run(api: WorkflowApi): Promise<unknown> {
|
|
|
166
163
|
phase: "Synthesize",
|
|
167
164
|
label: "synthesize",
|
|
168
165
|
tools: [],
|
|
169
|
-
|
|
166
|
+
profile: "medium",
|
|
170
167
|
resume: "read-only",
|
|
171
168
|
schema: AdvisoryReportSchema,
|
|
172
169
|
},
|
|
173
170
|
);
|
|
174
171
|
|
|
175
|
-
if (!report) return
|
|
172
|
+
if (!report) return emptyAdvisoryReport("Synthesis produced no output.", ["Inspect verifier evidence manually or rerun the workflow with a narrower target."], stats);
|
|
176
173
|
|
|
177
174
|
const findings = backfillAdvisoryFindings(report.findings, ranked, {
|
|
178
175
|
impact: "Impact not restated by synthesis.",
|
|
@@ -181,10 +178,6 @@ export default async function run(api: WorkflowApi): Promise<unknown> {
|
|
|
181
178
|
return { ...report, findings, stats };
|
|
182
179
|
}
|
|
183
180
|
|
|
184
|
-
function emptyReport(summary: string, nextSteps: string[], stats: WorkflowRunStats): AdvisoryReport & { stats: WorkflowRunStats } {
|
|
185
|
-
return { summary, findings: [], nextSteps, stats };
|
|
186
|
-
}
|
|
187
|
-
|
|
188
181
|
function rank(finding: Verified): number {
|
|
189
182
|
const verdictRank = finding.verdict === "CONFIRMED" ? 0 : 1;
|
|
190
183
|
const categoryRank = finding.category === "dead-code" || finding.category === "conventions" ? 2 : 0;
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { compactResults } from "../src/concurrency.ts";
|
|
2
|
+
import {
|
|
3
|
+
MAX_RESEARCH_LANES,
|
|
4
|
+
ResearchLaneResultSchema,
|
|
5
|
+
ResearchPlanSchema,
|
|
6
|
+
ResearchReportSchema,
|
|
7
|
+
ResearchVerificationSchema,
|
|
8
|
+
type ResearchClaimCandidate,
|
|
9
|
+
type ResearchReport,
|
|
10
|
+
type ResearchVerification,
|
|
11
|
+
} from "../src/research-contract.ts";
|
|
12
|
+
import {
|
|
13
|
+
buildClaimCandidates,
|
|
14
|
+
fallbackResearchReport,
|
|
15
|
+
normalizeResearchLanes,
|
|
16
|
+
sanitizeLaneResults,
|
|
17
|
+
sanitizeResearchReport,
|
|
18
|
+
sanitizeVerification,
|
|
19
|
+
unavailableResearchReport,
|
|
20
|
+
unavailableVerification,
|
|
21
|
+
} from "../src/research-evidence.ts";
|
|
22
|
+
import { WorkflowToolHintUnavailableError } from "../src/tool-capabilities.ts";
|
|
23
|
+
import type { WorkflowApi, WorkflowMeta } from "../src/types.ts";
|
|
24
|
+
|
|
25
|
+
export const meta: WorkflowMeta = {
|
|
26
|
+
name: "research",
|
|
27
|
+
description: "Source-grounded external research: decompose → gather direct-page evidence → independently verify claims → cited synthesis.",
|
|
28
|
+
phases: [{ title: "Plan" }, { title: "Gather" }, { title: "Verify" }, { title: "Synthesize" }],
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const EXTERNAL_TOOLS: string[] = [];
|
|
32
|
+
const EXTERNAL_TOOL_HINTS = ["external-search"] as const;
|
|
33
|
+
|
|
34
|
+
export default async function run(api: WorkflowApi): Promise<ResearchReport> {
|
|
35
|
+
const { agent, parallel, phase, log, progress, args } = api;
|
|
36
|
+
const question = args.trim();
|
|
37
|
+
if (!question) return unavailableResearchReport("empty-question");
|
|
38
|
+
|
|
39
|
+
phase("Plan");
|
|
40
|
+
let plan;
|
|
41
|
+
try {
|
|
42
|
+
plan = await agent(
|
|
43
|
+
`Plan bounded, source-grounded research for the user's question and any scope constraints embedded in it.\n\n` +
|
|
44
|
+
`Question and constraints (verbatim):\n${question}\n\n` +
|
|
45
|
+
`Create at most ${MAX_RESEARCH_LANES} non-overlapping lanes. Each lane needs a stable short id, title, objective, and 1-4 concrete search queries. ` +
|
|
46
|
+
"Separate primary-source discovery, current status, counterevidence, or jurisdiction/timeframe only when relevant. " +
|
|
47
|
+
"Do not claim exhaustive coverage. Structured output only.",
|
|
48
|
+
{
|
|
49
|
+
phase: "Plan",
|
|
50
|
+
label: "plan",
|
|
51
|
+
tools: EXTERNAL_TOOLS,
|
|
52
|
+
toolHints: EXTERNAL_TOOL_HINTS,
|
|
53
|
+
requireToolHints: true,
|
|
54
|
+
profile: "medium",
|
|
55
|
+
resume: "off",
|
|
56
|
+
schema: ResearchPlanSchema,
|
|
57
|
+
},
|
|
58
|
+
);
|
|
59
|
+
} catch (error) {
|
|
60
|
+
if (error instanceof WorkflowToolHintUnavailableError) return unavailableResearchReport("missing-capability");
|
|
61
|
+
throw error;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (!plan) return unavailableResearchReport("no-evidence");
|
|
65
|
+
const lanes = normalizeResearchLanes(plan);
|
|
66
|
+
if (lanes.length === 0) return unavailableResearchReport("no-evidence");
|
|
67
|
+
progress({ type: "counter", key: "research.lanes", label: "research lanes", value: lanes.length });
|
|
68
|
+
progress({ type: "summary", key: "research.question", value: question });
|
|
69
|
+
|
|
70
|
+
phase("Gather");
|
|
71
|
+
const gathered = compactResults(
|
|
72
|
+
await parallel(
|
|
73
|
+
lanes.map((lane) => async () => {
|
|
74
|
+
const result = await agent(
|
|
75
|
+
`Research one bounded lane using only installed external web-search, browsing, or URL-extraction tools.\n\n` +
|
|
76
|
+
`Question: ${question}\n` +
|
|
77
|
+
`Scope constraints: ${plan.scopeConstraints.join("; ") || "(none)"}\n` +
|
|
78
|
+
`Lane id: ${lane.id}\nLane: ${lane.title}\nObjective: ${lane.objective}\n` +
|
|
79
|
+
`Queries:\n${lane.queries.map((query) => `- ${query}`).join("\n")}\n\n` +
|
|
80
|
+
"Open the supporting pages instead of citing a search-results page. Prefer primary and authoritative sources; use independent sources when useful. " +
|
|
81
|
+
"Return concrete claims with importance, whether each page supports or conflicts with the claim, a short passage or precise paraphrase, and the exact page title and URL. " +
|
|
82
|
+
"State evidence gaps. Never invent a URL or claim that the opened page does not support. Structured output only.",
|
|
83
|
+
{
|
|
84
|
+
phase: "Gather",
|
|
85
|
+
label: `gather:${lane.id}`,
|
|
86
|
+
tools: EXTERNAL_TOOLS,
|
|
87
|
+
toolHints: EXTERNAL_TOOL_HINTS,
|
|
88
|
+
requireToolHints: true,
|
|
89
|
+
profile: "small",
|
|
90
|
+
resume: "off",
|
|
91
|
+
schema: ResearchLaneResultSchema,
|
|
92
|
+
},
|
|
93
|
+
);
|
|
94
|
+
if (!result) return null;
|
|
95
|
+
progress({ type: "counter_delta", key: "research.evidence", label: "evidence items", delta: result.evidence.length });
|
|
96
|
+
progress({
|
|
97
|
+
type: "lane_item",
|
|
98
|
+
lane: "Research lanes",
|
|
99
|
+
title: lane.title,
|
|
100
|
+
subtitle: `${result.evidence.length} evidence item(s)`,
|
|
101
|
+
status: result.evidence.length > 0 ? "success" : "warning",
|
|
102
|
+
details: result.gaps.join("; ") || lane.objective,
|
|
103
|
+
});
|
|
104
|
+
return result;
|
|
105
|
+
}),
|
|
106
|
+
),
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
const laneResults = sanitizeLaneResults(gathered);
|
|
110
|
+
const candidates = buildClaimCandidates(laneResults);
|
|
111
|
+
if (candidates.length === 0) return unavailableResearchReport("no-evidence");
|
|
112
|
+
progress({ type: "counter", key: "research.claims", label: "claims to verify", value: candidates.length });
|
|
113
|
+
log(`${candidates.length} bounded claim(s) selected for independent verification`);
|
|
114
|
+
|
|
115
|
+
phase("Verify");
|
|
116
|
+
const verificationResults = await parallel(
|
|
117
|
+
candidates.map((candidate, index) => async () => {
|
|
118
|
+
const result = await agent(verificationPrompt(question, candidate), {
|
|
119
|
+
phase: "Verify",
|
|
120
|
+
label: `verify:${index + 1}`,
|
|
121
|
+
tools: EXTERNAL_TOOLS,
|
|
122
|
+
toolHints: EXTERNAL_TOOL_HINTS,
|
|
123
|
+
requireToolHints: true,
|
|
124
|
+
profile: "medium",
|
|
125
|
+
resume: "off",
|
|
126
|
+
schema: ResearchVerificationSchema,
|
|
127
|
+
});
|
|
128
|
+
return result ? sanitizeVerification(result, candidate) : null;
|
|
129
|
+
}),
|
|
130
|
+
);
|
|
131
|
+
const verifications = verificationResults.map((result, index) => result ?? unavailableVerification(candidates[index]!));
|
|
132
|
+
for (const verification of verifications) {
|
|
133
|
+
progress({ type: "counter_delta", key: `research.${verification.verdict.toLowerCase()}`, label: verification.verdict.toLowerCase(), delta: 1 });
|
|
134
|
+
}
|
|
135
|
+
const synthesisInputs = verifications.filter((verification) => verification.verdict !== "REJECTED");
|
|
136
|
+
|
|
137
|
+
phase("Synthesize");
|
|
138
|
+
const synthesis = await agent(
|
|
139
|
+
`Answer the research question using only the independently verified handoff below.\n\n` +
|
|
140
|
+
`Question: ${question}\nScope constraints: ${plan.scopeConstraints.join("; ") || "(none)"}\n\n` +
|
|
141
|
+
`Verified claims JSON:\n${JSON.stringify(synthesisInputs)}\n\n` +
|
|
142
|
+
"Keep SUPPORTED claims, CONFLICTED evidence, UNCERTAIN claims, and model INFERENCE in their separate fields. Exclude REJECTED claims. " +
|
|
143
|
+
"Copy each verified claim string exactly so its citations remain bound to that claim during validation. " +
|
|
144
|
+
"Every supported or conflicting claim must cite exact title/URL objects from its verification; do not add URLs, cite search-results pages, or turn inference into fact. " +
|
|
145
|
+
"Answer concisely, disclose limited coverage, and provide useful next steps. Structured output only.",
|
|
146
|
+
{
|
|
147
|
+
phase: "Synthesize",
|
|
148
|
+
label: "synthesize",
|
|
149
|
+
tools: [],
|
|
150
|
+
profile: "medium",
|
|
151
|
+
resume: "off",
|
|
152
|
+
schema: ResearchReportSchema,
|
|
153
|
+
},
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
return sanitizeResearchReport(
|
|
157
|
+
synthesis ?? fallbackResearchReport(synthesisInputs, "The model did not return a structured synthesis."),
|
|
158
|
+
synthesisInputs,
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function verificationPrompt(question: string, candidate: ResearchClaimCandidate): string {
|
|
163
|
+
return `Independently verify one important research claim using installed external web-search, browsing, or URL-extraction tools.\n\n` +
|
|
164
|
+
`Question: ${question}\nClaim: ${candidate.claim}\nImportance: ${candidate.importance}\n\n` +
|
|
165
|
+
`Gather-stage evidence (context only; do not treat it as verified):\n${JSON.stringify(candidate.evidence)}\n\n` +
|
|
166
|
+
"Search independently and open direct supporting pages. Prefer primary/authoritative sources and actively look for credible counterevidence. " +
|
|
167
|
+
"Return SUPPORTED only when direct pages substantiate the claim, CONFLICTED when credible sources disagree, UNCERTAIN when evidence is insufficient, " +
|
|
168
|
+
"INFERENCE when the conclusion is reasoned rather than directly stated, or REJECTED when evidence refutes it. " +
|
|
169
|
+
"Include exact page titles and direct HTTP(S) URLs, never search-results URLs. Structured output only.";
|
|
170
|
+
}
|
package/README.md
CHANGED
|
@@ -4,63 +4,48 @@
|
|
|
4
4
|
[](https://www.npmjs.com/package/pi-workflow-engine)
|
|
5
5
|
[](LICENSE)
|
|
6
6
|
|
|
7
|
-
**
|
|
7
|
+
**Multi-agent workflows for [pi](https://pi.dev).**
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
The process is simple: **scope → fan out → verify → synthesize**. You see the work
|
|
14
|
-
live in the TUI, concurrency stays bounded, and the final answer includes the
|
|
15
|
-
subagents' combined usage and estimated cost when the provider exposes enough
|
|
16
|
-
data to calculate them.
|
|
9
|
+
When a task benefits from independent review, competing hypotheses, or separate
|
|
10
|
+
verification, pi-workflow-engine fans it out to subagents and synthesizes one
|
|
11
|
+
result. Run a built-in workflow or add `dynamax` to a prompt so pi can compose a
|
|
12
|
+
one-off workflow for the task.
|
|
17
13
|
|
|
18
14
|

|
|
19
15
|
|
|
20
16
|
## Quick start
|
|
21
17
|
|
|
18
|
+
Requires **pi 0.80.10 or newer**.
|
|
19
|
+
|
|
22
20
|
```bash
|
|
23
21
|
pi install npm:pi-workflow-engine
|
|
24
22
|
```
|
|
25
23
|
|
|
26
|
-
Restart pi or run `/reload`, then
|
|
24
|
+
Restart pi or run `/reload`, then try either style:
|
|
27
25
|
|
|
28
26
|
```text
|
|
29
27
|
dynamax investigate why typecheck started failing on this branch
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
`dynamax` is a one-shot opt-in. It lets the host agent choose a saved workflow
|
|
33
|
-
or author a temporary one for this task. Use `/workflow:dynamax on` when you
|
|
34
|
-
want that permission to remain active for the session.
|
|
35
|
-
|
|
36
|
-
Saved workflows are available directly:
|
|
37
28
|
|
|
38
|
-
```text
|
|
39
29
|
/workflow code-review
|
|
40
30
|
/workflow refactor-scout src/
|
|
41
31
|
/workflow diagnose "the schema migration broke typecheck"
|
|
42
|
-
/workflow perf-review "workflow startup latency"
|
|
43
32
|
```
|
|
44
33
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
## What
|
|
49
|
-
|
|
50
|
-
- **Independent
|
|
51
|
-
|
|
52
|
-
- **
|
|
53
|
-
|
|
54
|
-
- **Live
|
|
55
|
-
|
|
56
|
-
- **
|
|
57
|
-
|
|
58
|
-
- **
|
|
59
|
-
|
|
60
|
-
- **Reviewable mutation.** An author can opt a mutating agent into a disposable
|
|
61
|
-
git worktree and receive its patch.
|
|
62
|
-
- **Safe replay.** Interrupted runs reuse a completed call only when every
|
|
63
|
-
captured observable surface and its effective execution identity still match.
|
|
34
|
+
Built-in workflows inspect and report by default; they do not edit your working
|
|
35
|
+
tree.
|
|
36
|
+
|
|
37
|
+
## What you get
|
|
38
|
+
|
|
39
|
+
- **Independent analysis.** Give correctness, testing, performance, or other
|
|
40
|
+
concerns to separate agents instead of asking one agent to cover everything.
|
|
41
|
+
- **Verified results.** Workflows can check and rank findings before presenting
|
|
42
|
+
a single synthesis.
|
|
43
|
+
- **Live visibility.** Follow phases and agents in the TUI, with usage and cost
|
|
44
|
+
totals when the provider reports them.
|
|
45
|
+
- **Controlled execution.** Concurrency, timeouts, agent counts, and token
|
|
46
|
+
budgets keep fan-out bounded.
|
|
47
|
+
- **Safe follow-up.** Advisory runs leave the checkout alone, while selected
|
|
48
|
+
review fixes can return isolated patch previews.
|
|
64
49
|
|
|
65
50
|
## Built-in workflows
|
|
66
51
|
|
|
@@ -69,115 +54,63 @@ bundle a second agent runtime.
|
|
|
69
54
|
| `code-review` | PRs, branch diffs, ref ranges, or focused targets |
|
|
70
55
|
| `refactor-scout` | Small, defensible refactors without broad rewrites |
|
|
71
56
|
| `diagnose` | Competing explanations for bugs or failing commands |
|
|
72
|
-
| `perf-review` | Measured bottlenecks
|
|
57
|
+
| `perf-review` | Measured bottlenecks rather than performance guesses |
|
|
58
|
+
| `research` | Cited external evidence with independent claim verification |
|
|
73
59
|
|
|
74
|
-
|
|
75
|
-
|
|
60
|
+
The `research` workflow needs an installed pi tool that can search or browse the
|
|
61
|
+
web. See the [built-in workflow guide](USAGE.md#built-in-workflows) for behavior
|
|
62
|
+
and requirements.
|
|
76
63
|
|
|
77
|
-
##
|
|
64
|
+
## Use Dynamax for one-off workflows
|
|
78
65
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
independently verified, deduplicated, and ranked before synthesis.
|
|
66
|
+
Use `dynamax` when no saved workflow quite fits and independent passes are
|
|
67
|
+
likely to change the answer:
|
|
82
68
|
|
|
83
|
-
|
|
84
|
-
|
|
69
|
+
```text
|
|
70
|
+
dynamax review this branch for correctness, tests, and maintainability; verify every finding
|
|
71
|
+
dynamax investigate this flaky test using separate timing, fixture, diff, and external-state hypotheses
|
|
72
|
+
dynamax argue both implementation options, then have another agent challenge the recommendation
|
|
73
|
+
```
|
|
85
74
|
|
|
86
|
-
The
|
|
87
|
-
|
|
88
|
-
comments are available only for a verified PR target; the engine checks the
|
|
89
|
-
snapshot and PR head again and skips exact duplicates before posting.
|
|
75
|
+
The token enables Dynamax for one turn. Sticky mode remains active for the pi
|
|
76
|
+
session:
|
|
90
77
|
|
|
91
|
-
|
|
78
|
+
```text
|
|
79
|
+
/workflow:dynamax on
|
|
80
|
+
/workflow:dynamax off
|
|
81
|
+
/workflow:dynamax status
|
|
82
|
+
```
|
|
92
83
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
- **Decide:** `dynamax` argue both implementation options, then have another
|
|
98
|
-
agent attack the recommendation.
|
|
99
|
-
- **Refactor:** `dynamax` find the smallest safe path through this module and
|
|
100
|
-
identify what should not change.
|
|
84
|
+
In the TUI, a standalone `dynamax` token receives a short moving-shine sweep and
|
|
85
|
+
then stays highlighted. Use `PI_DYNAMAX_EFFECT=static` or
|
|
86
|
+
`PI_DYNAMAX_EFFECT=off` to reduce or disable the cue; the
|
|
87
|
+
[prompt editor guide](USAGE.md#prompt-editor-cue) has the full details.
|
|
101
88
|
|
|
102
89
|
Tiny edits and straightforward questions are still better handled by one agent.
|
|
103
|
-
Dynamax
|
|
104
|
-
|
|
105
|
-
##
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
export const meta: WorkflowMeta = {
|
|
116
|
-
name: "two-angle-review",
|
|
117
|
-
description: "Find issues independently, then synthesize.",
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
const Finding = Type.Object({
|
|
121
|
-
summary: Type.String(),
|
|
122
|
-
evidence: Type.Array(Type.String()),
|
|
123
|
-
});
|
|
124
|
-
const reviewTools = ["read", "grep", "find", "ls"];
|
|
125
|
-
|
|
126
|
-
export default async function run(
|
|
127
|
-
{ agent, parallel, phase, args }: WorkflowApi,
|
|
128
|
-
) {
|
|
129
|
-
phase("Find");
|
|
130
|
-
const findings = await parallel([
|
|
131
|
-
() => agent(`Review correctness: ${args}`, {
|
|
132
|
-
schema: Finding,
|
|
133
|
-
tools: reviewTools,
|
|
134
|
-
thinkingLevel: "low",
|
|
135
|
-
resume: "read-only",
|
|
136
|
-
}),
|
|
137
|
-
() => agent(`Review edge cases: ${args}`, {
|
|
138
|
-
schema: Finding,
|
|
139
|
-
tools: reviewTools,
|
|
140
|
-
thinkingLevel: "low",
|
|
141
|
-
resume: "read-only",
|
|
142
|
-
}),
|
|
143
|
-
]);
|
|
144
|
-
|
|
145
|
-
phase("Synthesize");
|
|
146
|
-
return agent(`Merge and rank these findings: ${JSON.stringify(findings)}`, {
|
|
147
|
-
tools: [],
|
|
148
|
-
thinkingLevel: "medium",
|
|
149
|
-
resume: "read-only",
|
|
150
|
-
});
|
|
151
|
-
}
|
|
90
|
+
Dynamax is useful when independence or breadth materially improves the result.
|
|
91
|
+
|
|
92
|
+
## Review and inspect results
|
|
93
|
+
|
|
94
|
+
`code-review` verifies, deduplicates, and ranks candidate findings. Open the
|
|
95
|
+
interactive findings view for follow-up, or bring back the latest result without
|
|
96
|
+
rerunning the workflow:
|
|
97
|
+
|
|
98
|
+
```text
|
|
99
|
+
/workflow code-review --result-viewer
|
|
100
|
+
/workflow:results
|
|
101
|
+
/workflow:inspector
|
|
152
102
|
```
|
|
153
103
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
by pi.
|
|
165
|
-
- **Recoverable failures:** a failed parallel branch becomes `null`; surviving
|
|
166
|
-
work continues.
|
|
167
|
-
- **Fatal failures:** cancellation aborts siblings and drains submitted work
|
|
168
|
-
before rejection.
|
|
169
|
-
- **Mutating agents:** disposable worktrees isolate edits and return
|
|
170
|
-
baseline-relative patches.
|
|
171
|
-
- **Resume:** journals bind workspace-aware calls to repository state and all
|
|
172
|
-
calls to workflow, model, prompt, skill, and tool identity.
|
|
173
|
-
- **Dependencies:** pi and TypeBox remain host-provided peers; the package ships
|
|
174
|
-
no duplicate runtime stack.
|
|
175
|
-
|
|
176
|
-
The replay contract deliberately fails closed. For workspace-aware calls,
|
|
177
|
-
changed commits, dirty state, and declared ignored inputs invalidate a hit.
|
|
178
|
-
Workflow source, effective model or prompt, selected skills, and executable
|
|
179
|
-
tools remain part of the relevant identity; unsafe or unbounded surfaces run
|
|
180
|
-
live instead.
|
|
104
|
+
The viewer can produce isolated patch previews for selected findings without
|
|
105
|
+
changing the active checkout. The [usage guide](USAGE.md#workflow-results)
|
|
106
|
+
covers review actions and recent run history.
|
|
107
|
+
|
|
108
|
+
## Create your own workflows
|
|
109
|
+
|
|
110
|
+
Saved workflows are TypeScript modules for repeatable orchestration; inline
|
|
111
|
+
workflows are useful for one-off Dynamax tasks. The
|
|
112
|
+
[workflow authoring guide](USAGE.md#author-a-saved-workflow) covers the API,
|
|
113
|
+
typed handoffs, model profiles, tool access, composition, and registration.
|
|
181
114
|
|
|
182
115
|
## Develop locally
|
|
183
116
|
|
|
@@ -192,11 +125,9 @@ pi -ne -e .
|
|
|
192
125
|
`pi -ne -e .` loads the working copy without also loading an installed global
|
|
193
126
|
copy. There is no build step; pi loads the TypeScript extension directly.
|
|
194
127
|
|
|
195
|
-
For the complete command reference,
|
|
196
|
-
|
|
197
|
-
[
|
|
198
|
-
[code-review workflow](.pi/extensions/pi-workflow-engine/workflows/code-review.ts)
|
|
199
|
-
is the most complete example.
|
|
128
|
+
For the complete command reference, model configuration, workflow authoring,
|
|
129
|
+
runtime controls, resume behavior, and troubleshooting, see
|
|
130
|
+
[USAGE.md](USAGE.md).
|
|
200
131
|
|
|
201
132
|
Questions and ideas are welcome in
|
|
202
133
|
[GitHub Issues](https://github.com/timbrinded/pi-workflow-engine/issues).
|