use anyhow::Result;
use serde_json::Value;
use std::collections::HashMap;
use std::fmt::Debug;
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct SkillParameter {
pub name: String,
#[serde(rename = "type")]
pub param_type: String,
pub description: String,
#[serde(default)]
pub required: bool,
#[serde(default)]
pub default: Option<Value>,
#[serde(default)]
pub example: Option<Value>,
#[serde(default)]
pub enum_values: Option<Vec<String>>,
}
#[derive(Debug, Clone, serde::Serialize)]
pub struct SkillMetadata {
pub name: String,
pub description: String,
pub usage_hint: String,
pub parameters: Vec<SkillParameter>,
pub example_call: serde_json::Value,
pub example_output: String,
pub category: String,
}
#[async_trait::async_trait]
pub trait Skill: Send + Sync + Debug {
fn name(&self) -> &str;
fn description(&self) -> &str;
fn usage_hint(&self) -> &str {
"No usage hint provided"
}
fn parameters(&self) -> Vec<SkillParameter> {
vec![]
}
fn example_call(&self) -> serde_json::Value {
serde_json::json!({})
}
fn example_output(&self) -> String {
String::new()
}
fn category(&self) -> &str {
"general"
}
async fn execute(&self, parameters: &HashMap<String, Value>) -> Result<String>;
fn validate(&self, parameters: &HashMap<String, Value>) -> Result<()> {
Ok(())
}
fn get_metadata(&self) -> SkillMetadata {
SkillMetadata {
name: self.name().to_string(),
description: self.description().to_string(),
usage_hint: self.usage_hint().to_string(),
parameters: self.parameters(),
example_call: self.example_call(),
example_output: self.example_output(),
category: self.category().to_string(),
}
}
}
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
pub struct SkillCall {
pub action: String,
#[serde(default)]
pub parameters: HashMap<String, Value>,
}