Pi coding agent neturi integruotos analitikos — nematai kiek išleidai, kurį modelį naudoji dažniausiai, ar kokie įrankiai iškviečiami dažniau. Tai galima išspręsti.

Galimi trys keliai:

PostHog Cloud PostHog savaeigis Lokali analitika
Paskyra reikalinga Taip Ne Ne
Internetas reikalingas Taip Ne Ne
npm priklausomybės posthog-node posthog-node Nė vienos
Duomenys išlieka lokaliai Ne Taip Taip

Šiame įraše sukursime lokalią versiją — vienas TypeScript failas, duomenys saugomi ~/.pi/agent/analytics.jsonl, ir /analytics komanda terminale rodo visą susumuotą statistiką.

Kaip veikia Pi plėtiniai?

Pi turi plėtinių (extension) sistemą — TypeScript moduliai, kurie gali prenumeruoti agento įvykius, registruoti papildomas komandas ir rodyti informaciją terminalo poraštėje.

Plėtiniai aptinkami automatiškai iš ~/.pi/agent/extensions/ direktorijos. Jie nereikalauja kompiliavimo — Pi naudoja jiti paketą, kuris TypeScript vykdo tiesiogiai.

Mums svarbūs keturi įvykių tipai:

Įvykis Kada iššaunamas
session_start Pi paleidimo metu
agent_start / agent_end Kiekvienam vartotojo užklausos ciklui
message_end Kai LLM baigia atsakyti — čia gauname žetonų statistiką
tool_execution_start / tool_execution_end Kiekvienam įrankio iškvietimui

AssistantMessage tipo objektas turi usage lauką su viskuo ko reikia:

interface Usage {
  input: number;       // įvesties žetonai
  output: number;      // išvesties žetonai
  cacheRead: number;   // žetonai iš talpyklos
  cacheWrite: number;  // žetonai įrašyti į talpyklą
  cost: {
    total: number;     // bendra kaina USD
  };
}

Duomenų saugojimas

Kiekvieną užklausą ir kiekvieną įrankio iškvietimą įrašome į ~/.pi/agent/analytics.jsonl — po vieną JSON objektą eilutėje:

{"t":1747834821000,"e":"generation","session_id":"a1b2c3","model":"claude-opus-4-5","provider":"anthropic","input_tokens":4521,"output_tokens":312,"cache_read":1200,"cache_write":0,"cost":0.0187,"latency_ms":4231,"tool_calls":3}
{"t":1747834821050,"e":"tool","session_id":"a1b2c3","tool_name":"bash","duration_ms":892,"is_error":false}

JSONL formatas patogu tuo, kad kiekvieną eilutę galima skaityti savarankiškai — nereikia skaityti viso failo į atmintį. Vėliau galima šį failą atidaryti DuckDB ar bet kuriuo kitu įrankiu.

Plėtinio kodas

Sukurk failą ~/.pi/agent/extensions/local-analytics.ts. Plėtinys neturi jokių npm priklausomybių — naudoja tik Node.js integruotus modulius (node:fs, node:path, node:os) ir Pi paties teikiamus paketus (@earendil-works/pi-tui).

import * as fs from "node:fs";
import * as path from "node:path";
import * as os from "node:os";
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
import { Key, matchesKey, truncateToWidth } from "@earendil-works/pi-tui";

const AGENT_DIR =
  process.env.PI_CODING_AGENT_DIR ?? path.join(os.homedir(), ".pi", "agent");
const LOG_FILE = path.join(AGENT_DIR, "analytics.jsonl");

Įvykių fiksavimas

Kiekvieną agento ciklą sekame tokiu būdu:

// 1. Sesijos pradžia — nustatome pradinę būseną
pi.on("session_start", async (_event, ctx) => {
  sessionId = ctx.sessionManager.getLeafEntry()?.id ?? String(Date.now());
  currentModel = ctx.model?.id ?? "";
  currentProvider = ctx.model?.provider ?? "";
  sessionCost = 0;
  sessionPrompts = 0;
  ctx.ui.setStatus("analytics", ctx.ui.theme.fg("dim", "⬡ $0.0000"));
});

// 2. Prieš kiekvieną užklausą — nulinuojame kaupiklius
pi.on("agent_start", async () => {
  agentStartMs = Date.now();
  promptInputTokens = 0;
  promptCost = 0;
  // ...
});

// 3. Po kiekvieno LLM atsakymo — surenkame žetonų statistiką
pi.on("message_end", async (event) => {
  const msg = event.message as { role?: string; usage?: Usage };
  if (msg.role !== "assistant" || !msg.usage) return;
  promptInputTokens += msg.usage.input;
  promptCost += msg.usage.cost?.total ?? 0;
  // ...
});

