use crate::contracts::runtime::{StopPolicy, ToolExecutor};
use crate::contracts::StopConditionSpec;
use crate::runtime::loop_runner::{
AgentConfig, LlmRetryPolicy, ParallelToolExecutor, SequentialToolExecutor,
};
use genai::chat::ChatOptions;
use std::sync::Arc;
#[derive(Clone)]
pub struct AgentDefinition {
pub id: String,
pub model: String,
pub system_prompt: String,
pub max_rounds: usize,
pub parallel_tools: bool,
pub chat_options: Option<ChatOptions>,
pub fallback_models: Vec<String>,
pub llm_retry_policy: LlmRetryPolicy,
pub plugin_ids: Vec<String>,
pub allowed_tools: Option<Vec<String>>,
pub excluded_tools: Option<Vec<String>>,
pub allowed_skills: Option<Vec<String>>,
pub excluded_skills: Option<Vec<String>>,
pub allowed_agents: Option<Vec<String>>,
pub excluded_agents: Option<Vec<String>>,
pub stop_condition_specs: Vec<StopConditionSpec>,
pub stop_condition_ids: Vec<String>,
}
impl Default for AgentDefinition {
fn default() -> Self {
Self {
id: "default".to_string(),
model: "gpt-4o-mini".to_string(),
system_prompt: String::new(),
max_rounds: 10,
parallel_tools: true,
chat_options: Some(
ChatOptions::default()
.with_capture_usage(true)
.with_capture_reasoning_content(true)
.with_capture_tool_calls(true),
),
fallback_models: Vec::new(),
llm_retry_policy: LlmRetryPolicy::default(),
plugin_ids: Vec::new(),
allowed_tools: None,
excluded_tools: None,
allowed_skills: None,
excluded_skills: None,
allowed_agents: None,
excluded_agents: None,
stop_condition_specs: Vec::new(),
stop_condition_ids: Vec::new(),
}
}
}
impl std::fmt::Debug for AgentDefinition {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("AgentDefinition")
.field("id", &self.id)
.field("model", &self.model)
.field(
"system_prompt",
&format!("[{} chars]", self.system_prompt.len()),
)
.field("max_rounds", &self.max_rounds)
.field("parallel_tools", &self.parallel_tools)
.field("chat_options", &self.chat_options)
.field("fallback_models", &self.fallback_models)
.field("llm_retry_policy", &self.llm_retry_policy)
.field("plugin_ids", &self.plugin_ids)
.field("allowed_tools", &self.allowed_tools)
.field("excluded_tools", &self.excluded_tools)
.field("allowed_skills", &self.allowed_skills)
.field("excluded_skills", &self.excluded_skills)
.field("allowed_agents", &self.allowed_agents)
.field("excluded_agents", &self.excluded_agents)
.field("stop_condition_specs", &self.stop_condition_specs)
.field("stop_condition_ids", &self.stop_condition_ids)
.finish()
}
}
impl AgentDefinition {
tirea_contract::impl_shared_agent_builder_methods!();
#[must_use]
pub fn with_parallel_tools(mut self, parallel: bool) -> Self {
self.parallel_tools = parallel;
self
}
#[must_use]
pub fn with_plugin_ids(mut self, plugin_ids: Vec<String>) -> Self {
self.plugin_ids = plugin_ids;
self
}
#[must_use]
pub fn with_plugin_id(mut self, plugin_id: impl Into<String>) -> Self {
self.plugin_ids.push(plugin_id.into());
self
}
#[must_use]
pub fn with_stop_condition_id(mut self, id: impl Into<String>) -> Self {
self.stop_condition_ids.push(id.into());
self
}
#[must_use]
pub fn with_stop_condition_ids(mut self, ids: Vec<String>) -> Self {
self.stop_condition_ids = ids;
self
}
#[must_use]
pub fn with_allowed_tools(mut self, tools: Vec<String>) -> Self {
self.allowed_tools = Some(tools);
self
}
#[must_use]
pub fn with_excluded_tools(mut self, tools: Vec<String>) -> Self {
self.excluded_tools = Some(tools);
self
}
#[must_use]
pub fn with_allowed_skills(mut self, skills: Vec<String>) -> Self {
self.allowed_skills = Some(skills);
self
}
#[must_use]
pub fn with_excluded_skills(mut self, skills: Vec<String>) -> Self {
self.excluded_skills = Some(skills);
self
}
#[must_use]
pub fn with_allowed_agents(mut self, agents: Vec<String>) -> Self {
self.allowed_agents = Some(agents);
self
}
#[must_use]
pub fn with_excluded_agents(mut self, agents: Vec<String>) -> Self {
self.excluded_agents = Some(agents);
self
}
pub(crate) fn into_loop_config(
self,
plugins: Vec<Arc<dyn crate::contracts::plugin::AgentPlugin>>,
stop_conditions: Vec<Arc<dyn StopPolicy>>,
) -> AgentConfig {
let tool_executor: Arc<dyn ToolExecutor> = if self.parallel_tools {
Arc::new(ParallelToolExecutor)
} else {
Arc::new(SequentialToolExecutor)
};
AgentConfig {
id: self.id,
model: self.model,
system_prompt: self.system_prompt,
max_rounds: self.max_rounds,
tool_executor,
chat_options: self.chat_options,
fallback_models: self.fallback_models,
llm_retry_policy: self.llm_retry_policy,
plugins,
stop_conditions,
stop_condition_specs: self.stop_condition_specs,
step_tool_provider: None,
llm_executor: None,
}
}
}