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