claude_code_acp/agent/
core.rs

1//! Core ACP Agent structure
2//!
3//! The ClaudeAcpAgent holds shared state and configuration for handling
4//! ACP protocol requests.
5
6use std::sync::Arc;
7
8use crate::session::SessionManager;
9use crate::types::AgentConfig;
10
11/// Claude ACP Agent
12///
13/// The main agent struct that holds configuration and session state.
14/// This is shared across all request handlers.
15///
16/// Configuration is loaded from (in priority order):
17/// 1. Environment variables (e.g., ANTHROPIC_MODEL, ANTHROPIC_BASE_URL)
18/// 2. Settings files (~/.claude/settings.json, .claude/settings.json, etc.)
19/// 3. Defaults
20#[derive(Debug)]
21pub struct ClaudeAcpAgent {
22    /// Agent configuration from environment
23    config: AgentConfig,
24    /// Session manager for tracking active sessions
25    sessions: Arc<SessionManager>,
26}
27
28impl ClaudeAcpAgent {
29    /// Create a new agent with configuration from environment and settings files
30    ///
31    /// Configuration is loaded from:
32    /// 1. Environment variables (highest priority)
33    /// 2. Settings files (~/.claude/settings.json, .claude/settings.json, etc.)
34    /// 3. Defaults
35    pub fn new() -> Self {
36        let project_dir = std::env::current_dir().unwrap_or_else(|_| std::path::PathBuf::from("."));
37
38        let config = AgentConfig::from_settings_or_env(&project_dir);
39
40        tracing::info!(
41            model = ?config.model,
42            base_url = ?config.base_url,
43            api_key = ?config.masked_api_key(),
44            "Agent initialized with configuration"
45        );
46
47        Self {
48            config,
49            sessions: Arc::new(SessionManager::new()),
50        }
51    }
52
53    /// Create with custom configuration
54    pub fn with_config(config: AgentConfig) -> Self {
55        Self {
56            config,
57            sessions: Arc::new(SessionManager::new()),
58        }
59    }
60
61    /// Get the agent configuration
62    pub fn config(&self) -> &AgentConfig {
63        &self.config
64    }
65
66    /// Get the session manager
67    pub fn sessions(&self) -> &Arc<SessionManager> {
68        &self.sessions
69    }
70
71    /// Get agent name for logging
72    pub fn name(&self) -> &'static str {
73        "claude-code-acp-rs"
74    }
75
76    /// Get agent version
77    pub fn version(&self) -> &'static str {
78        env!("CARGO_PKG_VERSION")
79    }
80}
81
82impl Default for ClaudeAcpAgent {
83    fn default() -> Self {
84        Self::new()
85    }
86}
87
88#[cfg(test)]
89mod tests {
90    use super::*;
91
92    #[test]
93    fn test_agent_new() {
94        let agent = ClaudeAcpAgent::new();
95        assert_eq!(agent.name(), "claude-code-acp-rs");
96        assert_eq!(agent.sessions().session_count(), 0);
97    }
98
99    #[test]
100    fn test_agent_with_config() {
101        let config = AgentConfig {
102            base_url: Some("https://api.example.com".to_string()),
103            api_key: Some("test-key".to_string()),
104            model: Some("claude-3-opus".to_string()),
105            small_fast_model: None,
106            max_thinking_tokens: Some(4096),
107        };
108
109        let agent = ClaudeAcpAgent::with_config(config);
110        assert_eq!(
111            agent.config().base_url,
112            Some("https://api.example.com".to_string())
113        );
114        assert_eq!(agent.config().max_thinking_tokens, Some(4096));
115    }
116}