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
oneshotreturn 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:
- Incoming messages from the UI.
- Incoming chunks from an LLM stream.
- 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.
