flake-update-20260505
 1/**
 2 * Provider Request Debug Extension
 3 *
 4 * Logs provider request payloads for debugging cache behavior,
 5 * token usage, and request structure.
 6 *
 7 * Toggle: PI_DEBUG_REQUESTS=1 or /debug-requests command
 8 *
 9 * Logs to: /tmp/pi-requests.log (truncated per session)
10 */
11
12import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
13import { appendFileSync, writeFileSync } from "node:fs";
14
15const LOG_FILE = "/tmp/pi-requests.log";
16
17export default function (pi: ExtensionAPI) {
18  let enabled = process.env.PI_DEBUG_REQUESTS === "1";
19  let requestCount = 0;
20
21  pi.on("before_provider_request", (event) => {
22    if (!enabled) return;
23
24    requestCount++;
25    const timestamp = new Date().toISOString();
26    const payload = event.payload;
27
28    // Summarize rather than dump entire payload (messages can be huge)
29    const summary: Record<string, any> = {
30      timestamp,
31      request: requestCount,
32      model: payload.model,
33    };
34
35    // Count messages by role
36    if (payload.messages) {
37      const roles: Record<string, number> = {};
38      for (const msg of payload.messages) {
39        roles[msg.role] = (roles[msg.role] || 0) + 1;
40      }
41      summary.messages = { count: payload.messages.length, roles };
42    }
43
44    // System prompt length
45    if (payload.system) {
46      if (typeof payload.system === "string") {
47        summary.systemPromptChars = payload.system.length;
48      } else if (Array.isArray(payload.system)) {
49        summary.systemPromptChars = payload.system.reduce(
50          (acc: number, b: any) => acc + (b.text?.length || 0), 0
51        );
52      }
53    }
54
55    // Tool count
56    if (payload.tools) {
57      summary.toolCount = payload.tools.length;
58    }
59
60    // Thinking config
61    if (payload.thinking) {
62      summary.thinking = payload.thinking;
63    }
64
65    // Max tokens
66    summary.maxTokens = payload.max_tokens;
67
68    // Temperature
69    if (payload.temperature !== undefined) {
70      summary.temperature = payload.temperature;
71    }
72
73    appendFileSync(LOG_FILE, JSON.stringify(summary, null, 2) + "\n---\n", "utf8");
74  });
75
76  pi.registerCommand("debug-requests", {
77    description: "Toggle provider request payload logging to /tmp/pi-requests.log",
78    handler: async (_args, ctx) => {
79      enabled = !enabled;
80      if (enabled) {
81        requestCount = 0;
82        writeFileSync(LOG_FILE, `# Pi request debug log - ${new Date().toISOString()}\n\n`, "utf8");
83      }
84      ctx.ui.notify(
85        enabled ? `Request debugging ON → ${LOG_FILE}` : "Request debugging OFF",
86        "info",
87      );
88    },
89  });
90}