rap-protocol 0.2.0

Core types and server scaffolding for the Reactive Agent Protocol (RAP).
Documentation


## v0.1.0 (2026-09-03)

### Chore

 - <csr-id-e2e0719faebbffc72ec7bd8a8b3b02223da8ba0e/> add automated THIRD-PARTY file generation with license enforcement
   Generates a plaintext THIRD-PARTY attribution file combining:
   - Rust dependencies via `cargo-about` (grouped by license, full text)
   - npm dependencies from `infinity-ui/` and `agent/` via `license-checker`
   
   Both ecosystems enforce an allowlist of permissive licenses:
   - Rust (about.toml): Apache-2.0, MIT, ISC, BSD-3-Clause, CC0-1.0,
     CDLA-Permissive-2.0, MPL-2.0, Unicode-3.0, Zlib
   - npm (script): MIT, Apache-2.0, ISC, BSD-2-Clause, BSD-3-Clause, 0BSD,
     CC0-1.0, Unlicense, BlueOak-1.0.0, MPL-2.0
   
   The script fails if any dependency uses a license not in the allowlist.
   
   New files:
   - `about.toml` — cargo-about config
   - `about.hbs` — plaintext Handlebars template
   - `scripts/generate-third-party.sh` — orchestration script
   - `scripts/license-checker-format.json` — tells license-checker to include text
   - `THIRD-PARTY` — the generated file
 - <csr-id-b92b7a17f4b69e2652f5cce813320eca851717e4/> add workspace lints and fix all lint violations

### New Features

 - <csr-id-1935c387d806a1da271e15078b26e06f228737c6/> multimodal (image) tool results end-to-end, with image display + review fixes
   Models can declare image input support, RAP tools can return images in tool
   results (both as model-facing content and as inline display segments), the
   sandbox `read_file` returns image files as image attachments, the web UI
   renders them inline, and the terminal falls back gracefully. Includes a
   shared test-server crate and mock-model / sandbox / TUI / web e2e coverage.
   
   ## Provider protocol (`infinity-provider-protocol`)
   
   * `ModelEntry` gains `supports_image_input: bool` (`#[serde(default)]`, so
     the remote provider socket protocol stays backward compatible).
   * Bedrock provider: all Claude models declare `supports_image_input: true`.
   * The capability is threaded from the resolved `ModelEntry` into
     `run_completion`/`process_batch` (rather than a trait method that re-lists
     models each turn): the daemon passes `catalog.find(&round_model)
     .supports_image_input` per round (following mid-session model switches);
     the Lambda resolves it once from `list_models()`.
   
   ## Agent core (`infinity-agent-core`)
   
   * `HistoryManager::get_history(supports_image_input)` replaces image
     tool-result content in place with `IMAGE_OMITTED_PLACEHOLDER` when the
     model can't accept images (no extra allocation pass). Images kept in
     history become visible again after switching to an image-capable model.
   
   ## RAP protocol (`rap-protocol`)
   
   * `RapToolResult` carries either `text` **or** structured `content`
     (`RapToolResultContent::{Text, Image{data, mediaType}}`, base64); `text` is
     now optional. When `content` is present it supersedes `text`.
   * New `DisplaySegment::Image(ImageContent { data, mediaType })` for
     human-facing UIs.
   * Spec docs (`tool-result.md`) and provider docs updated.
   
   ## Daemon (`infinity-daemon`)
   
   * RAP callbacks build the rig tool result from structured `content` when
     present (images → `ToolResultContent::Image`), else fall back to `text`.
   
   ## Sandbox (`sandbox-core` / `sandbox-local`)
   
   * `read_file` detects images by content (magic bytes, not extension) so
     mislabeled/extension-less files are classified correctly; returns a
     describing text plus base64 image content with `display_as: [image,
     text-summary]`. Tool output modeled as a named `ToolOutput` struct.
   
   ## Clients
   
   * Web (`infinity-ui`): `MessageItem` renders images as an inline bordered
     `<img>` (`data:` URL, `data-testid="tool-result-image"`).
   * TUI / ACP (`infinity-agent-cli`): renderers pick the first *supported*
     display segment; image-only results show `✓ [image — not displayable in
     terminal]`, otherwise the text summary.
   
   ## Shared test crate (`rap-test-servers`, unpublished)
   
   * `start_stub_image_server()` serves a `read_image` RAP tool returning a
     fixed indigo PNG; `write_rap_config(cwd, port)` points sessions at it.
     Dev-dependency of the CLI and daemon e2e suites.
   
   ## Tests
   
   * agent-core: image tool results reach image-capable models and are replaced
     with the placeholder otherwise.
   * daemon: RAP→rig content conversion (fallbacks, media types).
   * provider-protocol: remote transport round-trips `supports_image_input`.
   * sandbox-local: PNG content + display segments, content-based detection
     (PNG named `.txt`), text reads unchanged.
   * TUI e2e: image content reaches the model; terminal renders the text
     fallback (insta snapshot).
   * Web e2e: follow-up request carries the base64 image; transcript renders the
     inline `<img>`; `chat-image-result.png` golden.
 - <csr-id-7085405bbfa8d07f6a69bc0e418761a56d108a67/> add RAP view_update protocol + diff view in web UI
 - <csr-id-ba10ffd62644a4c86c31a7fb6d5eaaca8c403b55/> add remote host migration UI and daemon orchestration

