Skip to content

feat(infinity-agent-core)!: add high-level agent system API - #92

Open
shadaj wants to merge 1 commit into
sandbox-0f86f15a-4591-435a-bff7-27a45f33e143from
sandbox-eb0ff46e-96e1-4d2d-8c0b-9c683fa4d1b9
Open

feat(infinity-agent-core)!: add high-level agent system API#92
shadaj wants to merge 1 commit into
sandbox-0f86f15a-4591-435a-bff7-27a45f33e143from
sandbox-eb0ff46e-96e1-4d2d-8c0b-9c683fa4d1b9

Conversation

@shadaj

@shadaj shadaj commented Aug 4, 2026

Copy link
Copy Markdown
Member

Stack

This is PR 2 of 2, based on the shared-engine refactor in #96. Review #96 first; this diff contains the application-facing API, local protocol adapters, and documentation.

Summary

Add ergonomic local agent-system APIs on top of the engine extracted in #96:

  • static builder conveniences for tools, prompts, and RAP notification;
  • channel-backed ThreadHandles for sending inputs and streaming events;
  • launcher mode and ThreadBuilder for per-thread tools, prompts, and models;
  • root-based configuration inheritance for child threads;
  • direct local McpToolSet and RapToolSet adapters;
  • usage-oriented high-level and low-level documentation.

The daemon, Lambda, stores, driver, thread pipeline, admission, lifecycle behavior, and embedding-oriented bridge foundations are reviewed in #96.

Review guide

ThreadHandle and handle mode

system/local/handle.rs adds a channel-based observer and registry:

  • RunningSystem::thread_handle(id) attaches to a thread and returns a handle that can send inputs and receive its event stream.
  • The registry is owned by the running system, so handles continue receiving events when a driver idles and respawns.
  • Multiple handles can observe the same thread; dropping one prunes its registration without affecting the others.
  • Subscription installation is acknowledged before attach completes, preserving attach-then-send ordering.

Tests cover sending and receiving, streaming across tool-call rounds, driver respawn, and pruning dropped handles.

Launcher mode

system/local/launch.rs adds:

  • LocalAgentSystem::with_thread_launcher() and LaunchingSystem;
  • ThreadBuilder for launching a new root thread with its own tools, system prompt, and model;
  • attachment to existing threads through launcher handles without implicitly creating them.

Launch configuration is registered before the seed message is sent. UnionConfigSource and UnionModelSource resolve entries by the thread's root ID, so child threads inherit their parent's launch-specific tools, prompt, and model while retaining system-wide configuration.

Tests cover tool/prompt union, child inheritance, per-thread model selection, and attach-only behavior.

Builder typestate and conveniences

LocalAgentSystem gains explicit operation modes:

  • Handles is the default and start() returns RunningSystem with built-in handles.
  • Launcher is selected with with_thread_launcher() and start() returns LaunchingSystem.
  • start_with_observer remains available for embeddings that provide their own observer.

AgentSystemBuilder also gains static tool, tools, extra_system_prompt, and rap_notifier helpers for applications that do not need a custom ThreadConfigSource.

Local MCP and RAP adapters

  • McpToolSet exposes a lazy stdio or Streamable HTTP MCP client as local list/invoke tools while sharing metadata and dispatch with the daemon-facing McpClient.
  • RapToolSet discovers manifest tools and returns the shared core RapTool implementation. It takes an explicit callback URL rather than capturing the most recently invoked system sender.
  • RapCallbackBridge is bound separately and explicitly attached with serve_into(system.sender()), making callback ownership and view-update handling unambiguous. There is no late-bound sender mutex or destination switching.

Documentation

Adds The Agent System API section:

  1. overview;
  2. building a system;
  3. running locally;
  4. RAP servers;
  5. MCP servers;
  6. custom tools;
  7. dynamic configuration;
  8. observers;
  9. step mode;
  10. customizing the engine.

It also adds focused low-level guides for the history manager and completion loop, and updates existing runtime pages to direct application authors toward the new API.

Validation

  • cargo fmt --all -- --check
  • cargo clippy --workspace --all-targets -- -D warnings
  • cargo test --workspace, including doc tests

Breaking changes

Relative to #96:

  • LocalAgentSystem gains a mode type parameter, defaulting to Handles.
  • The default local startup method is start(); custom observers continue to use start_with_observer.
  • ThreadHandle, HandleObserver, HandleSubscribeRequest, LaunchingSystem, and ThreadBuilder are exported under system::local.
  • RapTool gains an optional callback URL used by local RAP tool sets.

No daemon behavior changes are introduced in this PR.

shadaj added a commit that referenced this pull request Aug 4, 2026
…on + lambda onto it

Introduce `infinity_agent_core::system`, a builder-based, object-oriented API for
running agents, and rebuild both production embeddings on top of it. The docs for
`infinity-runtime` are rewritten around the new API.

Core (`infinity_agent_core::system`):
- `AgentSystemBuilder`: two construction modes — `new(stores, model, sender)` builds a
  step-mode `AgentSystem` for serverless platforms; `new_local(stores, model)` builds a
  `LocalAgentSystem` with an internal in-process queue (`ChannelSender`).
- `Thread`: loads one conversation thread from the stores; `step(inputs, observer,
  cancel_rx)` runs one slice (prepare → completion → history sync → observer commit
  barrier → tool dispatch). Per-thread configuration is resolved lazily on first step so
  loading a thread never boots tool servers.
- `LocalAgentSystem::start` runs a full actor-system-style runtime: a router plus one
  driver task per active thread, with input batching, `<interrupt>` handling for user
  text during a completion, deferral of subscription events while a non-passive tool
  call is pending, auto-compaction above 75% of the context window, and race-free idle
  exit/respawn. `RunningSystem` exposes `sender()`, `send_user_text`, ack'd
  `subscribe`, `active_threads`, a `thread_exits` channel for per-conversation resource
  teardown, and `begin_shutdown` for process exit. The system itself runs for the
  process lifetime.
- `ThreadHandle`: `LocalAgentSystem::start_with_handles()` runs the system with a
  built-in channel-based observer (`HandleObserver`) whose subscriber registry is
  shared across driver respawns; `RunningSystem::thread_handle(thread_id)` then
  attaches to a thread (creating its subscription even before the thread exists) and
  returns a handle with `replay()` for the initial snapshot, an unbounded `events`
  queue of `AgentEvent`s (exactly-once relative to the replay), and
  `send_user_text`/`send` for input.
- `ThreadObserver`: synchronous `on_event(AgentEvent)` fan-out (exactly-once relative
  to `on_subscribe` replay snapshots) plus awaited durability hooks
  (`on_user_choice_required`/`_dismissed`, `on_commit` before tool dispatch).
- `ModelSource` (per-round model resolution; enables mid-session model switching) with
  `StaticModel`; `ThreadConfigSource` (per-thread tools/prompt/notifier; enables
  per-session RAP servers) with `StaticThreadConfig`; `DeferQueue` with
  `InMemoryDeferQueue`/`NoDeferral`.
- `AgentEvent`/`ReplaySnapshot`/`UserChoice` display types; `Tool::is_passive()`;
  in-memory `ConversationStore`/`StateStore` implementations in
  `infinity_agent_core::stores`; tokio-backed sleep tools moved into the core
  (`with_tokio_sleep_tools`).
- The core API is platform-neutral: `input_queue_arn` is removed from `ToolContext`
  and the builder. Platform-specific configuration lives on the tools that need it
  (the Lambda sleep tools now carry the input queue ARN as a field, alongside their
  scheduler client, role ARN, and delay queue URL).
- All 20 daemon agent-loop tests migrated into core `system/tests.rs` with
  byte-identical snapshots, plus 3 new `ThreadHandle` tests (send/receive + late
  replay, survival across idle/respawn, dropped-handle pruning).

Daemon (`infinity-daemon`):
- One daemon-lifetime agent system replaces per-session agent loops. Sessions are root
  threads; a `thread_exits` watcher marks sessions idle and shuts down their RAP
  servers when no keep-alive client is attached.
- New `rap_servers.rs`: `ManagedRapServer`/`ManagedRapTool`/`SessionRapManager` — RAP
  servers boot lazily per session via `ThreadConfigSource` and reboot transparently
  after idle shutdown. Config-source info messages ("Using local config", etc.) are
  preserved at first resolve.
- `DaemonObserver` implements the observer hooks (usage persistence, pending user
  choices, live-attach replay including mid-stream thinking).
- `CatalogModelSource` resolves each thread's persisted model selection per round.
- Deleted: `session/thread_worker.rs`, `session/agent_loop.rs`, `sleep_tools.rs`,
  `InMemoryMessageSender`, `Session`, `spawn_session`, `AgentMessage`.

Lambda (`infinity-agent-lambda`): event handler rewritten on
`AgentSystemBuilder::new(...).build()` + `thread()`/`filter_deferrable`/`step` with an
`EventCollector`, replacing the hand-rolled `process_batch` plumbing.

Docs (`docs/docs/infinity-runtime`): the single "Rust API" page is replaced by two
sections. "The Agent System API" (overview, building-a-system, running-locally,
step-mode, observers) documents the new high-level API — including thread handles —
and the patterns both embeddings use; "The Low-Level API" (overview, history-manager,
completion-loop) documents the platform traits and loop pieces underneath and when to
use them. Cross-references across overview/architecture/built-in-tools/
deploying-on-lambda updated.

BREAKING CHANGE: `infinity-daemon` no longer exports `sleep_tools`, `AgentMessage`,
`thread_worker`, `agent_loop`, `Session`, or `InMemoryMessageSender`; `SessionManager`'s
API is reshaped around the single agent system and `SharedSessionManager` is now
`Rc<tokio::Mutex<...>>`. In `infinity-agent-core`, builder tools are stored as
`Rc<dyn Tool<M>>`, `Tool` gains a defaulted `is_passive` method, `ToolContext` and
`AgentSystemBuilder` lose `input_queue_arn`, and daemon/lambda display paths now emit
`AgentEvent` instead of `DisplayEvent`.

Co-authored-by: Infinity 🤖 <infinity@hydro.run>
PR: #92
@shadaj
shadaj force-pushed the sandbox-eb0ff46e-96e1-4d2d-8c0b-9c683fa4d1b9 branch from 5689aff to 7a10b86 Compare August 4, 2026 22:36
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 4, 2026

Copy link
Copy Markdown

Deploying infinity with  Cloudflare Pages  Cloudflare Pages

Latest commit: eadab61
Status: ✅  Deploy successful!
Preview URL: https://1b2d8fb6.infinity-dc7.pages.dev
Branch Preview URL: https://sandbox-eb0ff46e-96e1-4d2d-8.infinity-dc7.pages.dev

View logs

shadaj added a commit that referenced this pull request Aug 4, 2026
…on + lambda onto it

Introduce `infinity_agent_core::system`, a builder-based, object-oriented API for
running agents, and rebuild both production embeddings on top of it. The docs for
`infinity-runtime` are rewritten around the new API.

Core (`infinity_agent_core::system`):
- `AgentSystemBuilder`: two construction modes — `new(stores, model, sender)` builds a
  step-mode `AgentSystem` for serverless platforms; `new_local(stores, model)` builds a
  `LocalAgentSystem` with an internal in-process queue (`ChannelSender`).
- `Thread`: loads one conversation thread from the stores. `step(inputs, observer,
  defer, cancel_rx)` runs one slice with the deferral policy applied (filter →
  prepare → completion → history sync → observer commit barrier → tool dispatch);
  `step_no_defer(batch, observer, cancel_rx)` is the raw step for callers that
  compose `filter_deferrable` themselves (the local driver, which must skip no-op
  steps when everything was deferred). Per-thread configuration is resolved lazily on
  first step so loading a thread never boots tool servers.
- `LocalAgentSystem::start` runs a full actor-system-style runtime: a router plus one
  driver task per active thread, with input batching, `<interrupt>` handling for user
  text during a completion, deferral of subscription events while a non-passive tool
  call is pending, auto-compaction above 75% of the context window, and race-free idle
  exit/respawn. `RunningSystem` exposes `sender()`, `send_user_text`, ack'd
  `subscribe`, `active_threads`, a `thread_exits` channel for per-conversation resource
  teardown, and `begin_shutdown` for process exit. The system itself runs for the
  process lifetime.
- `ThreadHandle`: `LocalAgentSystem::start_with_handles()` runs the system with a
  built-in channel-based observer (`HandleObserver`) whose subscriber registry is
  shared across driver respawns; `RunningSystem::thread_handle(thread_id)` then
  attaches to a thread (creating its subscription even before the thread exists) and
  returns a handle with `replay()` for the initial snapshot, an unbounded `events`
  queue of `AgentEvent`s (exactly-once relative to the replay), and
  `send_user_text`/`send` for input.
- `ThreadObserver`: synchronous `on_event(AgentEvent)` fan-out (exactly-once relative
  to `on_subscribe` replay snapshots) plus awaited durability hooks
  (`on_user_choice_required`/`_dismissed`, `on_commit` before tool dispatch).
- `ModelSource` (per-round model resolution; enables mid-session model switching) with
  `StaticModel`; `ThreadConfigSource` (per-thread tools/prompt/notifier; enables
  per-session RAP servers) with `StaticThreadConfig`; `DeferQueue` with
  `InMemoryDeferQueue`/`NoDeferral`.
- `AgentEvent`/`ReplaySnapshot`/`UserChoice` display types; `Tool::is_passive()`;
  in-memory `ConversationStore`/`StateStore` implementations in
  `infinity_agent_core::stores`; tokio-backed sleep tools moved into the core
  (`with_tokio_sleep_tools`).
- The core API is platform-neutral: `input_queue_arn` is removed from `ToolContext`
  and the builder. Platform-specific configuration lives on the tools that need it
  (the Lambda sleep tools now carry the input queue ARN as a field, alongside their
  scheduler client, role ARN, and delay queue URL).
- All 20 daemon agent-loop tests migrated into core `system/tests.rs` with
  byte-identical snapshots, plus 3 new `ThreadHandle` tests (send/receive + late
  replay, survival across idle/respawn, dropped-handle pruning).

Daemon (`infinity-daemon`):
- One daemon-lifetime agent system replaces per-session agent loops. Sessions are root
  threads; a `thread_exits` watcher marks sessions idle and shuts down their RAP
  servers when no keep-alive client is attached.
- New `rap_servers.rs`: `ManagedRapServer`/`ManagedRapTool`/`SessionRapManager` — RAP
  servers boot lazily per session via `ThreadConfigSource` and reboot transparently
  after idle shutdown. Config-source info messages ("Using local config", etc.) are
  preserved at first resolve.
- `DaemonObserver` implements the observer hooks (usage persistence, pending user
  choices, live-attach replay including mid-stream thinking).
- `CatalogModelSource` resolves each thread's persisted model selection per round.
- Deleted: `session/thread_worker.rs`, `session/agent_loop.rs`, `sleep_tools.rs`,
  `InMemoryMessageSender`, `Session`, `spawn_session`, `AgentMessage`.

Lambda (`infinity-agent-lambda`): event handler rewritten on
`AgentSystemBuilder::new(...).build()` + `thread()` + the deferral-aware
`Thread::step` with an `EventCollector`, replacing the hand-rolled `process_batch`
plumbing.

Docs (`docs/docs/infinity-runtime`): the single "Rust API" page is replaced by two
sections. "The Agent System API" (overview, building-a-system, running-locally,
step-mode, observers) documents the new high-level API — including thread handles and
the step/step_no_defer split — and the patterns both embeddings use; "The Low-Level
API" (overview, history-manager, completion-loop) documents the platform traits and
loop pieces underneath and when to use them. Cross-references across
overview/architecture/built-in-tools/deploying-on-lambda updated.

BREAKING CHANGE: `infinity-daemon` no longer exports `sleep_tools`, `AgentMessage`,
`thread_worker`, `agent_loop`, `Session`, or `InMemoryMessageSender`; `SessionManager`'s
API is reshaped around the single agent system and `SharedSessionManager` is now
`Rc<tokio::Mutex<...>>`. In `infinity-agent-core`, builder tools are stored as
`Rc<dyn Tool<M>>`, `Tool` gains a defaulted `is_passive` method, `ToolContext` and
`AgentSystemBuilder` lose `input_queue_arn`, and daemon/lambda display paths now emit
`AgentEvent` instead of `DisplayEvent`.

