Agent Builder
The aether_core crate provides the agent runtime. The main entry point is the agent() function, which returns an AgentBuilder for configuring and spawning agents.
[dependencies]aether-core = "0.1"llm = "0.1"Creating an agent
Section titled “Creating an agent”use aether_core::core::agent;use llm::{ProviderFactory, providers::AnthropicProvider};
let provider = AnthropicProvider::from_env().await?.with_model("claude-sonnet-4-5");
let (user_tx, agent_rx, handle) = agent(provider) .system_prompt(Prompt::text("You are a helpful assistant.")) .spawn() .await?;The agent() function takes any type implementing StreamingModelProvider and returns an AgentBuilder.
AgentBuilder
Section titled “AgentBuilder”Builder methods (all chainable):
| Method | Description |
|---|---|
system_prompt(prompt) | Add a system prompt |
tools(tx, tools) | Attach MCP tools (channel + tool definitions) |
tool_timeout(duration) | Set timeout for tool calls |
messages(messages) | Pre-populate conversation history |
compaction(config) | Configure context compaction |
disable_compaction() | Turn off automatic compaction |
max_auto_continues(n) | Max auto-continue attempts when model hits tool calls |
prompt_cache_key(key) | Set prompt caching key |
from_spec
Section titled “from_spec”Build an agent from an AgentSpec (loaded from .aether/settings.json). This is async because it parses the model spec and may perform provider setup:
use aether_core::core::AgentBuilder;
let builder = AgentBuilder::from_spec(&agent_spec, base_prompts).await?;spawn() returns three values:
let (user_tx, agent_rx, handle) = builder.spawn().await?;| Value | Type | Purpose |
|---|---|---|
user_tx | Sender<UserMessage> | Send messages to the agent |
agent_rx | Receiver<AgentMessage> | Receive events from the agent |
handle | AgentHandle | Control the agent lifecycle |
Sending messages
Section titled “Sending messages”use aether_core::events::UserMessage;
// Send a text messageuser_tx.send(UserMessage::text("What files are in this directory?")).await?;
// Cancel the current operationuser_tx.send(UserMessage::Cancel).await?;
// Clear conversation contextuser_tx.send(UserMessage::ClearContext).await?;
// Change reasoning effortuser_tx.send(UserMessage::SetReasoningEffort(Some(ReasoningEffort::High))).await?;AgentHandle
Section titled “AgentHandle”// Check if the agent is still runningif handle.is_finished() { /* ... */ }
// Abort the agenthandle.abort();
// Wait for completionhandle.await_completion().await;Full example
Section titled “Full example”use aether_core::core::agent;use aether_core::events::{UserMessage, AgentMessage};use llm::{ProviderFactory, providers::AnthropicProvider};
#[tokio::main]async fn main() -> Result<(), Box<dyn std::error::Error>> { let provider = AnthropicProvider::from_env().await?.with_model("claude-sonnet-4-5");
let (user_tx, mut agent_rx, handle) = agent(provider) .system_prompt(Prompt::text("You are a concise assistant.")) .spawn() .await?;
user_tx.send(UserMessage::text("What is Rust?")).await?;
while let Some(msg) = agent_rx.recv().await { match msg { AgentMessage::Text { chunk, .. } => print!("{chunk}"), AgentMessage::Done => break, AgentMessage::Error { message } => eprintln!("Error: {message}"), _ => {} } }
handle.await_completion().await; Ok(())}See Events & Streaming for the full list of AgentMessage variants, and MCP Integration for attaching tools.