♠ Previously.
Problem statement: mid-task, I want to ask the LLM agent a quick tangential question — “will this change cause downtime?” — without polluting the main agent thread.
Claude Code has /btw
1 for exactly this.
The upstream extension imports the pre-fork @mariozechner/*
package names,
which are now deprecated. As such, I use
earendil-works/pi. Rather than trust a
diff I hadn’t read, I reimplemented it against the current API, and
cross-checked against the bundled examples/extensions/summarize.ts
(the canonical example for calling the model from an extension):
import { complete } from "@earendil-works/pi-ai/compat";
import type { ExtensionAPI, SessionEntry } from "@earendil-works/pi-coding-agent";
import { convertToLlm, getMarkdownTheme } from "@earendil-works/pi-coding-agent";
// ...inside the /btw command handler, once at entry:
const branch = ctx.sessionManager.getBranch();
const mainMessages = branch
.filter((entry): entry is SessionEntry & { type: "message" } => entry.type === "message")
.map((entry) => entry.message);
const mainLlmMessages = convertToLlm(mainMessages); // frozen snapshot
const systemPrompt = ctx.getSystemPrompt();
// ...per question, the side-chat calls the model directly:
const response = await complete(
ctx.model!,
{ systemPrompt, messages: [...mainLlmMessages, ...btwLlmMessages] },
{ apiKey: auth.apiKey, headers: auth.headers, env: auth.env, signal },
);
The key move is what’s missing: the handler never calls pi.sendMessage()
or appends anything. It reads the branch once, talks to the model in an ctx.ui.custom() overlay, and returns. The main session is untouched, so the next real prompt doesn’t pay for any of it.
Added to ~/.pi/agent/extensions/btw.ts.
🤖 *Drafted with *
/bloggify
.— § —
Reply via [email](mailto:serendipity@perrotta.dev?subject=Reply to: pi: /btw side-chat)