1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3
4#[derive(Debug, Clone, Deserialize, Serialize)]
6#[serde(deny_unknown_fields)]
7pub struct ForgeConfig {
8 pub forge: ForgeMetadata,
9 #[serde(default)]
10 pub tools: Vec<ToolDef>,
11 #[serde(default)]
12 pub resources: Vec<ResourceDef>,
13 #[serde(default)]
14 pub prompts: Vec<PromptDef>,
15 #[serde(default)]
16 pub state: Option<StateDef>,
17}
18
19#[derive(Debug, Clone, Deserialize, Serialize)]
20pub struct ForgeMetadata {
21 pub name: String,
22 pub version: String,
23 #[serde(default = "default_transport")]
24 pub transport: TransportType,
25 #[serde(default)]
26 pub optimization: OptimizationLevel,
27}
28
29#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
30#[serde(rename_all = "lowercase")]
31pub enum TransportType {
32 Stdio,
33 Sse,
34 #[serde(rename = "websocket")]
35 WebSocket,
36}
37
38#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
39#[serde(rename_all = "lowercase")]
40pub enum OptimizationLevel {
41 Debug,
42 Release,
43}
44
45#[derive(Debug, Clone, Deserialize, Serialize)]
46#[serde(tag = "type", rename_all = "snake_case")]
47pub enum ToolDef {
48 Native {
49 name: String,
50 description: String,
51 handler: HandlerRef,
52 params: ParamSchema,
53 #[serde(default)]
54 timeout_ms: Option<u64>,
55 },
56 Cli {
57 name: String,
58 description: String,
59 command: String,
60 args: Vec<String>,
61 #[serde(default)]
62 cwd: Option<String>,
63 #[serde(default)]
64 env: HashMap<String, String>,
65 #[serde(default)]
66 stream: bool,
67 },
68 Http {
69 name: String,
70 description: String,
71 endpoint: String,
72 method: HttpMethod,
73 #[serde(default)]
74 auth: Option<AuthConfig>,
75 #[serde(default)]
76 headers: HashMap<String, String>,
77 },
78 Pipeline {
79 name: String,
80 description: String,
81 steps: Vec<PipelineStep>,
82 },
83}
84
85impl ToolDef {
86 pub fn name(&self) -> &str {
87 match self {
88 ToolDef::Native { name, .. } => name,
89 ToolDef::Cli { name, .. } => name,
90 ToolDef::Http { name, .. } => name,
91 ToolDef::Pipeline { name, .. } => name,
92 }
93 }
94}
95
96#[derive(Debug, Clone, Deserialize, Serialize)]
97pub struct HandlerRef {
98 pub path: String,
99 #[serde(default)]
100 pub inline: Option<String>,
101}
102
103#[derive(Debug, Clone, Deserialize, Serialize)]
104pub struct ParamSchema {
105 #[serde(flatten)]
106 pub fields: HashMap<String, ParamType>,
107}
108
109#[derive(Debug, Clone, Deserialize, Serialize)]
110#[serde(untagged)]
111pub enum ParamType {
112 Simple(SimpleType),
113 Complex {
114 #[serde(rename = "type")]
115 ty: SimpleType,
116 #[serde(default)]
117 required: bool,
118 #[serde(default)]
119 default: Option<serde_json::Value>,
120 #[serde(default)]
121 description: Option<String>,
122 #[serde(default)]
123 validation: Option<Validation>,
124 },
125}
126
127#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
128#[serde(rename_all = "lowercase")]
129pub enum SimpleType {
130 String,
131 Integer,
132 Float,
133 Boolean,
134 Array,
135 Object,
136}
137
138#[derive(Debug, Clone, Deserialize, Serialize)]
139pub struct Validation {
140 #[serde(default)]
141 pub min: Option<f64>,
142 #[serde(default)]
143 pub max: Option<f64>,
144 #[serde(default)]
145 pub pattern: Option<String>,
146 #[serde(default)]
147 pub min_length: Option<usize>,
148 #[serde(default)]
149 pub max_length: Option<usize>,
150}
151
152#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
153#[serde(rename_all = "UPPERCASE")]
154pub enum HttpMethod {
155 Get,
156 Post,
157 Put,
158 Delete,
159 Patch,
160}
161
162#[derive(Debug, Clone, Deserialize, Serialize)]
163#[serde(tag = "type", rename_all = "lowercase")]
164pub enum AuthConfig {
165 Bearer { token: String },
166 Basic { username: String, password: String },
167 ApiKey { key: String, header: String },
168}
169
170#[derive(Debug, Clone, Deserialize, Serialize)]
171pub struct PipelineStep {
172 pub tool: String,
173 #[serde(default)]
174 pub input: Option<serde_json::Value>,
175 #[serde(default)]
176 pub output_var: Option<String>,
177 #[serde(default)]
178 pub condition: Option<String>,
179 #[serde(default)]
180 pub error_policy: ErrorPolicy,
181}
182
183#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
184#[serde(rename_all = "snake_case")]
185pub enum ErrorPolicy {
186 FailFast,
187 Continue,
188}
189
190#[derive(Debug, Clone, Deserialize, Serialize)]
191pub struct ResourceDef {
192 pub uri_template: String,
193 pub handler: HandlerRef,
194 #[serde(default)]
195 pub supports: Vec<ResourceOperation>,
196}
197
198#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
199#[serde(rename_all = "lowercase")]
200pub enum ResourceOperation {
201 Read,
202 Write,
203 Subscribe,
204}
205
206#[derive(Debug, Clone, Deserialize, Serialize)]
207pub struct PromptDef {
208 pub name: String,
209 pub description: String,
210 pub template: String,
211 #[serde(default)]
212 pub arguments: HashMap<String, ParamType>,
213}
214
215#[derive(Debug, Clone, Deserialize, Serialize)]
216pub struct StateDef {
217 pub backend: StateBackend,
218 pub path: String,
219 #[serde(default)]
220 pub options: HashMap<String, serde_json::Value>,
221}
222
223#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
224#[serde(rename_all = "lowercase")]
225pub enum StateBackend {
226 Sled,
227 Memory,
228}
229
230fn default_transport() -> TransportType {
231 TransportType::Stdio
232}
233
234impl Default for OptimizationLevel {
235 fn default() -> Self {
236 Self::Debug
237 }
238}
239
240impl Default for ErrorPolicy {
241 fn default() -> Self {
242 Self::FailFast
243 }
244}