pi-codes 1.4.0

Typed Rust SDK for the pi coding agent (earendil-works/pi): serde models of the `pi --mode json` event stream and the `pi --mode rpc` stdin/stdout command protocol, plus an async (Tokio) RPC client.
Documentation
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.4.0] - 2026-10-21

### Changed

- Re-baseline the tested pin to pi **1.4.0** (from 1.3.0). No wire changes:
  `dist/modes/rpc/`, `json-event.d.ts`, `docs/rpc*.md`, `docs/json.md` and
  `pi --help` are identical, and the exact-version `pi-ai` /
  `pi-agent-core` `.d.ts` diffs touch only request options (client
  identity, telemetry span, System One compat), not messages, events or
  content blocks.

## [1.3.0] - 2026-10-15

### Added

- `ContentBlock::ToolCall::arguments_error` — pi 1.3.0's new optional
  `argumentsError` on assistant `toolCall` blocks. It is set when the
  model's full arguments text was not a valid JSON object; `arguments` is
  then `{}` and the call fails tool argument validation instead of running
  with a partial parse.

### Changed

- **Breaking:** `ContentBlock::ToolCall` has a new field, so struct-literal
  construction and patterns that list every field without `..` need
  updating.
- Re-baseline the tested pin to pi **1.3.0** (from 1.2.0). The RPC wire
  surface is otherwise unchanged: `dist/modes/rpc/`, `json-event.d.ts`,
  `dist/cli/args.d.ts`, `docs/rpc*.md`, `docs/json.md` and `pi --help` are
  byte-identical to 1.2.0, and `pi-agent-core` types are unchanged. The
  live suite passes unmodified. Behavioural changes now documented on the
  builder: `--model` matching several providers prefers the one with
  credentials and otherwise asks for `--provider` (previously catalog
  order), and `--tools +name`/`-name` on a resumed session applies on top
  of the session's active tools.

## [1.2.0] - 2026-10-14

### Changed

- Re-baseline the tested pin to pi **1.2.0** (from 1.1.0). The RPC wire
  surface is unchanged: `dist/modes/rpc/`, `json-event.d.ts`,
  `docs/rpc.md`, `docs/json.md` and `pi --help` are byte-identical to
  1.1.0, `pi-agent-core` types are unchanged, and the `pi-ai` type
  changes are a refactor (model/compat types moved into schema modules
  with the same shapes). The live suite passes unmodified. `--print` now
  exits nonzero when the final response is cut off at the output token
  limit (`length` stop reason), still printing the partial text; the
  `print` docs say so.

## [1.1.0] - 2026-10-08

### Changed

- Re-baseline the tested pin to pi **1.1.0** (from 1.0.4). The RPC wire
  surface is unchanged: `dist/modes/rpc/` and `json-event.d.ts` are
  byte-identical to 1.0.4, and the live suite passes unmodified. The
  `agent_settled` event now carries `aborted: bool`; the crate does not
  model `agent_settled`, so it still arrives as `PiEvent::Unknown` with
  the field in `payload`. `pi --help` documents `+name` / `-name` entries
  for `--tools`, which adjust the default tool selection instead of
  replacing it. The `tools` docs say so.

## [1.0.4] - 2026-10-05

### Added

- `PiCliBuilder::no_mcp` — the new `--no-mcp` flag (pi 1.0.4+): disable the
  built-in MCP support for the run, so no servers connect and there are no
  MCP tools.

### Changed

- Re-baseline the tested pin to pi **1.0.4** (from 1.0.3). The RPC wire
  surface is unchanged: `dist/modes/rpc/` and `json-event.d.ts` are
  byte-identical to 1.0.3, and the live suite passes unmodified. `pi --help`
  adds `--no-mcp`, and `--tools` / `--exclude-tools` now take `*` patterns
  (an allowlist keeps MCP tools unless an entry starts with `mcp__`; the
  denylist applies to MCP tools too). The `tools` / `exclude_tools` docs say
  so.

## [1.0.3] - 2026-10-05

### Changed

- Re-baseline the tested pin to pi **1.0.3** (from 1.0.2). The RPC wire
  surface is unchanged: `dist/modes/rpc/` and `json-event.d.ts` are
  byte-identical to 1.0.2, `pi --help` is byte-identical, and the live
  suite passes unmodified. Upstream 1.0.3 renames the Azure provider
  `azure-openai-responses` → `azure` (pass `--provider azure` now), adds
  Azure Foundry Chat Completions, and makes codemode `image()` save each
  image to a temp file.

## [1.0.2] - 2026-10-04

### Changed

