### Initialize OpenAiCompatProvider Source: https://github.com/yologdev/yoagent/blob/main/docs/providers/openai-compat.md Basic setup for an agent using the OpenAI compatible provider with an API key. ```rust use yoagent::provider::{OpenAiCompatProvider, ModelConfig}; let agent = Agent::new(OpenAiCompatProvider) .with_model("gpt-4o") .with_api_key(std::env::var("OPENAI_API_KEY").unwrap()); ``` -------------------------------- ### Basic Anthropic Agent Example Source: https://github.com/yologdev/yoagent/blob/main/docs/getting-started/quick-start.md Demonstrates setting up and using the YoAgent with AnthropicProvider. Requires ANTHROPIC_API_KEY environment variable. ```rust use yoagent::{Agent, AgentEvent, StreamDelta}; use yoagent::provider::AnthropicProvider; use yoagent::tools::default_tools; #[tokio::main] async fn main() { let mut agent = Agent::new(AnthropicProvider) .with_system_prompt("You are a helpful coding assistant.") .with_model("claude-sonnet-4-20250514") .with_api_key(std::env::var("ANTHROPIC_API_KEY").unwrap()) .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."); } _ => {} } } } ``` -------------------------------- ### Configure Local OpenAI-Compatible Servers Source: https://github.com/yologdev/yoagent/blob/main/docs/providers/openai-compat.md Setup for local servers like LM Studio or Ollama, which do not require an API key. ```rust use yoagent::agent::Agent; use yoagent::provider::{OpenAiCompatProvider, ModelConfig}; let agent = Agent::new(OpenAiCompatProvider) .with_model_config(ModelConfig::local("http://localhost:1234/v1", "my-model")) .with_model("my-model") .with_api_key(""); // empty string OK for local ``` ```bash cargo run --example cli -- --api-url http://localhost:1234/v1 --model my-model ``` -------------------------------- ### Initialize Agent with OpenAPI Source: https://github.com/yologdev/yoagent/blob/main/docs/guides/openapi.md Demonstrates the basic setup of an agent using an OpenAPI specification file. Requires the 'openapi' feature enabled in Cargo.toml. ```rust use yoagent::Agent; use yoagent::openapi::{OpenApiToolAdapter, OpenApiConfig, OperationFilter}; use yoagent::provider::AnthropicProvider; #[tokio::main] async fn main() -> Result<(), Box> { let config = OpenApiConfig::new() .with_bearer_token("sk-..."); let agent = Agent::new(AnthropicProvider) .with_system_prompt("You are an API assistant.") .with_model("claude-sonnet-4-20250514") .with_api_key(std::env::var("ANTHROPIC_API_KEY")?) .with_openapi_file("petstore.yaml", config, &OperationFilter::All) .await?; Ok(()) } ``` -------------------------------- ### SKILL.md YAML Frontmatter Source: https://github.com/yologdev/yoagent/blob/main/docs/concepts/skills.md Example of the YAML frontmatter and content structure for a SKILL.md file. ```markdown --- name: git description: Git operations — commit, branch, merge, rebase. Use when the user mentions version control. --- # Git Skill ## Workflow 1. Run `git status` first 2. Stage changes, write conventional commit messages 3. For merges, check for conflicts first ## Scripts For complex diffs: `bash {baseDir}/scripts/diff_summary.sh` ``` -------------------------------- ### Build and Development Commands Source: https://github.com/yologdev/yoagent/blob/main/CLAUDE.md Standard Cargo commands for building, testing, formatting, and running examples within the yoagent project. ```bash cargo build # Build the library cargo test # Run all unit tests cargo test # Run a single test by name cargo test --test agent_test # Run a specific test file cargo fmt # Auto-format code cargo fmt -- --check # Check formatting (CI uses this) cargo clippy --all-targets # Lint (CI runs with -Dwarnings) cargo run --example cli # Run the interactive CLI example cargo run --example basic # Run the minimal example ``` -------------------------------- ### OpenAI-Compatible Agent Example Source: https://github.com/yologdev/yoagent/blob/main/docs/getting-started/quick-start.md Shows how to use YoAgent with OpenAI-compatible providers like Groq, DeepSeek, etc. Requires OPENAI_API_KEY environment variable. ```rust use yoagent::{Agent, AgentEvent}; use yoagent::provider::OpenAiCompatProvider; use yoagent::tools::default_tools; #[tokio::main] async fn main() { let mut agent = Agent::new(OpenAiCompatProvider) .with_system_prompt("You are a helpful assistant.") .with_model("gpt-4o") .with_api_key(std::env::var("OPENAI_API_KEY").unwrap()) .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!(), _ => {} } } } ``` -------------------------------- ### Run Interactive CLI Agent Source: https://github.com/yologdev/yoagent/blob/main/README.md Commands to execute the example CLI agent with optional skill loading or custom API configurations. ```bash ANTHROPIC_API_KEY=sk-... cargo run --example cli # With skills: ANTHROPIC_API_KEY=sk-... cargo run --example cli -- --skills ./skills # With a local server (LM Studio, Ollama, llama.cpp, vLLM): cargo run --example cli -- --api-url http://localhost:1234/v1 --model my-model ``` -------------------------------- ### agent_loop() Source: https://github.com/yologdev/yoagent/blob/main/docs/concepts/agent-loop.md Starts a new agent run by adding initial prompts to the context and executing the agent loop. ```APIDOC ## agent_loop() ### Description Starts a new agent run with provided prompt messages. The prompts are added to the context, and the loop executes the full cycle of LLM calls and tool execution. ### Parameters - **prompts** (Vec) - Required - Initial messages to start the agent. - **context** (&mut AgentContext) - Required - The current agent state and history. - **config** (&AgentLoopConfig) - Required - Configuration for the agent loop. - **tx** (mpsc::UnboundedSender) - Required - Channel for emitting agent events. - **cancel** (CancellationToken) - Required - Token to signal cancellation of the loop. ### Response - **Returns** (Vec) - All new messages generated during the run. ``` -------------------------------- ### Add yoagent and tokio to Cargo.toml Source: https://github.com/yologdev/yoagent/blob/main/README.md Install the yoagent crate and the tokio runtime with full features by adding them to your Cargo.toml file. ```toml [dependencies] yoagent = "0.6" tokio = { version = "1", features = ["full"] } ``` -------------------------------- ### Agent Loop Entry Point: agent_loop() Source: https://github.com/yologdev/yoagent/blob/main/docs/concepts/agent-loop.md Starts a new agent run with initial prompt messages. It adds prompts to the context and then executes the main agent loop. Returns all new messages generated during the run. ```rust pub async fn agent_loop( prompts: Vec, context: &mut AgentContext, config: &AgentLoopConfig, tx: mpsc::UnboundedSender, cancel: CancellationToken, ) -> Vec ``` -------------------------------- ### Install yoagent and tokio with Cargo Source: https://github.com/yologdev/yoagent/blob/main/README.md Use the cargo add command to include yoagent and tokio with the 'full' features in your project dependencies. ```bash cargo add yoagent tokio --features tokio/full ``` -------------------------------- ### Derive ContextConfig from Model Context Window Source: https://github.com/yologdev/yoagent/blob/main/docs/reference/configuration.md Example of deriving `ContextConfig` from a model's context window size. 80% is allocated for context and 20% for output. ```rust // Derive from a model's context window: let config = ContextConfig::from_context_window(200_000); // config.max_context_tokens == 160_000 ``` -------------------------------- ### Error Handling Example: File Reading Tool Source: https://github.com/yologdev/yoagent/blob/main/docs/concepts/tools.md Demonstrates returning `Err(ToolError)` for failures. The agent converts this to a `Message::ToolResult` for LLM recovery. Handles missing arguments and file read errors. ```rust async fn execute(&self, params: serde_json::Value, _ctx: ToolContext) -> Result { let path = params["path"].as_str() .ok_or(ToolError::InvalidArgs("missing 'path'".into()))?; let content = std::fs::read_to_string(path) .map_err(|e| ToolError::Failed(format!("Cannot read {}: {}", path, e)))?; Ok(ToolResult { content: vec![Content::Text { text: content }], details: serde_json::Value::Null, }) } ``` -------------------------------- ### Initialize AzureOpenAiProvider Source: https://github.com/yologdev/yoagent/blob/main/docs/providers/azure-openai.md Instantiate the provider and configure the model and API key. ```rust use yoagent::provider::AzureOpenAiProvider; let agent = Agent::new(AzureOpenAiProvider) .with_model("gpt-4o") .with_api_key(std::env::var("AZURE_OPENAI_API_KEY").unwrap()); ``` -------------------------------- ### Configure LLM Providers Source: https://github.com/yologdev/yoagent/blob/main/README.md Demonstrates how to initialize different LLM providers using the registry. ```rust use yoagent::provider::{ModelConfig, ApiProtocol, ProviderRegistry}; // Use any OpenAI-compatible provider let model = ModelConfig::openai_compat("groq", "llama-3.3-70b", "https://api.groq.com/openai/v1"); // Or Google Gemini let model = ModelConfig::google("gemini-2.5-pro"); // Registry dispatches to the right provider let registry = ProviderRegistry::default(); ``` -------------------------------- ### JSON Message Serialization Format Source: https://github.com/yologdev/yoagent/blob/main/docs/concepts/persistence.md Example of the JSON structure used for serializing conversation messages and extension messages. ```json [ { "role": "user", "content": [{"type": "text", "text": "Hello"}], "timestamp": 1700000000000 }, { "role": "assistant", "content": [{"type": "text", "text": "Hi there!"}], "stopReason": "stop", "model": "claude-sonnet-4-20250514", "provider": "anthropic", "usage": {"input": 100, "output": 50, "cache_read": 0, "cache_write": 0, "total_tokens": 150}, "timestamp": 1700000001000 } ] ``` ```json { "role": "extension", "kind": "status_update", "data": {"status": "running"} } ``` -------------------------------- ### Configure Tool Execution Strategies Source: https://github.com/yologdev/yoagent/blob/main/docs/concepts/tools.md Demonstrates how to initialize an Agent with different ToolExecutionStrategy variants to control how multiple tool calls are processed. ```rust use yoagent::agent::Agent; use yoagent::types::ToolExecutionStrategy; // Default — parallel (fastest) let agent = Agent::new(provider); // Sequential (debug / shared state) let agent = Agent::new(provider) .with_tool_execution(ToolExecutionStrategy::Sequential); // Batched — 3 at a time let agent = Agent::new(provider) .with_tool_execution(ToolExecutionStrategy::Batched { size: 3 }); ``` -------------------------------- ### Basic Agent Prompt and Event Handling in Rust Source: https://github.com/yologdev/yoagent/blob/main/README.md Demonstrates setting up an agent with AnthropicProvider, sending a prompt, and processing streaming events to print text deltas until the agent ends. Requires ANTHROPIC_API_KEY environment variable. ```rust use yoagent::agent::Agent; use yoagent::provider::AnthropicProvider; use yoagent::types::*; #[tokio::main] async fn main() { let mut agent = Agent::new(AnthropicProvider) .with_system_prompt("You are a helpful assistant.") .with_model("claude-sonnet-4-20250514") .with_api_key(std::env::var("ANTHROPIC_API_KEY").unwrap()); let mut rx = agent.prompt("What is Rust's ownership model?").await; while let Some(event) = rx.recv().await { match event { AgentEvent::MessageUpdate { delta: StreamDelta::Text { delta }, .. } => print!("{}", delta), AgentEvent::AgentEnd { .. } => break, _ => {} } } } ``` -------------------------------- ### Implementing a Custom WeatherTool Source: https://github.com/yologdev/yoagent/blob/main/docs/concepts/tools.md Example of implementing the AgentTool trait for a custom WeatherTool. Ensure parameters schema matches expected inputs. ```rust use yoagent::types::*; use async_trait::async_trait; pub struct WeatherTool; #[async_trait] impl AgentTool for WeatherTool { fn name(&self) -> &str { "get_weather" } fn label(&self) -> &str { "Weather" } fn description(&self) -> &str { "Get current weather for a city." } fn parameters_schema(&self) -> serde_json::Value { serde_json::json!({ "type": "object", "properties": { "city": { "type": "string", "description": "City name" } }, "required": ["city"] }) } async fn execute( &self, params: serde_json::Value, _ctx: ToolContext, ) -> Result { let city = params["city"].as_str() .ok_or(ToolError::InvalidArgs("missing city".into()))?; // Call weather API... Ok(ToolResult { content: vec![Content::Text { text: format!("Weather in {}: 72°F, sunny", city), }], details: serde_json::Value::Null, }) } } ``` -------------------------------- ### Configure Context Management and Compaction Source: https://context7.com/yologdev/yoagent/llms.txt Set up automatic context window management with `ContextConfig` and `ExecutionLimits`. Options include token budgets, recent/first message retention, and tool output truncation. Context management can be disabled. ```rust use yoagent::agent::Agent; use yoagent::context::{ContextConfig, ExecutionLimits, CompactionStrategy, DefaultCompaction}; // Configure context management let context_config = ContextConfig { max_context_tokens: 100_000, system_prompt_tokens: 4_000, keep_recent: 10, keep_first: 2, tool_output_max_lines: 50, }; // Configure execution limits let limits = ExecutionLimits { max_turns: 50, max_total_tokens: 1_000_000, max_duration: std::time::Duration::from_secs(600), }; let agent = Agent::new(provider) .with_context_config(context_config) .with_execution_limits(limits) .with_model("claude-sonnet-4-20250514") .with_api_key(api_key); // Or derive from model's context window (auto-sets 80% for input) use yoagent::provider::ModelConfig; let model = ModelConfig::anthropic("claude-sonnet-4-20250514", "Claude Sonnet"); // model.context_window = 200_000 -> max_context_tokens = 160_000 // Disable automatic context management let agent = agent.without_context_management(); ``` -------------------------------- ### Initialize Google AI Studio Provider Source: https://github.com/yologdev/yoagent/blob/main/docs/providers/google.md Instantiate the GoogleProvider for Google AI Studio, specifying the model and API key. Ensure the GOOGLE_API_KEY environment variable is set. ```rust use yoagent::provider::GoogleProvider; let agent = Agent::new(GoogleProvider) .with_model("gemini-2.0-flash") .with_api_key(std::env::var("GOOGLE_API_KEY").unwrap()); ``` -------------------------------- ### Use ProviderRegistry Source: https://github.com/yologdev/yoagent/blob/main/docs/providers/overview.md Demonstrates using the default registry to stream responses and registering custom providers. ```rust let registry = ProviderRegistry::default(); // Use it to stream with any model let result = registry.stream(&model_config, stream_config, tx, cancel).await?; ``` ```rust let mut registry = ProviderRegistry::new(); registry.register(ApiProtocol::AnthropicMessages, AnthropicProvider); ``` -------------------------------- ### Initialize AnthropicProvider Source: https://github.com/yologdev/yoagent/blob/main/docs/providers/anthropic.md Instantiate the AnthropicProvider with a model and API key. Ensure the ANTHROPIC_API_KEY environment variable is set. ```rust use yoagent::provider::AnthropicProvider; let agent = Agent::new(AnthropicProvider) .with_model("claude-sonnet-4-20250514") .with_api_key(std::env::var("ANTHROPIC_API_KEY").unwrap()); ``` -------------------------------- ### Initialize default tools Source: https://github.com/yologdev/yoagent/blob/main/docs/reference/tools.md Retrieve all built-in tools using the default_tools function. ```rust use yoagent::tools::default_tools; let tools = default_tools(); ``` -------------------------------- ### Initialize BedrockProvider in Rust Source: https://github.com/yologdev/yoagent/blob/main/docs/providers/bedrock.md Configure the agent with the BedrockProvider and specify the model and credentials. ```rust use yoagent::provider::BedrockProvider; let agent = Agent::new(BedrockProvider) .with_model("anthropic.claude-3-sonnet-20240229-v1:0") .with_api_key("ACCESS_KEY:SECRET_KEY"); // or ACCESS_KEY:SECRET_KEY:SESSION_TOKEN ``` -------------------------------- ### Connect to MCP Server via Stdio Source: https://context7.com/yologdev/yoagent/llms.txt Integrate with Model Context Protocol (MCP) tool servers using stdio. This spawns the MCP server process. Environment variables can be optionally passed. ```rust use yoagent::agent::Agent; use yoagent::mcp::McpClient; use std::collections::HashMap; // Connect via stdio (spawns the MCP server process) let agent = Agent::new(provider) .with_model("claude-sonnet-4-20250514") .with_api_key(api_key) .with_mcp_server_stdio( "npx", &["-y", "@modelcontextprotocol/server-filesystem", "/tmp"], None, // Optional environment variables ).await?; ``` -------------------------------- ### Create and prompt an agent in Rust Source: https://context7.com/yologdev/yoagent/llms.txt Initializes an agent with a system prompt and model, then processes streaming events from a prompt. ```rust use yoagent::agent::Agent; use yoagent::provider::AnthropicProvider; use yoagent::types::*; #[tokio::main] async fn main() { let mut agent = Agent::new(AnthropicProvider) .with_system_prompt("You are a helpful assistant. Be concise.") .with_model("claude-sonnet-4-20250514") .with_api_key(std::env::var("ANTHROPIC_API_KEY").unwrap()); // prompt() spawns the loop concurrently and returns events immediately let mut rx = agent.prompt("What is Rust's ownership model in 2 sentences?").await; while let Some(event) = rx.recv().await { match event { AgentEvent::MessageUpdate { delta: StreamDelta::Text { delta }, .. } => print!("{}", delta), AgentEvent::AgentEnd { messages } => { println!("\n\nTotal messages: {}", messages.len()); break; } _ => {} } } // Call finish() to restore agent state after draining events agent.finish().await; } ``` -------------------------------- ### Instantiate BashTool Source: https://github.com/yologdev/yoagent/blob/main/docs/reference/tools.md Create a BashTool instance using defaults or custom configuration. ```rust let bash = BashTool::default(); // Or customize: let bash = BashTool { cwd: Some("/workspace".into()), timeout: Duration::from_secs(60), ..Default::default() }; ``` -------------------------------- ### Registering Custom Tools Source: https://github.com/yologdev/yoagent/blob/main/docs/concepts/tools.md Shows how to register a custom tool alongside default tools by pushing it to the tools vector. ```rust use yoagent::tools::default_tools; let mut tools = default_tools(); tools.push(Box::new(WeatherTool)); let agent = Agent::new(provider).with_tools(tools); ``` -------------------------------- ### Configure Agent Retries with Builder Source: https://github.com/yologdev/yoagent/blob/main/docs/concepts/retry.md Demonstrates how to create an Agent with default retry settings, custom retry configuration, or disable retries entirely. ```rust use yoagent::agent::Agent; use yoagent::retry::RetryConfig; // Default — 3 retries, exponential backoff (recommended) let agent = Agent::new(provider); // Custom — more retries, longer initial delay let agent = Agent::new(provider) .with_retry_config(RetryConfig { max_retries: 5, initial_delay_ms: 2000, backoff_multiplier: 2.0, max_delay_ms: 60_000, }); // Disable retries entirely let agent = Agent::new(provider) .with_retry_config(RetryConfig::none()); ``` -------------------------------- ### Configure OpenAPI Adapter Source: https://github.com/yologdev/yoagent/blob/main/docs/guides/openapi.md Settings for controlling authentication, headers, timeouts, and request behavior. ```rust let config = OpenApiConfig::new() .with_base_url("https://api.staging.example.com") // Override spec's servers .with_bearer_token("sk-...") // Bearer auth .with_header("X-Custom", "value") // Extra headers .with_timeout_secs(60) // Request timeout .with_max_response_bytes(128 * 1024) // Truncate large responses .with_name_prefix("github"); // Tool names: github__listRepos ``` ```rust // Bearer token let config = OpenApiConfig::new().with_bearer_token("token"); // API key in a custom header let config = OpenApiConfig::new().with_api_key("X-API-Key", "key-value"); // No auth let config = OpenApiConfig::new(); // default ``` -------------------------------- ### Configure Agent System Prompt Source: https://github.com/yologdev/yoagent/blob/main/docs/reference/api.md Sets the system prompt for the agent. ```rust with_system_prompt(prompt) -> Self ``` -------------------------------- ### Initialize ModelConfig Instances Source: https://github.com/yologdev/yoagent/blob/main/docs/providers/overview.md Convenience constructors for creating ModelConfig instances for various providers. ```rust let anthropic = ModelConfig::anthropic("claude-sonnet-4-20250514", "Claude Sonnet 4"); let openai = ModelConfig::openai("gpt-4o", "GPT-4o"); let google = ModelConfig::google("gemini-2.0-flash", "Gemini 2.0 Flash"); let xai = ModelConfig::xai("grok-3-mini", "Grok 3 Mini"); let groq = ModelConfig::groq("llama-3.3-70b-versatile", "Llama 3.3 70B"); let deepseek = ModelConfig::deepseek("deepseek-chat", "DeepSeek Chat"); let mistral = ModelConfig::mistral("mistral-large-latest", "Mistral Large"); let minimax = ModelConfig::minimax("MiniMax-Text-01", "MiniMax Text 01"); let zai = ModelConfig::zai("glm-4.7", "GLM 4.7"); let local = ModelConfig::local("http://localhost:1234/v1", "my-model"); ``` -------------------------------- ### Create a Sub-Agent Tool in Rust Source: https://github.com/yologdev/yoagent/blob/main/docs/concepts/sub-agents.md Demonstrates how to create a `SubAgentTool` for a researcher, configuring its description, system prompt, model, API key, and available tools like file reading and searching. It also sets a maximum turn limit. ```rust use std::sync::Arc; use yoagent::sub_agent::SubAgentTool; use yoagent::provider::AnthropicProvider; use yoagent::tools; let researcher = SubAgentTool::new("researcher", Arc::new(AnthropicProvider)) .with_description("Searches and reads files to gather information.") .with_system_prompt("You are a research assistant. Be thorough and concise.") .with_model("claude-sonnet-4-20250514") .with_api_key(&api_key) .with_tools(vec![ Arc::new(tools::ReadFileTool::new()), Arc::new(tools::SearchTool::new()), ]) .with_max_turns(10); ``` -------------------------------- ### Load Skills for Agent Source: https://context7.com/yologdev/yoagent/llms.txt Extend agent capabilities by loading skills from directories. Later directories override earlier ones. Skills are injected into the system prompt. Ensure the skill directory structure includes `SKILL.md` and an optional `scripts/` directory. ```rust use yoagent::skills::SkillSet; use yoagent::agent::Agent; use yoagent::provider::AnthropicProvider; // Load skills from directories (later directories override earlier) let skills = SkillSet::load(&["./skills", "~/.yoagent/skills"])?; println!("Loaded {} skills", skills.len()); let agent = Agent::new(AnthropicProvider) .with_system_prompt("You are a coding assistant.") .with_model("claude-sonnet-4-20250514") .with_api_key(api_key) .with_skills(skills) // Injects skill index into system prompt .with_tools(tools); ``` -------------------------------- ### Real-Time Streaming with Custom Channel Source: https://github.com/yologdev/yoagent/blob/main/docs/getting-started/quick-start.md Illustrates using `prompt_with_sender` to provide a custom channel for real-time event handling, allowing for concurrent event consumption. ```rust use yoagent::{Agent, AgentEvent, StreamDelta}; use yoagent::provider::AnthropicProvider; use yoagent::tools::default_tools; #[tokio::main] async fn main() { let mut agent = Agent::new(AnthropicProvider) .with_system_prompt("You are a helpful assistant.") .with_model("claude-sonnet-4-20250514") .with_api_key(std::env::var("ANTHROPIC_API_KEY").unwrap()) .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; } ``` -------------------------------- ### Create a User Message in Rust Source: https://github.com/yologdev/yoagent/blob/main/docs/concepts/messages-events.md Demonstrates the convenience constructor for creating a user message with simple text content. ```rust let msg = Message::user("Hello, world!"); ``` -------------------------------- ### Execute Agent Loop and Continue Source: https://context7.com/yologdev/yoagent/llms.txt Use agent_loop for initial execution and agent_loop_continue to resume from an existing context, such as during retries. ```rust use yoagent::agent_loop::{agent_loop, agent_loop_continue, AgentLoopConfig}; use yoagent::types::{AgentContext, AgentMessage, Message}; use yoagent::provider::AnthropicProvider; use tokio::sync::mpsc; use tokio_util::sync::CancellationToken; use std::sync::Arc; let mut context = AgentContext { system_prompt: "You are helpful.".into(), messages: Vec::new(), tools: vec![], }; let config = AgentLoopConfig { provider: Arc::new(AnthropicProvider), model: "claude-sonnet-4-20250514".into(), api_key: api_key.into(), thinking_level: Default::default(), max_tokens: Some(4096), 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: Default::default(), tool_execution: Default::default(), retry_config: Default::default(), before_turn: None, after_turn: None, on_error: None, input_filters: vec![], }; let (tx, mut rx) = mpsc::unbounded_channel(); let cancel = CancellationToken::new(); let prompts = vec![AgentMessage::Llm(Message::user("Hello!"))]; // Run the loop let new_messages = agent_loop(prompts, &mut context, &config, tx, cancel.clone()).await; // Continue from existing context (for retries) let (tx2, _rx2) = mpsc::unbounded_channel(); let more_messages = agent_loop_continue(&mut context, &config, tx2, cancel).await; ``` -------------------------------- ### Implement Tool with Progress Streaming Source: https://github.com/yologdev/yoagent/blob/main/docs/concepts/tools.md Demonstrates how to use the on_update callback within an AgentTool execution to stream progress updates. ```rust use yoagent::types::*; struct DataProcessorTool; #[async_trait] impl AgentTool for DataProcessorTool { // ... name, label, description, parameters_schema ... async fn execute( &self, params: serde_json::Value, ctx: ToolContext, ) -> Result { let rows = fetch_rows(¶ms)?; let total = rows.len(); for (i, row) in rows.iter().enumerate() { // Check for cancellation if ctx.cancel.is_cancelled() { return Err(ToolError::Cancelled); } process_row(row); // Stream progress every 100 rows if i % 100 == 0 { if let Some(ref cb) = &ctx.on_update { cb(ToolResult { content: vec![Content::Text { text: format!("Processed {}/{} rows", i, total), }], details: serde_json::json!({"progress": i as f64 / total as f64}), }); } } } Ok(ToolResult { content: vec![Content::Text { text: format!("Processed all {} rows", total), }], details: serde_json::Value::Null, }) } } ``` -------------------------------- ### Create an Extension Message in Rust Source: https://github.com/yologdev/yoagent/blob/main/docs/concepts/messages-events.md Shows how to create an `ExtensionMessage` using its convenience constructor and wrap it in an `AgentMessage`. ```rust let ext = ExtensionMessage::new("status_update", serde_json::json!({"status": "running"})); let msg = AgentMessage::Extension(ext); ``` -------------------------------- ### Configure Agent Queues and Steering Source: https://context7.com/yologdev/yoagent/llms.txt Manage agent execution flow by setting steering and follow-up queue modes. Use `steer` to interrupt and `follow_up` to queue tasks. Queues can be cleared or the agent aborted/reset. ```rust use yoagent::agent::{Agent, QueueMode}; use yoagent::types::{AgentMessage, Message}; let mut agent = Agent::new(provider) .with_system_prompt("You are helpful.") .with_model("claude-sonnet-4-20250514") .with_api_key(api_key) .with_tools(tools); // Configure queue modes agent.set_steering_mode(QueueMode::OneAtATime); // deliver one message per turn agent.set_follow_up_mode(QueueMode::All); // deliver all at once let rx = agent.prompt("Process these files...").await; // From another task: interrupt the agent mid-tool-execution agent.steer(AgentMessage::Llm(Message::user("Stop! Skip the large files."))); // Queue work to process after the current task completes agent.follow_up(AgentMessage::Llm(Message::user("Now summarize what you found."))); // Clear queues if needed agent.clear_steering_queue(); agent.clear_follow_up_queue(); // Abort the entire agent loop agent.abort(); // Reset completely: clear messages, queues, cancel running loop agent.reset().await; ``` -------------------------------- ### Create and Delegate to Sub-Agents in Rust Source: https://context7.com/yologdev/yoagent/llms.txt Demonstrates creating specialized sub-agents (researcher and coder) with distinct tools and system prompts, and delegating tasks to them from a parent agent. Requires Anthropic API key. ```rust use yoagent::agent::Agent; use yoagent::sub_agent::SubAgentTool; use yoagent::provider::{AnthropicProvider, StreamProvider}; use yoagent::tools; use std::sync::Arc; #[tokio::main] async fn main() { let api_key = std::env::var("ANTHROPIC_API_KEY").unwrap(); let provider: Arc = Arc::new(AnthropicProvider); // Research sub-agent with read-only tools let researcher = SubAgentTool::new("researcher", Arc::clone(&provider)) .with_description("Searches and reads files to gather information.") .with_system_prompt("You are a research assistant. Read files and summarize findings.") .with_model("claude-sonnet-4-20250514") .with_api_key(&api_key) .with_tools(vec![ Arc::new(tools::ReadFileTool::new()), Arc::new(tools::SearchTool::new()), Arc::new(tools::ListFilesTool::new()), ]) .with_max_turns(10); // Coder sub-agent with write tools let coder = SubAgentTool::new("coder", Arc::clone(&provider)) .with_description("Writes and edits code files.") .with_system_prompt("You are a coding assistant. Write clean, correct code.") .with_model("claude-sonnet-4-20250514") .with_api_key(&api_key) .with_tools(vec![ Arc::new(tools::ReadFileTool::new()), Arc::new(tools::WriteFileTool::new()), Arc::new(tools::EditFileTool::new()), ]) .with_max_turns(15); // Parent coordinator agent let mut agent = Agent::new(AnthropicProvider) .with_system_prompt( "You are a coordinator. Delegate research to 'researcher' and coding to 'coder'." ) .with_model("claude-sonnet-4-20250514") .with_api_key(api_key) .with_sub_agent(researcher) .with_sub_agent(coder); let mut rx = agent.prompt("Read README.md and create a summary in summary.txt").await; // Process events... } ``` -------------------------------- ### Connect to MCP Server via Stdio Source: https://github.com/yologdev/yoagent/blob/main/docs/guides/mcp.md Spawns an MCP server process and registers its tools using the stdio transport. ```rust use yoagent::Agent; use yoagent::provider::AnthropicProvider; #[tokio::main] async fn main() -> Result<(), Box> { let mut agent = Agent::new(AnthropicProvider) .with_system_prompt("You are a helpful assistant with file access.") .with_model("claude-sonnet-4-20250514") .with_api_key(std::env::var("ANTHROPIC_API_KEY")?) .with_mcp_server_stdio( "npx", &["-y", "@modelcontextprotocol/server-filesystem", "/tmp"], None, ) .await?; let rx = agent.prompt("List files in /tmp").await; // handle events... Ok(()) } ``` ```rust use std::collections::HashMap; let mut env = HashMap::new(); env.insert("API_TOKEN".into(), "secret".into()); let agent = Agent::new(provider) .with_mcp_server_stdio("my-mcp-server", &["--port", "0"], Some(env)) .await?; ``` -------------------------------- ### Load Agent Tools from OpenAPI URL Source: https://github.com/yologdev/yoagent/blob/main/docs/reference/api.md Fetches an OpenAPI specification from a URL and adds tools. Requires the `openapi` feature. ```rust async with_openapi_url(url, config, filter) -> Result ``` -------------------------------- ### Configure ListFilesTool Source: https://github.com/yologdev/yoagent/blob/main/docs/reference/tools.md Define the ListFilesTool structure for directory traversal settings. ```rust pub struct ListFilesTool { pub max_results: usize, // Default: 200 pub timeout: Duration, // Default: 10s } ``` -------------------------------- ### Define Base URL Format Source: https://github.com/yologdev/yoagent/blob/main/docs/providers/azure-openai.md Set the base URL using the Azure resource and deployment path. ```text https://{resource}.openai.azure.com/openai/deployments/{deployment} ``` -------------------------------- ### Load Agent Tools from OpenAPI File Source: https://github.com/yologdev/yoagent/blob/main/docs/reference/api.md Loads tools from an OpenAPI specification file. Requires the `openapi` feature. ```rust async with_openapi_file(path, config, filter) -> Result ``` -------------------------------- ### Implement Agent Lifecycle Callbacks in Rust Source: https://context7.com/yologdev/yoagent/llms.txt Shows how to use lifecycle callbacks like `on_before_turn`, `on_after_turn`, and `on_error` to control agent behavior, track token usage, and handle errors. Requires Anthropic API key. ```rust use yoagent::agent::Agent; use yoagent::provider::AnthropicProvider; use std::sync::{Arc, Mutex}; let usage_log: Arc>> = Arc::new(Mutex::new(Vec::new())); let log_clone = usage_log.clone(); let mut agent = Agent::new(AnthropicProvider) .with_system_prompt("You are helpful.") .with_model("claude-sonnet-4-20250514") .with_api_key(api_key) // Limit to 10 turns, return false to abort the loop .on_before_turn(|messages, turn| { println!("[before_turn] turn={}, messages={}", turn, messages.len()); turn < 10 // false aborts the loop }) // Track token usage after each turn .on_after_turn(move |messages, usage| { println!("[after_turn] {} in / {} out tokens", usage.input, usage.output); log_clone.lock().unwrap().push((usage.input, usage.output)); }) // Handle errors (e.g., rate limits, API errors) .on_error(|err| { eprintln!("[error] {}", err); }); ``` -------------------------------- ### Configure BashTool with Safety Limits Source: https://context7.com/yologdev/yoagent/llms.txt Set working directory, timeouts, and command denial patterns to secure the BashTool environment. ```rust use yoagent::tools::BashTool; use std::time::Duration; let bash = BashTool::new() .with_cwd("/home/user/project") // Working directory .with_timeout(Duration::from_secs(60)) // Command timeout .with_deny_patterns(vec![ // Block dangerous commands "rm -rf /".into(), "rm -rf /*".into(), "mkfs".into(), "dd if=".into(), ":(){:|:&};:".into(), // fork bomb ]) .with_confirm(|cmd| { // Optional confirmation callback for dangerous commands println!("Allow command: {}? (y/n)", cmd); true // Return false to block }); let agent = Agent::new(provider) .with_tools(vec![Box::new(bash)]) .with_model("claude-sonnet-4-20250514") .with_api_key(api_key); ``` -------------------------------- ### Load Agent Skills Source: https://github.com/yologdev/yoagent/blob/main/docs/reference/api.md Loads skills and appends their index to the system prompt. ```rust with_skills(skills: SkillSet) -> Self ``` -------------------------------- ### Configure Queue Delivery Modes Source: https://github.com/yologdev/yoagent/blob/main/docs/concepts/agent-loop.md Set the delivery mode for steering and follow-up queues using `set_steering_mode()` and `set_follow_up_mode()`. `QueueMode::All` delivers all messages at once, while `QueueMode::OneAtATime` delivers one message per turn. ```rust agent.set_steering_mode(QueueMode::All); agent.set_follow_up_mode(QueueMode::OneAtATime); ``` -------------------------------- ### Configure callbacks via AgentLoopConfig Source: https://github.com/yologdev/yoagent/blob/main/docs/concepts/callbacks.md Direct configuration for the agent loop without using the Agent wrapper. ```rust use std::sync::Arc; use yoagent::agent_loop::AgentLoopConfig; let config = AgentLoopConfig { before_turn: Some(Arc::new(|_msgs, turn| turn < 5)), after_turn: Some(Arc::new(|_msgs, _usage| { /* log */ })), on_error: Some(Arc::new(|err| eprintln!("{}", err))), // ... other fields }; ``` -------------------------------- ### Add a New Compatible Provider Source: https://github.com/yologdev/yoagent/blob/main/docs/providers/openai-compat.md Steps to define a custom provider constructor and integrate it into a ModelConfig. ```rust impl OpenAiCompat { pub fn my_provider() -> Self { Self { supports_usage_in_streaming: true, // set flags as needed... ..Default::default() } } } ``` ```rust let config = ModelConfig { id: "my-model".into(), name: "My Model".into(), api: ApiProtocol::OpenAiCompletions, provider: "my-provider".into(), base_url: "https://api.myprovider.com/v1".into(), compat: Some(OpenAiCompat::my_provider()), // ... }; ``` -------------------------------- ### Manually Derive ContextConfig Source: https://github.com/yologdev/yoagent/blob/main/docs/concepts/context-management.md Manually calculate the context configuration from a specific window size. ```rust let config = ContextConfig::from_context_window(1_000_000); // config.max_context_tokens == 800_000 ``` -------------------------------- ### Configure Tool Execution Strategy Source: https://context7.com/yologdev/yoagent/llms.txt Define how multiple tool calls from a single LLM response are executed. Options include `Parallel` (default, concurrent), `Sequential` (one at a time), and `Batched` (in groups of a specified size). ```rust use yoagent::types::ToolExecutionStrategy; // Parallel (default) - all tools run concurrently for best latency let agent = agent.with_tool_execution(ToolExecutionStrategy::Parallel); // Sequential - one at a time, check steering between each let agent = agent.with_tool_execution(ToolExecutionStrategy::Sequential); // Batched - run in batches of N, check steering between batches let agent = agent.with_tool_execution(ToolExecutionStrategy::Batched { size: 3 }); ``` -------------------------------- ### Implement before_turn callback Source: https://github.com/yologdev/yoagent/blob/main/docs/concepts/callbacks.md Executes before each LLM call. Returning false aborts the agent loop. ```rust let agent = Agent::new(provider) .on_before_turn(|messages, turn| { println!("Turn {} starting with {} messages", turn, messages.len()); turn < 10 // Stop after 10 turns }); ``` -------------------------------- ### Auto-derive ContextConfig from ModelConfig Source: https://github.com/yologdev/yoagent/blob/main/docs/concepts/context-management.md Automatically derive compaction budgets based on the model's context window when no explicit configuration is provided. ```rust // MiniMax with 1M context → compacts at 800K (no manual config needed) let agent = Agent::new(OpenAiCompatProvider) .with_model_config(ModelConfig::minimax("MiniMax-Text-01", "MiniMax Text 01")) .with_api_key(api_key); // Anthropic with 200K context → compacts at 160K let agent = Agent::new(AnthropicProvider) .with_model_config(ModelConfig::anthropic("claude-sonnet-4-20250514", "Claude Sonnet 4")) .with_api_key(api_key); ``` -------------------------------- ### Queue Follow-Up Tasks for Agent Execution Source: https://github.com/yologdev/yoagent/blob/main/docs/concepts/agent-loop.md Use `agent.follow_up()` to queue messages that will be processed after the agent completes its current task, without needing to re-prompt the agent. ```rust agent.follow_up(AgentMessage::Llm(Message::user("Now run the tests."))); agent.follow_up(AgentMessage::Llm(Message::user("Then commit the changes."))); ``` -------------------------------- ### Execute agent_loop with custom configuration Source: https://github.com/yologdev/yoagent/blob/main/docs/getting-started/quick-start.md Directly invokes the agent loop using a specified provider and configuration. Requires an active tokio runtime and proper environment variables for API keys. ```rust 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-4-20250514".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()); } ``` -------------------------------- ### Implement Proactive and Reactive Compaction Source: https://github.com/yologdev/yoagent/blob/main/docs/concepts/context-management.md Wire application-level logic to check context size before prompts or handle errors reactively by compacting messages. ```rust // Proactive: check before each prompt let tokens = tracker.estimate_context_tokens(agent.messages()); if tokens > context_window - reserve { let compacted = compact_messages(agent.messages().to_vec(), &config); agent.replace_messages(compacted); } // Reactive: catch overflow errors // ... on ContextOverflow or message.is_context_overflow(): // compact, then retry with agent.continue_loop() ```