1use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
6pub struct QueryRequest {
7 pub message: String,
9 pub session_id: Option<String>,
11 pub agent: Option<String>,
13 #[serde(default)]
15 pub stream: bool,
16 pub temperature: Option<f32>,
18 pub max_tokens: Option<usize>,
20}
21
22#[derive(Debug, Clone, Serialize, Deserialize)]
24pub struct QueryResponse {
25 pub response: String,
27 pub session_id: String,
29 pub agent: String,
31 #[serde(skip_serializing_if = "Vec::is_empty", default)]
33 pub tool_calls: Vec<ToolCallInfo>,
34 pub metadata: ResponseMetadata,
36}
37
38#[derive(Debug, Clone, Serialize, Deserialize)]
40pub struct ToolCallInfo {
41 pub name: String,
43 pub arguments: serde_json::Value,
45 pub success: bool,
47 #[serde(skip_serializing_if = "Option::is_none")]
49 pub output: Option<String>,
50 #[serde(skip_serializing_if = "Option::is_none")]
52 pub error: Option<String>,
53}
54
55#[derive(Debug, Clone, Serialize, Deserialize)]
57pub struct ResponseMetadata {
58 pub timestamp: String,
60 pub model: String,
62 pub processing_time_ms: u64,
64 pub run_id: String,
66}
67
68#[derive(Debug, Clone, Serialize, Deserialize)]
70#[serde(tag = "type")]
71pub enum StreamChunk {
72 #[serde(rename = "start")]
74 Start { session_id: String, agent: String },
75 #[serde(rename = "chunk")]
77 Content { text: String },
78 #[serde(rename = "tool_call")]
80 ToolCall {
81 name: String,
82 arguments: serde_json::Value,
83 },
84 #[serde(rename = "tool_result")]
86 ToolResult {
87 name: String,
88 result: serde_json::Value,
89 },
90 #[serde(rename = "end")]
92 End { metadata: ResponseMetadata },
93 #[serde(rename = "error")]
95 Error { message: String },
96}
97
98#[derive(Debug, Clone, Serialize, Deserialize)]
100pub struct ErrorResponse {
101 pub error: String,
103 pub code: String,
105 #[serde(skip_serializing_if = "Option::is_none")]
107 pub details: Option<serde_json::Value>,
108}
109
110impl ErrorResponse {
111 pub fn new(code: impl Into<String>, error: impl Into<String>) -> Self {
112 Self {
113 error: error.into(),
114 code: code.into(),
115 details: None,
116 }
117 }
118
119 pub fn with_details(mut self, details: serde_json::Value) -> Self {
120 self.details = Some(details);
121 self
122 }
123}
124
125#[derive(Debug, Clone, Serialize, Deserialize)]
127pub struct HealthResponse {
128 pub status: String,
130 pub version: String,
132 pub uptime_seconds: u64,
134 pub active_sessions: usize,
136}
137
138#[derive(Debug, Clone, Serialize, Deserialize)]
140pub struct AgentListResponse {
141 pub agents: Vec<AgentInfo>,
143}
144
145#[derive(Debug, Clone, Serialize, Deserialize)]
147pub struct AgentInfo {
148 pub id: String,
150 pub description: String,
152 #[serde(skip_serializing_if = "Vec::is_empty", default)]
154 pub allowed_tools: Vec<String>,
155 #[serde(skip_serializing_if = "Vec::is_empty", default)]
157 pub denied_tools: Vec<String>,
158}
159
160#[cfg(test)]
161mod tests {
162 use super::*;
163
164 #[test]
165 fn test_query_request_serialization() {
166 let req = QueryRequest {
167 message: "Hello".to_string(),
168 session_id: Some("sess123".to_string()),
169 agent: Some("coder".to_string()),
170 stream: false,
171 temperature: Some(0.7),
172 max_tokens: Some(1000),
173 };
174
175 let json = serde_json::to_string(&req).unwrap();
176 let deserialized: QueryRequest = serde_json::from_str(&json).unwrap();
177
178 assert_eq!(deserialized.message, "Hello");
179 assert_eq!(deserialized.session_id, Some("sess123".to_string()));
180 }
181
182 #[test]
183 fn test_query_response_serialization() {
184 let resp = QueryResponse {
185 response: "Hi there".to_string(),
186 session_id: "sess123".to_string(),
187 agent: "coder".to_string(),
188 tool_calls: vec![],
189 metadata: ResponseMetadata {
190 timestamp: "2024-01-01T00:00:00Z".to_string(),
191 model: "mock".to_string(),
192 processing_time_ms: 100,
193 run_id: "run-1".to_string(),
194 },
195 };
196
197 let json = serde_json::to_string(&resp).unwrap();
198 let deserialized: QueryResponse = serde_json::from_str(&json).unwrap();
199
200 assert_eq!(deserialized.response, "Hi there");
201 assert_eq!(deserialized.session_id, "sess123");
202 }
203
204 #[test]
205 fn test_stream_chunk_variants() {
206 let chunks = vec![
207 StreamChunk::Start {
208 session_id: "sess1".to_string(),
209 agent: "coder".to_string(),
210 },
211 StreamChunk::Content {
212 text: "Hello".to_string(),
213 },
214 StreamChunk::End {
215 metadata: ResponseMetadata {
216 timestamp: "2024-01-01T00:00:00Z".to_string(),
217 model: "mock".to_string(),
218 processing_time_ms: 100,
219 run_id: "run-1".to_string(),
220 },
221 },
222 ];
223
224 for chunk in chunks {
225 let json = serde_json::to_string(&chunk).unwrap();
226 let _deserialized: StreamChunk = serde_json::from_str(&json).unwrap();
227 }
228 }
229
230 #[test]
231 fn test_error_response() {
232 let err = ErrorResponse::new("invalid_request", "Invalid API key")
233 .with_details(serde_json::json!({"hint": "Check your configuration"}));
234
235 assert_eq!(err.error, "Invalid API key");
236 assert_eq!(err.code, "invalid_request");
237 assert!(err.details.is_some());
238 }
239
240 #[test]
241 fn test_health_response() {
242 let health = HealthResponse {
243 status: "healthy".to_string(),
244 version: "0.1.0".to_string(),
245 uptime_seconds: 3600,
246 active_sessions: 5,
247 };
248
249 let json = serde_json::to_string(&health).unwrap();
250 let deserialized: HealthResponse = serde_json::from_str(&json).unwrap();
251
252 assert_eq!(deserialized.status, "healthy");
253 assert_eq!(deserialized.uptime_seconds, 3600);
254 }
255}