### Bug Fixes

 - <csr-id-44fcca250a44029e36b49df6013a049d33bc985f/> log panics from fire-and-forget spawned tasks instead of silently swallowing them

### Other

 - <csr-id-ffc27d0bf5d964a655fedab9460bf5017971e6b6/> set up cargo-smart-release release workflow (mirroring hydro)
   * chore: set up cargo-smart-release release workflow (mirroring hydro)
   
   Sets up the release tooling for this workspace following the same
   cargo-smart-release setup as hydro-project/hydro (per its RELEASING.md).
   
   * `.github/workflows/release.yml`: new manually-dispatched Release workflow,
     adapted from hydro's. Supports major/minor/patch/keep/auto bumps, optional
     pre-release ids, and a dry-run mode (execute unchecked). Uses the
     hydro-project-bot GitHub App token to push past branch protection, and the
     pinned hydro-project fork of cargo-smart-release (rev e6f3368337a0).
   * `RELEASING.md`: releasing guide adapted from hydro's, including which crates
     are published and why the others are not, plus an addendum explaining why
     `[patch.crates-io]` on `rig-bedrock` blocks publishing the bedrock provider.
   * Crate manifests, 14 publishable crates (rap-protocol, rap-client,
     rap-steering-server, rap-github-event-poller, infinity-protocol,
     infinity-provider-protocol, infinity-agent-core, infinity-mcp-bridge,
     infinity-rap-bridge, infinity-daemon, infinity-agent-cli, sandbox-core,
     sandbox-local, sandbox-remote):
     - `publish = true`, `description`, `documentation` (docs.rs), and
       `repository = { workspace = true }` (new `[workspace.package]` in the root
       `Cargo.toml`).
     - `version = "^0.1.0"` added to all intra-workspace path dependencies
       (including dev-deps between publishable crates), as required for
       publishing.
     - New empty `CHANGELOG.md` per crate so cargo-smart-release will generate
       and track changelogs.
   * `publish = false` added to crates that must not be published:
     - `rig-mock`, `rap-test-servers` (test-only; left as path-only dev-deps so
       cargo strips them at publish time),
     - `rig-bedrock-patched` (vendored fork of crates-io `rig-bedrock`),
     - `infinity-provider-bedrock` + `infinity-agent-lambda` (depend on the
       patched rig-bedrock; publishing would silently drop the patches),
     - `infinity-slack-bot` (deployment artifact).

### Refactor

 - <csr-id-7634b823ad70378e666379a9a8e8a7935a06026f/> replace all .unwrap() with .expect() and fix clippy warnings
 - <csr-id-9757071818663cefb8e6a12438071d95000379a8/> add precheck script, lints

