Make agents.<name>.models optional

Changes:
- agents.<name>.models is now optional (uses serde default)
- If models not specified, uses default model for all task types
- AgentModels.for_task() now takes TaskType enum and returns cloned String
- Falls back to default model if task-specific model not set
- Default agent config simplified to only set default model

Example minimal agent config:
[agents.default]
description = "Default agent"
system_prompt = "You are helpful."
tools = ["file", "shell", "git"]
# No models needed - uses provider default

Example with only default model:
[agents.default.models]
default = "ollama/llama3"
# All tasks use llama3

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
2026-03-19 14:44:49 +01:00
parent bd8350b52a
commit d874194d95
3 changed files with 31 additions and 23 deletions

View File

@@ -147,15 +147,8 @@ pub struct AgentRuntimeConfig {
impl AgentRuntimeConfig { impl AgentRuntimeConfig {
pub fn get_model_for_task(&self, task_type: TaskType) -> Option<String> { pub fn get_model_for_task(&self, task_type: TaskType) -> Option<String> {
let model_str = match task_type { // Use the AgentModels helper which handles fallback to default
TaskType::Chat => self.config.models.chat.as_ref(), self.config.models.for_task(task_type)
TaskType::Code => self.config.models.code.as_ref(),
TaskType::Planning => self.config.models.planning.as_ref(),
TaskType::ToolUse => self.config.models.tool_use.as_ref(),
TaskType::Default => self.config.models.default.as_ref(),
};
model_str.cloned()
} }
} }

View File

@@ -248,11 +248,9 @@ fn default_agent_config() -> AgentConfig {
AgentConfig { AgentConfig {
description: "Default general-purpose agent".to_string(), description: "Default general-purpose agent".to_string(),
models: AgentModels { models: AgentModels {
chat: Some("ollama/llama3".to_string()), // Only set default model - will be used for all task types
code: Some("openai/gpt-4o".to_string()),
planning: Some("openai/gpt-4o".to_string()),
tool_use: Some("openai/gpt-4o".to_string()),
default: Some("ollama/llama3".to_string()), default: Some("ollama/llama3".to_string()),
..Default::default()
}, },
system_prompt: "You are a helpful AI assistant. Help the user with their tasks.".to_string(), system_prompt: "You are a helpful AI assistant. Help the user with their tasks.".to_string(),
tools: vec!["file".to_string(), "shell".to_string(), "git".to_string()], tools: vec!["file".to_string(), "shell".to_string(), "git".to_string()],

View File

@@ -1,6 +1,8 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::HashMap; use std::collections::HashMap;
use crate::providers::TaskType;
/// Main configuration structure /// Main configuration structure
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Config { pub struct Config {
@@ -131,7 +133,8 @@ pub struct AgentConfig {
#[serde(default)] #[serde(default)]
pub description: String, pub description: String,
/// Model routing configuration /// Model routing configuration (optional, uses default model for all tasks if not specified)
#[serde(default)]
pub models: AgentModels, pub models: AgentModels,
/// System prompt for this agent /// System prompt for this agent
@@ -152,6 +155,7 @@ pub struct AgentConfig {
} }
/// Model routing for different task types /// Model routing for different task types
/// If no models are specified, the default model is used for all tasks
#[derive(Debug, Clone, Serialize, Deserialize, Default)] #[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct AgentModels { pub struct AgentModels {
/// Model for general chat/conversation /// Model for general chat/conversation
@@ -170,21 +174,34 @@ pub struct AgentModels {
#[serde(default)] #[serde(default)]
pub tool_use: Option<String>, pub tool_use: Option<String>,
/// Fallback model when task type is unclear /// Fallback model for all tasks (used if task-specific models not set)
#[serde(default)] #[serde(default)]
pub default: Option<String>, pub default: Option<String>,
} }
impl AgentModels { impl AgentModels {
/// Get the model for a specific task type /// Get the model for a specific task type
pub fn for_task(&self, task_type: &str) -> Option<&str> { /// Falls back to default model if task-specific model not set
match task_type { pub fn for_task(&self, task_type: TaskType) -> Option<String> {
"chat" => self.chat.as_deref(), let task_model = match task_type {
"code" => self.code.as_deref(), TaskType::Chat => self.chat.as_ref(),
"planning" => self.planning.as_deref(), TaskType::Code => self.code.as_ref(),
"tool_use" => self.tool_use.as_deref(), TaskType::Planning => self.planning.as_ref(),
_ => self.default.as_deref(), TaskType::ToolUse => self.tool_use.as_ref(),
TaskType::Default => self.default.as_ref(),
};
// Return task-specific model if set, otherwise use default
task_model.or(self.default.as_ref()).cloned()
} }
/// Check if any models are configured
pub fn is_empty(&self) -> bool {
self.chat.is_none() &&
self.code.is_none() &&
self.planning.is_none() &&
self.tool_use.is_none() &&
self.default.is_none()
} }
} }