Skip to main content

liter_llm/types/
common.rs

1use serde::{Deserialize, Serialize};
2
3// ─── Messages ────────────────────────────────────────────────────────────────
4
5/// A chat message in a conversation.
6#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7#[serde(tag = "role")]
8pub enum Message {
9    #[serde(rename = "system")]
10    System(SystemMessage),
11    #[serde(rename = "user")]
12    User(UserMessage),
13    #[serde(rename = "assistant")]
14    Assistant(AssistantMessage),
15    #[serde(rename = "tool")]
16    Tool(ToolMessage),
17    #[serde(rename = "developer")]
18    Developer(DeveloperMessage),
19    /// Deprecated legacy function-role message; retained for API compatibility.
20    #[serde(rename = "function")]
21    Function(FunctionMessage),
22}
23
24impl Default for Message {
25    fn default() -> Self {
26        Self::Assistant(AssistantMessage::default())
27    }
28}
29
30#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
31pub struct SystemMessage {
32    pub content: String,
33    #[serde(default, skip_serializing_if = "Option::is_none")]
34    pub name: Option<String>,
35}
36
37#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
38pub struct UserMessage {
39    pub content: UserContent,
40    #[serde(default, skip_serializing_if = "Option::is_none")]
41    pub name: Option<String>,
42}
43
44#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
45#[serde(untagged)]
46pub enum UserContent {
47    Text(String),
48    Parts(Vec<ContentPart>),
49}
50
51impl Default for UserContent {
52    fn default() -> Self {
53        Self::Text(String::new())
54    }
55}
56
57#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
58#[serde(tag = "type")]
59pub enum ContentPart {
60    #[serde(rename = "text")]
61    Text { text: String },
62    #[serde(rename = "image_url")]
63    ImageUrl { image_url: ImageUrl },
64    #[serde(rename = "document")]
65    Document { document: DocumentContent },
66    #[serde(rename = "input_audio")]
67    InputAudio { input_audio: AudioContent },
68}
69
70impl Default for ContentPart {
71    fn default() -> Self {
72        Self::Text { text: String::new() }
73    }
74}
75
76#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
77#[serde(deny_unknown_fields)]
78pub struct ImageUrl {
79    pub url: String,
80    #[serde(default, skip_serializing_if = "Option::is_none")]
81    pub detail: Option<ImageDetail>,
82}
83
84#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
85#[serde(rename_all = "lowercase")]
86pub enum ImageDetail {
87    Low,
88    High,
89    Auto,
90}
91
92#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
93#[serde(deny_unknown_fields)]
94pub struct DocumentContent {
95    /// Base64-encoded document data or URL.
96    pub data: String,
97    /// MIME type (e.g., "application/pdf", "text/csv").
98    pub media_type: String,
99}
100
101#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
102#[serde(deny_unknown_fields)]
103pub struct AudioContent {
104    /// Base64-encoded audio data.
105    pub data: String,
106    /// Audio format (e.g., "wav", "mp3", "ogg").
107    pub format: String,
108}
109
110#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
111pub struct AssistantMessage {
112    #[serde(default, skip_serializing_if = "Option::is_none")]
113    pub content: Option<String>,
114    #[serde(default, skip_serializing_if = "Option::is_none")]
115    pub name: Option<String>,
116    #[serde(default, skip_serializing_if = "Option::is_none")]
117    pub tool_calls: Option<Vec<ToolCall>>,
118    #[serde(default, skip_serializing_if = "Option::is_none")]
119    pub refusal: Option<String>,
120    /// Deprecated legacy function_call field; retained for API compatibility.
121    #[serde(default, skip_serializing_if = "Option::is_none")]
122    pub function_call: Option<FunctionCall>,
123}
124
125#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
126pub struct ToolMessage {
127    pub content: String,
128    pub tool_call_id: String,
129    #[serde(default, skip_serializing_if = "Option::is_none")]
130    pub name: Option<String>,
131}
132
133#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
134pub struct DeveloperMessage {
135    pub content: String,
136    #[serde(default, skip_serializing_if = "Option::is_none")]
137    pub name: Option<String>,
138}
139
140/// Deprecated legacy function-role message body.
141#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
142pub struct FunctionMessage {
143    pub content: String,
144    pub name: String,
145}
146
147// ─── Tools ───────────────────────────────────────────────────────────────────
148
149/// The type discriminator for tool/tool-call objects.
150///
151/// Per the OpenAI spec this is always `"function"`. Using an enum enforces
152/// that constraint at the type level and rejects any other value on
153/// deserialization.
154#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
155pub enum ToolType {
156    #[default]
157    #[serde(rename = "function")]
158    Function,
159}
160
161#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
162#[serde(deny_unknown_fields)]
163pub struct ChatCompletionTool {
164    #[serde(rename = "type")]
165    pub tool_type: ToolType,
166    pub function: FunctionDefinition,
167}
168
169#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
170#[serde(deny_unknown_fields)]
171pub struct FunctionDefinition {
172    pub name: String,
173    #[serde(default, skip_serializing_if = "Option::is_none")]
174    pub description: Option<String>,
175    #[serde(default, skip_serializing_if = "Option::is_none")]
176    pub parameters: Option<serde_json::Value>,
177    #[serde(default, skip_serializing_if = "Option::is_none")]
178    pub strict: Option<bool>,
179}
180
181#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
182pub struct ToolCall {
183    pub id: String,
184    #[serde(rename = "type")]
185    pub call_type: ToolType,
186    pub function: FunctionCall,
187}
188
189#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
190pub struct FunctionCall {
191    pub name: String,
192    pub arguments: String,
193}
194
195// ─── Tool Choice ─────────────────────────────────────────────────────────────
196
197#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
198#[serde(untagged)]
199pub enum ToolChoice {
200    Mode(ToolChoiceMode),
201    Specific(SpecificToolChoice),
202}
203
204impl Default for ToolChoice {
205    fn default() -> Self {
206        Self::Mode(ToolChoiceMode::default())
207    }
208}
209
210#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
211#[serde(rename_all = "lowercase")]
212pub enum ToolChoiceMode {
213    #[default]
214    Auto,
215    Required,
216    None,
217}
218
219#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
220pub struct SpecificToolChoice {
221    #[serde(rename = "type")]
222    pub choice_type: ToolType,
223    pub function: SpecificFunction,
224}
225
226#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
227pub struct SpecificFunction {
228    pub name: String,
229}
230
231// ─── Response Format ─────────────────────────────────────────────────────────
232
233#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
234#[serde(tag = "type")]
235pub enum ResponseFormat {
236    #[default]
237    #[serde(rename = "text")]
238    Text,
239    #[serde(rename = "json_object")]
240    JsonObject,
241    #[serde(rename = "json_schema")]
242    JsonSchema { json_schema: JsonSchemaFormat },
243}
244
245#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
246#[serde(deny_unknown_fields)]
247pub struct JsonSchemaFormat {
248    pub name: String,
249    #[serde(default, skip_serializing_if = "Option::is_none")]
250    pub description: Option<String>,
251    pub schema: serde_json::Value,
252    #[serde(default, skip_serializing_if = "Option::is_none")]
253    pub strict: Option<bool>,
254}
255
256// ─── Usage ───────────────────────────────────────────────────────────────────
257
258#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
259pub struct Usage {
260    /// Prompt tokens used. Defaults to 0 when absent (some providers omit this).
261    #[serde(default)]
262    pub prompt_tokens: u64,
263    /// Completion tokens used. Defaults to 0 when absent (e.g. embedding responses).
264    #[serde(default)]
265    pub completion_tokens: u64,
266    /// Total tokens used. Defaults to 0 when absent (some providers omit this).
267    #[serde(default)]
268    pub total_tokens: u64,
269}
270
271// ─── Stop Sequence ───────────────────────────────────────────────────────────
272
273#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
274#[serde(untagged)]
275pub enum StopSequence {
276    Single(String),
277    Multiple(Vec<String>),
278}
279
280impl Default for StopSequence {
281    fn default() -> Self {
282        Self::Single(String::new())
283    }
284}