Quick Start
Basic Example with Anthropic
use yoagent::{Agent, AgentEvent, StreamDelta}; use yoagent::provider::ModelConfig; use yoagent::tools::default_tools; #[tokio::main] async fn main() { // The provider is selected from the config's protocol, and the API key is // read from ANTHROPIC_API_KEY. Add `.with_api_key(key)` to override it. let mut agent = Agent::from_config(ModelConfig::anthropic("claude-sonnet-5", "Sonnet 5")) .with_system_prompt("You are a helpful coding assistant.") .with_tools(default_tools()); let mut rx = agent.prompt("List the files in the current directory").await; while let Some(event) = rx.recv().await { match event { AgentEvent::MessageUpdate { delta, .. } => match delta { StreamDelta::Text { delta } => print!("{}", delta), StreamDelta::Thinking { delta } => print!("[thinking] {}", delta), _ => {} }, AgentEvent::ToolExecutionStart { tool_name, .. } => { println!("\nā Running tool: {}", tool_name); } AgentEvent::ToolExecutionEnd { tool_name, result, is_error, .. } => { if is_error { println!(" ā {} failed", tool_name); } else { println!(" ā {} done", tool_name); } } AgentEvent::AgentEnd { .. } => { println!("\n\nDone."); } _ => {} } } }
Example with OpenAI-Compatible Provider
For OpenAI, xAI, Groq, DeepSeek, Mistral, MiniMax, Z.ai, Qwen, Ollama, or any compatible API, pass the matching ModelConfig preset ā from_config picks the OpenAI-compatible provider and resolves the provider's env key automatically:
use yoagent::{Agent, AgentEvent}; use yoagent::provider::ModelConfig; use yoagent::tools::default_tools; #[tokio::main] async fn main() { // Provider inferred from the preset; key from OPENAI_API_KEY. let mut agent = Agent::from_config(ModelConfig::openai("gpt-5.5", "GPT-5.5")) .with_system_prompt("You are a helpful assistant.") .with_tools(default_tools()); let mut rx = agent.prompt("What is 2 + 2?").await; while let Some(event) = rx.recv().await { match event { AgentEvent::MessageUpdate { delta, .. } => { if let yoagent::StreamDelta::Text { delta } = delta { print!("{}", delta); } } AgentEvent::AgentEnd { .. } => println!(), _ => {} } } }
Real-Time Streaming
agent.prompt() spawns the agent loop concurrently and returns a receiver immediately, so events stream in real-time as they're produced. For cases where you want to provide your own channel (e.g., to share a sender across tasks), use prompt_with_sender():
use yoagent::{Agent, AgentEvent, StreamDelta}; use yoagent::provider::ModelConfig; use yoagent::tools::default_tools; #[tokio::main] async fn main() { let mut agent = Agent::from_config(ModelConfig::anthropic("claude-sonnet-5", "Sonnet 5")) .with_system_prompt("You are a helpful assistant.") .with_tools(default_tools()); let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel(); // Consume events in real-time on a separate task tokio::spawn(async move { while let Some(event) = rx.recv().await { match event { AgentEvent::MessageUpdate { delta, .. } => { if let StreamDelta::Text { delta } = delta { print!("{}", delta); } } AgentEvent::AgentEnd { .. } => println!(), _ => {} } } }); // This blocks until the loop finishes; state is restored automatically agent.prompt_with_sender("What is 2 + 2?", tx).await; // Agent is ready for another prompt immediately let _rx = agent.prompt("Follow up question").await; }
Using the Low-Level API
For more control, use agent_loop() directly:
use yoagent::agent_loop::{agent_loop, AgentLoopConfig}; use yoagent::provider::AnthropicProvider; use yoagent::types::*; use tokio::sync::mpsc; use tokio_util::sync::CancellationToken; #[tokio::main] async fn main() { let (tx, mut rx) = mpsc::unbounded_channel(); let cancel = CancellationToken::new(); let mut context = AgentContext { system_prompt: "You are helpful.".into(), messages: Vec::new(), tools: yoagent::tools::default_tools(), }; let config = AgentLoopConfig { provider: std::sync::Arc::new(AnthropicProvider), model: "claude-sonnet-5".into(), api_key: std::env::var("ANTHROPIC_API_KEY").unwrap(), thinking_level: ThinkingLevel::Off, max_tokens: None, temperature: None, model_config: None, convert_to_llm: None, transform_context: None, get_steering_messages: None, get_follow_up_messages: None, context_config: None, compaction_strategy: None, execution_limits: None, cache_config: CacheConfig::default(), tool_execution: ToolExecutionStrategy::default(), retry_config: yoagent::RetryConfig::default(), before_turn: None, after_turn: None, on_error: None, input_filters: vec![], }; let prompts = vec![AgentMessage::Llm(Message::user("Hello!"))]; let new_messages = agent_loop(prompts, &mut context, &config, tx, cancel).await; // Drain events while let Ok(event) = rx.try_recv() { // handle events... } println!("Got {} new messages", new_messages.len()); }