### Refactor (BREAKING)

 - <csr-id-4b18b37de219cb7fe27ce7c027b87f4fb35fbbf5/> introduce typed ThreadId for RAP group ids
   * refactor(rap-protocol)!: introduce typed ThreadId for RAP group ids
   
   Stage 1 of the string-ID to typed-ID migration (#108). Defines `ThreadId`
   via the published `strkind` 0.0.1 macro and converts every RAP `group_id`
   on the wire types, plus all consumers. Serialization is transparent, so
   the wire format and persisted metadata are byte-identical (verified: no
   insta snapshot changes; full test suite passes).
   
   * rap-protocol: `strkind! { pub ThreadId; }` with docs (RAP calls it
     `group_id` on the wire; UUIDs in the daemon, caller-chosen conversation
     keys in the Lambda runtime). `group_id: ThreadId` on `RapInvocation`,
     `RapToolResult`, `RapUserChoice`, `RapSubscriptionEvent`,
     `RapViewUpdate`, `RapOAuth`; `thread_ancestors: Option<Vec<ThreadId>>`;
     `send_subscription_event`/`send_view_update` take `ThreadId`
   * sandbox-core/local/remote (via sub-agent): `ThreadId` re-exported from
     sandbox-core root; `MetadataStore::get/delete(&ThreadId)`;
     `SandboxBackend::push_sandbox`/`cleanup_sandbox_permanently` typed;
     `RepoState.{group_id, root_thread_id}`, `CloneRepoArgs.base_thread_id`,
     `SquashSandboxArgs.from_thread_id`, `CloneContext.group_id`,
     `SandboxError::RepoNotFound`, and server request payload structs typed
   * infinity-agent-core: rap_tool boundary converts `ToolContext` strings
     into `ThreadId` when building invocations (context types themselves are
     Stage 2)
   * infinity-rap-bridge: callback conversion unwraps `ThreadId` into
     `InputMessage.group_id` (String until Stage 2)
   * rap-github-event-poller: `Subscription.group_id: ThreadId`
   * infinity-daemon: view-update routing + test fixture conversions
   * Workspace: `strkind = "0.0.1"` added to workspace dependencies

### Commit Statistics

<csr-read-only-do-not-edit/>

 - 17 commits contributed to the release.
 - 10 commits were understood as [conventional]https://www.conventionalcommits.org.
 - 4 unique issues were worked on: [#107]https://github.com/hydro-project/infinity/issues/107, [#113]https://github.com/hydro-project/infinity/issues/113, [#61]https://github.com/hydro-project/infinity/issues/61, [#8]https://github.com/hydro-project/infinity/issues/8

### Commit Details

<csr-read-only-do-not-edit/>

<details><summary>view details</summary>

 * **[#107]https://github.com/hydro-project/infinity/issues/107**
    - Set up cargo-smart-release release workflow (mirroring hydro) ([`ffc27d0`]https://github.com/hydro-project/infinity/commit/ffc27d0bf5d964a655fedab9460bf5017971e6b6)
 * **[#113]https://github.com/hydro-project/infinity/issues/113**
    - Introduce typed ThreadId for RAP group ids ([`4b18b37`]https://github.com/hydro-project/infinity/commit/4b18b37de219cb7fe27ce7c027b87f4fb35fbbf5)
 * **[#61]https://github.com/hydro-project/infinity/issues/61**
    - Multimodal (image) tool results end-to-end, with image display + review fixes ([`1935c38`]https://github.com/hydro-project/infinity/commit/1935c387d806a1da271e15078b26e06f228737c6)
 * **[#8]https://github.com/hydro-project/infinity/issues/8**
    - Add automated THIRD-PARTY file generation with license enforcement ([`e2e0719`]https://github.com/hydro-project/infinity/commit/e2e0719faebbffc72ec7bd8a8b3b02223da8ba0e)
 * **Uncategorized**
    - Add workspace lints and fix all lint violations ([`b92b7a1`]https://github.com/hydro-project/infinity/commit/b92b7a17f4b69e2652f5cce813320eca851717e4)
    - Add RAP view_update protocol + diff view in web UI ([`7085405`]https://github.com/hydro-project/infinity/commit/7085405bbfa8d07f6a69bc0e418761a56d108a67)
    - Add remote host migration UI and daemon orchestration ([`ba10ffd`]https://github.com/hydro-project/infinity/commit/ba10ffd62644a4c86c31a7fb6d5eaaca8c403b55)
    - Log panics from fire-and-forget spawned tasks instead of silently swallowing them ([`44fcca2`]https://github.com/hydro-project/infinity/commit/44fcca250a44029e36b49df6013a049d33bc985f)
    - Replace all .unwrap() with .expect() and fix clippy warnings ([`7634b82`]https://github.com/hydro-project/infinity/commit/7634b823ad70378e666379a9a8e8a7935a06026f)
    - Add precheck script, lints ([`9757071`]https://github.com/hydro-project/infinity/commit/9757071818663cefb8e6a12438071d95000379a8)
    - Introduce display_as typed variants and use Pierre to display in web client ([`1e65518`]https://github.com/hydro-project/infinity/commit/1e65518e4f041f76e6359b08ff88e32fc8753cda)
    - Add write:/path permissions, thread_ancestors protocol field, and ancestor-aware grant system ([`3464fad`]https://github.com/hydro-project/infinity/commit/3464fade510fd5ab7aa2dc2ffa27f61711c6be31)
    - Unify all duplicate RAP protocol types into rap-protocol crate ([`2def5ee`]https://github.com/hydro-project/infinity/commit/2def5eec01a5c197432a7959942cca8b0eb9d6a0)
    - Unify RapInvocation into a single type in rap-protocol ([`e14509e`]https://github.com/hydro-project/infinity/commit/e14509ecf6e6bf622d6ca0a1252148b647c1ef7f)
    - Add support for UserChoice prompts in RAP protocol and use for permissions expansion in sandbox ([`b0db6a7`]https://github.com/hydro-project/infinity/commit/b0db6a7a0764ddab7df1f5cf3fcefc7129c6ddcb)
    - Allow auto quit without quit picker when agent is idle ([`3285dc5`]https://github.com/hydro-project/infinity/commit/3285dc5078947b76ad440342316dbd1d665800f4)
    - Add steering file instructions to the default agent prompt ([`40b1f78`]https://github.com/hydro-project/infinity/commit/40b1f78d18466b99040caecc772adfaa7c6ed705)
</details>