// A stand-in for `pi --mode rpc`. Reads JSONL commands on stdin, writes // events on stdout. Behaviour is scripted per prompt text: // "slow " answer "slow reply" after // "garbage" emit one malformed line // "error" end the turn with stopReason error // anything else answer "echo: " immediately // A prompt received while busy without streamingBehavior is refused, as pi // does. Every command is mirrored to FAKE_PI_LOG when set. import { appendFileSync } from "node:fs"; const logPath = process.env.FAKE_PI_LOG; const out = (o) => process.stdout.write(JSON.stringify(o) + "\n"); let busy = false; const queue = []; function assistant(text, stopReason = "stop") { return { role: "assistant", content: text === null ? [] : [{ type: "text", text }], stopReason, usage: { input: 3, output: 2 }, model: "fake", provider: "fake" }; } function run(text) { busy = true; out({ type: "agent_start" }); out({ type: "turn_start" }); const finish = (message) => { out({ type: "turn_end", message, toolResults: [] }); out({ type: "agent_end", messages: [message] }); if (queue.length > 0) { run(queue.shift()); return; } busy = false; out({ type: "agent_settled" }); }; const m = /^slow (\d+)$/.exec(text); if (m) { const timer = setTimeout(() => finish(assistant("slow reply")), Number(m[1])); current = { timer, finish }; return; } if (text === "garbage") { process.stdout.write("this is not json\n"); finish(assistant("after garbage")); return; } if (text === "error") { finish({ ...assistant(null, "error"), errorMessage: "fake provider error" }); return; } finish(assistant(`echo: ${text}`)); } let current = null; let buffer = ""; process.stdin.setEncoding("utf8"); process.stdin.on("data", (chunk) => { buffer += chunk; let idx; while ((idx = buffer.indexOf("\n")) !== -1) { const line = buffer.slice(0, idx); buffer = buffer.slice(idx + 1); if (!line) continue; const cmd = JSON.parse(line); if (logPath) appendFileSync(logPath, line + "\n"); if (cmd.type === "prompt") { if (busy && !cmd.streamingBehavior) { out({ id: cmd.id, type: "response", command: "prompt", success: false, error: "agent is streaming; specify streamingBehavior" }); continue; } out({ id: cmd.id, type: "response", command: "prompt", success: true }); if (busy) queue.push(cmd.message); else run(cmd.message); } else if (cmd.type === "abort") { out({ id: cmd.id, type: "response", command: "abort", success: true }); if (current) { clearTimeout(current.timer); const f = current.finish; current = null; f(assistant("", "aborted")); } } else { out({ id: cmd.id, type: "response", command: cmd.type, success: true, data: {} }); } } }); process.stdin.on("end", () => process.exit(0));