Co-authored-by: Infinity 🤖 <infinity@hydro.run>
PR: #92
@shadaj
shadaj force-pushed the sandbox-eb0ff46e-96e1-4d2d-8c0b-9c683fa4d1b9 branch from 7a10b86 to 32bcb39 Compare August 4, 2026 23:59
@MingweiSamuel

Copy link
Copy Markdown
Member

Oh god

shadaj added a commit that referenced this pull request Aug 5, 2026
…on + lambda onto it

Introduce `infinity_agent_core::system`, a builder-based, object-oriented API for
running agents, and rebuild both production embeddings on top of it. The docs for
`infinity-runtime` are rewritten around the new API.

Core (`infinity_agent_core::system`):
- `AgentSystemBuilder`: two construction modes — `new(stores, model, sender)` builds a
  step-mode `AgentSystem` for serverless platforms; `new_local(stores, model)` builds a
  `LocalAgentSystem` with an internal in-process queue (`ChannelSender`).
- `Thread`: loads one conversation thread from the stores. `step(inputs, observer,
  defer, cancel_rx)` runs one slice with the deferral policy applied (filter →
  prepare → completion → history sync → observer commit barrier → tool dispatch);
  `step_no_defer(batch, observer, cancel_rx)` is the raw step for callers that
  compose `filter_deferrable` themselves (the local driver, which must skip no-op
  steps when everything was deferred). Per-thread configuration is resolved lazily on
  first step so loading a thread never boots tool servers.
- `LocalAgentSystem::start` runs a full actor-system-style runtime: a router plus one
  driver task per active thread, with input batching, `<interrupt>` handling for user
  text during a completion, deferral of subscription events while a non-passive tool
  call is pending, auto-compaction above 75% of the context window, and race-free idle
  exit/respawn. `RunningSystem` exposes `sender()`, `send_user_text`, ack'd
  `subscribe`, `active_threads`, a `thread_exits` channel for per-conversation resource
  teardown, and `begin_shutdown` for process exit. The system itself runs for the
  process lifetime.
- `ThreadHandle`: `LocalAgentSystem::start_with_handles()` runs the system with a
  built-in channel-based observer (`HandleObserver`) whose subscriber registry is
  shared across driver respawns; `RunningSystem::thread_handle(thread_id)` then
  attaches to a thread (creating its subscription even before the thread exists) and
  returns a handle with `replay()` for the initial snapshot, an unbounded `events`
  queue of `AgentEvent`s (exactly-once relative to the replay), and
  `send_user_text`/`send` for input.
- `ThreadObserver`: synchronous `on_event(AgentEvent)` fan-out (exactly-once relative
  to `on_subscribe` replay snapshots) plus awaited durability hooks
  (`on_user_choice_required`/`_dismissed`, `on_commit` before tool dispatch).
- `ModelSource` (per-round model resolution; enables mid-session model switching) with
  `StaticModel`; `ThreadConfigSource` (per-thread tools/prompt/notifier; enables
  per-session RAP servers) with `StaticThreadConfig`; `DeferQueue` with
  `InMemoryDeferQueue`/`NoDeferral`.
- `AgentEvent`/`ReplaySnapshot`/`UserChoice` display types; `Tool::is_passive()`;
  in-memory `ConversationStore`/`StateStore` implementations in
  `infinity_agent_core::stores`; tokio-backed sleep tools moved into the core
  (`with_tokio_sleep_tools`).
- The core API is platform-neutral: `input_queue_arn` is removed from `ToolContext`
  and the builder. Platform-specific configuration lives on the tools that need it
  (the Lambda sleep tools now carry the input queue ARN as a field, alongside their
  scheduler client, role ARN, and delay queue URL).
- All 20 daemon agent-loop tests migrated into core `system/tests.rs` with
  byte-identical snapshots, plus 3 new `ThreadHandle` tests (send/receive + late
  replay, survival across idle/respawn, dropped-handle pruning).

Daemon (`infinity-daemon`):
- One daemon-lifetime agent system replaces per-session agent loops. Sessions are root
  threads; a `thread_exits` watcher marks sessions idle and shuts down their RAP
  servers when no keep-alive client is attached.
- New `rap_servers.rs`: `ManagedRapServer`/`ManagedRapTool`/`SessionRapManager` — RAP
  servers boot lazily per session via `ThreadConfigSource` and reboot transparently
  after idle shutdown. Config-source info messages ("Using local config", etc.) are
  preserved at first resolve.
- `DaemonObserver` implements the observer hooks (usage persistence, pending user
  choices, live-attach replay including mid-stream thinking).
- `CatalogModelSource` resolves each thread's persisted model selection per round.
- Fix a pre-existing bug where the requesting client received `ModelSwitched` twice
  (once via the subscriber broadcast, once via the direct reply): `switch_model` now
  tracks whether the broadcast reached the requester (`same_channel`) and only sends
  directly when it did not. Verified by the `switch_model_mid_session` web e2e test.
- The `chat-image-result` web golden screenshot is regenerated: the old golden
  captured a layout artifact of the eager RAP-boot flow; the lazy flow renders the
  canonical transcript (verified against the DOM).
- Deleted: `session/thread_worker.rs`, `session/agent_loop.rs`, `sleep_tools.rs`,
  `InMemoryMessageSender`, `Session`, `spawn_session`, `AgentMessage`.

Lambda (`infinity-agent-lambda`): event handler rewritten on
`AgentSystemBuilder::new(...).build()` + `thread()` + the deferral-aware
`Thread::step` with an `EventCollector`, replacing the hand-rolled `process_batch`
plumbing.

Docs (`docs/docs/infinity-runtime`): the single "Rust API" page is replaced by two
sections. "The Agent System API" (overview, building-a-system, running-locally,
step-mode, observers) documents the new high-level API — including thread handles and
the step/step_no_defer split — and the patterns both embeddings use; "The Low-Level
API" (overview, history-manager, completion-loop) documents the platform traits and
loop pieces underneath and when to use them. Cross-references across
overview/architecture/built-in-tools/deploying-on-lambda updated.