// 4. Ciklo pabaiga — įrašome į diską ir atnaujiname poraštę
pi.on("agent_end", async (_event, ctx) => {
  sessionCost += promptCost;
  appendEvent({ e: "generation", cost: promptCost, latency_ms: Date.now() - agentStartMs, ... });
  ctx.ui.setStatus("analytics", theme.fg("dim", `⬡ ${fmtCost(sessionCost)}`));
});

Įrankių sekimas

pi.on("tool_execution_start", async (event) => {
  toolStartTimes.set(event.toolCallId, Date.now());
});

pi.on("tool_execution_end", async (event) => {
  const durationMs = Date.now() - (toolStartTimes.get(event.toolCallId) ?? Date.now());
  toolStartTimes.delete(event.toolCallId);
  appendEvent({
    e: "tool",
    tool_name: event.toolName,
    duration_ms: durationMs,
    is_error: event.isError,
  });
});

Analitikos skydelis

Komanda /analytics atidaro interaktyvų skydelį terminale. Jis naudoja ctx.ui.custom() — tai Pi mechanizmas, leidžiantis pilnai valdyti terminalo išvedimą su klaviatūros įvestimi:

pi.registerCommand("analytics", {
  description: "Rodyti analitikos skydelį  (naudojimas: /analytics [reset])",
  handler: async (args, ctx) => {
    const events = loadEvents();
    const stats = computeStats(events);
    let scrollOffset = 0;

    await new Promise<void>((resolve) => {
      ctx.ui.custom((_tui, theme, _kb, done) => {
        return {
          render(width: number): string[] {
            const all = renderDashboard(stats, sessionCost, sessionPrompts, theme, width);
            const visible = process.stdout.rows - 4;
            return all.slice(scrollOffset, scrollOffset + visible);
          },
          handleInput(data: string) {
            if (matchesKey(data, Key.down)) scrollOffset++;
            else if (matchesKey(data, Key.up)) scrollOffset--;
            else if (matchesKey(data, Key.enter) || matchesKey(data, Key.escape)) {
              done(undefined);
              resolve();
            }
          },
          invalidate() {},
        };
      });
    });
  },
});

Skydelio vaizdas terminale:

  ⬡ Pi Local Analytics
  ~/.pi/agent/analytics.jsonl
  ────────────────────────────────────────────────────

  ŠI SESIJA
  Užklausos: 3   Kaina: $0.0187

  IŠ VISO
  Sesijos:         47
  Užklausos:      312
  Įvesties žet.:  4.2M
  Išvesties žet.: 312k
  Vid. delsa:     3.8s
  Bendra kaina: $12.3400

  DIENOS KAINA  (paskutinės 14 dienų)
  2026-05-08   $1.2300  ██████████████░░░░░░  (8)
  2026-05-21   $0.0187  █░░░░░░░░░░░░░░░░░░░  (3)

  MODELIAI
  anthropic/claude-opus-4-5    312 užkl.   $12.3400  ████████████████████

  ĮRANKIAI  (viso)
  bash            245 išk.   3 kl.  vid.   892ms  ████████████████████
  read             89 išk.   0 kl.  vid.    12ms  ████████
  edit             67 išk.   0 kl.  vid.    45ms  ██████

  ↑ ↓  slinkti   Esc / Enter uždaryti

Įdiegimas

Visas plėtinio kodas viename faile — galima atsisiųsti arba sukurti rankiniu būdu:

# Sukurk extensions direktoriją jei dar neegzistuoja
mkdir -p ~/.pi/agent/extensions

# Sukurk plėtinio failą (kodas žemiau)
vim ~/.pi/agent/extensions/local-analytics.ts

Pi aptinka plėtinį automatiškai kito paleidimo metu. Jei Pi jau veikia — paleisk /reload.

Naudojimas

# Atidaryti analitikos skydelį
/analytics

# Ištrinti visus duomenis ir pradėti iš naujo
/analytics reset

Kiekvienos sesijos metu Pi poraštėje matysi:

⬡ $0.0187  (3 užklausos)

Tiesioginis duomenų naudojimas

Kadangi duomenys saugomi JSONL formatu, juos galima analizuoti bet kuriuo įrankiu:

# Bendra kaina su jq
cat ~/.pi/agent/analytics.jsonl \
  | jq 'select(.e == "generation") | .cost' \
  | awk '{s+=$1} END {printf "$%.4f\n", s}'

# SQL užklausos su DuckDB
duckdb -c "
  SELECT model, SUM(cost) AS kaina, COUNT(*) AS uzklausos
  FROM read_ndjson('~/.pi/agent/analytics.jsonl')
  WHERE e = 'generation'
  GROUP BY model
  ORDER BY kaina DESC
"

Šaltiniai