use async_trait::async_trait;
#[derive(Clone, Debug)]
pub struct SkillContext {
pub content: String,
pub metadata: Option<std::collections::HashMap<String, String>>,
}
impl SkillContext {
pub fn new(content: String) -> Self {
Self {
content,
metadata: None,
}
}
pub fn with_metadata(
content: String,
metadata: std::collections::HashMap<String, String>,
) -> Self {
Self {
content,
metadata: Some(metadata),
}
}
}
#[async_trait]
pub trait Skill: Send + Sync {
fn name(&self) -> String;
fn description(&self) -> String;
async fn load_context(&self) -> Result<SkillContext, Box<dyn std::error::Error>>;
fn should_load(&self, _input: &str) -> bool {
false
}
}
pub struct SimpleSkill {
name: String,
description: String,
context: SkillContext,
}
impl SimpleSkill {
pub fn new(name: String, description: String, context: SkillContext) -> Self {
Self {
name,
description,
context,
}
}
pub fn with_context(name: String, description: String, context: String) -> Self {
Self {
name,
description,
context: SkillContext::new(context),
}
}
}
#[async_trait]
impl Skill for SimpleSkill {
fn name(&self) -> String {
self.name.clone()
}
fn description(&self) -> String {
self.description.clone()
}
async fn load_context(&self) -> Result<SkillContext, Box<dyn std::error::Error>> {
Ok(self.context.clone())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_simple_skill() {
let skill = SimpleSkill::with_context(
"test_skill".to_string(),
"A test skill".to_string(),
"Test context content".to_string(),
);
assert_eq!(skill.name(), "test_skill");
assert_eq!(skill.description(), "A test skill");
let context = skill.load_context().await.unwrap();
assert_eq!(context.content, "Test context content");
}
#[test]
fn test_skill_context() {
let context = SkillContext::new("Test content".to_string());
assert_eq!(context.content, "Test content");
assert!(context.metadata.is_none());
}
}