1use serde::{Deserialize, Serialize};
4use serde_json::Value;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
8#[serde(rename_all = "snake_case")]
9pub enum ArgType {
10 Any,
11 String,
12 Number,
13 Integer,
14 Boolean,
15 Object,
16 Array,
17}
18
19impl ArgType {
20 pub fn matches(self, value: &Value) -> bool {
21 match self {
22 ArgType::Any => true,
23 ArgType::String => value.is_string(),
24 ArgType::Number => value.is_number(),
25 ArgType::Integer => value.as_i64().is_some() || value.as_u64().is_some(),
26 ArgType::Boolean => value.is_boolean(),
27 ArgType::Object => value.is_object(),
28 ArgType::Array => value.is_array(),
29 }
30 }
31}
32
33#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
35pub struct ArgSpec {
36 pub name: String,
37 pub arg_type: ArgType,
38 pub required: bool,
39 #[serde(default, skip_serializing_if = "Option::is_none")]
40 pub description: Option<String>,
41}
42
43impl ArgSpec {
44 pub fn required(name: impl Into<String>, arg_type: ArgType) -> Self {
45 Self {
46 name: name.into(),
47 arg_type,
48 required: true,
49 description: None,
50 }
51 }
52
53 pub fn optional(name: impl Into<String>, arg_type: ArgType) -> Self {
54 Self {
55 name: name.into(),
56 arg_type,
57 required: false,
58 description: None,
59 }
60 }
61
62 pub fn describe(mut self, description: impl Into<String>) -> Self {
63 self.description = Some(description.into());
64 self
65 }
66}
67
68#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
70pub struct ArgSchema {
71 #[serde(default)]
72 pub args: Vec<ArgSpec>,
73 #[serde(default = "default_allow_extra_args")]
74 pub allow_extra: bool,
75}
76
77impl ArgSchema {
78 pub fn new() -> Self {
79 Self {
80 args: Vec::new(),
81 allow_extra: true,
82 }
83 }
84
85 pub fn strict() -> Self {
86 Self {
87 args: Vec::new(),
88 allow_extra: false,
89 }
90 }
91
92 pub fn required(mut self, name: impl Into<String>, arg_type: ArgType) -> Self {
93 self.args.push(ArgSpec::required(name, arg_type));
94 self
95 }
96
97 pub fn optional(mut self, name: impl Into<String>, arg_type: ArgType) -> Self {
98 self.args.push(ArgSpec::optional(name, arg_type));
99 self
100 }
101
102 pub fn allow_extra(mut self, allow_extra: bool) -> Self {
103 self.allow_extra = allow_extra;
104 self
105 }
106
107 pub fn get(&self, name: &str) -> Option<&ArgSpec> {
108 self.args.iter().find(|spec| spec.name == name)
109 }
110
111 pub fn has_required_args(&self) -> bool {
112 self.args.iter().any(|spec| spec.required)
113 }
114}
115
116impl Default for ArgSchema {
117 fn default() -> Self {
118 Self::new()
119 }
120}
121
122fn default_allow_extra_args() -> bool {
123 true
124}
125
126#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
127#[serde(rename_all = "snake_case")]
128pub enum RiskLevel {
129 Low,
130 Medium,
131 High,
132}
133
134#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
135#[serde(rename_all = "snake_case")]
136pub enum SideEffect {
137 None,
138 ReadFs,
139 WriteFs,
140 Shell,
141 Network,
142 Git,
143 Docker,
144 Llm,
145 Database,
146 Process,
147}
148
149#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
150#[serde(rename_all = "snake_case")]
151pub enum Capability {
152 ReadFs,
153 WriteFs,
154 Shell,
155 Network,
156 Git,
157 Docker,
158 Llm,
159 Database,
160 Process,
161}
162
163#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
165pub struct HandlerMetadata {
166 pub name: String,
167 #[serde(default)]
168 pub description: String,
169 #[serde(default)]
170 pub args: ArgSchema,
171 pub risk: RiskLevel,
172 #[serde(default)]
173 pub side_effects: Vec<SideEffect>,
174 #[serde(default)]
175 pub capabilities: Vec<Capability>,
176 #[serde(default = "default_deterministic")]
177 pub deterministic: bool,
178}
179
180impl HandlerMetadata {
181 pub fn new(name: impl Into<String>) -> Self {
182 Self {
183 name: name.into(),
184 description: String::new(),
185 args: ArgSchema::new(),
186 risk: RiskLevel::Low,
187 side_effects: vec![SideEffect::None],
188 capabilities: Vec::new(),
189 deterministic: true,
190 }
191 }
192
193 pub fn describe(mut self, description: impl Into<String>) -> Self {
194 self.description = description.into();
195 self
196 }
197
198 pub fn args(mut self, args: ArgSchema) -> Self {
199 self.args = args;
200 self
201 }
202
203 pub fn risk(mut self, risk: RiskLevel) -> Self {
204 self.risk = risk;
205 self
206 }
207
208 pub fn side_effects(mut self, side_effects: impl Into<Vec<SideEffect>>) -> Self {
209 self.side_effects = side_effects.into();
210 self
211 }
212
213 pub fn capabilities(mut self, capabilities: impl Into<Vec<Capability>>) -> Self {
214 self.capabilities = capabilities.into();
215 self
216 }
217
218 pub fn deterministic(mut self, deterministic: bool) -> Self {
219 self.deterministic = deterministic;
220 self
221 }
222}
223
224fn default_deterministic() -> bool {
225 true
226}