BREAKING CHANGE: `infinity-daemon` no longer exports `sleep_tools`, `AgentMessage`,
`thread_worker`, `agent_loop`, `Session`, or `InMemoryMessageSender`; `SessionManager`'s
API is reshaped around the single agent system (`switch_model` now takes the
requester's sender and returns `Result<(), String>`) and `SharedSessionManager` is now
`Rc<tokio::Mutex<...>>`. In `infinity-agent-core`, builder tools are stored as
`Rc<dyn Tool<M>>`, `Tool` gains a defaulted `is_passive` method, `ToolContext` and
`AgentSystemBuilder` lose `input_queue_arn`, and daemon/lambda display paths now emit
`AgentEvent` instead of `DisplayEvent`.

Co-authored-by: Infinity 🤖 <infinity@hydro.run>
PR: #92
@shadaj
shadaj force-pushed the sandbox-eb0ff46e-96e1-4d2d-8c0b-9c683fa4d1b9 branch from 32bcb39 to 723ade3 Compare August 5, 2026 21:24
shadaj added a commit that referenced this pull request Aug 5, 2026
…on + lambda onto it

Introduce `infinity_agent_core::system`, a builder-based, object-oriented API for
running agents, and rebuild both production embeddings on top of it. The docs for
`infinity-runtime` are rewritten around the new API.

Core (`infinity_agent_core::system`):
- `AgentSystemBuilder`: two construction modes — `new(stores, model, sender)` builds a
  step-mode `AgentSystem` for serverless platforms; `new_local(stores, model)` builds a
  `LocalAgentSystem` with an internal in-process queue (`ChannelSender`).
- `Thread`: loads one conversation thread from the stores. `step(inputs, observer,
  defer, cancel_rx)` runs one slice with the deferral policy applied (filter →
  prepare → completion → history sync → observer commit barrier → tool dispatch);
  `step_no_defer(batch, observer, cancel_rx)` is the raw step for callers that
  compose `filter_deferrable` themselves (the local driver, which must skip no-op
  steps when everything was deferred). Per-thread configuration is resolved lazily on
  first step so loading a thread never boots tool servers.
- `LocalAgentSystem::start` runs a full actor-system-style runtime: a router plus one
  driver task per active thread, with input batching, `<interrupt>` handling for user
  text during a completion, deferral of subscription events while a non-passive tool
  call is pending, auto-compaction above 75% of the context window, and race-free idle
  exit/respawn. `RunningSystem` exposes `sender()`, `send_user_text`, ack'd
  `subscribe`, `active_threads`, a `thread_exits` channel for per-conversation resource
  teardown, and `begin_shutdown` for process exit. The system itself runs for the
  process lifetime.
- `ThreadHandle`: `LocalAgentSystem::start_with_handles()` runs the system with a
  built-in channel-based observer (`HandleObserver`) whose subscriber registry is
  shared across driver respawns; `RunningSystem::thread_handle(thread_id)` then
  attaches to a thread (creating its subscription even before the thread exists) and
  returns a handle with `replay()` for the initial snapshot, an unbounded `events`
  queue of `AgentEvent`s (exactly-once relative to the replay), and
  `send_user_text`/`send` for input.
- `ThreadObserver`: synchronous `on_event(AgentEvent)` fan-out (exactly-once relative
  to `on_subscribe` replay snapshots) plus awaited durability hooks
  (`on_user_choice_required`/`_dismissed`, `on_commit` before tool dispatch).
- `ModelSource` (per-round model resolution; enables mid-session model switching) with
  `StaticModel`; `ThreadConfigSource` (per-thread tools/prompt/notifier; enables
  per-session RAP servers) with `StaticThreadConfig`; `DeferQueue` with
  `InMemoryDeferQueue`/`NoDeferral`.
- `AgentEvent`/`ReplaySnapshot`/`UserChoice` display types; `Tool::is_passive()`;
  in-memory `ConversationStore`/`StateStore` implementations in
  `infinity_agent_core::stores`; tokio-backed sleep tools moved into the core
  (`with_tokio_sleep_tools`).
- The core API is platform-neutral: `input_queue_arn` is removed from `ToolContext`
  and the builder. Platform-specific configuration lives on the tools that need it
  (the Lambda sleep tools now carry the input queue ARN as a field, alongside their
  scheduler client, role ARN, and delay queue URL).
- All 20 daemon agent-loop tests migrated into core `system/tests.rs` with
  byte-identical snapshots, plus 3 new `ThreadHandle` tests (send/receive + late
  replay, survival across idle/respawn, dropped-handle pruning).

Daemon (`infinity-daemon`):
- One daemon-lifetime agent system replaces per-session agent loops. Sessions are root
  threads; a `thread_exits` watcher marks sessions idle and shuts down their RAP
  servers when no keep-alive client is attached.
- New `rap_servers.rs`: `ManagedRapServer`/`ManagedRapTool`/`SessionRapManager` — RAP
  servers boot lazily per session via `ThreadConfigSource` and reboot transparently
  after idle shutdown. Config-source info messages ("Using local config", etc.) are
  preserved at first resolve.
- `DaemonObserver` implements the observer hooks (usage persistence, pending user
  choices, live-attach replay including mid-stream thinking).
- `CatalogModelSource` resolves each thread's persisted model selection per round.
- Fix a pre-existing bug where the requesting client received `ModelSwitched` twice
  (once via the subscriber broadcast, once via the direct reply): `switch_model` now
  tracks whether the broadcast reached the requester (`same_channel`) and only sends
  directly when it did not. Verified by the `switch_model_mid_session` web e2e test.
- The `chat-image-result` web golden screenshot is regenerated: the old golden
  captured a layout artifact of the eager RAP-boot flow; the lazy flow renders the
  canonical transcript (verified against the DOM).
- Deleted: `session/thread_worker.rs`, `session/agent_loop.rs`, `sleep_tools.rs`,
  `InMemoryMessageSender`, `Session`, `spawn_session`, `AgentMessage`.

Lambda (`infinity-agent-lambda`): event handler rewritten on
`AgentSystemBuilder::new(...).build()` + `thread()` + the deferral-aware
`Thread::step` with an `EventCollector`, replacing the hand-rolled `process_batch`
plumbing.

Docs (`docs/docs/infinity-runtime`): the single "Rust API" page is replaced by two
sections. "The Agent System API" (overview, building-a-system, running-locally,
step-mode, observers) documents the new high-level API — including thread handles and
the step/step_no_defer split — and the patterns both embeddings use; "The Low-Level
API" (overview, history-manager, completion-loop) documents the platform traits and
loop pieces underneath and when to use them. Cross-references across
overview/architecture/built-in-tools/deploying-on-lambda updated.

BREAKING CHANGE: `infinity-daemon` no longer exports `sleep_tools`, `AgentMessage`,
`thread_worker`, `agent_loop`, `Session`, or `InMemoryMessageSender`; `SessionManager`'s
API is reshaped around the single agent system (`switch_model` now takes the
requester's sender and returns `Result<(), String>`) and `SharedSessionManager` is now
`Rc<tokio::Mutex<...>>`. In `infinity-agent-core`, builder tools are stored as
`Rc<dyn Tool<M>>`, `Tool` gains a defaulted `is_passive` method, `ToolContext` and
`AgentSystemBuilder` lose `input_queue_arn`, and daemon/lambda display paths now emit
`AgentEvent` instead of `DisplayEvent`.

Co-authored-by: Infinity 🤖 <infinity@hydro.run>
PR: #92
@shadaj
shadaj force-pushed the sandbox-eb0ff46e-96e1-4d2d-8c0b-9c683fa4d1b9 branch from 723ade3 to 794035c Compare August 5, 2026 23:01
shadaj added a commit that referenced this pull request Aug 10, 2026
…on + lambda onto it

Introduce `infinity_agent_core::system`, a builder-based, object-oriented API for
running agents, and rebuild both production embeddings on top of it. The docs for
`infinity-runtime` are rewritten around the new API.

Core (`infinity_agent_core::system`):
- `AgentSystemBuilder`: two construction modes — `new(stores, model, sender)` builds a
  step-mode `AgentSystem` for serverless platforms; `new_local(stores, model)` builds a
  `LocalAgentSystem` with an internal in-process queue (`ChannelSender`).
- Step mode's whole public surface is `AgentSystem::step(inputs, observer, defer)`:
  the batch may span multiple threads (e.g. an SQS FIFO delivery with batch size > 1
  interleaving several message groups). `step` partitions by `group_id`, applies the
  deferral policy per thread, and joins the per-thread steps concurrently — each
  loads its thread's state from the stores, prepares inputs, runs at most one
  completion round, commits durably (history sync → observer commit barrier), and
  dispatches at most one asynchronous tool call. Returns each thread's
  `StepOutcome`; one thread's failure never aborts another mid-commit. `&mut self`
  serializes calls per system instance; the internal `Thread` type (with
  `filter_deferrable`/`step_no_defer` composition points used by the local driver)
  is deliberately not public and `AgentSystem` is not `Clone`, so two live in-memory
  views of the same thread cannot exist through the public API. Per-thread
  configuration is resolved lazily on first step so loading a thread never boots
  tool servers.
- `LocalAgentSystem::start` runs a full actor-system-style runtime: a router plus one
  driver task per active thread, with input batching, `<interrupt>` handling for user
  text during a completion, deferral of subscription events while a non-passive tool
  call is pending, auto-compaction above 75% of the context window, and race-free idle
  exit/respawn. `RunningSystem` exposes `sender()`, `send_user_text`, ack'd
  `subscribe`, `active_threads`, a `thread_exits` channel for per-conversation resource
  teardown, and `begin_shutdown` for process exit. The system itself runs for the
  process lifetime.
- `ThreadHandle`: `LocalAgentSystem::start_with_handles()` runs the system with a
  built-in channel-based observer (`HandleObserver`) whose subscriber registry is
  shared across driver respawns; `RunningSystem::thread_handle(thread_id)` then
  attaches to a thread (creating its subscription even before the thread exists) and
  returns a handle with `replay()` for the initial snapshot, an unbounded `events`
  queue of `AgentEvent`s (exactly-once relative to the replay), and
  `send_user_text`/`send` for input. This is the only per-thread interface of a local
  system.
- `ThreadObserver`: synchronous `on_event(AgentEvent)` fan-out (exactly-once relative
  to `on_subscribe` replay snapshots) plus awaited durability hooks
  (`on_user_choice_required`/`_dismissed`, `on_commit` before tool dispatch).
  `EventCollector` buffers `(thread_id, event)` pairs.
- `ModelSource` (per-round model resolution; enables mid-session model switching) with
  `StaticModel`; `ThreadConfigSource` (per-thread tools/prompt/notifier; enables
  per-session RAP servers and toolsets) with `StaticThreadConfig`; `DeferQueue` with
  `InMemoryDeferQueue`/`NoDeferral`.
- `AgentEvent`/`ReplaySnapshot`/`UserChoice` display types; `Tool::is_passive()`;
  in-memory `ConversationStore`/`StateStore` implementations in
  `infinity_agent_core::stores`; tokio-backed sleep tools moved into the core
  (`with_tokio_sleep_tools`).
- The core API is platform-neutral: `input_queue_arn` is removed from `ToolContext`
  and the builder. Platform-specific configuration lives on the tools that need it
  (the Lambda sleep tools now carry the input queue ARN as a field).
- All 20 daemon agent-loop tests migrated into core `system/tests.rs` with
  byte-identical snapshots, plus new tests: 3 `ThreadHandle` tests (send/receive +
  late replay, survival across idle/respawn, dropped-handle pruning) and a
  multi-group step-mode batch test.

Daemon (`infinity-daemon`):
- One daemon-lifetime agent system replaces per-session agent loops. Sessions are root
  threads; a `thread_exits` watcher marks sessions idle and shuts down their RAP
  servers when no keep-alive client is attached.
- New `rap_servers.rs`: `ManagedRapServer`/`ManagedRapTool`/`SessionRapManager` — RAP
  servers boot lazily per session via `ThreadConfigSource` and reboot transparently
  after idle shutdown. Config-source info messages ("Using local config", etc.) are
  preserved at first resolve.
- `DaemonObserver` implements the observer hooks (usage persistence, pending user
  choices, live-attach replay including mid-stream thinking).
- `CatalogModelSource` resolves each thread's persisted model selection per round.
- Fix a pre-existing bug where the requesting client received `ModelSwitched` twice
  (once via the subscriber broadcast, once via the direct reply): `switch_model` now
  tracks whether the broadcast reached the requester (`same_channel`) and only sends
  directly when it did not. Verified by the `switch_model_mid_session` web e2e test.
- Dead parameters pruned: `send_input` loses its unused emit callback and takes a
  `user_driven: bool` instead of an unused `Option<Subscriber>`; obsolete
  `connection_keeps_alive` tracking removed from the client handler.
- The `chat-image-result` and `chat-diff-result` web golden screenshots are
  regenerated: the old goldens captured a layout artifact of the eager RAP-boot flow;
  the lazy flow renders the canonical transcript (verified against the DOM).
- Deleted: `session/thread_worker.rs`, `session/agent_loop.rs`, `sleep_tools.rs`,
  `InMemoryMessageSender`, `Session`, `spawn_session`, `AgentMessage`.

Lambda (`infinity-agent-lambda`): event handler rewritten on the new API. One system
per invocation with a `ThreadConfigSource` (`LambdaThreadConfig`) that resolves each
thread's RAP toolsets through the DynamoDB manifest cache and adds the platform sleep
tools — correct even when a FIFO batch spans several sessions (only `batchSize: 1` is
deployed today, but the handler no longer assumes it). One `AgentSystem::step` call
processes the whole batch; per-thread outputs are aggregated in a `BTreeMap` and sent
to the output queue with each thread's root metadata.

Docs (`docs/docs/infinity-runtime`): the single "Rust API" page is replaced by two
sections. "The Agent System API" (overview, building-a-system, running-locally,
step-mode, observers) documents the new high-level API — thread handles for local
systems, one batch-shaped `step` call for serverless — and the patterns both
embeddings use; "The Low-Level API" (overview, history-manager, completion-loop)
documents the platform traits and loop pieces underneath and when to use them.
Cross-references across overview/architecture/built-in-tools/deploying-on-lambda
updated; `cargo doc` is warning-free.

BREAKING CHANGE: `infinity-daemon` no longer exports `sleep_tools`, `AgentMessage`,
`thread_worker`, `agent_loop`, `Session`, or `InMemoryMessageSender`; `SessionManager`'s
API is reshaped around the single agent system (`switch_model` takes the requester's
sender and returns `Result<(), String>`; `send_input` takes `user_driven: bool`) and
`SharedSessionManager` is now `Rc<tokio::Mutex<...>>`. In `infinity-agent-core`,
builder tools are stored as `Rc<dyn Tool<M>>`, `Tool` gains a defaulted `is_passive`
method, `ToolContext` and `AgentSystemBuilder` lose `input_queue_arn`, `Thread` is no
longer public (use `AgentSystem::step` — now batch-shaped, returning per-thread
outcomes — or `ThreadHandle`), `AgentSystem` is not `Clone`, `EventCollector::take`
returns `(thread_id, event)` pairs, and daemon/lambda display paths now emit
`AgentEvent` instead of `DisplayEvent`.

Co-authored-by: Infinity 🤖 <infinity@hydro.run>
PR: #92
@shadaj
shadaj force-pushed the sandbox-eb0ff46e-96e1-4d2d-8c0b-9c683fa4d1b9 branch from 794035c to 608cb0f Compare August 10, 2026 21:29
shadaj added a commit that referenced this pull request Aug 10, 2026
…on + lambda onto it

Introduce `infinity_agent_core::system`, a builder-based, object-oriented API for
running agents, and rebuild both production embeddings on top of it. The docs for
`infinity-runtime` are rewritten around the new API.

Core (`infinity_agent_core::system`):
- `AgentSystemBuilder`: two construction modes — `new(stores, model, sender)` builds a
  step-mode `AgentSystem` for serverless platforms; `new_local(stores, model)` builds a
  `LocalAgentSystem` with an internal in-process queue (`ChannelSender`).
- Step mode's whole public surface is `AgentSystem::step(inputs, observer, defer)`:
  the batch may span multiple threads (e.g. an SQS FIFO delivery with batch size > 1
  interleaving several message groups). `step` partitions by `group_id`, applies the
  deferral policy per thread, and joins the per-thread steps concurrently — each
  loads its thread's state from the stores, prepares inputs, runs at most one
  completion round, commits durably (history sync → observer commit barrier), and
  dispatches at most one asynchronous tool call. Returns each thread's
  `StepOutcome`; one thread's failure never aborts another mid-commit. `&mut self`
  serializes calls per system instance; the internal `Thread` type (with
  `filter_deferrable`/`step_no_defer` composition points used by the local driver)
  is deliberately not public and `AgentSystem` is not `Clone`, so two live in-memory
  views of the same thread cannot exist through the public API. Per-thread
  configuration is resolved lazily on first step so loading a thread never boots
  tool servers.
- `LocalAgentSystem::start` runs a full actor-system-style runtime: a router plus one
  driver task per active thread, with input batching, `<interrupt>` handling for user
  text during a completion, deferral of subscription events while a non-passive tool
  call is pending, auto-compaction above 75% of the context window, and race-free idle
  exit/respawn. `RunningSystem` exposes `sender()`, `send_user_text`, ack'd
  `subscribe`, `active_threads`, a `thread_exits` channel for per-conversation resource
  teardown, and `begin_shutdown` for process exit. The system itself runs for the
  process lifetime.
- `ThreadHandle`: `LocalAgentSystem::start_with_handles()` runs the system with a
  built-in channel-based observer (`HandleObserver`) whose subscriber registry is
  shared across driver respawns; `RunningSystem::thread_handle(thread_id)` then
  attaches to a thread (creating its subscription even before the thread exists) and
  returns a handle with `replay()` for the initial snapshot, an unbounded `events`
  queue of `AgentEvent`s (exactly-once relative to the replay), and
  `send_user_text`/`send` for input. This is the only per-thread interface of a local
  system.
- `ThreadObserver`: synchronous `on_event(AgentEvent)` fan-out (exactly-once relative
  to `on_subscribe` replay snapshots) plus awaited durability hooks
  (`on_user_choice_required`/`_dismissed`, `on_commit` before tool dispatch).
  `EventCollector` buffers `(thread_id, event)` pairs.
- `ModelSource` (per-round model resolution; enables mid-session model switching) with
  `StaticModel`; `ThreadConfigSource` (per-thread tools/prompt/notifier; enables
  per-session RAP servers and toolsets) with `StaticThreadConfig`; `DeferQueue` with
  `InMemoryDeferQueue`/`NoDeferral`.
- `AgentEvent`/`ReplaySnapshot`/`UserChoice` display types; `Tool::is_passive()`;
  in-memory `ConversationStore`/`StateStore` implementations in
  `infinity_agent_core::stores`; tokio-backed sleep tools moved into the core
  (`with_tokio_sleep_tools`).
- The core API is platform-neutral: `input_queue_arn` is removed from `ToolContext`
  and the builder. Platform-specific configuration lives on the tools that need it
  (the Lambda sleep tools now carry the input queue ARN as a field).
- All 20 daemon agent-loop tests migrated into core `system/tests.rs` with
  byte-identical snapshots, plus new tests: 3 `ThreadHandle` tests (send/receive +
  late replay, survival across idle/respawn, dropped-handle pruning) and a
  multi-group step-mode batch test.

Daemon (`infinity-daemon`):
- One daemon-lifetime agent system replaces per-session agent loops. Sessions are root
  threads; a `thread_exits` watcher marks sessions idle and shuts down their RAP
  servers when no keep-alive client is attached.
- New `rap_servers.rs`: `ManagedRapServer`/`ManagedRapTool`/`SessionRapManager` — RAP
  servers boot lazily per session via `ThreadConfigSource` and reboot transparently
  after idle shutdown. Config-source info messages ("Using local config", etc.) are
  preserved at first resolve.
- `DaemonObserver` implements the observer hooks (usage persistence, pending user
  choices, live-attach replay including mid-stream thinking).
- `CatalogModelSource` resolves each thread's persisted model selection per round.
- Fix a pre-existing bug where the requesting client received `ModelSwitched` twice
  (once via the subscriber broadcast, once via the direct reply): `switch_model` now
  tracks whether the broadcast reached the requester (`same_channel`) and only sends
  directly when it did not. Verified by the `switch_model_mid_session` web e2e test.
- Dead parameters pruned: `send_input` loses its unused emit callback and takes a
  `user_driven: bool` instead of an unused `Option<Subscriber>`; obsolete
  `connection_keeps_alive` tracking removed from the client handler.
- The `chat-image-result` and `chat-diff-result` web golden screenshots are
  regenerated: the old goldens captured a layout artifact of the eager RAP-boot flow;
  the lazy flow renders the canonical transcript (verified against the DOM).
- Deleted: `session/thread_worker.rs`, `session/agent_loop.rs`, `sleep_tools.rs`,
  `InMemoryMessageSender`, `Session`, `spawn_session`, `AgentMessage`.

Lambda (`infinity-agent-lambda`): event handler rewritten on the new API. One system
per invocation with a `ThreadConfigSource` (`LambdaThreadConfig`) that resolves each
thread's RAP toolsets through the DynamoDB manifest cache and adds the platform sleep
tools — correct even when a FIFO batch spans several sessions (only `batchSize: 1` is
deployed today, but the handler no longer assumes it). One `AgentSystem::step` call
processes the whole batch; per-thread outputs are aggregated in a `BTreeMap` and sent
to the output queue with each thread's root metadata.

Docs (`docs/docs/infinity-runtime`): the single "Rust API" page is replaced by two
sections. "The Agent System API" (overview, building-a-system, running-locally,
step-mode, observers) documents the new high-level API — thread handles for local
systems, one batch-shaped `step` call for serverless — and the patterns both
embeddings use; "The Low-Level API" (overview, history-manager, completion-loop)
documents the platform traits and loop pieces underneath and when to use them.
Cross-references across overview/architecture/built-in-tools/deploying-on-lambda
updated; `cargo doc` is warning-free.

BREAKING CHANGE: `infinity-daemon` no longer exports `sleep_tools`, `AgentMessage`,
`thread_worker`, `agent_loop`, `Session`, or `InMemoryMessageSender`; `SessionManager`'s
API is reshaped around the single agent system (`switch_model` takes the requester's
sender and returns `Result<(), String>`; `send_input` takes `user_driven: bool`) and
`SharedSessionManager` is now `Rc<tokio::Mutex<...>>`. In `infinity-agent-core`,
builder tools are stored as `Rc<dyn Tool<M>>`, `Tool` gains a defaulted `is_passive`
method, `ToolContext` and `AgentSystemBuilder` lose `input_queue_arn`, `Thread` is no
longer public (use `AgentSystem::step` — now batch-shaped, returning per-thread
outcomes — or `ThreadHandle`), `AgentSystem` is not `Clone`, `EventCollector::take`
returns `(thread_id, event)` pairs, and daemon/lambda display paths now emit
`AgentEvent` instead of `DisplayEvent`.

Co-authored-by: Infinity 🤖 <infinity@hydro.run>
PR: #92
@shadaj
shadaj force-pushed the sandbox-eb0ff46e-96e1-4d2d-8c0b-9c683fa4d1b9 branch from 608cb0f to fc4b88c Compare August 10, 2026 21:45
shadaj added a commit that referenced this pull request Aug 11, 2026
…on + lambda onto it

Introduce `infinity_agent_core::system`, a builder-based, object-oriented API for
running agents, and rebuild both production embeddings on top of it. The docs for
`infinity-runtime` are rewritten around the new API.

Core (`infinity_agent_core::system`):
- `AgentSystemBuilder`: two construction modes — `new(stores, model, sender)` builds a
  step-mode `AgentSystem` for serverless platforms; `new_local(stores, model)` builds a
  `LocalAgentSystem` with an internal in-process queue (`ChannelSender`).
- Step mode's whole public surface is `AgentSystem::step(inputs, observer, defer)`:
  the batch may span multiple threads (e.g. an SQS FIFO delivery with batch size > 1
  interleaving several message groups). `step` partitions by `group_id`, applies the
  deferral policy per thread, and joins the per-thread steps concurrently — each
  loads its thread's state from the stores, prepares inputs, runs at most one
  completion round, commits durably (history sync → observer commit barrier), and
  dispatches at most one asynchronous tool call. Returns each thread's
  `StepOutcome`; one thread's failure never aborts another mid-commit. `&mut self`
  serializes calls per system instance; the internal `Thread` type (with
  `filter_deferrable`/`step_no_defer` composition points used by the local driver)
  is deliberately not public and `AgentSystem` is not `Clone`, so two live in-memory
  views of the same thread cannot exist through the public API. Per-thread
  configuration is resolved lazily on first step so loading a thread never boots
  tool servers.
- `LocalAgentSystem::start` runs a full actor-system-style runtime: a router plus one
  driver task per active thread, with input batching, `<interrupt>` handling for user
  text during a completion, deferral of subscription events while a non-passive tool
  call is pending, auto-compaction above 75% of the context window, and race-free idle
  exit/respawn. `RunningSystem` exposes `sender()`, `send_user_text`, ack'd
  `subscribe`, `active_threads`, a `thread_exits` channel for per-conversation resource
  teardown, and `begin_shutdown` for process exit. The system itself runs for the
  process lifetime.
- `ThreadHandle`: `LocalAgentSystem::start_with_handles()` runs the system with a
  built-in channel-based observer (`HandleObserver`) whose subscriber registry is
  shared across driver respawns; `RunningSystem::thread_handle(thread_id)` then
  attaches to a thread (creating its subscription even before the thread exists) and
  returns a handle with `replay()` for the initial snapshot, an unbounded `events`
  queue of `AgentEvent`s (exactly-once relative to the replay), and
  `send_user_text`/`send` for input. This is the only per-thread interface of a local
  system.
- `ThreadObserver`: synchronous `on_event(AgentEvent)` fan-out (exactly-once relative
  to `on_subscribe` replay snapshots) plus awaited durability hooks
  (`on_user_choice_required`/`_dismissed`, `on_commit` before tool dispatch).
  `EventCollector` buffers `(thread_id, event)` pairs.
- `ModelSource` (per-round model resolution; enables mid-session model switching) with
  `StaticModel`; `ThreadConfigSource` (per-thread tools/prompt/notifier; enables
  per-session RAP servers and toolsets) with `StaticThreadConfig`; `DeferQueue` with
  `InMemoryDeferQueue`/`NoDeferral`.
- `AgentEvent`/`ReplaySnapshot`/`UserChoice` display types; `Tool::is_passive()`;
  in-memory `ConversationStore`/`StateStore` implementations in
  `infinity_agent_core::stores`; tokio-backed sleep tools moved into the core
  (`with_tokio_sleep_tools`).
- The core API is platform-neutral: `input_queue_arn` is removed from `ToolContext`
  and the builder. Platform-specific configuration lives on the tools that need it
  (the Lambda sleep tools now carry the input queue ARN as a field).
- All 20 daemon agent-loop tests migrated into core `system/tests.rs` with
  byte-identical snapshots, plus new tests: 3 `ThreadHandle` tests (send/receive +
  late replay, survival across idle/respawn, dropped-handle pruning) and a
  multi-group step-mode batch test.

Daemon (`infinity-daemon`):
- One daemon-lifetime agent system replaces per-session agent loops. Sessions are root
  threads; a `thread_exits` watcher marks sessions idle and shuts down their RAP
  servers when no keep-alive client is attached.
- New `rap_servers.rs`: `ManagedRapServer`/`ManagedRapTool`/`SessionRapManager` — RAP
  servers boot lazily per session via `ThreadConfigSource` and reboot transparently
  after idle shutdown. Config-source info messages ("Using local config", etc.) are
  preserved at first resolve.
- `DaemonObserver` implements the observer hooks (usage persistence, pending user
  choices, live-attach replay including mid-stream thinking).
- `CatalogModelSource` resolves each thread's persisted model selection per round.
- Fix a pre-existing bug where the requesting client received `ModelSwitched` twice
  (once via the subscriber broadcast, once via the direct reply): `switch_model` now
  tracks whether the broadcast reached the requester (`same_channel`) and only sends
  directly when it did not. Verified by the `switch_model_mid_session` web e2e test.
- Dead parameters pruned: `send_input` loses its unused emit callback and takes a
  `user_driven: bool` instead of an unused `Option<Subscriber>`; obsolete
  `connection_keeps_alive` tracking removed from the client handler.
- The `chat-image-result` and `chat-diff-result` web golden screenshots are
  regenerated: the old goldens captured a layout artifact of the eager RAP-boot flow;
  the lazy flow renders the canonical transcript (verified against the DOM).
- Deleted: `session/thread_worker.rs`, `session/agent_loop.rs`, `sleep_tools.rs`,
  `InMemoryMessageSender`, `Session`, `spawn_session`, `AgentMessage`.

Lambda (`infinity-agent-lambda`): event handler rewritten on the new API. One system
per invocation with a `ThreadConfigSource` (`LambdaThreadConfig`) that resolves each
thread's RAP toolsets through the DynamoDB manifest cache and adds the platform sleep
tools — correct even when a FIFO batch spans several sessions (only `batchSize: 1` is
deployed today, but the handler no longer assumes it). One `AgentSystem::step` call
processes the whole batch; per-thread outputs are aggregated in a `BTreeMap` and sent
to the output queue with each thread's root metadata.

Docs (`docs/docs/infinity-runtime`): the single "Rust API" page is replaced by two
sections. "The Agent System API" (overview, building-a-system, running-locally,
step-mode, observers) documents the new high-level API — thread handles for local
systems, one batch-shaped `step` call for serverless — and the patterns both
embeddings use; "The Low-Level API" (overview, history-manager, completion-loop)
documents the platform traits and loop pieces underneath and when to use them.
Cross-references across overview/architecture/built-in-tools/deploying-on-lambda
updated; `cargo doc` is warning-free.

BREAKING CHANGE: `infinity-daemon` no longer exports `sleep_tools`, `AgentMessage`,
`thread_worker`, `agent_loop`, `Session`, or `InMemoryMessageSender`; `SessionManager`'s
API is reshaped around the single agent system (`switch_model` takes the requester's
sender and returns `Result<(), String>`; `send_input` takes `user_driven: bool`) and
`SharedSessionManager` is now `Rc<tokio::Mutex<...>>`. In `infinity-agent-core`,
builder tools are stored as `Rc<dyn Tool<M>>`, `Tool` gains a defaulted `is_passive`
method, `ToolContext` and `AgentSystemBuilder` lose `input_queue_arn`, `Thread` is no
longer public (use `AgentSystem::step` — now batch-shaped, returning per-thread
outcomes — or `ThreadHandle`), `AgentSystem` is not `Clone`, `EventCollector::take`
returns `(thread_id, event)` pairs, and daemon/lambda display paths now emit
`AgentEvent` instead of `DisplayEvent`.

Co-authored-by: Infinity 🤖 <infinity@hydro.run>
PR: #92
@shadaj
shadaj force-pushed the sandbox-eb0ff46e-96e1-4d2d-8c0b-9c683fa4d1b9 branch from fc4b88c to 6840c02 Compare August 11, 2026 00:12
shadaj added a commit that referenced this pull request Aug 11, 2026
…on + lambda onto it

Introduce `infinity_agent_core::system`, a builder-based, object-oriented API for
running agents, rebuild both production embeddings on top of it, unify the parallel
implementations that had grown around the old architecture, and rewrite the
`infinity-runtime` docs around the new API.

Core (`infinity_agent_core::system`):
- `AgentSystemBuilder`: `new(stores, model, sender)` builds a step-mode `AgentSystem`
  for serverless platforms; `new_local(stores, model)` builds a `LocalAgentSystem`
  with an internal in-process queue (`ChannelSender`).
- Step mode's public surface is `AgentSystem::step(inputs, observer, defer)`: the
  batch may span multiple threads (SQS FIFO batches can interleave message groups);
  `step` partitions by `group_id`, applies the deferral policy per thread, joins the
  per-thread slices concurrently (prepare → completion → history sync → observer
  commit barrier → tool dispatch), and returns each thread's `StepOutcome`. `&mut
  self` serializes calls per system; the internal `Thread` type is not public and
  `AgentSystem` is not `Clone`, so two live in-memory views of one thread cannot
  exist through the public API. Per-thread configuration resolves lazily on first
  step so loading a thread never boots tool servers.
- `LocalAgentSystem::start` runs an actor-system-style runtime: a router plus one
  driver per active thread, with input batching, `<interrupt>` handling, deferral of
  synthetic events while a non-passive tool call is pending, auto-compaction above
  75% of the context window, and race-free idle exit/respawn. `RunningSystem`
  exposes senders, ack'd `subscribe`, `active_threads`, a `thread_exits` channel for
  per-conversation resource teardown, and `begin_shutdown` for process exit.
- `ThreadHandle` (`start_with_handles()` + `thread_handle(id)`): attach to a thread
  (even before it exists), get `replay()` plus an exactly-once `events` stream, and
  send input; subscriptions survive driver respawns via a shared registry.
- `ThreadObserver`: synchronous `on_event(AgentEvent)` fan-out (exactly-once relative
  to `on_subscribe` replays) plus awaited durability hooks (`on_user_choice_required`
  /`_dismissed`, `on_commit` before tool dispatch). `EventCollector` buffers
  `(thread_id, event)` pairs.
- `ModelSource` (per-round resolution; enables mid-session model switching),
  `ThreadConfigSource` (per-thread tools/prompt/notifier; enables per-session RAP
  servers and toolsets), `DeferQueue` (`InMemoryDeferQueue`/`NoDeferral`),
  `Tool::is_passive()`, tokio sleep tools (`with_tokio_sleep_tools`).
- **`batch_processor` deleted**: `process_batch` had no production callers and its
  semantics violated the documented durability barrier (swallowed sync errors, then
  dispatched; emitted ResponseDone before sync). The documented low-level API is now
  `HistoryManager` + `prepare_input`/`run_completion`/`execute_action`;
  `execute_action_with_error_result` (the #88 error-fallback) lives in
  `event_processor`. `DisplayEvent` moved out of core: `AgentEvent` is core's only
  event vocabulary; the CLI keeps a local, non-generic `DisplayEvent` as its
  terminal-rendering enum. All unique regression coverage ported.
- **Shared slice internals**: `event_processor::input_echo` is the single
  computation of accepted-input echoes (was duplicated between the system path and
  the old batch path); `SyntheticKind::is_compaction_complete()`;
  `InputMessage::user_text()`; driver's in-flight step modeled as
  `InFlightStep { fut, cancel_tx }` with a consuming `cancel()`.
- **`rap_callback` module**: the RAP callback → `InputMessage` conversion
  (multimodal content, display segments, tagged synthetics incl. subscription
  final/associative flags, user_choice, oauth) now lives in core with 11 unit
  tests; the daemon delegates to it.
- In-memory `ConversationStore`/`StateStore` in `infinity_agent_core::stores` with a
  serializable snapshot/restore API; the daemon's stores are now thin wrappers
  (extras + JSON persistence) so the subtle ancestor/compaction/dedup semantics
  exist in exactly one place. `spawn_thread_with_id` supports deterministic IDs.
- Platform-neutral core: `input_queue_arn` removed from `ToolContext`/builder
  (Lambda sleep tools carry it as a field).
- All 20 daemon agent-loop tests migrated into core `system/tests.rs` with
  byte-identical snapshots, plus new coverage: `ThreadHandle` streaming across
  tool-call rounds (CompletionFinished is per round; consumers keep pulling while a
  call is pending), multi-group step batches, failed-dispatch fallback, OAuth
  surfacing, prepare-level user-choice, handle respawn survival and pruning.

Daemon (`infinity-daemon`):
- One daemon-lifetime agent system replaces per-session agent loops; sessions are
  root threads; a `thread_exits` watcher (via the single
  `session_has_active_threads` predicate) marks sessions idle and shuts down their
  RAP servers when no keep-alive client is attached.
- `rap_servers.rs`: `ManagedRapServer` boots lazily per session via
  `ThreadConfigSource` and reboots transparently after idle shutdown; `Up` state
  caches the manifest (fetch failure tears the boot down — no half-up state); MCP
  proxy tasks are owned (stdio children `kill_on_drop`) but proxies stay up across
  idles since MCP servers may be stateful; migration flows ride the same
  `collect_server_specs` + `ensure_up` path (`MigrationServer`;
  `boot_rap_servers`/`BootedRapServers`/`rap_tools.rs` deleted); RAP config
  reading/merging unified in `config::load_merged_rap_config`.
- `DaemonObserver` implements the observer hooks; subscriber broadcasting unified in
  `observer::broadcast_pruning`/`broadcast_to_thread` (fixing `handle_view_update`
  never pruning dead subscribers); re-sent Connects replace rather than stack
  subscriptions; replay rendering now matches live rendering (strips `<interrupt>`
  prefixes, uses `rap_protocol::build_display_segments`).
- `CatalogModelSource` resolves each thread's persisted model per round. Fix the
  pre-existing double `ModelSwitched` delivery (`switch_model` tracks whether the
  broadcast reached the requester via `same_channel`).
- `send_input` takes `user_driven: bool`; `SessionManager` methods that only touch
  interior-mutable state take `&self`.
- Web goldens `chat-image-result`/`chat-diff-result` regenerated (old goldens
  captured an eager-boot layout artifact).
- Deleted: `session/thread_worker.rs`, `session/agent_loop.rs`, `sleep_tools.rs`,
  `InMemoryMessageSender`, `Session`, `spawn_session`, `AgentMessage`.

Lambda (`infinity-agent-lambda`):
- Event handler rewritten on the new API: one system per invocation with a
  `ThreadConfigSource` resolving each thread's RAP toolsets (DynamoDB manifest
  cache) plus platform sleep tools; one batch-shaped `step`; per-thread outputs
  aggregated in a `BTreeMap`. Sleep tools share a `WakeupScheduler` (SQS delay /
  EventBridge dispatch deduplicated).
- **New `rap-receiver` binary replaces `agent/lib/infinity-agents/rap-receiver/
  index.mjs`** (deleted): same Function-URL contract, but full parity with the
  daemon's conversion via `infinity_agent_core::rap_callback` — user_choice
  callbacks accepted (JS returned 400), multimodal content and `display_as`
  preserved, subscription `final` flag and tagged synthetics honored, and stable
  dedup IDs for results/oauth/choices (per-delivery IDs only for subscription
  events, which share a tool_call_id). CDK switches the receiver to a
  cargo-lambda `RustFunction`. Deploy note: the Function URL is recreated, so
  persisted callback URLs from long-lived subscriptions must be re-subscribed.

Docs (`docs/docs/infinity-runtime`): the single "Rust API" page is replaced by two
sections rewritten in a usage-oriented style (example-first walkthroughs rather than
API inventories): "The Agent System API" (overview, building-a-system,
running-locally, step-mode, observers) and "The Low-Level API" (overview,
history-manager, completion-loop). Cross-references updated repo-wide; `cargo doc`
is warning-free.

BREAKING CHANGE: `infinity-agent-core` removes `batch_processor` (`process_batch`,
`process_input_item`, `DisplayEvent`); `Thread` is no longer public (use
`AgentSystem::step` or `ThreadHandle`); `AgentSystem` is not `Clone`;
`EventCollector::take` returns `(thread_id, event)` pairs; builder tools are stored
as `Rc<dyn Tool<M>>`; `Tool` gains defaulted `is_passive`; `ToolContext`/builder
lose `input_queue_arn`. `infinity-daemon` no longer exports `sleep_tools`,
`AgentMessage`, `thread_worker`, `agent_loop`, `Session`, `InMemoryMessageSender`,
`boot_rap_servers`, or `rap_tools`; `SessionManager::switch_model` takes the
requester's sender and returns `Result<(), String>`; `send_input` takes
`user_driven: bool`; `SharedSessionManager` is `Rc<tokio::Mutex<...>>`. The CLI's
`DisplayEvent` now lives in `infinity_agent_cli::display`.

Co-authored-by: Infinity 🤖 <infinity@hydro.run>
PR: #92
@shadaj
shadaj force-pushed the sandbox-eb0ff46e-96e1-4d2d-8c0b-9c683fa4d1b9 branch from 6840c02 to ccb90b9 Compare August 11, 2026 23:08
shadaj added a commit that referenced this pull request Aug 11, 2026
…on + lambda onto it

Introduce `infinity_agent_core::system`, a builder-based, object-oriented API for
running agents, rebuild both production embeddings on top of it, unify the parallel
implementations that had grown around the old architecture, and rewrite the
`infinity-runtime` docs around the new API.

Core (`infinity_agent_core::system`):
- `AgentSystemBuilder`: `new(stores, model, sender)` builds a step-mode `AgentSystem`
  for serverless platforms; `new_local(stores, model)` builds a `LocalAgentSystem`
  with an internal in-process queue (`ChannelSender`).
- Step mode's public surface is `AgentSystem::step(inputs, observer, defer)`: the
  batch may span multiple threads (SQS FIFO batches can interleave message groups);
  `step` partitions by `group_id`, applies the deferral policy per thread, joins the
  per-thread slices concurrently (prepare → completion → history sync → observer
  commit barrier → tool dispatch), and returns each thread's `StepOutcome`. `&mut
  self` serializes calls per system; the internal `Thread` type is not public and
  `AgentSystem` is not `Clone`, so two live in-memory views of one thread cannot
  exist through the public API. Per-thread configuration resolves lazily on first
  step so loading a thread never boots tool servers.
- `LocalAgentSystem::start` runs an actor-system-style runtime: a router plus one
  driver per active thread, with input batching, `<interrupt>` handling, deferral of
  synthetic events while a non-passive tool call is pending, auto-compaction above
  75% of the context window, and race-free idle exit/respawn. `RunningSystem`
  exposes senders, ack'd `subscribe`, `active_threads`, a `thread_exits` channel for
  per-conversation resource teardown, and `begin_shutdown` for process exit.
- `ThreadHandle` (`start_with_handles()` + `thread_handle(id)`): attach to a thread
  (even before it exists), get `replay()` plus an exactly-once `events` stream, and
  send input; subscriptions survive driver respawns via a shared registry.
- `ThreadObserver`: synchronous `on_event(AgentEvent)` fan-out (exactly-once relative
  to `on_subscribe` replays) plus awaited durability hooks (`on_user_choice_required`
  /`_dismissed`, `on_commit` before tool dispatch). `EventCollector` buffers
  `(thread_id, event)` pairs.
- `ModelSource` (per-round resolution; enables mid-session model switching),
  `ThreadConfigSource` (per-thread tools/prompt/notifier; enables per-session RAP
  servers and toolsets), `DeferQueue` (`InMemoryDeferQueue`/`NoDeferral`),
  `Tool::is_passive()`, tokio sleep tools (`with_tokio_sleep_tools`).
- **`batch_processor` deleted**: `process_batch` had no production callers and its
  semantics violated the documented durability barrier (swallowed sync errors, then
  dispatched; emitted ResponseDone before sync). The documented low-level API is now
  `HistoryManager` + `prepare_input`/`run_completion`/`execute_action`;
  `execute_action_with_error_result` (the #88 error-fallback) lives in
  `event_processor`. `DisplayEvent` moved out of core: `AgentEvent` is core's only
  event vocabulary; the CLI keeps a local, non-generic `DisplayEvent` as its
  terminal-rendering enum. All unique regression coverage ported.
- **Shared slice internals**: `event_processor::input_echo` is the single
  computation of accepted-input echoes (was duplicated between the system path and
  the old batch path); `SyntheticKind::is_compaction_complete()`;
  `InputMessage::user_text()`; driver's in-flight step modeled as
  `InFlightStep { fut, cancel_tx }` with a consuming `cancel()`.
- **`rap_callback` module**: the RAP callback → `InputMessage` conversion
  (multimodal content, display segments, tagged synthetics incl. subscription
  final/associative flags, user_choice, oauth) now lives in core with 11 unit
  tests; the daemon delegates to it.
- In-memory `ConversationStore`/`StateStore` in `infinity_agent_core::stores` with a
  serializable snapshot/restore API; the daemon's stores are now thin wrappers
  (extras + JSON persistence) so the subtle ancestor/compaction/dedup semantics
  exist in exactly one place. `spawn_thread_with_id` supports deterministic IDs.
- Platform-neutral core: `input_queue_arn` removed from `ToolContext`/builder
  (Lambda sleep tools carry it as a field).
- All 20 daemon agent-loop tests migrated into core `system/tests.rs` with
  byte-identical snapshots, plus new coverage: `ThreadHandle` streaming across
  tool-call rounds (CompletionFinished is per round; consumers keep pulling while a
  call is pending), multi-group step batches, failed-dispatch fallback, OAuth
  surfacing, prepare-level user-choice, handle respawn survival and pruning.

Daemon (`infinity-daemon`):
- One daemon-lifetime agent system replaces per-session agent loops; sessions are
  root threads; a `thread_exits` watcher (via the single
  `session_has_active_threads` predicate) marks sessions idle and shuts down their
  RAP servers when no keep-alive client is attached.
- `rap_servers.rs`: `ManagedRapServer` boots lazily per session via
  `ThreadConfigSource` and reboots transparently after idle shutdown; `Up` state
  caches the manifest (fetch failure tears the boot down — no half-up state); MCP
  proxy tasks are owned (stdio children `kill_on_drop`) but proxies stay up across
  idles since MCP servers may be stateful; migration flows ride the same
  `collect_server_specs` + `ensure_up` path (`MigrationServer`;
  `boot_rap_servers`/`BootedRapServers`/`rap_tools.rs` deleted); RAP config
  reading/merging unified in `config::load_merged_rap_config`.
- `DaemonObserver` implements the observer hooks; subscriber broadcasting unified in
  `observer::broadcast_pruning`/`broadcast_to_thread` (fixing `handle_view_update`
  never pruning dead subscribers); re-sent Connects replace rather than stack
  subscriptions; replay rendering now matches live rendering (strips `<interrupt>`
  prefixes, uses `rap_protocol::build_display_segments`).
- `CatalogModelSource` resolves each thread's persisted model per round. Fix the
  pre-existing double `ModelSwitched` delivery (`switch_model` tracks whether the
  broadcast reached the requester via `same_channel`).
- `send_input` takes `user_driven: bool`; `SessionManager` methods that only touch
  interior-mutable state take `&self`.
- Web goldens `chat-image-result`/`chat-diff-result` regenerated (old goldens
  captured an eager-boot layout artifact).
- Deleted: `session/thread_worker.rs`, `session/agent_loop.rs`, `sleep_tools.rs`,
  `InMemoryMessageSender`, `Session`, `spawn_session`, `AgentMessage`.

Lambda (`infinity-agent-lambda`):
- Event handler rewritten on the new API: one system per invocation with a
  `ThreadConfigSource` resolving each thread's RAP toolsets (DynamoDB manifest
  cache) plus platform sleep tools; one batch-shaped `step`; per-thread outputs
  aggregated in a `BTreeMap`. Sleep tools share a `WakeupScheduler` (SQS delay /
  EventBridge dispatch deduplicated).
- **New `rap-receiver` binary replaces `agent/lib/infinity-agents/rap-receiver/
  index.mjs`** (deleted): same Function-URL contract, but full parity with the
  daemon's conversion via `infinity_agent_core::rap_callback` — user_choice
  callbacks accepted (JS returned 400), multimodal content and `display_as`
  preserved, subscription `final` flag and tagged synthetics honored, and stable
  dedup IDs for results/oauth/choices (per-delivery IDs only for subscription
  events, which share a tool_call_id). CDK switches the receiver to a
  cargo-lambda `RustFunction`. Deploy note: the Function URL is recreated, so
  persisted callback URLs from long-lived subscriptions must be re-subscribed.

Docs (`docs/docs/infinity-runtime`): the single "Rust API" page is replaced by two
sections rewritten in a usage-oriented style (example-first walkthroughs rather than
API inventories): "The Agent System API" (overview, building-a-system,
running-locally, step-mode, observers) and "The Low-Level API" (overview,
history-manager, completion-loop). Cross-references updated repo-wide; `cargo doc`
is warning-free.

BREAKING CHANGE: `infinity-agent-core` removes `batch_processor` (`process_batch`,
`process_input_item`, `DisplayEvent`); `Thread` is no longer public (use
`AgentSystem::step` or `ThreadHandle`); `AgentSystem` is not `Clone`;
`EventCollector::take` returns `(thread_id, event)` pairs; builder tools are stored
as `Rc<dyn Tool<M>>`; `Tool` gains defaulted `is_passive`; `ToolContext`/builder
lose `input_queue_arn`. `infinity-daemon` no longer exports `sleep_tools`,
`AgentMessage`, `thread_worker`, `agent_loop`, `Session`, `InMemoryMessageSender`,
`boot_rap_servers`, or `rap_tools`; `SessionManager::switch_model` takes the
requester's sender and returns `Result<(), String>`; `send_input` takes
`user_driven: bool`; `SharedSessionManager` is `Rc<tokio::Mutex<...>>`. The CLI's
`DisplayEvent` now lives in `infinity_agent_cli::display`.

Co-authored-by: Infinity 🤖 <infinity@hydro.run>
PR: #92
@shadaj
shadaj force-pushed the sandbox-eb0ff46e-96e1-4d2d-8c0b-9c683fa4d1b9 branch from ccb90b9 to ec1b0d4 Compare August 11, 2026 23:33
shadaj added a commit that referenced this pull request Aug 12, 2026
…on + lambda onto it

Introduce `infinity_agent_core::system`, a builder-based, object-oriented API for
running agents, rebuild both production embeddings on top of it, unify the parallel
implementations that had grown around the old architecture, and rewrite the
`infinity-runtime` docs around the new API.

Core (`infinity_agent_core::system`):
- `AgentSystemBuilder`: `new(stores, model, sender)` builds a step-mode `AgentSystem`
  for serverless platforms; `new_local(stores, model)` builds a `LocalAgentSystem`
  with an internal in-process queue (`ChannelSender`).
- Step mode's public surface is `AgentSystem::step(inputs, observer, defer)`: the
  batch may span multiple threads (SQS FIFO batches can interleave message groups);
  `step` partitions by `group_id`, applies the deferral policy per thread, joins the
  per-thread slices concurrently (prepare → completion → history sync → observer
  commit barrier → tool dispatch), and returns each thread's `StepOutcome`. `&mut
  self` serializes calls per system; the internal `Thread` type is not public and
  `AgentSystem` is not `Clone`, so two live in-memory views of one thread cannot
  exist through the public API. Per-thread configuration resolves lazily on first
  step so loading a thread never boots tool servers.
- `LocalAgentSystem` is mode-typed (`Handles` by default, `Launcher` after
  `with_thread_launcher()`), with one `start()` per mode:
  - Handles mode: `start()` returns a `RunningSystem` running an actor-system-style
    runtime (router + one driver per active thread, input batching, `<interrupt>`
    handling, deferral while a non-passive tool call is pending, auto-compaction
    above 75% of the context window, race-free idle exit/respawn) with ack'd
    `subscribe`, a `thread_exits` channel, and `thread_handle(id)` attaching to any
    thread. `start_with_observer(factory)` swaps in a custom `ThreadObserver`.
  - Launcher mode: `start()` returns a `LaunchingSystem`. `thread_builder()`
    configures and launches new threads (generated IDs) with their own tools and
    prompt, unioned onto the system-wide configuration (static or
    `ThreadConfigSource`) via an internal `UnionConfigSource`; `thread_handle(id)`
    re-attaches to existing threads only (launched in-process or with history).
    Launch configurations are process-lifetime (not persisted).
- `ThreadHandle`: `replay()` plus an exactly-once `events` stream and input sending;
  subscriptions survive driver respawns via a shared registry.
- `ThreadObserver`: synchronous `on_event(AgentEvent)` fan-out (exactly-once relative
  to `on_subscribe` replays) plus awaited durability hooks (`on_user_choice_required`
  /`_dismissed`, `on_commit` before tool dispatch). `EventCollector` buffers
  `(thread_id, event)` pairs.
- `ModelSource` (per-round resolution; enables mid-session model switching),
  `ThreadConfigSource` (per-thread tools/prompt/notifier; enables per-session RAP
  servers and toolsets), `DeferQueue` (`InMemoryDeferQueue`/`NoDeferral`),
  `Tool::is_passive()`, tokio sleep tools (`with_tokio_sleep_tools`).
- `batch_processor` deleted: `process_batch` had no production callers and its
  semantics violated the documented durability barrier (swallowed sync errors, then
  dispatched; emitted ResponseDone before sync). The documented low-level API is now
  `HistoryManager` + `prepare_input`/`run_completion`/`execute_action`;
  `execute_action_with_error_result` (the #88 error-fallback) lives in
  `event_processor`. `DisplayEvent` moved out of core: `AgentEvent` is core's only
  event vocabulary; the CLI keeps a local, non-generic `DisplayEvent` as its
  terminal-rendering enum. All unique regression coverage ported.
- Shared slice internals: `event_processor::input_echo` is the single computation of
  accepted-input echoes; `SyntheticKind::is_compaction_complete()`;
  `InputMessage::user_text()`; driver's in-flight step modeled as
  `InFlightStep { fut, cancel_tx }` with a consuming `cancel()`.
- `rap_callback` module: the RAP callback → `InputMessage` conversion (multimodal
  content, display segments, tagged synthetics incl. subscription final/associative
  flags, user_choice, oauth) lives in core with 11 unit tests; the daemon delegates.
- In-memory `ConversationStore`/`StateStore` in `infinity_agent_core::stores` with a
  serializable snapshot/restore API; the daemon's stores are thin wrappers (extras +
  JSON persistence) so the ancestor/compaction/dedup semantics exist in exactly one
  place. `spawn_thread_with_id` supports deterministic IDs.
- Platform-neutral core: `input_queue_arn` removed from `ToolContext`/builder.
- All 20 daemon agent-loop tests migrated into core `system/tests.rs` with
  byte-identical snapshots, plus new coverage: launcher tool/prompt unioning and
  existing-only attachment, `ThreadHandle` streaming across tool-call rounds,
  multi-group step batches, failed-dispatch fallback, OAuth surfacing, prepare-level
  user-choice, handle respawn survival and pruning.

Daemon (`infinity-daemon`):
- One daemon-lifetime agent system replaces per-session agent loops; sessions are
  root threads; a `thread_exits` watcher marks sessions idle and shuts down their
  RAP servers when no keep-alive client is attached.
- `rap_servers.rs`: `ManagedRapServer` boots lazily per session via
  `ThreadConfigSource` and reboots transparently after idle shutdown; `Up` caches
  the manifest (fetch failure tears the boot down); MCP proxy tasks are owned
  (stdio children `kill_on_drop`) but proxies stay up across idles since MCP servers
  may be stateful; migration flows ride the same path (`MigrationServer`;
  `boot_rap_servers`/`rap_tools.rs` deleted); config merging unified in
  `config::load_merged_rap_config`.
- `DaemonObserver` implements the observer hooks; broadcasting unified in
  `observer::broadcast_pruning`/`broadcast_to_thread` (fixing `handle_view_update`
  never pruning dead subscribers); re-sent Connects replace rather than stack
  subscriptions; replay rendering matches live rendering.
- `CatalogModelSource` resolves each thread's persisted model per round; fixed the
  pre-existing double `ModelSwitched` delivery.
- `send_input` takes `user_driven: bool`; interior-mutability methods take `&self`.
- Web goldens `chat-image-result`/`chat-diff-result` regenerated (old goldens
  captured an eager-boot layout artifact).
- Deleted: `session/thread_worker.rs`, `session/agent_loop.rs`, `sleep_tools.rs`,
  `InMemoryMessageSender`, `Session`, `spawn_session`, `AgentMessage`.

Lambda (`infinity-agent-lambda`):
- Event handler rewritten on the new API: one system per invocation with a
  `ThreadConfigSource` resolving each thread's RAP toolsets (DynamoDB manifest
  cache) plus platform sleep tools (shared `WakeupScheduler` backend); one
  batch-shaped `step`; per-thread outputs aggregated in a `BTreeMap`.
- New `rap-receiver` binary replaces the drifted JS receiver (deleted): same
  Function-URL contract, full parity with the daemon's conversion via
  `infinity_agent_core::rap_callback` (user_choice accepted, multimodal and
  `display_as` preserved, tagged synthetics honored, stable dedup IDs where the
  wire has identity). CDK switches to a cargo-lambda `RustFunction`; the Function
  URL is recreated on deploy, so persisted callback URLs must be re-subscribed.

Docs (`docs/docs/infinity-runtime`): the single "Rust API" page is replaced by two
sections, written in the Hydro docs register (definitional openings, bolded key
terms, cause-and-effect guarantees, code-first examples, admonitions for caveats):
"The Agent System API" (overview, building-a-system, running-locally, step-mode,
observers, including launcher mode) and "The Low-Level API" (overview,
history-manager, completion-loop). Cross-references updated repo-wide; `cargo doc`
is warning-free.

BREAKING CHANGE: `infinity-agent-core` removes `batch_processor` (`process_batch`,
`process_input_item`, `DisplayEvent`); `Thread` is no longer public (use
`AgentSystem::step` or `ThreadHandle`); `AgentSystem` is not `Clone`;
`LocalAgentSystem::start_with_handles` is now `start()` and custom observers use
`start_with_observer` (`LocalAgentSystem` gained a mode type parameter, default
`Handles`); `EventCollector::take` returns `(thread_id, event)` pairs; builder tools
are stored as `Rc<dyn Tool<M>>`; `Tool` gains defaulted `is_passive`;
`ToolContext`/builder lose `input_queue_arn`. `infinity-daemon` no longer exports
`sleep_tools`, `AgentMessage`, `thread_worker`, `agent_loop`, `Session`,
`InMemoryMessageSender`, `boot_rap_servers`, or `rap_tools`;
`SessionManager::switch_model` takes the requester's sender and returns
`Result<(), String>`; `send_input` takes `user_driven: bool`;
`SharedSessionManager` is `Rc<tokio::Mutex<...>>`. The CLI's `DisplayEvent` lives in
`infinity_agent_cli::display`.

Co-authored-by: Infinity 🤖 <infinity@hydro.run>
PR: #92
@shadaj
shadaj force-pushed the sandbox-eb0ff46e-96e1-4d2d-8c0b-9c683fa4d1b9 branch from ec1b0d4 to 399a398 Compare August 12, 2026 00:01
shadaj added a commit that referenced this pull request Aug 12, 2026
…on + lambda onto it

Introduce `infinity_agent_core::system`, a builder-based, object-oriented API for
running agents, rebuild both production embeddings on top of it, unify the parallel
implementations that had grown around the old architecture, and rewrite the
`infinity-runtime` docs around the new API.

Core (`infinity_agent_core::system`):
- `AgentSystemBuilder`: `new(stores, model, sender)` builds a step-mode `AgentSystem`
  for serverless platforms; `new_local(stores, model)` builds a `LocalAgentSystem`
  with an internal in-process queue (`ChannelSender`).
- Step mode's public surface is `AgentSystem::step(inputs, observer, defer)`: the
  batch may span multiple threads (SQS FIFO batches can interleave message groups);
  `step` partitions by `group_id`, applies the deferral policy per thread, joins the
  per-thread slices concurrently (prepare → completion → history sync → observer
  commit barrier → tool dispatch), and returns each thread's `StepOutcome`. `&mut
  self` serializes calls per system; the internal `Thread` type is not public and
  `AgentSystem` is not `Clone`, so two live in-memory views of one thread cannot
  exist through the public API. Per-thread configuration resolves lazily on first
  step so loading a thread never boots tool servers.
- `LocalAgentSystem` is mode-typed (`Handles` by default, `Launcher` after
  `with_thread_launcher()`), with one `start()` per mode:
  - Handles mode: `start()` returns a `RunningSystem` running an actor-system-style
    runtime (router + one driver per active thread, input batching, `<interrupt>`
    handling, deferral while a non-passive tool call is pending, auto-compaction
    above 75% of the context window, race-free idle exit/respawn) with ack'd
    `subscribe`, a `thread_exits` channel, and `thread_handle(id)` attaching to any
    thread. `start_with_observer(factory)` swaps in a custom `ThreadObserver`.
  - Launcher mode: `start()` returns a `LaunchingSystem`. `thread_builder()`
    configures and launches new threads (generated IDs) with their own tools and
    prompt, unioned onto the system-wide configuration (static or
    `ThreadConfigSource`) via an internal `UnionConfigSource`; `thread_handle(id)`
    re-attaches to existing threads only (launched in-process or with history).
    Launch configurations are process-lifetime (not persisted).
- `ThreadHandle`: `replay()` plus an exactly-once `events` stream and input sending;
  subscriptions survive driver respawns via a shared registry.
- `ThreadObserver`: synchronous `on_event(AgentEvent)` fan-out (exactly-once relative
  to `on_subscribe` replays) plus awaited durability hooks (`on_user_choice_required`
  /`_dismissed`, `on_commit` before tool dispatch). `EventCollector` buffers
  `(thread_id, event)` pairs.
- `ModelSource` (per-round resolution; enables mid-session model switching),
  `ThreadConfigSource` (per-thread tools/prompt/notifier; enables per-session RAP
  servers and toolsets), `DeferQueue` (`InMemoryDeferQueue`/`NoDeferral`),
  `Tool::is_passive()`, tokio sleep tools (`with_tokio_sleep_tools`).
- `batch_processor` deleted: `process_batch` had no production callers and its
  semantics violated the documented durability barrier (swallowed sync errors, then
  dispatched; emitted ResponseDone before sync). The documented low-level API is now
  `HistoryManager` + `prepare_input`/`run_completion`/`execute_action`;
  `execute_action_with_error_result` (the #88 error-fallback) lives in
  `event_processor`. `DisplayEvent` moved out of core: `AgentEvent` is core's only
  event vocabulary; the CLI keeps a local, non-generic `DisplayEvent` as its
  terminal-rendering enum. All unique regression coverage ported.
- Shared slice internals: `event_processor::input_echo` is the single computation of
  accepted-input echoes; `SyntheticKind::is_compaction_complete()`;
  `InputMessage::user_text()`; driver's in-flight step modeled as
  `InFlightStep { fut, cancel_tx }` with a consuming `cancel()`.
- `rap_callback` module: the RAP callback → `InputMessage` conversion (multimodal
  content, display segments, tagged synthetics incl. subscription final/associative
  flags, user_choice, oauth) lives in core with 11 unit tests; the daemon delegates.
- In-memory `ConversationStore`/`StateStore` in `infinity_agent_core::stores` with a
  serializable snapshot/restore API; the daemon's stores are thin wrappers (extras +
  JSON persistence) so the ancestor/compaction/dedup semantics exist in exactly one
  place. `spawn_thread_with_id` supports deterministic IDs.
- Platform-neutral core: `input_queue_arn` removed from `ToolContext`/builder.
- All 20 daemon agent-loop tests migrated into core `system/tests.rs` with
  byte-identical snapshots, plus new coverage: launcher tool/prompt unioning and
  existing-only attachment, `ThreadHandle` streaming across tool-call rounds,
  multi-group step batches, failed-dispatch fallback, OAuth surfacing, prepare-level
  user-choice, handle respawn survival and pruning.

Daemon (`infinity-daemon`):
- One daemon-lifetime agent system replaces per-session agent loops; sessions are
  root threads; a `thread_exits` watcher marks sessions idle and shuts down their
  RAP servers when no keep-alive client is attached.
- `rap_servers.rs`: `ManagedRapServer` boots lazily per session via
  `ThreadConfigSource` and reboots transparently after idle shutdown; `Up` caches
  the manifest (fetch failure tears the boot down); MCP proxy tasks are owned
  (stdio children `kill_on_drop`) but proxies stay up across idles since MCP servers
  may be stateful; migration flows ride the same path (`MigrationServer`;
  `boot_rap_servers`/`rap_tools.rs` deleted); config merging unified in
  `config::load_merged_rap_config`.
- `DaemonObserver` implements the observer hooks; broadcasting unified in
  `observer::broadcast_pruning`/`broadcast_to_thread` (fixing `handle_view_update`
  never pruning dead subscribers); re-sent Connects replace rather than stack
  subscriptions; replay rendering matches live rendering.
- `CatalogModelSource` resolves each thread's persisted model per round; fixed the
  pre-existing double `ModelSwitched` delivery.
- `send_input` takes `user_driven: bool`; interior-mutability methods take `&self`.
- Web goldens `chat-image-result`/`chat-diff-result` regenerated (old goldens
  captured an eager-boot layout artifact).
- Deleted: `session/thread_worker.rs`, `session/agent_loop.rs`, `sleep_tools.rs`,
  `InMemoryMessageSender`, `Session`, `spawn_session`, `AgentMessage`.

Lambda (`infinity-agent-lambda`):
- Event handler rewritten on the new API: one system per invocation with a
  `ThreadConfigSource` resolving each thread's RAP toolsets (DynamoDB manifest
  cache) plus platform sleep tools (shared `WakeupScheduler` backend); one
  batch-shaped `step`; per-thread outputs aggregated in a `BTreeMap`.
- New `rap-receiver` binary replaces the drifted JS receiver (deleted): same
  Function-URL contract, full parity with the daemon's conversion via
  `infinity_agent_core::rap_callback` (user_choice accepted, multimodal and
  `display_as` preserved, tagged synthetics honored, stable dedup IDs where the
  wire has identity). CDK switches to a cargo-lambda `RustFunction`; the Function
  URL is recreated on deploy, so persisted callback URLs must be re-subscribed.

Docs (`docs/docs/infinity-runtime`): the single "Rust API" page is replaced by two
sections, written in the Hydro docs register (definitional openings, bolded key
terms, cause-and-effect guarantees, code-first examples, admonitions for caveats):
"The Agent System API" (overview, building-a-system, running-locally, step-mode,
observers, including launcher mode) and "The Low-Level API" (overview,
history-manager, completion-loop). Cross-references updated repo-wide; `cargo doc`
is warning-free.

BREAKING CHANGE: `infinity-agent-core` removes `batch_processor` (`process_batch`,
`process_input_item`, `DisplayEvent`); `Thread` is no longer public (use
`AgentSystem::step` or `ThreadHandle`); `AgentSystem` is not `Clone`;
`LocalAgentSystem::start_with_handles` is now `start()` and custom observers use
`start_with_observer` (`LocalAgentSystem` gained a mode type parameter, default
`Handles`); `EventCollector::take` returns `(thread_id, event)` pairs; builder tools
are stored as `Rc<dyn Tool<M>>`; `Tool` gains defaulted `is_passive`;
`ToolContext`/builder lose `input_queue_arn`. `infinity-daemon` no longer exports
`sleep_tools`, `AgentMessage`, `thread_worker`, `agent_loop`, `Session`,
`InMemoryMessageSender`, `boot_rap_servers`, or `rap_tools`;
`SessionManager::switch_model` takes the requester's sender and returns
`Result<(), String>`; `send_input` takes `user_driven: bool`;
`SharedSessionManager` is `Rc<tokio::Mutex<...>>`. The CLI's `DisplayEvent` lives in
`infinity_agent_cli::display`.

Co-authored-by: Infinity 🤖 <infinity@hydro.run>
PR: #92
@shadaj
shadaj force-pushed the sandbox-eb0ff46e-96e1-4d2d-8c0b-9c683fa4d1b9 branch from 399a398 to b822911 Compare August 12, 2026 00:02
shadaj added a commit that referenced this pull request Aug 12, 2026
…on + lambda onto it

Introduce `infinity_agent_core::system`, a builder-based, object-oriented API for
running agents, rebuild both production embeddings on top of it, unify the parallel
implementations that had grown around the old architecture, and rewrite the
`infinity-runtime` docs around the new API.

Core (`infinity_agent_core::system`):
- `AgentSystemBuilder`: `new(stores, model, sender)` builds a step-mode `AgentSystem`
  for serverless platforms; `new_local(stores, model)` builds a `LocalAgentSystem`
  with an internal in-process queue (`ChannelSender`).
- Step mode's public surface is `AgentSystem::step(inputs, observer, defer)`: the
  batch may span multiple threads (SQS FIFO batches can interleave message groups);
  `step` partitions by `group_id`, applies the deferral policy per thread, joins the
  per-thread slices concurrently (prepare → completion → history sync → observer
  commit barrier → tool dispatch), and returns each thread's `StepOutcome`. `&mut
  self` serializes calls per system; the internal `Thread` type is not public and
  `AgentSystem` is not `Clone`, so two live in-memory views of one thread cannot
  exist through the public API. Per-thread configuration resolves lazily on first
  step so loading a thread never boots tool servers.
- `LocalAgentSystem` is mode-typed (`Handles` by default, `Launcher` after
  `with_thread_launcher()`), with one `start()` per mode:
  - Handles mode: `start()` returns a `RunningSystem` running an actor-system-style
    runtime (router + one driver per active thread, input batching, `<interrupt>`
    handling, deferral while a non-passive tool call is pending, auto-compaction
    above 75% of the context window, race-free idle exit/respawn) with ack'd
    `subscribe`, a `thread_exits` channel, and `thread_handle(id)` attaching to any
    thread. `start_with_observer(factory)` swaps in a custom `ThreadObserver`.
  - Launcher mode: `start()` returns a `LaunchingSystem`. `thread_builder()`
    configures and launches new threads (generated IDs) with their own tools and
    prompt, unioned onto the system-wide configuration (static or
    `ThreadConfigSource`) via an internal `UnionConfigSource`; `thread_handle(id)`
    re-attaches to existing threads only (launched in-process or with history).
    Launch configurations are process-lifetime (not persisted).
- `ThreadHandle`: `replay()` plus an exactly-once `events` stream and input sending;
  subscriptions survive driver respawns via a shared registry.
- `ThreadObserver`: synchronous `on_event(AgentEvent)` fan-out (exactly-once relative
  to `on_subscribe` replays) plus awaited durability hooks (`on_user_choice_required`
  /`_dismissed`, `on_commit` before tool dispatch). `EventCollector` buffers
  `(thread_id, event)` pairs.
- `ModelSource` (per-round resolution; enables mid-session model switching),
  `ThreadConfigSource` (per-thread tools/prompt/notifier; enables per-session RAP
  servers and toolsets), `DeferQueue` (`InMemoryDeferQueue`/`NoDeferral`),
  `Tool::is_passive()`, tokio sleep tools (`with_tokio_sleep_tools`).
- `batch_processor` deleted: `process_batch` had no production callers and its
  semantics violated the documented durability barrier (swallowed sync errors, then
  dispatched; emitted ResponseDone before sync). The documented low-level API is now
  `HistoryManager` + `prepare_input`/`run_completion`/`execute_action`;
  `execute_action_with_error_result` (the #88 error-fallback) lives in
  `event_processor`. `DisplayEvent` moved out of core: `AgentEvent` is core's only
  event vocabulary; the CLI keeps a local, non-generic `DisplayEvent` as its
  terminal-rendering enum. All unique regression coverage ported.
- Shared slice internals: `event_processor::input_echo` is the single computation of
  accepted-input echoes; `SyntheticKind::is_compaction_complete()`;
  `InputMessage::user_text()`; driver's in-flight step modeled as
  `InFlightStep { fut, cancel_tx }` with a consuming `cancel()`.
- `rap_callback` module: the RAP callback → `InputMessage` conversion (multimodal
  content, display segments, tagged synthetics incl. subscription final/associative
  flags, user_choice, oauth) lives in core with 11 unit tests; the daemon delegates.
- In-memory `ConversationStore`/`StateStore` in `infinity_agent_core::stores` with a
  serializable snapshot/restore API; the daemon's stores are thin wrappers (extras +
  JSON persistence) so the ancestor/compaction/dedup semantics exist in exactly one
  place. `spawn_thread_with_id` supports deterministic IDs.
- Platform-neutral core: `input_queue_arn` removed from `ToolContext`/builder.
- All 20 daemon agent-loop tests migrated into core `system/tests.rs` with
  byte-identical snapshots, plus new coverage: launcher tool/prompt unioning and
  existing-only attachment, `ThreadHandle` streaming across tool-call rounds,
  multi-group step batches, failed-dispatch fallback, OAuth surfacing, prepare-level
  user-choice, handle respawn survival and pruning.

Daemon (`infinity-daemon`):
- One daemon-lifetime agent system replaces per-session agent loops; sessions are
  root threads; a `thread_exits` watcher marks sessions idle and shuts down their
  RAP servers when no keep-alive client is attached.
- `rap_servers.rs`: `ManagedRapServer` boots lazily per session via
  `ThreadConfigSource` and reboots transparently after idle shutdown; `Up` caches
  the manifest (fetch failure tears the boot down); MCP proxy tasks are owned
  (stdio children `kill_on_drop`) but proxies stay up across idles since MCP servers
  may be stateful; migration flows ride the same path (`MigrationServer`;
  `boot_rap_servers`/`rap_tools.rs` deleted); config merging unified in
  `config::load_merged_rap_config`.
- `DaemonObserver` implements the observer hooks; broadcasting unified in
  `observer::broadcast_pruning`/`broadcast_to_thread` (fixing `handle_view_update`
  never pruning dead subscribers); re-sent Connects replace rather than stack
  subscriptions; replay rendering matches live rendering.
- `CatalogModelSource` resolves each thread's persisted model per round; fixed the
  pre-existing double `ModelSwitched` delivery.
- `send_input` takes `user_driven: bool`; interior-mutability methods take `&self`.
- Web goldens `chat-image-result`/`chat-diff-result` regenerated (old goldens
  captured an eager-boot layout artifact).
- Deleted: `session/thread_worker.rs`, `session/agent_loop.rs`, `sleep_tools.rs`,
  `InMemoryMessageSender`, `Session`, `spawn_session`, `AgentMessage`.

Lambda (`infinity-agent-lambda`):
- Event handler rewritten on the new API: one system per invocation with a
  `ThreadConfigSource` resolving each thread's RAP toolsets (DynamoDB manifest
  cache) plus platform sleep tools (shared `WakeupScheduler` backend); one
  batch-shaped `step`; per-thread outputs aggregated in a `BTreeMap`.
- New `rap-receiver` binary replaces the drifted JS receiver (deleted): same
  Function-URL contract, full parity with the daemon's conversion via
  `infinity_agent_core::rap_callback` (user_choice accepted, multimodal and
  `display_as` preserved, tagged synthetics honored, stable dedup IDs where the
  wire has identity). CDK switches to a cargo-lambda `RustFunction`; the Function
  URL is recreated on deploy, so persisted callback URLs must be re-subscribed.

Docs (`docs/docs/infinity-runtime`): the single "Rust API" page is replaced by two
sections, written in the Hydro docs register (definitional openings, bolded key
terms, cause-and-effect guarantees, code-first examples, admonitions for caveats):
"The Agent System API" (overview, building-a-system, running-locally, step-mode,
observers, including launcher mode) and "The Low-Level API" (overview,
history-manager, completion-loop). Cross-references updated repo-wide; `cargo doc`
is warning-free.

BREAKING CHANGE: `infinity-agent-core` removes `batch_processor` (`process_batch`,
`process_input_item`, `DisplayEvent`); `Thread` is no longer public (use
`AgentSystem::step` or `ThreadHandle`); `AgentSystem` is not `Clone`;
`LocalAgentSystem::start_with_handles` is now `start()` and custom observers use
`start_with_observer` (`LocalAgentSystem` gained a mode type parameter, default
`Handles`); `EventCollector::take` returns `(thread_id, event)` pairs; builder tools
are stored as `Rc<dyn Tool<M>>`; `Tool` gains defaulted `is_passive`;
`ToolContext`/builder lose `input_queue_arn`. `infinity-daemon` no longer exports
`sleep_tools`, `AgentMessage`, `thread_worker`, `agent_loop`, `Session`,
`InMemoryMessageSender`, `boot_rap_servers`, or `rap_tools`;
`SessionManager::switch_model` takes the requester's sender and returns
`Result<(), String>`; `send_input` takes `user_driven: bool`;
`SharedSessionManager` is `Rc<tokio::Mutex<...>>`. The CLI's `DisplayEvent` lives in
`infinity_agent_cli::display`.

Co-authored-by: Infinity 🤖 <infinity@hydro.run>
PR: #92
@shadaj
shadaj force-pushed the sandbox-eb0ff46e-96e1-4d2d-8c0b-9c683fa4d1b9 branch from b822911 to d121304 Compare August 12, 2026 00:04
@shadaj
shadaj marked this pull request as ready for review August 12, 2026 00:04
@shadaj
shadaj requested a review from a team August 12, 2026 00:04
@shadaj

shadaj commented Aug 12, 2026

Copy link
Copy Markdown
Member Author

@MingweiSamuel I'm not sure how we want to go about reviewing this, most of the big blobs of code are unchanged from before, just moved around, but the new system builder, thread handle, etc APIs are new (and do have tests)

shadaj added a commit that referenced this pull request Aug 12, 2026
…on + lambda onto it

Introduce `infinity_agent_core::system`, a builder-based, object-oriented API for
running agents, rebuild both production embeddings on top of it, unify the parallel
implementations that had grown around the old architecture, and rewrite the
`infinity-runtime` docs around the new API.

Core (`infinity_agent_core::system`, resident runtime under `system::local`):
- `AgentSystemBuilder`: `new(stores, model, sender)` builds a step-mode `AgentSystem`
  for serverless platforms; `new_local(stores, model)` builds a `LocalAgentSystem`
  with an internal in-process queue (`ChannelSender`).
- Step mode's public surface is `AgentSystem::step(inputs, observer, defer)`: the
  batch may span multiple threads (SQS FIFO batches can interleave message groups);
  `step` partitions by `group_id`, applies the deferral policy per thread, joins the
  per-thread slices concurrently (prepare → completion → history sync → observer
  commit barrier → tool dispatch), and returns each thread's `StepOutcome`. `&mut
  self` serializes calls per system; the internal `Thread` type is not public and
  `AgentSystem` is not `Clone`, so two live in-memory views of one thread cannot
  exist through the public API. Per-thread configuration resolves lazily on first
  step so loading a thread never boots tool servers.
- `LocalAgentSystem` is mode-typed (`Handles` by default, `Launcher` after
  `with_thread_launcher()`), with one `start()` per mode:
  - Handles mode: `start()` returns a `RunningSystem` running an actor-system-style
    runtime (router + one driver per active thread, input batching, `<interrupt>`
    handling, deferral while a non-passive tool call is pending, auto-compaction
    above 75% of the context window, race-free idle exit/respawn) with ack'd
    `subscribe`, a `thread_exits` channel, and `thread_handle(id)` attaching to any
    thread. `start_with_observer(factory)` swaps in a custom `ThreadObserver`.
  - Launcher mode: `start()` returns a `LaunchingSystem`. `thread_builder()`
    configures and launches new threads (generated IDs) with their own tools and
    prompt, unioned onto the system-wide configuration (static or
    `ThreadConfigSource`); `thread_handle(id)` re-attaches to existing threads only.
    Launch configurations are process-lifetime (not persisted).
- `ThreadHandle`: `replay()` plus an exactly-once `events` stream and input sending;
  subscriptions survive driver respawns via a shared registry.
- `ThreadObserver`: synchronous `on_event(AgentEvent)` fan-out (exactly-once relative
  to `on_subscribe` replays) plus awaited durability hooks (`on_user_choice_required`
  /`_dismissed`, `on_commit` before tool dispatch). `EventCollector` buffers
  `(thread_id, event)` pairs.
- `ModelSource` (per-round resolution; enables mid-session model switching),
  `ThreadConfigSource` (per-thread tools/prompt/notifier; enables per-session RAP
  servers and toolsets), `DeferQueue` (`InMemoryDeferQueue`/`NoDeferral`),
  `Tool::is_passive()`, tokio sleep tools (`with_tokio_sleep_tools`).
- `batch_processor` deleted: `process_batch` had no production callers and its
  semantics violated the documented durability barrier (swallowed sync errors, then
  dispatched; emitted ResponseDone before sync). The documented low-level API is now
  `HistoryManager` + `prepare_input`/`run_completion`/`execute_action`;
  `execute_action_with_error_result` (the #88 error-fallback) lives in
  `event_processor`. `DisplayEvent` moved out of core: `AgentEvent` is core's only
  event vocabulary; the CLI keeps a local, non-generic `DisplayEvent` as its
  terminal-rendering enum. All unique regression coverage ported.
- Shared slice internals: `event_processor::input_echo` is the single computation of
  accepted-input echoes; `SyntheticKind::is_compaction_complete()`;
  `InputMessage::user_text()`; driver's in-flight step modeled as
  `InFlightStep { fut, cancel_tx }` with a consuming `cancel()`.
- `rap_callback` module: the RAP callback → `InputMessage` conversion (multimodal
  content, display segments, tagged synthetics incl. subscription final/associative
  flags, user_choice, oauth) lives in core with 11 unit tests; the daemon delegates.
- In-memory `ConversationStore`/`StateStore` in `infinity_agent_core::stores` with a
  serializable snapshot/restore API; the daemon's stores are thin wrappers (extras +
  JSON persistence) so the ancestor/compaction/dedup semantics exist in exactly one
  place. `spawn_thread_with_id` supports deterministic IDs.
- Platform-neutral core: `input_queue_arn` removed from `ToolContext`/builder.
- All 20 daemon agent-loop tests migrated into core `system/tests.rs` with
  byte-identical snapshots, plus new coverage: launcher tool/prompt unioning and
  existing-only attachment, `ThreadHandle` streaming across tool-call rounds,
  multi-group step batches, failed-dispatch fallback, OAuth surfacing, prepare-level
  user-choice, handle respawn survival and pruning.

Daemon (`infinity-daemon`):
- One daemon-lifetime agent system replaces per-session agent loops; sessions are
  root threads; a `thread_exits` watcher marks sessions idle and shuts down their
  RAP servers when no keep-alive client is attached.
- `rap_servers.rs`: `ManagedRapServer` boots lazily per session via
  `ThreadConfigSource` and reboots transparently after idle shutdown; `Up` caches
  the manifest (fetch failure tears the boot down); MCP proxy tasks are owned
  (stdio children `kill_on_drop`) but proxies stay up across idles since MCP servers
  may be stateful; migration flows ride the same path (`MigrationServer`;
  `boot_rap_servers`/`rap_tools.rs` deleted); config merging unified in
  `config::load_merged_rap_config`.
- `DaemonObserver` implements the observer hooks; broadcasting unified in
  `observer::broadcast_pruning`/`broadcast_to_thread` (fixing `handle_view_update`
  never pruning dead subscribers); re-sent Connects replace rather than stack
  subscriptions; replay rendering matches live rendering.
- `CatalogModelSource` resolves each thread's persisted model per round; fixed the
  pre-existing double `ModelSwitched` delivery.
- `send_input` takes `user_driven: bool`; interior-mutability methods take `&self`.
- Web goldens `chat-image-result`/`chat-diff-result` regenerated (old goldens
  captured an eager-boot layout artifact).
- Deleted: `session/thread_worker.rs`, `session/agent_loop.rs`, `sleep_tools.rs`,
  `InMemoryMessageSender`, `Session`, `spawn_session`, `AgentMessage`.

Lambda (`infinity-agent-lambda`):
- Event handler rewritten on the new API: one system per invocation with a
  `ThreadConfigSource` resolving each thread's RAP toolsets (DynamoDB manifest
  cache) plus platform sleep tools (shared `WakeupScheduler` backend); one
  batch-shaped `step`; per-thread outputs aggregated in a `BTreeMap`.
- New `rap-receiver` binary replaces the drifted JS receiver (deleted): same
  Function-URL contract, full parity with the daemon's conversion via
  `infinity_agent_core::rap_callback` (user_choice accepted, multimodal and
  `display_as` preserved, tagged synthetics honored, stable dedup IDs where the
  wire has identity). CDK switches to a cargo-lambda `RustFunction`; the Function
  URL is recreated on deploy, so persisted callback URLs must be re-subscribed.

Docs (`docs/docs/infinity-runtime`): the single "Rust API" page is replaced by two
sections, written in the Hydro docs register (definitional openings, bolded key
terms, cause-and-effect guarantees, code-first examples, admonitions for caveats):
"The Agent System API" (overview, building-a-system, running-locally, step-mode,
observers, including launcher mode) and "The Low-Level API" (overview,
history-manager, completion-loop). Cross-references updated repo-wide; `cargo doc`
is warning-free.

BREAKING CHANGE: `infinity-agent-core` removes `batch_processor` (`process_batch`,
`process_input_item`, `DisplayEvent`); `Thread` is no longer public (use
`AgentSystem::step` or `ThreadHandle`); `AgentSystem` is not `Clone`;
`LocalAgentSystem::start_with_handles` is now `start()` and custom observers use
`start_with_observer` (`LocalAgentSystem` gained a mode type parameter, default
`Handles`); the resident-runtime types (`RunningSystem`, `SubscribeHandle`,
`ThreadHandle`, `HandleObserver`, `HandleSubscribeRequest`, `LaunchingSystem`,
`ThreadBuilder`, `ChannelSender`, `ChannelSendError`, `ActiveThreads`) live under
`system::local`; `EventCollector::take` returns `(thread_id, event)` pairs; builder
tools are stored as `Rc<dyn Tool<M>>`; `Tool` gains defaulted `is_passive`;
`ToolContext`/builder lose `input_queue_arn`. `infinity-daemon` no longer exports
`sleep_tools`, `AgentMessage`, `thread_worker`, `agent_loop`, `Session`,
`InMemoryMessageSender`, `boot_rap_servers`, or `rap_tools`;
`SessionManager::switch_model` takes the requester's sender and returns
`Result<(), String>`; `send_input` takes `user_driven: bool`;
`SharedSessionManager` is `Rc<tokio::Mutex<...>>`. The CLI's `DisplayEvent` lives in
`infinity_agent_cli::display`.

Co-authored-by: Infinity 🤖 <infinity@hydro.run>
PR: #92
shadaj added a commit that referenced this pull request Aug 12, 2026
…on + lambda onto it

Introduce `infinity_agent_core::system`, a builder-based, object-oriented API for
running agents, rebuild both production embeddings on top of it, unify the parallel
implementations that had grown around the old architecture, and rewrite the
`infinity-runtime` docs around the new API.

Core (`infinity_agent_core::system`, resident runtime under `system::local`):
- `AgentSystemBuilder`: `new(stores, model, sender)` builds a step-mode `AgentSystem`
  for serverless platforms; `new_local(stores, model)` builds a `LocalAgentSystem`
  with an internal in-process queue (`ChannelSender`).
- Step mode's public surface is `AgentSystem::step(inputs, observer, defer)`: the
  batch may span multiple threads (SQS FIFO batches can interleave message groups);
  `step` partitions by `group_id`, applies the deferral policy per thread, joins the
  per-thread slices concurrently (prepare → completion → history sync → tool
  dispatch), and returns each thread's `StepOutcome`. `&mut self` serializes calls
  per system; the internal `Thread` type is not public and `AgentSystem` is not
  `Clone`, so two live in-memory views of one thread cannot exist through the
  public API. Per-thread configuration resolves lazily on first step so loading a
  thread never boots tool servers.
- `LocalAgentSystem` is mode-typed (`Handles` by default, `Launcher` after
  `with_thread_launcher()`), with one `start()` per mode:
  - Handles mode: `start()` returns a `RunningSystem` running an actor-system-style
    runtime (router + one driver per active thread, input batching, `<interrupt>`
    handling, deferral while a non-passive tool call is pending, auto-compaction
    above 75% of the context window, race-free idle exit/respawn) with ack'd
    `subscribe`, a `thread_exits` channel, and `thread_handle(id)` attaching to any
    thread. `start_with_observer(factory)` swaps in a custom `ThreadObserver`.
  - Launcher mode: `start()` returns a `LaunchingSystem`. `thread_builder()`
    configures and launches new threads (generated IDs) with their own tools,
    prompt, and optionally their own `ModelSource`, unioned onto the system-wide
    configuration; launch configurations attach to the launched (root) thread, so
    spawned subagent threads inherit tools, prompt, and model via root resolution.
    `thread_handle(id)` re-attaches to existing threads only (`None` means the
    thread does not exist). Launch configurations are process-lifetime.
- Shutdown is ownership-based: `RunningSystem::shutdown(self)` (and
  `LaunchingSystem::shutdown(self)`) cancels every driver, flushes in-flight turns,
  and awaits the router. Because shutting down consumes the system, `&self` methods
  are infallible: `thread_handle`/`launch` return handles directly, `subscribe`
  resolves once installed, and `send`/`send_user_text` return `()`. Independent
  handles that can outlive the system (`SubscribeHandle`, `ThreadHandle`) keep
  fallible signatures.
- `ThreadHandle`: `replay()` plus an exactly-once `events` stream and input sending;
  subscriptions survive driver respawns via a shared registry.
- `ThreadObserver`: synchronous `on_event(AgentEvent)` fan-out (exactly-once relative
  to `on_subscribe` replays) plus awaited user-choice durability hooks
  (`on_user_choice_required`/`_dismissed`). Tool dispatch happens strictly after
  history sync, so turns are durable before their effects are observable.
  `EventCollector` buffers `(thread_id, event)` pairs.
- `ModelSource` (per-round resolution; enables mid-session model switching),
  `ThreadConfigSource` (per-thread tools/prompt/notifier; enables per-session RAP
  servers and toolsets), `DeferQueue` (`InMemoryDeferQueue`/`NoDeferral`),
  `Tool::is_passive()`, tokio sleep tools (`with_tokio_sleep_tools`).
- `batch_processor` deleted: `process_batch` had no production callers and its
  semantics violated the documented durability barrier (swallowed sync errors, then
  dispatched; emitted ResponseDone before sync). The documented low-level API is now
  `HistoryManager` + `prepare_input`/`run_completion`/`execute_action`;
  `execute_action_with_error_result` (the #88 error-fallback) lives in
  `event_processor`. `DisplayEvent` moved out of core: `AgentEvent` is core's only
  event vocabulary; the CLI keeps a local, non-generic `DisplayEvent` as its
  terminal-rendering enum. All unique regression coverage ported.
- Shared slice internals: `event_processor::input_echo` is the single computation of
  accepted-input echoes; `SyntheticKind::is_compaction_complete()`;
  `InputMessage::user_text()`; driver's in-flight step modeled as
  `InFlightStep { fut, cancel_tx }` with a consuming `cancel()`.
- `rap_callback` module: the RAP callback → `InputMessage` conversion (multimodal
  content, display segments, tagged synthetics incl. subscription final/associative
  flags, user_choice, oauth) lives in core with 11 unit tests; the daemon delegates.
- In-memory `ConversationStore`/`StateStore` in `infinity_agent_core::stores` with a
  serializable snapshot/restore API; the daemon's stores are thin wrappers (extras +
  JSON persistence) so the ancestor/compaction/dedup semantics exist in exactly one
  place. `spawn_thread_with_id` supports deterministic IDs.
- Platform-neutral core: `input_queue_arn` removed from `ToolContext`/builder.
  Unused refactor leftovers pruned: `ToolSet`/`VecToolSet`,
  `ToolsConfig::{add_command, toolset_commands, mcp_servers, http_mcp_servers}`,
  `HistoryManager::state_store()`.
- All 20 daemon agent-loop tests migrated into core `system/tests.rs` with
  byte-identical snapshots, plus new coverage: launcher tool/prompt/model unioning
  and child inheritance, existing-only attachment, `ThreadHandle` streaming across
  tool-call rounds, multi-group step batches, failed-dispatch fallback, OAuth
  surfacing, prepare-level user-choice, handle respawn survival and pruning.

Daemon (`infinity-daemon`):
- One daemon-lifetime agent system replaces per-session agent loops and the
  restart-on-send path (`needs_restart` → `start_session`): idle threads respawn a
  driver transparently instead. Sessions are root threads; a `thread_exits` watcher
  marks sessions idle and shuts down their RAP servers when no keep-alive client is
  attached.
- `rap_servers.rs`: RAP server lifecycle moves out of session start — boot happens
  lazily when a thread's config first resolves (loading/replaying a thread never
  boots servers), shutdown is driven by session idleness, and a shut-down server
  reboots on the next tool interaction. `Up` caches the manifest (fetch failure
  tears the boot down); MCP proxy tasks are owned (stdio children `kill_on_drop`)
  but proxies stay up across idles since MCP servers may be stateful; migration
  flows ride the same path (`MigrationServer`; `boot_rap_servers`/`rap_tools.rs`
  deleted); config merging unified in `config::load_merged_rap_config`.
- `DaemonObserver` implements the observer hooks; broadcasting unified in
  `observer::broadcast_pruning`/`broadcast_to_thread` (fixing `handle_view_update`
  never pruning dead subscribers); re-sent Connects replace rather than stack
  subscriptions; replay rendering matches live rendering.
- `CatalogModelSource` resolves each thread's persisted model per round; fixed the
  pre-existing double `ModelSwitched` delivery.
- `send_input` takes `user_driven: bool`; interior-mutability methods take `&self`.
- Web goldens `chat-image-result`/`chat-diff-result` regenerated (old goldens
  captured an eager-boot layout artifact).
- Deleted: `session/thread_worker.rs`, `session/agent_loop.rs`, `sleep_tools.rs`,
  `InMemoryMessageSender`, `Session`, `spawn_session`, `AgentMessage`.

Lambda (`infinity-agent-lambda`):
- Event handler rewritten on the new API: one system per invocation with a
  `ThreadConfigSource` resolving each thread's RAP toolsets (DynamoDB manifest
  cache) plus platform sleep tools (shared `WakeupScheduler` backend); one
  batch-shaped `step`; per-thread outputs aggregated in a `BTreeMap`.
- New `rap-receiver` binary replaces the drifted JS receiver (deleted): same
  Function-URL contract, full parity with the daemon's conversion via
  `infinity_agent_core::rap_callback` (user_choice accepted, multimodal and
  `display_as` preserved, tagged synthetics honored, stable dedup IDs where the
  wire has identity). CDK switches to a cargo-lambda `RustFunction`; the Function
  URL is recreated on deploy, so persisted callback URLs must be re-subscribed.

Docs (`docs/docs/infinity-runtime`): the single "Rust API" page is replaced by two
sections, written in the Hydro docs register (definitional openings, bolded key
terms, cause-and-effect guarantees, code-first examples, admonitions for caveats):
"The Agent System API" (overview, building-a-system, running-locally, step-mode,
observers, including launcher mode) and "The Low-Level API" (overview,
history-manager, completion-loop). Cross-references updated repo-wide; `cargo doc`
is warning-free.

BREAKING CHANGE: `infinity-agent-core` removes `batch_processor` (`process_batch`,
`process_input_item`, `DisplayEvent`); `Thread` is no longer public (use
`AgentSystem::step` or `ThreadHandle`); `AgentSystem` is not `Clone`;
`LocalAgentSystem::start_with_handles` is now `start()` and custom observers use
`start_with_observer` (`LocalAgentSystem` gained a mode type parameter, default
`Handles`); the resident-runtime types (`RunningSystem`, `SubscribeHandle`,
`ThreadHandle`, `HandleObserver`, `HandleSubscribeRequest`, `LaunchingSystem`,
`ThreadBuilder`, `ChannelSender`, `ChannelSendError`, `ActiveThreads`) live under
`system::local`; `RunningSystem::begin_shutdown`/`task` are replaced by owned
`shutdown(self)`, and `RunningSystem::{send, send_user_text, subscribe,
thread_handle}` are infallible; `ThreadObserver` has no `on_commit` (persist in
`on_event` or externally; the turn is already durable before dispatch);
`EventCollector::take` returns `(thread_id, event)` pairs; builder tools are stored
as `Rc<dyn Tool<M>>`; `Tool` gains defaulted `is_passive`; `ToolContext`/builder
lose `input_queue_arn`; `ToolSet`/`VecToolSet` and `ToolsConfig::{add_command,
toolset_commands, mcp_servers, http_mcp_servers}` are removed. `infinity-daemon` no
longer exports `sleep_tools`, `AgentMessage`, `thread_worker`, `agent_loop`,
`Session`, `InMemoryMessageSender`, `boot_rap_servers`, or `rap_tools`;
`SessionManager::switch_model` takes the requester's sender and returns
`Result<(), String>`; `send_input` takes `user_driven: bool`;
`SharedSessionManager` is `Rc<tokio::Mutex<...>>`. The CLI's `DisplayEvent` lives in
`infinity_agent_cli::display`.

Co-authored-by: Infinity 🤖 <infinity@hydro.run>
PR: #92
@shadaj
shadaj force-pushed the sandbox-eb0ff46e-96e1-4d2d-8c0b-9c683fa4d1b9 branch from 4575d58 to 81b9046 Compare August 12, 2026 18:31
shadaj added a commit that referenced this pull request Aug 12, 2026
…bridges

Reorganize the agent-system documentation into a short default path from overview through an in-memory quickstart and local thread launching, followed by focused guides for dynamic configuration, RAP, MCP, custom tools, observers, step mode, and deeper engine customization. Merge subscription guidance into custom tools, document lifecycle behavior in the overview, and add validated contextual links and examples.

Add lightweight infinity-mcp-bridge and infinity-rap-bridge crates so applications can connect protocol tools without depending on the daemon. Move MCP transport/session behavior and RAP callback conversion into those reusable libraries, retain thin daemon and Lambda adapters, and make callback server task lifetimes explicit.

Update workspace integration and tests for the new bridge APIs. Validate the workspace with formatting, compilation, full tests, strict Clippy, rustdoc, and documentation link, anchor, fence, and style scans.

Co-authored-by: Infinity 🤖 <infinity@hydro.run>
PR: #92
@shadaj
shadaj force-pushed the sandbox-eb0ff46e-96e1-4d2d-8c0b-9c683fa4d1b9 branch from 81b9046 to c705753 Compare August 12, 2026 18:34
shadaj added a commit that referenced this pull request Aug 12, 2026
Remove the misleading dynamic-configuration recommendation from the overview and keep its default path focused on quickstart, local threads, and core tool integrations. Merge short navigation tails and API-note headings into the surrounding task-oriented narrative.

Combine RAP callback reachability with custom callback routing, consolidate custom tool definition, result delivery, and registration, and unify observer event, durability, and live-attach guidance. Fold root-versus-child resolution and low-level builder notes into their parent sections, and expand the Lambda embedding into a substantive step-mode example.

Verify all agent-system pages have balanced fences, valid local links and anchors, accepted style, Rust formatting, and no remaining undersized sections under the documentation audit.

Co-authored-by: Infinity 🤖 <infinity@hydro.run>
PR: #92
@shadaj
shadaj force-pushed the sandbox-eb0ff46e-96e1-4d2d-8c0b-9c683fa4d1b9 branch from c705753 to 911edcb Compare August 12, 2026 18:39
shadaj added a commit that referenced this pull request Aug 12, 2026
Restore AgentSystemBuilder::without_builtin_tools as public API for systems that need a minimal or fully custom toolset. Stop re-exporting convert_callback from infinity-rap-bridge and make it crate-private, since prepare_callback is the consumed entry point.

Audited internal support crates for further dead surface: LoadedToolset and from_manifest are used by the toolset loader's public signature and internals, SimpleHttpError and NoRapHttpError are required associated error types, and every HistoryManager method flagged by the scan is exercised by prepare_input and run_completion in production while forming the documented low-level API. No other removals were warranted.

Workspace formatting, clippy with denied warnings, 125 tests across the four affected crates, and rustdoc for the bridges and core pass clean.

Co-authored-by: Infinity 🤖 <infinity@hydro.run>
PR: #92
@shadaj
shadaj force-pushed the sandbox-eb0ff46e-96e1-4d2d-8c0b-9c683fa4d1b9 branch from 911edcb to 3da95fe Compare August 12, 2026 21:53
shadaj added a commit that referenced this pull request Aug 12, 2026
Restore AgentSystemBuilder::without_builtin_tools as public API for systems that need a minimal or fully custom toolset. Stop re-exporting convert_callback from infinity-rap-bridge and make it crate-private, since prepare_callback is the consumed entry point.

Audited internal support crates for further dead surface: LoadedToolset and from_manifest are used by the toolset loader's public signature and internals, SimpleHttpError and NoRapHttpError are required associated error types, and every HistoryManager method flagged by the scan is exercised by prepare_input and run_completion in production while forming the documented low-level API. No other removals were warranted.

Workspace formatting, clippy with denied warnings, 125 tests across the four affected crates, and rustdoc for the bridges and core pass clean.

Co-authored-by: Infinity 🤖 <infinity@hydro.run>
PR: #92
@shadaj
shadaj force-pushed the sandbox-eb0ff46e-96e1-4d2d-8c0b-9c683fa4d1b9 branch from 3da95fe to 5eacc60 Compare August 12, 2026 21:59
shadaj added a commit that referenced this pull request Aug 12, 2026
Regenerate the THIRD-PARTY file with cargo-about and the npm license checkers so the workspace list includes the new infinity-mcp-bridge and infinity-rap-bridge crates. No new third-party dependencies were introduced, so the notice content is otherwise unchanged.

Co-authored-by: Infinity 🤖 <infinity@hydro.run>
PR: #92
@shadaj
shadaj force-pushed the sandbox-eb0ff46e-96e1-4d2d-8c0b-9c683fa4d1b9 branch from 5eacc60 to 588e9bf Compare August 12, 2026 22:17
shadaj added a commit that referenced this pull request Aug 12, 2026
Regenerate the THIRD-PARTY file with cargo-about and the npm license checkers so the workspace list includes the new infinity-mcp-bridge and infinity-rap-bridge crates. No new third-party dependencies were introduced, so the notice content is otherwise unchanged.

Co-authored-by: Infinity 🤖 <infinity@hydro.run>
PR: #92
@shadaj
shadaj force-pushed the sandbox-eb0ff46e-96e1-4d2d-8c0b-9c683fa4d1b9 branch from 588e9bf to 883f241 Compare August 12, 2026 22:21
shadaj added a commit that referenced this pull request Aug 12, 2026
Regenerate the THIRD-PARTY file with cargo-about and the npm license checkers so the workspace list includes the new infinity-mcp-bridge and infinity-rap-bridge crates. No new third-party dependencies were introduced, so the notice content is otherwise unchanged.

Co-authored-by: Infinity 🤖 <infinity@hydro.run>
PR: #92
@shadaj
shadaj force-pushed the sandbox-eb0ff46e-96e1-4d2d-8c0b-9c683fa4d1b9 branch from 883f241 to 31cd016 Compare August 12, 2026 22:31
shadaj added a commit that referenced this pull request Aug 12, 2026
Remove the definitions parity test and the toolset naming test, which became self-comparisons once the local Tool adapters were rebuilt as wrappers over the same McpToolDefinition values, along with the operation parse test subsumed by dispatch routing and the descriptor conversion test that restated From field copies. The behavioral tests remain: lazy one-time transport connection with request recording, and dispatch routing including the guarantee that unknown operations never reach the server. The PR description no longer cites the removed parity test.

Co-authored-by: Infinity 🤖 <infinity@hydro.run>
PR: #92
@shadaj
shadaj force-pushed the sandbox-eb0ff46e-96e1-4d2d-8c0b-9c683fa4d1b9 branch from 31cd016 to d2cf08a Compare August 12, 2026 23:40
shadaj added a commit that referenced this pull request Aug 13, 2026
Remove the definitions parity test and the toolset naming test, which became self-comparisons once the local Tool adapters were rebuilt as wrappers over the same McpToolDefinition values, along with the operation parse test subsumed by dispatch routing and the descriptor conversion test that restated From field copies. The behavioral tests remain: lazy one-time transport connection with request recording, and dispatch routing including the guarantee that unknown operations never reach the server. The PR description no longer cites the removed parity test.

Co-authored-by: Infinity 🤖 <infinity@hydro.run>
PR: #92
@shadaj
shadaj force-pushed the sandbox-eb0ff46e-96e1-4d2d-8c0b-9c683fa4d1b9 branch from d2cf08a to a112560 Compare August 13, 2026 01:05
shadaj added a commit that referenced this pull request Aug 13, 2026
Remove the definitions parity test and the toolset naming test, which became self-comparisons once the local Tool adapters were rebuilt as wrappers over the same McpToolDefinition values, along with the operation parse test subsumed by dispatch routing and the descriptor conversion test that restated From field copies. The behavioral tests remain: lazy one-time transport connection with request recording, and dispatch routing including the guarantee that unknown operations never reach the server. The PR description no longer cites the removed parity test.

Co-authored-by: Infinity 🤖 <infinity@hydro.run>
PR: #92
@shadaj
shadaj force-pushed the sandbox-eb0ff46e-96e1-4d2d-8c0b-9c683fa4d1b9 branch from a112560 to a8c3438 Compare August 13, 2026 01:08
shadaj added a commit that referenced this pull request Aug 13, 2026
Move the daemon and Lambda runtimes onto the shared infinity-agent-core engine, including routing, lifecycle, state-store, observer, step-processing, and shutdown behavior. Split MCP and RAP integrations into reusable bridge crates and retain migrated daemon fidelity coverage.

Defer the additive ThreadHandle and launcher APIs to the stacked follow-up revision.

Co-authored-by: Infinity 🤖 <infinity@hydro.run>
PR: #92
shadaj added a commit that referenced this pull request Aug 13, 2026
Add thread handles for sending input and streaming observer events across completion rounds. Introduce launcher mode, per-thread builders, and inherited tool, prompt, model, and configuration sources for dynamically launched threads.

Document the high-level agent-system workflow, local execution, custom tools, dynamic configuration, observers, step mode, MCP servers, RAP servers, and engine customization.

BREAKING CHANGE: The public local agent-system builder now selects handle or launcher operation modes and exposes the corresponding running-system types.

Co-authored-by: Infinity 🤖 <infinity@hydro.run>
PR: #92
@shadaj
shadaj force-pushed the sandbox-eb0ff46e-96e1-4d2d-8c0b-9c683fa4d1b9 branch from a8c3438 to 81a6208 Compare August 13, 2026 02:51
shadaj added a commit that referenced this pull request Aug 13, 2026
Add thread handles for sending input and streaming observer events across completion rounds. Introduce launcher mode, per-thread builders, and inherited tool, prompt, model, and configuration sources for dynamically launched threads.

Document the high-level agent-system workflow, local execution, custom tools, dynamic configuration, observers, step mode, MCP servers, RAP servers, and engine customization.

BREAKING CHANGE: The public local agent-system builder now selects handle or launcher operation modes and exposes the corresponding running-system types.

Co-authored-by: Infinity 🤖 <infinity@hydro.run>
PR: #92
@shadaj
shadaj changed the base branch from main to sandbox-0f86f15a-4591-435a-bff7-27a45f33e143 August 13, 2026 02:58
@shadaj
shadaj force-pushed the sandbox-eb0ff46e-96e1-4d2d-8c0b-9c683fa4d1b9 branch from 81a6208 to 17ccfd6 Compare August 13, 2026 02:58
Keep PR 1 focused on the shared engine and production embeddings by deferring static builder conveniences, local MCP/RAP tool-set adapters, and usage guides to PR 2. Preserve migrated behavior with private test configuration sources and remove the unused null observer.

In PR 2, replace the RAP bridge's late-bound sender mutex and duplicate tool wrapper with the shared core RapTool. Make callback ownership explicit by requiring a callback URL during discovery and attaching RapCallbackBridge directly to the running system sender. Update the application guides and pull-request review boundaries accordingly.

Co-authored-by: Infinity 🤖 <infinity@hydro.run>
PR: #92
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.

2 participants