pi-agent-flow 1.1.0 → 1.2.2

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.
@@ -50,8 +50,8 @@ export function formatCompactStats(usage: Partial<UsageStats>, model?: string, m
50
50
  parts.push(`tps: ${formatTps(usage.smoothedTps)}`);
51
51
  parts.push(`ctx: ${formatFixedTokens(usage.contextTokens || 0)}`);
52
52
 
53
- let result = parts.join(" · ") + (model ? ` · ${model}` : "");
54
-
53
+ const displayModel = model ? model.replace(/^[^/]+\//, "") : undefined;
54
+ let result = parts.join(" · ") + (displayModel ? ` · ${displayModel}` : "");
55
55
  if (maxWidth && visibleLength(result) > maxWidth) {
56
56
  // Drop model first
57
57
  let narrow = parts.join(" · ");
@@ -22,7 +22,7 @@ import {
22
22
  isFlowError,
23
23
  isFlowSuccess,
24
24
  } from "./types.js";
25
- import { formatCompactStats, formatFlowTypeName, truncateChars, contentBudget } from "./render-utils.js";
25
+ import { formatCompactStats, formatFlowTypeName, truncateChars, tailText, contentBudget } from "./render-utils.js";
26
26
 
27
27
  function shortenPath(p: string): string {
28
28
  const home = os.homedir();
@@ -66,9 +66,10 @@ function formatFlowToolCall(toolName: string, args: Record<string, unknown>, fg:
66
66
  return fg("muted", "find ") + fg("accent", (args.pattern || "*") as string) + fg("dim", ` in ${shortenPath((args.path || ".") as string)}`);
67
67
  case "grep":
68
68
  return fg("muted", "grep ") + fg("accent", `/${(args.pattern || "") as string}/`) + fg("dim", ` in ${shortenPath((args.path || ".") as string)}`);
69
- case "batch": {
69
+ case "batch":
70
+ case "batch_read": {
70
71
  const ops = Array.isArray(args.o) ? args.o : Array.isArray(args.op) ? args.op : Array.isArray(args.operations) ? args.operations : Array.isArray(args) ? args : [];
71
- if (ops.length === 0) return fg("muted", "batch (empty)");
72
+ if (ops.length === 0) return fg("muted", `${toolName} (empty)`);
72
73
  const parts: string[] = [];
73
74
  for (const op of ops) {
74
75
  const opObj = op as Record<string, unknown>;
@@ -84,7 +85,7 @@ function formatFlowToolCall(toolName: string, args: Record<string, unknown>, fg:
84
85
  }
85
86
  }
86
87
  const summary = parts.length <= 3 ? parts.join(", ") : `${parts.slice(0, 2).join(", ")} +${parts.length - 2} more`;
87
- return fg("muted", "batch ") + fg("accent", summary);
88
+ return fg("muted", `${toolName} `) + fg("accent", summary);
88
89
  }
89
90
  default:
90
91
  return fg("accent", toolName) + fg("dim", ` ${JSON.stringify(args)}`);
@@ -240,6 +241,42 @@ function renderFlowExpanded(
240
241
  // Flow report (structured output)
241
242
  container.addChild(new Spacer(1));
242
243
  container.addChild(new Text(theme.fg("muted", sectionHeader("report")), 0, 0));
244
+
245
+ // Structured output summary (compact badge when available)
246
+ if (r.structuredOutput) {
247
+ const so = r.structuredOutput;
248
+ const statusColor = so.status === "complete" ? "success" : so.status === "partial" ? "warning" : "error";
249
+ container.addChild(new Text(
250
+ `${theme.fg(statusColor, `[${so.status}]`)} ${theme.fg("dim", so.summary)}`,
251
+ 0, 0,
252
+ ));
253
+ if (so.files.length > 0) {
254
+ container.addChild(new Text(theme.fg("dim", `Files: ${so.files.map((f) => f.path).join(", ")}`), 0, 0));
255
+ }
256
+ if (so.commands?.length > 0) {
257
+ const cmdLabels = so.commands.map((c) => {
258
+ const short = c.command.length > 30 ? c.command.slice(0, 30) + "..." : c.command;
259
+ return `${c.tool ?? "cmd"}: ${short}`;
260
+ });
261
+ container.addChild(new Text(theme.fg("dim", `Commands: ${cmdLabels.join(", ")}`), 0, 0));
262
+ }
263
+ if (so.notDone.length > 0) {
264
+ const notDoneText = so.notDone.map((item) => {
265
+ const details = [
266
+ item.reason ? `reason: ${item.reason}` : undefined,
267
+ item.blocker ? `blocker: ${item.blocker}` : undefined,
268
+ item.nextStep ? `next: ${item.nextStep}` : undefined,
269
+ ].filter(Boolean).join("; ");
270
+ return details ? `${item.item} (${details})` : item.item;
271
+ }).join("; ");
272
+ container.addChild(new Text(theme.fg("dim", `Not Done: ${notDoneText}`), 0, 0));
273
+ }
274
+ if (so.nextSteps.length > 0) {
275
+ container.addChild(new Text(theme.fg("dim", `Next: ${so.nextSteps.join("; ")}`), 0, 0));
276
+ }
277
+ container.addChild(new Spacer(1));
278
+ }
279
+
243
280
  if (flowOutput) {
244
281
  container.addChild(new Markdown(flowOutput.trim(), 0, 0, mdTheme));
245
282
  } else {
@@ -290,11 +327,17 @@ function renderFlowCollapsed(
290
327
  }
291
328
 
292
329
  // msg: line (last assistant text or streaming)
293
- if (flowOutput) {
294
- const logContent = truncateChars(flowOutput, contentBudget(10));
330
+ if (r.exitCode === -1 && streamingText) {
331
+ const logContent = tailText(streamingText, contentBudget(10));
332
+ container.addChild(new TruncatedText(`${theme.fg("dim", "└─ msg:")} ${theme.fg("dim", logContent)}`, 0, 0));
333
+ } else if (r.structuredOutput?.summary) {
334
+ const logContent = truncateChars(r.structuredOutput.summary, contentBudget(10));
335
+ container.addChild(new TruncatedText(`${theme.fg("dim", "└─ msg:")} ${theme.fg("dim", logContent)}`, 0, 0));
336
+ } else if (flowOutput) {
337
+ const logContent = tailText(flowOutput, contentBudget(10));
295
338
  container.addChild(new TruncatedText(`${theme.fg("dim", "└─ msg:")} ${theme.fg("dim", logContent)}`, 0, 0));
296
339
  } else if (streamingText) {
297
- const logContent = truncateChars(streamingText, contentBudget(10));
340
+ const logContent = tailText(streamingText, contentBudget(10));
298
341
  container.addChild(new TruncatedText(`${theme.fg("dim", "└─ msg:")} ${theme.fg("dim", logContent)}`, 0, 0));
299
342
  } else if (error && r.errorMessage) {
300
343
  const logContent = truncateChars(r.errorMessage, contentBudget(10));
@@ -421,10 +464,11 @@ function renderActivityPanel(
421
464
  container.addChild(new TruncatedText(`${theme.fg("dim", indent + "├─ " + actPrefix)}${actContent}`, 0, 0));
422
465
  }
423
466
 
424
- // msg: line (last assistant text)
425
- const lastText = getLastAssistantText(r.messages);
467
+ // msg: line (live streaming text or last assistant text)
468
+ const liveText = r.exitCode === -1 ? r.streamingText : undefined;
469
+ const lastText = liveText || getLastAssistantText(r.messages);
426
470
  if (lastText) {
427
- const logContent = truncateChars(lastText, contentBudget(10));
471
+ const logContent = tailText(lastText, contentBudget(10));
428
472
  container.addChild(new TruncatedText(`${theme.fg("dim", indent + "└─ msg:")} ${theme.fg("dim", logContent)}`, 0, 0));
429
473
  } else if (error && r.errorMessage) {
430
474
  const logContent = truncateChars(r.errorMessage, contentBudget(10));