syncable_cli/agent/tools/
analyze.rs1use rig::completion::ToolDefinition;
4use rig::tool::Tool;
5use serde::{Deserialize, Serialize};
6use serde_json::json;
7use std::path::PathBuf;
8
9#[derive(Debug, Deserialize)]
11pub struct AnalyzeArgs {
12 pub path: Option<String>,
14}
15
16#[derive(Debug, thiserror::Error)]
18#[error("Analysis error: {0}")]
19pub struct AnalyzeError(String);
20
21#[derive(Debug, Clone, Serialize, Deserialize)]
23pub struct AnalyzeTool {
24 project_path: PathBuf,
25}
26
27impl AnalyzeTool {
28 pub fn new(project_path: PathBuf) -> Self {
29 Self { project_path }
30 }
31}
32
33impl Tool for AnalyzeTool {
34 const NAME: &'static str = "analyze_project";
35
36 type Error = AnalyzeError;
37 type Args = AnalyzeArgs;
38 type Output = String;
39
40 async fn definition(&self, _prompt: String) -> ToolDefinition {
41 ToolDefinition {
42 name: Self::NAME.to_string(),
43 description: "Analyze the project to detect programming languages, frameworks, dependencies, build tools, and architecture patterns. Returns a comprehensive overview of the project's technology stack.".to_string(),
44 parameters: json!({
45 "type": "object",
46 "properties": {
47 "path": {
48 "type": "string",
49 "description": "Optional subdirectory path to analyze (relative to project root). If not provided, analyzes the entire project."
50 }
51 }
52 }),
53 }
54 }
55
56 async fn call(&self, args: Self::Args) -> Result<Self::Output, Self::Error> {
57 let path = if let Some(subpath) = args.path {
58 self.project_path.join(subpath)
59 } else {
60 self.project_path.clone()
61 };
62
63 match crate::analyzer::analyze_project(&path) {
64 Ok(analysis) => serde_json::to_string_pretty(&analysis)
65 .map_err(|e| AnalyzeError(format!("Failed to serialize: {}", e))),
66 Err(e) => Err(AnalyzeError(format!("Analysis failed: {}", e))),
67 }
68 }
69}