claude_agent/agent/
executor.rs

1//! Agent core structure and construction.
2
3use std::sync::Arc;
4
5use tokio::sync::RwLock;
6
7use super::config::AgentConfig;
8use crate::Client;
9use crate::budget::{BudgetTracker, TenantBudget};
10use crate::context::PromptOrchestrator;
11use crate::hooks::HookManager;
12use crate::tools::{ToolRegistry, ToolRegistryBuilder};
13use crate::types::Message;
14
15pub struct Agent {
16    pub(crate) client: Client,
17    pub(crate) config: AgentConfig,
18    pub(crate) tools: Arc<ToolRegistry>,
19    pub(crate) hooks: HookManager,
20    pub(crate) session_id: String,
21    pub(crate) orchestrator: Option<Arc<RwLock<PromptOrchestrator>>>,
22    pub(crate) initial_messages: Option<Vec<Message>>,
23    pub(crate) budget_tracker: BudgetTracker,
24    pub(crate) tenant_budget: Option<Arc<TenantBudget>>,
25    pub(crate) mcp_manager: Option<Arc<crate::mcp::McpManager>>,
26}
27
28impl Agent {
29    pub fn new(client: Client, config: AgentConfig) -> Self {
30        let tools = ToolRegistry::default_tools(
31            &config.security.tool_access,
32            config.working_dir.clone(),
33            Some(config.security.permission_policy.clone()),
34        );
35        Self::from_parts(client, config, Arc::new(tools), HookManager::new(), None)
36    }
37
38    pub fn with_skills(
39        client: Client,
40        config: AgentConfig,
41        skill_executor: crate::skills::SkillExecutor,
42    ) -> Self {
43        let mut builder = ToolRegistryBuilder::new()
44            .access(&config.security.tool_access)
45            .skill_executor(skill_executor)
46            .policy(config.security.permission_policy.clone());
47
48        if let Some(dir) = config.working_dir.clone() {
49            builder = builder.working_dir(dir);
50        }
51
52        let tools = builder.build();
53        Self::from_parts(client, config, Arc::new(tools), HookManager::new(), None)
54    }
55
56    pub fn with_components(
57        client: Client,
58        config: AgentConfig,
59        tools: ToolRegistry,
60        hooks: HookManager,
61    ) -> Self {
62        Self::from_parts(client, config, Arc::new(tools), hooks, None)
63    }
64
65    pub fn with_orchestrator(
66        client: Client,
67        config: AgentConfig,
68        tools: Arc<ToolRegistry>,
69        hooks: HookManager,
70        orchestrator: PromptOrchestrator,
71    ) -> Self {
72        Self::from_parts(
73            client,
74            config,
75            tools,
76            hooks,
77            Some(Arc::new(RwLock::new(orchestrator))),
78        )
79    }
80
81    pub fn with_shared_tools(
82        client: Client,
83        config: AgentConfig,
84        tools: Arc<ToolRegistry>,
85        hooks: HookManager,
86    ) -> Self {
87        Self::from_parts(client, config, tools, hooks, None)
88    }
89
90    fn from_parts(
91        client: Client,
92        config: AgentConfig,
93        tools: Arc<ToolRegistry>,
94        hooks: HookManager,
95        orchestrator: Option<Arc<RwLock<PromptOrchestrator>>>,
96    ) -> Self {
97        let budget_tracker = match config.budget.max_cost_usd {
98            Some(max) => BudgetTracker::new(max),
99            None => BudgetTracker::unlimited(),
100        };
101
102        Self {
103            client,
104            config,
105            tools,
106            hooks,
107            session_id: uuid::Uuid::new_v4().to_string(),
108            orchestrator,
109            initial_messages: None,
110            budget_tracker,
111            tenant_budget: None,
112            mcp_manager: None,
113        }
114    }
115
116    pub fn with_tenant_budget(mut self, budget: Arc<TenantBudget>) -> Self {
117        self.tenant_budget = Some(budget);
118        self
119    }
120
121    pub fn with_mcp_manager(mut self, manager: Arc<crate::mcp::McpManager>) -> Self {
122        self.mcp_manager = Some(manager);
123        self
124    }
125
126    pub fn mcp_manager(&self) -> Option<&Arc<crate::mcp::McpManager>> {
127        self.mcp_manager.as_ref()
128    }
129
130    pub fn with_initial_messages(mut self, messages: Vec<Message>) -> Self {
131        self.initial_messages = Some(messages);
132        self
133    }
134
135    pub fn with_session_id(mut self, id: impl Into<String>) -> Self {
136        self.session_id = id.into();
137        self
138    }
139
140    #[must_use]
141    pub fn builder() -> super::AgentBuilder {
142        super::AgentBuilder::new()
143    }
144
145    pub fn with_model(model: impl Into<String>) -> super::AgentBuilder {
146        super::AgentBuilder::new().model(model)
147    }
148
149    pub async fn default_agent() -> crate::Result<Self> {
150        Self::builder().build().await
151    }
152
153    #[must_use]
154    pub fn hooks(&self) -> &HookManager {
155        &self.hooks
156    }
157
158    #[must_use]
159    pub fn session_id(&self) -> &str {
160        &self.session_id
161    }
162
163    pub fn orchestrator(&self) -> Option<&Arc<RwLock<PromptOrchestrator>>> {
164        self.orchestrator.as_ref()
165    }
166
167    #[must_use]
168    pub fn config(&self) -> &AgentConfig {
169        &self.config
170    }
171
172    #[must_use]
173    pub fn tools(&self) -> &Arc<ToolRegistry> {
174        &self.tools
175    }
176}