1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
5pub struct SkillManifest {
6 pub name: String,
7 pub version: String,
8 pub description: String,
9 pub capabilities: Vec<String>,
10 pub inputs: Vec<SkillIO>,
11 pub outputs: Vec<SkillIO>,
12 #[serde(default)]
13 pub dependencies: Vec<String>,
14 #[serde(default)]
15 pub has_code: bool,
16}
17
18#[derive(Debug, Clone, Serialize, Deserialize)]
19pub struct SkillIO {
20 pub name: String,
21 pub r#type: String,
22 #[serde(default)]
23 pub required: bool,
24 pub description: Option<String>,
25}
26
27#[derive(Debug, Clone, Serialize, Deserialize)]
28pub struct SkillConfig {
29 pub endpoints: Vec<SkillEndpoint>,
30 #[serde(default)]
31 pub auth_ref: Option<String>,
32 #[serde(default)]
33 pub extra: HashMap<String, serde_json::Value>,
34}
35
36#[derive(Debug, Clone, Serialize, Deserialize)]
37pub struct SkillEndpoint {
38 pub name: String,
39 pub url: String,
40 pub method: HttpMethod,
41 #[serde(default)]
42 pub headers: HashMap<String, String>,
43}
44
45#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
46#[serde(rename_all = "UPPERCASE")]
47pub enum HttpMethod {
48 Get,
49 Post,
50 Put,
51 Delete,
52 Patch,
53}
54
55impl SkillManifest {
56 pub fn from_toml(content: &str) -> Result<Self, toml::de::Error> {
57 toml::from_str(content)
58 }
59}
60
61impl SkillConfig {
62 pub fn from_toml(content: &str) -> Result<Self, toml::de::Error> {
63 toml::from_str(content)
64 }
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70
71 #[test]
72 fn parse_skill_manifest() {
73 let toml_str = r#"
74name = "web-search"
75version = "0.1.0"
76description = "Search the web for information"
77capabilities = ["search", "summarize"]
78has_code = false
79dependencies = []
80
81[[inputs]]
82name = "query"
83type = "string"
84required = true
85description = "Search query"
86
87[[outputs]]
88name = "results"
89type = "array"
90required = true
91description = "Search results"
92"#;
93 let manifest = SkillManifest::from_toml(toml_str).unwrap();
94 assert_eq!(manifest.name, "web-search");
95 assert_eq!(manifest.capabilities.len(), 2);
96 assert!(manifest.inputs[0].required);
97 }
98
99 #[test]
100 fn parse_skill_config() {
101 let toml_str = r#"
102auth_ref = "SEARCH_API_KEY"
103
104[[endpoints]]
105name = "search"
106url = "https://api.search.com/v1/search"
107method = "GET"
108
109[endpoints.headers]
110Accept = "application/json"
111"#;
112 let config = SkillConfig::from_toml(toml_str).unwrap();
113 assert_eq!(config.endpoints[0].method, HttpMethod::Get);
114 assert_eq!(config.auth_ref.unwrap(), "SEARCH_API_KEY");
115 }
116}