use rig::tool::{Tool, ToolContext};
use serde::{Deserialize, Serialize};
use serde_json::json;
use std::sync::Arc;
use tokio::sync::Mutex;
use crate::common::package_resolver::PackageResolver;
#[derive(Debug, Deserialize, Serialize)]
pub struct FindPackageArgs {
pattern: String,
}
pub struct FindPackage {
dependencies: Arc<Mutex<PackageResolver>>,
}
impl FindPackage {
pub fn new(dependencies: Arc<Mutex<PackageResolver>>) -> Self {
Self { dependencies }
}
}
impl Tool for FindPackage {
const NAME: &'static str = "find_package";
type Error = super::ToolError;
type Args = FindPackageArgs;
type Output = Vec<String>;
#[tracing::instrument(skip(self, _context))]
async fn call(
&self,
_context: &mut ToolContext,
args: Self::Args,
) -> Result<Self::Output, Self::Error> {
let dependencies = self.dependencies.lock().await;
Ok(dependencies.search_dependency(&args.pattern))
}
fn description(&self) -> String {
"Find all packages/dependencies whose name matches the provided pattern. \
Returns a list of identifiers for the packages that match the pattern. \
Each identifier follows the format `{package_manager}:name@version` (e.g., `cargo:tokio@1.42.0`)."
.to_string()
}
fn parameters(&self) -> serde_json::Value {
json!({
"type": "object",
"properties": {
"pattern": {
"type": "string",
"description": "Text pattern to search for within package or dependency names. \
Performs a **substring match** (e.g., `\"tokio\"` will match both `\"tokio\"` and `\"tokio-util\"`). \
Use short keywords rather than full descriptions."
},
},
"required": ["pattern"]
})
}
fn map_error(&self, error: Self::Error) -> rig::tool::ToolExecutionError {
rig::tool::ToolExecutionError::from_error(error)
}
}