pi-agent-flow 0.1.0-alpha.4 → 0.1.0-alpha.6
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/package.json +2 -1
- package/render-utils.ts +53 -0
- package/render.ts +10 -10
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-agent-flow",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.6",
|
|
4
4
|
"description": "Flow-state delegation extension for Pi coding agent.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"runner-cli.js",
|
|
12
12
|
"runner-events.js",
|
|
13
13
|
"render.ts",
|
|
14
|
+
"render-utils.ts",
|
|
14
15
|
"types.ts",
|
|
15
16
|
"agents/",
|
|
16
17
|
"README.md"
|
package/render-utils.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure utility functions for rendering — extracted for testability.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { UsageStats } from "./types.js";
|
|
6
|
+
|
|
7
|
+
export function formatTokens(count: number): string {
|
|
8
|
+
if (count < 1000) return count.toString();
|
|
9
|
+
if (count < 10000) return `${(count / 1000).toFixed(1)}k`;
|
|
10
|
+
if (count < 1000000) return `${Math.round(count / 1000)}k`;
|
|
11
|
+
return `${(count / 1000000).toFixed(1)}M`;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function formatFlowUsage(usage: Partial<UsageStats>, model?: string): string {
|
|
15
|
+
const parts: string[] = [];
|
|
16
|
+
if (usage.toolCalls && usage.toolCalls > 0) parts.push(`${usage.toolCalls} calls`);
|
|
17
|
+
if (usage.turns) parts.push(`${usage.turns} turn${usage.turns > 1 ? "s" : ""}`);
|
|
18
|
+
if (usage.input) parts.push(`↑${formatTokens(usage.input)}`);
|
|
19
|
+
if (usage.output) parts.push(`↓${formatTokens(usage.output)}`);
|
|
20
|
+
if (usage.cacheRead) parts.push(`CR:${formatTokens(usage.cacheRead)}`);
|
|
21
|
+
if (usage.cacheWrite) parts.push(`CW:${formatTokens(usage.cacheWrite)}`);
|
|
22
|
+
if (usage.cost) parts.push(`$${usage.cost.toFixed(4)}`);
|
|
23
|
+
if (usage.contextTokens && usage.contextTokens > 0) parts.push(`ctx:${formatTokens(usage.contextTokens)}`);
|
|
24
|
+
if (model) parts.push(model);
|
|
25
|
+
return parts.join(" ");
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function formatCompactStats(usage: Partial<UsageStats>, model?: string): string {
|
|
29
|
+
const io: string[] = [];
|
|
30
|
+
if (usage.input) io.push(`↑${formatTokens(usage.input)}`);
|
|
31
|
+
if (usage.output) io.push(`↓${formatTokens(usage.output)}`);
|
|
32
|
+
const meta: string[] = [];
|
|
33
|
+
if (usage.cacheRead) meta.push(`CR:${formatTokens(usage.cacheRead)}`);
|
|
34
|
+
if (usage.contextTokens && usage.contextTokens > 0) meta.push(`ctx:${formatTokens(usage.contextTokens)}`);
|
|
35
|
+
if (model) meta.push(model);
|
|
36
|
+
const parts: string[] = [];
|
|
37
|
+
if (io.length) parts.push(io.join(" "));
|
|
38
|
+
if (meta.length) parts.push(meta.join(" "));
|
|
39
|
+
return parts.join(" │ ");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function truncateChars(text: string, max: number): string {
|
|
43
|
+
if (text.length <= max) return text;
|
|
44
|
+
const head = Math.ceil(max * 0.6);
|
|
45
|
+
const tail = max - head - 3;
|
|
46
|
+
return text.slice(0, head) + " ... " + text.slice(-tail);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function tailText(text: string, max: number): string {
|
|
50
|
+
const flat = text.replace(/[\n\r\t]+/g, " ").replace(/ +/g, " ").trim();
|
|
51
|
+
if (flat.length <= max) return flat;
|
|
52
|
+
return flat.slice(-max);
|
|
53
|
+
}
|
package/render.ts
CHANGED
|
@@ -235,10 +235,8 @@ function renderFlowCollapsed(
|
|
|
235
235
|
if (error && r.stopReason) text += ` ${theme.fg("error", `[${r.stopReason}]`)}`;
|
|
236
236
|
|
|
237
237
|
// Intent line
|
|
238
|
-
const hasOutput = !!(flowOutput || streamingText || (error && r.errorMessage));
|
|
239
238
|
if (r.intent) {
|
|
240
|
-
|
|
241
|
-
text += `\n${theme.fg("dim", `${prefix}─ int:`)} ${theme.fg("dim", truncateChars(r.intent, 40))}`;
|
|
239
|
+
text += `\n${theme.fg("dim", `├─ int:`)} ${theme.fg("dim", truncateChars(r.intent, 40))}`;
|
|
242
240
|
}
|
|
243
241
|
|
|
244
242
|
// Output line
|
|
@@ -248,6 +246,8 @@ function renderFlowCollapsed(
|
|
|
248
246
|
text += `\n${theme.fg("dim", "└─ msg:")} ${theme.fg("dim", tailText(streamingText, 40))}`;
|
|
249
247
|
} else if (error && r.errorMessage) {
|
|
250
248
|
text += `\n${theme.fg("dim", "└─ msg:")} ${theme.fg("error", truncateChars(r.errorMessage, 25))}`;
|
|
249
|
+
} else {
|
|
250
|
+
text += `\n${theme.fg("dim", "└─ msg:")} ${theme.fg("dim", "[n/a]")}`;
|
|
251
251
|
}
|
|
252
252
|
|
|
253
253
|
return new Text(text, 0, 0);
|
|
@@ -270,7 +270,7 @@ function renderMultiFlowResult(
|
|
|
270
270
|
if (expanded) {
|
|
271
271
|
return renderMultiFlowExpanded(results, successCount, icon, theme);
|
|
272
272
|
}
|
|
273
|
-
return renderMultiFlowCollapsed(results,
|
|
273
|
+
return renderMultiFlowCollapsed(results, theme);
|
|
274
274
|
}
|
|
275
275
|
|
|
276
276
|
function renderMultiFlowExpanded(
|
|
@@ -324,11 +324,9 @@ function renderMultiFlowExpanded(
|
|
|
324
324
|
|
|
325
325
|
function renderMultiFlowCollapsed(
|
|
326
326
|
results: SingleResult[],
|
|
327
|
-
successCount: number,
|
|
328
|
-
icon: string,
|
|
329
327
|
theme: FlowTheme,
|
|
330
328
|
): Text {
|
|
331
|
-
let text =
|
|
329
|
+
let text = "";
|
|
332
330
|
|
|
333
331
|
for (let i = 0; i < results.length; i++) {
|
|
334
332
|
const r = results[i];
|
|
@@ -339,22 +337,22 @@ function renderMultiFlowCollapsed(
|
|
|
339
337
|
|
|
340
338
|
// Header line
|
|
341
339
|
const headerPrefix = isLast ? "└─" : "├─";
|
|
342
|
-
let line =
|
|
340
|
+
let line = `${theme.fg("dim", headerPrefix)} ${theme.bg("selectedBg", theme.fg("accent", theme.bold(r.type)))}`;
|
|
343
341
|
if (stats) {
|
|
344
342
|
line += ` ${theme.fg("dim", "─")} ${theme.fg("dim", stats)}`;
|
|
345
343
|
}
|
|
346
344
|
if (error && r.stopReason) {
|
|
347
345
|
line += ` ${theme.fg("error", `[${r.stopReason}]`)}`;
|
|
348
346
|
}
|
|
347
|
+
if (i > 0) text += "\n";
|
|
349
348
|
text += line;
|
|
350
349
|
|
|
351
350
|
// Continuation indent for sub-lines
|
|
352
351
|
const indent = isLast ? " " : "│ ";
|
|
353
352
|
|
|
354
353
|
// Intent line
|
|
355
|
-
const hasOutput = !!(flowOutput || (error && r.errorMessage));
|
|
356
354
|
if (r.intent) {
|
|
357
|
-
const intentPrefix =
|
|
355
|
+
const intentPrefix = hasMsg ? "├─" : "└─";
|
|
358
356
|
text += `\n${theme.fg("dim", indent + intentPrefix + " int:")} ${theme.fg("dim", truncateChars(r.intent, 40))}`;
|
|
359
357
|
}
|
|
360
358
|
|
|
@@ -363,6 +361,8 @@ function renderMultiFlowCollapsed(
|
|
|
363
361
|
text += `\n${theme.fg("dim", indent + "└─ msg:")} ${renderFlowReport(truncateChars(flowOutput, 25), theme)}`;
|
|
364
362
|
} else if (error && r.errorMessage) {
|
|
365
363
|
text += `\n${theme.fg("dim", indent + "└─ msg:")} ${theme.fg("error", truncateChars(r.errorMessage, 25))}`;
|
|
364
|
+
} else {
|
|
365
|
+
text += `\n${theme.fg("dim", indent + "└─ msg:")} ${theme.fg("dim", "[n/a]")}`;
|
|
366
366
|
}
|
|
367
367
|
}
|
|
368
368
|
|