Skip to main content

sh_layer3/
skills.rs

1//! # Skills
2//!
3//! Skills 模块:可复用的能力模块。
4
5use crate::types::{Layer3Result, ToolRequest, ToolResponse};
6use async_trait::async_trait;
7use serde::{Deserialize, Serialize};
8
9/// Skill trait
10///
11/// 定义可复用能力模块的接口。
12#[async_trait]
13pub trait Skill: Send + Sync {
14    /// Skill 名称
15    fn name(&self) -> &str;
16
17    /// Skill 描述
18    fn description(&self) -> &str;
19
20    /// Skill 版本
21    fn version(&self) -> &str {
22        "1.0.0"
23    }
24
25    /// 执行 Skill
26    async fn execute(&self, input: SkillInput) -> Layer3Result<SkillOutput>;
27
28    /// Skill 所需的工具列表
29    fn required_tools(&self) -> Vec<String>;
30
31    /// Skill 所需的权限
32    fn required_permissions(&self) -> Vec<String>;
33
34    /// 获取 Skill 配置 Schema
35    fn config_schema(&self) -> serde_json::Value;
36}
37
38/// Skill 输入
39#[derive(Debug, Clone, Serialize, Deserialize)]
40pub struct SkillInput {
41    /// 输入参数
42    pub params: serde_json::Value,
43    /// 上下文信息
44    pub context: SkillContext,
45}
46
47/// Skill 输出
48#[derive(Debug, Clone, Serialize, Deserialize)]
49pub struct SkillOutput {
50    /// 输出结果
51    pub result: serde_json::Value,
52    /// 状态
53    pub status: SkillStatus,
54    /// 生成的工具调用(可选)
55    pub tool_calls: Vec<ToolRequest>,
56    /// 工具结果(可选)
57    pub tool_results: Vec<ToolResponse>,
58}
59
60/// Skill 状态
61#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
62#[serde(rename_all = "snake_case")]
63pub enum SkillStatus {
64    Success,
65    Failed,
66    Pending,
67    NeedsApproval,
68    ToolCalling,
69}
70
71/// Skill 执行上下文
72#[derive(Debug, Clone, Serialize, Deserialize)]
73pub struct SkillContext {
74    /// 会话 ID
75    pub session_id: String,
76    /// 用户 ID
77    pub user_id: Option<String>,
78    /// 工作目录
79    pub working_dir: String,
80    /// 环境变量
81    pub env_vars: std::collections::HashMap<String, String>,
82}
83
84impl Default for SkillContext {
85    fn default() -> Self {
86        Self {
87            session_id: String::new(),
88            user_id: None,
89            working_dir: ".".to_string(),
90            env_vars: std::collections::HashMap::new(),
91        }
92    }
93}
94
95/// Skill 注册表
96pub struct SkillRegistry {
97    skills: std::collections::HashMap<String, Box<dyn Skill>>,
98}
99
100impl SkillRegistry {
101    pub fn new() -> Self {
102        Self {
103            skills: std::collections::HashMap::new(),
104        }
105    }
106
107    pub fn register(&mut self, skill: Box<dyn Skill>) {
108        self.skills.insert(skill.name().to_string(), skill);
109    }
110
111    pub fn get(&self, name: &str) -> Option<&dyn Skill> {
112        self.skills.get(name).map(|s| s.as_ref())
113    }
114
115    pub fn list(&self) -> Vec<&dyn Skill> {
116        self.skills.values().map(|s| s.as_ref()).collect()
117    }
118}
119
120impl Default for SkillRegistry {
121    fn default() -> Self {
122        Self::new()
123    }
124}
125
126#[cfg(test)]
127mod tests {
128    use super::*;
129
130    #[test]
131    fn test_skill_context_default() {
132        let ctx = SkillContext::default();
133        assert_eq!(ctx.working_dir, ".");
134    }
135
136    #[test]
137    fn test_skill_registry() {
138        let registry = SkillRegistry::new();
139        assert!(registry.list().is_empty());
140    }
141}