Configuration
AgentLoopConfig
The main configuration for the agent loop:
#![allow(unused)] fn main() { pub struct AgentLoopConfig { pub provider: Arc<dyn StreamProvider>, pub model: String, pub api_key: String, pub thinking_level: ThinkingLevel, pub max_tokens: Option<u32>, pub temperature: Option<f32>, pub model_config: Option<ModelConfig>, pub convert_to_llm: Option<ConvertToLlmFn>, pub transform_context: Option<TransformContextFn>, pub get_steering_messages: Option<GetMessagesFn>, pub get_follow_up_messages: Option<GetMessagesFn>, pub context_config: Option<ContextConfig>, pub compaction_strategy: Option<Arc<dyn CompactionStrategy>>, pub execution_limits: Option<ExecutionLimits>, pub cache_config: CacheConfig, pub tool_execution: ToolExecutionStrategy, pub retry_config: RetryConfig, pub before_turn: Option<BeforeTurnFn>, pub after_turn: Option<AfterTurnFn>, pub on_error: Option<OnErrorFn>, pub input_filters: Vec<Arc<dyn InputFilter>>, pub turn_delay: Option<Duration>, } }
StreamConfig
Passed to StreamProvider::stream():
#![allow(unused)] fn main() { pub struct StreamConfig { pub model: String, pub system_prompt: String, pub messages: Vec<Message>, pub tools: Vec<ToolDefinition>, pub thinking_level: ThinkingLevel, pub api_key: String, pub max_tokens: Option<u32>, pub temperature: Option<f32>, pub model_config: Option<ModelConfig>, pub cache_config: CacheConfig, } }
ContextConfig
Controls context window compaction:
#![allow(unused)] fn main() { pub struct ContextConfig { pub max_context_tokens: usize, // Default: 100,000 pub system_prompt_tokens: usize, // Default: 4,000 pub keep_recent: usize, // Default: 10 pub keep_first: usize, // Default: 2 pub tool_output_max_lines: usize, // Default: 200 pub tool_output_max_lines_overrides: HashMap<String, usize>, // Default: {"read_file": MAX} pub compact_target_ratio: f32, // Default: 0.7 pub compact_headroom_turns: Option<usize>, // Default: Some(30) pub truncate_tool_output_on_append: bool, // Default: true } }
compact_headroom_turns sets the compaction target from observed growth (target = budget − turns × growth_per_turn), keeping the interval between compactions constant as a session lengthens; compact_target_ratio is the fallback and a ceiling on retention. truncate_tool_output_on_append caps tool output as it enters the context rather than retroactively, and tool_output_max_lines_overrides gives per-tool budgets so a tool that head+tail would damage (a paging reader) can opt out. All three exist to keep the provider's prefix cache intact — see Context Management.
When context_config is not explicitly set, it is automatically derived from ModelConfig.context_window (80% for context, 20% reserved for output). If neither is set, ContextConfig::default() (100K) is used.
#![allow(unused)] fn main() { // Derive from a model's context window: let config = ContextConfig::from_context_window(200_000); // config.max_context_tokens == 160_000 }
ExecutionLimits
Prevents runaway agents:
#![allow(unused)] fn main() { #[non_exhaustive] // build with Default::default() + with_* pub struct ExecutionLimits { pub max_turns: usize, // Default: 50 pub max_total_tokens: usize, // Default: 1,000,000 pub max_duration: Duration, // Default: 600s pub max_consecutive_identical_tool_calls: Option<usize>, // Default: Some(3) } }
#![allow(unused)] fn main() { ExecutionLimits::default() .with_max_turns(20) .with_max_consecutive_identical_tool_calls(None) // disable loop detection }
ThinkingLevel
#![allow(unused)] fn main() { pub enum ThinkingLevel { Off, // No thinking (default) Minimal, // Anthropic: effort "low" (adaptive) / 1,024-token budget (legacy) Low, // Anthropic: effort "low" / 1,024 Medium, // Anthropic: effort "medium" / 2,048 High, // Anthropic: effort "high" / 8,192 } }
OpenAI-family providers map these levels to reasoning_effort where the
compat flags enable it; the Google and Bedrock providers currently ignore
thinking_level.
CostConfig
Token pricing per million:
#![allow(unused)] fn main() { #[non_exhaustive] // build with new() + with_*, not a literal pub struct CostConfig { pub input_per_million: f64, pub output_per_million: f64, pub cache_read_per_million: f64, pub cache_write_per_million: f64, pub context_tiers: Vec<ContextTier>, // empty = one flat rate at every size } }
Cache rates are set with builders rather than positionally. Four same-typed
f64 arguments in a row is a transposition hazard, and no vendor publishes them
in one order — Anthropic lists input / cache-write / cache-read / output, OpenAI
lists input / cached-input / output:
#![allow(unused)] fn main() { CostConfig::new(5.0, 30.0) // input, output — output is always dearer .with_cache_read(0.5) .with_cache_write(6.25) }
All-zero rates mean pricing unknown, not free. is_configured() reports
which, and session_cost_usd() returns None for an unpriced model rather than
$0.
Context tiers
Some vendors charge more above a prompt-size threshold. cost_usd selects by
the request's prompt tokens (input + cache_read + cache_write), so a long
reply to a short prompt stays on the base rate:
#![allow(unused)] fn main() { CostConfig::new(5.0, 30.0) .with_context_tier(ContextTier::new(272_000, 10.0, 45.0).with_cache_read(1.0)) }
Tiers are kept sorted, and cost_usd takes the last one the prompt clears, so a
multi-step schedule works. No shipped preset sets one — see
ModelConfig::gpt_5_5's docs for why the one candidate stayed flat.
One caveat if you add a tier: prompt size is derived as
input + cache_read + cache_write, which holds only where the provider
subtracts cached tokens out of input. bedrock.rs populates neither cache
field, so a heavily-cached prompt reads small there.
ModelConfig Presets
yoagent provides first-class ModelConfig::* constructors for Anthropic, OpenAI, Google Gemini, xAI, Groq, DeepSeek, Mistral, MiniMax, Z.ai, Qwen, Ollama, and local OpenAI-compatible servers.
See Model Presets for the full table of constructors, default base URLs, context windows, and DeepSeek legacy alias notes.