Skip to main content

gproxy_protocol/protocol/openai/generate_content/
response_tools.rs

1use std::collections::BTreeMap;
2
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5
6use super::super::common::*;
7
8#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
9#[serde(tag = "type")]
10pub enum ResponseTool {
11    #[serde(rename = "function")]
12    Function {
13        name: String,
14        parameters: JsonSchema,
15        // Some OpenAI-compatible Responses providers echo `strict: null`.
16        #[serde(skip_serializing_if = "Option::is_none")]
17        strict: Option<bool>,
18        #[serde(skip_serializing_if = "Option::is_none")]
19        defer_loading: Option<bool>,
20        #[serde(skip_serializing_if = "Option::is_none")]
21        description: Option<String>,
22        #[serde(skip_serializing_if = "Option::is_none")]
23        allowed_callers: Option<Vec<ToolCaller>>,
24        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
25        extra: Extra,
26    },
27    #[serde(rename = "file_search")]
28    FileSearch {
29        vector_store_ids: Vec<String>,
30        #[serde(skip_serializing_if = "Option::is_none")]
31        filters: Option<FileSearchFilter>,
32        #[serde(skip_serializing_if = "Option::is_none")]
33        max_num_results: Option<u32>,
34        #[serde(skip_serializing_if = "Option::is_none")]
35        ranking_options: Option<FileSearchRankingOptions>,
36        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
37        extra: Extra,
38    },
39    #[serde(rename = "computer")]
40    Computer {
41        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
42        extra: Extra,
43    },
44    #[serde(rename = "computer_use_preview")]
45    ComputerUsePreview {
46        display_height: u32,
47        display_width: u32,
48        environment: ComputerUseEnvironment,
49        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
50        extra: Extra,
51    },
52    #[serde(rename = "web_search")]
53    WebSearch {
54        #[serde(skip_serializing_if = "Option::is_none")]
55        filters: Option<WebSearchFilters>,
56        #[serde(skip_serializing_if = "Option::is_none")]
57        search_context_size: Option<SearchContextSize>,
58        #[serde(skip_serializing_if = "Option::is_none")]
59        user_location: Option<WebSearchUserLocation>,
60        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
61        extra: Extra,
62    },
63    #[serde(rename = "web_search_2025_08_26")]
64    WebSearch20250826 {
65        #[serde(skip_serializing_if = "Option::is_none")]
66        filters: Option<WebSearchFilters>,
67        #[serde(skip_serializing_if = "Option::is_none")]
68        search_context_size: Option<SearchContextSize>,
69        #[serde(skip_serializing_if = "Option::is_none")]
70        user_location: Option<WebSearchUserLocation>,
71        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
72        extra: Extra,
73    },
74    #[serde(rename = "x_search")]
75    XSearch {
76        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
77        extra: Extra,
78    },
79    #[serde(rename = "collections_search")]
80    CollectionsSearch {
81        vector_store_ids: Vec<String>,
82        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
83        extra: Extra,
84    },
85    #[serde(rename = "mcp")]
86    Mcp {
87        server_label: String,
88        #[serde(skip_serializing_if = "Option::is_none")]
89        allowed_tools: Option<McpAllowedTools>,
90        #[serde(skip_serializing_if = "Option::is_none")]
91        authorization: Option<String>,
92        #[serde(skip_serializing_if = "Option::is_none")]
93        connector_id: Option<McpConnectorId>,
94        #[serde(skip_serializing_if = "Option::is_none")]
95        defer_loading: Option<bool>,
96        #[serde(skip_serializing_if = "Option::is_none")]
97        headers: Option<BTreeMap<String, String>>,
98        #[serde(skip_serializing_if = "Option::is_none")]
99        require_approval: Option<McpRequireApproval>,
100        #[serde(skip_serializing_if = "Option::is_none")]
101        server_description: Option<String>,
102        #[serde(skip_serializing_if = "Option::is_none")]
103        server_url: Option<String>,
104        #[serde(skip_serializing_if = "Option::is_none")]
105        tunnel_id: Option<String>,
106        #[serde(skip_serializing_if = "Option::is_none")]
107        allowed_callers: Option<Vec<ToolCaller>>,
108        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
109        extra: Extra,
110    },
111    #[serde(rename = "code_execution")]
112    CodeExecution {
113        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
114        extra: Extra,
115    },
116    #[serde(rename = "code_interpreter")]
117    CodeInterpreter {
118        container: CodeInterpreterContainer,
119        #[serde(skip_serializing_if = "Option::is_none")]
120        allowed_callers: Option<Vec<ToolCaller>>,
121        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
122        extra: Extra,
123    },
124    #[serde(rename = "image_generation")]
125    ImageGeneration {
126        #[serde(skip_serializing_if = "Option::is_none")]
127        action: Option<ImageGenerationAction>,
128        #[serde(skip_serializing_if = "Option::is_none")]
129        background: Option<ImageBackground>,
130        #[serde(skip_serializing_if = "Option::is_none")]
131        input_fidelity: Option<ImageInputFidelity>,
132        #[serde(skip_serializing_if = "Option::is_none")]
133        input_image_mask: Option<ImageMask>,
134        #[serde(skip_serializing_if = "Option::is_none")]
135        model: Option<OpenAiModelId>,
136        #[serde(skip_serializing_if = "Option::is_none")]
137        moderation: Option<ImageModeration>,
138        #[serde(skip_serializing_if = "Option::is_none")]
139        output_compression: Option<u32>,
140        #[serde(skip_serializing_if = "Option::is_none")]
141        output_format: Option<ImageOutputFormat>,
142        #[serde(skip_serializing_if = "Option::is_none")]
143        partial_images: Option<u32>,
144        #[serde(skip_serializing_if = "Option::is_none")]
145        quality: Option<ImageEditQuality>,
146        #[serde(skip_serializing_if = "Option::is_none")]
147        size: Option<ResponseImageGenerationSize>,
148        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
149        extra: Extra,
150    },
151    #[serde(rename = "local_shell")]
152    LocalShell {
153        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
154        extra: Extra,
155    },
156    #[serde(rename = "shell")]
157    Shell {
158        #[serde(skip_serializing_if = "Option::is_none")]
159        environment: Option<ResponseShellEnvironment>,
160        #[serde(skip_serializing_if = "Option::is_none")]
161        allowed_callers: Option<Vec<ToolCaller>>,
162        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
163        extra: Extra,
164    },
165    #[serde(rename = "custom")]
166    Custom {
167        name: String,
168        #[serde(skip_serializing_if = "Option::is_none")]
169        defer_loading: Option<bool>,
170        #[serde(skip_serializing_if = "Option::is_none")]
171        description: Option<String>,
172        #[serde(skip_serializing_if = "Option::is_none")]
173        format: Option<CustomToolInputFormat>,
174        #[serde(skip_serializing_if = "Option::is_none")]
175        allowed_callers: Option<Vec<ToolCaller>>,
176        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
177        extra: Extra,
178    },
179    #[serde(rename = "namespace")]
180    Namespace {
181        description: String,
182        name: String,
183        tools: Vec<ResponseNamespaceTool>,
184        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
185        extra: Extra,
186    },
187    #[serde(rename = "tool_search")]
188    ToolSearch {
189        #[serde(skip_serializing_if = "Option::is_none")]
190        description: Option<String>,
191        #[serde(skip_serializing_if = "Option::is_none")]
192        execution: Option<ToolSearchExecution>,
193        #[serde(skip_serializing_if = "Option::is_none")]
194        parameters: Option<Value>,
195        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
196        extra: Extra,
197    },
198    #[serde(rename = "programmatic_tool_calling")]
199    ProgrammaticToolCalling {
200        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
201        extra: Extra,
202    },
203    #[serde(rename = "web_search_preview")]
204    WebSearchPreview {
205        #[serde(skip_serializing_if = "Option::is_none")]
206        search_content_types: Option<Vec<SearchContentType>>,
207        #[serde(skip_serializing_if = "Option::is_none")]
208        search_context_size: Option<SearchContextSize>,
209        #[serde(skip_serializing_if = "Option::is_none")]
210        user_location: Option<WebSearchPreviewUserLocation>,
211        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
212        extra: Extra,
213    },
214    #[serde(rename = "web_search_preview_2025_03_11")]
215    WebSearchPreview20250311 {
216        #[serde(skip_serializing_if = "Option::is_none")]
217        search_content_types: Option<Vec<SearchContentType>>,
218        #[serde(skip_serializing_if = "Option::is_none")]
219        search_context_size: Option<SearchContextSize>,
220        #[serde(skip_serializing_if = "Option::is_none")]
221        user_location: Option<WebSearchPreviewUserLocation>,
222        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
223        extra: Extra,
224    },
225    #[serde(rename = "apply_patch")]
226    ApplyPatch {
227        #[serde(skip_serializing_if = "Option::is_none")]
228        allowed_callers: Option<Vec<ToolCaller>>,
229        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
230        extra: Extra,
231    },
232}
233
234#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
235#[serde(tag = "type")]
236pub enum ResponseNamespaceTool {
237    #[serde(rename = "function")]
238    Function {
239        name: String,
240        #[serde(skip_serializing_if = "Option::is_none")]
241        defer_loading: Option<bool>,
242        #[serde(skip_serializing_if = "Option::is_none")]
243        description: Option<String>,
244        #[serde(skip_serializing_if = "Option::is_none")]
245        parameters: Option<Value>,
246        #[serde(skip_serializing_if = "Option::is_none")]
247        strict: Option<bool>,
248        #[serde(skip_serializing_if = "Option::is_none")]
249        allowed_callers: Option<Vec<ToolCaller>>,
250        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
251        extra: Extra,
252    },
253    #[serde(rename = "custom")]
254    Custom {
255        name: String,
256        #[serde(skip_serializing_if = "Option::is_none")]
257        defer_loading: Option<bool>,
258        #[serde(skip_serializing_if = "Option::is_none")]
259        description: Option<String>,
260        #[serde(skip_serializing_if = "Option::is_none")]
261        format: Option<CustomToolInputFormat>,
262        #[serde(skip_serializing_if = "Option::is_none")]
263        allowed_callers: Option<Vec<ToolCaller>>,
264        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
265        extra: Extra,
266    },
267}
268
269#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
270#[serde(untagged)]
271pub enum FileSearchFilter {
272    Comparison(FileSearchComparisonFilter),
273    Compound(FileSearchCompoundFilter),
274}
275
276#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
277pub struct FileSearchComparisonFilter {
278    pub key: String,
279    #[serde(rename = "type")]
280    pub type_: FileSearchComparisonOperator,
281    pub value: FileSearchComparisonValue,
282    #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
283    pub extra: Extra,
284}
285
286#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
287#[serde(untagged)]
288pub enum FileSearchComparisonValue {
289    String(String),
290    Number(f64),
291    Boolean(bool),
292    List(Vec<FileSearchComparisonListValue>),
293}
294
295#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
296#[serde(untagged)]
297pub enum FileSearchComparisonListValue {
298    String(String),
299    Number(f64),
300}
301
302#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
303pub enum FileSearchComparisonOperator {
304    #[serde(rename = "eq")]
305    Eq,
306    #[serde(rename = "ne")]
307    Ne,
308    #[serde(rename = "gt")]
309    Gt,
310    #[serde(rename = "gte")]
311    Gte,
312    #[serde(rename = "lt")]
313    Lt,
314    #[serde(rename = "lte")]
315    Lte,
316    #[serde(rename = "in")]
317    In,
318    #[serde(rename = "nin")]
319    Nin,
320}
321
322#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
323pub struct FileSearchCompoundFilter {
324    pub filters: Vec<FileSearchFilter>,
325    #[serde(rename = "type")]
326    pub type_: FileSearchCompoundOperator,
327    #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
328    pub extra: Extra,
329}
330
331#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
332pub enum FileSearchCompoundOperator {
333    #[serde(rename = "and")]
334    And,
335    #[serde(rename = "or")]
336    Or,
337}
338
339#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
340pub struct FileSearchRankingOptions {
341    #[serde(skip_serializing_if = "Option::is_none")]
342    pub hybrid_search: Option<FileSearchHybridSearch>,
343    #[serde(skip_serializing_if = "Option::is_none")]
344    pub ranker: Option<FileSearchRanker>,
345    #[serde(skip_serializing_if = "Option::is_none")]
346    pub score_threshold: Option<f64>,
347    #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
348    pub extra: Extra,
349}
350
351#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
352pub struct FileSearchHybridSearch {
353    pub embedding_weight: f64,
354    pub text_weight: f64,
355    #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
356    pub extra: Extra,
357}
358
359#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
360pub enum FileSearchRanker {
361    #[serde(rename = "auto")]
362    Auto,
363    #[serde(rename = "default-2024-11-15")]
364    Default20241115,
365}
366
367#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
368pub enum ComputerUseEnvironment {
369    #[serde(rename = "windows")]
370    Windows,
371    #[serde(rename = "mac")]
372    Mac,
373    #[serde(rename = "linux")]
374    Linux,
375    #[serde(rename = "ubuntu")]
376    Ubuntu,
377    #[serde(rename = "browser")]
378    Browser,
379}
380
381#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
382pub struct WebSearchFilters {
383    #[serde(skip_serializing_if = "Option::is_none")]
384    pub allowed_domains: Option<Vec<String>>,
385    #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
386    pub extra: Extra,
387}
388
389#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
390pub struct WebSearchUserLocation {
391    #[serde(skip_serializing_if = "Option::is_none")]
392    pub city: Option<String>,
393    #[serde(skip_serializing_if = "Option::is_none")]
394    pub country: Option<String>,
395    #[serde(skip_serializing_if = "Option::is_none")]
396    pub region: Option<String>,
397    #[serde(skip_serializing_if = "Option::is_none")]
398    pub timezone: Option<String>,
399    #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
400    pub type_: Option<ApproximateLocationType>,
401    #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
402    pub extra: Extra,
403}
404
405#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
406#[serde(untagged)]
407pub enum McpAllowedTools {
408    Names(Vec<String>),
409    Filter(McpToolFilter),
410}
411
412#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
413pub struct McpToolFilter {
414    #[serde(skip_serializing_if = "Option::is_none")]
415    pub read_only: Option<bool>,
416    #[serde(skip_serializing_if = "Option::is_none")]
417    pub tool_names: Option<Vec<String>>,
418    #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
419    pub extra: Extra,
420}
421
422#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
423pub enum McpConnectorId {
424    #[serde(rename = "connector_dropbox")]
425    Dropbox,
426    #[serde(rename = "connector_gmail")]
427    Gmail,
428    #[serde(rename = "connector_googlecalendar")]
429    GoogleCalendar,
430    #[serde(rename = "connector_googledrive")]
431    GoogleDrive,
432    #[serde(rename = "connector_microsoftteams")]
433    MicrosoftTeams,
434    #[serde(rename = "connector_outlookcalendar")]
435    OutlookCalendar,
436    #[serde(rename = "connector_outlookemail")]
437    OutlookEmail,
438    #[serde(rename = "connector_sharepoint")]
439    SharePoint,
440}
441
442#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
443#[serde(untagged)]
444pub enum McpRequireApproval {
445    Setting(McpApprovalSetting),
446    Filter(McpToolApprovalFilter),
447}
448
449#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
450pub enum McpApprovalSetting {
451    #[serde(rename = "always")]
452    Always,
453    #[serde(rename = "never")]
454    Never,
455}
456
457#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
458pub struct McpToolApprovalFilter {
459    #[serde(skip_serializing_if = "Option::is_none")]
460    pub always: Option<McpToolFilter>,
461    #[serde(skip_serializing_if = "Option::is_none")]
462    pub never: Option<McpToolFilter>,
463    #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
464    pub extra: Extra,
465}
466
467#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
468#[serde(untagged)]
469pub enum CodeInterpreterContainer {
470    Id(String),
471    Auto(CodeInterpreterAutoContainer),
472}
473
474#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
475pub struct CodeInterpreterAutoContainer {
476    #[serde(rename = "type")]
477    pub type_: CodeInterpreterContainerType,
478    #[serde(skip_serializing_if = "Option::is_none")]
479    pub file_ids: Option<Vec<String>>,
480    #[serde(skip_serializing_if = "Option::is_none")]
481    pub memory_limit: Option<CodeInterpreterMemoryLimit>,
482    #[serde(skip_serializing_if = "Option::is_none")]
483    pub network_policy: Option<CodeInterpreterNetworkPolicy>,
484    #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
485    pub extra: Extra,
486}
487
488#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
489#[serde(tag = "type")]
490pub enum CodeInterpreterNetworkPolicy {
491    #[serde(rename = "disabled")]
492    Disabled {
493        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
494        extra: Extra,
495    },
496    #[serde(rename = "allowlist")]
497    Allowlist {
498        allowed_domains: Vec<String>,
499        #[serde(skip_serializing_if = "Option::is_none")]
500        domain_secrets: Option<Vec<CodeInterpreterDomainSecret>>,
501        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
502        extra: Extra,
503    },
504}
505
506#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
507pub struct CodeInterpreterDomainSecret {
508    pub domain: String,
509    pub name: String,
510    pub value: String,
511    #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
512    pub extra: Extra,
513}
514
515#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
516pub struct ImageMask {
517    #[serde(skip_serializing_if = "Option::is_none")]
518    pub file_id: Option<String>,
519    #[serde(skip_serializing_if = "Option::is_none")]
520    pub image_url: Option<String>,
521    #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
522    pub extra: Extra,
523}
524
525#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
526#[serde(tag = "type")]
527pub enum ResponseShellEnvironment {
528    #[serde(rename = "container_auto")]
529    ContainerAuto {
530        #[serde(skip_serializing_if = "Option::is_none")]
531        file_ids: Option<Vec<String>>,
532        #[serde(skip_serializing_if = "Option::is_none")]
533        memory_limit: Option<CodeInterpreterMemoryLimit>,
534        #[serde(skip_serializing_if = "Option::is_none")]
535        network_policy: Option<CodeInterpreterNetworkPolicy>,
536        #[serde(skip_serializing_if = "Option::is_none")]
537        skills: Option<Vec<ResponseShellContainerSkill>>,
538    },
539    #[serde(rename = "local")]
540    Local {
541        #[serde(skip_serializing_if = "Option::is_none")]
542        skills: Option<Vec<ResponseShellLocalSkill>>,
543    },
544    #[serde(rename = "container_reference")]
545    ContainerReference { container_id: String },
546}
547
548#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
549#[serde(untagged)]
550pub enum ResponseShellContainerSkill {
551    Reference(ResponseShellSkillReference),
552    Inline(ResponseShellInlineSkill),
553}
554
555#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
556pub struct ResponseShellSkillReference {
557    pub skill_id: String,
558    #[serde(rename = "type")]
559    pub type_: ResponseShellSkillReferenceType,
560    #[serde(skip_serializing_if = "Option::is_none")]
561    pub version: Option<String>,
562    #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
563    pub extra: Extra,
564}
565
566#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
567pub enum ResponseShellSkillReferenceType {
568    #[serde(rename = "skill_reference")]
569    SkillReference,
570}
571
572#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
573pub struct ResponseShellInlineSkill {
574    pub description: String,
575    pub name: String,
576    pub source: ResponseShellInlineSkillSource,
577    #[serde(rename = "type")]
578    pub type_: ResponseShellInlineSkillType,
579    #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
580    pub extra: Extra,
581}
582
583#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
584pub enum ResponseShellInlineSkillType {
585    #[serde(rename = "inline")]
586    Inline,
587}
588
589#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
590pub struct ResponseShellInlineSkillSource {
591    pub data: String,
592    pub media_type: ResponseShellInlineSkillMediaType,
593    #[serde(rename = "type")]
594    pub type_: ResponseShellInlineSkillSourceType,
595    #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
596    pub extra: Extra,
597}
598
599#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
600pub enum ResponseShellInlineSkillMediaType {
601    #[serde(rename = "application/zip")]
602    ApplicationZip,
603}
604
605#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
606pub enum ResponseShellInlineSkillSourceType {
607    #[serde(rename = "base64")]
608    Base64,
609}
610
611#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
612pub struct ResponseShellLocalSkill {
613    pub description: String,
614    pub name: String,
615    pub path: String,
616    #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
617    pub extra: Extra,
618}
619
620#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
621pub enum SearchContentType {
622    #[serde(rename = "text")]
623    Text,
624    #[serde(rename = "image")]
625    Image,
626}
627
628#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
629pub struct WebSearchPreviewUserLocation {
630    #[serde(rename = "type")]
631    pub type_: ApproximateLocationType,
632    #[serde(skip_serializing_if = "Option::is_none")]
633    pub city: Option<String>,
634    #[serde(skip_serializing_if = "Option::is_none")]
635    pub country: Option<String>,
636    #[serde(skip_serializing_if = "Option::is_none")]
637    pub region: Option<String>,
638    #[serde(skip_serializing_if = "Option::is_none")]
639    pub timezone: Option<String>,
640    #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
641    pub extra: Extra,
642}