- Re-baseline the tested pin to pi **1.0.2** (from 1.0.0; 1.0.1 was skipped).
  The RPC wire surface is unchanged: `dist/modes/rpc/` and `json-event.d.ts`
  are byte-identical to 1.0.0, `pi --help` is byte-identical, and the live
  suite passes unmodified. Upstream 1.0.1/1.0.2 touch MCP config/OAuth,
  model config and provider composition, the extension runner, and docs.

## [1.0.0] - 2026-10-02

### Changed

- Re-baseline the tested pin to pi **1.0.0** (from 0.99.2). The RPC wire
  surface is unchanged: `dist/modes/rpc/rpc-types.d.ts`, `json-event.d.ts`
  and the packaged `rpc.md`/`json.md`/`message-types.md` docs are
  byte-identical to 0.99.2, and the live suite passes unmodified. Upstream
  1.0.0 is a TUI/login/codemode release (fullscreen by default, Radius
  `/login`, `models.generateImages()`, MCP OAuth hardening).
- pi 1.0.0 rejects `--provider` without `--model` (`Error: --provider
  requires --model`, exit 1) instead of silently running the default model
  from another provider (earendil-works/pi#10236). `PiCliBuilder::provider`
  now documents that it must be paired with `PiCliBuilder::model`; the crate
  passes both flags through unchanged, so a builder that set only
  `provider` fails at spawn with pi's own error.

## [0.99.2] - 2026-10-01

### Changed

- Re-baseline the tested pin to pi **0.99.2** (from 0.99.1). `pi --help` and
  the RPC docs are unchanged (doc edits cover codemode deferred tools,
  `pi mcp add --oauth-client-name/--description`, `/reload` of
  `defaultTools`, and Anthropic workload identity federation); the live
  suite passes unmodified — pin-only release.

## [0.99.1] - 2026-09-30

Re-baseline the tested pin to pi **0.99.1** (from 0.87.1; upstream jumped
0.87.1 → 0.99.0 → 0.99.1 with no releases in between) and model the RPC
wire drift. The RPC command set (`dist/modes/rpc/rpc-types.d.ts`) and the
event name set in the packaged docs are unchanged; everything below is
additive on the wire. The unmodified 0.87.1 crate still passes its live
tier against 0.99.1.

### Added

- `InputDisposition` (`handled` / `queued` / `started`, open set) and
  `RpcResponse::disposition()`. pi 0.99.0 acknowledges a successful
  `prompt`, `steer` or `follow_up` with `data.disposition`
  (earendil-works/pi#9098, #9803): `started` when the prompt began a run,
  `queued` when pi held the input during a run, `handled` when an
  extension command or input handler consumed it — in which case no run
  started and there is no `agent_settled` to wait for. Earlier CLIs sent a
  bare success envelope, for which the accessor returns `None`.
- `PiMessage::Assistant::thinking_level` (wire `thinkingLevel`): the pi
  thinking level the agent loop requested for the response. Previously the
  key would have landed in `extra`.
- A fresh RPC tool-use corpus captured against 0.99.1
  (`test_cases/rpc_tool_use_0_99_1.jsonl`); the corpus tests run over all
  three captures and pin the prompt disposition, the typed thinking level
  and the `structuredContent` twin on built-in `bash` results.

### Changed

- **Breaking:** `PiEvent::ToolExecutionStart`, `::ToolExecutionUpdate` and
  `::ToolExecutionEnd` gain `parent_tool_call_id: Option<String>` (wire
  `parentToolCallId`). pi 0.99.0 lets a tool run other tools
  (`ctx.executeTool()`, used by the new `codemode` tool and MCP calls made
  from its scripts); those nested calls emit tool-execution events with
  the calling tool's id as parent and a `<parent id>/<n>` `toolCallId`,
  and never appear as tool calls or tool results in the transcript.
  Patterns that list every field need a `..`.

### Not modeled

- The new `pi mcp add|remove|list|login|logout` management subcommand, the
  `-e builtin:<name>` extension form and `--no-extensions` now also
  disabling built-in extensions: `PiCliBuilder` has no extension flags;
  pass them through `extra_args`.
- `nestedCalls` on a calling tool's `toolResult` message and the new
  `type` discriminator (`chat` / `image` / `classifier`) on catalog models
  stay reachable through the `extra` maps.
- `docs/session-format.md` additions (`thinkingLevel` on stored assistant
  messages, `pi.virtual-model-state` custom entries): this crate does not
  parse session files.

## [0.87.1] - 2026-09-23

### Changed

- Re-baseline the tested pin to pi **0.87.1** (from 0.87.0). No wire
  changes on the RPC surface: `pi --help` is byte-identical between the
  two releases, the RPC command set in the packaged docs is unchanged,
  and the full live tier passes unmodified. Upstream's 0.87.1 changes are
  model-catalog additions (Claude Opus 5.5, GPT-6 Sol/Luna, Grok 4.7 as
  the xAI default) and bug fixes. The packaged docs were reorganized in
  this release (`rpc.md` split into `rpc-commands.md`,
  `rpc-extension-ui.md` and `message-types.md`; `json.md` rewritten as
  the canonical event reference), so the byte-diff signal this changelog
  usually cites is noisy from here on; compare command and event name
  sets instead.

## [0.87.0] - 2026-09-22

### Changed

- Re-baseline the tested pin to pi **0.87.0** (from 0.86.1). No wire
  changes on the RPC surface: the packaged `docs/{json,rpc}.md` and the
  `pi --help` output are byte-identical between the two releases, and
  the full live tier passes unmodified. Upstream's 0.87.0 changes are
  SDK-side (`finishTurn` replaces `shouldStopAfterTurn`, canonical
  `SessionManager` context, `context_with_system` and
  `agent_before_settle` extension events, per-model image input limits)
  plus a new append-only `context_edit` session entry in
  `docs/session-format.md`. This crate does not parse session files, so
  the new entry type needs no modeling.

## [0.86.1] - 2026-09-21

### Changed

- Re-baseline the tested pin to pi **0.86.1** (from 0.86.0). No wire
  changes: the packaged `docs/{json,rpc,session-format,sdk}.md` are
  byte-identical between the two releases, and the full live tier
  passes unmodified. Upstream's only user-visible addition is a `meta`
  provider (Muse Spark models via `/login meta` or `META_API_KEY`);
  the crate passes provider names through as strings, so
  `.provider("meta")` works with no type changes.

## [0.86.0] - 2026-09-20

### Added

- `PiMessage::System` — pi 0.86.0 moved the system prompt and tool
  loadout into the transcript (earendil-works/pi#9548). Every turn now
  opens with a `role: "system"` message (`message_start` /
  `message_end` before the user message, and first in `agent_end`'s
  `messages`) carrying named prompt `sections`, `toolsAdded`
  declarations, and `toolsRemoved` references. Without this variant the
  stream failed at the first frame of every model turn with
  `unknown variant "system"`.
- A fresh RPC tool-use capture, `test_cases/rpc_tool_use_0_86_0.jsonl`,
  alongside the 0.84.4 one; the corpus tests now run over both, and a
  new test pins the leading system message's sections and tool set.

### Changed

- Re-baseline the tested pin to pi **0.86.0** (from 0.85.1). The full
  live tier passes against 0.86.0 once the variant lands: six
  credential-free RPC checks, the streamed model turn, and the
  model-tool conformance trio. The `tool_execution_end`-without-`args`
  quirk is still present and now pinned on both captures.

## [0.85.1] - 2026-09-06

### Changed

- Re-baseline the tested pin to pi **0.85.1** (from 0.84.4): the full
  live tier passes unchanged — six credential-free RPC checks, a
  streamed model turn, the model-tool conformance trio (disk-verified),
  and the 5 corpus tests over the committed 0.84.4 tool-use capture,
  which still parses fully typed. Pin-only release.

## [0.84.4] - 2026-09-02

### Changed

- Pin forward out of alpha: the crate version now names the tested pi
  release per the version-means-tested convention. Evidence: the full
  live tier passes 10/10 against pi 0.84.4 — six credential-free RPC
  checks, a streamed model turn, and the model-tool conformance trio
  (read a planted nonce, write a requested nonce, bash with a
  disk-visible side effect; write/bash verified on disk) — plus the
  committed 117-record tool-use corpus, fully typed.

## [0.0.1] - 2026-09-01

### Added

- Initial **alpha** release, tested against pi 0.84.4. The crate
  version intentionally does not yet track the tested CLI release;
  it will jump to the pi version once the API settles and the pin
  is moved forward.
  (`@earendil-works/pi-coding-agent`; requires Node 22+):
  - `PiCliBuilder` — typed argv for `--mode json` / `--mode rpc`
    invocations (provider, model, session, tools, thinking, extras).
  - `rpc` — the headless command protocol: typed `RpcCommand`s with id
    correlation, the response envelope, `AgentState` / `BashResult` /
    message views, and `RpcCommand::Raw` passthrough for unmodeled
    commands.
  - `io` — `PiEvent` (lifecycle + tool events, `Unknown` preserves
    payloads) and `PiMessage` (user / assistant / toolResult /
    bashExecution) with content blocks and usage accounting.
  - `PiRpcClient` — async (Tokio) client honoring the strict LF-only
    JSONL framing contract.
  - Live integration tier that is credential-free: drives a real
    `pi --mode rpc` process through state, model catalog, bash round
    trips (typed results landing in `get_messages`), and clean failure
    envelopes.