add summary tool
This commit is contained in:
@@ -76,6 +76,10 @@ pub struct CodeToolConfig {
|
|||||||
/// By default (false), non-UTF-8 files are skipped entirely.
|
/// By default (false), non-UTF-8 files are skipped entirely.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub include_non_utf8: bool,
|
pub include_non_utf8: bool,
|
||||||
|
/// Path to a file containing a summary/description of the codebase.
|
||||||
|
/// If present, the agent can request a summary of the repository.
|
||||||
|
#[serde(default)]
|
||||||
|
pub summary_file: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ pub struct CodeTool {
|
|||||||
config: CodeToolConfig,
|
config: CodeToolConfig,
|
||||||
source: ResolvedSource,
|
source: ResolvedSource,
|
||||||
glob_filter: Option<GlobSet>,
|
glob_filter: Option<GlobSet>,
|
||||||
|
summary: Option<Box<str>>,
|
||||||
get_sha: ShaCallback,
|
get_sha: ShaCallback,
|
||||||
client: reqwest::Client,
|
client: reqwest::Client,
|
||||||
cache: Mutex<Option<CachedTarball>>,
|
cache: Mutex<Option<CachedTarball>>,
|
||||||
@@ -91,10 +92,18 @@ impl CodeTool {
|
|||||||
})?)
|
})?)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Load summary from file if configured
|
||||||
|
let summary = config
|
||||||
|
.summary_file
|
||||||
|
.as_ref()
|
||||||
|
.map(|path| std::fs::read_to_string(path).map(|s| s.into_boxed_str()))
|
||||||
|
.transpose()?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
config,
|
config,
|
||||||
source,
|
source,
|
||||||
glob_filter,
|
glob_filter,
|
||||||
|
summary,
|
||||||
get_sha,
|
get_sha,
|
||||||
client: reqwest::Client::new(),
|
client: reqwest::Client::new(),
|
||||||
cache: Mutex::new(None),
|
cache: Mutex::new(None),
|
||||||
@@ -106,6 +115,16 @@ impl CodeTool {
|
|||||||
&self.config.name
|
&self.config.name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if this code tool has a summary available.
|
||||||
|
pub fn has_summary(&self) -> bool {
|
||||||
|
self.summary.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the summary of the codebase, if available.
|
||||||
|
pub fn summary(&self) -> Option<&str> {
|
||||||
|
self.summary.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the current tarball, downloading or reading from file as needed.
|
/// Get the current tarball, downloading or reading from file as needed.
|
||||||
///
|
///
|
||||||
/// Returns a mutex guard containing the cached tarball. This method never fails;
|
/// Returns a mutex guard containing the cached tarball. This method never fails;
|
||||||
@@ -482,6 +501,15 @@ impl CodeToolTools {
|
|||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join(", ")
|
.join(", ")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get list of app names that have summaries available.
|
||||||
|
fn apps_with_summaries(&self) -> Vec<&str> {
|
||||||
|
self.apps
|
||||||
|
.iter()
|
||||||
|
.filter(|a| a.has_summary())
|
||||||
|
.map(|a| a.name())
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
@@ -513,10 +541,15 @@ struct SearchInput {
|
|||||||
path_prefix: Option<String>,
|
path_prefix: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct SummaryInput {
|
||||||
|
app: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl ToolExecutor for CodeToolTools {
|
impl ToolExecutor for CodeToolTools {
|
||||||
fn tools(&self) -> Vec<Tool> {
|
fn tools(&self) -> Vec<Tool> {
|
||||||
vec![
|
let mut tools = vec![
|
||||||
Tool {
|
Tool {
|
||||||
name: "code_ls",
|
name: "code_ls",
|
||||||
description: "List files in a directory of an application's source code.",
|
description: "List files in a directory of an application's source code.",
|
||||||
@@ -605,11 +638,35 @@ impl ToolExecutor for CodeToolTools {
|
|||||||
"required": ["app", "pattern"]
|
"required": ["app", "pattern"]
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
|
// Only include summary tool if at least one app has a summary
|
||||||
|
let apps_with_summaries = self.apps_with_summaries();
|
||||||
|
if !apps_with_summaries.is_empty() {
|
||||||
|
tools.push(Tool {
|
||||||
|
name: "code_summary",
|
||||||
|
description: "Get a summary/overview of an application's codebase.",
|
||||||
|
input_schema: serde_json::json!({
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"app": {
|
||||||
|
"type": "string",
|
||||||
|
"description": format!("Name of the application. Apps with summaries: {}", apps_with_summaries.join(", "))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["app"]
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
tools
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_tool(&self, name: &str) -> bool {
|
fn has_tool(&self, name: &str) -> bool {
|
||||||
matches!(name, "code_ls" | "code_find" | "code_read" | "code_search")
|
matches!(
|
||||||
|
name,
|
||||||
|
"code_ls" | "code_find" | "code_read" | "code_search" | "code_summary"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn execute(&self, name: &str, input: &serde_json::Value) -> Result<ToolResult, String> {
|
async fn execute(&self, name: &str, input: &serde_json::Value) -> Result<ToolResult, String> {
|
||||||
@@ -670,6 +727,25 @@ impl ToolExecutor for CodeToolTools {
|
|||||||
.await?;
|
.await?;
|
||||||
Ok(ToolResult::new(result))
|
Ok(ToolResult::new(result))
|
||||||
}
|
}
|
||||||
|
"code_summary" => {
|
||||||
|
let input: SummaryInput = serde_json::from_value(input.clone())
|
||||||
|
.map_err(|e| format!("Invalid input: {e}"))?;
|
||||||
|
let app = self.find_app(&input.app).ok_or_else(|| {
|
||||||
|
format!(
|
||||||
|
"Unknown app '{}'. Available: {}",
|
||||||
|
input.app,
|
||||||
|
self.app_names()
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
let summary = app.summary().ok_or_else(|| {
|
||||||
|
format!(
|
||||||
|
"No summary available for '{}'. Apps with summaries: {}",
|
||||||
|
input.app,
|
||||||
|
self.apps_with_summaries().join(", ")
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
Ok(ToolResult::new(summary.to_string()))
|
||||||
|
}
|
||||||
_ => Err(format!("Unknown tool: {name}")),
|
_ => Err(format!("Unknown tool: {name}")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ fn create_test_repo_code_with_glob(glob: Vec<String>) -> CodeTool {
|
|||||||
},
|
},
|
||||||
glob,
|
glob,
|
||||||
include_non_utf8: false,
|
include_non_utf8: false,
|
||||||
|
summary_file: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let sha = TEST_SHA.to_string();
|
let sha = TEST_SHA.to_string();
|
||||||
|
|||||||
Reference in New Issue
Block a user