LLMRegistry
This page documents the LLMRegistry, which manages provider configurations and enables multi-provider setups. The registry provides a central location for storing API credentials and default provider selection.
Registry Overview
┌─────────────────────────────────────────────────────────────────┐
│ AgentConfig │
│ Loads provider configurations from YAML/env │
└─────────────────────────────────┬───────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ LLMRegistry │
│ - Stores LLMSessionConfig entries │
│ - Tracks default provider │
│ - Provides config lookup │
└─────────────────────────────────┬───────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ AgentAir │
│ - Creates sessions from registry configs │
│ - Supports switching between providers │
└─────────────────────────────────────────────────────────────────┘
LLMRegistry Structure
The registry stores provider configurations:
pub struct LLMRegistry {
configs: Vec<LLMSessionConfig>,
default_index: usize,
}
| Field | Type | Purpose |
|---|---|---|
configs | Vec<LLMSessionConfig> | All registered provider configurations |
default_index | usize | Index of the default provider |
Creating a Registry
Empty Registry
impl LLMRegistry {
pub fn new() -> Self {
Self {
configs: Vec::new(),
default_index: 0,
}
}
}
From Configuration
impl LLMRegistry {
pub fn from_configs(configs: Vec<LLMSessionConfig>) -> Self {
Self {
configs,
default_index: 0,
}
}
}
Registering Providers
Add configurations to the registry:
impl LLMRegistry {
pub fn register(&mut self, config: LLMSessionConfig) {
self.configs.push(config);
}
pub fn register_default(&mut self, config: LLMSessionConfig) {
self.default_index = self.configs.len();
self.configs.push(config);
}
}
Provider Lookup
Get Default Provider
impl LLMRegistry {
pub fn get_default(&self) -> Option<&LLMSessionConfig> {
self.configs.get(self.default_index)
}
}
Get Provider by Index
impl LLMRegistry {
pub fn get(&self, index: usize) -> Option<&LLMSessionConfig> {
self.configs.get(index)
}
}
Get Provider by Name
impl LLMRegistry {
pub fn get_by_model(&self, model: &str) -> Option<&LLMSessionConfig> {
self.configs.iter().find(|c| c.model == model)
}
pub fn get_by_provider(&self, provider: LLMProvider) -> Option<&LLMSessionConfig> {
self.configs.iter().find(|c| c.provider == provider)
}
}
Setting Default Provider
Change the default provider:
impl LLMRegistry {
pub fn set_default(&mut self, index: usize) -> bool {
if index < self.configs.len() {
self.default_index = index;
true
} else {
false
}
}
pub fn set_default_by_model(&mut self, model: &str) -> bool {
if let Some(index) = self.configs.iter().position(|c| c.model == model) {
self.default_index = index;
true
} else {
false
}
}
}
Iterating Providers
Access all registered providers:
impl LLMRegistry {
pub fn iter(&self) -> impl Iterator<Item = &LLMSessionConfig> {
self.configs.iter()
}
pub fn len(&self) -> usize {
self.configs.len()
}
pub fn is_empty(&self) -> bool {
self.configs.is_empty()
}
}
Usage in AgentAir
The registry is used during session creation:
impl AgentAir {
pub fn create_initial_session(&mut self) -> Result<(i64, String, i32), AgentError> {
// Get registry
let registry = self.llm_registry.as_ref()
.ok_or_else(|| AgentError::NoConfiguration(
"No LLM configuration found".to_string()
))?;
// Get default provider config
let config = registry.get_default()
.ok_or_else(|| AgentError::NoConfiguration(
"No default provider configured".to_string()
))?;
// Create session
let session_id = self.create_session(config.clone())?;
Ok((session_id, config.model.clone(), config.context_limit))
}
}
Multi-Provider Configuration
Register multiple providers for switching:
let mut registry = LLMRegistry::new();
// Register Anthropic as default
registry.register_default(
LLMSessionConfig::anthropic(&anthropic_key, "claude-sonnet-4-20250514")
.with_system_prompt("You are a helpful assistant.")
);
// Register OpenAI as backup
registry.register(
LLMSessionConfig::openai(&openai_key, "gpt-4o")
.with_system_prompt("You are a helpful assistant.")
);
// Register Claude for complex tasks
registry.register(
LLMSessionConfig::anthropic(&anthropic_key, "claude-opus-4-20250514")
.with_system_prompt("You are an expert analyst.")
.with_max_tokens(8192)
);
Provider Switching
Switch between providers at runtime:
// Create session with default provider
let session1 = core.create_initial_session()?;
// Switch to different provider
let registry = core.llm_registry.as_ref().unwrap();
if let Some(gpt4_config) = registry.get_by_model("gpt-4o") {
let session2 = core.create_session(gpt4_config.clone())?;
}
// Switch to high-capability model
if let Some(opus_config) = registry.get_by_model("claude-opus-4-20250514") {
let session3 = core.create_session(opus_config.clone())?;
}
Configuration Loading
The registry is typically populated from configuration:
impl AgentConfig for MyAgent {
fn load_llm_registry(&self) -> Option<LLMRegistry> {
let mut registry = LLMRegistry::new();
// Load from environment
if let Ok(api_key) = std::env::var("ANTHROPIC_API_KEY") {
registry.register_default(
LLMSessionConfig::anthropic(&api_key, "claude-sonnet-4-20250514")
);
}
if let Ok(api_key) = std::env::var("OPENAI_API_KEY") {
registry.register(
LLMSessionConfig::openai(&api_key, "gpt-4o")
);
}
if registry.is_empty() {
None
} else {
Some(registry)
}
}
}
YAML Configuration
Load providers from YAML:
providers:
- name: anthropic-sonnet
provider: anthropic
model: claude-sonnet-4-20250514
api_key_env: ANTHROPIC_API_KEY
max_tokens: 4096
default: true
- name: openai-gpt4
provider: openai
model: gpt-4o
api_key_env: OPENAI_API_KEY
max_tokens: 4096
- name: anthropic-opus
provider: anthropic
model: claude-opus-4-20250514
api_key_env: ANTHROPIC_API_KEY
max_tokens: 8192
Error Handling
Registry operations handle missing providers:
// Safe access with Option
if let Some(config) = registry.get_default() {
let session = core.create_session(config.clone())?;
} else {
return Err(AgentError::NoConfiguration("No providers configured".into()));
}
// Check before switching
if !registry.set_default_by_model("gpt-4o") {
tracing::warn!("Provider gpt-4o not found in registry");
}
Registry Inspection
List available providers:
fn list_providers(registry: &LLMRegistry) {
println!("Available providers:");
for (i, config) in registry.iter().enumerate() {
let default = if i == registry.default_index { " (default)" } else { "" };
println!(" {} - {:?} / {}{}", i, config.provider, config.model, default);
}
}
Example output:
Available providers:
0 - Anthropic / claude-sonnet-4-20250514 (default)
1 - OpenAI / gpt-4o
2 - Anthropic / claude-opus-4-20250514
Thread Safety
The registry is typically stored in AgentAir:
pub struct AgentAir {
llm_registry: Option<LLMRegistry>,
// ...
}
For concurrent access, wrap in appropriate synchronization:
// Read-only access after initialization
let config = self.llm_registry.as_ref()?.get_default()?;
// For runtime modifications, use RwLock
pub struct AgentAir {
llm_registry: RwLock<Option<LLMRegistry>>,
}
Next Steps
- Session Creation - Creating sessions from configs
- Multi-Provider Setup - Configuring multiple providers
- Provider Abstraction - Provider implementation
