Skip to main content

matrixcode_core/agent/
builder.rs

1//! Agent builder implementation.
2
3use std::path::PathBuf;
4use std::sync::Arc;
5
6use crate::approval::ApproveMode;
7use crate::constants::QUICK_ACTION_MAX_TOKENS;
8use crate::event::AgentEvent;
9use crate::prompt::PromptProfile;
10use crate::providers::Provider;
11use crate::skills::Skill;
12use crate::tools::Tool;
13use crate::tools::toolproxy::{ProxyToolDef, ProxyToolExecutor};
14
15use super::types::{Agent, AgentBuilder};
16
17impl AgentBuilder {
18    pub fn new(provider: Box<dyn Provider>) -> Self {
19        Self {
20            provider,
21            model_name: "unknown".to_string(),
22            tools: Vec::new(),
23            system_prompt: "You are a helpful AI coding assistant.".to_string(),
24            max_tokens: QUICK_ACTION_MAX_TOKENS,
25            context_size_override: None,
26            think: false,
27            approve_mode: ApproveMode::Ask,
28            event_tx: None,
29            skills: Vec::new(),
30            profile: PromptProfile::Default,
31            project_overview: None,
32            memory_summary: None,
33            project_path: None,
34            proxy_tool_defs: Vec::new(),
35            proxy_executor: None,
36            mcp_registry: None,
37            lsp_registry: None,
38            pending_input_rx: None,
39        }
40    }
41
42    pub fn system_prompt(mut self, prompt: impl Into<String>) -> Self {
43        self.system_prompt = prompt.into();
44        self
45    }
46
47    pub fn model_name(mut self, name: impl Into<String>) -> Self {
48        self.model_name = name.into();
49        self
50    }
51
52    pub fn max_tokens(mut self, tokens: u32) -> Self {
53        self.max_tokens = tokens;
54        self
55    }
56
57    /// Override provider-inferred context window size.
58    pub fn context_size(mut self, context_size: Option<u32>) -> Self {
59        self.context_size_override = context_size;
60        self
61    }
62
63    pub fn think(mut self, enabled: bool) -> Self {
64        self.think = enabled;
65        self
66    }
67
68    pub fn approve_mode(mut self, mode: ApproveMode) -> Self {
69        self.approve_mode = mode;
70        self
71    }
72
73    pub fn tool(mut self, tool: Arc<dyn Tool>) -> Self {
74        self.tools.push(tool);
75        self
76    }
77
78    /// Add multiple tools
79    pub fn tools(mut self, tools: Vec<Box<dyn Tool>>) -> Self {
80        self.tools.extend(tools.into_iter().map(Arc::from));
81        self
82    }
83
84    /// Add multiple tools with provider support
85    pub fn tools_with_provider(mut self, tools: Vec<Box<dyn Tool>>) -> Self {
86        self.tools.extend(tools.into_iter().map(Arc::from));
87        self
88    }
89
90    /// Set external event sender for streaming events
91    pub fn event_tx(mut self, tx: tokio::sync::mpsc::Sender<AgentEvent>) -> Self {
92        self.event_tx = Some(tx);
93        self
94    }
95
96    /// Add skills
97    pub fn skills(mut self, skills: Vec<Skill>) -> Self {
98        self.skills = skills;
99        self
100    }
101
102    /// Set prompt profile
103    pub fn profile(mut self, profile: PromptProfile) -> Self {
104        self.profile = profile;
105        self
106    }
107
108    /// Set project overview
109    pub fn overview(mut self, overview: impl Into<String>) -> Self {
110        self.project_overview = Some(overview.into());
111        self
112    }
113
114    /// Set memory summary
115    pub fn memory(mut self, summary: impl Into<String>) -> Self {
116        self.memory_summary = Some(summary.into());
117        self
118    }
119
120    /// Set project path (for dynamic tool injection like CodeGraph)
121    pub fn project_path(mut self, path: PathBuf) -> Self {
122        self.project_path = Some(path);
123        self
124    }
125
126    /// 设置代理工具执行器
127    ///
128    /// # Example
129    /// ```ignore
130    /// use std::sync::Arc;
131    /// use serde_json::json;
132    /// use matrixcode_core::tools::toolproxy::{ProxyToolExecutor, ProxyToolDef};
133    ///
134    /// let executor = Arc::new(MyProxyExecutor);
135    /// let tool_def = ProxyToolDef::new("image_search", "搜索图片", json!({...}))
136    ///     .with_priority(true);
137    ///
138    /// builder.proxy_executor(executor, vec![tool_def])
139    /// ```
140    pub fn proxy_executor(
141        mut self,
142        executor: Arc<dyn ProxyToolExecutor>,
143        tool_defs: Vec<ProxyToolDef>,
144    ) -> Self {
145        self.proxy_executor = Some(executor);
146        self.proxy_tool_defs = tool_defs;
147        self
148    }
149
150    pub fn build(self) -> Agent {
151        Agent::new(self)
152    }
153
154    /// 设置 MCP 工具注册表
155    ///
156    /// # Example
157    /// ```ignore
158    /// use std::sync::Arc;
159    /// use matrixcode_core::mcp::McpToolRegistry;
160    ///
161    /// let registry = Arc::new(tokio::sync::RwLock::new(McpToolRegistry::new()));
162    /// builder.mcp_registry(registry)
163    /// ```
164    pub fn mcp_registry(
165        mut self,
166        registry: Arc<tokio::sync::RwLock<crate::mcp::McpToolRegistry>>,
167    ) -> Self {
168        self.mcp_registry = Some(registry);
169        self
170    }
171
172    /// 设置 LSP 客户端注册表
173    ///
174    /// # Example
175    /// ```ignore
176    /// use std::sync::Arc;
177    /// use matrixcode_core::lsp::LspClientRegistry;
178    ///
179    /// let registry = Arc::new(LspClientRegistry::new());
180    /// // 启动 LSP 服务器
181    /// registry.register(&config, &project_root).await?;
182    /// builder.lsp_registry(registry)
183    /// ```
184    pub fn lsp_registry(mut self, registry: Arc<crate::lsp::LspClientRegistry>) -> Self {
185        self.lsp_registry = Some(registry);
186        self
187    }
188
189    /// 设置实时追加消息接收器
190    ///
191    /// 允许在 Agent 处理过程中接收新消息,实现实时追加功能。
192    ///
193    /// # Example
194    /// ```ignore
195    /// let (pending_tx, pending_rx) = tokio::sync::mpsc::channel::<String>(100);
196    /// builder.pending_input_rx(pending_rx)
197    /// ```
198    pub fn pending_input_rx(mut self, rx: tokio::sync::mpsc::Receiver<String>) -> Self {
199        self.pending_input_rx = Some(rx);
200        self
201    }
202}