pi-agent-flow 1.4.4 → 1.5.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/README.md +4 -2
- package/agents/build.md +4 -2
- package/agents/debug.md +4 -1
- package/package.json +1 -1
- package/src/agents.ts +12 -0
- package/src/config.ts +21 -1
- package/src/index.ts +11 -5
- package/src/render-utils.ts +15 -12
- package/src/render.ts +2 -2
package/README.md
CHANGED
|
@@ -81,8 +81,8 @@ The result is faster, cheaper, and cleaner delegation: the main agent remains un
|
|
|
81
81
|
| Flow | Purpose | Tools | Tier |
|
|
82
82
|
|------|---------|-------|------|
|
|
83
83
|
| `[scout]` | Discover files, trace code paths, map architecture | `batch`, `bash`, `find`, `grep`, `ls` | `lite` |
|
|
84
|
-
| `[debug]` | Investigate logs, errors, stack traces, root causes | `batch`, `bash`, `find`, `grep`, `ls` | `lite` |
|
|
85
|
-
| `[build]` | Implement features, fix bugs, write tests, ship | `batch`, `bash`, `find`, `grep`, `ls` | `flash` |
|
|
84
|
+
| `[debug]` | Investigate logs, errors, stack traces, root causes, and update relevant troubleshooting docs | `batch`, `bash`, `find`, `grep`, `ls` | `lite` |
|
|
85
|
+
| `[build]` | Implement features, fix bugs, write tests, update relevant docs, ship | `batch`, `bash`, `find`, `grep`, `ls` | `flash` |
|
|
86
86
|
| `[craft]` | Plan structure, break down requirements, design solutions | `batch`, `bash`, `find`, `grep`, `ls` | `full` |
|
|
87
87
|
| `[audit]` | Audit security, quality, correctness; fix issues autonomously | `batch`, `bash`, `find`, `grep`, `ls` | `flash` |
|
|
88
88
|
| `[ideas]` | Generate ideas and explore possibilities with inherited context | `batch`, `bash` | `full` |
|
|
@@ -91,6 +91,8 @@ The result is faster, cheaper, and cleaner delegation: the main agent remains un
|
|
|
91
91
|
|
|
92
92
|
> **Clean slate:** Set `inheritContext: false` in a custom flow's front-matter so it receives only the intent, ideal for unbiased creative work.
|
|
93
93
|
|
|
94
|
+
> **Docs hygiene:** Bundled `build` and `debug` flows are instructed to update relevant documentation after their work when the findings or implementation change developer or operational knowledge. If no docs apply, they should state why in the final report.
|
|
95
|
+
|
|
94
96
|
### Session modes
|
|
95
97
|
|
|
96
98
|
Each flow call may set `sessionMode` to choose the child-agent time budget:
|
package/agents/build.md
CHANGED
|
@@ -17,8 +17,9 @@ During this build flow — your mission is to implement and verify changes. Be a
|
|
|
17
17
|
4. Execute — implement changes following core principles.
|
|
18
18
|
5. Refactor — clean up only if the change is working.
|
|
19
19
|
6. Verify — run tests and relevant checks before considering the work done.
|
|
20
|
-
7.
|
|
21
|
-
8.
|
|
20
|
+
7. Document — update relevant docs after the implementation and verification are settled; if no docs apply, state why.
|
|
21
|
+
8. Ship — commit, push, monitor CI/CD, and fix failures until green when shipping is in scope.
|
|
22
|
+
9. Finalize — confirm implementation, docs, tests, and CI/CD status.
|
|
22
23
|
|
|
23
24
|
## Rules
|
|
24
25
|
|
|
@@ -28,6 +29,7 @@ During this build flow — your mission is to implement and verify changes. Be a
|
|
|
28
29
|
- If already on a feature/fix branch, continue on it.
|
|
29
30
|
- Commit with a clear conventional message such as `feat:`, `fix:`, or `refactor:` when committing is in scope.
|
|
30
31
|
- Push only after local verification passes when shipping is in scope.
|
|
32
|
+
- Update relevant documentation after finishing the work; if no docs changed, explain why in the final report.
|
|
31
33
|
- If CI/CD fails, diagnose, fix, commit, push, and repeat until green.
|
|
32
34
|
- If an unexpected error or trace is needed, recommend [debug] rather than guessing.
|
|
33
35
|
|
package/agents/debug.md
CHANGED
|
@@ -16,6 +16,8 @@ During this debug flow — your mission is to investigate root cause. Be forensi
|
|
|
16
16
|
3. Check changes — inspect recent diffs, configuration, dependencies, and environment differences.
|
|
17
17
|
4. Identify root cause — state exactly what is broken and why.
|
|
18
18
|
5. Recommend fix — propose the smallest safe correction only after evidence confirms the cause.
|
|
19
|
+
6. Document — update relevant docs, runbooks, or troubleshooting notes after finishing the investigation; if no docs apply, state why.
|
|
20
|
+
7. Finalize — confirm root cause, evidence, documentation updates, and recommended next steps.
|
|
19
21
|
|
|
20
22
|
## Rules
|
|
21
23
|
|
|
@@ -23,7 +25,8 @@ During this debug flow — your mission is to investigate root cause. Be forensi
|
|
|
23
25
|
- Read logs and symptoms before reading broad code areas.
|
|
24
26
|
- Use `batch` with `o: "read"`, `s: <offset>`, and `l: <limit>` for targeted file reading instead of bash `sed`/`head`/`tail`.
|
|
25
27
|
- Do not suggest fixes until root cause is confirmed.
|
|
26
|
-
-
|
|
28
|
+
- Documentation-only updates are required after finishing the work when relevant and safe; if no docs changed, explain why in the final report.
|
|
29
|
+
- Do not implement product-code changes from this flow unless explicitly requested.
|
|
27
30
|
|
|
28
31
|
## Note
|
|
29
32
|
Treat this as a clean-slate system rewrite, unless explicitly mentioned in the requirements. Perform a comprehensive migration with zero requirements for backwards compatibility. You must ensure that all residual code, variable names, test suites, and documentation are fully refactored and perfectly aligned with the new architecture.
|
package/package.json
CHANGED
package/src/agents.ts
CHANGED
|
@@ -56,6 +56,18 @@ export function getFlowTier(flowName: string): FlowTier {
|
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
/** Return the bundled flow names associated with a given tier. */
|
|
60
|
+
export function getTierFlowNames(tier: FlowTier): string[] {
|
|
61
|
+
switch (tier) {
|
|
62
|
+
case "lite":
|
|
63
|
+
return ["scout", "debug"];
|
|
64
|
+
case "flash":
|
|
65
|
+
return ["build", "audit"];
|
|
66
|
+
case "full":
|
|
67
|
+
return ["ideas", "craft"];
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
59
71
|
// ---------------------------------------------------------------------------
|
|
60
72
|
// Internal helpers
|
|
61
73
|
// ---------------------------------------------------------------------------
|
package/src/config.ts
CHANGED
|
@@ -9,8 +9,8 @@ import * as fs from "node:fs";
|
|
|
9
9
|
import * as os from "node:os";
|
|
10
10
|
import * as path from "node:path";
|
|
11
11
|
import { parseAgentSessionMode, type AgentSessionMode } from "./session-mode.js";
|
|
12
|
+
import { type FlowTier } from "./agents.js";
|
|
12
13
|
|
|
13
|
-
export type FlowTier = "lite" | "flash" | "full";
|
|
14
14
|
|
|
15
15
|
export interface FlowModelTierConfig {
|
|
16
16
|
primary?: string;
|
|
@@ -369,3 +369,23 @@ export function resolveFlowModelCandidates(opts: {
|
|
|
369
369
|
|
|
370
370
|
return { primary: candidates[0], candidates };
|
|
371
371
|
}
|
|
372
|
+
|
|
373
|
+
export function formatFlowModelStrategy(modeName: string, strategy: FlowModelStrategy): string {
|
|
374
|
+
const tiers: FlowTier[] = ["lite", "flash", "full"];
|
|
375
|
+
const parts: string[] = [];
|
|
376
|
+
for (const tier of tiers) {
|
|
377
|
+
const config = strategy[tier];
|
|
378
|
+
const hasPrimary = Boolean(config?.primary);
|
|
379
|
+
const hasFailover = config?.failover && config.failover.length > 0;
|
|
380
|
+
let value: string;
|
|
381
|
+
if (hasPrimary) {
|
|
382
|
+
value = config!.primary!;
|
|
383
|
+
} else if (hasFailover) {
|
|
384
|
+
value = `failover: ${config!.failover!.join(", ")}`;
|
|
385
|
+
} else {
|
|
386
|
+
value = "(default)";
|
|
387
|
+
}
|
|
388
|
+
parts.push(`${tier}: ${value}`);
|
|
389
|
+
}
|
|
390
|
+
return `mode: ${modeName} | ${parts.join(" · ")}`;
|
|
391
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
resolveFlowModelCandidates,
|
|
18
18
|
selectFlowModelStrategy,
|
|
19
19
|
writeGlobalFlowMode,
|
|
20
|
+
formatFlowModelStrategy,
|
|
20
21
|
type LoadedFlowModelConfigs,
|
|
21
22
|
} from "./config.js";
|
|
22
23
|
import { getInheritedCliArgs } from "./cli-args.js";
|
|
@@ -727,8 +728,10 @@ export default function (pi: ExtensionAPI) {
|
|
|
727
728
|
);
|
|
728
729
|
} else {
|
|
729
730
|
try {
|
|
730
|
-
|
|
731
|
-
|
|
731
|
+
writeGlobalFlowMode(requestedFlowMode);
|
|
732
|
+
const strategy = loadedFlowModelConfigs.configs[requestedFlowMode] ?? {};
|
|
733
|
+
const strategyDescription = formatFlowModelStrategy(requestedFlowMode, strategy);
|
|
734
|
+
console.warn(strategyDescription);
|
|
732
735
|
} catch (error) {
|
|
733
736
|
const message = error instanceof Error ? error.message : String(error);
|
|
734
737
|
console.warn(`[pi-agent-flow] ${message}`);
|
|
@@ -1091,7 +1094,12 @@ flow [type] accomplished
|
|
|
1091
1094
|
pi.emit("pi-agent-flow:ready", pluginApi);
|
|
1092
1095
|
}
|
|
1093
1096
|
|
|
1094
|
-
// Register cleanup on process exit (once)
|
|
1097
|
+
// Register cleanup on process exit (once).
|
|
1098
|
+
// We intentionally do NOT hook SIGINT/SIGTERM here. A plugin must not
|
|
1099
|
+
// override the host process signal handling; doing so can cut off the
|
|
1100
|
+
// host's terminal-cleanup logic and leave escape sequences or status
|
|
1101
|
+
// lines visible on Ctrl+C. The 'exit' event fires for normal exits,
|
|
1102
|
+
// including when the host handles the signal and calls process.exit().
|
|
1095
1103
|
if (!(globalThis as any).__pi_agent_flow_shutdown_registered) {
|
|
1096
1104
|
(globalThis as any).__pi_agent_flow_shutdown_registered = true;
|
|
1097
1105
|
const emitShutdown = () => {
|
|
@@ -1100,8 +1108,6 @@ flow [type] accomplished
|
|
|
1100
1108
|
}
|
|
1101
1109
|
};
|
|
1102
1110
|
process.on("exit", emitShutdown);
|
|
1103
|
-
process.on("SIGINT", () => { emitShutdown(); process.exit(130); });
|
|
1104
|
-
process.on("SIGTERM", () => { emitShutdown(); process.exit(143); });
|
|
1105
1111
|
}
|
|
1106
1112
|
|
|
1107
1113
|
}
|
package/src/render-utils.ts
CHANGED
|
@@ -47,27 +47,30 @@ export function formatCompactTokenPair(usage: Partial<UsageStats>): string {
|
|
|
47
47
|
return `↑ ${formatFixedTokens(usage.input || 0)} · ↓ ${formatFixedTokens(usage.output || 0)}`;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
export function formatCompactStats(
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
50
|
+
export function formatCompactStats(
|
|
51
|
+
usage: Partial<UsageStats>,
|
|
52
|
+
model?: string,
|
|
53
|
+
maxWidth?: number,
|
|
54
|
+
options: { skipTokens?: boolean } = {},
|
|
55
|
+
): string {
|
|
56
|
+
const tokenParts = [`↑ ${formatFixedTokens(usage.input || 0)}`, `↓ ${formatFixedTokens(usage.output || 0)}`];
|
|
57
|
+
const runtimeParts = [`tps: ${formatTps(usage.smoothedTps)}`, `ctx: ${formatFixedTokens(usage.contextTokens || 0)}`];
|
|
58
|
+
const parts = options.skipTokens ? runtimeParts : [...tokenParts, ...runtimeParts];
|
|
56
59
|
|
|
57
60
|
const displayModel = model ? model.replace(/^[^/]+\//, "") : undefined;
|
|
58
61
|
let result = parts.join(" · ") + (displayModel ? ` · ${displayModel}` : "");
|
|
59
62
|
if (maxWidth && visibleLength(result) > maxWidth) {
|
|
60
|
-
// Drop model first
|
|
63
|
+
// Drop model first.
|
|
61
64
|
let narrow = parts.join(" · ");
|
|
62
65
|
if (visibleLength(narrow) <= maxWidth) return narrow;
|
|
63
66
|
|
|
64
|
-
// Drop context tokens
|
|
65
|
-
const
|
|
66
|
-
narrow =
|
|
67
|
+
// Drop context tokens next.
|
|
68
|
+
const withoutContext = parts.filter((part) => !part.startsWith("ctx:"));
|
|
69
|
+
narrow = withoutContext.join(" · ");
|
|
67
70
|
if (visibleLength(narrow) <= maxWidth) return narrow;
|
|
68
71
|
|
|
69
|
-
// Bare minimum
|
|
70
|
-
narrow =
|
|
72
|
+
// Bare minimum: token pair for normal stats, tps for token-free headers.
|
|
73
|
+
narrow = options.skipTokens ? runtimeParts[0] : tokenParts.join(" · ");
|
|
71
74
|
if (visibleLength(narrow) <= maxWidth) return narrow;
|
|
72
75
|
|
|
73
76
|
return truncateChars(result, maxWidth);
|
package/src/render.ts
CHANGED
|
@@ -319,7 +319,7 @@ function renderFlowCollapsed(
|
|
|
319
319
|
): Container {
|
|
320
320
|
const container = new Container();
|
|
321
321
|
const maxWidth = process.stdout.columns ?? 80;
|
|
322
|
-
const stats = formatCompactStats(r.usage, r.model, maxWidth);
|
|
322
|
+
const stats = formatCompactStats(r.usage, r.model, maxWidth, { skipTokens: true });
|
|
323
323
|
const typeName = formatFlowTypeName(r.type);
|
|
324
324
|
let header = `${theme.fg("accent", theme.bold(typeName))} ${theme.fg("dim", stats)}`;
|
|
325
325
|
if (error && r.stopReason) header += ` ${theme.fg("error", `[${r.stopReason}]`)}`;
|
|
@@ -451,7 +451,7 @@ function renderActivityPanel(
|
|
|
451
451
|
for (let i = 0; i < results.length; i++) {
|
|
452
452
|
const r = results[i];
|
|
453
453
|
const isLast = i === results.length - 1;
|
|
454
|
-
const stats = formatCompactStats(r.usage, r.model, maxWidth);
|
|
454
|
+
const stats = formatCompactStats(r.usage, r.model, maxWidth, { skipTokens: true });
|
|
455
455
|
const error = isFlowError(r);
|
|
456
456
|
const typeName = formatFlowTypeName(r.type);
|
|
457
457
|
|