use std::sync::Arc;
use async_trait::async_trait;
use meerkat_core::ToolDef;
use meerkat_core::skills::{SkillFilter, SkillRuntime, SourceUuid};
use meerkat_core::types::{ToolProvenance, ToolSourceKind};
use serde::Deserialize;
use serde_json::{Value, json};
use crate::builtin::{BuiltinTool, BuiltinToolError, ToolOutput};
#[derive(Debug, Deserialize, schemars::JsonSchema)]
struct BrowseSkillsArgs {
#[serde(default)]
query: Option<String>,
#[serde(default)]
source_uuid: Option<String>,
}
pub struct BrowseSkillsTool {
engine: Arc<SkillRuntime>,
}
impl BrowseSkillsTool {
pub fn new(engine: Arc<SkillRuntime>) -> Self {
Self { engine }
}
}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl BuiltinTool for BrowseSkillsTool {
fn name(&self) -> &'static str {
"browse_skills"
}
fn def(&self) -> ToolDef {
ToolDef {
name: "browse_skills".into(),
description:
"List available skills, optionally filtered by search query or source UUID.".into(),
input_schema: crate::schema::schema_for::<BrowseSkillsArgs>(),
provenance: Some(ToolProvenance {
kind: ToolSourceKind::Builtin,
source_id: "skills".into(),
}),
}
}
fn default_enabled(&self) -> bool {
false
}
async fn call(&self, args: Value) -> Result<ToolOutput, BuiltinToolError> {
let args: BrowseSkillsArgs = serde_json::from_value(args)
.map_err(|err| BuiltinToolError::InvalidArgs(err.to_string()))?;
let source_uuid = match args.source_uuid.as_deref() {
Some(raw) => Some(
SourceUuid::parse(raw)
.map_err(|e| BuiltinToolError::ExecutionFailed(e.to_string()))?,
),
None => None,
};
let filter = SkillFilter {
query: args.query,
source_uuid,
};
let entries = self
.engine
.list_all_with_provenance(&filter)
.await
.map_err(|e| BuiltinToolError::ExecutionFailed(e.to_string()))?;
let skill_values: Vec<Value> = entries
.iter()
.filter(|entry| entry.is_active)
.map(|entry| {
let s = &entry.descriptor;
json!({
"source_uuid": s.key.source_uuid.to_string(),
"skill_name": s.key.skill_name.as_str(),
"name": s.name,
"description": s.description,
})
})
.collect();
Ok(ToolOutput::Json(json!({
"skills": skill_values,
})))
}
}