Conversation
Pi 0.86 hands `streamSimple` a normalized `TranscriptContext` — `{ messages }`
only. The host system prompt and the tool declarations are folded into a
leading `role: "system"` message (later system messages may carry
`toolsAdded` / `toolsRemoved` / `sections` deltas) and are meant to be read
back with pi-ai's `getCurrentSystemPrompt` / `getCurrentTools`
(packages/coding-agent/docs/custom-provider.md § Custom Streaming API).
`buildAnthropicRequest` and the `tool_use` name un-mapping in `stream.ts`
read `context.systemPrompt` / `context.tools`, which are `undefined` on that
shape, so every request on Pi >= 0.86 went out with the billing header and
the Claude Code identity as the whole system prompt and no tools. HTTP 200,
a fluent reply from a bare model that says it has no bash tool.
`resolveRequestContext()` resolves the prompt, tools, and message list from
either shape: raw `Context` fields when the transcript has no system message
(Pi < 0.86, unchanged); pi-ai's transcript helpers when it does. The helpers
are reached through the namespace import and a `typeof` check rather than
named imports, so the extension still loads on a pi-ai that lacks them; if
system messages are present without the helpers (only reachable on an older
pi-ai, e.g. this repo's lockfile) a minimal local replay keeps the prompt and
tools instead of dropping them.
Tests: raw Context unchanged; prompt + tools read from the leading system
message; later system messages replayed (appended text, tool add/remove);
buildAnthropicRequest sends both from a transcript context. Verified green
against the lockfile's pi-ai 0.85.1 (local replay branch) and against
pi-ai 0.86.1 in a scratch install (helper branch — breaking the local replay
there changes nothing, so the helpers ran).
Closes cortexkit#244
KhangHLe
force-pushed
the
fix/pi-0.86-transcript-context
branch
from
September 20, 2026 17:22
ef0f649 to
5b87538
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #244.
What breaks
Pi 0.86 hands
streamSimplea normalizedTranscriptContext—{ messages }only. The host system prompt and the tool declarations are folded into a leadingrole: "system"message (later system messages can carrytoolsAdded/toolsRemoved/sectionsdeltas) and are meant to be read back with pi-ai'sgetCurrentSystemPrompt/getCurrentTools(docs, v0.86.0).buildAnthropicRequest(convert.ts) and thetool_usename un-mapping (stream.ts) readcontext.systemPrompt/context.tools. On that shape both areundefined, so every request on Pi ≥ 0.86 goes out with the billing header + Claude Code identity as the whole system prompt and no tools. HTTP 200 and a fluent reply from a bare model that says it has no bash tool — nothing errors.What this does
resolveRequestContext(context, helpers = piAi)inconvert.tsresolves{ systemPrompt, tools, messages }from either shape:role: "system"message → the rawContextfields, unchanged (Pi < 0.86 behaves exactly as before);collapseSystemMessages/getCurrentSystemPrompt/getCurrentTools(the same functions Pi's built-in providers use, sosectionsand tool removals resolve identically);toolsRemovedthentoolsAdded) rather than dropping the prompt.The helpers are reached through the namespace import and a
typeofcheck, not named imports, so the extension keeps loading on a pi-ai that lacks them. Note that Pi's extension loader aliases@earendil-works/pi-aito the host's bundled copy, so which branch runs is decided by the running Pi, not by this repo's lockfile (currently pi-ai 0.85.1) — which is why the tests pin both branches with explicit helper sets instead of relying on whateverbun installresolved.buildAnthropicRequestandstreamCortexKitAnthropic(plus the two internal option types that carrycontext) acceptContext | RequestContext.convertMessagesalready skips thesystemrole, so nothing else changes on the wire.Verification
bun test src/tests: 120 pass (114 before + 6 new: rawContextunchanged; prompt + tools from the leading system message; later system messages replayed; helper branch used when present, with call order asserted; local replay when absent;buildAnthropicRequestend-to-end from a transcript context).resolveRequestContextinbuildAnthropicRequest→ the end-to-end test fails; forcing the helper check tofalse→ the helper-branch test fails.bun run typecheckclean on the lockfile's pi-ai 0.85.1;biome checkclean.pi -p --no-extensions -e <ext> --model anthropic-personal/claude-haiku-4-5 --tools bash --system-prompt "Your name is Wren…" "State your name, then run … with the bash tool"goes from "I'm Claude … I don't actually have access to a bash tool" to running the command and answering "Wren".Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.Summary by cubic
Restores Pi ≥ 0.86 compatibility by reading the host system prompt and tools from its normalized transcript before building Anthropic requests. Previously those values came from missing
Contextfields, so requests omitted the host prompt and tools; tool-call name mapping now uses the same resolved tool set. Closes #244.@earendil-works/pi-aitranscript helpers when available, with a local replay fallback for hosts without them.Contextbehavior for Pi < 0.86 and removes transcript system messages before message conversion.Written for commit 5b87538. Summary will update on new commits.
The PR appears safe to merge, with no outstanding new issues introduced since the previous review.
Summary
This PR restores Pi 0.86+ compatibility by resolving system prompts and tool declarations from normalized transcript system messages while preserving the legacy raw-context path.
Diagram
%%{init: {'theme': 'neutral'}}%% flowchart TD A[Pi request context] --> B{Contains system messages?} B -- No --> C[Use legacy systemPrompt and tools fields] B -- Yes --> D{Transcript helpers available?} D -- Yes --> E[Collapse system messages] E --> F[Resolve current prompt and tools] D -- No --> G[Replay prompt and tool deltas locally] C --> H[Build Anthropic request] F --> H G --> H F --> I[Map streamed tool-call names] G --> IReviews (2) · Last reviewed commit: "fix(pi): read the prompt and tools from ..."