On pi 0.86.x, streamSimple no longer gets context.systemPrompt or context.tools. pi-ai now passes a normalized TranscriptContext ({ messages } only) — the system prompt and tool declarations are folded into a leading role: "system" message and have to be read back with getCurrentSystemPrompt(context.messages) / getCurrentTools(context.messages) (docs: packages/coding-agent/docs/custom-provider.md, "Custom Streaming API", v0.86.0; types in pi-ai/dist/types.d.ts, helpers in pi-ai/dist/utils/transcript.js).
packages/pi/src/convert.ts still reads context.systemPrompt (L580) and context.tools (L621), and stream.ts L1270 reads context.tools for the tool_use name un-mapping. On 0.86 both are undefined, so every request goes out with the billing header + Claude Code identity as the whole system prompt and no tools. No error — HTTP 200 and a normal-looking reply.
Repro (pi 0.86.1, @cortexkit/pi-anthropic-auth 1.22.0, from an empty dir):
pi -p --no-session --no-extensions -e <extension> \
--model anthropic-personal/claude-haiku-4-5 --tools bash \
--system-prompt "Your name is Wren. Always state your name first." \
"State your name, then run this with the bash tool: echo probe-ok"
Result: I'm Claude, made by Anthropic. However … I don't actually have access to a bash tool. Same command on the built-in anthropic provider answers "Wren" and runs the command.
Fix that worked for me (in a vendored copy of the extension): resolve the prompt/tools/messages once, before building the request —
import * as piAi from "@earendil-works/pi-ai";
function resolveRequestContext(context) {
const hasHelpers =
typeof piAi.collapseSystemMessages === "function" &&
typeof piAi.getCurrentSystemPrompt === "function" &&
typeof piAi.getCurrentTools === "function";
const hasSystemMessages = context.messages.some((m) => m?.role === "system");
if (hasHelpers && hasSystemMessages) {
const transcript = piAi.collapseSystemMessages(context);
return {
systemPrompt: piAi.getCurrentSystemPrompt(transcript.messages),
tools: piAi.getCurrentTools(transcript.messages),
messages: transcript.messages.filter((m) => m.role !== "system"),
};
}
return {
systemPrompt: context.systemPrompt ?? "",
tools: context.tools ?? [],
messages: context.messages,
};
}
then use request.systemPrompt / request.tools / request.messages in buildAnthropicRequest, and the resolved tools in the tool_use branch of stream.ts. The typeof checks + namespace import keep the extension loading on pi < 0.86, where the helpers don't exist and the old fields are still populated. convertMessages already skips the system role, so nothing else changes on the wire.
Happy to open a PR if you want it in that shape.
On pi 0.86.x,
streamSimpleno longer getscontext.systemPromptorcontext.tools. pi-ai now passes a normalizedTranscriptContext({ messages }only) — the system prompt and tool declarations are folded into a leadingrole: "system"message and have to be read back withgetCurrentSystemPrompt(context.messages)/getCurrentTools(context.messages)(docs:packages/coding-agent/docs/custom-provider.md, "Custom Streaming API", v0.86.0; types inpi-ai/dist/types.d.ts, helpers inpi-ai/dist/utils/transcript.js).packages/pi/src/convert.tsstill readscontext.systemPrompt(L580) andcontext.tools(L621), andstream.tsL1270 readscontext.toolsfor thetool_usename un-mapping. On 0.86 both areundefined, so every request goes out with the billing header + Claude Code identity as the whole system prompt and no tools. No error — HTTP 200 and a normal-looking reply.Repro (pi 0.86.1,
@cortexkit/pi-anthropic-auth1.22.0, from an empty dir):Result:
I'm Claude, made by Anthropic. However … I don't actually have access to a bash tool.Same command on the built-inanthropicprovider answers "Wren" and runs the command.Fix that worked for me (in a vendored copy of the extension): resolve the prompt/tools/messages once, before building the request —
then use
request.systemPrompt/request.tools/request.messagesinbuildAnthropicRequest, and the resolved tools in thetool_usebranch ofstream.ts. Thetypeofchecks + namespace import keep the extension loading on pi < 0.86, where the helpers don't exist and the old fields are still populated.convertMessagesalready skips thesystemrole, so nothing else changes on the wire.Happy to open a PR if you want it in that shape.