1use crate::Rest;
2use serde::{Deserialize, Serialize};
3
4pub(crate) fn present_nullable<'de, D, T>(deserializer: D) -> Result<Option<Option<T>>, D::Error>
5where
6 D: serde::Deserializer<'de>,
7 T: Deserialize<'de>,
8{
9 Option::<T>::deserialize(deserializer).map(Some)
10}
11
12pub(crate) fn required_nullable<'de, D, T>(deserializer: D) -> Result<Option<T>, D::Error>
13where
14 D: serde::Deserializer<'de>,
15 T: Deserialize<'de>,
16{
17 Option::<T>::deserialize(deserializer)
18}
19
20#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
21#[serde(untagged)]
22#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
23#[derive(gproxy_protocol_macros::DeclaredFields)]
24#[allow(clippy::large_enum_variant)]
26pub enum ChatMessage {
27 Developer(DeveloperMessage),
28 System(SystemMessage),
29 User(UserMessage),
30 Assistant(AssistantMessage),
31 Tool(ToolMessage),
32 Function(FunctionMessage),
33}
34
35#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
36#[serde(rename_all = "snake_case")]
37#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
38#[derive(gproxy_protocol_macros::DeclaredFields)]
39pub struct DeveloperMessage {
40 pub role: DeveloperRole,
41 pub content: TextContent,
42 #[serde(skip_serializing_if = "Option::is_none")]
43 pub name: Option<String>,
44 #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
45 pub rest: Rest,
46}
47#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
48#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
49#[derive(gproxy_protocol_macros::DeclaredFields)]
50pub enum DeveloperRole {
51 #[serde(rename = "developer")]
52 Developer,
53}
54
55#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
56#[serde(rename_all = "snake_case")]
57#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
58#[derive(gproxy_protocol_macros::DeclaredFields)]
59pub struct SystemMessage {
60 pub role: SystemRole,
61 pub content: TextContent,
62 #[serde(skip_serializing_if = "Option::is_none")]
63 pub name: Option<String>,
64 #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
65 pub rest: Rest,
66}
67#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
68#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
69#[derive(gproxy_protocol_macros::DeclaredFields)]
70pub enum SystemRole {
71 #[serde(rename = "system")]
72 System,
73}
74
75#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
76#[serde(rename_all = "snake_case")]
77#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
78#[derive(gproxy_protocol_macros::DeclaredFields)]
79pub struct UserMessage {
80 pub role: UserRole,
81 pub content: UserContent,
82 #[serde(skip_serializing_if = "Option::is_none")]
83 pub name: Option<String>,
84 #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
85 pub rest: Rest,
86}
87#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
88#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
89#[derive(gproxy_protocol_macros::DeclaredFields)]
90pub enum UserRole {
91 #[serde(rename = "user")]
92 User,
93}
94
95#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
96#[serde(rename_all = "snake_case")]
97#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
98#[derive(gproxy_protocol_macros::DeclaredFields)]
99pub struct AssistantMessage {
100 #[serde(
101 default,
102 deserialize_with = "present_nullable",
103 skip_serializing_if = "Option::is_none"
104 )]
105 pub reasoning_details: Option<Option<Vec<super::reasoning::ReasoningDetail>>>,
106 #[serde(
108 default,
109 deserialize_with = "present_nullable",
110 skip_serializing_if = "Option::is_none"
111 )]
112 pub reasoning_content: Option<Option<String>>,
113 #[serde(
115 default,
116 deserialize_with = "present_nullable",
117 skip_serializing_if = "Option::is_none"
118 )]
119 pub reasoning: Option<Option<String>>,
120 pub role: AssistantRole,
121 #[serde(
122 default,
123 deserialize_with = "present_nullable",
124 skip_serializing_if = "Option::is_none"
125 )]
126 pub content: Option<Option<AssistantContent>>,
127 #[serde(
128 default,
129 deserialize_with = "present_nullable",
130 skip_serializing_if = "Option::is_none"
131 )]
132 pub audio: Option<Option<AssistantAudio>>,
133 #[serde(
134 default,
135 deserialize_with = "present_nullable",
136 skip_serializing_if = "Option::is_none"
137 )]
138 pub refusal: Option<Option<String>>,
139 #[serde(skip_serializing_if = "Option::is_none")]
140 pub name: Option<String>,
141 #[serde(skip_serializing_if = "Option::is_none")]
142 pub tool_calls: Option<Vec<MessageToolCall>>,
143 #[serde(
144 default,
145 deserialize_with = "present_nullable",
146 skip_serializing_if = "Option::is_none"
147 )]
148 pub function_call: Option<Option<FunctionCall>>,
149 #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
150 pub rest: Rest,
151}
152#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
153#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
154#[derive(gproxy_protocol_macros::DeclaredFields)]
155pub enum AssistantRole {
156 #[serde(rename = "assistant")]
157 Assistant,
158}
159
160#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
161#[serde(rename_all = "snake_case")]
162#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
163#[derive(gproxy_protocol_macros::DeclaredFields)]
164pub struct ToolMessage {
165 pub role: ToolRole,
166 pub content: TextContent,
167 pub tool_call_id: String,
168 #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
169 pub rest: Rest,
170}
171#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
172#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
173#[derive(gproxy_protocol_macros::DeclaredFields)]
174pub enum ToolRole {
175 #[serde(rename = "tool")]
176 Tool,
177}
178
179#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
180#[serde(rename_all = "snake_case")]
181#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
182#[derive(gproxy_protocol_macros::DeclaredFields)]
183pub struct FunctionMessage {
184 pub role: FunctionRole,
185 #[wire(required)]
186 #[serde(deserialize_with = "required_nullable")]
187 pub content: Option<String>,
188 pub name: String,
189 #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
190 pub rest: Rest,
191}
192#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
193#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
194#[derive(gproxy_protocol_macros::DeclaredFields)]
195pub enum FunctionRole {
196 #[serde(rename = "function")]
197 Function,
198}
199
200pub type TextContent = StringOrTextParts;
201#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
202#[serde(untagged)]
203#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
204#[derive(gproxy_protocol_macros::DeclaredFields)]
205pub enum StringOrTextParts {
206 Text(String),
207 Parts(Vec<TextPart>),
208}
209pub type UserContent = UserContentParts;
210#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
211#[serde(untagged)]
212#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
213#[derive(gproxy_protocol_macros::DeclaredFields)]
214pub enum UserContentParts {
215 Text(String),
216 Parts(Vec<UserContentPart>),
217}
218pub type AssistantContent = AssistantContentParts;
219#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
220#[serde(untagged)]
221#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
222#[derive(gproxy_protocol_macros::DeclaredFields)]
223pub enum AssistantContentParts {
224 Text(String),
225 Parts(Vec<AssistantContentPart>),
226}
227
228#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
229#[serde(untagged)]
230#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
231#[derive(gproxy_protocol_macros::DeclaredFields)]
232pub enum UserContentPart {
233 #[serde(rename = "text")]
234 Text(TextPart),
235 #[serde(rename = "image_url")]
236 Image(ImagePart),
237 #[serde(rename = "input_audio")]
238 InputAudio(InputAudioPart),
239 #[serde(rename = "file")]
240 File(FilePart),
241}
242#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
243#[serde(untagged)]
244#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
245#[derive(gproxy_protocol_macros::DeclaredFields)]
246pub enum AssistantContentPart {
247 #[serde(rename = "text")]
248 Text(TextPart),
249 #[serde(rename = "refusal")]
250 Refusal(RefusalPart),
251}
252#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
253#[serde(rename_all = "snake_case")]
254#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
255#[derive(gproxy_protocol_macros::DeclaredFields)]
256pub struct TextPart {
257 #[serde(rename = "type")]
258 pub type_: TextPartType,
259 pub text: String,
260 #[serde(skip_serializing_if = "Option::is_none")]
261 pub prompt_cache_breakpoint: Option<PromptCacheBreakpoint>,
262 #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
263 pub rest: Rest,
264}
265#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
266#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
267#[derive(gproxy_protocol_macros::DeclaredFields)]
268pub enum TextPartType {
269 #[serde(rename = "text")]
270 Text,
271}
272#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
273#[serde(rename_all = "snake_case")]
274#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
275#[derive(gproxy_protocol_macros::DeclaredFields)]
276pub struct RefusalPart {
277 #[serde(rename = "type")]
278 pub type_: RefusalType,
279 pub refusal: String,
280 #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
281 pub rest: Rest,
282}
283#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
284#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
285#[derive(gproxy_protocol_macros::DeclaredFields)]
286pub enum RefusalType {
287 #[serde(rename = "refusal")]
288 Refusal,
289}
290#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
291#[serde(rename_all = "snake_case")]
292#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
293#[derive(gproxy_protocol_macros::DeclaredFields)]
294pub struct ImagePart {
295 #[serde(rename = "type")]
296 pub type_: ImagePartType,
297 pub image_url: ImageUrl,
298 #[serde(skip_serializing_if = "Option::is_none")]
299 pub prompt_cache_breakpoint: Option<PromptCacheBreakpoint>,
300 #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
301 pub rest: Rest,
302}
303#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
304#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
305#[derive(gproxy_protocol_macros::DeclaredFields)]
306pub enum ImagePartType {
307 #[serde(rename = "image_url")]
308 ImageUrl,
309}
310#[derive(
311 Debug, Clone, PartialEq, Eq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder,
312)]
313#[serde(rename_all = "snake_case")]
314#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
315#[derive(gproxy_protocol_macros::DeclaredFields)]
316pub struct ImageUrl {
317 pub url: String,
318 #[serde(skip_serializing_if = "Option::is_none")]
319 pub detail: Option<ImageDetail>,
320 #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
321 pub rest: Rest,
322}
323#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
324#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
325#[derive(gproxy_protocol_macros::DeclaredFields)]
326pub enum ImageDetail {
327 #[serde(rename = "auto")]
328 Auto,
329 #[serde(rename = "low")]
330 Low,
331 #[serde(rename = "high")]
332 High,
333}
334#[derive(
335 Debug, Clone, PartialEq, Eq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder,
336)]
337#[serde(rename_all = "snake_case")]
338#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
339#[derive(gproxy_protocol_macros::DeclaredFields)]
340pub struct InputAudioPart {
341 #[serde(rename = "type")]
342 pub type_: InputAudioPartType,
343 pub input_audio: InputAudio,
344 #[serde(skip_serializing_if = "Option::is_none")]
345 pub prompt_cache_breakpoint: Option<PromptCacheBreakpoint>,
346 #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
347 pub rest: Rest,
348}
349#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
350#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
351#[derive(gproxy_protocol_macros::DeclaredFields)]
352pub enum InputAudioPartType {
353 #[serde(rename = "input_audio")]
354 InputAudio,
355}
356#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
357#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
358#[derive(gproxy_protocol_macros::DeclaredFields)]
359pub enum AudioFormat {
360 #[serde(rename = "wav")]
361 Wav,
362 #[serde(rename = "mp3")]
363 Mp3,
364}
365#[derive(
366 Debug, Clone, PartialEq, Eq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder,
367)]
368#[serde(rename_all = "snake_case")]
369#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
370#[derive(gproxy_protocol_macros::DeclaredFields)]
371pub struct InputAudio {
372 pub data: String,
373 pub format: AudioFormat,
374 #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
375 pub rest: Rest,
376}
377#[derive(
378 Debug, Clone, PartialEq, Eq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder,
379)]
380#[serde(rename_all = "snake_case")]
381#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
382#[derive(gproxy_protocol_macros::DeclaredFields)]
383pub struct FilePart {
384 #[serde(rename = "type")]
385 pub type_: FilePartType,
386 pub file: FileRef,
387 #[serde(skip_serializing_if = "Option::is_none")]
388 pub prompt_cache_breakpoint: Option<PromptCacheBreakpoint>,
389 #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
390 pub rest: Rest,
391}
392#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
393#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
394#[derive(gproxy_protocol_macros::DeclaredFields)]
395pub enum FilePartType {
396 #[serde(rename = "file")]
397 File,
398}
399#[derive(
400 Debug, Clone, PartialEq, Eq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder,
401)]
402#[serde(rename_all = "snake_case")]
403#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
404#[derive(gproxy_protocol_macros::DeclaredFields)]
405pub struct FileRef {
406 #[serde(skip_serializing_if = "Option::is_none")]
407 pub file_data: Option<String>,
408 #[serde(skip_serializing_if = "Option::is_none")]
409 pub file_id: Option<String>,
410 #[serde(skip_serializing_if = "Option::is_none")]
411 pub filename: Option<String>,
412 #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
413 pub rest: Rest,
414}
415#[derive(
416 Debug, Clone, PartialEq, Eq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder,
417)]
418#[serde(rename_all = "snake_case")]
419#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
420#[derive(gproxy_protocol_macros::DeclaredFields)]
421pub struct PromptCacheBreakpoint {
422 pub mode: PromptCacheMode,
423 #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
424 pub rest: Rest,
425}
426#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
427#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
428#[derive(gproxy_protocol_macros::DeclaredFields)]
429pub enum PromptCacheMode {
430 #[serde(rename = "explicit")]
431 Explicit,
432}
433
434#[derive(
435 Debug, Clone, PartialEq, Eq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder,
436)]
437#[serde(rename_all = "snake_case")]
438#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
439#[derive(gproxy_protocol_macros::DeclaredFields)]
440pub struct AssistantAudio {
441 pub id: String,
442 #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
443 pub rest: Rest,
444}
445#[derive(
446 Debug, Clone, PartialEq, Eq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder,
447)]
448#[serde(rename_all = "snake_case")]
449#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
450#[derive(gproxy_protocol_macros::DeclaredFields)]
451pub struct FunctionCall {
452 pub arguments: String,
453 pub name: String,
454 #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
455 pub rest: Rest,
456}
457#[derive(
458 Debug, Clone, PartialEq, Eq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder,
459)]
460#[serde(rename_all = "snake_case")]
461#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
462#[derive(gproxy_protocol_macros::DeclaredFields)]
463pub struct ChatToolCall {
464 pub id: String,
465 pub function: FunctionCall,
466 #[serde(rename = "type")]
467 pub type_: ChatToolCallType,
468 #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
469 pub rest: Rest,
470}
471#[derive(
472 Debug, Clone, PartialEq, Eq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder,
473)]
474#[serde(rename_all = "snake_case")]
475#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
476#[derive(gproxy_protocol_macros::DeclaredFields)]
477pub struct CustomToolCall {
478 pub id: String,
479 pub custom: CustomCall,
480 #[serde(rename = "type")]
481 pub type_: CustomToolCallType,
482 #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
483 pub rest: Rest,
484}
485#[derive(
486 Debug, Clone, PartialEq, Eq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder,
487)]
488#[serde(rename_all = "snake_case")]
489#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
490#[derive(gproxy_protocol_macros::DeclaredFields)]
491pub struct CustomCall {
492 pub input: String,
493 pub name: String,
494 #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
495 pub rest: Rest,
496}
497#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
498#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
499#[derive(gproxy_protocol_macros::DeclaredFields)]
500pub enum ChatToolCallType {
501 #[serde(rename = "function")]
502 Function,
503}
504#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
505#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
506#[derive(gproxy_protocol_macros::DeclaredFields)]
507pub enum CustomToolCallType {
508 #[serde(rename = "custom")]
509 Custom,
510}
511
512#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
513#[serde(untagged)]
514#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
515#[derive(gproxy_protocol_macros::DeclaredFields)]
516pub enum MessageToolCall {
517 Function(ChatToolCall),
518 Custom(CustomToolCall),
519}