rainy_sdk/models.rs
1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3use std::collections::HashMap;
4
5/// Represents a single message in a chat conversation.
6#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
7pub struct ChatMessage {
8 /// The role of the message author.
9 pub role: MessageRole,
10 /// The content of the message.
11 pub content: String,
12}
13
14/// The role of a message's author.
15#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
16#[serde(rename_all = "lowercase")]
17pub enum MessageRole {
18 /// A message from the system, setting the context or instructions for the assistant.
19 System,
20 /// A message from the user.
21 User,
22 /// A message from the assistant.
23 Assistant,
24}
25
26/// Represents a request to create a chat completion.
27#[derive(Debug, Clone, Serialize, Deserialize)]
28pub struct ChatCompletionRequest {
29 /// The identifier of the model to use for the completion (e.g., "gpt-4o", "claude-sonnet-4").
30 pub model: String,
31
32 /// A list of messages that form the conversation history.
33 pub messages: Vec<ChatMessage>,
34
35 /// The sampling temperature to use, between 0.0 and 2.0. Higher values will make the output
36 /// more random, while lower values will make it more focused and deterministic.
37 #[serde(skip_serializing_if = "Option::is_none")]
38 pub temperature: Option<f32>,
39
40 /// The maximum number of tokens to generate in the completion.
41 #[serde(skip_serializing_if = "Option::is_none")]
42 pub max_tokens: Option<u32>,
43
44 /// The nucleus sampling parameter. The model considers the results of the tokens with `top_p`
45 /// probability mass. So, 0.1 means only the tokens comprising the top 10% probability mass are considered.
46 #[serde(skip_serializing_if = "Option::is_none")]
47 pub top_p: Option<f32>,
48
49 /// A penalty applied to new tokens based on their frequency in the text so far.
50 /// It decreases the model's likelihood to repeat the same line verbatim.
51 #[serde(skip_serializing_if = "Option::is_none")]
52 pub frequency_penalty: Option<f32>,
53
54 /// A penalty applied to new tokens based on whether they appear in the text so far.
55 /// It increases the model's likelihood to talk about new topics.
56 #[serde(skip_serializing_if = "Option::is_none")]
57 pub presence_penalty: Option<f32>,
58
59 /// A list of sequences that will cause the model to stop generating further tokens.
60 #[serde(skip_serializing_if = "Option::is_none")]
61 pub stop: Option<Vec<String>>,
62
63 /// A unique identifier representing your end-user, which can help in monitoring and
64 /// tracking conversations.
65 #[serde(skip_serializing_if = "Option::is_none")]
66 pub user: Option<String>,
67
68 /// A hint to the router about which provider to use for the model.
69 #[serde(skip_serializing_if = "Option::is_none")]
70 pub provider: Option<String>,
71
72 /// If set to `true`, the response will be streamed as a series of events.
73 #[serde(skip_serializing_if = "Option::is_none")]
74 pub stream: Option<bool>,
75
76 /// Modify the likelihood of specified tokens appearing in the completion.
77 #[serde(skip_serializing_if = "Option::is_none")]
78 pub logit_bias: Option<serde_json::Value>,
79
80 /// Whether to return log probabilities of the output tokens.
81 #[serde(skip_serializing_if = "Option::is_none")]
82 pub logprobs: Option<bool>,
83
84 /// An integer between 0 and 20 specifying the number of most likely tokens to return at each token position.
85 #[serde(skip_serializing_if = "Option::is_none")]
86 pub top_logprobs: Option<u32>,
87
88 /// How many chat completion choices to generate for each input message.
89 #[serde(skip_serializing_if = "Option::is_none")]
90 pub n: Option<u32>,
91
92 /// An object specifying the format that the model must output.
93 #[serde(skip_serializing_if = "Option::is_none")]
94 pub response_format: Option<ResponseFormat>,
95
96 /// A list of tools the model may call.
97 #[serde(skip_serializing_if = "Option::is_none")]
98 pub tools: Option<Vec<Tool>>,
99
100 /// Controls which (if any) tool is called by the model.
101 #[serde(skip_serializing_if = "Option::is_none")]
102 pub tool_choice: Option<ToolChoice>,
103}
104
105/// Represents the response from a chat completion request.
106#[derive(Debug, Clone, Serialize, Deserialize)]
107pub struct ChatCompletionResponse {
108 /// A unique identifier for the chat completion.
109 pub id: String,
110
111 /// The type of object, which is always "chat.completion".
112 pub object: String,
113
114 /// The Unix timestamp (in seconds) of when the completion was created.
115 pub created: u64,
116
117 /// The model that was used for the completion.
118 pub model: String,
119
120 /// A list of chat completion choices.
121 pub choices: Vec<ChatChoice>,
122
123 /// Information about the token usage for this completion.
124 #[serde(skip_serializing_if = "Option::is_none")]
125 pub usage: Option<Usage>,
126}
127
128/// Represents a single choice in a chat completion response.
129#[derive(Debug, Clone, Serialize, Deserialize)]
130pub struct ChatChoice {
131 /// The index of the choice in the list of choices.
132 pub index: u32,
133
134 /// The message generated by the model.
135 pub message: ChatMessage,
136
137 /// The reason the model stopped generating tokens.
138 pub finish_reason: String,
139}
140
141/// Represents the token usage statistics for a chat completion.
142#[derive(Debug, Clone, Serialize, Deserialize)]
143pub struct Usage {
144 /// The number of tokens in the prompt.
145 pub prompt_tokens: u32,
146
147 /// The number of tokens in the generated completion.
148 pub completion_tokens: u32,
149
150 /// The total number of tokens used in the request (prompt + completion).
151 pub total_tokens: u32,
152}
153
154/// Represents the health status of the Rainy API.
155#[derive(Debug, Clone, Serialize, Deserialize)]
156pub struct HealthStatus {
157 /// The overall status of the API (e.g., "healthy", "degraded").
158 pub status: String,
159
160 /// The timestamp of when the health check was performed.
161 pub timestamp: String,
162
163 /// The uptime of the system in seconds.
164 pub uptime: f64,
165
166 /// The status of individual services.
167 pub services: ServiceStatus,
168}
169
170/// Represents the status of individual backend services.
171#[derive(Debug, Clone, Serialize, Deserialize)]
172pub struct ServiceStatus {
173 /// The status of the database connection.
174 pub database: bool,
175
176 /// The status of the Redis connection, if applicable.
177 #[serde(skip_serializing_if = "Option::is_none")]
178 pub redis: Option<bool>,
179
180 /// The overall status of the connections to AI providers.
181 pub providers: bool,
182}
183
184/// Represents the available models and providers.
185#[derive(Debug, Clone, Serialize, Deserialize)]
186pub struct AvailableModels {
187 /// A map where keys are provider names and values are lists of model names.
188 pub providers: HashMap<String, Vec<String>>,
189
190 /// The total number of available models across all providers.
191 pub total_models: usize,
192
193 /// A list of provider names that are currently active and available.
194 pub active_providers: Vec<String>,
195}
196
197/// Represents information about credit usage for a request.
198#[derive(Debug, Clone, Serialize, Deserialize)]
199pub struct CreditInfo {
200 /// The number of credits available before the request.
201 pub current_credits: f64,
202
203 /// The estimated number of credits that the request will cost.
204 pub estimated_cost: f64,
205
206 /// The estimated number of credits remaining after the request.
207 pub credits_after_request: f64,
208
209 /// The date when the credit balance is next scheduled to be reset.
210 pub reset_date: String,
211}
212
213/// Represents metadata extracted from the response headers of an API request.
214#[derive(Debug, Clone)]
215pub struct RequestMetadata {
216 /// The time taken for the request to complete, in milliseconds.
217 pub response_time: Option<u64>,
218
219 /// The AI provider that handled the request.
220 pub provider: Option<String>,
221
222 /// The number of tokens used in the request.
223 pub tokens_used: Option<u32>,
224
225 /// The number of credits used for the request.
226 pub credits_used: Option<f64>,
227
228 /// The number of credits remaining after the request.
229 pub credits_remaining: Option<f64>,
230
231 /// The unique ID of the request, for tracking and debugging.
232 pub request_id: Option<String>,
233}
234
235/// A collection of predefined model constants for convenience.
236/// All models listed here are confirmed to be 100% OpenAI-compatible without parameter adaptations.
237pub mod model_constants {
238 // OpenAI models (fully compatible)
239 /// Constant for the GPT-4o model.
240 pub const OPENAI_GPT_4O: &str = "gpt-4o";
241 /// Constant for the GPT-5 model.
242 pub const OPENAI_GPT_5: &str = "gpt-5";
243 /// Constant for the GPT-5 Pro model.
244 pub const OPENAI_GPT_5_PRO: &str = "gpt-5-pro";
245 /// Constant for the O3 model.
246 pub const OPENAI_O3: &str = "o3";
247 /// Constant for the O4 Mini model.
248 pub const OPENAI_O4_MINI: &str = "o4-mini";
249
250 // Google Gemini models (fully compatible via official compatibility layer)
251 /// Constant for the Gemini 2.5 Pro model.
252 pub const GOOGLE_GEMINI_2_5_PRO: &str = "gemini-2.5-pro";
253 /// Constant for the Gemini 2.5 Flash model.
254 pub const GOOGLE_GEMINI_2_5_FLASH: &str = "gemini-2.5-flash";
255 /// Constant for the Gemini 2.5 Flash Lite model.
256 pub const GOOGLE_GEMINI_2_5_FLASH_LITE: &str = "gemini-2.5-flash-lite";
257
258 // Groq models (fully compatible)
259 /// Constant for the Llama 3.1 8B Instant model.
260 pub const GROQ_LLAMA_3_1_8B_INSTANT: &str = "llama-3.1-8b-instant";
261 /// Constant for the Llama 3.3 70B Versatile model.
262 pub const GROQ_LLAMA_3_3_70B_VERSATILE: &str = "llama-3.3-70b-versatile";
263 /// Constant for the moonshotai/kimi-k2-instruct-0905 Instant model.
264 pub const KIMI_K2_0925: &str = "moonshotai/kimi-k2-instruct-0905";
265
266 // Cerebras models (fully compatible)
267 /// Constant for the Llama3.1 8B model.
268 pub const CEREBRAS_LLAMA3_1_8B: &str = "cerebras/llama3.1-8b";
269
270 // Enosis Labs models (fully compatible)
271 /// Constant for the Astronomer 1 model.
272 pub const ASTRONOMER_1: &str = "astronomer-1";
273 /// Constant for the Astronomer 1 Max model.
274 pub const ASTRONOMER_1_MAX: &str = "astronomer-1-max";
275 /// Constant for the Astronomer 1.5 model.
276 pub const ASTRONOMER_1_5: &str = "astronomer-1.5";
277 /// Constant for the Astronomer 2 model.
278 pub const ASTRONOMER_2: &str = "astronomer-2";
279 /// Constant for the Astronomer 2 Pro model.
280 pub const ASTRONOMER_2_PRO: &str = "astronomer-2-pro";
281
282 // Legacy aliases for backward compatibility (deprecated - use provider-prefixed versions above)
283 /// Legacy constant for the GPT-4o model (use OPENAI_GPT_4O instead).
284 #[deprecated(note = "Use OPENAI_GPT_4O instead for OpenAI compatibility")]
285 pub const GPT_4O: &str = "openai/gpt-4o";
286 /// Legacy constant for the GPT-5 model (use OPENAI_GPT_5 instead).
287 #[deprecated(note = "Use OPENAI_GPT_5 instead for OpenAI compatibility")]
288 pub const GPT_5: &str = "openai/gpt-5";
289 /// Legacy constant for the Gemini 2.5 Pro model (use GOOGLE_GEMINI_2_5_PRO instead).
290 #[deprecated(note = "Use GOOGLE_GEMINI_2_5_PRO instead for OpenAI compatibility")]
291 pub const GEMINI_2_5_PRO: &str = "google/gemini-2.5-pro";
292 /// Legacy constant for the Gemini 2.5 Flash model (use GOOGLE_GEMINI_2_5_FLASH instead).
293 #[deprecated(note = "Use GOOGLE_GEMINI_2_5_FLASH instead for OpenAI compatibility")]
294 pub const GEMINI_2_5_FLASH: &str = "google/gemini-2.5-flash";
295 /// Legacy constant for the Gemini 2.5 Flash Lite model (use GOOGLE_GEMINI_2_5_FLASH_LITE instead).
296 #[deprecated(note = "Use GOOGLE_GEMINI_2_5_FLASH_LITE instead for OpenAI compatibility")]
297 pub const GEMINI_2_5_FLASH_LITE: &str = "google/gemini-2.5-flash-lite";
298 /// Legacy constant for the Llama 3.1 8B Instant model (use GROQ_LLAMA_3_1_8B_INSTANT instead).
299 #[deprecated(note = "Use GROQ_LLAMA_3_1_8B_INSTANT instead for OpenAI compatibility")]
300 pub const LLAMA_3_1_8B_INSTANT: &str = "groq/llama-3.1-8b-instant";
301 /// Legacy constant for the Llama3.1 8B model (use CEREBRAS_LLAMA3_1_8B instead).
302 #[deprecated(note = "Use CEREBRAS_LLAMA3_1_8B instead for OpenAI compatibility")]
303 pub const LLAMA3_1_8B: &str = "cerebras/llama3.1-8b";
304}
305
306/// A collection of predefined provider name constants for convenience.
307pub mod providers {
308 /// Constant for the OpenAI provider.
309 pub const OPENAI: &str = "openai";
310 /// Constant for the Anthropic provider.
311 pub const ANTHROPIC: &str = "anthropic";
312 /// Constant for the Groq provider.
313 pub const GROQ: &str = "groq";
314 /// Constant for the Cerebras provider.
315 pub const CEREBRAS: &str = "cerebras";
316 /// Constant for the Gemini provider.
317 pub const GEMINI: &str = "gemini";
318 /// Constant for the Enosis Labs provider.
319 pub const ENOSISLABS: &str = "enosislabs";
320}
321
322impl ChatCompletionRequest {
323 /// Creates a new `ChatCompletionRequest` with the given model and messages.
324 ///
325 /// # Arguments
326 ///
327 /// * `model` - The identifier of the model to use.
328 /// * `messages` - The list of messages for the conversation.
329 pub fn new(model: impl Into<String>, messages: Vec<ChatMessage>) -> Self {
330 Self {
331 model: model.into(),
332 messages,
333 temperature: None,
334 max_tokens: None,
335 top_p: None,
336 frequency_penalty: None,
337 presence_penalty: None,
338 stop: None,
339 user: None,
340 provider: None,
341 stream: None,
342 logit_bias: None,
343 logprobs: None,
344 top_logprobs: None,
345 n: None,
346 response_format: None,
347 tools: None,
348 tool_choice: None,
349 }
350 }
351
352 /// Sets the temperature for the chat completion.
353 ///
354 /// The temperature is clamped between 0.0 and 2.0.
355 ///
356 /// # Arguments
357 ///
358 /// * `temperature` - The sampling temperature.
359 pub fn with_temperature(mut self, temperature: f32) -> Self {
360 self.temperature = Some(temperature.clamp(0.0, 2.0));
361 self
362 }
363
364 /// Sets the maximum number of tokens to generate.
365 ///
366 /// # Arguments
367 ///
368 /// * `max_tokens` - The maximum number of tokens.
369 pub fn with_max_tokens(mut self, max_tokens: u32) -> Self {
370 self.max_tokens = Some(max_tokens);
371 self
372 }
373
374 /// Sets the user identifier for the chat completion.
375 ///
376 /// # Arguments
377 ///
378 /// * `user` - A unique identifier for the end-user.
379 pub fn with_user(mut self, user: impl Into<String>) -> Self {
380 self.user = Some(user.into());
381 self
382 }
383
384 /// Sets a provider hint for the request.
385 ///
386 /// # Arguments
387 ///
388 /// * `provider` - The name of the provider to use.
389 pub fn with_provider(mut self, provider: impl Into<String>) -> Self {
390 self.provider = Some(provider.into());
391 self
392 }
393
394 /// Enables or disables streaming for the response.
395 ///
396 /// # Arguments
397 ///
398 /// * `stream` - `true` to enable streaming, `false` to disable.
399 pub fn with_stream(mut self, stream: bool) -> Self {
400 self.stream = Some(stream);
401 self
402 }
403
404 /// Sets the logit bias for the chat completion.
405 ///
406 /// # Arguments
407 ///
408 /// * `logit_bias` - A map of token IDs to bias values.
409 pub fn with_logit_bias(mut self, logit_bias: serde_json::Value) -> Self {
410 self.logit_bias = Some(logit_bias);
411 self
412 }
413
414 /// Enables or disables log probabilities for the response.
415 ///
416 /// # Arguments
417 ///
418 /// * `logprobs` - `true` to include log probabilities.
419 pub fn with_logprobs(mut self, logprobs: bool) -> Self {
420 self.logprobs = Some(logprobs);
421 self
422 }
423
424 /// Sets the number of most likely tokens to return at each position.
425 ///
426 /// # Arguments
427 ///
428 /// * `top_logprobs` - The number of top log probabilities to return.
429 pub fn with_top_logprobs(mut self, top_logprobs: u32) -> Self {
430 self.top_logprobs = Some(top_logprobs);
431 self
432 }
433
434 /// Sets the number of chat completion choices to generate.
435 ///
436 /// # Arguments
437 ///
438 /// * `n` - The number of completions to generate.
439 pub fn with_n(mut self, n: u32) -> Self {
440 self.n = Some(n);
441 self
442 }
443
444 /// Sets the response format for the chat completion.
445 ///
446 /// # Arguments
447 ///
448 /// * `response_format` - The format the model must output.
449 pub fn with_response_format(mut self, response_format: ResponseFormat) -> Self {
450 self.response_format = Some(response_format);
451 self
452 }
453
454 /// Sets the tools available to the model.
455 ///
456 /// # Arguments
457 ///
458 /// * `tools` - A list of tools the model can use.
459 pub fn with_tools(mut self, tools: Vec<Tool>) -> Self {
460 self.tools = Some(tools);
461 self
462 }
463
464 /// Sets the tool choice for the chat completion.
465 ///
466 /// # Arguments
467 ///
468 /// * `tool_choice` - Controls which tool the model uses.
469 pub fn with_tool_choice(mut self, tool_choice: ToolChoice) -> Self {
470 self.tool_choice = Some(tool_choice);
471 self
472 }
473
474 /// Validates that the request parameters are compatible with OpenAI standards.
475 ///
476 /// This method checks parameter ranges and values to ensure they match OpenAI's API specifications.
477 ///
478 /// # Returns
479 ///
480 /// A `Result` indicating whether the request is valid for OpenAI compatibility.
481 pub fn validate_openai_compatibility(&self) -> Result<(), String> {
482 // Validate temperature
483 if let Some(temp) = self.temperature {
484 if !(0.0..=2.0).contains(&temp) {
485 return Err(format!(
486 "Temperature must be between 0.0 and 2.0, got {}",
487 temp
488 ));
489 }
490 }
491
492 // Validate top_p
493 if let Some(top_p) = self.top_p {
494 if !(0.0..=1.0).contains(&top_p) {
495 return Err(format!("Top-p must be between 0.0 and 1.0, got {}", top_p));
496 }
497 }
498
499 // Validate frequency_penalty
500 if let Some(fp) = self.frequency_penalty {
501 if !(-2.0..=2.0).contains(&fp) {
502 return Err(format!(
503 "Frequency penalty must be between -2.0 and 2.0, got {}",
504 fp
505 ));
506 }
507 }
508
509 // Validate presence_penalty
510 if let Some(pp) = self.presence_penalty {
511 if !(-2.0..=2.0).contains(&pp) {
512 return Err(format!(
513 "Presence penalty must be between -2.0 and 2.0, got {}",
514 pp
515 ));
516 }
517 }
518
519 // Validate max_tokens
520 if let Some(mt) = self.max_tokens {
521 if mt == 0 {
522 return Err("Max tokens must be greater than 0".to_string());
523 }
524 }
525
526 // Validate top_logprobs
527 if let Some(tlp) = self.top_logprobs {
528 if !(0..=20).contains(&tlp) {
529 return Err(format!(
530 "Top logprobs must be between 0 and 20, got {}",
531 tlp
532 ));
533 }
534 }
535
536 // Validate n
537 if let Some(n) = self.n {
538 if n == 0 {
539 return Err("n must be greater than 0".to_string());
540 }
541 }
542
543 // Validate stop sequences
544 if let Some(stop) = &self.stop {
545 if stop.len() > 4 {
546 return Err("Cannot have more than 4 stop sequences".to_string());
547 }
548 for seq in stop {
549 if seq.is_empty() {
550 return Err("Stop sequences cannot be empty".to_string());
551 }
552 if seq.len() > 64 {
553 return Err("Stop sequences cannot be longer than 64 characters".to_string());
554 }
555 }
556 }
557
558 Ok(())
559 }
560}
561
562impl ChatMessage {
563 /// Creates a new message with the `System` role.
564 ///
565 /// # Arguments
566 ///
567 /// * `content` - The content of the system message.
568 pub fn system(content: impl Into<String>) -> Self {
569 Self {
570 role: MessageRole::System,
571 content: content.into(),
572 }
573 }
574
575 /// Creates a new message with the `User` role.
576 ///
577 /// # Arguments
578 ///
579 /// * `content` - The content of the user message.
580 pub fn user(content: impl Into<String>) -> Self {
581 Self {
582 role: MessageRole::User,
583 content: content.into(),
584 }
585 }
586
587 /// Creates a new message with the `Assistant` role.
588 ///
589 /// # Arguments
590 ///
591 /// * `content` - The content of the assistant message.
592 pub fn assistant(content: impl Into<String>) -> Self {
593 Self {
594 role: MessageRole::Assistant,
595 content: content.into(),
596 }
597 }
598}
599
600// Legacy compatibility types - keep existing types for backward compatibility
601use uuid::Uuid;
602
603/// Represents a user account (legacy).
604#[derive(Debug, Clone, Serialize, Deserialize)]
605pub struct User {
606 /// The unique ID of the user.
607 pub id: Uuid,
608 /// The user's identifier string.
609 pub user_id: String,
610 /// The name of the user's subscription plan.
611 pub plan_name: String,
612 /// The user's current credit balance.
613 pub current_credits: f64,
614 /// The amount of credits the user has used in the current month.
615 pub credits_used_this_month: f64,
616 /// The date when the user's credits will reset.
617 pub credits_reset_date: DateTime<Utc>,
618 /// Indicates if the user account is active.
619 pub is_active: bool,
620 /// The timestamp of when the user account was created.
621 pub created_at: DateTime<Utc>,
622}
623
624/// Represents an API key (legacy).
625#[derive(Debug, Clone, Serialize, Deserialize)]
626pub struct ApiKey {
627 /// The unique ID of the API key.
628 pub id: Uuid,
629 /// The API key string.
630 pub key: String,
631 /// The ID of the user who owns the key.
632 pub owner_id: Uuid,
633 /// Indicates if the API key is active.
634 pub is_active: bool,
635 /// The timestamp of when the key was created.
636 pub created_at: DateTime<Utc>,
637 /// The expiration date of the key, if any.
638 pub expires_at: Option<DateTime<Utc>>,
639 /// A description of the key.
640 pub description: Option<String>,
641 /// The timestamp of when the key was last used.
642 pub last_used_at: Option<DateTime<Utc>>,
643}
644
645/// Represents usage statistics over a period (legacy).
646#[derive(Debug, Clone, Serialize, Deserialize)]
647pub struct UsageStats {
648 /// The number of days in the usage period.
649 pub period_days: u32,
650 /// A list of daily usage data.
651 pub daily_usage: Vec<DailyUsage>,
652 /// A list of recent credit transactions.
653 pub recent_transactions: Vec<CreditTransaction>,
654 /// The total number of requests made in the period.
655 pub total_requests: u64,
656 /// The total number of tokens used in the period.
657 pub total_tokens: u64,
658}
659
660/// Represents usage data for a single day (legacy).
661#[derive(Debug, Clone, Serialize, Deserialize)]
662pub struct DailyUsage {
663 /// The date for the usage data.
664 pub date: String,
665 /// The number of credits used on this day.
666 pub credits_used: f64,
667 /// The number of requests made on this day.
668 pub requests: u64,
669 /// The number of tokens used on this day.
670 pub tokens: u64,
671}
672
673/// Represents a single credit transaction (legacy).
674#[derive(Debug, Clone, Serialize, Deserialize)]
675pub struct CreditTransaction {
676 /// The unique ID of the transaction.
677 pub id: Uuid,
678 /// The type of the transaction.
679 pub transaction_type: TransactionType,
680 /// The amount of credits involved in the transaction.
681 pub credits_amount: f64,
682 /// The credit balance after the transaction.
683 pub credits_balance_after: f64,
684 /// The provider associated with the transaction, if any.
685 pub provider: Option<String>,
686 /// The model associated with the transaction, if any.
687 pub model: Option<String>,
688 /// A description of the transaction.
689 pub description: String,
690 /// The timestamp of when the transaction occurred.
691 pub created_at: DateTime<Utc>,
692}
693
694/// The type of credit transaction (legacy).
695#[derive(Debug, Clone, Serialize, Deserialize)]
696#[serde(rename_all = "lowercase")]
697pub enum TransactionType {
698 /// A transaction for API usage.
699 Usage,
700 /// A transaction for a credit reset.
701 Reset,
702 /// A transaction for a credit purchase.
703 Purchase,
704 /// A transaction for a credit refund.
705 Refund,
706}
707
708// Legacy aliases for backward compatibility
709/// A legacy type alias for `MessageRole`.
710pub type ChatRole = MessageRole;
711/// A legacy type alias for `Usage`.
712pub type ChatUsage = Usage;
713/// A legacy type alias for `HealthStatus`.
714pub type HealthCheck = HealthStatus;
715
716/// Represents the status of backend services (legacy).
717#[derive(Debug, Clone, Serialize, Deserialize)]
718pub struct HealthServices {
719 /// The status of the database connection.
720 pub database: bool,
721 /// The status of the Redis connection.
722 pub redis: bool,
723 /// The overall status of AI providers.
724 pub providers: bool,
725}
726
727/// The health status of the API (legacy).
728#[derive(Debug, Clone, Serialize, Deserialize)]
729#[serde(rename_all = "lowercase")]
730pub enum HealthStatusEnum {
731 /// The API is healthy.
732 Healthy,
733 /// The API is in a degraded state.
734 Degraded,
735 /// The API is unhealthy.
736 Unhealthy,
737 /// The API needs initialization.
738 NeedsInit,
739}
740
741/// Represents the format that the model must output.
742#[derive(Debug, Clone, Serialize, Deserialize)]
743#[serde(rename_all = "snake_case")]
744pub enum ResponseFormat {
745 /// The model can return text.
746 Text,
747 /// The model must return a valid JSON object.
748 JsonObject,
749 /// The model must return a JSON object that matches the provided schema.
750 JsonSchema { json_schema: serde_json::Value },
751}
752
753/// Represents a tool that the model can use.
754#[derive(Debug, Clone, Serialize, Deserialize)]
755pub struct Tool {
756 /// The type of the tool.
757 pub r#type: ToolType,
758 /// The function definition for the tool.
759 pub function: FunctionDefinition,
760}
761
762/// The type of tool.
763#[derive(Debug, Clone, Serialize, Deserialize)]
764#[serde(rename_all = "snake_case")]
765pub enum ToolType {
766 /// A function tool.
767 Function,
768}
769
770/// Represents a function definition for a tool.
771#[derive(Debug, Clone, Serialize, Deserialize)]
772pub struct FunctionDefinition {
773 /// The name of the function.
774 pub name: String,
775 /// A description of what the function does.
776 #[serde(skip_serializing_if = "Option::is_none")]
777 pub description: Option<String>,
778 /// The parameters the function accepts, described as a JSON Schema object.
779 #[serde(skip_serializing_if = "Option::is_none")]
780 pub parameters: Option<serde_json::Value>,
781}
782
783/// Controls which tool is called by the model.
784#[derive(Debug, Clone, Serialize, Deserialize)]
785#[serde(untagged)]
786pub enum ToolChoice {
787 /// No tool is called.
788 None,
789 /// The model chooses which tool to call.
790 Auto,
791 /// A specific tool is called.
792 Tool {
793 r#type: ToolType,
794 function: ToolFunction,
795 },
796}
797
798/// Represents a tool function call.
799#[derive(Debug, Clone, Serialize, Deserialize)]
800pub struct ToolFunction {
801 /// The name of the function to call.
802 pub name: String,
803}
804
805/// Represents a streaming chat completion response (OpenAI delta format).
806#[derive(Debug, Clone, Serialize, Deserialize)]
807pub struct ChatCompletionStreamResponse {
808 /// A unique identifier for the chat completion.
809 pub id: String,
810 /// The type of object, which is always "chat.completion.chunk".
811 pub object: String,
812 /// The Unix timestamp (in seconds) of when the completion was created.
813 pub created: u64,
814 /// The model that was used for the completion.
815 pub model: String,
816 /// A list of chat completion choices.
817 pub choices: Vec<ChatCompletionStreamChoice>,
818 /// Information about the token usage for this completion (only present in the final chunk).
819 #[serde(skip_serializing_if = "Option::is_none")]
820 pub usage: Option<Usage>,
821}
822
823/// Represents a single choice in a streaming chat completion response.
824#[derive(Debug, Clone, Serialize, Deserialize)]
825pub struct ChatCompletionStreamChoice {
826 /// The index of the choice in the list of choices.
827 pub index: u32,
828 /// The delta containing the new content for this choice.
829 pub delta: ChatCompletionStreamDelta,
830 /// The reason the model stopped generating tokens (only present in the final chunk).
831 #[serde(skip_serializing_if = "Option::is_none")]
832 pub finish_reason: Option<String>,
833}
834
835/// Represents the delta (change) in a streaming chat completion response.
836#[derive(Debug, Clone, Serialize, Deserialize)]
837pub struct ChatCompletionStreamDelta {
838 /// The role of the message (only present in the first chunk).
839 #[serde(skip_serializing_if = "Option::is_none")]
840 pub role: Option<String>,
841 /// The new content for this chunk.
842 #[serde(skip_serializing_if = "Option::is_none")]
843 pub content: Option<String>,
844 /// Tool calls for this chunk (if any).
845 #[serde(skip_serializing_if = "Option::is_none")]
846 pub tool_calls: Option<Vec<ToolCall>>,
847}
848
849/// Represents a tool call in a streaming response.
850#[derive(Debug, Clone, Serialize, Deserialize)]
851pub struct ToolCall {
852 /// The index of the tool call.
853 pub index: u32,
854 /// The ID of the tool call.
855 #[serde(skip_serializing_if = "Option::is_none")]
856 pub id: Option<String>,
857 /// The type of the tool call.
858 #[serde(skip_serializing_if = "Option::is_none")]
859 pub r#type: Option<String>,
860 /// The function being called.
861 #[serde(skip_serializing_if = "Option::is_none")]
862 pub function: Option<ToolCallFunction>,
863}
864
865/// Represents a function call in a tool call.
866#[derive(Debug, Clone, Serialize, Deserialize)]
867pub struct ToolCallFunction {
868 /// The name of the function.
869 #[serde(skip_serializing_if = "Option::is_none")]
870 pub name: Option<String>,
871 /// The arguments for the function.
872 #[serde(skip_serializing_if = "Option::is_none")]
873 pub arguments: Option<String>,
874}