Skip to main content

linger_openai_sdk/
responses.rs

1use crate::error::LingerError;
2use crate::stream::{SseEvent, SseStream};
3use crate::transport::BodyStream;
4use crate::RequestId;
5use futures_core::Stream;
6use serde::ser::SerializeStruct;
7use serde::{Deserialize, Serialize};
8use serde_json::Value;
9use std::collections::BTreeMap;
10use std::pin::Pin;
11use std::task::{Context, Poll};
12
13/// EN: Request body for `POST /v1/responses`.
14/// 中文:`POST /v1/responses` 的请求体。
15#[derive(Clone, Debug, Serialize, PartialEq)]
16#[non_exhaustive]
17pub struct CreateResponseRequest {
18    /// EN: Model id used to generate the response.
19    /// 中文:用于生成响应的模型 ID。
20    pub model: String,
21    /// EN: Input text or message list.
22    /// 中文:输入文本或消息列表。
23    pub input: ResponseInput,
24    /// EN: Optional system or developer instructions for this response.
25    /// 中文:此响应可选的系统或开发者指令。
26    #[serde(skip_serializing_if = "Option::is_none")]
27    pub instructions: Option<String>,
28    /// EN: Optional model-owned style preset to apply to this response.
29    /// 中文:应用于此响应的可选模型自有风格预设。
30    #[serde(skip_serializing_if = "Option::is_none")]
31    pub personality: Option<String>,
32    /// EN: Optional previous response id for multi-turn conversation state.
33    /// 中文:用于多轮会话状态的可选上一条响应 ID。
34    #[serde(skip_serializing_if = "Option::is_none")]
35    pub previous_response_id: Option<String>,
36    /// EN: Optional conversation this response should belong to.
37    /// 中文:此响应应归属的可选 conversation。
38    #[serde(skip_serializing_if = "Option::is_none")]
39    pub conversation: Option<ResponseConversation>,
40    /// EN: Optional context management entries for this response request.
41    /// 中文:此响应请求的可选上下文管理条目。
42    #[serde(skip_serializing_if = "Option::is_none")]
43    pub context_management: Option<Vec<ResponseContextManagement>>,
44    /// EN: Optional moderation configuration for this response request.
45    /// 中文:此响应请求的可选 moderation 配置。
46    #[serde(skip_serializing_if = "Option::is_none")]
47    pub moderation: Option<ResponseModeration>,
48    /// EN: Optional tools the model may call while generating the response.
49    /// 中文:模型生成响应时可以调用的可选工具列表。
50    #[serde(skip_serializing_if = "Vec::is_empty")]
51    pub tools: Vec<Value>,
52    /// EN: Optional mode controlling whether the model may call tools.
53    /// 中文:控制模型是否可以调用工具的可选模式。
54    #[serde(skip_serializing_if = "Option::is_none")]
55    pub tool_choice: Option<ResponseToolChoice>,
56    /// EN: Optional reusable prompt template reference and variables.
57    /// 中文:可选的可复用 prompt 模板引用及变量。
58    #[serde(skip_serializing_if = "Option::is_none")]
59    pub prompt: Option<ResponsePrompt>,
60    /// EN: Optional upper bound for generated output tokens.
61    /// 中文:生成输出 token 数量的可选上限。
62    #[serde(skip_serializing_if = "Option::is_none")]
63    pub max_output_tokens: Option<u32>,
64    /// EN: Whether to store the generated response for later retrieval.
65    /// 中文:是否存储生成的响应以便稍后检索。
66    #[serde(skip_serializing_if = "Option::is_none")]
67    pub store: Option<bool>,
68    /// EN: Whether to run the model response in the background.
69    /// 中文:是否在后台运行模型响应。
70    #[serde(skip_serializing_if = "Option::is_none")]
71    pub background: Option<bool>,
72    /// EN: Optional maximum number of built-in tool calls for the response.
73    /// 中文:响应中内置工具调用总次数的可选上限。
74    #[serde(skip_serializing_if = "Option::is_none")]
75    pub max_tool_calls: Option<u32>,
76    /// EN: Optional metadata attached to the generated response.
77    /// 中文:附加到生成响应的可选元数据。
78    #[serde(skip_serializing_if = "BTreeMap::is_empty")]
79    pub metadata: BTreeMap<String, String>,
80    /// EN: Whether to allow tool calls to run in parallel.
81    /// 中文:是否允许并行运行工具调用。
82    #[serde(skip_serializing_if = "Option::is_none")]
83    pub parallel_tool_calls: Option<bool>,
84    /// EN: Optional sampling temperature.
85    /// 中文:可选的采样温度。
86    #[serde(skip_serializing_if = "Option::is_none")]
87    pub temperature: Option<f64>,
88    /// EN: Optional nucleus sampling value.
89    /// 中文:可选的 nucleus sampling 值。
90    #[serde(skip_serializing_if = "Option::is_none")]
91    pub top_p: Option<f64>,
92    /// EN: Optional maximum number of top token log probabilities to return.
93    /// 中文:可选的每个 token 位置返回的最高概率 token log probability 数量。
94    #[serde(skip_serializing_if = "Option::is_none")]
95    pub top_logprobs: Option<u8>,
96    /// EN: Optional reasoning configuration for reasoning-capable models.
97    /// 中文:支持推理模型的可选推理配置。
98    #[serde(skip_serializing_if = "Option::is_none")]
99    pub reasoning: Option<ResponseReasoning>,
100    /// EN: Optional context truncation strategy for the response.
101    /// 中文:响应可选的上下文截断策略。
102    #[serde(skip_serializing_if = "Option::is_none")]
103    pub truncation: Option<ResponseTruncation>,
104    /// EN: Optional prompt cache bucketing key for similar requests.
105    /// 中文:用于相似请求提示缓存分桶的可选键。
106    #[serde(skip_serializing_if = "Option::is_none")]
107    pub prompt_cache_key: Option<String>,
108    /// EN: Optional retention policy for prompt cache entries created by this request.
109    /// 中文:此请求创建的提示缓存条目的可选保留策略。
110    #[serde(skip_serializing_if = "Option::is_none")]
111    pub prompt_cache_retention: Option<ResponsePromptCacheRetention>,
112    /// EN: Optional stable safety identifier for abuse detection.
113    /// 中文:用于滥用检测的可选稳定安全标识符。
114    #[serde(skip_serializing_if = "Option::is_none")]
115    pub safety_identifier: Option<String>,
116    /// EN: Optional processing tier for serving the response request.
117    /// 中文:用于处理响应请求的可选服务层级。
118    #[serde(skip_serializing_if = "Option::is_none")]
119    pub service_tier: Option<ResponseServiceTier>,
120    /// EN: Optional additional output data to include in the model response.
121    /// 中文:要包含在模型响应中的可选额外输出数据。
122    #[serde(skip_serializing_if = "Option::is_none")]
123    pub include: Option<Vec<ResponseInclude>>,
124    /// EN: Optional text generation configuration.
125    /// 中文:可选的文本生成配置。
126    #[serde(skip_serializing_if = "Option::is_none")]
127    pub text: Option<ResponseTextConfig>,
128    /// EN: Optional streaming configuration used when streaming a response.
129    /// 中文:流式响应时使用的可选流配置。
130    #[serde(skip_serializing_if = "Option::is_none")]
131    pub stream_options: Option<StreamOptions>,
132    /// EN: Optional stream flag set by streaming convenience methods.
133    /// 中文:由流式便捷方法设置的可选 stream 标志。
134    #[serde(skip_serializing_if = "Option::is_none")]
135    pub stream: Option<bool>,
136    /// EN: Forward-compatible optional fields not yet covered by handwritten types.
137    /// 中文:手写类型尚未覆盖的前向兼容可选字段。
138    #[serde(flatten)]
139    pub extra: BTreeMap<String, Value>,
140}
141
142impl CreateResponseRequest {
143    /// EN: Starts building a create-response request.
144    /// 中文:开始构建创建响应请求。
145    pub fn builder() -> CreateResponseRequestBuilder {
146        CreateResponseRequestBuilder::default()
147    }
148
149    pub(crate) fn into_streaming(mut self) -> Self {
150        self.stream = Some(true);
151        self
152    }
153}
154
155/// EN: Builder for create-response requests.
156/// 中文:创建响应请求的构建器。
157#[derive(Clone, Debug, Default)]
158#[non_exhaustive]
159pub struct CreateResponseRequestBuilder {
160    model: Option<String>,
161    input: Option<ResponseInput>,
162    instructions: Option<String>,
163    personality: Option<String>,
164    previous_response_id: Option<String>,
165    conversation: Option<ResponseConversation>,
166    context_management: Option<Vec<ResponseContextManagement>>,
167    moderation: Option<ResponseModeration>,
168    tools: Vec<Value>,
169    tool_choice: Option<ResponseToolChoice>,
170    prompt: Option<ResponsePrompt>,
171    max_output_tokens: Option<u32>,
172    store: Option<bool>,
173    background: Option<bool>,
174    max_tool_calls: Option<u32>,
175    metadata: BTreeMap<String, String>,
176    parallel_tool_calls: Option<bool>,
177    temperature: Option<f64>,
178    top_p: Option<f64>,
179    top_logprobs: Option<u8>,
180    reasoning: Option<ResponseReasoning>,
181    truncation: Option<ResponseTruncation>,
182    prompt_cache_key: Option<String>,
183    prompt_cache_retention: Option<ResponsePromptCacheRetention>,
184    safety_identifier: Option<String>,
185    service_tier: Option<ResponseServiceTier>,
186    include: Option<Vec<ResponseInclude>>,
187    text: Option<ResponseTextConfig>,
188    stream_options: Option<StreamOptions>,
189    extra: BTreeMap<String, Value>,
190}
191
192impl CreateResponseRequestBuilder {
193    /// EN: Sets the model id.
194    /// 中文:设置模型 ID。
195    pub fn model(mut self, model: impl Into<String>) -> Self {
196        self.model = Some(model.into());
197        self
198    }
199
200    /// EN: Sets the request input.
201    /// 中文:设置请求输入。
202    pub fn input(mut self, input: impl Into<ResponseInput>) -> Self {
203        self.input = Some(input.into());
204        self
205    }
206
207    /// EN: Sets system or developer instructions for this response.
208    /// 中文:设置此响应的系统或开发者指令。
209    pub fn instructions(mut self, instructions: impl Into<String>) -> Self {
210        self.instructions = Some(instructions.into());
211        self
212    }
213
214    /// EN: Sets the model-owned style preset for this response.
215    /// 中文:设置此响应的模型自有风格预设。
216    pub fn personality(mut self, personality: impl Into<String>) -> Self {
217        self.personality = Some(personality.into());
218        self
219    }
220
221    /// EN: Sets the previous response id for multi-turn conversation state.
222    /// 中文:设置用于多轮会话状态的上一条响应 ID。
223    pub fn previous_response_id(mut self, previous_response_id: impl Into<String>) -> Self {
224        self.previous_response_id = Some(previous_response_id.into());
225        self
226    }
227
228    /// EN: Sets the conversation this response should belong to.
229    /// 中文:设置此响应应归属的 conversation。
230    pub fn conversation(mut self, conversation: impl Into<ResponseConversation>) -> Self {
231        self.conversation = Some(conversation.into());
232        self
233    }
234
235    /// EN: Sets context management entries for this response request.
236    /// 中文:设置此响应请求的上下文管理条目。
237    pub fn context_management<I>(mut self, context_management: I) -> Self
238    where
239        I: IntoIterator<Item = ResponseContextManagement>,
240    {
241        self.context_management = Some(context_management.into_iter().collect());
242        self
243    }
244
245    /// EN: Sets moderation configuration for this response request.
246    /// 中文:设置此响应请求的 moderation 配置。
247    pub fn moderation(mut self, moderation: ResponseModeration) -> Self {
248        self.moderation = Some(moderation);
249        self
250    }
251
252    /// EN: Sets the tools the model may call while generating the response.
253    /// 中文:设置模型生成响应时可以调用的工具列表。
254    pub fn tools<T>(mut self, tools: impl IntoIterator<Item = T>) -> Self
255    where
256        T: Into<ResponseTool>,
257    {
258        self.tools = tools
259            .into_iter()
260            .map(|tool| tool.into().into_value())
261            .collect();
262        self
263    }
264
265    /// EN: Adds one tool the model may call while generating the response.
266    /// 中文:添加一个模型生成响应时可以调用的工具。
267    pub fn tool(mut self, tool: impl Into<ResponseTool>) -> Self {
268        self.tools.push(tool.into().into_value());
269        self
270    }
271
272    /// EN: Sets how the model should select tools while generating the response.
273    /// 中文:设置模型生成响应时应如何选择工具。
274    pub fn tool_choice(mut self, tool_choice: ResponseToolChoice) -> Self {
275        self.tool_choice = Some(tool_choice);
276        self
277    }
278
279    /// EN: Sets the reusable prompt template reference for this response.
280    /// 中文:设置此响应使用的可复用 prompt 模板引用。
281    pub fn prompt(mut self, prompt: ResponsePrompt) -> Self {
282        self.prompt = Some(prompt);
283        self
284    }
285
286    /// EN: Sets the upper bound for generated output tokens.
287    /// 中文:设置生成输出 token 数量的上限。
288    pub fn max_output_tokens(mut self, max_output_tokens: u32) -> Self {
289        self.max_output_tokens = Some(max_output_tokens);
290        self
291    }
292
293    /// EN: Sets whether the generated response is stored for later retrieval.
294    /// 中文:设置是否存储生成的响应以便稍后检索。
295    pub fn store(mut self, store: bool) -> Self {
296        self.store = Some(store);
297        self
298    }
299
300    /// EN: Sets whether the response should run in the background.
301    /// 中文:设置响应是否应在后台运行。
302    pub fn background(mut self, background: bool) -> Self {
303        self.background = Some(background);
304        self
305    }
306
307    /// EN: Sets the maximum number of built-in tool calls for the response.
308    /// 中文:设置响应中内置工具调用总次数上限。
309    pub fn max_tool_calls(mut self, max_tool_calls: u32) -> Self {
310        self.max_tool_calls = Some(max_tool_calls);
311        self
312    }
313
314    /// EN: Adds a metadata key/value pair.
315    /// 中文:添加一个元数据键值对。
316    pub fn metadata(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
317        self.metadata.insert(key.into(), value.into());
318        self
319    }
320
321    /// EN: Sets whether tool calls may run in parallel.
322    /// 中文:设置是否允许工具调用并行运行。
323    pub fn parallel_tool_calls(mut self, parallel_tool_calls: bool) -> Self {
324        self.parallel_tool_calls = Some(parallel_tool_calls);
325        self
326    }
327
328    /// EN: Sets the sampling temperature.
329    /// 中文:设置采样温度。
330    pub fn temperature(mut self, temperature: f64) -> Self {
331        self.temperature = Some(temperature);
332        self
333    }
334
335    /// EN: Sets the nucleus sampling value.
336    /// 中文:设置 nucleus sampling 值。
337    pub fn top_p(mut self, top_p: f64) -> Self {
338        self.top_p = Some(top_p);
339        self
340    }
341
342    /// EN: Sets the maximum number of top token log probabilities to return.
343    /// 中文:设置每个 token 位置返回的最高概率 token log probability 数量。
344    pub fn top_logprobs(mut self, top_logprobs: u8) -> Self {
345        self.top_logprobs = Some(top_logprobs);
346        self
347    }
348
349    /// EN: Sets reasoning configuration for reasoning-capable models.
350    /// 中文:设置支持推理模型的推理配置。
351    pub fn reasoning(mut self, reasoning: ResponseReasoning) -> Self {
352        self.reasoning = Some(reasoning);
353        self
354    }
355
356    /// EN: Sets the context truncation strategy for the response.
357    /// 中文:设置响应的上下文截断策略。
358    pub fn truncation(mut self, truncation: ResponseTruncation) -> Self {
359        self.truncation = Some(truncation);
360        self
361    }
362
363    /// EN: Sets the prompt cache bucketing key for similar requests.
364    /// 中文:设置用于相似请求提示缓存分桶的键。
365    pub fn prompt_cache_key(mut self, prompt_cache_key: impl Into<String>) -> Self {
366        self.prompt_cache_key = Some(prompt_cache_key.into());
367        self
368    }
369
370    /// EN: Sets the prompt cache retention policy for this request.
371    /// 中文:设置此请求的提示缓存保留策略。
372    pub fn prompt_cache_retention(
373        mut self,
374        prompt_cache_retention: ResponsePromptCacheRetention,
375    ) -> Self {
376        self.prompt_cache_retention = Some(prompt_cache_retention);
377        self
378    }
379
380    /// EN: Sets the stable safety identifier for abuse detection.
381    /// 中文:设置用于滥用检测的稳定安全标识符。
382    pub fn safety_identifier(mut self, safety_identifier: impl Into<String>) -> Self {
383        self.safety_identifier = Some(safety_identifier.into());
384        self
385    }
386
387    /// EN: Sets the service tier used to serve the response request.
388    /// 中文:设置用于处理响应请求的服务层级。
389    pub fn service_tier(mut self, service_tier: ResponseServiceTier) -> Self {
390        self.service_tier = Some(service_tier);
391        self
392    }
393
394    /// EN: Sets additional output data to include in the model response.
395    /// 中文:设置要包含在模型响应中的额外输出数据。
396    pub fn include<I>(mut self, include: I) -> Self
397    where
398        I: IntoIterator<Item = ResponseInclude>,
399    {
400        self.include = Some(include.into_iter().collect());
401        self
402    }
403
404    /// EN: Sets text generation configuration.
405    /// 中文:设置文本生成配置。
406    pub fn text(mut self, text: ResponseTextConfig) -> Self {
407        self.text = Some(text);
408        self
409    }
410
411    /// EN: Sets streaming options for a request that will be sent with streaming enabled.
412    /// 中文:设置将在启用流式传输时发送的请求流选项。
413    pub fn stream_options(mut self, stream_options: StreamOptions) -> Self {
414        self.stream_options = Some(stream_options);
415        self
416    }
417
418    /// EN: Adds a forward-compatible JSON field.
419    /// 中文:添加前向兼容的 JSON 字段。
420    pub fn extra(mut self, name: impl Into<String>, value: Value) -> Self {
421        self.extra.insert(name.into(), value);
422        self
423    }
424
425    /// EN: Builds and validates the request.
426    /// 中文:构建并校验请求。
427    pub fn build(self) -> Result<CreateResponseRequest, LingerError> {
428        let model = self
429            .model
430            .filter(|value| !value.trim().is_empty())
431            .ok_or_else(|| LingerError::invalid_config("model is required"))?;
432        let input = self
433            .input
434            .ok_or_else(|| LingerError::invalid_config("input is required"))?;
435        if self
436            .max_output_tokens
437            .is_some_and(|max_output_tokens| max_output_tokens < 16)
438        {
439            return Err(LingerError::invalid_config(
440                "max_output_tokens must be at least 16",
441            ));
442        }
443        if self
444            .temperature
445            .is_some_and(|temperature| !(0.0..=2.0).contains(&temperature))
446        {
447            return Err(LingerError::invalid_config(
448                "temperature must be between 0.0 and 2.0",
449            ));
450        }
451        if self
452            .top_p
453            .is_some_and(|top_p| !(0.0..=1.0).contains(&top_p))
454        {
455            return Err(LingerError::invalid_config(
456                "top_p must be between 0.0 and 1.0",
457            ));
458        }
459        if self
460            .top_logprobs
461            .is_some_and(|top_logprobs| top_logprobs > 20)
462        {
463            return Err(LingerError::invalid_config(
464                "top_logprobs must be between 0 and 20",
465            ));
466        }
467        validate_optional_string("prompt_cache_key", self.prompt_cache_key.as_deref())?;
468        validate_optional_string("safety_identifier", self.safety_identifier.as_deref())?;
469        validate_optional_string("personality", self.personality.as_deref())?;
470        if let Some(conversation) = &self.conversation {
471            validate_optional_string("conversation", Some(conversation.id()))?;
472        }
473        if self.previous_response_id.is_some() && self.conversation.is_some() {
474            return Err(LingerError::invalid_config(
475                "previous_response_id cannot be used with conversation",
476            ));
477        }
478        if let Some(context_management) = &self.context_management {
479            validate_context_management(context_management)?;
480        }
481        if let Some(moderation) = &self.moderation {
482            validate_moderation(moderation)?;
483        }
484        validate_tools(&self.tools)?;
485        if let Some(tool_choice) = &self.tool_choice {
486            validate_tool_choice(tool_choice)?;
487        }
488        if let Some(prompt) = &self.prompt {
489            validate_prompt(prompt)?;
490        }
491        if let Some(text) = &self.text {
492            validate_text_config(text)?;
493        }
494        if self
495            .personality
496            .as_deref()
497            .is_some_and(|value| value.chars().count() > 64)
498        {
499            return Err(LingerError::invalid_config(
500                "personality must be at most 64 characters",
501            ));
502        }
503        validate_metadata(&self.metadata)?;
504        if self
505            .safety_identifier
506            .as_deref()
507            .is_some_and(|value| value.chars().count() > 64)
508        {
509            return Err(LingerError::invalid_config(
510                "safety_identifier must be at most 64 characters",
511            ));
512        }
513        validate_extra_fields(&self.extra)?;
514        Ok(CreateResponseRequest {
515            model,
516            input,
517            instructions: self.instructions,
518            personality: self.personality,
519            previous_response_id: self.previous_response_id,
520            conversation: self.conversation,
521            context_management: self.context_management,
522            moderation: self.moderation,
523            tools: self.tools,
524            tool_choice: self.tool_choice,
525            prompt: self.prompt,
526            max_output_tokens: self.max_output_tokens,
527            store: self.store,
528            background: self.background,
529            max_tool_calls: self.max_tool_calls,
530            metadata: self.metadata,
531            parallel_tool_calls: self.parallel_tool_calls,
532            temperature: self.temperature,
533            top_p: self.top_p,
534            top_logprobs: self.top_logprobs,
535            reasoning: self.reasoning,
536            truncation: self.truncation,
537            prompt_cache_key: self.prompt_cache_key,
538            prompt_cache_retention: self.prompt_cache_retention,
539            safety_identifier: self.safety_identifier,
540            service_tier: self.service_tier,
541            include: self.include,
542            text: self.text,
543            stream_options: self.stream_options,
544            stream: None,
545            extra: self.extra,
546        })
547    }
548}
549
550/// EN: Additional Responses API output data to include.
551/// 中文:Responses API 可额外包含的输出数据。
552#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
553#[non_exhaustive]
554pub enum ResponseInclude {
555    /// EN: File search results from file search tool calls.
556    /// 中文:文件搜索工具调用的搜索结果。
557    #[serde(rename = "file_search_call.results")]
558    FileSearchCallResults,
559    /// EN: Web search results from web search tool calls.
560    /// 中文:网页搜索工具调用的搜索结果。
561    #[serde(rename = "web_search_call.results")]
562    WebSearchCallResults,
563    /// EN: Source links for web search actions.
564    /// 中文:网页搜索动作的来源链接。
565    #[serde(rename = "web_search_call.action.sources")]
566    WebSearchCallActionSources,
567    /// EN: Image URLs from input messages.
568    /// 中文:输入消息中的图像 URL。
569    #[serde(rename = "message.input_image.image_url")]
570    MessageInputImageImageUrl,
571    /// EN: Image URLs from computer call outputs.
572    /// 中文:computer call 输出中的图像 URL。
573    #[serde(rename = "computer_call_output.output.image_url")]
574    ComputerCallOutputOutputImageUrl,
575    /// EN: Code interpreter tool call outputs.
576    /// 中文:代码解释器工具调用输出。
577    #[serde(rename = "code_interpreter_call.outputs")]
578    CodeInterpreterCallOutputs,
579    /// EN: Encrypted reasoning content for stateless multi-turn use.
580    /// 中文:用于无状态多轮使用的加密推理内容。
581    #[serde(rename = "reasoning.encrypted_content")]
582    ReasoningEncryptedContent,
583    /// EN: Log probabilities for assistant output text.
584    /// 中文:assistant 输出文本的 logprobs。
585    #[serde(rename = "message.output_text.logprobs")]
586    MessageOutputTextLogprobs,
587}
588
589/// EN: Context truncation strategy for a Responses API request.
590/// 中文:Responses API 请求的上下文截断策略。
591#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
592#[serde(rename_all = "snake_case")]
593#[non_exhaustive]
594pub enum ResponseTruncation {
595    /// EN: Automatically truncate input items from the beginning when needed.
596    /// 中文:需要时自动从开头截断输入项目。
597    Auto,
598    /// EN: Disable truncation and let oversized inputs fail.
599    /// 中文:禁用截断,让超出上下文限制的输入失败。
600    Disabled,
601}
602
603/// EN: Conversation selector for a Responses API request.
604/// 中文:Responses API 请求的 conversation 选择器。
605#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
606#[serde(untagged)]
607#[non_exhaustive]
608pub enum ResponseConversation {
609    /// EN: Use the conversation with this id.
610    /// 中文:使用此 ID 对应的 conversation。
611    Id(String),
612    /// EN: Use the conversation object with this id.
613    /// 中文:使用包含此 ID 的 conversation 对象。
614    Object {
615        /// EN: Conversation id.
616        /// 中文:Conversation ID。
617        id: String,
618    },
619}
620
621impl ResponseConversation {
622    /// EN: Creates a conversation object selector with the provided id.
623    /// 中文:使用提供的 ID 创建 conversation 对象选择器。
624    pub fn object(id: impl Into<String>) -> Self {
625        Self::Object { id: id.into() }
626    }
627
628    fn id(&self) -> &str {
629        match self {
630            Self::Id(id) => id,
631            Self::Object { id } => id,
632        }
633    }
634}
635
636impl From<String> for ResponseConversation {
637    fn from(value: String) -> Self {
638        Self::Id(value)
639    }
640}
641
642impl From<&str> for ResponseConversation {
643    fn from(value: &str) -> Self {
644        Self::Id(value.to_string())
645    }
646}
647
648/// EN: Reference to a reusable Responses API prompt template.
649/// 中文:Responses API 可复用 prompt 模板引用。
650#[derive(Clone, Debug, Serialize, PartialEq)]
651#[non_exhaustive]
652pub struct ResponsePrompt {
653    /// EN: Unique prompt template identifier.
654    /// 中文:唯一的 prompt 模板标识符。
655    pub id: String,
656    /// EN: Optional prompt template version.
657    /// 中文:可选的 prompt 模板版本。
658    #[serde(skip_serializing_if = "Option::is_none")]
659    pub version: Option<String>,
660    /// EN: Optional variables substituted into the prompt template.
661    /// 中文:可选的 prompt 模板变量替换值。
662    #[serde(skip_serializing_if = "BTreeMap::is_empty")]
663    pub variables: BTreeMap<String, Value>,
664}
665
666impl ResponsePrompt {
667    /// EN: Creates a prompt template reference with the provided id.
668    /// 中文:使用提供的 id 创建 prompt 模板引用。
669    pub fn new(id: impl Into<String>) -> Self {
670        Self {
671            id: id.into(),
672            version: None,
673            variables: BTreeMap::new(),
674        }
675    }
676
677    /// EN: Sets the prompt template version.
678    /// 中文:设置 prompt 模板版本。
679    pub fn version(mut self, version: impl Into<String>) -> Self {
680        self.version = Some(version.into());
681        self
682    }
683
684    /// EN: Adds a prompt template variable.
685    /// 中文:添加 prompt 模板变量。
686    pub fn variable(mut self, name: impl Into<String>, value: Value) -> Self {
687        self.variables.insert(name.into(), value);
688        self
689    }
690}
691
692/// EN: Context management entry for a Responses API request.
693/// 中文:Responses API 请求的上下文管理条目。
694#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
695#[non_exhaustive]
696pub struct ResponseContextManagement {
697    /// EN: Context management entry type.
698    /// 中文:上下文管理条目类型。
699    #[serde(rename = "type")]
700    pub kind: ResponseContextManagementType,
701    /// EN: Optional token threshold at which compaction should run.
702    /// 中文:触发压缩的可选 token 阈值。
703    #[serde(skip_serializing_if = "Option::is_none")]
704    pub compact_threshold: Option<u32>,
705}
706
707impl ResponseContextManagement {
708    /// EN: Creates a compaction context management entry.
709    /// 中文:创建 compaction 上下文管理条目。
710    pub fn compaction() -> Self {
711        Self {
712            kind: ResponseContextManagementType::Compaction,
713            compact_threshold: None,
714        }
715    }
716
717    /// EN: Sets the token threshold at which compaction should run.
718    /// 中文:设置触发压缩的 token 阈值。
719    pub fn compact_threshold(mut self, compact_threshold: u32) -> Self {
720        self.compact_threshold = Some(compact_threshold);
721        self
722    }
723}
724
725/// EN: Context management entry type.
726/// 中文:上下文管理条目类型。
727#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
728#[serde(rename_all = "snake_case")]
729#[non_exhaustive]
730pub enum ResponseContextManagementType {
731    /// EN: Compact conversation context when configured thresholds are reached.
732    /// 中文:达到配置阈值时压缩会话上下文。
733    Compaction,
734}
735
736/// EN: Moderation configuration for a Responses API request.
737/// 中文:Responses API 请求的 moderation 配置。
738#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
739#[non_exhaustive]
740pub struct ResponseModeration {
741    /// EN: Moderation model id used for this response.
742    /// 中文:此响应使用的 moderation 模型 ID。
743    pub model: String,
744}
745
746impl ResponseModeration {
747    /// EN: Creates moderation configuration with the provided model id.
748    /// 中文:使用提供的模型 ID 创建 moderation 配置。
749    pub fn new(model: impl Into<String>) -> Self {
750        Self {
751            model: model.into(),
752        }
753    }
754}
755
756/// EN: Tool definition accepted by a Responses API request.
757/// 中文:Responses API 请求接受的工具定义。
758#[derive(Clone, Debug, PartialEq)]
759#[non_exhaustive]
760pub struct ResponseTool {
761    value: Value,
762}
763
764impl ResponseTool {
765    /// EN: Creates a forward-compatible raw JSON tool definition.
766    /// 中文:创建前向兼容的原始 JSON 工具定义。
767    pub fn raw(value: Value) -> Self {
768        Self { value }
769    }
770
771    /// EN: Converts the tool definition into the request JSON value.
772    /// 中文:将工具定义转换为请求 JSON 值。
773    pub fn into_value(self) -> Value {
774        self.value
775    }
776}
777
778impl From<Value> for ResponseTool {
779    fn from(value: Value) -> Self {
780        Self::raw(value)
781    }
782}
783
784impl From<ResponseFunctionTool> for ResponseTool {
785    fn from(tool: ResponseFunctionTool) -> Self {
786        Self {
787            value: serde_json::to_value(tool)
788                .expect("serializing a response function tool should not fail"),
789        }
790    }
791}
792
793impl From<ResponseFileSearchTool> for ResponseTool {
794    fn from(tool: ResponseFileSearchTool) -> Self {
795        Self {
796            value: serde_json::to_value(tool)
797                .expect("serializing a response file search tool should not fail"),
798        }
799    }
800}
801
802impl From<ResponseComputerTool> for ResponseTool {
803    fn from(tool: ResponseComputerTool) -> Self {
804        Self {
805            value: serde_json::to_value(tool)
806                .expect("serializing a response computer tool should not fail"),
807        }
808    }
809}
810
811impl From<ResponseLocalShellTool> for ResponseTool {
812    fn from(tool: ResponseLocalShellTool) -> Self {
813        Self {
814            value: serde_json::to_value(tool)
815                .expect("serializing a response local shell tool should not fail"),
816        }
817    }
818}
819
820impl From<ResponseApplyPatchTool> for ResponseTool {
821    fn from(tool: ResponseApplyPatchTool) -> Self {
822        Self {
823            value: serde_json::to_value(tool)
824                .expect("serializing a response apply patch tool should not fail"),
825        }
826    }
827}
828
829impl From<ResponseCustomTool> for ResponseTool {
830    fn from(tool: ResponseCustomTool) -> Self {
831        Self {
832            value: serde_json::to_value(tool)
833                .expect("serializing a response custom tool should not fail"),
834        }
835    }
836}
837
838impl From<ResponseNamespaceTool> for ResponseTool {
839    fn from(tool: ResponseNamespaceTool) -> Self {
840        Self {
841            value: serde_json::to_value(tool)
842                .expect("serializing a response namespace tool should not fail"),
843        }
844    }
845}
846
847impl From<ResponseToolSearchTool> for ResponseTool {
848    fn from(tool: ResponseToolSearchTool) -> Self {
849        Self {
850            value: serde_json::to_value(tool)
851                .expect("serializing a response tool search tool should not fail"),
852        }
853    }
854}
855
856impl From<ResponseShellTool> for ResponseTool {
857    fn from(tool: ResponseShellTool) -> Self {
858        Self {
859            value: serde_json::to_value(tool)
860                .expect("serializing a response shell tool should not fail"),
861        }
862    }
863}
864
865impl From<ResponseCodeInterpreterTool> for ResponseTool {
866    fn from(tool: ResponseCodeInterpreterTool) -> Self {
867        Self {
868            value: serde_json::to_value(tool)
869                .expect("serializing a response code interpreter tool should not fail"),
870        }
871    }
872}
873
874impl From<ResponseImageGenerationTool> for ResponseTool {
875    fn from(tool: ResponseImageGenerationTool) -> Self {
876        Self {
877            value: serde_json::to_value(tool)
878                .expect("serializing a response image generation tool should not fail"),
879        }
880    }
881}
882
883impl From<ResponseMcpTool> for ResponseTool {
884    fn from(tool: ResponseMcpTool) -> Self {
885        Self {
886            value: serde_json::to_value(tool)
887                .expect("serializing a response MCP tool should not fail"),
888        }
889    }
890}
891
892impl From<ResponseWebSearchTool> for ResponseTool {
893    fn from(tool: ResponseWebSearchTool) -> Self {
894        Self {
895            value: serde_json::to_value(tool)
896                .expect("serializing a response web search tool should not fail"),
897        }
898    }
899}
900
901/// EN: Computer tool definition for Responses API computer-use models.
902/// 中文:Responses API computer-use 模型使用的 computer 工具定义。
903#[derive(Clone, Debug, Serialize, PartialEq)]
904#[non_exhaustive]
905pub struct ResponseComputerTool {
906    #[serde(rename = "type")]
907    kind: &'static str,
908    /// EN: Computer environment controlled by the tool.
909    /// 中文:工具控制的计算机环境。
910    #[serde(skip_serializing_if = "Option::is_none")]
911    pub environment: Option<ResponseComputerEnvironment>,
912    /// EN: Width of the virtual computer display.
913    /// 中文:虚拟计算机显示器宽度。
914    #[serde(skip_serializing_if = "Option::is_none")]
915    pub display_width: Option<u32>,
916    /// EN: Height of the virtual computer display.
917    /// 中文:虚拟计算机显示器高度。
918    #[serde(skip_serializing_if = "Option::is_none")]
919    pub display_height: Option<u32>,
920}
921
922impl ResponseComputerTool {
923    /// EN: Creates the basic hosted computer tool.
924    /// 中文:创建基础 hosted computer 工具。
925    pub fn computer() -> Self {
926        Self {
927            kind: "computer",
928            environment: None,
929            display_width: None,
930            display_height: None,
931        }
932    }
933
934    /// EN: Creates a computer-use preview tool for a display environment.
935    /// 中文:为指定显示环境创建 computer-use preview 工具。
936    pub fn computer_use_preview(
937        environment: ResponseComputerEnvironment,
938        display_width: u32,
939        display_height: u32,
940    ) -> Self {
941        Self {
942            kind: "computer_use_preview",
943            environment: Some(environment),
944            display_width: Some(display_width),
945            display_height: Some(display_height),
946        }
947    }
948}
949
950/// EN: Environment controlled by a Responses API computer tool.
951/// 中文:Responses API computer 工具控制的环境。
952#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
953#[non_exhaustive]
954pub enum ResponseComputerEnvironment {
955    /// EN: Windows desktop environment.
956    /// 中文:Windows 桌面环境。
957    #[serde(rename = "windows")]
958    Windows,
959    /// EN: macOS desktop environment.
960    /// 中文:macOS 桌面环境。
961    #[serde(rename = "mac")]
962    Mac,
963    /// EN: Linux desktop environment.
964    /// 中文:Linux 桌面环境。
965    #[serde(rename = "linux")]
966    Linux,
967    /// EN: Ubuntu desktop environment.
968    /// 中文:Ubuntu 桌面环境。
969    #[serde(rename = "ubuntu")]
970    Ubuntu,
971    /// EN: Browser environment.
972    /// 中文:浏览器环境。
973    #[serde(rename = "browser")]
974    Browser,
975}
976
977/// EN: Local shell tool definition for Responses API requests.
978/// 中文:Responses API 请求使用的 local shell 工具定义。
979#[derive(Clone, Debug, Serialize, PartialEq, Eq)]
980#[non_exhaustive]
981pub struct ResponseLocalShellTool {
982    #[serde(rename = "type")]
983    kind: &'static str,
984}
985
986impl ResponseLocalShellTool {
987    /// EN: Creates a local shell tool.
988    /// 中文:创建 local shell 工具。
989    pub fn new() -> Self {
990        Self {
991            kind: "local_shell",
992        }
993    }
994}
995
996impl Default for ResponseLocalShellTool {
997    fn default() -> Self {
998        Self::new()
999    }
1000}
1001
1002/// EN: Apply-patch tool definition for Responses API requests.
1003/// 中文:Responses API 请求使用的 apply-patch 工具定义。
1004#[derive(Clone, Debug, Serialize, PartialEq, Eq)]
1005#[non_exhaustive]
1006pub struct ResponseApplyPatchTool {
1007    #[serde(rename = "type")]
1008    kind: &'static str,
1009}
1010
1011impl ResponseApplyPatchTool {
1012    /// EN: Creates an apply-patch tool.
1013    /// 中文:创建 apply-patch 工具。
1014    pub fn new() -> Self {
1015        Self {
1016            kind: "apply_patch",
1017        }
1018    }
1019}
1020
1021impl Default for ResponseApplyPatchTool {
1022    fn default() -> Self {
1023        Self::new()
1024    }
1025}
1026
1027/// EN: Custom tool definition for Responses API requests.
1028/// 中文:Responses API 请求使用的 custom 工具定义。
1029#[derive(Clone, Debug, Serialize, PartialEq)]
1030#[non_exhaustive]
1031pub struct ResponseCustomTool {
1032    #[serde(rename = "type")]
1033    kind: &'static str,
1034    /// EN: Name used to identify this custom tool in tool calls.
1035    /// 中文:在工具调用中识别此 custom 工具的名称。
1036    pub name: String,
1037    /// EN: Optional description used to provide model context.
1038    /// 中文:用于向模型提供上下文的可选描述。
1039    #[serde(skip_serializing_if = "Option::is_none")]
1040    pub description: Option<String>,
1041    /// EN: Optional input format for the custom tool.
1042    /// 中文:custom 工具的可选输入格式。
1043    #[serde(skip_serializing_if = "Option::is_none")]
1044    pub format: Option<ResponseCustomToolFormat>,
1045    /// EN: Whether this tool is deferred and loaded via tool search.
1046    /// 中文:此工具是否通过工具搜索延迟加载。
1047    #[serde(skip_serializing_if = "Option::is_none")]
1048    pub defer_loading: Option<bool>,
1049}
1050
1051impl ResponseCustomTool {
1052    /// EN: Creates a custom tool with the provided name.
1053    /// 中文:使用提供的名称创建 custom 工具。
1054    pub fn new(name: impl Into<String>) -> Self {
1055        Self {
1056            kind: "custom",
1057            name: name.into(),
1058            description: None,
1059            format: None,
1060            defer_loading: None,
1061        }
1062    }
1063
1064    /// EN: Sets the custom tool description.
1065    /// 中文:设置 custom 工具描述。
1066    pub fn description(mut self, description: impl Into<String>) -> Self {
1067        self.description = Some(description.into());
1068        self
1069    }
1070
1071    /// EN: Sets the custom tool input format.
1072    /// 中文:设置 custom 工具输入格式。
1073    pub fn format(mut self, format: ResponseCustomToolFormat) -> Self {
1074        self.format = Some(format);
1075        self
1076    }
1077
1078    /// EN: Sets whether the custom tool is loaded via tool search.
1079    /// 中文:设置 custom 工具是否通过工具搜索加载。
1080    pub fn defer_loading(mut self, defer_loading: bool) -> Self {
1081        self.defer_loading = Some(defer_loading);
1082        self
1083    }
1084}
1085
1086/// EN: Input format for a Responses API custom tool.
1087/// 中文:Responses API custom 工具的输入格式。
1088#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
1089#[serde(tag = "type")]
1090#[non_exhaustive]
1091pub enum ResponseCustomToolFormat {
1092    /// EN: Unconstrained text input.
1093    /// 中文:不受约束的文本输入。
1094    #[serde(rename = "text")]
1095    Text,
1096    /// EN: Grammar-constrained input.
1097    /// 中文:受 grammar 约束的输入。
1098    #[serde(rename = "grammar")]
1099    Grammar {
1100        /// EN: Grammar syntax used by the definition.
1101        /// 中文:definition 使用的 grammar 语法。
1102        syntax: ResponseCustomToolGrammarSyntax,
1103        /// EN: Grammar definition.
1104        /// 中文:grammar 定义。
1105        definition: String,
1106    },
1107}
1108
1109impl ResponseCustomToolFormat {
1110    /// EN: Creates an unconstrained text format.
1111    /// 中文:创建不受约束的 text 格式。
1112    pub fn text() -> Self {
1113        Self::Text
1114    }
1115
1116    /// EN: Creates a grammar-constrained format.
1117    /// 中文:创建受 grammar 约束的格式。
1118    pub fn grammar(syntax: ResponseCustomToolGrammarSyntax, definition: impl Into<String>) -> Self {
1119        Self::Grammar {
1120            syntax,
1121            definition: definition.into(),
1122        }
1123    }
1124}
1125
1126/// EN: Grammar syntax supported by Responses API custom tools.
1127/// 中文:Responses API custom 工具支持的 grammar 语法。
1128#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
1129#[non_exhaustive]
1130pub enum ResponseCustomToolGrammarSyntax {
1131    /// EN: Lark grammar syntax.
1132    /// 中文:Lark grammar 语法。
1133    #[serde(rename = "lark")]
1134    Lark,
1135    /// EN: Regex grammar syntax.
1136    /// 中文:Regex grammar 语法。
1137    #[serde(rename = "regex")]
1138    Regex,
1139}
1140
1141/// EN: Namespace tool definition for grouping function and custom tools.
1142/// 中文:用于分组 function 和 custom 工具的 namespace 工具定义。
1143#[derive(Clone, Debug, Serialize, PartialEq)]
1144#[non_exhaustive]
1145pub struct ResponseNamespaceTool {
1146    #[serde(rename = "type")]
1147    kind: &'static str,
1148    /// EN: Namespace name used in tool calls.
1149    /// 中文:工具调用中使用的 namespace 名称。
1150    pub name: String,
1151    /// EN: Description shown to the model.
1152    /// 中文:展示给模型的描述。
1153    pub description: String,
1154    /// EN: Function or custom tools inside this namespace.
1155    /// 中文:此 namespace 内的 function 或 custom 工具。
1156    pub tools: Vec<Value>,
1157}
1158
1159impl ResponseNamespaceTool {
1160    /// EN: Creates an empty namespace tool that must receive nested tools before build.
1161    /// 中文:创建空 namespace 工具,build 前必须加入嵌套工具。
1162    pub fn new(name: impl Into<String>, description: impl Into<String>) -> Self {
1163        Self {
1164            kind: "namespace",
1165            name: name.into(),
1166            description: description.into(),
1167            tools: Vec::new(),
1168        }
1169    }
1170
1171    /// EN: Adds a function or custom tool to this namespace.
1172    /// 中文:向此 namespace 添加 function 或 custom 工具。
1173    pub fn tool<T>(mut self, tool: T) -> Self
1174    where
1175        T: Into<ResponseTool>,
1176    {
1177        self.tools.push(tool.into().into_value());
1178        self
1179    }
1180
1181    /// EN: Replaces the nested tool list for this namespace.
1182    /// 中文:替换此 namespace 的嵌套工具列表。
1183    pub fn tools<I, T>(mut self, tools: I) -> Self
1184    where
1185        I: IntoIterator<Item = T>,
1186        T: Into<ResponseTool>,
1187    {
1188        self.tools = tools
1189            .into_iter()
1190            .map(|tool| tool.into().into_value())
1191            .collect();
1192        self
1193    }
1194}
1195
1196/// EN: Tool-search tool definition for deferred Responses API tools.
1197/// 中文:用于延迟 Responses API 工具的 tool-search 工具定义。
1198#[derive(Clone, Debug, Serialize, PartialEq)]
1199#[non_exhaustive]
1200pub struct ResponseToolSearchTool {
1201    #[serde(rename = "type")]
1202    kind: &'static str,
1203    /// EN: Whether tool search is executed by the server or client.
1204    /// 中文:工具搜索由服务器还是客户端执行。
1205    #[serde(skip_serializing_if = "Option::is_none")]
1206    pub execution: Option<ResponseToolSearchExecution>,
1207    /// EN: Optional description shown to the model.
1208    /// 中文:展示给模型的可选描述。
1209    #[serde(skip_serializing_if = "Option::is_none")]
1210    pub description: Option<String>,
1211    /// EN: Optional parameter schema for client-executed tool search.
1212    /// 中文:客户端执行工具搜索时使用的可选参数 schema。
1213    #[serde(skip_serializing_if = "Option::is_none")]
1214    pub parameters: Option<Value>,
1215}
1216
1217impl ResponseToolSearchTool {
1218    /// EN: Creates a tool-search tool without an execution hint.
1219    /// 中文:创建不带执行位置提示的 tool-search 工具。
1220    pub fn new() -> Self {
1221        Self {
1222            kind: "tool_search",
1223            execution: None,
1224            description: None,
1225            parameters: None,
1226        }
1227    }
1228
1229    /// EN: Creates a server-executed tool-search tool.
1230    /// 中文:创建由服务器执行的 tool-search 工具。
1231    pub fn server() -> Self {
1232        Self::new().execution(ResponseToolSearchExecution::Server)
1233    }
1234
1235    /// EN: Creates a client-executed tool-search tool.
1236    /// 中文:创建由客户端执行的 tool-search 工具。
1237    pub fn client() -> Self {
1238        Self::new().execution(ResponseToolSearchExecution::Client)
1239    }
1240
1241    /// EN: Sets the tool-search execution location.
1242    /// 中文:设置 tool-search 的执行位置。
1243    pub fn execution(mut self, execution: ResponseToolSearchExecution) -> Self {
1244        self.execution = Some(execution);
1245        self
1246    }
1247
1248    /// EN: Sets the description shown to the model.
1249    /// 中文:设置展示给模型的描述。
1250    pub fn description(mut self, description: impl Into<String>) -> Self {
1251        self.description = Some(description.into());
1252        self
1253    }
1254
1255    /// EN: Sets the parameter schema for client-executed tool search.
1256    /// 中文:设置客户端执行工具搜索时使用的参数 schema。
1257    pub fn parameters(mut self, parameters: Value) -> Self {
1258        self.parameters = Some(parameters);
1259        self
1260    }
1261}
1262
1263impl Default for ResponseToolSearchTool {
1264    fn default() -> Self {
1265        Self::new()
1266    }
1267}
1268
1269/// EN: Execution location for Responses API tool search.
1270/// 中文:Responses API tool search 的执行位置。
1271#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
1272#[non_exhaustive]
1273pub enum ResponseToolSearchExecution {
1274    /// EN: Execute tool search on the server.
1275    /// 中文:在服务器执行工具搜索。
1276    #[serde(rename = "server")]
1277    Server,
1278    /// EN: Execute tool search on the client.
1279    /// 中文:在客户端执行工具搜索。
1280    #[serde(rename = "client")]
1281    Client,
1282}
1283
1284/// EN: Shell tool definition for Responses API requests.
1285/// 中文:Responses API 请求使用的 shell 工具定义。
1286#[derive(Clone, Debug, Serialize, PartialEq)]
1287#[non_exhaustive]
1288pub struct ResponseShellTool {
1289    #[serde(rename = "type")]
1290    kind: &'static str,
1291    /// EN: Optional shell execution environment.
1292    /// 中文:可选 shell 执行环境。
1293    #[serde(skip_serializing_if = "Option::is_none")]
1294    pub environment: Option<Value>,
1295}
1296
1297impl ResponseShellTool {
1298    /// EN: Creates a shell tool without an environment hint.
1299    /// 中文:创建不带环境提示的 shell 工具。
1300    pub fn new() -> Self {
1301        Self {
1302            kind: "shell",
1303            environment: None,
1304        }
1305    }
1306
1307    /// EN: Creates a shell tool that uses a local environment.
1308    /// 中文:创建使用 local 环境的 shell 工具。
1309    pub fn local() -> Self {
1310        Self::new().environment(shell_environment_type("local"))
1311    }
1312
1313    /// EN: Creates a shell tool that automatically creates a container.
1314    /// 中文:创建自动创建 container 的 shell 工具。
1315    pub fn container_auto() -> Self {
1316        Self::new().environment(shell_environment_type("container_auto"))
1317    }
1318
1319    /// EN: Creates a shell tool that references an existing container.
1320    /// 中文:创建引用现有 container 的 shell 工具。
1321    pub fn container_reference(container_id: impl Into<String>) -> Self {
1322        let mut environment = serde_json::Map::new();
1323        environment.insert(
1324            "type".to_string(),
1325            Value::String("container_reference".to_string()),
1326        );
1327        environment.insert(
1328            "container_id".to_string(),
1329            Value::String(container_id.into()),
1330        );
1331        Self::new().environment(Value::Object(environment))
1332    }
1333
1334    /// EN: Sets a raw shell environment object for forward compatibility.
1335    /// 中文:设置原始 shell environment 对象以保持前向兼容。
1336    pub fn environment(mut self, environment: Value) -> Self {
1337        self.environment = Some(environment);
1338        self
1339    }
1340}
1341
1342impl Default for ResponseShellTool {
1343    fn default() -> Self {
1344        Self::new()
1345    }
1346}
1347
1348fn shell_environment_type(kind: &'static str) -> Value {
1349    let mut environment = serde_json::Map::new();
1350    environment.insert("type".to_string(), Value::String(kind.to_string()));
1351    Value::Object(environment)
1352}
1353
1354/// EN: Function tool definition for Responses API tool calling.
1355/// 中文:Responses API 工具调用使用的 function 工具定义。
1356#[derive(Clone, Debug, Serialize, PartialEq)]
1357#[non_exhaustive]
1358pub struct ResponseFunctionTool {
1359    #[serde(rename = "type")]
1360    kind: &'static str,
1361    /// EN: Function name the model may call.
1362    /// 中文:模型可以调用的函数名称。
1363    pub name: String,
1364    /// EN: Optional function description used by the model.
1365    /// 中文:供模型使用的可选函数描述。
1366    #[serde(skip_serializing_if = "Option::is_none")]
1367    pub description: Option<String>,
1368    /// EN: JSON schema describing function parameters.
1369    /// 中文:描述函数参数的 JSON schema。
1370    pub parameters: Value,
1371    /// EN: Whether to enforce strict parameter validation.
1372    /// 中文:是否强制严格参数校验。
1373    pub strict: bool,
1374    /// EN: Whether this function is deferred and loaded via tool search.
1375    /// 中文:此函数是否通过工具搜索延迟加载。
1376    #[serde(skip_serializing_if = "Option::is_none")]
1377    pub defer_loading: Option<bool>,
1378}
1379
1380impl ResponseFunctionTool {
1381    /// EN: Creates a function tool with default strict parameter validation.
1382    /// 中文:创建默认启用严格参数校验的 function 工具。
1383    pub fn new(name: impl Into<String>, parameters: Value) -> Self {
1384        Self {
1385            kind: "function",
1386            name: name.into(),
1387            description: None,
1388            parameters,
1389            strict: true,
1390            defer_loading: None,
1391        }
1392    }
1393
1394    /// EN: Sets the function description used by the model.
1395    /// 中文:设置供模型使用的函数描述。
1396    pub fn description(mut self, description: impl Into<String>) -> Self {
1397        self.description = Some(description.into());
1398        self
1399    }
1400
1401    /// EN: Sets whether strict parameter validation is enforced.
1402    /// 中文:设置是否强制严格参数校验。
1403    pub fn strict(mut self, strict: bool) -> Self {
1404        self.strict = strict;
1405        self
1406    }
1407
1408    /// EN: Sets whether the function is deferred and loaded via tool search.
1409    /// 中文:设置函数是否通过工具搜索延迟加载。
1410    pub fn defer_loading(mut self, defer_loading: bool) -> Self {
1411        self.defer_loading = Some(defer_loading);
1412        self
1413    }
1414}
1415
1416/// EN: File search tool definition for Responses API built-in file search.
1417/// 中文:Responses API 内置文件搜索使用的 file_search 工具定义。
1418#[derive(Clone, Debug, Serialize, PartialEq)]
1419#[non_exhaustive]
1420pub struct ResponseFileSearchTool {
1421    #[serde(rename = "type")]
1422    kind: &'static str,
1423    /// EN: Vector store ids the tool searches.
1424    /// 中文:工具要搜索的 vector store ID 列表。
1425    pub vector_store_ids: Vec<String>,
1426    /// EN: Optional maximum number of search results to return.
1427    /// 中文:可选的最大搜索结果数量。
1428    #[serde(skip_serializing_if = "Option::is_none")]
1429    pub max_num_results: Option<u8>,
1430    /// EN: Optional ranking options object.
1431    /// 中文:可选的排序选项对象。
1432    #[serde(skip_serializing_if = "Option::is_none")]
1433    pub ranking_options: Option<Value>,
1434    /// EN: Optional filter object to apply.
1435    /// 中文:可选的过滤器对象。
1436    #[serde(skip_serializing_if = "Option::is_none")]
1437    pub filters: Option<Value>,
1438}
1439
1440impl ResponseFileSearchTool {
1441    /// EN: Creates a file search tool for the provided vector store ids.
1442    /// 中文:使用提供的 vector store ID 创建 file_search 工具。
1443    pub fn new<I, S>(vector_store_ids: I) -> Self
1444    where
1445        I: IntoIterator<Item = S>,
1446        S: Into<String>,
1447    {
1448        Self {
1449            kind: "file_search",
1450            vector_store_ids: vector_store_ids.into_iter().map(Into::into).collect(),
1451            max_num_results: None,
1452            ranking_options: None,
1453            filters: None,
1454        }
1455    }
1456
1457    /// EN: Sets the maximum number of search results to return.
1458    /// 中文:设置最大搜索结果数量。
1459    pub fn max_num_results(mut self, max_num_results: u8) -> Self {
1460        self.max_num_results = Some(max_num_results);
1461        self
1462    }
1463
1464    /// EN: Sets ranking options for file search.
1465    /// 中文:设置文件搜索排序选项。
1466    pub fn ranking_options(mut self, ranking_options: Value) -> Self {
1467        self.ranking_options = Some(ranking_options);
1468        self
1469    }
1470
1471    /// EN: Sets a filter for file search.
1472    /// 中文:设置文件搜索过滤器。
1473    pub fn filters(mut self, filters: Value) -> Self {
1474        self.filters = Some(filters);
1475        self
1476    }
1477}
1478
1479/// EN: Code interpreter tool definition for Responses API built-in Python execution.
1480/// 中文:Responses API 内置 Python 执行使用的 code_interpreter 工具定义。
1481#[derive(Clone, Debug, Serialize, PartialEq)]
1482#[non_exhaustive]
1483pub struct ResponseCodeInterpreterTool {
1484    #[serde(rename = "type")]
1485    kind: &'static str,
1486    /// EN: Code interpreter container id or auto container configuration.
1487    /// 中文:code interpreter 容器 ID 或自动容器配置。
1488    pub container: ResponseCodeInterpreterContainer,
1489}
1490
1491impl ResponseCodeInterpreterTool {
1492    /// EN: Creates a code interpreter tool that reuses an existing container id.
1493    /// 中文:创建复用已有容器 ID 的 code_interpreter 工具。
1494    pub fn container_id(container_id: impl Into<String>) -> Self {
1495        Self {
1496            kind: "code_interpreter",
1497            container: ResponseCodeInterpreterContainer::Id(container_id.into()),
1498        }
1499    }
1500
1501    /// EN: Creates a code interpreter tool with an automatically managed container.
1502    /// 中文:创建使用自动托管容器的 code_interpreter 工具。
1503    pub fn auto() -> Self {
1504        Self::auto_container(ResponseCodeInterpreterAutoContainer::new())
1505    }
1506
1507    /// EN: Creates a code interpreter tool from an auto container configuration.
1508    /// 中文:使用自动容器配置创建 code_interpreter 工具。
1509    pub fn auto_container(container: ResponseCodeInterpreterAutoContainer) -> Self {
1510        Self {
1511            kind: "code_interpreter",
1512            container: ResponseCodeInterpreterContainer::Auto(container),
1513        }
1514    }
1515
1516    /// EN: Sets uploaded file ids for the auto container.
1517    /// 中文:设置自动容器可访问的上传文件 ID。
1518    pub fn file_ids<I, S>(mut self, file_ids: I) -> Self
1519    where
1520        I: IntoIterator<Item = S>,
1521        S: Into<String>,
1522    {
1523        if let ResponseCodeInterpreterContainer::Auto(container) = &mut self.container {
1524            container.file_ids = file_ids.into_iter().map(Into::into).collect();
1525        }
1526        self
1527    }
1528
1529    /// EN: Sets the memory limit for the auto container.
1530    /// 中文:设置自动容器的内存限制。
1531    pub fn memory_limit(mut self, memory_limit: ResponseCodeInterpreterMemoryLimit) -> Self {
1532        if let ResponseCodeInterpreterContainer::Auto(container) = &mut self.container {
1533            container.memory_limit = Some(memory_limit);
1534        }
1535        self
1536    }
1537
1538    /// EN: Sets raw network policy configuration for the auto container.
1539    /// 中文:设置自动容器的原始网络策略配置。
1540    pub fn network_policy(mut self, network_policy: Value) -> Self {
1541        if let ResponseCodeInterpreterContainer::Auto(container) = &mut self.container {
1542            container.network_policy = Some(network_policy);
1543        }
1544        self
1545    }
1546}
1547
1548/// EN: Code interpreter container selector.
1549/// 中文:code interpreter 容器选择器。
1550#[derive(Clone, Debug, Serialize, PartialEq)]
1551#[serde(untagged)]
1552#[non_exhaustive]
1553pub enum ResponseCodeInterpreterContainer {
1554    /// EN: Existing container id.
1555    /// 中文:已有容器 ID。
1556    Id(String),
1557    /// EN: Automatically managed container configuration.
1558    /// 中文:自动托管容器配置。
1559    Auto(ResponseCodeInterpreterAutoContainer),
1560}
1561
1562/// EN: Auto container configuration for a code interpreter tool.
1563/// 中文:code interpreter 工具的自动容器配置。
1564#[derive(Clone, Debug, Serialize, PartialEq)]
1565#[non_exhaustive]
1566pub struct ResponseCodeInterpreterAutoContainer {
1567    #[serde(rename = "type")]
1568    kind: &'static str,
1569    /// EN: Uploaded file ids to make available to Python code.
1570    /// 中文:提供给 Python 代码使用的上传文件 ID。
1571    #[serde(skip_serializing_if = "Vec::is_empty")]
1572    pub file_ids: Vec<String>,
1573    /// EN: Optional memory limit for the container.
1574    /// 中文:容器的可选内存限制。
1575    #[serde(skip_serializing_if = "Option::is_none")]
1576    pub memory_limit: Option<ResponseCodeInterpreterMemoryLimit>,
1577    /// EN: Optional raw network policy for the container.
1578    /// 中文:容器的可选原始网络策略。
1579    #[serde(skip_serializing_if = "Option::is_none")]
1580    pub network_policy: Option<Value>,
1581}
1582
1583impl ResponseCodeInterpreterAutoContainer {
1584    /// EN: Creates an empty auto container configuration.
1585    /// 中文:创建空的自动容器配置。
1586    pub fn new() -> Self {
1587        Self {
1588            kind: "auto",
1589            file_ids: Vec::new(),
1590            memory_limit: None,
1591            network_policy: None,
1592        }
1593    }
1594
1595    /// EN: Sets uploaded file ids for the auto container.
1596    /// 中文:设置自动容器可访问的上传文件 ID。
1597    pub fn file_ids<I, S>(mut self, file_ids: I) -> Self
1598    where
1599        I: IntoIterator<Item = S>,
1600        S: Into<String>,
1601    {
1602        self.file_ids = file_ids.into_iter().map(Into::into).collect();
1603        self
1604    }
1605
1606    /// EN: Sets the memory limit for the auto container.
1607    /// 中文:设置自动容器的内存限制。
1608    pub fn memory_limit(mut self, memory_limit: ResponseCodeInterpreterMemoryLimit) -> Self {
1609        self.memory_limit = Some(memory_limit);
1610        self
1611    }
1612
1613    /// EN: Sets raw network policy configuration for the auto container.
1614    /// 中文:设置自动容器的原始网络策略配置。
1615    pub fn network_policy(mut self, network_policy: Value) -> Self {
1616        self.network_policy = Some(network_policy);
1617        self
1618    }
1619}
1620
1621impl Default for ResponseCodeInterpreterAutoContainer {
1622    fn default() -> Self {
1623        Self::new()
1624    }
1625}
1626
1627/// EN: Memory limit for a code interpreter auto container.
1628/// 中文:code interpreter 自动容器的内存限制。
1629#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
1630#[non_exhaustive]
1631pub enum ResponseCodeInterpreterMemoryLimit {
1632    /// EN: One gigabyte memory limit.
1633    /// 中文:1GB 内存限制。
1634    #[serde(rename = "1g")]
1635    OneGigabyte,
1636    /// EN: Four gigabyte memory limit.
1637    /// 中文:4GB 内存限制。
1638    #[serde(rename = "4g")]
1639    FourGigabytes,
1640    /// EN: Sixteen gigabyte memory limit.
1641    /// 中文:16GB 内存限制。
1642    #[serde(rename = "16g")]
1643    SixteenGigabytes,
1644    /// EN: Sixty-four gigabyte memory limit.
1645    /// 中文:64GB 内存限制。
1646    #[serde(rename = "64g")]
1647    SixtyFourGigabytes,
1648}
1649
1650/// EN: Image generation tool definition for Responses API built-in image creation.
1651/// 中文:Responses API 内置图像创建使用的 image_generation 工具定义。
1652#[derive(Clone, Debug, Serialize, PartialEq)]
1653#[non_exhaustive]
1654pub struct ResponseImageGenerationTool {
1655    #[serde(rename = "type")]
1656    kind: &'static str,
1657    /// EN: Optional image generation model id.
1658    /// 中文:可选的图像生成模型 ID。
1659    #[serde(skip_serializing_if = "Option::is_none")]
1660    pub model: Option<String>,
1661    /// EN: Optional generated image quality.
1662    /// 中文:可选的生成图像质量。
1663    #[serde(skip_serializing_if = "Option::is_none")]
1664    pub quality: Option<ResponseImageGenerationQuality>,
1665    /// EN: Optional generated image size.
1666    /// 中文:可选的生成图像尺寸。
1667    #[serde(skip_serializing_if = "Option::is_none")]
1668    pub size: Option<String>,
1669    /// EN: Optional output image format.
1670    /// 中文:可选的输出图像格式。
1671    #[serde(skip_serializing_if = "Option::is_none")]
1672    pub output_format: Option<ResponseImageGenerationOutputFormat>,
1673    /// EN: Optional output image compression percentage.
1674    /// 中文:可选的输出图像压缩百分比。
1675    #[serde(skip_serializing_if = "Option::is_none")]
1676    pub output_compression: Option<u8>,
1677    /// EN: Optional image moderation level.
1678    /// 中文:可选的图像审核级别。
1679    #[serde(skip_serializing_if = "Option::is_none")]
1680    pub moderation: Option<ResponseImageGenerationModeration>,
1681    /// EN: Optional generated image background.
1682    /// 中文:可选的生成图像背景。
1683    #[serde(skip_serializing_if = "Option::is_none")]
1684    pub background: Option<ResponseImageGenerationBackground>,
1685    /// EN: Optional input image fidelity for edit actions.
1686    /// 中文:编辑动作的可选输入图像保真度。
1687    #[serde(skip_serializing_if = "Option::is_none")]
1688    pub input_fidelity: Option<ResponseImageGenerationInputFidelity>,
1689    /// EN: Optional mask for inpainting edits.
1690    /// 中文:修补编辑使用的可选遮罩。
1691    #[serde(skip_serializing_if = "Option::is_none")]
1692    pub input_image_mask: Option<ResponseImageGenerationMask>,
1693    /// EN: Optional number of partial images to stream.
1694    /// 中文:可选的流式部分图像数量。
1695    #[serde(skip_serializing_if = "Option::is_none")]
1696    pub partial_images: Option<u8>,
1697    /// EN: Optional image generation action.
1698    /// 中文:可选的图像生成动作。
1699    #[serde(skip_serializing_if = "Option::is_none")]
1700    pub action: Option<ResponseImageGenerationAction>,
1701}
1702
1703impl ResponseImageGenerationTool {
1704    /// EN: Creates an image generation tool with default server-side options.
1705    /// 中文:创建使用服务端默认选项的 image_generation 工具。
1706    pub fn new() -> Self {
1707        Self {
1708            kind: "image_generation",
1709            model: None,
1710            quality: None,
1711            size: None,
1712            output_format: None,
1713            output_compression: None,
1714            moderation: None,
1715            background: None,
1716            input_fidelity: None,
1717            input_image_mask: None,
1718            partial_images: None,
1719            action: None,
1720        }
1721    }
1722
1723    /// EN: Sets the image generation model id.
1724    /// 中文:设置图像生成模型 ID。
1725    pub fn model(mut self, model: impl Into<String>) -> Self {
1726        self.model = Some(model.into());
1727        self
1728    }
1729
1730    /// EN: Sets generated image quality.
1731    /// 中文:设置生成图像质量。
1732    pub fn quality(mut self, quality: ResponseImageGenerationQuality) -> Self {
1733        self.quality = Some(quality);
1734        self
1735    }
1736
1737    /// EN: Sets generated image size.
1738    /// 中文:设置生成图像尺寸。
1739    pub fn size(mut self, size: impl Into<String>) -> Self {
1740        self.size = Some(size.into());
1741        self
1742    }
1743
1744    /// EN: Sets output image format.
1745    /// 中文:设置输出图像格式。
1746    pub fn output_format(mut self, output_format: ResponseImageGenerationOutputFormat) -> Self {
1747        self.output_format = Some(output_format);
1748        self
1749    }
1750
1751    /// EN: Sets output image compression percentage.
1752    /// 中文:设置输出图像压缩百分比。
1753    pub fn output_compression(mut self, output_compression: u8) -> Self {
1754        self.output_compression = Some(output_compression);
1755        self
1756    }
1757
1758    /// EN: Sets image moderation level.
1759    /// 中文:设置图像审核级别。
1760    pub fn moderation(mut self, moderation: ResponseImageGenerationModeration) -> Self {
1761        self.moderation = Some(moderation);
1762        self
1763    }
1764
1765    /// EN: Sets generated image background.
1766    /// 中文:设置生成图像背景。
1767    pub fn background(mut self, background: ResponseImageGenerationBackground) -> Self {
1768        self.background = Some(background);
1769        self
1770    }
1771
1772    /// EN: Sets input image fidelity for edit actions.
1773    /// 中文:设置编辑动作的输入图像保真度。
1774    pub fn input_fidelity(mut self, input_fidelity: ResponseImageGenerationInputFidelity) -> Self {
1775        self.input_fidelity = Some(input_fidelity);
1776        self
1777    }
1778
1779    /// EN: Sets the mask for inpainting edits.
1780    /// 中文:设置修补编辑使用的遮罩。
1781    pub fn input_image_mask(mut self, input_image_mask: ResponseImageGenerationMask) -> Self {
1782        self.input_image_mask = Some(input_image_mask);
1783        self
1784    }
1785
1786    /// EN: Sets the number of partial images to stream.
1787    /// 中文:设置要流式返回的部分图像数量。
1788    pub fn partial_images(mut self, partial_images: u8) -> Self {
1789        self.partial_images = Some(partial_images);
1790        self
1791    }
1792
1793    /// EN: Sets image generation action.
1794    /// 中文:设置图像生成动作。
1795    pub fn action(mut self, action: ResponseImageGenerationAction) -> Self {
1796        self.action = Some(action);
1797        self
1798    }
1799}
1800
1801impl Default for ResponseImageGenerationTool {
1802    fn default() -> Self {
1803        Self::new()
1804    }
1805}
1806
1807/// EN: Image generation mask for inpainting edits.
1808/// 中文:修补编辑使用的图像生成遮罩。
1809#[derive(Clone, Debug, Default, Serialize, PartialEq, Eq)]
1810#[non_exhaustive]
1811pub struct ResponseImageGenerationMask {
1812    /// EN: Base64 data URL mask image.
1813    /// 中文:base64 data URL 遮罩图像。
1814    #[serde(skip_serializing_if = "Option::is_none")]
1815    pub image_url: Option<String>,
1816    /// EN: Uploaded file id for the mask image.
1817    /// 中文:遮罩图像的已上传文件 ID。
1818    #[serde(skip_serializing_if = "Option::is_none")]
1819    pub file_id: Option<String>,
1820}
1821
1822impl ResponseImageGenerationMask {
1823    /// EN: Creates a mask from a base64 data URL image.
1824    /// 中文:使用 base64 data URL 图像创建遮罩。
1825    pub fn image_url(image_url: impl Into<String>) -> Self {
1826        Self {
1827            image_url: Some(image_url.into()),
1828            file_id: None,
1829        }
1830    }
1831
1832    /// EN: Creates a mask from an uploaded file id.
1833    /// 中文:使用已上传文件 ID 创建遮罩。
1834    pub fn file_id(file_id: impl Into<String>) -> Self {
1835        Self {
1836            image_url: None,
1837            file_id: Some(file_id.into()),
1838        }
1839    }
1840}
1841
1842/// EN: Image generation quality.
1843/// 中文:图像生成质量。
1844#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
1845#[serde(rename_all = "snake_case")]
1846#[non_exhaustive]
1847pub enum ResponseImageGenerationQuality {
1848    /// EN: Low image quality.
1849    /// 中文:低图像质量。
1850    Low,
1851    /// EN: Medium image quality.
1852    /// 中文:中等图像质量。
1853    Medium,
1854    /// EN: High image quality.
1855    /// 中文:高图像质量。
1856    High,
1857    /// EN: Let the API choose image quality automatically.
1858    /// 中文:让 API 自动选择图像质量。
1859    Auto,
1860}
1861
1862/// EN: Image generation output format.
1863/// 中文:图像生成输出格式。
1864#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
1865#[serde(rename_all = "snake_case")]
1866#[non_exhaustive]
1867pub enum ResponseImageGenerationOutputFormat {
1868    /// EN: PNG output.
1869    /// 中文:PNG 输出。
1870    Png,
1871    /// EN: WebP output.
1872    /// 中文:WebP 输出。
1873    Webp,
1874    /// EN: JPEG output.
1875    /// 中文:JPEG 输出。
1876    Jpeg,
1877}
1878
1879/// EN: Image generation moderation level.
1880/// 中文:图像生成审核级别。
1881#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
1882#[serde(rename_all = "snake_case")]
1883#[non_exhaustive]
1884pub enum ResponseImageGenerationModeration {
1885    /// EN: Let the API choose moderation automatically.
1886    /// 中文:让 API 自动选择审核级别。
1887    Auto,
1888    /// EN: Use the low moderation level.
1889    /// 中文:使用低审核级别。
1890    Low,
1891}
1892
1893/// EN: Image generation background mode.
1894/// 中文:图像生成背景模式。
1895#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
1896#[serde(rename_all = "snake_case")]
1897#[non_exhaustive]
1898pub enum ResponseImageGenerationBackground {
1899    /// EN: Transparent background.
1900    /// 中文:透明背景。
1901    Transparent,
1902    /// EN: Opaque background.
1903    /// 中文:不透明背景。
1904    Opaque,
1905    /// EN: Let the API choose the background automatically.
1906    /// 中文:让 API 自动选择背景。
1907    Auto,
1908}
1909
1910/// EN: Input image fidelity for image generation edits.
1911/// 中文:图像生成编辑的输入图像保真度。
1912#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
1913#[serde(rename_all = "snake_case")]
1914#[non_exhaustive]
1915pub enum ResponseImageGenerationInputFidelity {
1916    /// EN: High input image fidelity.
1917    /// 中文:高输入图像保真度。
1918    High,
1919    /// EN: Low input image fidelity.
1920    /// 中文:低输入图像保真度。
1921    Low,
1922}
1923
1924/// EN: Image generation action.
1925/// 中文:图像生成动作。
1926#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
1927#[serde(rename_all = "snake_case")]
1928#[non_exhaustive]
1929pub enum ResponseImageGenerationAction {
1930    /// EN: Generate a new image.
1931    /// 中文:生成新图像。
1932    Generate,
1933    /// EN: Edit an existing image.
1934    /// 中文:编辑已有图像。
1935    Edit,
1936    /// EN: Let the API choose the action automatically.
1937    /// 中文:让 API 自动选择动作。
1938    Auto,
1939}
1940
1941/// EN: MCP tool definition for Responses API remote MCP servers and connectors.
1942/// 中文:Responses API 远程 MCP 服务器和连接器使用的 MCP 工具定义。
1943#[derive(Clone, Debug, Serialize, PartialEq, Eq)]
1944#[non_exhaustive]
1945pub struct ResponseMcpTool {
1946    #[serde(rename = "type")]
1947    kind: &'static str,
1948    /// EN: Label used to identify this MCP server in tool calls.
1949    /// 中文:在工具调用中标识此 MCP 服务器的标签。
1950    pub server_label: String,
1951    /// EN: URL for a custom remote MCP server.
1952    /// 中文:自定义远程 MCP 服务器 URL。
1953    #[serde(skip_serializing_if = "Option::is_none")]
1954    pub server_url: Option<String>,
1955    /// EN: Built-in service connector identifier.
1956    /// 中文:内置服务连接器标识。
1957    #[serde(skip_serializing_if = "Option::is_none")]
1958    pub connector_id: Option<ResponseMcpConnector>,
1959    /// EN: Optional OAuth access token for the MCP server or connector.
1960    /// 中文:MCP 服务器或连接器使用的可选 OAuth access token。
1961    #[serde(skip_serializing_if = "Option::is_none")]
1962    pub authorization: Option<String>,
1963    /// EN: Optional MCP server description.
1964    /// 中文:可选的 MCP 服务器描述。
1965    #[serde(skip_serializing_if = "Option::is_none")]
1966    pub server_description: Option<String>,
1967    /// EN: Optional HTTP headers to send to the MCP server.
1968    /// 中文:发送给 MCP 服务器的可选 HTTP header。
1969    #[serde(skip_serializing_if = "BTreeMap::is_empty")]
1970    pub headers: BTreeMap<String, String>,
1971    /// EN: Optional allowed tool names or filter object.
1972    /// 中文:可选的允许工具名称列表或过滤器对象。
1973    #[serde(skip_serializing_if = "Option::is_none")]
1974    pub allowed_tools: Option<ResponseMcpAllowedTools>,
1975    /// EN: Optional approval policy for MCP tools.
1976    /// 中文:MCP 工具的可选审批策略。
1977    #[serde(skip_serializing_if = "Option::is_none")]
1978    pub require_approval: Option<ResponseMcpRequireApproval>,
1979    /// EN: Whether this MCP tool is deferred and discovered via tool search.
1980    /// 中文:此 MCP 工具是否延迟并通过工具搜索发现。
1981    #[serde(skip_serializing_if = "Option::is_none")]
1982    pub defer_loading: Option<bool>,
1983}
1984
1985impl ResponseMcpTool {
1986    /// EN: Creates an MCP tool backed by a custom remote MCP server URL.
1987    /// 中文:创建由自定义远程 MCP 服务器 URL 支持的 MCP 工具。
1988    pub fn server_url(server_label: impl Into<String>, server_url: impl Into<String>) -> Self {
1989        Self {
1990            kind: "mcp",
1991            server_label: server_label.into(),
1992            server_url: Some(server_url.into()),
1993            connector_id: None,
1994            authorization: None,
1995            server_description: None,
1996            headers: BTreeMap::new(),
1997            allowed_tools: None,
1998            require_approval: None,
1999            defer_loading: None,
2000        }
2001    }
2002
2003    /// EN: Creates an MCP tool backed by a built-in service connector.
2004    /// 中文:创建由内置服务连接器支持的 MCP 工具。
2005    pub fn connector(server_label: impl Into<String>, connector: ResponseMcpConnector) -> Self {
2006        Self {
2007            kind: "mcp",
2008            server_label: server_label.into(),
2009            server_url: None,
2010            connector_id: Some(connector),
2011            authorization: None,
2012            server_description: None,
2013            headers: BTreeMap::new(),
2014            allowed_tools: None,
2015            require_approval: None,
2016            defer_loading: None,
2017        }
2018    }
2019
2020    /// EN: Sets an OAuth access token for the MCP server or connector.
2021    /// 中文:设置 MCP 服务器或连接器使用的 OAuth access token。
2022    pub fn authorization(mut self, authorization: impl Into<String>) -> Self {
2023        self.authorization = Some(authorization.into());
2024        self
2025    }
2026
2027    /// EN: Sets an optional MCP server description.
2028    /// 中文:设置可选的 MCP 服务器描述。
2029    pub fn server_description(mut self, server_description: impl Into<String>) -> Self {
2030        self.server_description = Some(server_description.into());
2031        self
2032    }
2033
2034    /// EN: Adds an HTTP header sent to the MCP server.
2035    /// 中文:添加发送给 MCP 服务器的 HTTP header。
2036    pub fn header(mut self, name: impl Into<String>, value: impl Into<String>) -> Self {
2037        self.headers.insert(name.into(), value.into());
2038        self
2039    }
2040
2041    /// EN: Restricts MCP calls to the provided tool names.
2042    /// 中文:将 MCP 调用限制为提供的工具名称。
2043    pub fn allowed_tools<I, S>(mut self, tool_names: I) -> Self
2044    where
2045        I: IntoIterator<Item = S>,
2046        S: Into<String>,
2047    {
2048        self.allowed_tools = Some(ResponseMcpAllowedTools::Names(
2049            tool_names.into_iter().map(Into::into).collect(),
2050        ));
2051        self
2052    }
2053
2054    /// EN: Restricts MCP calls using a filter object.
2055    /// 中文:使用过滤器对象限制 MCP 调用。
2056    pub fn allowed_tool_filter(mut self, filter: ResponseMcpToolFilter) -> Self {
2057        self.allowed_tools = Some(ResponseMcpAllowedTools::Filter(filter));
2058        self
2059    }
2060
2061    /// EN: Sets the MCP tool approval policy.
2062    /// 中文:设置 MCP 工具审批策略。
2063    pub fn require_approval(mut self, require_approval: ResponseMcpRequireApproval) -> Self {
2064        self.require_approval = Some(require_approval);
2065        self
2066    }
2067
2068    /// EN: Sets whether this MCP tool is deferred and discovered via tool search.
2069    /// 中文:设置此 MCP 工具是否延迟并通过工具搜索发现。
2070    pub fn defer_loading(mut self, defer_loading: bool) -> Self {
2071        self.defer_loading = Some(defer_loading);
2072        self
2073    }
2074}
2075
2076/// EN: Built-in MCP service connector identifiers.
2077/// 中文:内置 MCP 服务连接器标识。
2078#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
2079#[non_exhaustive]
2080pub enum ResponseMcpConnector {
2081    /// EN: Dropbox connector.
2082    /// 中文:Dropbox 连接器。
2083    #[serde(rename = "connector_dropbox")]
2084    Dropbox,
2085    /// EN: Gmail connector.
2086    /// 中文:Gmail 连接器。
2087    #[serde(rename = "connector_gmail")]
2088    Gmail,
2089    /// EN: Google Calendar connector.
2090    /// 中文:Google Calendar 连接器。
2091    #[serde(rename = "connector_googlecalendar")]
2092    GoogleCalendar,
2093    /// EN: Google Drive connector.
2094    /// 中文:Google Drive 连接器。
2095    #[serde(rename = "connector_googledrive")]
2096    GoogleDrive,
2097    /// EN: Microsoft Teams connector.
2098    /// 中文:Microsoft Teams 连接器。
2099    #[serde(rename = "connector_microsoftteams")]
2100    MicrosoftTeams,
2101    /// EN: Outlook Calendar connector.
2102    /// 中文:Outlook Calendar 连接器。
2103    #[serde(rename = "connector_outlookcalendar")]
2104    OutlookCalendar,
2105    /// EN: Outlook Email connector.
2106    /// 中文:Outlook Email 连接器。
2107    #[serde(rename = "connector_outlookemail")]
2108    OutlookEmail,
2109    /// EN: SharePoint connector.
2110    /// 中文:SharePoint 连接器。
2111    #[serde(rename = "connector_sharepoint")]
2112    SharePoint,
2113}
2114
2115/// EN: MCP allowed tools selector.
2116/// 中文:MCP 允许工具选择器。
2117#[derive(Clone, Debug, Serialize, PartialEq, Eq)]
2118#[serde(untagged)]
2119#[non_exhaustive]
2120pub enum ResponseMcpAllowedTools {
2121    /// EN: Explicit allowed tool names.
2122    /// 中文:显式允许的工具名称。
2123    Names(Vec<String>),
2124    /// EN: Filter-based allowed tools.
2125    /// 中文:基于过滤器的允许工具。
2126    Filter(ResponseMcpToolFilter),
2127}
2128
2129/// EN: MCP tool filter by names and read-only annotation.
2130/// 中文:按名称和只读标注过滤 MCP 工具。
2131#[derive(Clone, Debug, Default, Serialize, PartialEq, Eq)]
2132#[non_exhaustive]
2133pub struct ResponseMcpToolFilter {
2134    /// EN: Optional tool names to match.
2135    /// 中文:可选的匹配工具名称。
2136    #[serde(skip_serializing_if = "Vec::is_empty")]
2137    pub tool_names: Vec<String>,
2138    /// EN: Optional read-only filter.
2139    /// 中文:可选的只读过滤器。
2140    #[serde(skip_serializing_if = "Option::is_none")]
2141    pub read_only: Option<bool>,
2142}
2143
2144impl ResponseMcpToolFilter {
2145    /// EN: Creates an empty MCP tool filter.
2146    /// 中文:创建空的 MCP 工具过滤器。
2147    pub fn new() -> Self {
2148        Self::default()
2149    }
2150
2151    /// EN: Sets the tool names matched by this filter.
2152    /// 中文:设置此过滤器匹配的工具名称。
2153    pub fn tool_names<I, S>(mut self, tool_names: I) -> Self
2154    where
2155        I: IntoIterator<Item = S>,
2156        S: Into<String>,
2157    {
2158        self.tool_names = tool_names.into_iter().map(Into::into).collect();
2159        self
2160    }
2161
2162    /// EN: Sets the read-only filter.
2163    /// 中文:设置只读过滤器。
2164    pub fn read_only(mut self, read_only: bool) -> Self {
2165        self.read_only = Some(read_only);
2166        self
2167    }
2168}
2169
2170/// EN: MCP approval policy.
2171/// 中文:MCP 审批策略。
2172#[derive(Clone, Debug, Serialize, PartialEq, Eq)]
2173#[serde(untagged)]
2174#[non_exhaustive]
2175pub enum ResponseMcpRequireApproval {
2176    /// EN: A single approval mode for all tools.
2177    /// 中文:应用于全部工具的单一审批模式。
2178    Mode(ResponseMcpApprovalMode),
2179    /// EN: Filtered approval policy.
2180    /// 中文:基于过滤器的审批策略。
2181    Filter(ResponseMcpApprovalFilter),
2182}
2183
2184/// EN: MCP approval mode for all tools.
2185/// 中文:全部 MCP 工具的审批模式。
2186#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
2187#[serde(rename_all = "snake_case")]
2188#[non_exhaustive]
2189pub enum ResponseMcpApprovalMode {
2190    /// EN: Always require approval.
2191    /// 中文:始终要求审批。
2192    Always,
2193    /// EN: Never require approval.
2194    /// 中文:从不要求审批。
2195    Never,
2196}
2197
2198/// EN: MCP approval filters for always and never approval sets.
2199/// 中文:MCP always 和 never 审批集合的过滤器。
2200#[derive(Clone, Debug, Default, Serialize, PartialEq, Eq)]
2201#[non_exhaustive]
2202pub struct ResponseMcpApprovalFilter {
2203    /// EN: Tools that always require approval.
2204    /// 中文:始终需要审批的工具。
2205    #[serde(skip_serializing_if = "Option::is_none")]
2206    pub always: Option<ResponseMcpToolFilter>,
2207    /// EN: Tools that never require approval.
2208    /// 中文:从不需要审批的工具。
2209    #[serde(skip_serializing_if = "Option::is_none")]
2210    pub never: Option<ResponseMcpToolFilter>,
2211}
2212
2213impl ResponseMcpApprovalFilter {
2214    /// EN: Creates an empty MCP approval filter.
2215    /// 中文:创建空的 MCP 审批过滤器。
2216    pub fn new() -> Self {
2217        Self::default()
2218    }
2219
2220    /// EN: Sets tools that always require approval.
2221    /// 中文:设置始终需要审批的工具。
2222    pub fn always(mut self, filter: ResponseMcpToolFilter) -> Self {
2223        self.always = Some(filter);
2224        self
2225    }
2226
2227    /// EN: Sets tools that never require approval.
2228    /// 中文:设置从不需要审批的工具。
2229    pub fn never(mut self, filter: ResponseMcpToolFilter) -> Self {
2230        self.never = Some(filter);
2231        self
2232    }
2233}
2234
2235/// EN: Web search tool definition for Responses API built-in web search.
2236/// 中文:Responses API 内置网页搜索使用的 web search 工具定义。
2237#[derive(Clone, Debug, Serialize, PartialEq)]
2238#[non_exhaustive]
2239pub struct ResponseWebSearchTool {
2240    #[serde(rename = "type")]
2241    kind: ResponseWebSearchToolType,
2242    /// EN: Optional filters for web search.
2243    /// 中文:可选的网页搜索过滤器。
2244    #[serde(skip_serializing_if = "Option::is_none")]
2245    pub filters: Option<Value>,
2246    /// EN: Optional approximate user location object.
2247    /// 中文:可选的用户大致位置对象。
2248    #[serde(skip_serializing_if = "Option::is_none")]
2249    pub user_location: Option<Value>,
2250    /// EN: Optional search context size guidance.
2251    /// 中文:可选的搜索上下文大小提示。
2252    #[serde(skip_serializing_if = "Option::is_none")]
2253    pub search_context_size: Option<ResponseWebSearchContextSize>,
2254    /// EN: Optional preview search content types.
2255    /// 中文:可选的 preview 搜索内容类型。
2256    #[serde(skip_serializing_if = "Vec::is_empty")]
2257    pub search_content_types: Vec<String>,
2258}
2259
2260impl ResponseWebSearchTool {
2261    /// EN: Creates the current web search tool.
2262    /// 中文:创建当前 web_search 工具。
2263    pub fn web_search() -> Self {
2264        Self::new(ResponseWebSearchToolType::WebSearch)
2265    }
2266
2267    /// EN: Creates the versioned 2025-08-26 web search tool.
2268    /// 中文:创建 2025-08-26 版本的 web_search 工具。
2269    pub fn web_search_2025_08_26() -> Self {
2270        Self::new(ResponseWebSearchToolType::WebSearch20250826)
2271    }
2272
2273    /// EN: Creates the current web search preview tool.
2274    /// 中文:创建当前 web_search_preview 工具。
2275    pub fn web_search_preview() -> Self {
2276        Self::new(ResponseWebSearchToolType::WebSearchPreview)
2277    }
2278
2279    /// EN: Creates the versioned 2025-03-11 web search preview tool.
2280    /// 中文:创建 2025-03-11 版本的 web_search_preview 工具。
2281    pub fn web_search_preview_2025_03_11() -> Self {
2282        Self::new(ResponseWebSearchToolType::WebSearchPreview20250311)
2283    }
2284
2285    fn new(kind: ResponseWebSearchToolType) -> Self {
2286        Self {
2287            kind,
2288            filters: None,
2289            user_location: None,
2290            search_context_size: None,
2291            search_content_types: Vec::new(),
2292        }
2293    }
2294
2295    /// EN: Sets web search filters.
2296    /// 中文:设置网页搜索过滤器。
2297    pub fn filters(mut self, filters: Value) -> Self {
2298        self.filters = Some(filters);
2299        self
2300    }
2301
2302    /// EN: Sets the approximate user location object.
2303    /// 中文:设置用户大致位置对象。
2304    pub fn user_location(mut self, user_location: Value) -> Self {
2305        self.user_location = Some(user_location);
2306        self
2307    }
2308
2309    /// EN: Sets search context size guidance.
2310    /// 中文:设置搜索上下文大小提示。
2311    pub fn search_context_size(
2312        mut self,
2313        search_context_size: ResponseWebSearchContextSize,
2314    ) -> Self {
2315        self.search_context_size = Some(search_context_size);
2316        self
2317    }
2318
2319    /// EN: Sets preview search content types.
2320    /// 中文:设置 preview 搜索内容类型。
2321    pub fn search_content_types<I, S>(mut self, search_content_types: I) -> Self
2322    where
2323        I: IntoIterator<Item = S>,
2324        S: Into<String>,
2325    {
2326        self.search_content_types = search_content_types.into_iter().map(Into::into).collect();
2327        self
2328    }
2329}
2330
2331/// EN: Web search tool wire type.
2332/// 中文:网页搜索工具的传输类型。
2333#[derive(Clone, Copy, Debug, Serialize, PartialEq, Eq)]
2334#[non_exhaustive]
2335pub enum ResponseWebSearchToolType {
2336    /// EN: Current web search tool.
2337    /// 中文:当前 web_search 工具。
2338    #[serde(rename = "web_search")]
2339    WebSearch,
2340    /// EN: Versioned 2025-08-26 web search tool.
2341    /// 中文:2025-08-26 版本的 web_search 工具。
2342    #[serde(rename = "web_search_2025_08_26")]
2343    WebSearch20250826,
2344    /// EN: Current web search preview tool.
2345    /// 中文:当前 web_search_preview 工具。
2346    #[serde(rename = "web_search_preview")]
2347    WebSearchPreview,
2348    /// EN: Versioned 2025-03-11 web search preview tool.
2349    /// 中文:2025-03-11 版本的 web_search_preview 工具。
2350    #[serde(rename = "web_search_preview_2025_03_11")]
2351    WebSearchPreview20250311,
2352}
2353
2354/// EN: Search context size guidance for web search tools.
2355/// 中文:网页搜索工具的搜索上下文大小提示。
2356#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
2357#[serde(rename_all = "snake_case")]
2358#[non_exhaustive]
2359pub enum ResponseWebSearchContextSize {
2360    /// EN: Use a small search context.
2361    /// 中文:使用较小的搜索上下文。
2362    Low,
2363    /// EN: Use the default medium search context.
2364    /// 中文:使用默认的中等搜索上下文。
2365    Medium,
2366    /// EN: Use a larger search context.
2367    /// 中文:使用较大的搜索上下文。
2368    High,
2369}
2370
2371/// EN: Tool selection mode or specific tool for a Responses API request.
2372/// 中文:Responses API 请求的工具选择模式或指定工具。
2373#[derive(Clone, Debug, PartialEq, Eq)]
2374#[non_exhaustive]
2375pub enum ResponseToolChoice {
2376    /// EN: The model must not call tools and should generate a message.
2377    /// 中文:模型不得调用工具,应直接生成消息。
2378    None,
2379    /// EN: The model may choose between generating a message and calling tools.
2380    /// 中文:模型可以在生成消息和调用工具之间自动选择。
2381    Auto,
2382    /// EN: The model must call one or more tools.
2383    /// 中文:模型必须调用一个或多个工具。
2384    Required,
2385    /// EN: Force the model to call a built-in hosted tool.
2386    /// 中文:强制模型调用一个内置托管工具。
2387    HostedTool {
2388        /// EN: Hosted tool type to call.
2389        /// 中文:要调用的托管工具类型。
2390        tool_type: ResponseHostedToolChoice,
2391    },
2392    /// EN: Force the model to call a named function tool.
2393    /// 中文:强制模型调用指定名称的 function 工具。
2394    Function {
2395        /// EN: Function name to call.
2396        /// 中文:要调用的 function 名称。
2397        name: String,
2398    },
2399    /// EN: Force the model to call a named custom tool.
2400    /// 中文:强制模型调用指定名称的 custom 工具。
2401    Custom {
2402        /// EN: Custom tool name to call.
2403        /// 中文:要调用的 custom 工具名称。
2404        name: String,
2405    },
2406    /// EN: Force the model to call a tool on a remote MCP server.
2407    /// 中文:强制模型调用远程 MCP 服务器上的工具。
2408    Mcp {
2409        /// EN: MCP server label to use.
2410        /// 中文:要使用的 MCP 服务器标签。
2411        server_label: String,
2412        /// EN: Optional tool name to call on the MCP server.
2413        /// 中文:要在 MCP 服务器上调用的可选工具名称。
2414        name: Option<String>,
2415    },
2416    /// EN: Force the model to call the apply_patch tool.
2417    /// 中文:强制模型调用 apply_patch 工具。
2418    ApplyPatch,
2419    /// EN: Force the model to call the shell tool.
2420    /// 中文:强制模型调用 shell 工具。
2421    Shell,
2422    /// EN: Constrain the model to a pre-defined set of allowed tools.
2423    /// 中文:将模型限制为只能从预定义的允许工具集合中选择。
2424    AllowedTools {
2425        /// EN: Selection mode within the allowed tools set.
2426        /// 中文:允许工具集合内的选择模式。
2427        mode: ResponseAllowedToolsMode,
2428        /// EN: Tool definitions the model may call.
2429        /// 中文:模型可以调用的工具定义。
2430        tools: Vec<Value>,
2431    },
2432}
2433
2434impl ResponseToolChoice {
2435    /// EN: Creates a hosted tool choice for the provided built-in tool type.
2436    /// 中文:为提供的内置工具类型创建 hosted tool 选择。
2437    pub fn hosted_tool(tool_type: ResponseHostedToolChoice) -> Self {
2438        Self::HostedTool { tool_type }
2439    }
2440
2441    /// EN: Creates a function tool choice for the provided function name.
2442    /// 中文:为提供的 function 名称创建工具选择。
2443    pub fn function(name: impl Into<String>) -> Self {
2444        Self::Function { name: name.into() }
2445    }
2446
2447    /// EN: Creates a custom tool choice for the provided custom tool name.
2448    /// 中文:为提供的 custom 工具名称创建工具选择。
2449    pub fn custom(name: impl Into<String>) -> Self {
2450        Self::Custom { name: name.into() }
2451    }
2452
2453    /// EN: Creates an MCP server tool choice for the provided server label.
2454    /// 中文:为提供的服务器标签创建 MCP 工具选择。
2455    pub fn mcp(server_label: impl Into<String>) -> Self {
2456        Self::Mcp {
2457            server_label: server_label.into(),
2458            name: None,
2459        }
2460    }
2461
2462    /// EN: Creates an MCP tool choice for a named tool on the provided server.
2463    /// 中文:为提供的服务器和工具名称创建 MCP 工具选择。
2464    pub fn mcp_tool(server_label: impl Into<String>, name: impl Into<String>) -> Self {
2465        Self::Mcp {
2466            server_label: server_label.into(),
2467            name: Some(name.into()),
2468        }
2469    }
2470
2471    /// EN: Creates an allowed-tools choice with the provided mode and tool definitions.
2472    /// 中文:使用提供的模式和工具定义创建 allowed-tools 选择。
2473    pub fn allowed_tools<I>(mode: ResponseAllowedToolsMode, tools: I) -> Self
2474    where
2475        I: IntoIterator<Item = Value>,
2476    {
2477        Self::AllowedTools {
2478            mode,
2479            tools: tools.into_iter().collect(),
2480        }
2481    }
2482}
2483
2484impl Serialize for ResponseToolChoice {
2485    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
2486    where
2487        S: serde::Serializer,
2488    {
2489        match self {
2490            Self::None => serializer.serialize_str("none"),
2491            Self::Auto => serializer.serialize_str("auto"),
2492            Self::Required => serializer.serialize_str("required"),
2493            Self::HostedTool { tool_type } => {
2494                let mut state = serializer.serialize_struct("ResponseToolChoiceHostedTool", 1)?;
2495                state.serialize_field("type", tool_type)?;
2496                state.end()
2497            }
2498            Self::Function { name } => {
2499                let mut state = serializer.serialize_struct("ResponseToolChoiceFunction", 2)?;
2500                state.serialize_field("type", "function")?;
2501                state.serialize_field("name", name)?;
2502                state.end()
2503            }
2504            Self::Custom { name } => {
2505                let mut state = serializer.serialize_struct("ResponseToolChoiceCustom", 2)?;
2506                state.serialize_field("type", "custom")?;
2507                state.serialize_field("name", name)?;
2508                state.end()
2509            }
2510            Self::Mcp { server_label, name } => {
2511                let mut state = serializer
2512                    .serialize_struct("ResponseToolChoiceMcp", 2 + usize::from(name.is_some()))?;
2513                state.serialize_field("type", "mcp")?;
2514                state.serialize_field("server_label", server_label)?;
2515                if let Some(name) = name {
2516                    state.serialize_field("name", name)?;
2517                }
2518                state.end()
2519            }
2520            Self::ApplyPatch => {
2521                let mut state = serializer.serialize_struct("ResponseToolChoiceApplyPatch", 1)?;
2522                state.serialize_field("type", "apply_patch")?;
2523                state.end()
2524            }
2525            Self::Shell => {
2526                let mut state = serializer.serialize_struct("ResponseToolChoiceShell", 1)?;
2527                state.serialize_field("type", "shell")?;
2528                state.end()
2529            }
2530            Self::AllowedTools { mode, tools } => {
2531                let mut state = serializer.serialize_struct("ResponseToolChoiceAllowedTools", 3)?;
2532                state.serialize_field("type", "allowed_tools")?;
2533                state.serialize_field("mode", mode)?;
2534                state.serialize_field("tools", tools)?;
2535                state.end()
2536            }
2537        }
2538    }
2539}
2540
2541impl<'de> Deserialize<'de> for ResponseToolChoice {
2542    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2543    where
2544        D: serde::Deserializer<'de>,
2545    {
2546        #[derive(Deserialize)]
2547        struct ObjectToolChoice {
2548            #[serde(rename = "type")]
2549            tool_type: String,
2550            name: Option<String>,
2551            server_label: Option<String>,
2552            mode: Option<ResponseAllowedToolsMode>,
2553            tools: Option<Vec<Value>>,
2554        }
2555
2556        let value = Value::deserialize(deserializer)?;
2557        if let Some(value) = value.as_str() {
2558            return match value {
2559                "none" => Ok(Self::None),
2560                "auto" => Ok(Self::Auto),
2561                "required" => Ok(Self::Required),
2562                other => Err(serde::de::Error::unknown_variant(
2563                    other,
2564                    &["none", "auto", "required"],
2565                )),
2566            };
2567        }
2568        let object = ObjectToolChoice::deserialize(value).map_err(serde::de::Error::custom)?;
2569        if object.tool_type == "function" {
2570            let name = object
2571                .name
2572                .ok_or_else(|| serde::de::Error::missing_field("name"))?;
2573            return Ok(Self::Function { name });
2574        }
2575        if object.tool_type == "custom" {
2576            let name = object
2577                .name
2578                .ok_or_else(|| serde::de::Error::missing_field("name"))?;
2579            return Ok(Self::Custom { name });
2580        }
2581        if object.tool_type == "mcp" {
2582            let server_label = object
2583                .server_label
2584                .ok_or_else(|| serde::de::Error::missing_field("server_label"))?;
2585            return Ok(Self::Mcp {
2586                server_label,
2587                name: object.name,
2588            });
2589        }
2590        if object.tool_type == "apply_patch" {
2591            return Ok(Self::ApplyPatch);
2592        }
2593        if object.tool_type == "shell" {
2594            return Ok(Self::Shell);
2595        }
2596        if object.tool_type == "allowed_tools" {
2597            let mode = object
2598                .mode
2599                .ok_or_else(|| serde::de::Error::missing_field("mode"))?;
2600            let tools = object
2601                .tools
2602                .ok_or_else(|| serde::de::Error::missing_field("tools"))?;
2603            return Ok(Self::AllowedTools { mode, tools });
2604        }
2605        if let Some(tool_type) = ResponseHostedToolChoice::from_wire_type(&object.tool_type) {
2606            return Ok(Self::HostedTool { tool_type });
2607        }
2608        Err(serde::de::Error::unknown_variant(
2609            &object.tool_type,
2610            &[
2611                "none",
2612                "auto",
2613                "required",
2614                "file_search",
2615                "web_search_preview",
2616                "computer",
2617                "computer_use_preview",
2618                "computer_use",
2619                "web_search_preview_2025_03_11",
2620                "image_generation",
2621                "code_interpreter",
2622                "function",
2623                "custom",
2624                "mcp",
2625                "apply_patch",
2626                "shell",
2627                "allowed_tools",
2628            ],
2629        ))
2630    }
2631}
2632
2633/// EN: Selection mode for an allowed tools Responses API tool choice.
2634/// 中文:Responses API allowed tools 工具选择的选择模式。
2635#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
2636#[serde(rename_all = "snake_case")]
2637#[non_exhaustive]
2638pub enum ResponseAllowedToolsMode {
2639    /// EN: Allow the model to choose among allowed tools or generate a message.
2640    /// 中文:允许模型在允许工具中选择,或生成普通消息。
2641    Auto,
2642    /// EN: Require the model to call one or more allowed tools.
2643    /// 中文:要求模型调用一个或多个允许工具。
2644    Required,
2645}
2646
2647/// EN: Built-in hosted tool type for a Responses API tool choice.
2648/// 中文:Responses API 工具选择使用的内置托管工具类型。
2649#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
2650#[non_exhaustive]
2651pub enum ResponseHostedToolChoice {
2652    /// EN: File search hosted tool.
2653    /// 中文:文件搜索托管工具。
2654    #[serde(rename = "file_search")]
2655    FileSearch,
2656    /// EN: Web search preview hosted tool.
2657    /// 中文:网页搜索预览托管工具。
2658    #[serde(rename = "web_search_preview")]
2659    WebSearchPreview,
2660    /// EN: Computer hosted tool.
2661    /// 中文:计算机托管工具。
2662    #[serde(rename = "computer")]
2663    Computer,
2664    /// EN: Computer use preview hosted tool.
2665    /// 中文:计算机使用预览托管工具。
2666    #[serde(rename = "computer_use_preview")]
2667    ComputerUsePreview,
2668    /// EN: Computer use hosted tool.
2669    /// 中文:计算机使用托管工具。
2670    #[serde(rename = "computer_use")]
2671    ComputerUse,
2672    /// EN: Versioned web search preview hosted tool.
2673    /// 中文:带版本的网页搜索预览托管工具。
2674    #[serde(rename = "web_search_preview_2025_03_11")]
2675    WebSearchPreview2025_03_11,
2676    /// EN: Image generation hosted tool.
2677    /// 中文:图像生成托管工具。
2678    #[serde(rename = "image_generation")]
2679    ImageGeneration,
2680    /// EN: Code interpreter hosted tool.
2681    /// 中文:代码解释器托管工具。
2682    #[serde(rename = "code_interpreter")]
2683    CodeInterpreter,
2684}
2685
2686impl ResponseHostedToolChoice {
2687    fn from_wire_type(value: &str) -> Option<Self> {
2688        match value {
2689            "file_search" => Some(Self::FileSearch),
2690            "web_search_preview" => Some(Self::WebSearchPreview),
2691            "computer" => Some(Self::Computer),
2692            "computer_use_preview" => Some(Self::ComputerUsePreview),
2693            "computer_use" => Some(Self::ComputerUse),
2694            "web_search_preview_2025_03_11" => Some(Self::WebSearchPreview2025_03_11),
2695            "image_generation" => Some(Self::ImageGeneration),
2696            "code_interpreter" => Some(Self::CodeInterpreter),
2697            _ => None,
2698        }
2699    }
2700}
2701
2702/// EN: Reasoning configuration for reasoning-capable Responses API models.
2703/// 中文:Responses API 中支持推理模型的推理配置。
2704#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
2705#[non_exhaustive]
2706pub struct ResponseReasoning {
2707    /// EN: Optional effort level for reasoning tokens.
2708    /// 中文:推理 token 的可选努力等级。
2709    #[serde(skip_serializing_if = "Option::is_none")]
2710    pub effort: Option<ResponseReasoningEffort>,
2711    /// EN: Optional summary mode for the model's reasoning.
2712    /// 中文:模型推理过程的可选摘要模式。
2713    #[serde(skip_serializing_if = "Option::is_none")]
2714    pub summary: Option<ResponseReasoningSummary>,
2715}
2716
2717impl ResponseReasoning {
2718    /// EN: Starts building reasoning configuration.
2719    /// 中文:开始构建推理配置。
2720    pub fn builder() -> ResponseReasoningBuilder {
2721        ResponseReasoningBuilder::default()
2722    }
2723}
2724
2725/// EN: Builder for Responses API reasoning configuration.
2726/// 中文:Responses API 推理配置的构建器。
2727#[derive(Clone, Debug, Default)]
2728#[non_exhaustive]
2729pub struct ResponseReasoningBuilder {
2730    effort: Option<ResponseReasoningEffort>,
2731    summary: Option<ResponseReasoningSummary>,
2732}
2733
2734impl ResponseReasoningBuilder {
2735    /// EN: Sets the reasoning effort level.
2736    /// 中文:设置推理努力等级。
2737    pub fn effort(mut self, effort: ResponseReasoningEffort) -> Self {
2738        self.effort = Some(effort);
2739        self
2740    }
2741
2742    /// EN: Sets the reasoning summary mode.
2743    /// 中文:设置推理摘要模式。
2744    pub fn summary(mut self, summary: ResponseReasoningSummary) -> Self {
2745        self.summary = Some(summary);
2746        self
2747    }
2748
2749    /// EN: Builds the reasoning configuration.
2750    /// 中文:构建推理配置。
2751    pub fn build(self) -> ResponseReasoning {
2752        ResponseReasoning {
2753            effort: self.effort,
2754            summary: self.summary,
2755        }
2756    }
2757}
2758
2759/// EN: Effort level for reasoning-capable models.
2760/// 中文:支持推理模型的努力等级。
2761#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
2762#[serde(rename_all = "snake_case")]
2763#[non_exhaustive]
2764pub enum ResponseReasoningEffort {
2765    /// EN: Disable reasoning when the selected model supports it.
2766    /// 中文:在所选模型支持时禁用推理。
2767    None,
2768    /// EN: Use minimal reasoning effort.
2769    /// 中文:使用最小推理努力。
2770    Minimal,
2771    /// EN: Use low reasoning effort.
2772    /// 中文:使用低推理努力。
2773    Low,
2774    /// EN: Use medium reasoning effort.
2775    /// 中文:使用中等推理努力。
2776    Medium,
2777    /// EN: Use high reasoning effort.
2778    /// 中文:使用高推理努力。
2779    High,
2780    /// EN: Use extra-high reasoning effort when supported.
2781    /// 中文:在支持时使用超高推理努力。
2782    #[serde(rename = "xhigh")]
2783    XHigh,
2784}
2785
2786/// EN: Summary mode for reasoning output.
2787/// 中文:推理输出的摘要模式。
2788#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
2789#[serde(rename_all = "snake_case")]
2790#[non_exhaustive]
2791pub enum ResponseReasoningSummary {
2792    /// EN: Let the API choose the reasoning summary mode.
2793    /// 中文:让 API 选择推理摘要模式。
2794    Auto,
2795    /// EN: Request a concise reasoning summary.
2796    /// 中文:请求简洁的推理摘要。
2797    Concise,
2798    /// EN: Request a detailed reasoning summary.
2799    /// 中文:请求详细的推理摘要。
2800    Detailed,
2801}
2802
2803/// EN: Service tier used to serve a Responses API request.
2804/// 中文:用于处理 Responses API 请求的服务层级。
2805#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
2806#[serde(rename_all = "snake_case")]
2807#[non_exhaustive]
2808pub enum ResponseServiceTier {
2809    /// EN: Use the project-configured service tier, defaulting to standard processing.
2810    /// 中文:使用项目配置的服务层级,默认使用标准处理。
2811    Auto,
2812    /// EN: Use standard pricing and performance for the selected model.
2813    /// 中文:对所选模型使用标准价格和性能。
2814    Default,
2815    /// EN: Use flex processing when available for the request.
2816    /// 中文:在请求可用时使用 flex 处理。
2817    Flex,
2818    /// EN: Use priority processing when available for the request.
2819    /// 中文:在请求可用时使用 priority 处理。
2820    Priority,
2821}
2822
2823/// EN: Retention policy for prompt cache entries created by a Responses API request.
2824/// 中文:Responses API 请求创建的提示缓存条目的保留策略。
2825#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
2826#[non_exhaustive]
2827pub enum ResponsePromptCacheRetention {
2828    /// EN: Keep the cached prefix in memory only.
2829    /// 中文:仅在内存中保留缓存前缀。
2830    #[serde(rename = "in_memory")]
2831    InMemory,
2832    /// EN: Keep cached prefixes active for up to 24 hours where supported.
2833    /// 中文:在支持时让缓存前缀最多保持 24 小时活跃。
2834    #[serde(rename = "24h")]
2835    TwentyFourHours,
2836}
2837
2838/// EN: Request body for `POST /v1/responses/input_tokens`.
2839/// 中文:`POST /v1/responses/input_tokens` 的请求体。
2840#[derive(Clone, Debug, Default, Serialize, PartialEq)]
2841#[non_exhaustive]
2842pub struct CreateResponseInputTokensRequest {
2843    /// EN: Optional model id used for token accounting.
2844    /// 中文:用于 token 计数的可选模型 ID。
2845    #[serde(skip_serializing_if = "Option::is_none")]
2846    pub model: Option<String>,
2847    /// EN: Optional response input to count.
2848    /// 中文:要计数的可选响应输入。
2849    #[serde(skip_serializing_if = "Option::is_none")]
2850    pub input: Option<ResponseInput>,
2851    /// EN: Optional system or developer instructions.
2852    /// 中文:可选的系统或开发者指令。
2853    #[serde(skip_serializing_if = "Option::is_none")]
2854    pub instructions: Option<String>,
2855    /// EN: Optional previous response id for conversation state.
2856    /// 中文:用于会话状态的可选上一条响应 ID。
2857    #[serde(skip_serializing_if = "Option::is_none")]
2858    pub previous_response_id: Option<String>,
2859    /// EN: Optional text configuration used for token accounting.
2860    /// 中文:用于 token 计数的可选文本配置。
2861    #[serde(skip_serializing_if = "Option::is_none")]
2862    pub text: Option<ResponseTextConfig>,
2863    /// EN: Forward-compatible optional fields not yet covered by handwritten types.
2864    /// 中文:手写类型尚未覆盖的前向兼容可选字段。
2865    #[serde(flatten)]
2866    pub extra: BTreeMap<String, Value>,
2867}
2868
2869impl CreateResponseInputTokensRequest {
2870    /// EN: Starts building an input-token count request.
2871    /// 中文:开始构建输入 token 计数请求。
2872    pub fn builder() -> CreateResponseInputTokensRequestBuilder {
2873        CreateResponseInputTokensRequestBuilder::default()
2874    }
2875}
2876
2877/// EN: Builder for input-token count requests.
2878/// 中文:输入 token 计数请求的构建器。
2879#[derive(Clone, Debug, Default)]
2880#[non_exhaustive]
2881pub struct CreateResponseInputTokensRequestBuilder {
2882    model: Option<String>,
2883    input: Option<ResponseInput>,
2884    instructions: Option<String>,
2885    previous_response_id: Option<String>,
2886    text: Option<ResponseTextConfig>,
2887    extra: BTreeMap<String, Value>,
2888}
2889
2890impl CreateResponseInputTokensRequestBuilder {
2891    /// EN: Sets the optional model id.
2892    /// 中文:设置可选模型 ID。
2893    pub fn model(mut self, model: impl Into<String>) -> Self {
2894        self.model = Some(model.into());
2895        self
2896    }
2897
2898    /// EN: Sets the optional input value.
2899    /// 中文:设置可选输入值。
2900    pub fn input(mut self, input: impl Into<ResponseInput>) -> Self {
2901        self.input = Some(input.into());
2902        self
2903    }
2904
2905    /// EN: Sets optional system or developer instructions.
2906    /// 中文:设置可选系统或开发者指令。
2907    pub fn instructions(mut self, instructions: impl Into<String>) -> Self {
2908        self.instructions = Some(instructions.into());
2909        self
2910    }
2911
2912    /// EN: Sets the optional previous response id.
2913    /// 中文:设置可选上一条响应 ID。
2914    pub fn previous_response_id(mut self, previous_response_id: impl Into<String>) -> Self {
2915        self.previous_response_id = Some(previous_response_id.into());
2916        self
2917    }
2918
2919    /// EN: Sets optional text configuration.
2920    /// 中文:设置可选文本配置。
2921    pub fn text(mut self, text: ResponseTextConfig) -> Self {
2922        self.text = Some(text);
2923        self
2924    }
2925
2926    /// EN: Adds a forward-compatible JSON field.
2927    /// 中文:添加前向兼容的 JSON 字段。
2928    pub fn extra(mut self, name: impl Into<String>, value: Value) -> Self {
2929        self.extra.insert(name.into(), value);
2930        self
2931    }
2932
2933    /// EN: Builds and validates the request.
2934    /// 中文:构建并校验请求。
2935    pub fn build(self) -> Result<CreateResponseInputTokensRequest, LingerError> {
2936        validate_optional_string("model", self.model.as_deref())?;
2937        validate_optional_string("instructions", self.instructions.as_deref())?;
2938        validate_optional_string("previous_response_id", self.previous_response_id.as_deref())?;
2939        if self.input.is_none() && self.extra.is_empty() {
2940            return Err(LingerError::invalid_config("input is required"));
2941        }
2942        if let Some(text) = &self.text {
2943            validate_text_config(text)?;
2944        }
2945        validate_extra_fields(&self.extra)?;
2946        Ok(CreateResponseInputTokensRequest {
2947            model: self.model,
2948            input: self.input,
2949            instructions: self.instructions,
2950            previous_response_id: self.previous_response_id,
2951            text: self.text,
2952            extra: self.extra,
2953        })
2954    }
2955}
2956
2957/// EN: Request body for `POST /v1/responses/compact`.
2958/// 中文:`POST /v1/responses/compact` 的请求体。
2959#[derive(Clone, Debug, Serialize, PartialEq)]
2960#[non_exhaustive]
2961pub struct CompactResponseRequest {
2962    /// EN: Model id used for compaction.
2963    /// 中文:用于压缩上下文的模型 ID。
2964    pub model: String,
2965    /// EN: Optional input to compact.
2966    /// 中文:要压缩的可选输入。
2967    #[serde(skip_serializing_if = "Option::is_none")]
2968    pub input: Option<ResponseInput>,
2969    /// EN: Optional system or developer instructions.
2970    /// 中文:可选的系统或开发者指令。
2971    #[serde(skip_serializing_if = "Option::is_none")]
2972    pub instructions: Option<String>,
2973    /// EN: Optional previous response id for conversation state.
2974    /// 中文:用于会话状态的可选上一条响应 ID。
2975    #[serde(skip_serializing_if = "Option::is_none")]
2976    pub previous_response_id: Option<String>,
2977    /// EN: Forward-compatible optional fields not yet covered by handwritten types.
2978    /// 中文:手写类型尚未覆盖的前向兼容可选字段。
2979    #[serde(flatten)]
2980    pub extra: BTreeMap<String, Value>,
2981}
2982
2983impl CompactResponseRequest {
2984    /// EN: Starts building a response compaction request.
2985    /// 中文:开始构建响应压缩请求。
2986    pub fn builder() -> CompactResponseRequestBuilder {
2987        CompactResponseRequestBuilder::default()
2988    }
2989}
2990
2991/// EN: Builder for response compaction requests.
2992/// 中文:响应压缩请求的构建器。
2993#[derive(Clone, Debug, Default)]
2994#[non_exhaustive]
2995pub struct CompactResponseRequestBuilder {
2996    model: Option<String>,
2997    input: Option<ResponseInput>,
2998    instructions: Option<String>,
2999    previous_response_id: Option<String>,
3000    extra: BTreeMap<String, Value>,
3001}
3002
3003impl CompactResponseRequestBuilder {
3004    /// EN: Sets the model id.
3005    /// 中文:设置模型 ID。
3006    pub fn model(mut self, model: impl Into<String>) -> Self {
3007        self.model = Some(model.into());
3008        self
3009    }
3010
3011    /// EN: Sets optional input.
3012    /// 中文:设置可选输入。
3013    pub fn input(mut self, input: impl Into<ResponseInput>) -> Self {
3014        self.input = Some(input.into());
3015        self
3016    }
3017
3018    /// EN: Sets optional system or developer instructions.
3019    /// 中文:设置可选系统或开发者指令。
3020    pub fn instructions(mut self, instructions: impl Into<String>) -> Self {
3021        self.instructions = Some(instructions.into());
3022        self
3023    }
3024
3025    /// EN: Sets the optional previous response id.
3026    /// 中文:设置可选上一条响应 ID。
3027    pub fn previous_response_id(mut self, previous_response_id: impl Into<String>) -> Self {
3028        self.previous_response_id = Some(previous_response_id.into());
3029        self
3030    }
3031
3032    /// EN: Adds a forward-compatible JSON field.
3033    /// 中文:添加前向兼容的 JSON 字段。
3034    pub fn extra(mut self, name: impl Into<String>, value: Value) -> Self {
3035        self.extra.insert(name.into(), value);
3036        self
3037    }
3038
3039    /// EN: Builds and validates the request.
3040    /// 中文:构建并校验请求。
3041    pub fn build(self) -> Result<CompactResponseRequest, LingerError> {
3042        let model = self
3043            .model
3044            .filter(|value| !value.trim().is_empty())
3045            .ok_or_else(|| LingerError::invalid_config("model is required"))?;
3046        validate_optional_string("instructions", self.instructions.as_deref())?;
3047        validate_optional_string("previous_response_id", self.previous_response_id.as_deref())?;
3048        validate_extra_fields(&self.extra)?;
3049        Ok(CompactResponseRequest {
3050            model,
3051            input: self.input,
3052            instructions: self.instructions,
3053            previous_response_id: self.previous_response_id,
3054            extra: self.extra,
3055        })
3056    }
3057}
3058
3059/// EN: Responses API input value.
3060/// 中文:Responses API 输入值。
3061#[derive(Clone, Debug, Serialize, PartialEq)]
3062#[serde(untagged)]
3063#[non_exhaustive]
3064pub enum ResponseInput {
3065    /// EN: Plain text input.
3066    /// 中文:纯文本输入。
3067    Text(String),
3068    /// EN: Structured input messages.
3069    /// 中文:结构化输入消息。
3070    Messages(Vec<ResponseInputMessage>),
3071}
3072
3073impl From<&str> for ResponseInput {
3074    fn from(value: &str) -> Self {
3075        Self::Text(value.to_string())
3076    }
3077}
3078
3079impl From<String> for ResponseInput {
3080    fn from(value: String) -> Self {
3081        Self::Text(value)
3082    }
3083}
3084
3085impl From<Vec<ResponseInputMessage>> for ResponseInput {
3086    fn from(value: Vec<ResponseInputMessage>) -> Self {
3087        Self::Messages(value)
3088    }
3089}
3090
3091/// EN: Structured input message.
3092/// 中文:结构化输入消息。
3093#[derive(Clone, Debug, Serialize, PartialEq)]
3094#[non_exhaustive]
3095pub struct ResponseInputMessage {
3096    /// EN: Message role.
3097    /// 中文:消息角色。
3098    pub role: String,
3099    /// EN: Message content.
3100    /// 中文:消息内容。
3101    pub content: Vec<ResponseInputMessageContent>,
3102}
3103
3104/// EN: Structured input message content.
3105/// 中文:结构化输入消息内容。
3106#[derive(Clone, Debug, Serialize, PartialEq)]
3107#[serde(tag = "type")]
3108#[non_exhaustive]
3109pub enum ResponseInputMessageContent {
3110    /// EN: Input text content.
3111    /// 中文:输入文本内容。
3112    #[serde(rename = "input_text")]
3113    InputText {
3114        /// EN: Text content.
3115        /// 中文:文本内容。
3116        text: String,
3117    },
3118}
3119
3120/// EN: Text output configuration.
3121/// 中文:文本输出配置。
3122#[derive(Clone, Debug, Default, Serialize, PartialEq)]
3123#[non_exhaustive]
3124pub struct ResponseTextConfig {
3125    /// EN: Optional text format configuration.
3126    /// 中文:可选的文本格式配置。
3127    #[serde(skip_serializing_if = "Option::is_none")]
3128    pub format: Option<ResponseTextFormat>,
3129    /// EN: Optional output verbosity.
3130    /// 中文:可选的输出详细程度。
3131    #[serde(skip_serializing_if = "Option::is_none")]
3132    pub verbosity: Option<ResponseTextVerbosity>,
3133}
3134
3135impl ResponseTextConfig {
3136    /// EN: Sets the text output format.
3137    /// 中文:设置文本输出格式。
3138    pub fn format(mut self, format: impl Into<ResponseTextFormat>) -> Self {
3139        self.format = Some(format.into());
3140        self
3141    }
3142
3143    /// EN: Sets the text output verbosity.
3144    /// 中文:设置文本输出详细程度。
3145    pub fn verbosity(mut self, verbosity: ResponseTextVerbosity) -> Self {
3146        self.verbosity = Some(verbosity);
3147        self
3148    }
3149}
3150
3151/// EN: Text output format configuration.
3152/// 中文:文本输出格式配置。
3153#[derive(Clone, Debug, Serialize, PartialEq)]
3154#[serde(tag = "type")]
3155#[non_exhaustive]
3156pub enum ResponseTextFormat {
3157    /// EN: Plain text output.
3158    /// 中文:纯文本输出。
3159    #[serde(rename = "text")]
3160    Text,
3161    /// EN: JSON object output.
3162    /// 中文:JSON 对象输出。
3163    #[serde(rename = "json_object")]
3164    JsonObject,
3165    /// EN: JSON Schema structured output.
3166    /// 中文:JSON Schema 结构化输出。
3167    #[serde(rename = "json_schema")]
3168    JsonSchema {
3169        /// EN: Response format name.
3170        /// 中文:响应格式名称。
3171        name: String,
3172        /// EN: JSON schema the model output should match.
3173        /// 中文:模型输出应匹配的 JSON schema。
3174        schema: Value,
3175        /// EN: Optional schema description.
3176        /// 中文:可选的 schema 描述。
3177        #[serde(skip_serializing_if = "Option::is_none")]
3178        description: Option<String>,
3179        /// EN: Whether to enable strict schema adherence.
3180        /// 中文:是否启用严格 schema 遵循。
3181        #[serde(skip_serializing_if = "Option::is_none")]
3182        strict: Option<bool>,
3183    },
3184}
3185
3186impl ResponseTextFormat {
3187    /// EN: Starts a JSON Schema text format configuration.
3188    /// 中文:开始构建 JSON Schema 文本格式配置。
3189    pub fn json_schema(name: impl Into<String>, schema: Value) -> ResponseTextJsonSchemaFormat {
3190        ResponseTextJsonSchemaFormat::new(name, schema)
3191    }
3192}
3193
3194/// EN: Builder value for JSON Schema structured text output.
3195/// 中文:JSON Schema 结构化文本输出的构建值。
3196#[derive(Clone, Debug, PartialEq)]
3197#[non_exhaustive]
3198pub struct ResponseTextJsonSchemaFormat {
3199    /// EN: Response format name.
3200    /// 中文:响应格式名称。
3201    pub name: String,
3202    /// EN: JSON schema the model output should match.
3203    /// 中文:模型输出应匹配的 JSON schema。
3204    pub schema: Value,
3205    /// EN: Optional schema description.
3206    /// 中文:可选的 schema 描述。
3207    pub description: Option<String>,
3208    /// EN: Whether to enable strict schema adherence.
3209    /// 中文:是否启用严格 schema 遵循。
3210    pub strict: Option<bool>,
3211}
3212
3213impl ResponseTextJsonSchemaFormat {
3214    /// EN: Creates a JSON Schema text format configuration.
3215    /// 中文:创建 JSON Schema 文本格式配置。
3216    pub fn new(name: impl Into<String>, schema: Value) -> Self {
3217        Self {
3218            name: name.into(),
3219            schema,
3220            description: None,
3221            strict: None,
3222        }
3223    }
3224
3225    /// EN: Sets the schema description.
3226    /// 中文:设置 schema 描述。
3227    pub fn description(mut self, description: impl Into<String>) -> Self {
3228        self.description = Some(description.into());
3229        self
3230    }
3231
3232    /// EN: Sets strict schema adherence.
3233    /// 中文:设置严格 schema 遵循。
3234    pub fn strict(mut self, strict: bool) -> Self {
3235        self.strict = Some(strict);
3236        self
3237    }
3238}
3239
3240impl From<ResponseTextJsonSchemaFormat> for ResponseTextFormat {
3241    fn from(format: ResponseTextJsonSchemaFormat) -> Self {
3242        Self::JsonSchema {
3243            name: format.name,
3244            schema: format.schema,
3245            description: format.description,
3246            strict: format.strict,
3247        }
3248    }
3249}
3250
3251/// EN: Text output verbosity.
3252/// 中文:文本输出详细程度。
3253#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
3254#[serde(rename_all = "snake_case")]
3255#[non_exhaustive]
3256pub enum ResponseTextVerbosity {
3257    /// EN: Low verbosity.
3258    /// 中文:低详细程度。
3259    Low,
3260    /// EN: Medium verbosity.
3261    /// 中文:中等详细程度。
3262    Medium,
3263    /// EN: High verbosity.
3264    /// 中文:高详细程度。
3265    High,
3266}
3267
3268/// EN: Options for streaming Responses API requests.
3269/// 中文:Responses API 流式请求的选项。
3270#[derive(Clone, Debug, Default, Serialize, PartialEq, Eq)]
3271#[non_exhaustive]
3272pub struct StreamOptions {
3273    /// EN: Whether to include obfuscation padding fields in streaming delta events.
3274    /// 中文:是否在流式增量事件中包含混淆填充字段。
3275    #[serde(skip_serializing_if = "Option::is_none")]
3276    pub include_obfuscation: Option<bool>,
3277}
3278
3279impl StreamOptions {
3280    /// EN: Starts building stream options.
3281    /// 中文:开始构建流选项。
3282    pub fn builder() -> StreamOptionsBuilder {
3283        StreamOptionsBuilder::default()
3284    }
3285}
3286
3287/// EN: Builder for Responses API stream options.
3288/// 中文:Responses API 流选项的构建器。
3289#[derive(Clone, Debug, Default)]
3290#[non_exhaustive]
3291pub struct StreamOptionsBuilder {
3292    include_obfuscation: Option<bool>,
3293}
3294
3295impl StreamOptionsBuilder {
3296    /// EN: Sets whether streaming delta events include obfuscation padding fields.
3297    /// 中文:设置流式增量事件是否包含混淆填充字段。
3298    pub fn include_obfuscation(mut self, include_obfuscation: bool) -> Self {
3299        self.include_obfuscation = Some(include_obfuscation);
3300        self
3301    }
3302
3303    /// EN: Builds the stream options.
3304    /// 中文:构建流选项。
3305    pub fn build(self) -> StreamOptions {
3306        StreamOptions {
3307            include_obfuscation: self.include_obfuscation,
3308        }
3309    }
3310}
3311
3312/// EN: Response object returned by the Responses API.
3313/// 中文:Responses API 返回的响应对象。
3314#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
3315#[non_exhaustive]
3316pub struct Response {
3317    /// EN: Response id.
3318    /// 中文:响应 ID。
3319    pub id: String,
3320    /// EN: API object type.
3321    /// 中文:API 对象类型。
3322    pub object: String,
3323    /// EN: Model that produced the response.
3324    /// 中文:生成响应的模型。
3325    pub model: String,
3326    /// EN: Output items returned by the model.
3327    /// 中文:模型返回的输出项。
3328    #[serde(default)]
3329    pub output: Vec<ResponseOutput>,
3330    /// EN: OpenAI request id from response headers.
3331    /// 中文:响应头中的 OpenAI 请求 ID。
3332    #[serde(skip)]
3333    request_id: Option<RequestId>,
3334}
3335
3336impl Response {
3337    pub(crate) fn with_request_id(mut self, request_id: Option<RequestId>) -> Self {
3338        self.request_id = request_id;
3339        self
3340    }
3341
3342    /// EN: Returns the OpenAI request id, when present.
3343    /// 中文:返回 OpenAI 请求 ID,如存在。
3344    pub fn request_id(&self) -> Option<&RequestId> {
3345        self.request_id.as_ref()
3346    }
3347
3348    /// EN: Concatenates text from `output_text` content items.
3349    /// 中文:拼接 `output_text` 内容项中的文本。
3350    pub fn output_text(&self) -> String {
3351        let mut text = String::new();
3352        for item in &self.output {
3353            if let ResponseOutput::Message(message) = item {
3354                for content in &message.content {
3355                    if let ResponseContent::OutputText { text: value, .. } = content {
3356                        text.push_str(value);
3357                    }
3358                }
3359            }
3360        }
3361        text
3362    }
3363}
3364
3365/// EN: Input-token count returned by `POST /v1/responses/input_tokens`.
3366/// 中文:`POST /v1/responses/input_tokens` 返回的输入 token 计数。
3367#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
3368#[non_exhaustive]
3369pub struct ResponseInputTokens {
3370    /// EN: API object type, normally `response.input_tokens`.
3371    /// 中文:API 对象类型,通常为 `response.input_tokens`。
3372    pub object: String,
3373    /// EN: Count of input tokens.
3374    /// 中文:输入 token 数量。
3375    pub input_tokens: u64,
3376    /// EN: OpenAI request id from response headers.
3377    /// 中文:响应头中的 OpenAI 请求 ID。
3378    #[serde(skip)]
3379    request_id: Option<RequestId>,
3380}
3381
3382impl ResponseInputTokens {
3383    pub(crate) fn with_request_id(mut self, request_id: Option<RequestId>) -> Self {
3384        self.request_id = request_id;
3385        self
3386    }
3387
3388    /// EN: Returns the OpenAI request id, when present.
3389    /// 中文:返回 OpenAI 请求 ID,如存在。
3390    pub fn request_id(&self) -> Option<&RequestId> {
3391        self.request_id.as_ref()
3392    }
3393}
3394
3395/// EN: Compacted response object returned by `POST /v1/responses/compact`.
3396/// 中文:`POST /v1/responses/compact` 返回的压缩响应对象。
3397#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
3398#[non_exhaustive]
3399pub struct ResponseCompaction {
3400    /// EN: Compacted response id.
3401    /// 中文:压缩响应 ID。
3402    pub id: String,
3403    /// EN: API object type, normally `response.compaction`.
3404    /// 中文:API 对象类型,通常为 `response.compaction`。
3405    pub object: String,
3406    /// EN: Unix timestamp when the compacted response was created.
3407    /// 中文:压缩响应创建时的 Unix 时间戳。
3408    pub created_at: u64,
3409    /// EN: Compacted output items preserved as JSON for forward compatibility.
3410    /// 中文:以 JSON 形式保留的压缩输出项,用于前向兼容。
3411    #[serde(default)]
3412    pub output: Vec<Value>,
3413    /// EN: Token usage for the compaction pass.
3414    /// 中文:压缩过程的 token 用量。
3415    pub usage: ResponseUsage,
3416    /// EN: Additional fields preserved for forward compatibility.
3417    /// 中文:为前向兼容保留的额外字段。
3418    #[serde(flatten)]
3419    pub extra: BTreeMap<String, Value>,
3420    /// EN: OpenAI request id from response headers.
3421    /// 中文:响应头中的 OpenAI 请求 ID。
3422    #[serde(skip)]
3423    request_id: Option<RequestId>,
3424}
3425
3426impl ResponseCompaction {
3427    pub(crate) fn with_request_id(mut self, request_id: Option<RequestId>) -> Self {
3428        self.request_id = request_id;
3429        self
3430    }
3431
3432    /// EN: Returns the OpenAI request id, when present.
3433    /// 中文:返回 OpenAI 请求 ID,如存在。
3434    pub fn request_id(&self) -> Option<&RequestId> {
3435        self.request_id.as_ref()
3436    }
3437}
3438
3439/// EN: Token usage returned by Responses endpoints.
3440/// 中文:Responses 端点返回的 token 用量。
3441#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
3442#[non_exhaustive]
3443pub struct ResponseUsage {
3444    /// EN: Input token count.
3445    /// 中文:输入 token 数量。
3446    pub input_tokens: u64,
3447    /// EN: Output token count.
3448    /// 中文:输出 token 数量。
3449    pub output_tokens: u64,
3450    /// EN: Total token count.
3451    /// 中文:总 token 数量。
3452    pub total_tokens: u64,
3453    /// EN: Input token detail fields preserved for forward compatibility.
3454    /// 中文:为前向兼容保留的输入 token 详情字段。
3455    #[serde(default)]
3456    pub input_tokens_details: BTreeMap<String, Value>,
3457    /// EN: Output token detail fields preserved for forward compatibility.
3458    /// 中文:为前向兼容保留的输出 token 详情字段。
3459    #[serde(default)]
3460    pub output_tokens_details: BTreeMap<String, Value>,
3461    /// EN: Additional usage fields preserved for forward compatibility.
3462    /// 中文:为前向兼容保留的额外用量字段。
3463    #[serde(flatten)]
3464    pub extra: BTreeMap<String, Value>,
3465}
3466
3467/// EN: Deletion result returned by the Responses API.
3468/// 中文:Responses API 返回的删除结果。
3469#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
3470#[non_exhaustive]
3471pub struct ResponseDeletion {
3472    /// EN: Deleted response id.
3473    /// 中文:已删除的响应 ID。
3474    pub id: String,
3475    /// EN: API object type.
3476    /// 中文:API 对象类型。
3477    pub object: String,
3478    /// EN: Whether the response was deleted.
3479    /// 中文:响应是否已删除。
3480    pub deleted: bool,
3481    /// EN: OpenAI request id from response headers.
3482    /// 中文:响应头中的 OpenAI 请求 ID。
3483    #[serde(skip)]
3484    request_id: Option<RequestId>,
3485}
3486
3487impl ResponseDeletion {
3488    pub(crate) fn with_request_id(mut self, request_id: Option<RequestId>) -> Self {
3489        self.request_id = request_id;
3490        self
3491    }
3492
3493    /// EN: Returns the OpenAI request id, when present.
3494    /// 中文:返回 OpenAI 请求 ID,如存在。
3495    pub fn request_id(&self) -> Option<&RequestId> {
3496        self.request_id.as_ref()
3497    }
3498}
3499
3500/// EN: Paginated input items returned by the Responses API.
3501/// 中文:Responses API 返回的分页输入项。
3502#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
3503#[non_exhaustive]
3504pub struct ResponseInputItemsPage {
3505    /// EN: API list object type.
3506    /// 中文:API 列表对象类型。
3507    pub object: String,
3508    /// EN: Input items on this page.
3509    /// 中文:本页输入项。
3510    #[serde(default)]
3511    pub data: Vec<ResponseInputItem>,
3512    /// EN: First item id on this page.
3513    /// 中文:本页第一个项目 ID。
3514    #[serde(default)]
3515    pub first_id: Option<String>,
3516    /// EN: Last item id on this page.
3517    /// 中文:本页最后一个项目 ID。
3518    #[serde(default)]
3519    pub last_id: Option<String>,
3520    /// EN: Whether more items are available.
3521    /// 中文:是否还有更多项目。
3522    pub has_more: bool,
3523    /// EN: OpenAI request id from response headers.
3524    /// 中文:响应头中的 OpenAI 请求 ID。
3525    #[serde(skip)]
3526    request_id: Option<RequestId>,
3527}
3528
3529impl ResponseInputItemsPage {
3530    pub(crate) fn with_request_id(mut self, request_id: Option<RequestId>) -> Self {
3531        self.request_id = request_id;
3532        self
3533    }
3534
3535    /// EN: Returns the OpenAI request id, when present.
3536    /// 中文:返回 OpenAI 请求 ID,如存在。
3537    pub fn request_id(&self) -> Option<&RequestId> {
3538        self.request_id.as_ref()
3539    }
3540}
3541
3542/// EN: Response input item.
3543/// 中文:响应输入项。
3544#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
3545#[serde(tag = "type")]
3546#[non_exhaustive]
3547pub enum ResponseInputItem {
3548    /// EN: Message input item.
3549    /// 中文:消息输入项。
3550    #[serde(rename = "message")]
3551    Message(ResponseInputItemMessage),
3552    /// EN: Forward-compatible unknown input item.
3553    /// 中文:前向兼容的未知输入项。
3554    #[serde(other)]
3555    Unknown,
3556}
3557
3558/// EN: Message input item returned by the Responses API.
3559/// 中文:Responses API 返回的消息输入项。
3560#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
3561#[non_exhaustive]
3562pub struct ResponseInputItemMessage {
3563    /// EN: Input item id.
3564    /// 中文:输入项 ID。
3565    pub id: String,
3566    /// EN: Message role.
3567    /// 中文:消息角色。
3568    pub role: String,
3569    /// EN: Message content.
3570    /// 中文:消息内容。
3571    #[serde(default)]
3572    pub content: Vec<ResponseInputItemContent>,
3573}
3574
3575impl ResponseInputItemMessage {
3576    /// EN: Concatenates `input_text` content.
3577    /// 中文:拼接 `input_text` 内容。
3578    pub fn input_text(&self) -> String {
3579        let mut text = String::new();
3580        for content in &self.content {
3581            if let ResponseInputItemContent::InputText { text: value, .. } = content {
3582                text.push_str(value);
3583            }
3584        }
3585        text
3586    }
3587}
3588
3589/// EN: Input item message content.
3590/// 中文:输入项消息内容。
3591#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
3592#[serde(tag = "type")]
3593#[non_exhaustive]
3594pub enum ResponseInputItemContent {
3595    /// EN: Input text content.
3596    /// 中文:输入文本内容。
3597    #[serde(rename = "input_text")]
3598    InputText {
3599        /// EN: Text content.
3600        /// 中文:文本内容。
3601        text: String,
3602        /// EN: Additional fields preserved for forward compatibility.
3603        /// 中文:为前向兼容保留的额外字段。
3604        #[serde(flatten)]
3605        extra: BTreeMap<String, Value>,
3606    },
3607    /// EN: Forward-compatible unknown content item.
3608    /// 中文:前向兼容的未知内容项。
3609    #[serde(other)]
3610    Unknown,
3611}
3612
3613/// EN: Response output item.
3614/// 中文:响应输出项。
3615#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
3616#[serde(tag = "type")]
3617#[non_exhaustive]
3618pub enum ResponseOutput {
3619    /// EN: Assistant message output.
3620    /// 中文:助手消息输出。
3621    #[serde(rename = "message")]
3622    Message(ResponseOutputMessage),
3623    /// EN: Forward-compatible unknown output item.
3624    /// 中文:前向兼容的未知输出项。
3625    #[serde(other)]
3626    Unknown,
3627}
3628
3629/// EN: Assistant message output item.
3630/// 中文:助手消息输出项。
3631#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
3632#[non_exhaustive]
3633pub struct ResponseOutputMessage {
3634    /// EN: Output item id.
3635    /// 中文:输出项 ID。
3636    pub id: String,
3637    /// EN: Message role.
3638    /// 中文:消息角色。
3639    pub role: String,
3640    /// EN: Message content.
3641    /// 中文:消息内容。
3642    #[serde(default)]
3643    pub content: Vec<ResponseContent>,
3644}
3645
3646/// EN: Response message content.
3647/// 中文:响应消息内容。
3648#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
3649#[serde(tag = "type")]
3650#[non_exhaustive]
3651pub enum ResponseContent {
3652    /// EN: Output text content.
3653    /// 中文:输出文本内容。
3654    #[serde(rename = "output_text")]
3655    OutputText {
3656        /// EN: Text content.
3657        /// 中文:文本内容。
3658        text: String,
3659        /// EN: Additional fields preserved for forward compatibility.
3660        /// 中文:为前向兼容保留的额外字段。
3661        #[serde(flatten)]
3662        extra: BTreeMap<String, Value>,
3663    },
3664    /// EN: Forward-compatible unknown content item.
3665    /// 中文:前向兼容的未知内容项。
3666    #[serde(other)]
3667    Unknown,
3668}
3669
3670/// EN: Typed Responses streaming event.
3671/// 中文:类型化的 Responses 流式事件。
3672#[derive(Clone, Debug, PartialEq)]
3673#[non_exhaustive]
3674pub enum ResponseStreamEvent {
3675    /// EN: Incremental output text delta.
3676    /// 中文:增量输出文本片段。
3677    OutputTextDelta {
3678        /// EN: Delta text.
3679        /// 中文:文本增量。
3680        delta: String,
3681    },
3682    /// EN: Completed response event.
3683    /// 中文:响应完成事件。
3684    Completed {
3685        /// EN: Completed response.
3686        /// 中文:已完成的响应。
3687        response: Response,
3688    },
3689    /// EN: Forward-compatible unknown event.
3690    /// 中文:前向兼容的未知事件。
3691    Unknown {
3692        /// EN: Event type.
3693        /// 中文:事件类型。
3694        event_type: String,
3695        /// EN: Raw JSON data.
3696        /// 中文:原始 JSON 数据。
3697        data: Value,
3698    },
3699}
3700
3701/// EN: Streaming item with typed and raw event access.
3702/// 中文:同时提供类型化和原始事件访问的流式项。
3703#[derive(Clone, Debug, PartialEq)]
3704#[non_exhaustive]
3705pub struct ResponseStreamItem {
3706    /// EN: Typed event.
3707    /// 中文:类型化事件。
3708    pub event: ResponseStreamEvent,
3709    /// EN: Raw SSE frame.
3710    /// 中文:原始 SSE 帧。
3711    pub raw: SseEvent,
3712}
3713
3714impl ResponseStreamItem {
3715    /// EN: Returns the event type.
3716    /// 中文:返回事件类型。
3717    pub fn event_type(&self) -> &str {
3718        self.raw.event_type.as_deref().unwrap_or("")
3719    }
3720
3721    /// EN: Returns output text delta when this is a delta event.
3722    /// 中文:当事件为文本增量时返回输出文本增量。
3723    pub fn output_text_delta(&self) -> Option<&str> {
3724        match &self.event {
3725            ResponseStreamEvent::OutputTextDelta { delta } => Some(delta),
3726            _ => None,
3727        }
3728    }
3729}
3730
3731/// EN: Incremental Responses stream.
3732/// 中文:增量 Responses 流。
3733pub struct ResponseStream {
3734    inner: SseStream,
3735}
3736
3737impl ResponseStream {
3738    /// EN: Creates a response stream from an HTTP body stream.
3739    /// 中文:通过 HTTP 响应体流创建响应流。
3740    pub fn new(body: BodyStream) -> Self {
3741        Self {
3742            inner: SseStream::new(body),
3743        }
3744    }
3745}
3746
3747impl Stream for ResponseStream {
3748    type Item = Result<ResponseStreamItem, LingerError>;
3749
3750    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
3751        let this = self.get_mut();
3752        match Pin::new(&mut this.inner).poll_next(cx) {
3753            Poll::Ready(Some(Ok(raw))) => Poll::Ready(Some(parse_response_event(raw))),
3754            Poll::Ready(Some(Err(error))) => Poll::Ready(Some(Err(error))),
3755            Poll::Ready(None) => Poll::Ready(None),
3756            Poll::Pending => Poll::Pending,
3757        }
3758    }
3759}
3760
3761fn parse_response_event(raw: SseEvent) -> Result<ResponseStreamItem, LingerError> {
3762    let event_type = raw.event_type.clone().unwrap_or_default();
3763    let value: Value = serde_json::from_str(&raw.data).map_err(|error| {
3764        LingerError::streaming(format!("invalid response stream JSON: {error}"))
3765    })?;
3766    let event = match event_type.as_str() {
3767        "response.output_text.delta" => {
3768            let delta = value
3769                .get("delta")
3770                .and_then(Value::as_str)
3771                .unwrap_or_default()
3772                .to_string();
3773            ResponseStreamEvent::OutputTextDelta { delta }
3774        }
3775        "response.completed" => {
3776            let response = value.get("response").cloned().ok_or_else(|| {
3777                LingerError::streaming("response.completed event is missing response")
3778            })?;
3779            let response = serde_json::from_value(response).map_err(|error| {
3780                LingerError::streaming(format!("invalid completed response: {error}"))
3781            })?;
3782            ResponseStreamEvent::Completed { response }
3783        }
3784        _ => ResponseStreamEvent::Unknown {
3785            event_type,
3786            data: value,
3787        },
3788    };
3789    Ok(ResponseStreamItem { event, raw })
3790}
3791
3792fn validate_optional_string(name: &str, value: Option<&str>) -> Result<(), LingerError> {
3793    if value.is_some_and(|value| value.trim().is_empty()) {
3794        return Err(LingerError::invalid_config(format!(
3795            "{name} must not be empty"
3796        )));
3797    }
3798    Ok(())
3799}
3800
3801fn validate_metadata(metadata: &BTreeMap<String, String>) -> Result<(), LingerError> {
3802    if metadata.len() > 16 {
3803        return Err(LingerError::invalid_config(
3804            "metadata must contain at most 16 entries",
3805        ));
3806    }
3807    for (key, value) in metadata {
3808        if key.trim().is_empty() {
3809            return Err(LingerError::invalid_config(
3810                "metadata keys must not be empty",
3811            ));
3812        }
3813        if key.chars().count() > 64 {
3814            return Err(LingerError::invalid_config(
3815                "metadata keys must be at most 64 characters",
3816            ));
3817        }
3818        if value.chars().count() > 512 {
3819            return Err(LingerError::invalid_config(
3820                "metadata values must be at most 512 characters",
3821            ));
3822        }
3823    }
3824    Ok(())
3825}
3826
3827fn validate_json_items(name: &str, values: &[Value]) -> Result<(), LingerError> {
3828    if values.iter().any(Value::is_null) {
3829        return Err(LingerError::invalid_config(format!(
3830            "{name} must not contain null"
3831        )));
3832    }
3833    Ok(())
3834}
3835
3836fn validate_tools(tools: &[Value]) -> Result<(), LingerError> {
3837    validate_json_items("tools", tools)?;
3838    for tool in tools {
3839        let Some(object) = tool.as_object() else {
3840            continue;
3841        };
3842        match object.get("type").and_then(Value::as_str) {
3843            Some("function") => validate_function_tool(object)?,
3844            Some("custom") => validate_custom_tool(object)?,
3845            Some("namespace") => validate_namespace_tool(object)?,
3846            Some("tool_search") => validate_tool_search_tool(object)?,
3847            Some("shell") => validate_shell_tool(object)?,
3848            Some("file_search") => validate_file_search_tool(object)?,
3849            Some("computer_use_preview") => validate_computer_use_preview_tool(object)?,
3850            Some("code_interpreter") => validate_code_interpreter_tool(object)?,
3851            Some("image_generation") => validate_image_generation_tool(object)?,
3852            Some("mcp") => validate_mcp_tool(object)?,
3853            Some(
3854                "web_search"
3855                | "web_search_2025_08_26"
3856                | "web_search_preview"
3857                | "web_search_preview_2025_03_11",
3858            ) => validate_web_search_tool(object)?,
3859            _ => {}
3860        }
3861    }
3862    Ok(())
3863}
3864
3865fn validate_custom_tool(object: &serde_json::Map<String, Value>) -> Result<(), LingerError> {
3866    let name = object
3867        .get("name")
3868        .and_then(Value::as_str)
3869        .unwrap_or_default();
3870    validate_optional_string("custom tool name", Some(name))?;
3871    validate_optional_string(
3872        "custom tool description",
3873        object.get("description").and_then(Value::as_str),
3874    )?;
3875    if let Some(description) = object.get("description") {
3876        if !description.is_string() {
3877            return Err(LingerError::invalid_config(
3878                "custom tool description must be a string",
3879            ));
3880        }
3881    }
3882    if let Some(defer_loading) = object.get("defer_loading") {
3883        if !defer_loading.is_boolean() {
3884            return Err(LingerError::invalid_config(
3885                "custom tool defer_loading must be a boolean",
3886            ));
3887        }
3888    }
3889    if let Some(format) = object.get("format") {
3890        validate_custom_tool_format(format)?;
3891    }
3892    Ok(())
3893}
3894
3895fn validate_custom_tool_format(format: &Value) -> Result<(), LingerError> {
3896    let Some(format) = format.as_object() else {
3897        return Err(LingerError::invalid_config(
3898            "custom tool format must be a JSON object",
3899        ));
3900    };
3901    match format.get("type").and_then(Value::as_str) {
3902        Some("text") => Ok(()),
3903        Some("grammar") => {
3904            let syntax = format
3905                .get("syntax")
3906                .and_then(Value::as_str)
3907                .ok_or_else(|| {
3908                    LingerError::invalid_config("custom tool grammar format must include syntax")
3909                })?;
3910            if !matches!(syntax, "lark" | "regex") {
3911                return Err(LingerError::invalid_config(
3912                    "custom tool grammar syntax has an unsupported value",
3913                ));
3914            }
3915            let definition = format
3916                .get("definition")
3917                .and_then(Value::as_str)
3918                .unwrap_or_default();
3919            validate_optional_string("custom tool grammar definition", Some(definition))
3920        }
3921        _ => Err(LingerError::invalid_config(
3922            "custom tool format type has an unsupported value",
3923        )),
3924    }
3925}
3926
3927fn validate_tool_search_tool(object: &serde_json::Map<String, Value>) -> Result<(), LingerError> {
3928    if let Some(execution) = object.get("execution") {
3929        let Some(execution) = execution.as_str() else {
3930            return Err(LingerError::invalid_config(
3931                "tool_search execution must be a string",
3932            ));
3933        };
3934        if !matches!(execution, "server" | "client") {
3935            return Err(LingerError::invalid_config(
3936                "tool_search execution has an unsupported value",
3937            ));
3938        }
3939    }
3940    if let Some(description) = object.get("description") {
3941        if !(description.is_string() || description.is_null()) {
3942            return Err(LingerError::invalid_config(
3943                "tool_search description must be a string or null",
3944            ));
3945        }
3946        if let Some(description) = description.as_str() {
3947            validate_optional_string("tool_search description", Some(description))?;
3948        }
3949    }
3950    if let Some(parameters) = object.get("parameters") {
3951        if !(parameters.is_object() || parameters.is_null()) {
3952            return Err(LingerError::invalid_config(
3953                "tool_search parameters must be a JSON object or null",
3954            ));
3955        }
3956    }
3957    Ok(())
3958}
3959
3960fn validate_shell_tool(object: &serde_json::Map<String, Value>) -> Result<(), LingerError> {
3961    let Some(environment) = object.get("environment") else {
3962        return Ok(());
3963    };
3964    if environment.is_null() {
3965        return Ok(());
3966    }
3967    let Some(environment) = environment.as_object() else {
3968        return Err(LingerError::invalid_config(
3969            "shell environment must be a JSON object or null",
3970        ));
3971    };
3972    match environment.get("type").and_then(Value::as_str) {
3973        Some("local" | "container_auto") => Ok(()),
3974        Some("container_reference") => {
3975            let container_id = environment
3976                .get("container_id")
3977                .and_then(Value::as_str)
3978                .unwrap_or_default();
3979            validate_optional_string("shell container_id", Some(container_id))
3980        }
3981        _ => Err(LingerError::invalid_config(
3982            "shell environment type has an unsupported value",
3983        )),
3984    }
3985}
3986
3987fn validate_namespace_tool(object: &serde_json::Map<String, Value>) -> Result<(), LingerError> {
3988    let name = object
3989        .get("name")
3990        .and_then(Value::as_str)
3991        .unwrap_or_default();
3992    validate_optional_string("namespace tool name", Some(name))?;
3993    let description = object
3994        .get("description")
3995        .and_then(Value::as_str)
3996        .unwrap_or_default();
3997    validate_optional_string("namespace tool description", Some(description))?;
3998    let tools = object
3999        .get("tools")
4000        .and_then(Value::as_array)
4001        .ok_or_else(|| LingerError::invalid_config("namespace tools must include tools"))?;
4002    if tools.is_empty() {
4003        return Err(LingerError::invalid_config(
4004            "namespace tools must not be empty",
4005        ));
4006    }
4007    for tool in tools {
4008        let Some(tool) = tool.as_object() else {
4009            return Err(LingerError::invalid_config(
4010                "namespace tools must contain objects",
4011            ));
4012        };
4013        match tool.get("type").and_then(Value::as_str) {
4014            Some("function") => validate_namespace_function_tool(tool)?,
4015            Some("custom") => validate_custom_tool(tool)?,
4016            _ => {
4017                return Err(LingerError::invalid_config(
4018                    "namespace tools may only contain function or custom tools",
4019                ));
4020            }
4021        }
4022    }
4023    Ok(())
4024}
4025
4026fn validate_namespace_function_tool(
4027    object: &serde_json::Map<String, Value>,
4028) -> Result<(), LingerError> {
4029    let name = object
4030        .get("name")
4031        .and_then(Value::as_str)
4032        .unwrap_or_default();
4033    validate_optional_string("namespace function tool name", Some(name))?;
4034    if let Some(description) = object.get("description") {
4035        if !(description.is_string() || description.is_null()) {
4036            return Err(LingerError::invalid_config(
4037                "namespace function tool description must be a string or null",
4038            ));
4039        }
4040    }
4041    if let Some(parameters) = object.get("parameters") {
4042        if !(parameters.is_object() || parameters.is_null()) {
4043            return Err(LingerError::invalid_config(
4044                "namespace function tool parameters must be a JSON object or null",
4045            ));
4046        }
4047    }
4048    if let Some(strict) = object.get("strict") {
4049        if !(strict.is_boolean() || strict.is_null()) {
4050            return Err(LingerError::invalid_config(
4051                "namespace function tool strict must be a boolean or null",
4052            ));
4053        }
4054    }
4055    if let Some(defer_loading) = object.get("defer_loading") {
4056        if !defer_loading.is_boolean() {
4057            return Err(LingerError::invalid_config(
4058                "namespace function tool defer_loading must be a boolean",
4059            ));
4060        }
4061    }
4062    Ok(())
4063}
4064
4065fn validate_computer_use_preview_tool(
4066    object: &serde_json::Map<String, Value>,
4067) -> Result<(), LingerError> {
4068    let environment = object
4069        .get("environment")
4070        .and_then(Value::as_str)
4071        .ok_or_else(|| {
4072            LingerError::invalid_config("computer_use_preview tools must include environment")
4073        })?;
4074    if !matches!(
4075        environment,
4076        "windows" | "mac" | "linux" | "ubuntu" | "browser"
4077    ) {
4078        return Err(LingerError::invalid_config(
4079            "computer_use_preview environment has an unsupported value",
4080        ));
4081    }
4082
4083    for field in ["display_width", "display_height"] {
4084        let value = object.get(field).and_then(Value::as_u64).ok_or_else(|| {
4085            LingerError::invalid_config(format!(
4086                "computer_use_preview tools must include integer {field}"
4087            ))
4088        })?;
4089        if value == 0 {
4090            return Err(LingerError::invalid_config(format!(
4091                "computer_use_preview {field} must be greater than 0"
4092            )));
4093        }
4094    }
4095    Ok(())
4096}
4097
4098fn validate_function_tool(object: &serde_json::Map<String, Value>) -> Result<(), LingerError> {
4099    let name = object
4100        .get("name")
4101        .and_then(Value::as_str)
4102        .unwrap_or_default();
4103    validate_optional_string("tools[].name", Some(name))?;
4104    let parameters = object
4105        .get("parameters")
4106        .ok_or_else(|| LingerError::invalid_config("function tools must include parameters"))?;
4107    if parameters.is_null() {
4108        return Err(LingerError::invalid_config(
4109            "function tool parameters must not be null",
4110        ));
4111    }
4112    if !parameters.is_object() {
4113        return Err(LingerError::invalid_config(
4114            "function tool parameters must be a JSON object",
4115        ));
4116    }
4117    if !object.get("strict").is_some_and(Value::is_boolean) {
4118        return Err(LingerError::invalid_config(
4119            "function tools must include boolean strict",
4120        ));
4121    }
4122    Ok(())
4123}
4124
4125fn validate_file_search_tool(object: &serde_json::Map<String, Value>) -> Result<(), LingerError> {
4126    let vector_store_ids = object
4127        .get("vector_store_ids")
4128        .and_then(Value::as_array)
4129        .ok_or_else(|| {
4130            LingerError::invalid_config("file_search tools must include vector_store_ids")
4131        })?;
4132    if vector_store_ids.is_empty() {
4133        return Err(LingerError::invalid_config(
4134            "file_search vector_store_ids must not be empty",
4135        ));
4136    }
4137    for vector_store_id in vector_store_ids {
4138        let Some(vector_store_id) = vector_store_id.as_str() else {
4139            return Err(LingerError::invalid_config(
4140                "file_search vector_store_ids must contain strings",
4141            ));
4142        };
4143        validate_optional_string("file_search vector_store_ids", Some(vector_store_id))?;
4144    }
4145    if let Some(max_num_results) = object.get("max_num_results") {
4146        let max_num_results = max_num_results.as_u64().ok_or_else(|| {
4147            LingerError::invalid_config("file_search max_num_results must be an integer")
4148        })?;
4149        if !(1..=50).contains(&max_num_results) {
4150            return Err(LingerError::invalid_config(
4151                "file_search max_num_results must be between 1 and 50",
4152            ));
4153        }
4154    }
4155    for field in ["ranking_options", "filters"] {
4156        if object.get(field).is_some_and(Value::is_null) {
4157            return Err(LingerError::invalid_config(format!(
4158                "file_search {field} must not be null"
4159            )));
4160        }
4161    }
4162    Ok(())
4163}
4164
4165fn validate_code_interpreter_tool(
4166    object: &serde_json::Map<String, Value>,
4167) -> Result<(), LingerError> {
4168    let container = object.get("container").ok_or_else(|| {
4169        LingerError::invalid_config("code_interpreter tools must include container")
4170    })?;
4171    if container.is_null() {
4172        return Err(LingerError::invalid_config(
4173            "code_interpreter container must not be null",
4174        ));
4175    }
4176    if let Some(container_id) = container.as_str() {
4177        validate_optional_string("code_interpreter container", Some(container_id))?;
4178        return Ok(());
4179    }
4180    let container = container.as_object().ok_or_else(|| {
4181        LingerError::invalid_config("code_interpreter container must be a string or object")
4182    })?;
4183    let container_type = container
4184        .get("type")
4185        .and_then(Value::as_str)
4186        .unwrap_or_default();
4187    if container_type != "auto" {
4188        return Err(LingerError::invalid_config(
4189            "code_interpreter auto container type must be auto",
4190        ));
4191    }
4192    if let Some(file_ids) = container.get("file_ids") {
4193        let file_ids = file_ids.as_array().ok_or_else(|| {
4194            LingerError::invalid_config("code_interpreter file_ids must be an array")
4195        })?;
4196        if file_ids.len() > 50 {
4197            return Err(LingerError::invalid_config(
4198                "code_interpreter file_ids must contain at most 50 entries",
4199            ));
4200        }
4201        for file_id in file_ids {
4202            let Some(file_id) = file_id.as_str() else {
4203                return Err(LingerError::invalid_config(
4204                    "code_interpreter file_ids must contain strings",
4205                ));
4206            };
4207            validate_optional_string("code_interpreter file_ids", Some(file_id))?;
4208        }
4209    }
4210    if let Some(memory_limit) = container.get("memory_limit") {
4211        if !memory_limit.is_null() {
4212            let Some(memory_limit) = memory_limit.as_str() else {
4213                return Err(LingerError::invalid_config(
4214                    "code_interpreter memory_limit must be a string",
4215                ));
4216            };
4217            if !matches!(memory_limit, "1g" | "4g" | "16g" | "64g") {
4218                return Err(LingerError::invalid_config(
4219                    "code_interpreter memory_limit must be one of 1g, 4g, 16g, or 64g",
4220                ));
4221            }
4222        }
4223    }
4224    if let Some(network_policy) = container.get("network_policy") {
4225        validate_code_interpreter_network_policy(network_policy)?;
4226    }
4227    Ok(())
4228}
4229
4230fn validate_code_interpreter_network_policy(network_policy: &Value) -> Result<(), LingerError> {
4231    if network_policy.is_null() {
4232        return Err(LingerError::invalid_config(
4233            "code_interpreter network_policy must not be null",
4234        ));
4235    }
4236    let policy = network_policy.as_object().ok_or_else(|| {
4237        LingerError::invalid_config("code_interpreter network_policy must be a JSON object")
4238    })?;
4239    match policy.get("type").and_then(Value::as_str) {
4240        Some("disabled") => Ok(()),
4241        Some("allowlist") => {
4242            if let Some(domains) = policy.get("allowed_domains") {
4243                let domains = domains.as_array().ok_or_else(|| {
4244                    LingerError::invalid_config("code_interpreter allowed_domains must be an array")
4245                })?;
4246                if domains.is_empty() {
4247                    return Err(LingerError::invalid_config(
4248                        "code_interpreter allowed_domains must not be empty",
4249                    ));
4250                }
4251                for domain in domains {
4252                    let Some(domain) = domain.as_str() else {
4253                        return Err(LingerError::invalid_config(
4254                            "code_interpreter allowed_domains must contain strings",
4255                        ));
4256                    };
4257                    validate_optional_string("code_interpreter allowed_domains", Some(domain))?;
4258                }
4259            }
4260            Ok(())
4261        }
4262        _ => Err(LingerError::invalid_config(
4263            "code_interpreter network_policy type must be disabled or allowlist",
4264        )),
4265    }
4266}
4267
4268fn validate_image_generation_tool(
4269    object: &serde_json::Map<String, Value>,
4270) -> Result<(), LingerError> {
4271    for field in ["model", "size"] {
4272        if let Some(value) = object.get(field) {
4273            let Some(value) = value.as_str() else {
4274                return Err(LingerError::invalid_config(format!(
4275                    "image_generation {field} must be a string"
4276                )));
4277            };
4278            validate_optional_string(&format!("image_generation {field}"), Some(value))?;
4279        }
4280    }
4281    validate_image_generation_enum(object, "quality", &["low", "medium", "high", "auto"])?;
4282    validate_image_generation_enum(object, "output_format", &["png", "webp", "jpeg"])?;
4283    validate_image_generation_enum(object, "moderation", &["auto", "low"])?;
4284    validate_image_generation_enum(object, "background", &["transparent", "opaque", "auto"])?;
4285    validate_image_generation_enum(object, "input_fidelity", &["high", "low"])?;
4286    validate_image_generation_enum(object, "action", &["generate", "edit", "auto"])?;
4287    if let Some(output_compression) = object.get("output_compression") {
4288        let output_compression = output_compression.as_u64().ok_or_else(|| {
4289            LingerError::invalid_config("image_generation output_compression must be an integer")
4290        })?;
4291        if output_compression > 100 {
4292            return Err(LingerError::invalid_config(
4293                "image_generation output_compression must be between 0 and 100",
4294            ));
4295        }
4296    }
4297    if let Some(partial_images) = object.get("partial_images") {
4298        let partial_images = partial_images.as_u64().ok_or_else(|| {
4299            LingerError::invalid_config("image_generation partial_images must be an integer")
4300        })?;
4301        if partial_images > 3 {
4302            return Err(LingerError::invalid_config(
4303                "image_generation partial_images must be between 0 and 3",
4304            ));
4305        }
4306    }
4307    if let Some(input_image_mask) = object.get("input_image_mask") {
4308        validate_image_generation_mask(input_image_mask)?;
4309    }
4310    Ok(())
4311}
4312
4313fn validate_image_generation_enum(
4314    object: &serde_json::Map<String, Value>,
4315    field: &str,
4316    allowed: &[&str],
4317) -> Result<(), LingerError> {
4318    if let Some(value) = object.get(field) {
4319        let Some(value) = value.as_str() else {
4320            return Err(LingerError::invalid_config(format!(
4321                "image_generation {field} must be a string"
4322            )));
4323        };
4324        validate_optional_string(&format!("image_generation {field}"), Some(value))?;
4325        if !allowed.contains(&value) {
4326            return Err(LingerError::invalid_config(format!(
4327                "image_generation {field} has an unsupported value"
4328            )));
4329        }
4330    }
4331    Ok(())
4332}
4333
4334fn validate_image_generation_mask(input_image_mask: &Value) -> Result<(), LingerError> {
4335    if input_image_mask.is_null() {
4336        return Err(LingerError::invalid_config(
4337            "image_generation input_image_mask must not be null",
4338        ));
4339    }
4340    let mask = input_image_mask.as_object().ok_or_else(|| {
4341        LingerError::invalid_config("image_generation input_image_mask must be a JSON object")
4342    })?;
4343    let image_url = mask.get("image_url").and_then(Value::as_str);
4344    let file_id = mask.get("file_id").and_then(Value::as_str);
4345    match (image_url, file_id) {
4346        (Some(image_url), None) => validate_optional_string(
4347            "image_generation input_image_mask.image_url",
4348            Some(image_url),
4349        ),
4350        (None, Some(file_id)) => {
4351            validate_optional_string("image_generation input_image_mask.file_id", Some(file_id))
4352        }
4353        (None, None) => Err(LingerError::invalid_config(
4354            "image_generation input_image_mask must include image_url or file_id",
4355        )),
4356        (Some(_), Some(_)) => Err(LingerError::invalid_config(
4357            "image_generation input_image_mask must not include both image_url and file_id",
4358        )),
4359    }
4360}
4361
4362fn validate_mcp_tool(object: &serde_json::Map<String, Value>) -> Result<(), LingerError> {
4363    let server_label = object
4364        .get("server_label")
4365        .and_then(Value::as_str)
4366        .unwrap_or_default();
4367    validate_optional_string("mcp server_label", Some(server_label))?;
4368
4369    let server_url = validate_mcp_optional_string(object, "server_url")?;
4370    let connector_id = validate_mcp_optional_string(object, "connector_id")?;
4371    match (server_url, connector_id) {
4372        (Some(_), Some(_)) => {
4373            return Err(LingerError::invalid_config(
4374                "mcp tools must include only one of server_url or connector_id",
4375            ));
4376        }
4377        (None, None) => {
4378            return Err(LingerError::invalid_config(
4379                "mcp tools must include server_url or connector_id",
4380            ));
4381        }
4382        (Some(_), None) => {}
4383        (None, Some(connector_id)) => validate_mcp_connector_id(connector_id)?,
4384    }
4385
4386    validate_mcp_optional_string(object, "authorization")?;
4387    validate_mcp_optional_string(object, "server_description")?;
4388
4389    if let Some(headers) = object.get("headers") {
4390        validate_mcp_headers(headers)?;
4391    }
4392    if let Some(allowed_tools) = object.get("allowed_tools") {
4393        validate_mcp_allowed_tools(allowed_tools)?;
4394    }
4395    if let Some(require_approval) = object.get("require_approval") {
4396        validate_mcp_require_approval(require_approval)?;
4397    }
4398    if let Some(defer_loading) = object.get("defer_loading") {
4399        if !defer_loading.is_boolean() {
4400            return Err(LingerError::invalid_config(
4401                "mcp defer_loading must be a boolean",
4402            ));
4403        }
4404    }
4405
4406    Ok(())
4407}
4408
4409fn validate_mcp_optional_string<'a>(
4410    object: &'a serde_json::Map<String, Value>,
4411    field: &str,
4412) -> Result<Option<&'a str>, LingerError> {
4413    let Some(value) = object.get(field) else {
4414        return Ok(None);
4415    };
4416    let Some(value) = value.as_str() else {
4417        return Err(LingerError::invalid_config(format!(
4418            "mcp {field} must be a string"
4419        )));
4420    };
4421    validate_optional_string(&format!("mcp {field}"), Some(value))?;
4422    Ok(Some(value))
4423}
4424
4425fn validate_mcp_connector_id(connector_id: &str) -> Result<(), LingerError> {
4426    if matches!(
4427        connector_id,
4428        "connector_dropbox"
4429            | "connector_gmail"
4430            | "connector_googlecalendar"
4431            | "connector_googledrive"
4432            | "connector_microsoftteams"
4433            | "connector_outlookcalendar"
4434            | "connector_outlookemail"
4435            | "connector_sharepoint"
4436    ) {
4437        Ok(())
4438    } else {
4439        Err(LingerError::invalid_config(
4440            "mcp connector_id has an unsupported value",
4441        ))
4442    }
4443}
4444
4445fn validate_mcp_headers(headers: &Value) -> Result<(), LingerError> {
4446    if headers.is_null() {
4447        return Err(LingerError::invalid_config("mcp headers must not be null"));
4448    }
4449    let headers = headers
4450        .as_object()
4451        .ok_or_else(|| LingerError::invalid_config("mcp headers must be a JSON object"))?;
4452    for (name, value) in headers {
4453        if name.trim().is_empty() {
4454            return Err(LingerError::invalid_config(
4455                "mcp header names must not be empty",
4456            ));
4457        }
4458        if !value.is_string() {
4459            return Err(LingerError::invalid_config(
4460                "mcp header values must be strings",
4461            ));
4462        }
4463    }
4464    Ok(())
4465}
4466
4467fn validate_mcp_allowed_tools(allowed_tools: &Value) -> Result<(), LingerError> {
4468    if allowed_tools.is_null() {
4469        return Err(LingerError::invalid_config(
4470            "mcp allowed_tools must not be null",
4471        ));
4472    }
4473    if let Some(tool_names) = allowed_tools.as_array() {
4474        return validate_mcp_tool_names("mcp allowed_tools", tool_names);
4475    }
4476    validate_mcp_tool_filter("mcp allowed_tools", allowed_tools)
4477}
4478
4479fn validate_mcp_require_approval(require_approval: &Value) -> Result<(), LingerError> {
4480    if require_approval.is_null() {
4481        return Err(LingerError::invalid_config(
4482            "mcp require_approval must not be null",
4483        ));
4484    }
4485    if let Some(mode) = require_approval.as_str() {
4486        if matches!(mode, "always" | "never") {
4487            return Ok(());
4488        }
4489        return Err(LingerError::invalid_config(
4490            "mcp require_approval must be always, never, or a filter object",
4491        ));
4492    }
4493    let approval = require_approval.as_object().ok_or_else(|| {
4494        LingerError::invalid_config("mcp require_approval must be a string or object")
4495    })?;
4496    for field in ["always", "never"] {
4497        if let Some(filter) = approval.get(field) {
4498            validate_mcp_tool_filter(&format!("mcp require_approval.{field}"), filter)?;
4499        }
4500    }
4501    for field in approval.keys() {
4502        if !matches!(field.as_str(), "always" | "never") {
4503            return Err(LingerError::invalid_config(
4504                "mcp require_approval only supports always and never filters",
4505            ));
4506        }
4507    }
4508    Ok(())
4509}
4510
4511fn validate_mcp_tool_filter(name: &str, filter: &Value) -> Result<(), LingerError> {
4512    if filter.is_null() {
4513        return Err(LingerError::invalid_config(format!(
4514            "{name} must not be null"
4515        )));
4516    }
4517    let filter = filter
4518        .as_object()
4519        .ok_or_else(|| LingerError::invalid_config(format!("{name} must be a JSON object")))?;
4520    if let Some(tool_names) = filter.get("tool_names") {
4521        let tool_names = tool_names.as_array().ok_or_else(|| {
4522            LingerError::invalid_config(format!("{name}.tool_names must be an array"))
4523        })?;
4524        validate_mcp_tool_names(&format!("{name}.tool_names"), tool_names)?;
4525    }
4526    if let Some(read_only) = filter.get("read_only") {
4527        if !read_only.is_boolean() {
4528            return Err(LingerError::invalid_config(format!(
4529                "{name}.read_only must be a boolean"
4530            )));
4531        }
4532    }
4533    for field in filter.keys() {
4534        if !matches!(field.as_str(), "tool_names" | "read_only") {
4535            return Err(LingerError::invalid_config(format!(
4536                "{name} only supports tool_names and read_only"
4537            )));
4538        }
4539    }
4540    Ok(())
4541}
4542
4543fn validate_mcp_tool_names(name: &str, tool_names: &[Value]) -> Result<(), LingerError> {
4544    for tool_name in tool_names {
4545        let Some(tool_name) = tool_name.as_str() else {
4546            return Err(LingerError::invalid_config(format!(
4547                "{name} must contain strings"
4548            )));
4549        };
4550        validate_optional_string(name, Some(tool_name))?;
4551    }
4552    Ok(())
4553}
4554
4555fn validate_web_search_tool(object: &serde_json::Map<String, Value>) -> Result<(), LingerError> {
4556    for field in ["filters", "user_location"] {
4557        if let Some(value) = object.get(field) {
4558            if value.is_null() {
4559                return Err(LingerError::invalid_config(format!(
4560                    "web_search {field} must not be null"
4561                )));
4562            }
4563            if !value.is_object() {
4564                return Err(LingerError::invalid_config(format!(
4565                    "web_search {field} must be a JSON object"
4566                )));
4567            }
4568        }
4569    }
4570    if let Some(content_types) = object.get("search_content_types") {
4571        let content_types = content_types.as_array().ok_or_else(|| {
4572            LingerError::invalid_config("web_search search_content_types must be an array")
4573        })?;
4574        for content_type in content_types {
4575            let Some(content_type) = content_type.as_str() else {
4576                return Err(LingerError::invalid_config(
4577                    "web_search search_content_types must contain strings",
4578                ));
4579            };
4580            validate_optional_string("web_search search_content_types", Some(content_type))?;
4581        }
4582    }
4583    Ok(())
4584}
4585
4586fn validate_tool_choice(tool_choice: &ResponseToolChoice) -> Result<(), LingerError> {
4587    if let ResponseToolChoice::AllowedTools { tools, .. } = tool_choice {
4588        validate_json_items("tool_choice.tools", tools)?;
4589    }
4590    Ok(())
4591}
4592
4593fn validate_prompt(prompt: &ResponsePrompt) -> Result<(), LingerError> {
4594    validate_optional_string("prompt.id", Some(&prompt.id))?;
4595    validate_optional_string("prompt.version", prompt.version.as_deref())?;
4596    for (name, value) in &prompt.variables {
4597        if name.trim().is_empty() {
4598            return Err(LingerError::invalid_config(
4599                "prompt variable names must not be empty",
4600            ));
4601        }
4602        if value.is_null() {
4603            return Err(LingerError::invalid_config(
4604                "prompt variable values must not be null",
4605            ));
4606        }
4607    }
4608    Ok(())
4609}
4610
4611fn validate_text_config(text: &ResponseTextConfig) -> Result<(), LingerError> {
4612    if let Some(ResponseTextFormat::JsonSchema { name, schema, .. }) = &text.format {
4613        validate_optional_string("text.format.name", Some(name))?;
4614        if name.chars().count() > 64 {
4615            return Err(LingerError::invalid_config(
4616                "text.format.name must be at most 64 characters",
4617            ));
4618        }
4619        if !name
4620            .chars()
4621            .all(|ch| ch.is_ascii_alphanumeric() || ch == '_' || ch == '-')
4622        {
4623            return Err(LingerError::invalid_config(
4624                "text.format.name must contain only ASCII letters, digits, underscores, or dashes",
4625            ));
4626        }
4627        if schema.is_null() {
4628            return Err(LingerError::invalid_config(
4629                "text.format.schema must not be null",
4630            ));
4631        }
4632    }
4633    Ok(())
4634}
4635
4636fn validate_context_management(
4637    context_management: &[ResponseContextManagement],
4638) -> Result<(), LingerError> {
4639    if context_management.is_empty() {
4640        return Err(LingerError::invalid_config(
4641            "context_management must contain at least one entry",
4642        ));
4643    }
4644    if context_management.iter().any(|entry| {
4645        entry
4646            .compact_threshold
4647            .is_some_and(|compact_threshold| compact_threshold < 1000)
4648    }) {
4649        return Err(LingerError::invalid_config(
4650            "context_management compact_threshold must be at least 1000",
4651        ));
4652    }
4653    Ok(())
4654}
4655
4656fn validate_moderation(moderation: &ResponseModeration) -> Result<(), LingerError> {
4657    if moderation.model.trim().is_empty() {
4658        return Err(LingerError::invalid_config(
4659            "moderation model must not be empty",
4660        ));
4661    }
4662    Ok(())
4663}
4664
4665fn validate_extra_fields(extra: &BTreeMap<String, Value>) -> Result<(), LingerError> {
4666    for (key, value) in extra {
4667        if key.trim().is_empty() {
4668            return Err(LingerError::invalid_config(
4669                "extra field names must not be empty",
4670            ));
4671        }
4672        if value.is_null() {
4673            return Err(LingerError::invalid_config(format!(
4674                "extra field {key} must not be null"
4675            )));
4676        }
4677    }
4678    Ok(())
4679}