Repository navigation
feat(pi): add a pi --mode rpc adapter - #29
Merged
Merged
Conversation
Provider::Pi drives the pi coding agent through `pi --mode rpc`, its JSONL stdio protocol, behind a new default `pi` feature. Each turn starts with get_state. A resumed session that pi reports as empty fails with pi::session_not_found before the prompt is written, so a stale id never silently starts a new conversation. Text and thinking deltas, tool executions, usage with the context window, compaction and auto-retry are mapped onto TurnEvent, and agent_settled ends the turn. Extension confirm, select, input and editor dialogs reach the interaction handler as approvals and questions; cancellation sends abort. pi has no per-tool approval prompt, so only FullAccess (--no-approve) and Plan (read-only --tools) are accepted, and other modes fail before spawning. Strict MCP config maps to --no-extensions. Discovery reads the catalog over RPC with --no-session and authentication from --list-models. pi's end-of-run events repeat the whole conversation and outgrow the event line limit on long turns. The runtime now consumes an oversized frame without buffering it and passes its prefix to the new AgentAdapter::parse_oversized_frame, which lets pi drop those redundant frames and report an oversized tool result as omitted; every other adapter keeps failing the turn. Lines are now held to the limit exactly, including CRLF-terminated lines and a final line without a terminator. PI_CODING_AGENT_DIR and PI_CODING_AGENT_SESSION_DIR join the forwarded environment allowlists, and skill discovery covers pi's user and project skill directories. Verified with unit tests, a scripted RPC fixture (tests/pi_rpc.rs) and examples/pi_smoke.rs against pi 1.0.0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
…ments Discovery reports every provider compiled into the runtime, and the example took the SDK's default features, so adding pi made it discover a fourth harness its UI has no label, icon or picker entry for, and its e2e test failed. Enable only Claude Code, Codex and OpenCode, plus the transports it uses, until the example supports pi. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ions An oversized tool_execution_end was reported as Succeeded from its first 512 bytes, but pi writes isError after the result, so a failed tool with a large result looked successful. The runtime now also keeps the last 512 bytes of an oversized frame and passes both ends to the adapter as an OversizedFrame. pi reads isError from the tail, and reports a call whose outcome it cannot read as failed, never as succeeded. Adapters now decide on an oversized frame as soon as it crosses the limit, through the new AgentAdapter::accepts_oversized_frame. A declined frame fails the turn at once instead of being read to its end, so a provider writing an endless line no longer holds the turn until its deadline; only frames the adapter accepts are consumed. Under a limit smaller than 512 bytes the decision waits for the whole prefix. A resume now requires get_state to report a positive messageCount. A missing or malformed count fails as pi::session_unconfirmed before the prompt is sent, instead of being treated as a session that exists. The pi smoke example gains a failing bash call whose output exceeds a 4 KiB event limit; against pi 1.0.0 it is reported as failed from isError. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Outcome
Adds
Provider::Piandproviders::Pi, behind a new defaultpifeature, which drive the pi coding agent throughpi --mode rpc(JSONL over stdio). Embedders get pi as a fourth first-class harness next to Claude Code, Codex and OpenCode, with:pi::session_not_found, and one whosemessageCountpi does not report as a valid count fails aspi::session_unconfirmed, both before the prompt is written, so a stale id never silently starts a new conversation;abortcommand;confirm,select,input,editor) delivered to the interaction handler as approvals and questions;--no-sessionand including per-model thinking levels, plus a credential check throughpi --list-models;pi's end-of-run events (
agent_end,turn_end) repeat the whole conversation, so on long turns they outgrow the event-line limit. To keep those turns working without raising the limit:AgentAdapter::accepts_oversized_framewith the frame's first 512 bytes. The default declines, which fails the turn at once, so other adapters behave as before;AgentAdapter::parse_oversized_framereceives anOversizedFramewith its first and last 512 bytes;isError, which pi places after the result. If that outcome cannot be read, the call is reported as failed, never as succeeded.Fix included: event lines are now held to
max_event_line_bytesexactly. Previously a CRLF-terminated line at the limit was rejected, and an unterminated final line one byte over it was accepted.Not included yet:
--no-extensions;Protocol and security impact
FullAccess(--no-approve) andPlan, which passes pi's read-only tools (read,grep,find,ls) through--tools, intersected withallowed_tools.Default,AcceptEditsand custom modes fail before spawning instead of silently running with full access.-, empty values, and tool names containing,are rejected.PI_CODING_AGENT_DIRandPI_CODING_AGENT_SESSION_DIRjoin the local, SSH and Temps sandbox environment allowlists, likeCLAUDE_HOME.PI_SKIP_VERSION_CHECK=1stops pi from contacting its update server on every turn.Provideris#[non_exhaustive], soProvider::Piis additive.accepts_oversized_frameandparse_oversized_framehave default implementations. Default discovery now reports four harnesses instead of three; the fullstack example now enables only the three agents its UI implements.Verification
cargo fmt --all -- --checkcargo clippy --all-targets --all-features -- -D warningscargo test --all-features: 382 lib tests plus every integration suite, including the newtests/pi_rpc.rs(12 tests against a scripted pi RPC fixture: tool turn, retained resume, missing session, rejected prompt, extension confirm, cancel/abort, oversized summaries, an oversized failing tool result, an oversized answer, rejected modes and turn-scoped MCP, discovery)cargo clippyand the full Playwright e2e suite (19 passed)--no-default-features,--no-default-features --features pi, andcargo +1.88 check --all-features --all-targets --locked(MSRV)python3 scripts/check-package.pyandcargo package --lockedManual:
examples/pi_smoke.rsdrives the real pi 1.0.0 binary against a local mock of the Anthropic Messages API. All scenarios passed:SessionStarted;bash;isError;To run it against a real model, set
PI_SMOKE_ENVIRONMENTto the names of the provider key variables to forward:🤖 Generated with Claude Code