diff --git a/crates/owlen-cli/tests/agent_tests.rs b/crates/owlen-cli/tests/agent_tests.rs index 5650eb6..3e978cb 100644 --- a/crates/owlen-cli/tests/agent_tests.rs +++ b/crates/owlen-cli/tests/agent_tests.rs @@ -82,10 +82,9 @@ async fn test_agent_single_tool_scenario() { model: "llama3.2".to_string(), temperature: Some(0.7), max_tokens: None, - max_tool_calls: 10, }; - let executor = AgentExecutor::new(provider, mcp_client, config, None); + let executor = AgentExecutor::new(provider, mcp_client, config); // Simple query that should complete in one tool call let result = executor @@ -93,9 +92,12 @@ async fn test_agent_single_tool_scenario() { .await; match result { - Ok(answer) => { - assert!(!answer.is_empty(), "Answer should not be empty"); - println!("Agent answer: {}", answer); + Ok(agent_result) => { + assert!( + !agent_result.answer.is_empty(), + "Answer should not be empty" + ); + println!("Agent answer: {}", agent_result.answer); } Err(e) => { // It's okay if this fails due to LLM not following format @@ -116,10 +118,9 @@ async fn test_agent_multi_step_workflow() { model: "llama3.2".to_string(), temperature: Some(0.5), // Lower temperature for more consistent behavior max_tokens: None, - max_tool_calls: 20, }; - let executor = AgentExecutor::new(provider, mcp_client, config, None); + let executor = AgentExecutor::new(provider, mcp_client, config); // Query requiring multiple steps: list -> read -> analyze let result = executor @@ -127,9 +128,9 @@ async fn test_agent_multi_step_workflow() { .await; match result { - Ok(answer) => { - assert!(!answer.is_empty()); - println!("Multi-step answer: {}", answer); + Ok(agent_result) => { + assert!(!agent_result.answer.is_empty()); + println!("Multi-step answer: {:?}", agent_result); } Err(e) => { println!("Multi-step test skipped: {}", e); @@ -148,10 +149,9 @@ async fn test_agent_iteration_limit() { model: "llama3.2".to_string(), temperature: Some(0.7), max_tokens: None, - max_tool_calls: 5, }; - let executor = AgentExecutor::new(provider, mcp_client, config, None); + let executor = AgentExecutor::new(provider, mcp_client, config); // Complex query that would require many iterations let result = executor @@ -186,14 +186,13 @@ async fn test_agent_tool_budget_enforcement() { let mcp_client = Arc::clone(&provider) as Arc; let config = AgentConfig { - max_iterations: 20, + max_iterations: 3, // Very low iteration limit to enforce budget model: "llama3.2".to_string(), temperature: Some(0.7), max_tokens: None, - max_tool_calls: 3, // Very low tool call budget }; - let executor = AgentExecutor::new(provider, mcp_client, config, None); + let executor = AgentExecutor::new(provider, mcp_client, config); // Query that would require many tool calls let result = executor @@ -238,7 +237,7 @@ fn create_test_executor() -> AgentExecutor { let mcp_client = Arc::clone(&provider) as Arc; let config = AgentConfig::default(); - AgentExecutor::new(provider, mcp_client, config, None) + AgentExecutor::new(provider, mcp_client, config) } #[test] @@ -248,7 +247,7 @@ fn test_agent_config_defaults() { assert_eq!(config.max_iterations, 10); assert_eq!(config.model, "ollama"); assert_eq!(config.temperature, Some(0.7)); - assert_eq!(config.max_tool_calls, 20); + // max_tool_calls field removed - agent now tracks iterations instead } #[test] @@ -258,12 +257,10 @@ fn test_agent_config_custom() { model: "custom-model".to_string(), temperature: Some(0.5), max_tokens: Some(2000), - max_tool_calls: 30, }; assert_eq!(config.max_iterations, 15); assert_eq!(config.model, "custom-model"); assert_eq!(config.temperature, Some(0.5)); assert_eq!(config.max_tokens, Some(2000)); - assert_eq!(config.max_tool_calls, 30); } diff --git a/crates/owlen-core/src/agent.rs b/crates/owlen-core/src/agent.rs index 1958fa3..7c8b5f1 100644 --- a/crates/owlen-core/src/agent.rs +++ b/crates/owlen-core/src/agent.rs @@ -235,7 +235,7 @@ impl AgentExecutor { } /// Parse LLM response into structured format - fn parse_response(&self, text: &str) -> Result { + pub fn parse_response(&self, text: &str) -> Result { let lines: Vec<&str> = text.lines().collect(); let mut thought = String::new(); let mut action = String::new(); @@ -370,8 +370,8 @@ mod tests { #[test] fn test_parse_tool_call() { let executor = AgentExecutor { - llm_client: Arc::new(MockProvider::new()), - tool_client: Arc::new(MockMcpClient::new()), + llm_client: Arc::new(MockProvider), + tool_client: Arc::new(MockMcpClient), config: AgentConfig::default(), }; @@ -399,8 +399,8 @@ ACTION_INPUT: {"query": "Rust programming language"} #[test] fn test_parse_final_answer() { let executor = AgentExecutor { - llm_client: Arc::new(MockProvider::new()), - tool_client: Arc::new(MockMcpClient::new()), + llm_client: Arc::new(MockProvider), + tool_client: Arc::new(MockMcpClient), config: AgentConfig::default(), }; diff --git a/crates/owlen-core/src/lib.rs b/crates/owlen-core/src/lib.rs index 391dc54..a0c82c0 100644 --- a/crates/owlen-core/src/lib.rs +++ b/crates/owlen-core/src/lib.rs @@ -34,10 +34,15 @@ pub use credentials::*; pub use encryption::*; pub use formatting::*; pub use input::*; -pub use mcp::*; +// Export MCP types but exclude test_utils to avoid ambiguity +pub use mcp::{ + client, factory, failover, permission, protocol, remote_client, LocalMcpClient, McpServer, + McpToolCall, McpToolDescriptor, McpToolResponse, +}; pub use mode::*; pub use model::*; -pub use provider::*; +// Export provider types but exclude test_utils to avoid ambiguity +pub use provider::{ChatStream, Provider, ProviderConfig, ProviderRegistry}; pub use router::*; pub use sandbox::*; pub use session::*; diff --git a/crates/owlen-core/src/mcp.rs b/crates/owlen-core/src/mcp.rs index 0e91c1d..24a99ae 100644 --- a/crates/owlen-core/src/mcp.rs +++ b/crates/owlen-core/src/mcp.rs @@ -149,14 +149,9 @@ pub mod test_utils { use super::*; /// Mock MCP client for testing + #[derive(Default)] pub struct MockMcpClient; - impl MockMcpClient { - pub fn new() -> Self { - Self - } - } - #[async_trait] impl McpClient for MockMcpClient { async fn list_tools(&self) -> Result> { diff --git a/crates/owlen-core/src/provider.rs b/crates/owlen-core/src/provider.rs index e5539a0..ed9a019 100644 --- a/crates/owlen-core/src/provider.rs +++ b/crates/owlen-core/src/provider.rs @@ -181,14 +181,9 @@ pub mod test_utils { use crate::types::{ChatRequest, ChatResponse, Message, ModelInfo, Role}; /// Mock provider for testing + #[derive(Default)] pub struct MockProvider; - impl MockProvider { - pub fn new() -> Self { - Self - } - } - #[async_trait::async_trait] impl Provider for MockProvider { fn name(&self) -> &str { diff --git a/crates/owlen-core/tests/file_server.rs b/crates/owlen-core/tests/file_server.rs index 490a11b..9215706 100644 --- a/crates/owlen-core/tests/file_server.rs +++ b/crates/owlen-core/tests/file_server.rs @@ -1,6 +1,5 @@ -use owlen_core::mcp::client::McpClient; use owlen_core::mcp::remote_client::RemoteMcpClient; -use owlen_core::mcp::McpToolCall; +use owlen_core::McpToolCall; use std::fs::File; use std::io::Write; use tempfile::tempdir; @@ -22,7 +21,7 @@ async fn remote_file_server_read_and_list() { .join("../..") .join("Cargo.toml"); let build_status = std::process::Command::new("cargo") - .args(&["build", "-p", "owlen-mcp-server", "--manifest-path"]) + .args(["build", "-p", "owlen-mcp-server", "--manifest-path"]) .arg(manifest_path) .status() .expect("failed to run cargo build for MCP server"); diff --git a/crates/owlen-core/tests/file_write.rs b/crates/owlen-core/tests/file_write.rs index 921f31d..fe48d4b 100644 --- a/crates/owlen-core/tests/file_write.rs +++ b/crates/owlen-core/tests/file_write.rs @@ -1,13 +1,12 @@ -use owlen_core::mcp::client::McpClient; use owlen_core::mcp::remote_client::RemoteMcpClient; -use owlen_core::mcp::McpToolCall; +use owlen_core::McpToolCall; use tempfile::tempdir; #[tokio::test] async fn remote_write_and_delete() { // Build the server binary first let status = std::process::Command::new("cargo") - .args(&["build", "-p", "owlen-mcp-server"]) + .args(["build", "-p", "owlen-mcp-server"]) .status() .expect("failed to build MCP server"); assert!(status.success()); @@ -42,7 +41,7 @@ async fn remote_write_and_delete() { async fn write_outside_root_is_rejected() { // Build server (already built in previous test, but ensure it exists) let status = std::process::Command::new("cargo") - .args(&["build", "-p", "owlen-mcp-server"]) + .args(["build", "-p", "owlen-mcp-server"]) .status() .expect("failed to build MCP server"); assert!(status.success()); diff --git a/crates/owlen-core/tests/mode_tool_filter.rs b/crates/owlen-core/tests/mode_tool_filter.rs index a89f862..5b77c6d 100644 --- a/crates/owlen-core/tests/mode_tool_filter.rs +++ b/crates/owlen-core/tests/mode_tool_filter.rs @@ -42,14 +42,16 @@ impl Tool for EchoTool { #[tokio::test] async fn test_tool_allowed_in_chat_mode() { // Build a config where the `echo` tool is explicitly allowed in chat. - let mut cfg = Config::default(); - cfg.modes = ModeConfig { - chat: ModeToolConfig { - allowed_tools: vec!["echo".to_string()], - }, - code: ModeToolConfig { - allowed_tools: vec!["*".to_string()], + let cfg = Config { + modes: ModeConfig { + chat: ModeToolConfig { + allowed_tools: vec!["echo".to_string()], + }, + code: ModeToolConfig { + allowed_tools: vec!["*".to_string()], + }, }, + ..Default::default() }; let cfg = Arc::new(Mutex::new(cfg)); @@ -70,17 +72,18 @@ async fn test_tool_allowed_in_chat_mode() { #[tokio::test] async fn test_tool_not_allowed_in_any_mode() { // Config that does NOT list `echo` in either mode. - let mut cfg = Config::default(); - cfg.modes = ModeConfig { - chat: ModeToolConfig { - allowed_tools: vec!["web_search".to_string()], - }, - code: ModeToolConfig { - allowed_tools: vec!["*".to_string()], // allow all in code + let cfg = Config { + modes: ModeConfig { + chat: ModeToolConfig { + allowed_tools: vec!["web_search".to_string()], + }, + code: ModeToolConfig { + // Strict denial - only web_search allowed + allowed_tools: vec!["web_search".to_string()], + }, }, + ..Default::default() }; - // Remove the wildcard for code to simulate strict denial. - cfg.modes.code.allowed_tools = vec!["web_search".to_string()]; let cfg = Arc::new(Mutex::new(cfg)); let ui: Arc = Arc::new(NoOpUiController); diff --git a/crates/owlen-mcp-llm-server/Cargo.toml b/crates/owlen-mcp-llm-server/Cargo.toml index 6cdd465..303cf70 100644 --- a/crates/owlen-mcp-llm-server/Cargo.toml +++ b/crates/owlen-mcp-llm-server/Cargo.toml @@ -12,9 +12,6 @@ serde_json = "1.0" anyhow = "1.0" tokio-stream = "0.1" -[lib] -path = "src/lib.rs" - [[bin]] name = "owlen-mcp-llm-server" -path = "src/lib.rs" +path = "src/main.rs" diff --git a/crates/owlen-mcp-llm-server/src/lib.rs b/crates/owlen-mcp-llm-server/src/main.rs similarity index 100% rename from crates/owlen-mcp-llm-server/src/lib.rs rename to crates/owlen-mcp-llm-server/src/main.rs