use rustc_hash::FxHashMap;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct ForgeConfig {
pub forge: ForgeMetadata,
#[serde(default)]
pub tools: Vec<ToolDef>,
#[serde(default)]
pub resources: Vec<ResourceDef>,
#[serde(default)]
pub prompts: Vec<PromptDef>,
#[serde(default)]
pub state: Option<StateDef>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ForgeMetadata {
pub name: String,
pub version: String,
#[serde(default = "default_transport")]
pub transport: TransportType,
#[serde(default)]
pub optimization: OptimizationLevel,
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum TransportType {
Stdio,
Sse,
#[serde(rename = "websocket")]
WebSocket,
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, Default)]
#[serde(rename_all = "lowercase")]
pub enum OptimizationLevel {
#[default]
Debug,
Release,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ToolDef {
Native {
name: String,
description: String,
handler: HandlerRef,
params: ParamSchema,
#[serde(default)]
timeout_ms: Option<u64>,
},
Cli {
name: String,
description: String,
command: String,
args: Vec<String>,
#[serde(default)]
cwd: Option<String>,
#[serde(default)]
env: FxHashMap<String, String>,
#[serde(default)]
stream: bool,
#[serde(default)]
timeout_ms: Option<u64>,
},
Http {
name: String,
description: String,
endpoint: String,
method: HttpMethod,
#[serde(default)]
auth: Option<AuthConfig>,
#[serde(default)]
headers: FxHashMap<String, String>,
#[serde(default)]
timeout_ms: Option<u64>,
},
Pipeline {
name: String,
description: String,
steps: Vec<PipelineStep>,
},
}
impl ToolDef {
pub fn name(&self) -> &str {
match self {
Self::Native { name, .. }
| Self::Cli { name, .. }
| Self::Http { name, .. }
| Self::Pipeline { name, .. } => name,
}
}
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct HandlerRef {
pub path: String,
#[serde(default)]
pub inline: Option<String>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ParamSchema {
#[serde(flatten)]
pub fields: FxHashMap<String, ParamType>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(untagged)]
pub enum ParamType {
Simple(SimpleType),
Complex {
#[serde(rename = "type")]
ty: SimpleType,
#[serde(default)]
required: bool,
#[serde(default)]
default: Option<serde_json::Value>,
#[serde(default)]
description: Option<String>,
#[serde(default)]
validation: Option<Validation>,
},
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum SimpleType {
String,
Integer,
Float,
Boolean,
Array,
Object,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Validation {
#[serde(default)]
pub min: Option<f64>,
#[serde(default)]
pub max: Option<f64>,
#[serde(default)]
pub pattern: Option<String>,
#[serde(default)]
pub min_length: Option<usize>,
#[serde(default)]
pub max_length: Option<usize>,
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "UPPERCASE")]
pub enum HttpMethod {
Get,
Post,
Put,
Delete,
Patch,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(tag = "type", rename_all = "lowercase")]
pub enum AuthConfig {
Bearer { token: String },
Basic { username: String, password: String },
ApiKey { key: String, header: String },
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct PipelineStep {
pub tool: String,
#[serde(default)]
pub input: Option<serde_json::Value>,
#[serde(default)]
pub output_var: Option<String>,
#[serde(default)]
pub condition: Option<String>,
#[serde(default)]
pub error_policy: ErrorPolicy,
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, Default)]
#[serde(rename_all = "snake_case")]
pub enum ErrorPolicy {
#[default]
FailFast,
Continue,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ResourceDef {
pub uri_template: String,
pub handler: HandlerRef,
#[serde(default)]
pub supports: Vec<ResourceOperation>,
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum ResourceOperation {
Read,
Write,
Subscribe,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct PromptDef {
pub name: String,
pub description: String,
pub template: String,
#[serde(default)]
pub arguments: FxHashMap<String, ParamType>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct StateDef {
pub backend: StateBackend,
pub path: String,
#[serde(default)]
pub options: FxHashMap<String, serde_json::Value>,
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum StateBackend {
Sled,
Memory,
}
const fn default_transport() -> TransportType {
TransportType::Stdio
}