1use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8
9use super::config::*;
10use super::error::ProtocolError;
11use super::request::UnifiedRequest;
12
13#[derive(Debug, Clone, Serialize, Deserialize)]
17pub struct ProtocolManifest {
18 #[serde(rename = "$schema", skip_serializing_if = "Option::is_none")]
19 pub schema: Option<String>,
20
21 pub id: String,
23 pub protocol_version: String,
24 pub endpoint: EndpointDefinition,
25 #[serde(default, skip_serializing_if = "Option::is_none")]
26 pub availability: Option<AvailabilityConfig>,
27 pub capabilities: Capabilities,
28
29 #[serde(skip_serializing_if = "Option::is_none")]
31 pub name: Option<String>,
32 #[serde(skip_serializing_if = "Option::is_none")]
33 pub provider_id: Option<String>,
34 #[serde(skip_serializing_if = "Option::is_none")]
35 pub version: Option<String>,
36 pub status: String, pub category: String, pub official_url: String,
39 pub support_contact: String,
40
41 #[serde(default, skip_serializing_if = "Option::is_none")]
43 pub auth: Option<AuthConfig>,
44 #[serde(skip_serializing_if = "Option::is_none")]
45 pub payload_format: Option<String>,
46 #[serde(default)]
47 pub parameter_mappings: HashMap<String, String>,
48 #[serde(skip_serializing_if = "Option::is_none")]
49 pub response_format: Option<String>,
50 #[serde(skip_serializing_if = "Option::is_none")]
51 pub response_paths: Option<HashMap<String, String>>,
52
53 #[serde(skip_serializing_if = "Option::is_none")]
55 pub streaming: Option<StreamingConfig>,
56 #[serde(skip_serializing_if = "Option::is_none")]
57 pub features: Option<FeaturesConfig>,
58
59 #[serde(skip_serializing_if = "Option::is_none")]
61 pub endpoints: Option<HashMap<String, EndpointConfig>>,
62 #[serde(skip_serializing_if = "Option::is_none")]
63 pub services: Option<HashMap<String, ServiceConfig>>,
64
65 #[serde(skip_serializing_if = "Option::is_none")]
67 pub api_families: Option<Vec<String>>,
68 #[serde(skip_serializing_if = "Option::is_none")]
69 pub default_api_family: Option<String>,
70
71 #[serde(skip_serializing_if = "Option::is_none")]
73 pub termination: Option<TerminationConfig>,
74 #[serde(skip_serializing_if = "Option::is_none")]
75 pub tooling: Option<ToolingConfig>,
76
77 #[serde(skip_serializing_if = "Option::is_none")]
79 pub retry_policy: Option<RetryPolicy>,
80 #[serde(skip_serializing_if = "Option::is_none")]
81 pub error_classification: Option<ErrorClassification>,
82 #[serde(skip_serializing_if = "Option::is_none")]
83 pub rate_limit_headers: Option<RateLimitHeaders>,
84
85 #[serde(skip_serializing_if = "Option::is_none")]
87 pub experimental_features: Option<Vec<String>>,
88 #[serde(skip_serializing_if = "Option::is_none")]
89 pub capability_profile: Option<serde_json::Value>,
90}
91
92impl ProtocolManifest {
93 pub fn supports_capability(&self, capability: &str) -> bool {
95 match capability {
96 "streaming" => self.capabilities.streaming,
97 "tools" => self.capabilities.tools,
98 "vision" => self.capabilities.vision,
99 "agentic" => self.capabilities.agentic,
100 "parallel_tools" => self.capabilities.parallel_tools,
101 "reasoning" => self.capabilities.reasoning,
102 "multimodal" => {
103 self.capabilities.multimodal || self.capabilities.vision || self.capabilities.audio
104 }
105 "audio" => self.capabilities.audio,
106 "structured_output" => self.capabilities.structured_output,
107 "mcp_client" => self.capabilities.mcp_client,
108 _ => false,
109 }
110 }
111
112 pub fn get_base_url(&self) -> &str {
114 &self.endpoint.base_url
115 }
116
117 pub fn compile_request(
119 &self,
120 request: &UnifiedRequest,
121 ) -> Result<serde_json::Value, ProtocolError> {
122 use crate::utils::PathMapper;
123
124 let mut provider_request = serde_json::json!({});
125
126 let model_path = self
128 .parameter_mappings
129 .get("model")
130 .map(|s| s.as_str())
131 .unwrap_or("model");
132 PathMapper::set_path(
133 &mut provider_request,
134 model_path,
135 serde_json::Value::String(request.model.clone()),
136 )
137 .map_err(|e| ProtocolError::ValidationError(format!("Failed to set model: {}", e)))?;
138
139 if let Some(temp) = request.temperature {
141 if let Some(mapped) = self.parameter_mappings.get("temperature") {
142 PathMapper::set_path(
143 &mut provider_request,
144 mapped,
145 serde_json::Value::Number(serde_json::Number::from_f64(temp).ok_or_else(
146 || ProtocolError::ValidationError("Invalid temperature".to_string()),
147 )?),
148 )
149 .map_err(|e| {
150 ProtocolError::ValidationError(format!("Failed to set temperature: {}", e))
151 })?;
152 }
153 }
154
155 if let Some(max) = request.max_tokens {
156 if let Some(mapped) = self.parameter_mappings.get("max_tokens") {
157 PathMapper::set_path(
158 &mut provider_request,
159 mapped,
160 serde_json::Value::Number(max.into()),
161 )
162 .map_err(|e| {
163 ProtocolError::ValidationError(format!("Failed to set max_tokens: {}", e))
164 })?;
165 }
166 }
167
168 if let Some(mapped) = self.parameter_mappings.get("stream") {
169 PathMapper::set_path(
170 &mut provider_request,
171 mapped,
172 serde_json::Value::Bool(request.stream),
173 )
174 .map_err(|e| ProtocolError::ValidationError(format!("Failed to set stream: {}", e)))?;
175 }
176
177 let messages_path = self
179 .parameter_mappings
180 .get("messages")
181 .map(|s| s.as_str())
182 .unwrap_or("messages");
183 let messages: Vec<serde_json::Value> = request
184 .messages
185 .iter()
186 .map(|m| serde_json::to_value(m).unwrap())
187 .collect();
188 PathMapper::set_path(
189 &mut provider_request,
190 messages_path,
191 serde_json::Value::Array(messages),
192 )
193 .map_err(|e| ProtocolError::ValidationError(format!("Failed to set messages: {}", e)))?;
194
195 if let Some(tools) = &request.tools {
197 if let Some(mapped) = self.parameter_mappings.get("tools") {
198 let tools_value: Vec<serde_json::Value> = tools
199 .iter()
200 .map(|t| serde_json::to_value(t).unwrap())
201 .collect();
202 PathMapper::set_path(
203 &mut provider_request,
204 mapped,
205 serde_json::Value::Array(tools_value),
206 )
207 .map_err(|e| {
208 ProtocolError::ValidationError(format!("Failed to set tools: {}", e))
209 })?;
210 }
211 }
212
213 if let Some(tool_choice) = &request.tool_choice {
215 if let Some(mapped) = self.parameter_mappings.get("tool_choice") {
216 PathMapper::set_path(&mut provider_request, mapped, tool_choice.clone()).map_err(
217 |e| ProtocolError::ValidationError(format!("Failed to set tool_choice: {}", e)),
218 )?;
219 }
220 }
221
222 if let Some(fmt) = &request.response_format {
223 let patch = fmt.to_openai_format();
224 if let serde_json::Value::Object(extra) = patch {
225 for (k, v) in extra {
226 provider_request[k] = v;
227 }
228 }
229 }
230
231 Ok(provider_request)
232 }
233}