output.ts

 1import type { AgentEvent } from "@mariozechner/pi-agent";
 2
 3const MAX_OUTPUT_LINES = 20;
 4
 5export interface OutputOptions {
 6  verbose: boolean;
 7}
 8
 9export function formatToolOutput(output: string): string {
10  const lines = output.split(/\r?\n/);
11  if (lines.length <= MAX_OUTPUT_LINES) {
12    return output;
13  }
14
15  const truncated = lines.slice(0, MAX_OUTPUT_LINES).join("\n");
16  return `${truncated}\n(+${lines.length - MAX_OUTPUT_LINES} more lines)`;
17}
18
19export function createEventLogger(options: OutputOptions) {
20  return (event: AgentEvent) => {
21    if (!options.verbose) return;
22
23    if (event.type === "tool_execution_start") {
24      console.error(`\n[tool] ${event.toolName}`);
25      console.error(JSON.stringify(event.args, null, 2));
26    }
27
28    if (event.type === "tool_execution_end") {
29      if (event.isError) {
30        console.error("[tool error]");
31        console.error(String(event.result));
32        return;
33      }
34
35      const text = (event.result?.content ?? [])
36        .filter((content: { type: string }) => content.type === "text")
37        .map((content: { text?: string }) => content.text ?? "")
38        .join("");
39
40      if (text) {
41        console.error(formatToolOutput(text));
42      }
43    }
44  };
45}
46
47export function printUsageSummary(usage: { cost?: { total?: number }; totalTokens?: number; output?: number; input?: number } | undefined) {
48  if (!usage) return;
49
50  const cost = usage.cost?.total ?? 0;
51  const tokens = usage.totalTokens ?? (usage.output ?? 0) + (usage.input ?? 0);
52  console.error(`\nusage: ${tokens} tokens, cost $${cost.toFixed(4)}`);
53}