mcp_langbase_reasoning/langbase/
types.rs1use serde::{Deserialize, Serialize};
6use std::collections::HashMap;
7use tracing::warn;
8
9#[cfg(test)]
10#[path = "types_tests.rs"]
11mod types_tests;
12
13#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct Message {
16 pub role: MessageRole,
18 pub content: String,
20}
21
22#[derive(Debug, Clone, Serialize, Deserialize)]
24#[serde(rename_all = "lowercase")]
25pub enum MessageRole {
26 System,
28 User,
30 Assistant,
32}
33
34#[derive(Debug, Clone, Serialize)]
36pub struct PipeRequest {
37 pub name: String,
39 pub messages: Vec<Message>,
41 #[serde(default)]
43 pub stream: bool,
44 #[serde(skip_serializing_if = "Option::is_none")]
46 pub variables: Option<HashMap<String, String>>,
47 #[serde(rename = "threadId", skip_serializing_if = "Option::is_none")]
49 pub thread_id: Option<String>,
50}
51
52#[derive(Debug, Clone, Deserialize)]
54pub struct PipeResponse {
55 pub success: bool,
57 pub completion: String,
59 #[serde(rename = "threadId")]
61 pub thread_id: Option<String>,
62 pub raw: Option<RawResponse>,
64}
65
66#[derive(Debug, Clone, Deserialize)]
68pub struct RawResponse {
69 pub model: Option<String>,
71 pub usage: Option<Usage>,
73}
74
75#[derive(Debug, Clone, Deserialize)]
77pub struct Usage {
78 pub prompt_tokens: Option<u32>,
80 pub completion_tokens: Option<u32>,
82 pub total_tokens: Option<u32>,
84}
85
86impl Message {
87 pub fn system(content: impl Into<String>) -> Self {
89 Self {
90 role: MessageRole::System,
91 content: content.into(),
92 }
93 }
94
95 pub fn user(content: impl Into<String>) -> Self {
97 Self {
98 role: MessageRole::User,
99 content: content.into(),
100 }
101 }
102
103 pub fn assistant(content: impl Into<String>) -> Self {
105 Self {
106 role: MessageRole::Assistant,
107 content: content.into(),
108 }
109 }
110}
111
112impl PipeRequest {
113 pub fn new(name: impl Into<String>, messages: Vec<Message>) -> Self {
115 Self {
116 name: name.into(),
117 messages,
118 stream: false, variables: None,
120 thread_id: None,
121 }
122 }
123
124 pub fn with_variables(mut self, variables: HashMap<String, String>) -> Self {
126 self.variables = Some(variables);
127 self
128 }
129
130 pub fn with_variable(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
132 self.variables
133 .get_or_insert_with(HashMap::new)
134 .insert(key.into(), value.into());
135 self
136 }
137
138 pub fn with_thread_id(mut self, thread_id: impl Into<String>) -> Self {
140 self.thread_id = Some(thread_id.into());
141 self
142 }
143}
144
145#[derive(Debug, Clone, Serialize, Deserialize)]
147pub struct ReasoningResponse {
148 pub thought: String,
150 pub confidence: f64,
152 #[serde(default)]
154 pub metadata: Option<serde_json::Value>,
155}
156
157#[derive(Debug, Clone, Serialize)]
159pub struct CreatePipeRequest {
160 pub name: String,
162 #[serde(skip_serializing_if = "Option::is_none")]
164 pub description: Option<String>,
165 #[serde(skip_serializing_if = "Option::is_none")]
167 pub status: Option<PipeStatus>,
168 #[serde(skip_serializing_if = "Option::is_none")]
170 pub model: Option<String>,
171 #[serde(skip_serializing_if = "Option::is_none")]
173 pub upsert: Option<bool>,
174 #[serde(skip_serializing_if = "Option::is_none")]
176 pub stream: Option<bool>,
177 #[serde(skip_serializing_if = "Option::is_none")]
179 pub json: Option<bool>,
180 #[serde(skip_serializing_if = "Option::is_none")]
182 pub store: Option<bool>,
183 #[serde(skip_serializing_if = "Option::is_none")]
185 pub temperature: Option<f64>,
186 #[serde(skip_serializing_if = "Option::is_none")]
188 pub max_tokens: Option<u32>,
189 #[serde(skip_serializing_if = "Option::is_none")]
191 pub messages: Option<Vec<Message>>,
192}
193
194#[derive(Debug, Clone, Serialize, Deserialize)]
196#[serde(rename_all = "lowercase")]
197pub enum PipeStatus {
198 Public,
200 Private,
202}
203
204#[derive(Debug, Clone, Deserialize)]
206pub struct CreatePipeResponse {
207 pub name: String,
209 pub description: Option<String>,
211 pub status: String,
213 pub owner_login: String,
215 pub url: String,
217 #[serde(rename = "type")]
219 pub pipe_type: String,
220 pub api_key: String,
222}
223
224impl CreatePipeRequest {
225 pub fn new(name: impl Into<String>) -> Self {
227 Self {
228 name: name.into(),
229 description: None,
230 status: None,
231 model: None,
232 upsert: None,
233 stream: None,
234 json: None,
235 store: None,
236 temperature: None,
237 max_tokens: None,
238 messages: None,
239 }
240 }
241
242 pub fn with_description(mut self, description: impl Into<String>) -> Self {
244 self.description = Some(description.into());
245 self
246 }
247
248 pub fn with_status(mut self, status: PipeStatus) -> Self {
250 self.status = Some(status);
251 self
252 }
253
254 pub fn with_model(mut self, model: impl Into<String>) -> Self {
256 self.model = Some(model.into());
257 self
258 }
259
260 pub fn with_upsert(mut self, upsert: bool) -> Self {
262 self.upsert = Some(upsert);
263 self
264 }
265
266 pub fn with_json_output(mut self, json: bool) -> Self {
268 self.json = Some(json);
269 self
270 }
271
272 pub fn with_temperature(mut self, temperature: f64) -> Self {
274 self.temperature = Some(temperature);
275 self
276 }
277
278 pub fn with_max_tokens(mut self, max_tokens: u32) -> Self {
280 self.max_tokens = Some(max_tokens);
281 self
282 }
283
284 pub fn with_messages(mut self, messages: Vec<Message>) -> Self {
286 self.messages = Some(messages);
287 self
288 }
289}
290
291impl ReasoningResponse {
292 pub fn from_completion(completion: &str) -> Self {
294 match serde_json::from_str::<ReasoningResponse>(completion) {
295 Ok(parsed) => parsed,
296 Err(e) => {
297 warn!(
298 error = %e,
299 completion_preview = %completion.chars().take(200).collect::<String>(),
300 "Failed to parse reasoning response as JSON, using raw completion as thought"
301 );
302 Self {
304 thought: completion.to_string(),
305 confidence: 0.8,
306 metadata: None,
307 }
308 }
309 }
310 }
311}
312
313#[derive(Debug, Clone, Serialize, Deserialize)]
319pub struct DetectedBias {
320 pub bias_type: String,
322 pub severity: i32,
324 pub confidence: f64,
326 pub explanation: String,
328 #[serde(skip_serializing_if = "Option::is_none")]
330 pub remediation: Option<String>,
331 #[serde(skip_serializing_if = "Option::is_none")]
333 pub excerpt: Option<String>,
334}
335
336#[derive(Debug, Clone, Serialize, Deserialize)]
338pub struct BiasDetectionResponse {
339 pub detections: Vec<DetectedBias>,
341 pub reasoning_quality: f64,
343 pub overall_assessment: String,
345 #[serde(default, skip_serializing_if = "Option::is_none")]
347 pub metadata: Option<serde_json::Value>,
348}
349
350impl BiasDetectionResponse {
351 pub fn from_completion(completion: &str) -> Self {
353 match serde_json::from_str::<BiasDetectionResponse>(completion) {
354 Ok(parsed) => parsed,
355 Err(e) => {
356 warn!(
357 error = %e,
358 completion_preview = %completion.chars().take(200).collect::<String>(),
359 "Failed to parse bias detection response as JSON, returning empty result"
360 );
361 Self {
362 detections: vec![],
363 reasoning_quality: 0.5,
364 overall_assessment: completion.to_string(),
365 metadata: None,
366 }
367 }
368 }
369 }
370}
371
372#[derive(Debug, Clone, Serialize, Deserialize)]
374pub struct DetectedFallacy {
375 pub fallacy_type: String,
377 pub category: String,
379 pub severity: i32,
381 pub confidence: f64,
383 pub explanation: String,
385 #[serde(skip_serializing_if = "Option::is_none")]
387 pub remediation: Option<String>,
388 #[serde(skip_serializing_if = "Option::is_none")]
390 pub excerpt: Option<String>,
391}
392
393#[derive(Debug, Clone, Serialize, Deserialize)]
395pub struct FallacyDetectionResponse {
396 pub detections: Vec<DetectedFallacy>,
398 pub argument_validity: f64,
400 pub overall_assessment: String,
402 #[serde(default, skip_serializing_if = "Option::is_none")]
404 pub metadata: Option<serde_json::Value>,
405}
406
407impl FallacyDetectionResponse {
408 pub fn from_completion(completion: &str) -> Self {
410 match serde_json::from_str::<FallacyDetectionResponse>(completion) {
411 Ok(parsed) => parsed,
412 Err(e) => {
413 warn!(
414 error = %e,
415 completion_preview = %completion.chars().take(200).collect::<String>(),
416 "Failed to parse fallacy detection response as JSON, returning empty result"
417 );
418 Self {
419 detections: vec![],
420 argument_validity: 0.5,
421 overall_assessment: completion.to_string(),
422 metadata: None,
423 }
424 }
425 }
426 }
427}