diff --git a/Cargo.lock b/Cargo.lock index f0c900f..f9cef43 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1935,8 +1935,8 @@ dependencies = [ "serde_json", "signal-gateway", "signal-gateway-assistant-claude", + "signal-gateway-code-tool", "signal-gateway-log-ingest", - "signal-gateway-repo-code", "tokio", "tokio-util", "toml", @@ -1945,6 +1945,23 @@ dependencies = [ "url", ] +[[package]] +name = "signal-gateway-code-tool" +version = "0.1.0" +dependencies = [ + "async-trait", + "flate2", + "globset", + "regex", + "reqwest", + "serde", + "serde_json", + "signal-gateway-assistant", + "tar", + "tokio", + "tracing", +] + [[package]] name = "signal-gateway-log-ingest" version = "0.1.0" @@ -1960,23 +1977,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "signal-gateway-repo-code" -version = "0.1.0" -dependencies = [ - "async-trait", - "flate2", - "globset", - "regex", - "reqwest", - "serde", - "serde_json", - "signal-gateway-assistant", - "tar", - "tokio", - "tracing", -] - [[package]] name = "signal-hook-registry" version = "1.4.7" diff --git a/Cargo.toml b/Cargo.toml index 1655887..2320883 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ resolver = "2" members = [ "prometheus-http-client", "signal-gateway", - "signal-gateway-repo-code", + "signal-gateway-code-tool", "signal-gateway-assistant", "signal-gateway-assistant/claude", "signal-gateway-bin", diff --git a/signal-gateway-bin/Cargo.toml b/signal-gateway-bin/Cargo.toml index d2a9875..cc4d729 100644 --- a/signal-gateway-bin/Cargo.toml +++ b/signal-gateway-bin/Cargo.toml @@ -18,7 +18,7 @@ rustls-tls = ["signal-gateway/rustls-tls"] [dependencies] signal-gateway = { workspace = true } signal-gateway-assistant-claude = { workspace = true } -signal-gateway-repo-code = { path = "../signal-gateway-repo-code" } +signal-gateway-code-tool = { path = "../signal-gateway-code-tool" } signal-gateway-log-ingest = { path = "../signal-gateway-log-ingest" } async-trait = { workspace = true } diff --git a/signal-gateway-bin/src/repo_code.rs b/signal-gateway-bin/src/code_tool.rs similarity index 82% rename from signal-gateway-bin/src/repo_code.rs rename to signal-gateway-bin/src/code_tool.rs index 40bc12d..1c162d4 100644 --- a/signal-gateway-bin/src/repo_code.rs +++ b/signal-gateway-bin/src/code_tool.rs @@ -1,24 +1,24 @@ //! Extended configuration for application source code browsing. use serde::Deserialize; -use signal_gateway_repo_code::{RepoCode, RepoCodeConfig, ShaCallback}; +use signal_gateway_code_tool::{CodeTool, CodeToolConfig, ShaCallback}; use std::sync::Arc; use tracing::warn; use url::Url; -/// Extended configuration for RepoCode with HTTP-based SHA fetching. +/// Extended configuration for CodeTool with HTTP-based SHA fetching. #[derive(Clone, Debug, Deserialize)] -pub struct RepoCodeConfigExt { - /// The base RepoCode configuration. +pub struct CodeToolConfigExt { + /// The base CodeTool configuration. #[serde(flatten)] - pub config: RepoCodeConfig, + pub config: CodeToolConfig, /// URL to GET the current deployed version SHA. pub version_sha_http_get: Url, } -impl RepoCodeConfigExt { - /// Convert to an RepoCode instance with HTTP-based SHA callback. - pub fn into_app_code(self) -> Result { +impl CodeToolConfigExt { + /// Convert to an CodeTool instance with HTTP-based SHA callback. + pub fn into_app_code(self) -> Result { let url = self.version_sha_http_get.clone(); let client = reqwest::Client::new(); @@ -66,6 +66,6 @@ impl RepoCodeConfigExt { }) }); - RepoCode::new(self.config, sha_callback) + CodeTool::new(self.config, sha_callback) } } diff --git a/signal-gateway-bin/src/main.rs b/signal-gateway-bin/src/main.rs index 6057956..d71b484 100644 --- a/signal-gateway-bin/src/main.rs +++ b/signal-gateway-bin/src/main.rs @@ -6,7 +6,7 @@ use conf::Conf; use metrics_exporter_prometheus::PrometheusBuilder; use signal_gateway::{CommandRouter, Gateway, GatewayConfig, Handling}; use signal_gateway_assistant_claude::{ClaudeAssistant, ClaudeConfig}; -use signal_gateway_repo_code::RepoCodeTools; +use signal_gateway_code_tool::CodeToolTools; use std::{env, fs, net::SocketAddr, path::PathBuf, sync::Arc}; use tokio::net::TcpListener; use tokio_util::sync::CancellationToken; @@ -16,8 +16,8 @@ use tracing_subscriber::EnvFilter; mod admin_http; use admin_http::AdminHttpConfig; -mod repo_code; -use repo_code::RepoCodeConfigExt; +mod code_tool; +use code_tool::CodeToolConfigExt; mod listen_http; use listen_http::start_http_task; @@ -51,7 +51,7 @@ pub struct Config { admin_http: Option, /// Application source code configurations for Claude tools. #[conf(long, env, value_parser = serde_json::from_str, default, default_help_str = "[]")] - app_code: Vec, + app_code: Vec, /// Claude API configuration for AI-powered responses. #[conf(flatten, prefix)] claude: Option, @@ -150,7 +150,7 @@ async fn main() -> Result<(), Box> { router_builder.build() }; - // Build RepoCode tools if configured + // Build CodeTool tools if configured let app_code_tools = if !config.app_code.is_empty() { let mut apps = Vec::new(); for app_config in config.app_code { @@ -163,7 +163,7 @@ async fn main() -> Result<(), Box> { } } } - Some(Arc::new(RepoCodeTools::new(apps))) + Some(Arc::new(CodeToolTools::new(apps))) } else { None }; diff --git a/signal-gateway-repo-code/Cargo.toml b/signal-gateway-code-tool/Cargo.toml similarity index 94% rename from signal-gateway-repo-code/Cargo.toml rename to signal-gateway-code-tool/Cargo.toml index d66ba30..5a9e561 100644 --- a/signal-gateway-repo-code/Cargo.toml +++ b/signal-gateway-code-tool/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "signal-gateway-repo-code" +name = "signal-gateway-code-tool" version = "0.1.0" edition.workspace = true diff --git a/signal-gateway-repo-code/src/config.rs b/signal-gateway-code-tool/src/config.rs similarity index 94% rename from signal-gateway-repo-code/src/config.rs rename to signal-gateway-code-tool/src/config.rs index d220550..b2f5a38 100644 --- a/signal-gateway-repo-code/src/config.rs +++ b/signal-gateway-code-tool/src/config.rs @@ -61,7 +61,7 @@ pub enum Source { /// Configuration for an application's source code access. #[derive(Clone, Debug, Deserialize, PartialEq, Eq)] -pub struct RepoCodeConfig { +pub struct CodeToolConfig { /// Name of the application (used to identify it in tool calls). pub name: String, /// Source of the repository code. @@ -92,7 +92,7 @@ mod tests { } }"#; - let config: RepoCodeConfig = serde_json::from_str(json).unwrap(); + let config: CodeToolConfig = serde_json::from_str(json).unwrap(); assert_eq!(config.name, "my-app"); assert_eq!( config.source, @@ -117,7 +117,7 @@ mod tests { } }"#; - let config: RepoCodeConfig = serde_json::from_str(json).unwrap(); + let config: CodeToolConfig = serde_json::from_str(json).unwrap(); assert_eq!(config.name, "public-app"); assert_eq!( config.source, @@ -140,7 +140,7 @@ mod tests { } }"#; - let config: RepoCodeConfig = serde_json::from_str(json).unwrap(); + let config: CodeToolConfig = serde_json::from_str(json).unwrap(); assert_eq!(config.name, "local-app"); assert_eq!( config.source, @@ -161,7 +161,7 @@ mod tests { "include_non_utf8": true }"#; - let config: RepoCodeConfig = serde_json::from_str(json).unwrap(); + let config: CodeToolConfig = serde_json::from_str(json).unwrap(); assert_eq!(config.name, "filtered-app"); assert_eq!(config.glob, vec!["**/*.rs", "Cargo.toml"]); assert!(config.include_non_utf8); diff --git a/signal-gateway-repo-code/src/lib.rs b/signal-gateway-code-tool/src/lib.rs similarity index 95% rename from signal-gateway-repo-code/src/lib.rs rename to signal-gateway-code-tool/src/lib.rs index 13b6246..0c58438 100644 --- a/signal-gateway-repo-code/src/lib.rs +++ b/signal-gateway-code-tool/src/lib.rs @@ -5,7 +5,7 @@ mod config; -pub use config::{GitHubRepo, RepoCodeConfig, Source}; +pub use config::{CodeToolConfig, GitHubRepo, Source}; use async_trait::async_trait; use flate2::read::GzDecoder; @@ -13,7 +13,9 @@ use globset::{Glob, GlobSet, GlobSetBuilder}; use regex::Regex; use serde::Deserialize; use signal_gateway_assistant::{Tool, ToolExecutor, ToolResult}; -use std::{collections::HashMap, error::Error, fmt::Write, future::Future, io::Read, pin::Pin, sync::Arc}; +use std::{ + collections::HashMap, error::Error, fmt::Write, future::Future, io::Read, pin::Pin, sync::Arc, +}; use tar::Archive; use tokio::sync::{Mutex, MutexGuard}; use tracing::{error, info, warn}; @@ -57,7 +59,7 @@ enum ResolvedSource { /// Application source code browser. /// /// Downloads and caches GitHub tarballs for browsing application source code. -pub struct RepoCode { +pub struct CodeTool { name: String, source: ResolvedSource, glob_filter: Option, @@ -67,13 +69,13 @@ pub struct RepoCode { cache: Mutex>, } -impl RepoCode { - /// Create a new RepoCode instance from configuration. +impl CodeTool { + /// Create a new CodeTool instance from configuration. /// /// The `get_sha` callback is called to determine which git SHA to download/load. /// For GitHub sources, this is the commit SHA. For file sources, this can be /// used to track file modification (e.g., mtime or a version string). - pub fn new(config: RepoCodeConfig, get_sha: ShaCallback) -> Result { + pub fn new(config: CodeToolConfig, get_sha: ShaCallback) -> Result { let source = match config.source { Source::GitHub { repo, token_file } => { let token = token_file @@ -90,20 +92,21 @@ impl RepoCode { }; // Compile glob patterns if any are specified - let glob_filter = if config.glob.is_empty() { - None - } else { - let mut builder = GlobSetBuilder::new(); - for pattern in &config.glob { - let glob = Glob::new(pattern).map_err(|e| { - std::io::Error::other(format!("invalid glob pattern '{}': {}", pattern, e)) - })?; - builder.add(glob); - } - Some(builder.build().map_err(|e| { - std::io::Error::other(format!("failed to build glob set: {}", e)) - })?) - }; + let glob_filter = + if config.glob.is_empty() { + None + } else { + let mut builder = GlobSetBuilder::new(); + for pattern in &config.glob { + let glob = Glob::new(pattern).map_err(|e| { + std::io::Error::other(format!("invalid glob pattern '{}': {}", pattern, e)) + })?; + builder.add(glob); + } + Some(builder.build().map_err(|e| { + std::io::Error::other(format!("failed to build glob set: {}", e)) + })?) + }; Ok(Self { name: config.name, @@ -187,9 +190,8 @@ impl RepoCode { self.download_tarball_from_github(owner, repo, token.as_deref(), sha) .await } - ResolvedSource::File { path } => std::fs::read(path).map_err(|e| { - format!("Failed to read tarball from {}: {e}", path.display()) - }), + ResolvedSource::File { path } => std::fs::read(path) + .map_err(|e| format!("Failed to read tarball from {}: {e}", path.display())), } } @@ -576,18 +578,18 @@ fn looks_binary(content: &str) -> bool { } /// Tool executor for multiple application source code browsers. -pub struct RepoCodeTools { - apps: Vec, +pub struct CodeToolTools { + apps: Vec, } -impl RepoCodeTools { - /// Create a new RepoCodeTools instance. - pub fn new(apps: Vec) -> Self { +impl CodeToolTools { + /// Create a new CodeToolTools instance. + pub fn new(apps: Vec) -> Self { Self { apps } } /// Find an app by name. - fn find_app(&self, name: &str) -> Option<&RepoCode> { + fn find_app(&self, name: &str) -> Option<&CodeTool> { self.apps.iter().find(|app| app.name() == name) } @@ -631,7 +633,7 @@ struct SearchInput { } #[async_trait] -impl ToolExecutor for RepoCodeTools { +impl ToolExecutor for CodeToolTools { fn tools(&self) -> Vec { vec![ Tool { diff --git a/signal-gateway-repo-code/tests/integration.rs b/signal-gateway-code-tool/tests/integration.rs similarity index 94% rename from signal-gateway-repo-code/tests/integration.rs rename to signal-gateway-code-tool/tests/integration.rs index d3e029b..77d07b8 100644 --- a/signal-gateway-repo-code/tests/integration.rs +++ b/signal-gateway-code-tool/tests/integration.rs @@ -1,9 +1,9 @@ -//! Integration tests for signal-gateway-repo-code. +//! Integration tests for signal-gateway-code-tool. //! //! These tests exercise the GitHub tarball download and file browsing functionality //! against a real public repository at a pinned commit. -use signal_gateway_repo_code::{GitHubRepo, RepoCode, RepoCodeConfig, ShaCallback, Source}; +use signal_gateway_code_tool::{CodeTool, CodeToolConfig, GitHubRepo, ShaCallback, Source}; use std::sync::Arc; /// Test against cbeck88/ver-stub-rs at a known commit. @@ -12,12 +12,12 @@ const TEST_OWNER: &str = "cbeck88"; const TEST_REPO: &str = "ver-stub-rs"; const TEST_SHA: &str = "79b98e25f27ae4f5dd73a5a3d8f37dad655a57e8"; -fn create_test_repo_code() -> RepoCode { +fn create_test_repo_code() -> CodeTool { create_test_repo_code_with_glob(vec![]) } -fn create_test_repo_code_with_glob(glob: Vec) -> RepoCode { - let config = RepoCodeConfig { +fn create_test_repo_code_with_glob(glob: Vec) -> CodeTool { + let config = CodeToolConfig { name: "test-app".to_string(), source: Source::GitHub { repo: GitHubRepo { @@ -36,7 +36,7 @@ fn create_test_repo_code_with_glob(glob: Vec) -> RepoCode { Box::pin(async move { Ok(sha) }) }); - RepoCode::new(config, sha_callback).expect("Failed to create RepoCode") + CodeTool::new(config, sha_callback).expect("Failed to create CodeTool") } #[tokio::test] @@ -276,7 +276,8 @@ async fn test_glob_filter_specific_directory() { #[tokio::test] async fn test_glob_filter_multiple_patterns() { // Include both Cargo.toml files and shell scripts - let app = create_test_repo_code_with_glob(vec!["**/Cargo.toml".to_string(), "*.sh".to_string()]); + let app = + create_test_repo_code_with_glob(vec!["**/Cargo.toml".to_string(), "*.sh".to_string()]); let result = app.find(Some("*")).await.expect("find failed");