main
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}