Skip to content

Add same-turn steering for Pi - #462

Merged
cfal merged 9 commits into
mainfrom
claude-steer
Aug 4, 2026
Merged

cfal merged 9 commits into
mainfrom
claude-steer

Conversation

@cfal

@cfal cfal commented Aug 4, 2026

Copy link
Copy Markdown
Owner

Pi’s one-shot JSON transport cannot accept input during an active turn. This replaces it with a long-lived RPC runtime, exposes same-turn steering at Pi’s tool-call boundary, preserves strict native-session identity and kill-based stop semantics, upgrades the pinned Pi packages to 0.83.0, and retains compatibility with sessions created by the previous runtime.

cfal added 9 commits August 4, 2026 04:10
Scripted stand-in for the model behind real chat-completions CLIs. The
Chat Completions API is generic, not Pi-specific, so this double is written
for reuse: Pi consumes it now and opencode will later.

Mirrors FakeClaudeModel/FakeCodexModel semantics: a turn script queue with
held turns (response gated until release), request recording (user texts,
tool results), fault injection (http-error, stream-error), and cleanup
assertions (assertSettled fails on unconsumed turns, unreleased holds, or
recorded protocol violations). Outbound SSE conforms to the chunk sequence
the real Pi CLI parses (role delta, content/tool_calls deltas with index,
finish_reason, usage, [DONE]); inbound validation checks the conversation
contract while staying lenient about extra fields.

Script exhaustion responds 500 and records a violation so CLI auto-retry
terminates deterministically and cleanup fails on unexpected requests.

Verified against the real pinned pi binary: a tool-call turn and a final
reply complete with no violations.
Runs the real pinned Pi CLI against FakeChatCompletionsModel: models.json
points the CLI's openai-completions provider at the fake, so CLI behavior
(process lifecycle, local tool execution, session persistence) stays real
while every model choice is deterministic.

Isolation relies on the fixture HOME alone: both the spawned CLI and the
in-server SDK discovery resolve ~/.pi/agent inside the temp home, so the
user's real ~/.pi is never touched. The pi bin is a node shim, so the
fixture PATH gets the runner's node directory (same pattern live-codex.ts
already uses for the codex shim in CI).

Pins the integration-tests pi devDependency at 0.80.10 -- the version the
server currently ships -- so the baseline suite locks true current
behavior; the upgrade bumps it together with the server deps.

Provides scriptedPiStartRequest/scriptedPiRunRequest builders mirroring the
Claude/Codex live request helpers.
Suite A: 17 tests that pin every observable behavior of the current Pi
integration before the RPC transport switch. Written and green against the
0.80.10 CLI; they gate the upgrade and the switch.

Coverage:
- lifecycle: session identity established before the first turn settles
  (locked native-path shape), tool events precede terminal WS events,
  transcript/preview accumulation across turns on one session file,
  catalog model discovery and explicit-model requirement, single-query
  title generation through the untouched --mode text path
- queue: FIFO drain, pause/resume, duplicate clientRequestId, cancelled
  entries never reach the model
- stop: current Pi order is stopping -> idle -> stopped (differs from
  Claude's stopping -> stopped -> idle); locked explicitly. A stop before
  Pi persists anything leaves the next --session lookup unresolvable --
  that wart is deliberately not locked (the RPC runtime establishes
  identity before the first prompt)
- persistence: graceful/crash restart stability, whole-session fork
  isolation, provider-neutral transcript search
- failures: observed current contract -- a failed model request surfaces
  an ErrorMessage, the run still finishes, and the CLI makes three more
  orphaned auto-retry attempts (~15s apart, four total per process) that
  Garcon does not see; tests script all four attempts and drain them via
  an observable request count so retries cannot eat later scripted turns

Adds piNativeSession to scripted-pi support for workspace-registry
inspection, mirroring the fixture's direct-agent helpers.
…ions

Tests that deliberately exhaust the scripted queue (the failure suite's
wedge case) record violations on purpose; clearProtocolViolations lets
them reset the ledger before recovery assertions without touching the
script queue or pending holds.
Bumps all four lockstep @earendil-works/pi-* dependencies in
server-agents/pi and the integration-tests CLI devDependency together, so
the scripted lane and the server SDK never form a version mix that does
not ship.

Upgrade gate results:
- Suite A (17 tests) green against the 0.83.0 CLI: no observable drift in
  lifecycle, queue, stop, persistence, search, or failure behavior
- root unit suites green (3441 tests), covering the Pi SDK surfaces the
  integration imports (model discovery, session parsing, fork)
- build-exe:compile and build-exe:smoke:linux-x64 pass with the new
  embedded pi-coding-agent package metadata

The only breaking change in the 0.80.10 -> 0.83.0 range is a bundled
TypeBox alias upgrade that affects Pi extensions, which Garcon does not
use.
@cfal
cfal merged commit 4ff447a into main Aug 4, 2026
9 checks passed
@cfal
cfal deleted the claude-steer branch August 4, 2026 05:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant