Skip to main content

openai_oxide/types/
common.rs

1// Shared types (Usage, Role, etc.)
2
3use serde::{Deserialize, Serialize};
4
5/// Message role in chat/thread conversations.
6#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
7#[serde(rename_all = "snake_case")]
8#[non_exhaustive]
9pub enum Role {
10    System,
11    Developer,
12    User,
13    Assistant,
14    Tool,
15    Function,
16}
17
18/// Token usage information returned by the API.
19#[derive(Debug, Clone, Serialize, Deserialize)]
20pub struct Usage {
21    pub prompt_tokens: Option<i64>,
22    pub completion_tokens: Option<i64>,
23    pub total_tokens: Option<i64>,
24    /// Detailed breakdown of prompt tokens.
25    #[serde(default)]
26    pub prompt_tokens_details: Option<PromptTokensDetails>,
27    /// Detailed breakdown of completion tokens.
28    #[serde(default)]
29    pub completion_tokens_details: Option<CompletionTokensDetails>,
30}
31
32/// Detailed breakdown of prompt token usage.
33#[derive(Debug, Clone, Serialize, Deserialize)]
34pub struct PromptTokensDetails {
35    #[serde(default)]
36    pub cached_tokens: Option<i64>,
37    #[serde(default)]
38    pub audio_tokens: Option<i64>,
39}
40
41/// Reason the model stopped generating tokens.
42#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
43#[serde(rename_all = "snake_case")]
44#[non_exhaustive]
45pub enum FinishReason {
46    Stop,
47    Length,
48    ToolCalls,
49    ContentFilter,
50    FunctionCall,
51}
52
53impl std::fmt::Display for FinishReason {
54    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55        match self {
56            Self::Stop => write!(f, "stop"),
57            Self::Length => write!(f, "length"),
58            Self::ToolCalls => write!(f, "tool_calls"),
59            Self::ContentFilter => write!(f, "content_filter"),
60            Self::FunctionCall => write!(f, "function_call"),
61        }
62    }
63}
64
65/// Service tier used for the request.
66#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
67#[serde(rename_all = "snake_case")]
68#[non_exhaustive]
69pub enum ServiceTier {
70    Auto,
71    Default,
72    Flex,
73    Scale,
74    Priority,
75}
76
77/// Reasoning effort level for o-series models.
78#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
79#[serde(rename_all = "snake_case")]
80#[non_exhaustive]
81pub enum ReasoningEffort {
82    Low,
83    Medium,
84    High,
85}
86
87/// Search context size for web search.
88#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
89#[serde(rename_all = "snake_case")]
90#[non_exhaustive]
91pub enum SearchContextSize {
92    Low,
93    Medium,
94    High,
95}
96
97/// A value that is either "auto" or a fixed number.
98///
99/// Used for hyperparameters like `n_epochs`, `batch_size`, `learning_rate_multiplier`.
100/// Serializes as the string `"auto"` or a bare number.
101#[derive(Debug, Clone, PartialEq)]
102pub enum AutoOrFixed<T> {
103    Auto,
104    Fixed(T),
105}
106
107impl<T: Serialize> Serialize for AutoOrFixed<T> {
108    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
109        match self {
110            Self::Auto => serializer.serialize_str("auto"),
111            Self::Fixed(v) => v.serialize(serializer),
112        }
113    }
114}
115
116impl<'de, T: Deserialize<'de>> Deserialize<'de> for AutoOrFixed<T> {
117    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
118        let value = serde_json::Value::deserialize(deserializer)?;
119        match &value {
120            serde_json::Value::String(s) if s == "auto" => Ok(Self::Auto),
121            _ => T::deserialize(value)
122                .map(Self::Fixed)
123                .map_err(serde::de::Error::custom),
124        }
125    }
126}
127
128/// Token limit that is either "inf" (unlimited) or a fixed integer.
129///
130/// Used for `max_response_output_tokens` in the Realtime API.
131#[derive(Debug, Clone, PartialEq)]
132pub enum MaxResponseTokens {
133    Inf,
134    Fixed(i64),
135}
136
137impl Serialize for MaxResponseTokens {
138    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
139        match self {
140            Self::Inf => serializer.serialize_str("inf"),
141            Self::Fixed(v) => serializer.serialize_i64(*v),
142        }
143    }
144}
145
146impl<'de> Deserialize<'de> for MaxResponseTokens {
147    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
148        let value = serde_json::Value::deserialize(deserializer)?;
149        match &value {
150            serde_json::Value::String(s) if s == "inf" => Ok(Self::Inf),
151            serde_json::Value::Number(n) => n
152                .as_i64()
153                .map(Self::Fixed)
154                .ok_or_else(|| serde::de::Error::custom("expected integer")),
155            _ => Err(serde::de::Error::custom("expected \"inf\" or integer")),
156        }
157    }
158}
159
160/// Sort order for paginated list endpoints.
161#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
162#[serde(rename_all = "snake_case")]
163#[non_exhaustive]
164pub enum SortOrder {
165    Asc,
166    Desc,
167}
168
169/// Detailed breakdown of completion token usage.
170#[derive(Debug, Clone, Serialize, Deserialize)]
171pub struct CompletionTokensDetails {
172    #[serde(default)]
173    pub reasoning_tokens: Option<i64>,
174    #[serde(default)]
175    pub audio_tokens: Option<i64>,
176    #[serde(default)]
177    pub accepted_prediction_tokens: Option<i64>,
178    #[serde(default)]
179    pub rejected_prediction_tokens: Option<i64>,
180}