Agent Air relies heavily on Rust’s async/await ecosystem, primarily built on top of tokio.

The Actor-Like Model

While not using a strict actor framework, we follow an actor-like pattern:

  • State is owned by a long-running async task (the “Actor”).
  • Communication happens via mpsc (Multi-Producer, Single-Consumer) channels.
  • Responses are handled via oneshot return channels sent along with the request.
struct MyActor {
    receiver: mpsc::Receiver<Message>,
    state: InternalState,
}

enum Message {
    DoSomething { 
        arg: String, 
        respond_to: oneshot::Sender<Result<()>> 
    },
}

Select Loops

The tokio::select! macro is ubiquitous. It allows a task to wait on multiple async sources simultaneously, such as:

  1. Incoming messages from the UI.
  2. Incoming chunks from an LLM stream.
  3. A cancellation signal (CancellationToken).
loop {
    tokio::select! {
        Some(msg) = rx.recv() => handle_msg(msg),
        _ = cancellation_token.cancelled() => break,
    }
}

Structured Concurrency

We avoid “detached” tasks (tokio::spawn without a handle) where possible. Most spawned tasks are tracked via JoinSet or kept in a struct to ensure they can be cleanly aborted during shutdown.