#334
harnesses: add Pi
Stacked on #318. Adds Pi as a third harness: harnesses.pi(), over pi --mode rpc.
What it is
- One
pi --mode rpcprocess per conversation. The SDK mints the id (--session-id), sopi --session <id>opens the same conversation in pi's own TUI. - Same surface as
claude_code()/codex(): run, stream, steer, stop, resume, fork,history()/sessions()(read from pi's session files),tui(), handoff (history=), the session lock, gateway, MCP servers, images, structured output.pi()takes everyclaude_code()argument;max_turnsraisesUnsupportedError. - Approvals: pi has no permission prompt, so the SDK loads a small extension (
_adapters/pi_extension.js) whosetool_callhandler asks the hook through an RPC dialog. Coverage is"all",Allow(input=)rewrites the call, andDeny(reason)reaches the agent. Startup refuses to continue unless the extension proves it loaded, so the gate can't fail open. - Gateway: pi's gateway provider sends
x-api-key, which sandbox egress injection doesn't rewrite. The extension sendsAuthorization: Bearerinstead. Measured: the gateway accepts it, and a wrong key comes back as a 401. - No model given: pi chooses exactly as it does on its own.
- A pi conversation handed to pi keeps its model. pi restores a session's model from its last reply's author, so handed-off replies keep theirs (
provider_metadata["pi"]). Measured: without this, a pushed conversation ran on pi's default model, which the gateway refused.
Also in this PR:
- afk drives pi: it lists pi conversations and handles push, attach, peek, pull, stop and rm.
- New example:
examples/harnesses/pi.py. - Docs, README and skill updated.
Tested
- Offline: 1243 tests pass, 40 of them new in
test_pi_adapter.py. Format, lint, mypy and ty are clean. - Live pi suite, local: 92 passed, 3 skipped.
- Live pi suite, Vercel Sandbox: 86 passed, 1 skipped. Gateway and brokered-credential tests included.
- afk, for real on pi in a sandbox:
- push
--bg, thenwait,peekandpull --files - TUI push, Ctrl-] detach, attach
stop, then attach (resumes from the snapshot)- attach to a
--bgone (ends the agent, opens the TUI), thenrm - The pushed agent remembered the codeword from the handed-off history in each case.
- push
- Example:
harnesses/pi.pypasses inrun-examples.py. - Review: four rounds of Codex
/review(gpt-6.1-sol). Every P1 is fixed.
Known gaps
- A
pistarted in a terminal isn't shown as running: pi hides its arguments fromps. - Sandbox TUI test: pi's ready prompt in a sandbox isn't measured yet, so that check is skipped.
- Extension-injected context mid-turn is in
history()but not in the livesession.messages. The SDK has no event for it. - A failed retry's partial text stays in
session.messages; it is excluded fromresult.text. - Not from pi, seen while testing:
RuntimeError: aclose(): asynchronous generator is already runningis sometimes printed when a turn is abandoned (afkpush --bg). It also happens with codex, so it comes from the sharedTurnclose path in #318, not from pi.
Activity
13vercel[bot]reviewed15d ago
5be941ekajogo777reviewed15d ago
kajogo777reviewed15d ago
You must have Developer access to commit code to Vercel Labs on Vercel. If you contact an administrator and receive Developer access, commit again to see your changes.
Learn more: https://vercel.com/docs/accounts/team-members-and-roles/access-roles#team-level-roles