use std::sync::Arc; use crate::agent::{AgentError, AgentLoop, CompositeSystemPromptProvider}; use crate::config::LLMProviderConfig; use crate::gateway::agent_prompt_provider::AgentPromptProvider; use crate::gateway::todo_prompt_provider::TodoPromptProvider; use crate::skills::{SkillPromptProvider, SkillRuntime}; use crate::storage::persistent_session_id; use crate::storage::PromptInjectionRepository; use crate::tools::{ToolContext, ToolRegistry}; #[derive(Clone)] pub(crate) struct AgentFactory { tools: Arc, skills: Arc, reinject_every: usize, prompt_repository: Arc, } pub(crate) struct AgentBuildRequest<'a> { pub(crate) channel_name: &'a str, pub(crate) session_chat_id: &'a str, pub(crate) notification_chat_id: Option<&'a str>, pub(crate) sender_id: Option<&'a str>, pub(crate) message_id: Option<&'a str>, pub(crate) provider_config: LLMProviderConfig, /// 当前话题 ID(可选):用于 todo 等按 topic 隔离的工具 pub(crate) topic_id: Option, /// 取消信号接收端(可选):Agent 在每次迭代时检查是否被取消 pub(crate) cancel_token: Option>, } impl AgentFactory { pub(crate) fn new( tools: Arc, skills: Arc, reinject_every: usize, prompt_repository: Arc, ) -> Self { Self { tools, skills, reinject_every, prompt_repository, } } pub(crate) fn create(&self, request: AgentBuildRequest<'_>) -> Result { let session_id = persistent_session_id(request.channel_name, request.session_chat_id); // 创建组合的系统提示词提供者 let system_prompt_provider = Arc::new(CompositeSystemPromptProvider::new(vec![ Box::new(AgentPromptProvider::new( self.reinject_every, request.provider_config.clone(), self.prompt_repository.clone(), )), Box::new(SkillPromptProvider::new(self.skills.clone())), Box::new(TodoPromptProvider::new()), ])); AgentLoop::with_tools_and_system_prompt_provider( request.provider_config, self.tools.clone(), system_prompt_provider, Some(self.skills.clone()), ) .map(|agent| { // notification_chat_id 优先,否则使用 session_chat_id let tool_chat_id = request .notification_chat_id .unwrap_or(request.session_chat_id); let mut agent = agent.with_tool_context(ToolContext { channel_name: Some(request.channel_name.to_string()), sender_id: request.sender_id.map(str::to_string), chat_id: Some(tool_chat_id.to_string()), session_id: Some(session_id), topic_id: request.topic_id.clone(), message_id: request.message_id.map(str::to_string), message_seq: None, subagent_description: None, nesting_depth: 0, }); // 如果有取消信号接收端,注入 Agent if let Some(token) = request.cancel_token { agent = agent.with_cancel_token(token); } agent }) } }