Skip to main content

gproxy_protocol/wire/openai/chat/
content.rs

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// Keep the public wire variants inline, as with the Claude content unions.
25#[allow(clippy::large_enum_variant)]
26#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
27pub enum ChatMessage {
28    Developer(DeveloperMessage),
29    System(SystemMessage),
30    User(UserMessage),
31    Assistant(AssistantMessage),
32    Tool(ToolMessage),
33    Function(FunctionMessage),
34}
35
36#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
37#[serde(rename_all = "snake_case")]
38#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
39#[derive(gproxy_protocol_macros::DeclaredFields)]
40#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
41pub struct DeveloperMessage {
42    pub role: DeveloperRole,
43    pub content: TextContent,
44    #[serde(skip_serializing_if = "Option::is_none")]
45    pub name: Option<String>,
46    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
47    pub rest: Rest,
48}
49#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
50#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
51#[derive(gproxy_protocol_macros::DeclaredFields)]
52#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
53pub enum DeveloperRole {
54    #[serde(rename = "developer")]
55    Developer,
56}
57
58#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
59#[serde(rename_all = "snake_case")]
60#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
61#[derive(gproxy_protocol_macros::DeclaredFields)]
62#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
63pub struct SystemMessage {
64    pub role: SystemRole,
65    pub content: TextContent,
66    #[serde(skip_serializing_if = "Option::is_none")]
67    pub name: Option<String>,
68    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
69    pub rest: Rest,
70}
71#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
72#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
73#[derive(gproxy_protocol_macros::DeclaredFields)]
74#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
75pub enum SystemRole {
76    #[serde(rename = "system")]
77    System,
78}
79
80#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
81#[serde(rename_all = "snake_case")]
82#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
83#[derive(gproxy_protocol_macros::DeclaredFields)]
84#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
85pub struct UserMessage {
86    pub role: UserRole,
87    pub content: UserContent,
88    #[serde(skip_serializing_if = "Option::is_none")]
89    pub name: Option<String>,
90    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
91    pub rest: Rest,
92}
93#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
94#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
95#[derive(gproxy_protocol_macros::DeclaredFields)]
96#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
97pub enum UserRole {
98    #[serde(rename = "user")]
99    User,
100}
101
102#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
103#[serde(rename_all = "snake_case")]
104#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
105#[derive(gproxy_protocol_macros::DeclaredFields)]
106#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
107pub struct AssistantMessage {
108    #[serde(
109        default,
110        deserialize_with = "present_nullable",
111        skip_serializing_if = "Option::is_none"
112    )]
113    pub reasoning_details: Option<Option<Vec<super::reasoning::ReasoningDetail>>>,
114    /// Plain-text reasoning returned by compatible providers (for example DeepSeek).
115    #[serde(
116        default,
117        deserialize_with = "present_nullable",
118        skip_serializing_if = "Option::is_none"
119    )]
120    pub reasoning_content: Option<Option<String>>,
121    /// Alternative compatible-provider spelling. Kept separately on the wire.
122    #[serde(
123        default,
124        deserialize_with = "present_nullable",
125        skip_serializing_if = "Option::is_none"
126    )]
127    pub reasoning: Option<Option<String>>,
128    pub role: AssistantRole,
129    #[serde(
130        default,
131        deserialize_with = "present_nullable",
132        skip_serializing_if = "Option::is_none"
133    )]
134    pub content: Option<Option<AssistantContent>>,
135    #[serde(
136        default,
137        deserialize_with = "present_nullable",
138        skip_serializing_if = "Option::is_none"
139    )]
140    pub audio: Option<Option<AssistantAudio>>,
141    #[serde(
142        default,
143        deserialize_with = "present_nullable",
144        skip_serializing_if = "Option::is_none"
145    )]
146    pub refusal: Option<Option<String>>,
147    #[serde(skip_serializing_if = "Option::is_none")]
148    pub name: Option<String>,
149    #[serde(skip_serializing_if = "Option::is_none")]
150    pub tool_calls: Option<Vec<MessageToolCall>>,
151    #[serde(
152        default,
153        deserialize_with = "present_nullable",
154        skip_serializing_if = "Option::is_none"
155    )]
156    pub function_call: Option<Option<FunctionCall>>,
157    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
158    pub rest: Rest,
159}
160#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
161#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
162#[derive(gproxy_protocol_macros::DeclaredFields)]
163#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
164pub enum AssistantRole {
165    #[serde(rename = "assistant")]
166    Assistant,
167}
168
169#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
170#[serde(rename_all = "snake_case")]
171#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
172#[derive(gproxy_protocol_macros::DeclaredFields)]
173#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
174pub struct ToolMessage {
175    pub role: ToolRole,
176    pub content: TextContent,
177    pub tool_call_id: String,
178    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
179    pub rest: Rest,
180}
181#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
182#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
183#[derive(gproxy_protocol_macros::DeclaredFields)]
184#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
185pub enum ToolRole {
186    #[serde(rename = "tool")]
187    Tool,
188}
189
190#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
191#[serde(rename_all = "snake_case")]
192#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
193#[derive(gproxy_protocol_macros::DeclaredFields)]
194#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
195pub struct FunctionMessage {
196    pub role: FunctionRole,
197    #[wire(required)]
198    #[cfg_attr(feature = "schema", schemars(extend("x-gproxy-required" = true)))]
199    #[serde(deserialize_with = "required_nullable")]
200    pub content: Option<String>,
201    pub name: String,
202    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
203    pub rest: Rest,
204}
205#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
206#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
207#[derive(gproxy_protocol_macros::DeclaredFields)]
208#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
209pub enum FunctionRole {
210    #[serde(rename = "function")]
211    Function,
212}
213
214pub type TextContent = StringOrTextParts;
215#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
216#[serde(untagged)]
217#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
218#[derive(gproxy_protocol_macros::DeclaredFields)]
219#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
220pub enum StringOrTextParts {
221    Text(String),
222    Parts(Vec<TextPart>),
223}
224pub type UserContent = UserContentParts;
225#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
226#[serde(untagged)]
227#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
228#[derive(gproxy_protocol_macros::DeclaredFields)]
229#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
230pub enum UserContentParts {
231    Text(String),
232    Parts(Vec<UserContentPart>),
233}
234pub type AssistantContent = AssistantContentParts;
235#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
236#[serde(untagged)]
237#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
238#[derive(gproxy_protocol_macros::DeclaredFields)]
239#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
240pub enum AssistantContentParts {
241    Text(String),
242    Parts(Vec<AssistantContentPart>),
243}
244
245#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
246#[serde(untagged)]
247#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
248#[derive(gproxy_protocol_macros::DeclaredFields)]
249#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
250pub enum UserContentPart {
251    #[serde(rename = "text")]
252    Text(TextPart),
253    #[serde(rename = "image_url")]
254    Image(ImagePart),
255    #[serde(rename = "input_audio")]
256    InputAudio(InputAudioPart),
257    #[serde(rename = "file")]
258    File(FilePart),
259}
260#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
261#[serde(untagged)]
262#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
263#[derive(gproxy_protocol_macros::DeclaredFields)]
264#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
265pub enum AssistantContentPart {
266    #[serde(rename = "text")]
267    Text(TextPart),
268    #[serde(rename = "refusal")]
269    Refusal(RefusalPart),
270}
271#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
272#[serde(rename_all = "snake_case")]
273#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
274#[derive(gproxy_protocol_macros::DeclaredFields)]
275#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
276pub struct TextPart {
277    #[serde(rename = "type")]
278    pub type_: TextPartType,
279    pub text: String,
280    #[serde(skip_serializing_if = "Option::is_none")]
281    pub prompt_cache_breakpoint: Option<PromptCacheBreakpoint>,
282    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
283    pub rest: Rest,
284}
285#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
286#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
287#[derive(gproxy_protocol_macros::DeclaredFields)]
288#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
289pub enum TextPartType {
290    #[serde(rename = "text")]
291    Text,
292}
293#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
294#[serde(rename_all = "snake_case")]
295#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
296#[derive(gproxy_protocol_macros::DeclaredFields)]
297#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
298pub struct RefusalPart {
299    #[serde(rename = "type")]
300    pub type_: RefusalType,
301    pub refusal: String,
302    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
303    pub rest: Rest,
304}
305#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
306#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
307#[derive(gproxy_protocol_macros::DeclaredFields)]
308#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
309pub enum RefusalType {
310    #[serde(rename = "refusal")]
311    Refusal,
312}
313#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
314#[serde(rename_all = "snake_case")]
315#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
316#[derive(gproxy_protocol_macros::DeclaredFields)]
317#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
318pub struct ImagePart {
319    #[serde(rename = "type")]
320    pub type_: ImagePartType,
321    pub image_url: ImageUrl,
322    #[serde(skip_serializing_if = "Option::is_none")]
323    pub prompt_cache_breakpoint: Option<PromptCacheBreakpoint>,
324    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
325    pub rest: Rest,
326}
327#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
328#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
329#[derive(gproxy_protocol_macros::DeclaredFields)]
330#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
331pub enum ImagePartType {
332    #[serde(rename = "image_url")]
333    ImageUrl,
334}
335#[derive(
336    Debug, Clone, PartialEq, Eq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder,
337)]
338#[serde(rename_all = "snake_case")]
339#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
340#[derive(gproxy_protocol_macros::DeclaredFields)]
341#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
342pub struct ImageUrl {
343    pub url: String,
344    #[serde(skip_serializing_if = "Option::is_none")]
345    pub detail: Option<ImageDetail>,
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)]
352#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
353pub enum ImageDetail {
354    #[serde(rename = "auto")]
355    Auto,
356    #[serde(rename = "low")]
357    Low,
358    #[serde(rename = "high")]
359    High,
360}
361#[derive(
362    Debug, Clone, PartialEq, Eq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder,
363)]
364#[serde(rename_all = "snake_case")]
365#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
366#[derive(gproxy_protocol_macros::DeclaredFields)]
367#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
368pub struct InputAudioPart {
369    #[serde(rename = "type")]
370    pub type_: InputAudioPartType,
371    pub input_audio: InputAudio,
372    #[serde(skip_serializing_if = "Option::is_none")]
373    pub prompt_cache_breakpoint: Option<PromptCacheBreakpoint>,
374    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
375    pub rest: Rest,
376}
377#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
378#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
379#[derive(gproxy_protocol_macros::DeclaredFields)]
380#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
381pub enum InputAudioPartType {
382    #[serde(rename = "input_audio")]
383    InputAudio,
384}
385#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
386#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
387#[derive(gproxy_protocol_macros::DeclaredFields)]
388#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
389pub enum AudioFormat {
390    #[serde(rename = "wav")]
391    Wav,
392    #[serde(rename = "mp3")]
393    Mp3,
394}
395#[derive(
396    Debug, Clone, PartialEq, Eq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder,
397)]
398#[serde(rename_all = "snake_case")]
399#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
400#[derive(gproxy_protocol_macros::DeclaredFields)]
401#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
402pub struct InputAudio {
403    pub data: String,
404    pub format: AudioFormat,
405    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
406    pub rest: Rest,
407}
408#[derive(
409    Debug, Clone, PartialEq, Eq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder,
410)]
411#[serde(rename_all = "snake_case")]
412#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
413#[derive(gproxy_protocol_macros::DeclaredFields)]
414#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
415pub struct FilePart {
416    #[serde(rename = "type")]
417    pub type_: FilePartType,
418    pub file: FileRef,
419    #[serde(skip_serializing_if = "Option::is_none")]
420    pub prompt_cache_breakpoint: Option<PromptCacheBreakpoint>,
421    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
422    pub rest: Rest,
423}
424#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
425#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
426#[derive(gproxy_protocol_macros::DeclaredFields)]
427#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
428pub enum FilePartType {
429    #[serde(rename = "file")]
430    File,
431}
432#[derive(
433    Debug, Clone, PartialEq, Eq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder,
434)]
435#[serde(rename_all = "snake_case")]
436#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
437#[derive(gproxy_protocol_macros::DeclaredFields)]
438#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
439pub struct FileRef {
440    #[serde(skip_serializing_if = "Option::is_none")]
441    pub file_data: Option<String>,
442    #[serde(skip_serializing_if = "Option::is_none")]
443    pub file_id: Option<String>,
444    #[serde(skip_serializing_if = "Option::is_none")]
445    pub filename: Option<String>,
446    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
447    pub rest: Rest,
448}
449#[derive(
450    Debug, Clone, PartialEq, Eq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder,
451)]
452#[serde(rename_all = "snake_case")]
453#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
454#[derive(gproxy_protocol_macros::DeclaredFields)]
455#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
456pub struct PromptCacheBreakpoint {
457    pub mode: PromptCacheMode,
458    /// Minimum lifetime of this breakpoint; omitted inherits the request TTL.
459    /// OpenAI OpenAPI: PromptCacheBreakpointParam (2026-10-21).
460    #[serde(default, skip_serializing_if = "Option::is_none")]
461    pub ttl: Option<PromptCacheBreakpointTtl>,
462    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
463    pub rest: Rest,
464}
465
466/// Explicit cache-breakpoint lifetimes from OpenAI's PromptCacheBreakpointParam.
467/// Separate from the request-wide PromptCacheTTLEnum and legacy retention policy.
468#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
469#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
470#[derive(gproxy_protocol_macros::DeclaredFields)]
471#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
472pub enum PromptCacheBreakpointTtl {
473    #[serde(rename = "30m")]
474    ThirtyMinutes,
475    #[serde(rename = "12h")]
476    TwelveHours,
477}
478#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
479#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
480#[derive(gproxy_protocol_macros::DeclaredFields)]
481#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
482pub enum PromptCacheMode {
483    #[serde(rename = "explicit")]
484    Explicit,
485}
486
487#[derive(
488    Debug, Clone, PartialEq, Eq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder,
489)]
490#[serde(rename_all = "snake_case")]
491#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
492#[derive(gproxy_protocol_macros::DeclaredFields)]
493#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
494pub struct AssistantAudio {
495    pub id: String,
496    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
497    pub rest: Rest,
498}
499#[derive(
500    Debug, Clone, PartialEq, Eq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder,
501)]
502#[serde(rename_all = "snake_case")]
503#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
504#[derive(gproxy_protocol_macros::DeclaredFields)]
505#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
506pub struct FunctionCall {
507    pub arguments: String,
508    pub name: String,
509    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
510    pub rest: Rest,
511}
512#[derive(
513    Debug, Clone, PartialEq, Eq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder,
514)]
515#[serde(rename_all = "snake_case")]
516#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
517#[derive(gproxy_protocol_macros::DeclaredFields)]
518#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
519pub struct ChatToolCall {
520    pub id: String,
521    pub function: FunctionCall,
522    #[serde(rename = "type")]
523    pub type_: ChatToolCallType,
524    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
525    pub rest: Rest,
526}
527#[derive(
528    Debug, Clone, PartialEq, Eq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder,
529)]
530#[serde(rename_all = "snake_case")]
531#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
532#[derive(gproxy_protocol_macros::DeclaredFields)]
533#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
534pub struct CustomToolCall {
535    pub id: String,
536    pub custom: CustomCall,
537    #[serde(rename = "type")]
538    pub type_: CustomToolCallType,
539    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
540    pub rest: Rest,
541}
542#[derive(
543    Debug, Clone, PartialEq, Eq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder,
544)]
545#[serde(rename_all = "snake_case")]
546#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
547#[derive(gproxy_protocol_macros::DeclaredFields)]
548#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
549pub struct CustomCall {
550    pub input: String,
551    pub name: String,
552    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
553    pub rest: Rest,
554}
555#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
556#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
557#[derive(gproxy_protocol_macros::DeclaredFields)]
558#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
559pub enum ChatToolCallType {
560    #[serde(rename = "function")]
561    Function,
562}
563#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
564#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
565#[derive(gproxy_protocol_macros::DeclaredFields)]
566#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
567pub enum CustomToolCallType {
568    #[serde(rename = "custom")]
569    Custom,
570}
571
572#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
573#[serde(untagged)]
574#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
575#[derive(gproxy_protocol_macros::DeclaredFields)]
576#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
577pub enum MessageToolCall {
578    Function(ChatToolCall),
579    Custom(CustomToolCall),
580}