openai_tools/responses/
request.rs

1use crate::{
2    common::{
3        errors::{OpenAIToolError, Result},
4        message::Message,
5        structured_output::Schema,
6        tool::Tool,
7    },
8    responses::response::Response,
9};
10use derive_new::new;
11use dotenvy::dotenv;
12use request;
13use serde::{ser::SerializeStruct, Serialize};
14use std::collections::HashMap;
15use std::env;
16use strum::{Display, EnumString};
17
18/// Specifies additional data to include in the response output
19///
20/// This enum defines various types of additional information that can be
21/// included in the API response output, such as web search results, code
22/// interpreter outputs, image URLs, and other metadata.
23///
24/// # API Reference
25///
26/// Corresponds to the `include` parameter in the OpenAI Responses API:
27/// <https://platform.openai.com/docs/api-reference/responses/create>
28#[derive(Debug, Clone, EnumString, Display, Serialize, PartialEq)]
29#[serde(rename_all = "snake_case")]
30pub enum Include {
31    /// Include web search call results in the output  
32    ///
33    /// When included, the response will contain information about web search
34    /// results that were used during the response generation process.
35    #[strum(serialize = "web_search_call.results")]
36    #[serde(rename = "web_search_call.results")]
37    WebSearchCall,
38
39    /// Include code interpreter call outputs in the output
40    ///
41    /// When included, the response will contain outputs from any code
42    /// that was executed during the response generation process.
43    #[strum(serialize = "code_interpreter_call.outputs")]
44    #[serde(rename = "code_interpreter_call.outputs")]
45    CodeInterpreterCall,
46
47    /// Include computer call output image URLs in the output
48    ///
49    /// When included, the response will contain image URLs from any
50    /// computer interaction calls that were made.
51    #[strum(serialize = "computer_call_output.output.image_url")]
52    #[serde(rename = "computer_call_output.output.image_url")]
53    ImageUrlInComputerCallOutput,
54
55    /// Include file search call results in the output
56    ///
57    /// When included, the response will contain results from any
58    /// file search operations that were performed.
59    #[strum(serialize = "file_search_call.results")]
60    #[serde(rename = "file_search_call.results")]
61    FileSearchCall,
62
63    /// Include image URLs from input messages in the output
64    ///
65    /// When included, the response will contain image URLs that were
66    /// present in the input messages.
67    #[strum(serialize = "message.input_image.image_url")]
68    #[serde(rename = "message.input_image.image_url")]
69    ImageUrlInInputMessages,
70
71    /// Include log probabilities in the output
72    ///
73    /// When included, the response will contain log probability information
74    /// for the generated text tokens.
75    #[strum(serialize = "message.output_text.logprobs")]
76    #[serde(rename = "message.output_text.logprobs")]
77    LogprobsInOutput,
78
79    /// Include reasoning encrypted content in the output
80    ///
81    /// When included, the response will contain encrypted reasoning
82    /// content that shows the model's internal reasoning process.
83    #[strum(serialize = "reasoning.encrypted_content")]
84    #[serde(rename = "reasoning.encrypted_content")]
85    ReasoningEncryptedContent,
86}
87
88/// Defines the level of reasoning effort the model should apply
89///
90/// This enum controls how much computational effort the model invests
91/// in reasoning through complex problems before generating a response.
92///
93/// # API Reference
94///
95/// Corresponds to the `reasoning.effort` parameter in the OpenAI Responses API.
96#[derive(Debug, Clone, Serialize, EnumString, Display, PartialEq)]
97#[serde(rename_all = "snake_case")]
98pub enum ReasoningEffort {
99    /// Minimal reasoning effort - fastest response time
100    ///
101    /// Use this for simple queries that don't require deep analysis.
102    #[strum(serialize = "minimal")]
103    #[serde(rename = "minimal")]
104    Minimal,
105
106    /// Low reasoning effort - balanced performance
107    ///
108    /// Use this for moderately complex queries that benefit from some reasoning.
109    #[strum(serialize = "low")]
110    #[serde(rename = "low")]
111    Low,
112
113    /// Medium reasoning effort - comprehensive analysis
114    ///
115    /// Use this for complex queries that require thorough consideration.
116    #[strum(serialize = "medium")]
117    #[serde(rename = "medium")]
118    Medium,
119
120    /// High reasoning effort - maximum thoughtfulness
121    ///
122    /// Use this for very complex queries requiring deep, careful analysis.
123    #[strum(serialize = "high")]
124    #[serde(rename = "high")]
125    High,
126}
127
128/// Defines the format of reasoning summary to include in the response
129///
130/// This enum controls how the model's reasoning process is summarized
131/// and presented in the response output.
132///
133/// # API Reference
134///
135/// Corresponds to the `reasoning.summary` parameter in the OpenAI Responses API.
136#[derive(Debug, Clone, Serialize, EnumString, Display, PartialEq)]
137#[serde(rename_all = "snake_case")]
138pub enum ReasoningSummary {
139    /// Automatically determine the appropriate summary format
140    ///
141    /// The model will choose the most suitable summary format based on the query.
142    #[strum(serialize = "auto")]
143    #[serde(rename = "auto")]
144    Auto,
145
146    /// Provide a concise summary of the reasoning process
147    ///
148    /// Use this for shorter, more focused reasoning explanations.
149    #[strum(serialize = "concise")]
150    #[serde(rename = "concise")]
151    Concise,
152
153    /// Provide a detailed summary of the reasoning process
154    ///
155    /// Use this for comprehensive reasoning explanations with full detail.
156    #[strum(serialize = "detailed")]
157    #[serde(rename = "detailed")]
158    Detailed,
159}
160
161/// Configuration for reasoning behavior in responses
162///
163/// This struct allows you to control how the model approaches reasoning
164/// for complex queries, including the effort level and summary format.
165///
166/// # API Reference
167///
168/// Corresponds to the `reasoning` parameter in the OpenAI Responses API.
169#[derive(Debug, Clone, Serialize)]
170pub struct Reasoning {
171    /// The level of reasoning effort to apply
172    pub effort: Option<ReasoningEffort>,
173    /// The format for the reasoning summary
174    pub summary: Option<ReasoningSummary>,
175}
176
177/// Defines how the model should choose and use tools
178///
179/// This enum controls the model's behavior regarding tool usage during
180/// response generation.
181///
182/// # API Reference
183///
184/// Corresponds to the `tool_choice` parameter in the OpenAI Responses API.
185#[derive(Debug, Clone, Serialize, EnumString, Display, PartialEq)]
186#[serde(rename_all = "snake_case")]
187pub enum ToolChoiceMode {
188    /// Disable tool usage completely
189    ///
190    /// The model will not use any tools and will generate responses
191    /// based solely on its training data.
192    #[strum(serialize = "none")]
193    #[serde(rename = "none")]
194    None,
195
196    /// Automatically decide when to use tools
197    ///
198    /// The model will automatically determine when tools are needed
199    /// and which tools to use based on the query context.
200    #[strum(serialize = "auto")]
201    #[serde(rename = "auto")]
202    Auto,
203
204    /// Require the use of tools
205    ///
206    /// The model must use at least one of the provided tools in its response.
207    #[strum(serialize = "required")]
208    #[serde(rename = "required")]
209    Required,
210}
211
212/// Controls truncation behavior for long inputs
213///
214/// This enum defines how the system should handle inputs that exceed
215/// the maximum context length.
216///
217/// # API Reference
218///
219/// Corresponds to the `truncation` parameter in the OpenAI Responses API.
220#[derive(Debug, Clone, Serialize, EnumString, Display, PartialEq)]
221#[serde(rename_all = "snake_case")]
222pub enum Truncation {
223    /// Automatically truncate inputs to fit context length
224    ///
225    /// The system will automatically trim inputs to ensure they fit
226    /// within the model's context window.
227    #[strum(serialize = "auto")]
228    #[serde(rename = "auto")]
229    Auto,
230
231    /// Disable truncation - return error if input is too long
232    ///
233    /// The system will return an error rather than truncating
234    /// inputs that exceed the context length.
235    #[strum(serialize = "disabled")]
236    #[serde(rename = "disabled")]
237    Disabled,
238}
239
240/// Options for streaming responses
241///
242/// This struct configures how streaming responses should behave,
243/// including whether to include obfuscated content.
244///
245/// # API Reference
246///
247/// Corresponds to the `stream_options` parameter in the OpenAI Responses API.
248#[derive(Debug, Clone, Serialize)]
249pub struct StreamOptions {
250    /// Whether to include obfuscated content in streaming responses
251    ///
252    /// When enabled, streaming responses may include placeholder or
253    /// obfuscated content that gets replaced as the real content is generated.
254    pub include_obfuscation: bool,
255}
256/// Represents the format configuration for structured output in responses
257///
258/// This struct is used to specify the schema format for structured text output
259/// when making requests to the OpenAI Responses API.
260#[derive(Debug, Clone, Default, Serialize, new)]
261pub struct Format {
262    /// The schema definition that specifies the structure of the expected output
263    pub format: Schema,
264}
265
266/// Represents the body of a request to the OpenAI Responses API
267///
268/// This struct contains all the parameters for making requests to the OpenAI Responses API.
269/// It supports both plain text and structured message input, along with extensive configuration
270/// options for tools, reasoning, output formatting, and response behavior.
271///
272/// # Required Parameters
273///
274/// - `model`: The ID of the model to use
275/// - Either `plain_text_input` OR `messages_input` (mutually exclusive)
276///
277/// # API Reference
278///
279/// Based on the OpenAI Responses API specification:
280/// <https://platform.openai.com/docs/api-reference/responses/create>
281///
282/// # Examples
283///
284/// ## Simple Text Input
285///
286/// ```rust
287/// use openai_tools::responses::request::Body;
288///
289/// let body = Body {
290///     model: "gpt-4".to_string(),
291///     plain_text_input: Some("What is the weather like?".to_string()),
292///     ..Default::default()
293/// };
294/// ```
295///
296/// ## With Messages and Tools
297///
298/// ```rust
299/// use openai_tools::responses::request::Body;
300/// use openai_tools::common::message::Message;
301/// use openai_tools::common::role::Role;
302///
303/// let messages = vec![
304///     Message::from_string(Role::User, "Help me with coding")
305/// ];
306///
307/// let body = Body {
308///     model: "gpt-4".to_string(),
309///     messages_input: Some(messages),
310///     instructions: Some("You are a helpful coding assistant".to_string()),
311///     max_output_tokens: Some(1000),
312///     ..Default::default()
313/// };
314/// ```
315#[derive(Debug, Clone, Default, new)]
316pub struct Body {
317    /// The ID of the model to use for generating responses
318    ///
319    /// Specifies which OpenAI model to use for response generation.
320    /// Common values include "gpt-4", "gpt-4-turbo", "gpt-3.5-turbo".
321    ///
322    /// # Required
323    ///
324    /// This field is required for all requests.
325    ///
326    /// # Examples
327    ///
328    /// - `"gpt-4"` - Latest GPT-4 model
329    /// - `"gpt-4-turbo"` - GPT-4 Turbo for faster responses
330    /// - `"gpt-3.5-turbo"` - More cost-effective option
331    pub model: String,
332
333    /// Optional instructions to guide the model's behavior and response style
334    ///
335    /// Provides system-level instructions that define how the model should
336    /// behave, its personality, response format, or any other behavioral guidance.
337    ///
338    /// # Examples
339    ///
340    /// - `"You are a helpful assistant that provides concise answers"`
341    /// - `"Respond only with JSON formatted data"`
342    /// - `"Act as a professional code reviewer"`
343    pub instructions: Option<String>,
344
345    /// Plain text input for simple text-based requests
346    ///
347    /// Use this for straightforward text input when you don't need the structure
348    /// of messages with roles. This is mutually exclusive with `messages_input`.
349    ///
350    /// # Mutually Exclusive
351    ///
352    /// Cannot be used together with `messages_input`. Choose one based on your needs:
353    /// - Use `plain_text_input` for simple, single-turn interactions
354    /// - Use `messages_input` for conversation history or role-based interactions
355    ///
356    /// # Examples
357    ///
358    /// - `"What is the capital of France?"`
359    /// - `"Summarize this article: [article content]"`
360    /// - `"Write a haiku about programming"`
361    pub plain_text_input: Option<String>,
362
363    /// Structured message input for conversation-style interactions
364    ///
365    /// Use this when you need conversation history, different message roles
366    /// (user, assistant, system), or structured dialogue. This is mutually
367    /// exclusive with `plain_text_input`.
368    ///
369    /// # Mutually Exclusive
370    ///
371    /// Cannot be used together with `plain_text_input`.
372    ///
373    /// # Message Roles
374    ///
375    /// - `System`: Instructions for the model's behavior
376    /// - `User`: User input or questions
377    /// - `Assistant`: Previous model responses (for conversation history)
378    ///
379    /// # Examples
380    ///
381    /// ```rust
382    /// use openai_tools::common::message::Message;
383    /// use openai_tools::common::role::Role;
384    ///
385    /// let messages = vec![
386    ///     Message::from_string(Role::System, "You are a helpful assistant"),
387    ///     Message::from_string(Role::User, "Hello!"),
388    ///     Message::from_string(Role::Assistant, "Hi there! How can I help you?"),
389    ///     Message::from_string(Role::User, "What's 2+2?"),
390    /// ];
391    /// ```
392    pub messages_input: Option<Vec<Message>>,
393
394    /// Optional tools that the model can use during response generation
395    ///
396    /// Provides the model with access to external tools like web search,
397    /// code execution, file access, or custom functions. The model will
398    /// automatically decide when and how to use these tools based on the query.
399    ///
400    /// # Tool Types
401    ///
402    /// - Web search tools for finding current information
403    /// - Code interpreter for running and analyzing code
404    /// - File search tools for accessing document collections
405    /// - Custom function tools for specific business logic
406    ///
407    /// # Examples
408    ///
409    /// ```rust
410    /// use openai_tools::common::tool::Tool;
411    /// use openai_tools::common::parameters::ParameterProperty;
412    ///
413    /// let tools = vec![
414    ///     Tool::function("search", "Search the web", Vec::<(&str, ParameterProperty)>::new(), false),
415    ///     Tool::function("calculate", "Perform calculations", Vec::<(&str, ParameterProperty)>::new(), false),
416    /// ];
417    /// ```
418    pub tools: Option<Vec<Tool>>,
419    /// Optional tool choice configuration
420    // TODO: Implement ToolChoice
421    // pub tool_choice: Option<ToolChoice>,
422
423    /// Optional structured output format specification
424    ///
425    /// Defines the structure and format for the model's response output.
426    /// Use this when you need the response in a specific JSON schema format
427    /// or other structured format for programmatic processing.
428    ///
429    /// # Examples
430    ///
431    /// ```rust
432    /// use openai_tools::common::structured_output::Schema;
433    /// use openai_tools::responses::request::Format;
434    ///
435    /// let format = Format::new(Schema::responses_json_schema("response_schema"));
436    /// ```
437    pub structured_output: Option<Format>,
438
439    /// Optional sampling temperature for controlling response randomness
440    ///
441    /// Controls the randomness and creativity of the model's responses.
442    /// Higher values make the output more random and creative, while lower
443    /// values make it more focused, deterministic, and consistent.
444    ///
445    /// # Range
446    ///
447    /// - **Range**: 0.0 to 2.0
448    /// - **Default**: 1.0 (if not specified)
449    /// - **Minimum**: 0.0 (most deterministic, least creative)
450    /// - **Maximum**: 2.0 (most random, most creative)
451    ///
452    /// # Recommended Values
453    ///
454    /// - **0.0 - 0.3**: Highly focused and deterministic
455    ///   - Best for: Factual questions, code generation, translations
456    ///   - Behavior: Very consistent, predictable responses
457    ///
458    /// - **0.3 - 0.7**: Balanced creativity and consistency
459    ///   - Best for: General conversation, explanations, analysis
460    ///   - Behavior: Good balance between creativity and reliability
461    ///
462    /// - **0.7 - 1.2**: More creative and varied responses
463    ///   - Best for: Creative writing, brainstorming, ideation
464    ///   - Behavior: More diverse and interesting outputs
465    ///
466    /// - **1.2 - 2.0**: Highly creative and unpredictable
467    ///   - Best for: Experimental creative tasks, humor, unconventional ideas
468    ///   - Behavior: Very diverse but potentially less coherent
469    ///
470    /// # Usage Guidelines
471    ///
472    /// - **Start with 0.7** for most applications as a good default
473    /// - **Use 0.0-0.3** when you need consistent, reliable responses
474    /// - **Use 0.8-1.2** for creative tasks that still need coherence
475    /// - **Avoid values above 1.5** unless you specifically want very random outputs
476    ///
477    /// # API Reference
478    ///
479    /// Corresponds to the `temperature` parameter in the OpenAI Responses API:
480    /// <https://platform.openai.com/docs/api-reference/responses/create>
481    ///
482    /// # Examples
483    ///
484    /// ```rust
485    /// use openai_tools::responses::request::Responses;
486    ///
487    /// // Deterministic, factual responses
488    /// let mut client_factual = Responses::new();
489    /// client_factual.temperature(0.2);
490    ///
491    /// // Balanced creativity and consistency
492    /// let mut client_balanced = Responses::new();
493    /// client_balanced.temperature(0.7);
494    ///
495    /// // High creativity for brainstorming
496    /// let mut client_creative = Responses::new();
497    /// client_creative.temperature(1.1);
498    /// ```
499    pub temperature: Option<f64>,
500
501    /// Optional maximum number of tokens to generate in the response
502    ///
503    /// Controls the maximum length of the generated response. The actual response
504    /// may be shorter if the model naturally concludes or hits other stopping conditions.
505    ///
506    /// # Range
507    ///
508    /// - Minimum: 1
509    /// - Maximum: Depends on the model (typically 4096-8192 for most models)
510    ///
511    /// # Default Behavior
512    ///
513    /// If not specified, the model will use its default maximum output length.
514    ///
515    /// # Examples
516    ///
517    /// - `Some(100)` - Short responses, good for summaries or brief answers
518    /// - `Some(1000)` - Medium responses, suitable for detailed explanations
519    /// - `Some(4000)` - Long responses, for comprehensive analysis or long-form content
520    pub max_output_tokens: Option<usize>,
521
522    /// Optional maximum number of tool calls to make
523    ///
524    /// Limits how many tools the model can invoke during response generation.
525    /// This helps control cost and response time when using multiple tools.
526    ///
527    /// # Range
528    ///
529    /// - Minimum: 0 (no tool calls allowed)
530    /// - Maximum: Implementation-dependent
531    ///
532    /// # Use Cases
533    ///
534    /// - Set to `Some(1)` for single tool usage
535    /// - Set to `Some(0)` to disable tool usage entirely
536    /// - Leave as `None` for unlimited tool usage (subject to other constraints)
537    pub max_tool_calls: Option<usize>,
538
539    /// Optional metadata to include with the request
540    ///
541    /// Arbitrary key-value pairs that can be attached to the request for
542    /// tracking, logging, or passing additional context that doesn't affect
543    /// the model's behavior.
544    ///
545    /// # Common Use Cases
546    ///
547    /// - Request tracking: `{"request_id": "req_123", "user_id": "user_456"}`
548    /// - A/B testing: `{"experiment": "variant_a", "test_group": "control"}`
549    /// - Analytics: `{"session_id": "sess_789", "feature": "chat"}`
550    ///
551    /// # Examples
552    ///
553    /// ```rust
554    /// use std::collections::HashMap;
555    /// use serde_json::Value;
556    ///
557    /// let mut metadata = HashMap::new();
558    /// metadata.insert("user_id".to_string(), Value::String("user123".to_string()));
559    /// metadata.insert("session_id".to_string(), Value::String("sess456".to_string()));
560    /// metadata.insert("priority".to_string(), Value::Number(serde_json::Number::from(1)));
561    /// ```
562    pub metadata: Option<HashMap<String, serde_json::Value>>,
563
564    /// Optional flag to enable parallel tool calls
565    ///
566    /// When enabled, the model can make multiple tool calls simultaneously
567    /// rather than sequentially. This can significantly improve response time
568    /// when multiple independent tools need to be used.
569    ///
570    /// # Default
571    ///
572    /// If not specified, defaults to the model's default behavior (usually `true`).
573    ///
574    /// # When to Use
575    ///
576    /// - `Some(true)`: Enable when tools are independent and can run in parallel
577    /// - `Some(false)`: Disable when tools have dependencies or order matters
578    ///
579    /// # Examples
580    ///
581    /// - Weather + Stock prices: Can run in parallel (`true`)
582    /// - File read + File analysis: Should run sequentially (`false`)
583    pub parallel_tool_calls: Option<bool>,
584
585    /// Optional fields to include in the output
586    ///
587    /// Specifies additional metadata and information to include in the response
588    /// beyond the main generated content. This can include tool call details,
589    /// reasoning traces, log probabilities, and more.
590    ///
591    /// # Available Inclusions
592    ///
593    /// - Web search call sources and results
594    /// - Code interpreter execution outputs
595    /// - Image URLs from various sources
596    /// - Log probabilities for generated tokens
597    /// - Reasoning traces and encrypted content
598    ///
599    /// # Examples
600    ///
601    /// ```rust
602    /// use openai_tools::responses::request::Include;
603    ///
604    /// let includes = vec![
605    ///     Include::WebSearchCall,
606    ///     Include::LogprobsInOutput,
607    ///     Include::ReasoningEncryptedContent,
608    /// ];
609    /// ```
610    pub include: Option<Vec<Include>>,
611
612    /// Optional flag to enable background processing
613    ///
614    /// When enabled, allows the request to be processed in the background,
615    /// potentially improving throughput for non-urgent requests.
616    ///
617    /// # Use Cases
618    ///
619    /// - `Some(true)`: Batch processing, non-interactive requests
620    /// - `Some(false)` or `None`: Real-time, interactive requests
621    ///
622    /// # Trade-offs
623    ///
624    /// - Background processing may have lower latency guarantees
625    /// - May be more cost-effective for bulk operations
626    /// - May have different rate limiting behavior
627    pub background: Option<bool>,
628
629    /// Optional conversation ID for tracking
630    ///
631    /// Identifier for grouping related requests as part of the same conversation
632    /// or session. This helps with context management and analytics.
633    ///
634    /// # Format
635    ///
636    /// Typically a UUID or other unique identifier string.
637    ///
638    /// # Examples
639    ///
640    /// - `Some("conv_123e4567-e89b-12d3-a456-426614174000".to_string())`
641    /// - `Some("user123_session456".to_string())`
642    pub conversation: Option<String>,
643
644    /// Optional ID of the previous response for context
645    ///
646    /// References a previous response in the same conversation to maintain
647    /// context and enable features like response chaining or follow-up handling.
648    ///
649    /// # Use Cases
650    ///
651    /// - Multi-turn conversations with context preservation
652    /// - Follow-up questions or clarifications
653    /// - Response refinement or iteration
654    ///
655    /// # Examples
656    ///
657    /// - `Some("resp_abc123def456".to_string())`
658    pub previous_response_id: Option<String>,
659
660    /// Optional reasoning configuration
661    ///
662    /// Controls how the model approaches complex reasoning tasks, including
663    /// the effort level and format of reasoning explanations.
664    ///
665    /// # Use Cases
666    ///
667    /// - Complex problem-solving requiring deep analysis
668    /// - Mathematical or logical reasoning tasks
669    /// - When you need insight into the model's reasoning process
670    ///
671    /// # Examples
672    ///
673    /// ```rust
674    /// use openai_tools::responses::request::{Reasoning, ReasoningEffort, ReasoningSummary};
675    ///
676    /// let reasoning = Reasoning {
677    ///     effort: Some(ReasoningEffort::High),
678    ///     summary: Some(ReasoningSummary::Detailed),
679    /// };
680    /// ```
681    pub reasoning: Option<Reasoning>,
682
683    /// Optional safety identifier
684    ///
685    /// Identifier for safety and content filtering configurations.
686    /// Used to specify which safety policies should be applied to the request.
687    ///
688    /// # Examples
689    ///
690    /// - `Some("strict".to_string())` - Apply strict content filtering
691    /// - `Some("moderate".to_string())` - Apply moderate content filtering
692    /// - `Some("permissive".to_string())` - Apply permissive content filtering
693    pub safety_identifier: Option<String>,
694
695    /// Optional service tier specification
696    ///
697    /// Specifies the service tier for the request, which may affect
698    /// processing priority, rate limits, and pricing.
699    ///
700    /// # Common Values
701    ///
702    /// - `Some("default".to_string())` - Standard service tier
703    /// - `Some("scale".to_string())` - High-throughput tier
704    /// - `Some("premium".to_string())` - Premium service tier with enhanced features
705    pub service_tier: Option<String>,
706
707    /// Optional flag to store the conversation
708    ///
709    /// When enabled, the conversation may be stored for future reference,
710    /// training, or analytics purposes (subject to privacy policies).
711    ///
712    /// # Privacy Considerations
713    ///
714    /// - `Some(true)`: Allow storage (check privacy policies)
715    /// - `Some(false)`: Explicitly opt-out of storage
716    /// - `None`: Use default storage policy
717    pub store: Option<bool>,
718
719    /// Optional flag to enable streaming responses
720    ///
721    /// When enabled, the response will be streamed back in chunks as it's
722    /// generated, allowing for real-time display of partial results.
723    ///
724    /// # Use Cases
725    ///
726    /// - `Some(true)`: Real-time chat interfaces, live text generation
727    /// - `Some(false)`: Batch processing, when you need the complete response
728    ///
729    /// # Considerations
730    ///
731    /// - Streaming responses require different handling in client code
732    /// - May affect some response features or formatting options
733    pub stream: Option<bool>,
734
735    /// Optional streaming configuration options
736    ///
737    /// Additional options for controlling streaming response behavior,
738    /// such as whether to include obfuscated placeholder content.
739    ///
740    /// # Only Relevant When Streaming
741    ///
742    /// This field is only meaningful when `stream` is `Some(true)`.
743    pub stream_options: Option<StreamOptions>,
744
745    /// Optional number of top log probabilities to include
746    ///
747    /// Specifies how many of the most likely alternative tokens to include
748    /// with their log probabilities for each generated token.
749    ///
750    /// # Range
751    ///
752    /// - Minimum: 0 (no log probabilities)
753    /// - Maximum: Model-dependent (typically 5-20)
754    ///
755    /// # Use Cases
756    ///
757    /// - Model analysis and debugging
758    /// - Confidence estimation
759    /// - Alternative response exploration
760    ///
761    /// # Examples
762    ///
763    /// - `Some(1)` - Include the top alternative for each token
764    /// - `Some(5)` - Include top 5 alternatives for detailed analysis
765    pub top_logprobs: Option<usize>,
766
767    /// Optional nucleus sampling parameter
768    ///
769    /// Controls the randomness of the model's responses by limiting the
770    /// cumulative probability of considered tokens.
771    ///
772    /// # Range
773    ///
774    /// - 0.0 to 1.0
775    /// - Lower values (e.g., 0.1) make responses more focused and deterministic
776    /// - Higher values (e.g., 0.9) make responses more diverse and creative
777    ///
778    /// # Default
779    ///
780    /// If not specified, uses the model's default value (typically around 1.0).
781    ///
782    /// # Examples
783    ///
784    /// - `Some(0.1)` - Very focused, deterministic responses
785    /// - `Some(0.7)` - Balanced creativity and focus
786    /// - `Some(0.95)` - High creativity and diversity
787    pub top_p: Option<f64>,
788
789    /// Optional truncation behavior configuration
790    ///
791    /// Controls how the system handles inputs that exceed the maximum
792    /// context length supported by the model.
793    ///
794    /// # Options
795    ///
796    /// - `Some(Truncation::Auto)` - Automatically truncate long inputs
797    /// - `Some(Truncation::Disabled)` - Return error for long inputs
798    /// - `None` - Use system default behavior
799    ///
800    /// # Use Cases
801    ///
802    /// - `Auto`: When you want to handle long documents gracefully
803    /// - `Disabled`: When you need to ensure complete input processing
804    pub truncation: Option<Truncation>,
805}
806
807impl Serialize for Body {
808    /// Custom serialization implementation for the request body
809    ///
810    /// This implementation handles the conversion of either plain text input
811    /// or messages input into the appropriate "input" field format required
812    /// by the OpenAI API. It also conditionally includes optional fields
813    /// like tools and text formatting.
814    ///
815    /// # Errors
816    ///
817    /// Returns a serialization error if neither plain_text_input nor
818    /// messages_input is set, as one of them is required.
819    fn serialize<S>(&self, serializer: S) -> anyhow::Result<S::Ok, S::Error>
820    where
821        S: serde::Serializer,
822    {
823        let mut state = serializer.serialize_struct("ResponsesBody", 4)?;
824        state.serialize_field("model", &self.model)?;
825
826        // Set input
827        if self.plain_text_input.is_some() {
828            state.serialize_field("input", &self.plain_text_input.clone().unwrap())?;
829        } else if self.messages_input.is_some() {
830            state.serialize_field("input", &self.messages_input.clone().unwrap())?;
831        } else {
832            return Err(serde::ser::Error::custom("Either plain_text_input or messages_input must be set."));
833        };
834
835        // Optional fields
836        if self.temperature.is_some() {
837            state.serialize_field("temperature", &self.temperature)?;
838        }
839        if self.instructions.is_some() {
840            state.serialize_field("instructions", &self.instructions)?;
841        }
842        if self.tools.is_some() {
843            state.serialize_field("tools", &self.tools)?;
844        }
845        if self.structured_output.is_some() {
846            state.serialize_field("text", &self.structured_output)?;
847        }
848        if self.max_output_tokens.is_some() {
849            state.serialize_field("max_output_tokens", &self.max_output_tokens)?;
850        }
851        if self.max_tool_calls.is_some() {
852            state.serialize_field("max_tool_calls", &self.max_tool_calls)?;
853        }
854        if self.metadata.is_some() {
855            state.serialize_field("metadata", &self.metadata)?;
856        }
857        if self.parallel_tool_calls.is_some() {
858            state.serialize_field("parallel_tool_calls", &self.parallel_tool_calls)?;
859        }
860        if self.include.is_some() {
861            state.serialize_field("include", &self.include)?;
862        }
863        if self.background.is_some() {
864            state.serialize_field("background", &self.background)?;
865        }
866        if self.conversation.is_some() {
867            state.serialize_field("conversation", &self.conversation)?;
868        }
869        if self.previous_response_id.is_some() {
870            state.serialize_field("previous_response_id", &self.previous_response_id)?;
871        }
872        if self.reasoning.is_some() {
873            state.serialize_field("reasoning", &self.reasoning)?;
874        }
875        if self.safety_identifier.is_some() {
876            state.serialize_field("safety_identifier", &self.safety_identifier)?;
877        }
878        if self.service_tier.is_some() {
879            state.serialize_field("service_tier", &self.service_tier)?;
880        }
881        if self.store.is_some() {
882            state.serialize_field("store", &self.store)?;
883        }
884        if self.stream.is_some() {
885            state.serialize_field("stream", &self.stream)?;
886        }
887        if self.stream_options.is_some() {
888            state.serialize_field("stream_options", &self.stream_options)?;
889        }
890        if self.top_logprobs.is_some() {
891            state.serialize_field("top_logprobs", &self.top_logprobs)?;
892        }
893        if self.top_p.is_some() {
894            state.serialize_field("top_p", &self.top_p)?;
895        }
896        if self.truncation.is_some() {
897            state.serialize_field("truncation", &self.truncation)?;
898        }
899        state.end()
900    }
901}
902
903/// Client for making requests to the OpenAI Responses API
904///
905/// This struct provides a convenient interface for building and executing requests
906/// to the OpenAI Responses API. It handles authentication, request formatting,
907/// and response parsing automatically.
908///
909/// # Examples
910///
911/// ```rust,no_run
912/// use openai_tools::responses::request::Responses;
913///
914/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
915/// let mut client = Responses::new();
916/// let response = client
917///     .model_id("gpt-4")
918///     .instructions("You are a helpful assistant.")
919///     .str_message("Hello, how are you?")
920///     .complete()
921///     .await?;
922/// # Ok(())
923/// # }
924/// ```
925#[derive(Debug, Clone, Default, Serialize)]
926pub struct Responses {
927    /// The API endpoint for the OpenAI Responses service
928    endpoint: String,
929    /// The OpenAI API key used for authentication
930    api_key: String,
931    /// The User-Agent string to include in requests
932    user_agent: String,
933    /// The request body containing all parameters for the API call
934    pub request_body: Body,
935}
936
937impl Responses {
938    /// Creates a new instance of the Responses client
939    ///
940    /// This method initializes a new client by loading the OpenAI API key from
941    /// the `OPENAI_API_KEY` environment variable. Make sure to set this environment
942    /// variable before calling this method.
943    ///
944    /// # Panics
945    ///
946    /// Panics if the `OPENAI_API_KEY` environment variable is not set.
947    pub fn new() -> Self {
948        dotenv().ok();
949        let api_key = env::var("OPENAI_API_KEY").expect("OPENAI_API_KEY is not set.");
950        Self { endpoint: "https://api.openai.com/v1/responses".into(), api_key, user_agent: "".into(), request_body: Body::default() }
951    }
952
953    /// Creates a new instance of the Responses client with a custom endpoint
954    pub fn from_endpoint<T: AsRef<str>>(endpoint: T) -> Self {
955        dotenv().ok();
956        let api_key = env::var("OPENAI_API_KEY").expect("OPENAI_API_KEY is not set.");
957        Self { endpoint: endpoint.as_ref().to_string(), api_key, user_agent: "".into(), request_body: Body::default() }
958    }
959
960    /// Sets the model ID for the request
961    ///
962    /// # Arguments
963    ///
964    /// * `model_id` - The ID of the model to use (e.g., "gpt-4", "gpt-3.5-turbo")
965    ///
966    /// # Returns
967    ///
968    /// A mutable reference to self for method chaining
969    pub fn model_id<T: AsRef<str>>(&mut self, model_id: T) -> &mut Self {
970        self.request_body.model = model_id.as_ref().to_string();
971        self
972    }
973
974    /// Sets the User-Agent string for the request
975    ///
976    /// # Arguments
977    ///
978    /// * `user_agent` - The User-Agent string to include in the request headers
979    ///
980    /// # Returns
981    ///
982    /// A mutable reference to self for method chaining
983    pub fn user_agent<T: AsRef<str>>(&mut self, user_agent: T) -> &mut Self {
984        self.user_agent = user_agent.as_ref().to_string();
985        self
986    }
987
988    /// Sets instructions to guide the model's behavior
989    ///
990    /// # Arguments
991    ///
992    /// * `instructions` - Instructions that define how the model should behave
993    ///
994    /// # Returns
995    ///
996    /// A mutable reference to self for method chaining
997    pub fn instructions<T: AsRef<str>>(&mut self, instructions: T) -> &mut Self {
998        self.request_body.instructions = Some(instructions.as_ref().to_string());
999        self
1000    }
1001
1002    /// Sets plain text input for simple text-based requests
1003    ///
1004    /// This method is mutually exclusive with `messages()`. Use this for simple
1005    /// text-based interactions where you don't need conversation history.
1006    ///
1007    /// # Arguments
1008    ///
1009    /// * `input` - The plain text input to send to the model
1010    ///
1011    /// # Returns
1012    ///
1013    /// A mutable reference to self for method chaining
1014    pub fn str_message<T: AsRef<str>>(&mut self, input: T) -> &mut Self {
1015        self.request_body.plain_text_input = Some(input.as_ref().to_string());
1016        self
1017    }
1018
1019    /// Sets structured message input for conversation-style interactions
1020    ///
1021    /// This method is mutually exclusive with `plain_text_input()`. Use this
1022    /// for complex conversations with message history and different roles.
1023    ///
1024    /// # Arguments
1025    ///
1026    /// * `messages` - A vector of messages representing the conversation history
1027    ///
1028    /// # Returns
1029    ///
1030    /// A mutable reference to self for method chaining
1031    pub fn messages(&mut self, messages: Vec<Message>) -> &mut Self {
1032        self.request_body.messages_input = Some(messages);
1033        self
1034    }
1035
1036    /// Sets tools that the model can use during response generation
1037    ///
1038    /// # Arguments
1039    ///
1040    /// * `tools` - A vector of tools available to the model
1041    ///
1042    /// # Returns
1043    ///
1044    /// A mutable reference to self for method chaining
1045    pub fn tools(&mut self, tools: Vec<Tool>) -> &mut Self {
1046        self.request_body.tools = Some(tools);
1047        self
1048    }
1049
1050    /// Sets structured output format specification
1051    ///
1052    /// This allows you to specify the exact format and structure of the
1053    /// model's response output.
1054    ///
1055    /// # Arguments
1056    ///
1057    /// * `text_format` - The schema defining the expected output structure
1058    ///
1059    /// # Returns
1060    ///
1061    /// A mutable reference to self for method chaining
1062    pub fn structured_output(&mut self, text_format: Schema) -> &mut Self {
1063        self.request_body.structured_output = Option::from(Format::new(text_format));
1064        self
1065    }
1066
1067    /// Sets the sampling temperature for controlling response randomness
1068    ///
1069    /// Controls the randomness and creativity of the model's responses.
1070    /// Higher values make the output more random and creative, while lower
1071    /// values make it more focused and deterministic.
1072    ///
1073    /// # Arguments
1074    ///
1075    /// * `temperature` - The temperature value (0.0 to 2.0)
1076    ///   - 0.0: Most deterministic and focused responses
1077    ///   - 1.0: Default balanced behavior
1078    ///   - 2.0: Most random and creative responses
1079    ///
1080    /// # Panics
1081    ///
1082    /// This method will panic if the temperature value is outside the valid
1083    /// range of 0.0 to 2.0, as this would result in an API error.
1084    ///
1085    /// # Returns
1086    ///
1087    /// A mutable reference to self for method chaining
1088    ///
1089    /// # Examples
1090    ///
1091    /// ```rust
1092    /// use openai_tools::responses::request::Responses;
1093    ///
1094    /// // Deterministic responses for factual queries
1095    /// let mut client = Responses::new();
1096    /// client.temperature(0.2);
1097    ///
1098    /// // Creative responses for brainstorming
1099    /// let mut client = Responses::new();
1100    /// client.temperature(1.1);
1101    /// ```
1102    pub fn temperature(&mut self, temperature: f64) -> &mut Self {
1103        assert!((0.0..=2.0).contains(&temperature), "Temperature must be between 0.0 and 2.0, got {}", temperature);
1104        self.request_body.temperature = Some(temperature);
1105        self
1106    }
1107
1108    /// Sets the maximum number of tokens to generate in the response
1109    ///
1110    /// Controls the maximum length of the generated response. The actual response
1111    /// may be shorter if the model naturally concludes or hits other stopping conditions.
1112    ///
1113    /// # Arguments
1114    ///
1115    /// * `max_tokens` - Maximum number of tokens to generate (minimum: 1)
1116    ///
1117    /// # Returns
1118    ///
1119    /// A mutable reference to self for method chaining
1120    ///
1121    /// # Examples
1122    ///
1123    /// ```rust
1124    /// use openai_tools::responses::request::Responses;
1125    ///
1126    /// let mut client = Responses::new();
1127    /// client.max_output_tokens(100);  // Limit response to 100 tokens
1128    /// ```
1129    pub fn max_output_tokens(&mut self, max_tokens: usize) -> &mut Self {
1130        self.request_body.max_output_tokens = Some(max_tokens);
1131        self
1132    }
1133
1134    /// Sets the maximum number of tool calls allowed during response generation
1135    ///
1136    /// Limits how many tools the model can invoke during response generation.
1137    /// This helps control cost and response time when using multiple tools.
1138    ///
1139    /// # Arguments
1140    ///
1141    /// * `max_tokens` - Maximum number of tool calls allowed (0 = no tool calls)
1142    ///
1143    /// # Returns
1144    ///
1145    /// A mutable reference to self for method chaining
1146    ///
1147    /// # Examples
1148    ///
1149    /// ```rust
1150    /// use openai_tools::responses::request::Responses;
1151    ///
1152    /// let mut client = Responses::new();
1153    /// client.max_tool_calls(3);  // Allow up to 3 tool calls
1154    /// client.max_tool_calls(0);  // Disable tool usage
1155    /// ```
1156    pub fn max_tool_calls(&mut self, max_tokens: usize) -> &mut Self {
1157        self.request_body.max_tool_calls = Some(max_tokens);
1158        self
1159    }
1160
1161    /// Adds or updates a metadata key-value pair for the request
1162    ///
1163    /// Metadata provides arbitrary key-value pairs that can be attached to the request
1164    /// for tracking, logging, or passing additional context that doesn't affect
1165    /// the model's behavior.
1166    ///
1167    /// # Arguments
1168    ///
1169    /// * `key` - The metadata key (string identifier)
1170    /// * `value` - The metadata value (can be string, number, boolean, etc.)
1171    ///
1172    /// # Behavior
1173    ///
1174    /// - If the key already exists, the old value is replaced with the new one
1175    /// - If metadata doesn't exist yet, a new metadata map is created
1176    /// - Values are stored as `serde_json::Value` for flexibility
1177    ///
1178    /// # Returns
1179    ///
1180    /// A mutable reference to self for method chaining
1181    ///
1182    /// # Examples
1183    ///
1184    /// ```rust
1185    /// use openai_tools::responses::request::Responses;
1186    /// use serde_json::Value;
1187    ///
1188    /// let mut client = Responses::new();
1189    /// client.metadata("user_id".to_string(), Value::String("user123".to_string()));
1190    /// client.metadata("priority".to_string(), Value::Number(serde_json::Number::from(1)));
1191    /// client.metadata("debug".to_string(), Value::Bool(true));
1192    /// ```
1193    pub fn metadata(&mut self, key: String, value: serde_json::Value) -> &mut Self {
1194        if self.request_body.metadata.is_none() {
1195            self.request_body.metadata = Some(HashMap::new());
1196        }
1197        if self.request_body.metadata.as_ref().unwrap().keys().any(|k| k == &key) {
1198            self.request_body.metadata.as_mut().unwrap().remove(&key);
1199        }
1200        self.request_body.metadata.as_mut().unwrap().insert(key, value);
1201        self
1202    }
1203
1204    /// Enables or disables parallel tool calls
1205    ///
1206    /// When enabled, the model can make multiple tool calls simultaneously
1207    /// rather than sequentially. This can significantly improve response time
1208    /// when multiple independent tools need to be used.
1209    ///
1210    /// # Arguments
1211    ///
1212    /// * `enable` - Whether to enable parallel tool calls
1213    ///   - `true`: Tools can be called in parallel (faster for independent tools)
1214    ///   - `false`: Tools are called sequentially (better for dependent operations)
1215    ///
1216    /// # Returns
1217    ///
1218    /// A mutable reference to self for method chaining
1219    ///
1220    /// # When to Use
1221    ///
1222    /// - **Enable (true)**: When tools are independent (e.g., weather + stock prices)
1223    /// - **Disable (false)**: When tools have dependencies (e.g., read file → analyze content)
1224    ///
1225    /// # Examples
1226    ///
1227    /// ```rust
1228    /// use openai_tools::responses::request::Responses;
1229    ///
1230    /// let mut client = Responses::new();
1231    /// client.parallel_tool_calls(true);   // Enable parallel execution
1232    /// client.parallel_tool_calls(false);  // Force sequential execution
1233    /// ```
1234    pub fn parallel_tool_calls(&mut self, enable: bool) -> &mut Self {
1235        self.request_body.parallel_tool_calls = Some(enable);
1236        self
1237    }
1238
1239    /// Specifies additional data to include in the response output
1240    ///
1241    /// Defines various types of additional information that can be included
1242    /// in the API response output, such as web search results, code interpreter
1243    /// outputs, image URLs, log probabilities, and reasoning traces.
1244    ///
1245    /// # Arguments
1246    ///
1247    /// * `includes` - A vector of `Include` enum values specifying what to include
1248    ///
1249    /// # Available Inclusions
1250    ///
1251    /// - `Include::WebSearchCall` - Web search results and sources
1252    /// - `Include::CodeInterpreterCall` - Code execution outputs
1253    /// - `Include::FileSearchCall` - File search operation results
1254    /// - `Include::LogprobsInOutput` - Token log probabilities
1255    /// - `Include::ReasoningEncryptedContent` - Reasoning process traces
1256    /// - `Include::ImageUrlInInputMessages` - Image URLs from input
1257    /// - `Include::ImageUrlInComputerCallOutput` - Computer interaction screenshots
1258    ///
1259    /// # Returns
1260    ///
1261    /// A mutable reference to self for method chaining
1262    ///
1263    /// # Examples
1264    ///
1265    /// ```rust
1266    /// use openai_tools::responses::request::{Responses, Include};
1267    ///
1268    /// let mut client = Responses::new();
1269    /// client.include(vec![
1270    ///     Include::WebSearchCall,
1271    ///     Include::LogprobsInOutput,
1272    ///     Include::ReasoningEncryptedContent,
1273    /// ]);
1274    /// ```
1275    pub fn include(&mut self, includes: Vec<Include>) -> &mut Self {
1276        self.request_body.include = Some(includes);
1277        self
1278    }
1279
1280    /// Enables or disables background processing for the request
1281    ///
1282    /// When enabled, allows the request to be processed in the background,
1283    /// potentially improving throughput for non-urgent requests at the cost
1284    /// of potentially higher latency.
1285    ///
1286    /// # Arguments
1287    ///
1288    /// * `enable` - Whether to enable background processing
1289    ///   - `true`: Process in background (lower priority, potentially longer latency)
1290    ///   - `false`: Process with standard priority (default behavior)
1291    ///
1292    /// # Trade-offs
1293    ///
1294    /// - **Background processing**: Better for batch operations, non-interactive requests
1295    /// - **Standard processing**: Better for real-time, interactive applications
1296    ///
1297    /// # Returns
1298    ///
1299    /// A mutable reference to self for method chaining
1300    ///
1301    /// # Examples
1302    ///
1303    /// ```rust
1304    /// use openai_tools::responses::request::Responses;
1305    ///
1306    /// let mut client = Responses::new();
1307    /// client.background(true);   // Enable background processing
1308    /// client.background(false);  // Use standard processing
1309    /// ```
1310    pub fn background(&mut self, enable: bool) -> &mut Self {
1311        self.request_body.background = Some(enable);
1312        self
1313    }
1314
1315    /// Sets the conversation ID for grouping related requests
1316    ///
1317    /// Identifier for grouping related requests as part of the same conversation
1318    /// or session. This helps with context management, analytics, and conversation
1319    /// tracking across multiple API calls.
1320    ///
1321    /// # Arguments
1322    ///
1323    /// * `conversation_id` - The conversation identifier
1324    ///   - Must start with "conv-" prefix according to API requirements
1325    ///   - Should be a unique identifier (UUID recommended)
1326    ///
1327    /// # Returns
1328    ///
1329    /// A mutable reference to self for method chaining
1330    ///
1331    /// # Format Requirements
1332    ///
1333    /// The conversation ID must follow the format: `conv-{identifier}`
1334    ///
1335    /// # Examples
1336    ///
1337    /// ```rust
1338    /// use openai_tools::responses::request::Responses;
1339    ///
1340    /// let mut client = Responses::new();
1341    /// client.conversation("conv-123e4567-e89b-12d3-a456-426614174000");
1342    /// client.conversation("conv-user123-session456");
1343    /// ```
1344    pub fn conversation<T: AsRef<str>>(&mut self, conversation_id: T) -> &mut Self {
1345        self.request_body.conversation = Some(conversation_id.as_ref().to_string());
1346        self
1347    }
1348
1349    /// Sets the ID of the previous response for context continuation
1350    ///
1351    /// References a previous response in the same conversation to maintain
1352    /// context and enable features like response chaining, follow-up handling,
1353    /// or response refinement.
1354    ///
1355    /// # Arguments
1356    ///
1357    /// * `response_id` - The ID of the previous response to reference
1358    ///
1359    /// # Use Cases
1360    ///
1361    /// - **Multi-turn conversations**: Maintaining context across multiple exchanges
1362    /// - **Follow-up questions**: Building on previous responses
1363    /// - **Response refinement**: Iterating on or clarifying previous answers
1364    /// - **Context chaining**: Creating connected sequences of responses
1365    ///
1366    /// # Returns
1367    ///
1368    /// A mutable reference to self for method chaining
1369    ///
1370    /// # Examples
1371    ///
1372    /// ```rust
1373    /// use openai_tools::responses::request::Responses;
1374    ///
1375    /// let mut client = Responses::new();
1376    /// client.previous_response_id("resp_abc123def456");
1377    /// client.previous_response_id("response-uuid-here");
1378    /// ```
1379    pub fn previous_response_id<T: AsRef<str>>(&mut self, response_id: T) -> &mut Self {
1380        self.request_body.previous_response_id = Some(response_id.as_ref().to_string());
1381        self
1382    }
1383
1384    /// Configures reasoning behavior for complex problem-solving
1385    ///
1386    /// Controls how the model approaches complex reasoning tasks, including
1387    /// the computational effort level and format of reasoning explanations.
1388    /// This is particularly useful for mathematical, logical, or analytical tasks.
1389    ///
1390    /// # Arguments
1391    ///
1392    /// * `effort` - The level of reasoning effort to apply:
1393    ///   - `ReasoningEffort::Minimal` - Fastest, for simple queries
1394    ///   - `ReasoningEffort::Low` - Balanced, for moderate complexity
1395    ///   - `ReasoningEffort::Medium` - Thorough, for complex queries
1396    ///   - `ReasoningEffort::High` - Maximum analysis, for very complex problems
1397    ///
1398    /// * `summary` - The format for reasoning explanations:
1399    ///   - `ReasoningSummary::Auto` - Let the model choose the format
1400    ///   - `ReasoningSummary::Concise` - Brief, focused explanations
1401    ///   - `ReasoningSummary::Detailed` - Comprehensive, step-by-step explanations
1402    ///
1403    /// # Returns
1404    ///
1405    /// A mutable reference to self for method chaining
1406    ///
1407    /// # Use Cases
1408    ///
1409    /// - Mathematical problem-solving with step-by-step explanations
1410    /// - Complex logical reasoning tasks
1411    /// - Analysis requiring deep consideration
1412    /// - Tasks where understanding the reasoning process is important
1413    ///
1414    /// # Examples
1415    ///
1416    /// ```rust
1417    /// use openai_tools::responses::request::{Responses, ReasoningEffort, ReasoningSummary};
1418    ///
1419    /// let mut client = Responses::new();
1420    ///
1421    /// // High effort with detailed explanations for complex problems
1422    /// client.reasoning(ReasoningEffort::High, ReasoningSummary::Detailed);
1423    ///
1424    /// // Medium effort with concise explanations for balanced approach
1425    /// client.reasoning(ReasoningEffort::Medium, ReasoningSummary::Concise);
1426    /// ```
1427    pub fn reasoning(&mut self, effort: ReasoningEffort, summary: ReasoningSummary) -> &mut Self {
1428        self.request_body.reasoning = Some(Reasoning { effort: Some(effort), summary: Some(summary) });
1429        self
1430    }
1431
1432    /// Sets the safety identifier for content filtering configuration
1433    ///
1434    /// Specifies which safety and content filtering policies should be applied
1435    /// to the request. Different safety levels provide varying degrees of content
1436    /// restriction and filtering.
1437    ///
1438    /// # Arguments
1439    ///
1440    /// * `safety_id` - The safety configuration identifier
1441    ///
1442    /// # Common Safety Levels
1443    ///
1444    /// - `"strict"` - Apply strict content filtering (highest safety)
1445    /// - `"moderate"` - Apply moderate content filtering (balanced approach)
1446    /// - `"permissive"` - Apply permissive content filtering (minimal restrictions)
1447    /// - `"default"` - Use system default safety settings
1448    ///
1449    /// # Returns
1450    ///
1451    /// A mutable reference to self for method chaining
1452    ///
1453    /// # Use Cases
1454    ///
1455    /// - Educational content requiring strict filtering
1456    /// - Business applications with moderate restrictions
1457    /// - Research applications needing broader content access
1458    ///
1459    /// # Examples
1460    ///
1461    /// ```rust
1462    /// use openai_tools::responses::request::Responses;
1463    ///
1464    /// let mut client = Responses::new();
1465    /// client.safety_identifier("strict");     // High safety for education
1466    /// client.safety_identifier("moderate");   // Balanced for general use
1467    /// client.safety_identifier("permissive"); // Minimal restrictions
1468    /// ```
1469    pub fn safety_identifier<T: AsRef<str>>(&mut self, safety_id: T) -> &mut Self {
1470        self.request_body.safety_identifier = Some(safety_id.as_ref().to_string());
1471        self
1472    }
1473
1474    /// Sets the service tier for request processing priority and features
1475    ///
1476    /// Specifies the service tier for the request, which affects processing
1477    /// priority, rate limits, pricing, and available features. Different tiers
1478    /// provide different levels of service quality and capabilities.
1479    ///
1480    /// # Arguments
1481    ///
1482    /// * `tier` - The service tier identifier
1483    ///
1484    /// # Common Service Tiers
1485    ///
1486    /// - `"default"` - Standard service tier with regular priority
1487    /// - `"scale"` - High-throughput tier optimized for bulk processing
1488    /// - `"premium"` - Premium service tier with enhanced features and priority
1489    /// - `"enterprise"` - Enterprise tier with dedicated resources
1490    ///
1491    /// # Returns
1492    ///
1493    /// A mutable reference to self for method chaining
1494    ///
1495    /// # Considerations
1496    ///
1497    /// - Higher tiers may have different pricing structures
1498    /// - Some features may only be available in certain tiers
1499    /// - Rate limits and quotas may vary by tier
1500    ///
1501    /// # Examples
1502    ///
1503    /// ```rust
1504    /// use openai_tools::responses::request::Responses;
1505    ///
1506    /// let mut client = Responses::new();
1507    /// client.service_tier("default");   // Standard service
1508    /// client.service_tier("scale");     // High-throughput processing
1509    /// client.service_tier("premium");   // Premium features and priority
1510    /// ```
1511    pub fn service_tier<T: AsRef<str>>(&mut self, tier: T) -> &mut Self {
1512        self.request_body.service_tier = Some(tier.as_ref().to_string());
1513        self
1514    }
1515
1516    /// Enables or disables conversation storage
1517    ///
1518    /// Controls whether the conversation may be stored for future reference,
1519    /// training, or analytics purposes. This setting affects data retention
1520    /// and privacy policies.
1521    ///
1522    /// # Arguments
1523    ///
1524    /// * `enable` - Whether to allow conversation storage
1525    ///   - `true`: Allow storage for training, analytics, etc.
1526    ///   - `false`: Explicitly opt-out of storage
1527    ///
1528    /// # Privacy Considerations
1529    ///
1530    /// - **Enabled storage**: Conversation may be retained according to service policies
1531    /// - **Disabled storage**: Request explicit deletion after processing
1532    /// - **Default behavior**: Varies by service configuration
1533    ///
1534    /// # Returns
1535    ///
1536    /// A mutable reference to self for method chaining
1537    ///
1538    /// # Use Cases
1539    ///
1540    /// - **Enable**: Contributing to model improvement, analytics
1541    /// - **Disable**: Sensitive data, privacy-critical applications
1542    ///
1543    /// # Examples
1544    ///
1545    /// ```rust
1546    /// use openai_tools::responses::request::Responses;
1547    ///
1548    /// let mut client = Responses::new();
1549    /// client.store(false);  // Opt-out of storage for privacy
1550    /// client.store(true);   // Allow storage for improvement
1551    /// ```
1552    pub fn store(&mut self, enable: bool) -> &mut Self {
1553        self.request_body.store = Some(enable);
1554        self
1555    }
1556
1557    /// Enables or disables streaming responses
1558    ///
1559    /// When enabled, the response will be streamed back in chunks as it's
1560    /// generated, allowing for real-time display of partial results instead
1561    /// of waiting for the complete response.
1562    ///
1563    /// # Arguments
1564    ///
1565    /// * `enable` - Whether to enable streaming
1566    ///   - `true`: Stream response in real-time chunks
1567    ///   - `false`: Wait for complete response before returning
1568    ///
1569    /// # Returns
1570    ///
1571    /// A mutable reference to self for method chaining
1572    ///
1573    /// # Use Cases
1574    ///
1575    /// - **Enable streaming**: Real-time chat interfaces, live text generation
1576    /// - **Disable streaming**: Batch processing, when complete response is needed
1577    ///
1578    /// # Implementation Notes
1579    ///
1580    /// - Streaming responses require different handling in client code
1581    /// - May affect some response features or formatting options
1582    /// - Typically used with `stream_options()` for additional configuration
1583    ///
1584    /// # Examples
1585    ///
1586    /// ```rust
1587    /// use openai_tools::responses::request::Responses;
1588    ///
1589    /// let mut client = Responses::new();
1590    /// client.stream(true);   // Enable real-time streaming
1591    /// client.stream(false);  // Wait for complete response
1592    /// ```
1593    pub fn stream(&mut self, enable: bool) -> &mut Self {
1594        self.request_body.stream = Some(enable);
1595        self
1596    }
1597
1598    /// Configures streaming response options
1599    ///
1600    /// Additional options for controlling streaming response behavior,
1601    /// such as whether to include obfuscated placeholder content during
1602    /// the streaming process.
1603    ///
1604    /// # Arguments
1605    ///
1606    /// * `include_obfuscation` - Whether to include obfuscated content
1607    ///   - `true`: Include placeholder/obfuscated content in streams
1608    ///   - `false`: Only include final, non-obfuscated content
1609    ///
1610    /// # Returns
1611    ///
1612    /// A mutable reference to self for method chaining
1613    ///
1614    /// # Relevance
1615    ///
1616    /// This setting is only meaningful when `stream(true)` is also set.
1617    /// It has no effect on non-streaming responses.
1618    ///
1619    /// # Use Cases
1620    ///
1621    /// - **Include obfuscation**: Better user experience with placeholder content
1622    /// - **Exclude obfuscation**: Cleaner streams with only final content
1623    ///
1624    /// # Examples
1625    ///
1626    /// ```rust
1627    /// use openai_tools::responses::request::Responses;
1628    ///
1629    /// let mut client = Responses::new();
1630    /// client.stream(true);                    // Enable streaming
1631    /// client.stream_options(true);            // Include placeholder content
1632    /// client.stream_options(false);           // Only final content
1633    /// ```
1634    pub fn stream_options(&mut self, include_obfuscation: bool) -> &mut Self {
1635        self.request_body.stream_options = Some(StreamOptions { include_obfuscation });
1636        self
1637    }
1638
1639    /// Sets the number of top log probabilities to include in the response
1640    ///
1641    /// Specifies how many of the most likely alternative tokens to include
1642    /// with their log probabilities for each generated token. This provides
1643    /// insight into the model's confidence and alternative choices.
1644    ///
1645    /// # Arguments
1646    ///
1647    /// * `n` - Number of top alternatives to include (typically 1-20)
1648    ///   - `0`: No log probabilities included
1649    ///   - `1-5`: Common range for most use cases
1650    ///   - `>5`: Detailed analysis scenarios
1651    ///
1652    /// # Returns
1653    ///
1654    /// A mutable reference to self for method chaining
1655    ///
1656    /// # Use Cases
1657    ///
1658    /// - **Model analysis**: Understanding model decision-making
1659    /// - **Confidence estimation**: Measuring response certainty
1660    /// - **Alternative exploration**: Seeing what else the model considered
1661    /// - **Debugging**: Analyzing unexpected model behavior
1662    ///
1663    /// # Performance Note
1664    ///
1665    /// Higher values increase response size and may affect latency.
1666    ///
1667    /// # Examples
1668    ///
1669    /// ```rust
1670    /// use openai_tools::responses::request::Responses;
1671    ///
1672    /// let mut client = Responses::new();
1673    /// client.top_logprobs(1);   // Include top alternative for each token
1674    /// client.top_logprobs(5);   // Include top 5 alternatives (detailed analysis)
1675    /// client.top_logprobs(0);   // No log probabilities
1676    /// ```
1677    pub fn top_logprobs(&mut self, n: usize) -> &mut Self {
1678        self.request_body.top_logprobs = Some(n);
1679        self
1680    }
1681
1682    /// Sets the nucleus sampling parameter for controlling response diversity
1683    ///
1684    /// Controls the randomness of the model's responses by limiting the
1685    /// cumulative probability of considered tokens. This is an alternative
1686    /// to temperature-based sampling that can provide more stable results.
1687    ///
1688    /// # Arguments
1689    ///
1690    /// * `p` - The nucleus sampling parameter (0.0 to 1.0)
1691    ///   - `0.1`: Very focused, deterministic responses
1692    ///   - `0.7`: Balanced creativity and focus (good default)
1693    ///   - `0.9`: More diverse and creative responses
1694    ///   - `1.0`: Consider all possible tokens (no truncation)
1695    ///
1696    /// # Returns
1697    ///
1698    /// A mutable reference to self for method chaining
1699    ///
1700    /// # How It Works
1701    ///
1702    /// The model considers only the tokens whose cumulative probability
1703    /// reaches the specified threshold, filtering out unlikely options.
1704    ///
1705    /// # Interaction with Temperature
1706    ///
1707    /// Can be used together with `temperature()` for fine-tuned control:
1708    /// - Low top_p + Low temperature = Very focused responses
1709    /// - High top_p + High temperature = Very creative responses
1710    ///
1711    /// # Examples
1712    ///
1713    /// ```rust
1714    /// use openai_tools::responses::request::Responses;
1715    ///
1716    /// let mut client = Responses::new();
1717    /// client.top_p(0.1);   // Very focused responses
1718    /// client.top_p(0.7);   // Balanced (recommended default)
1719    /// client.top_p(0.95);  // High diversity
1720    /// ```
1721    pub fn top_p(&mut self, p: f64) -> &mut Self {
1722        self.request_body.top_p = Some(p);
1723        self
1724    }
1725
1726    /// Sets the truncation behavior for handling long inputs
1727    ///
1728    /// Controls how the system handles inputs that exceed the maximum
1729    /// context length supported by the model. This helps manage cases
1730    /// where input content is too large to process entirely.
1731    ///
1732    /// # Arguments
1733    ///
1734    /// * `truncation` - The truncation mode to use:
1735    ///   - `Truncation::Auto`: Automatically truncate long inputs to fit
1736    ///   - `Truncation::Disabled`: Return error if input exceeds context length
1737    ///
1738    /// # Returns
1739    ///
1740    /// A mutable reference to self for method chaining
1741    ///
1742    /// # Use Cases
1743    ///
1744    /// - **Auto truncation**: When you want to handle long documents gracefully
1745    /// - **Disabled truncation**: When you need to ensure complete input processing
1746    ///
1747    /// # Considerations
1748    ///
1749    /// - Auto truncation may remove important context from long inputs
1750    /// - Disabled truncation ensures complete processing but may cause errors
1751    /// - Consider breaking long inputs into smaller chunks when possible
1752    ///
1753    /// # Examples
1754    ///
1755    /// ```rust
1756    /// use openai_tools::responses::request::{Responses, Truncation};
1757    ///
1758    /// let mut client = Responses::new();
1759    /// client.truncation(Truncation::Auto);      // Handle long inputs gracefully
1760    /// client.truncation(Truncation::Disabled);  // Ensure complete processing
1761    /// ```
1762    pub fn truncation(&mut self, truncation: Truncation) -> &mut Self {
1763        self.request_body.truncation = Some(truncation);
1764        self
1765    }
1766
1767    /// Executes the request and returns the response
1768    ///
1769    /// This method sends the configured request to the OpenAI Responses API
1770    /// and returns the parsed response. It performs validation of required
1771    /// fields before sending the request.
1772    ///
1773    /// # Returns
1774    ///
1775    /// A `Result` containing the `Response` on success, or an `OpenAIToolError` on failure
1776    ///
1777    /// # Errors
1778    ///
1779    /// Returns an error if:
1780    /// - The API key is not set or is empty
1781    /// - The model ID is not set or is empty  
1782    /// - Neither messages nor plain text input is provided
1783    /// - Both messages and plain text input are provided (mutually exclusive)
1784    /// - The HTTP request fails
1785    /// - The response cannot be parsed
1786    ///
1787    /// # Examples
1788    ///
1789    /// ```rust,no_run
1790    /// use openai_tools::responses::request::Responses;
1791    ///
1792    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
1793    /// let mut client = Responses::new();
1794    /// let response = client
1795    ///     .model_id("gpt-4")
1796    ///     .str_message("Hello!")
1797    ///     .complete()
1798    ///     .await?;
1799    /// # Ok(())
1800    /// # }
1801    /// ```
1802    pub async fn complete(&self) -> Result<Response> {
1803        if self.api_key.is_empty() {
1804            return Err(OpenAIToolError::Error("API key is not set.".into()));
1805        }
1806        if self.request_body.model.is_empty() {
1807            return Err(OpenAIToolError::Error("Model ID is not set.".into()));
1808        }
1809        if self.request_body.messages_input.is_none() && self.request_body.plain_text_input.is_none() {
1810            return Err(OpenAIToolError::Error("Messages are not set.".into()));
1811        } else if self.request_body.plain_text_input.is_none() && self.request_body.messages_input.is_none() {
1812            return Err(OpenAIToolError::Error("Both plain text input and messages are set. Please use one of them.".into()));
1813        }
1814
1815        let body = serde_json::to_string(&self.request_body)?;
1816        let url = self.endpoint.clone();
1817
1818        let client = request::Client::new();
1819
1820        // Set up headers
1821        let mut header = request::header::HeaderMap::new();
1822        header.insert("Content-Type", request::header::HeaderValue::from_static("application/json"));
1823        header.insert("Authorization", request::header::HeaderValue::from_str(&format!("Bearer {}", self.api_key)).unwrap());
1824        if !self.user_agent.is_empty() {
1825            header.insert("User-Agent", request::header::HeaderValue::from_str(&self.user_agent).unwrap());
1826        }
1827
1828        if cfg!(test) {
1829            tracing::info!("Endpoint: {}", self.endpoint);
1830            // Replace API key with a placeholder for security
1831            let body_for_debug = serde_json::to_string_pretty(&self.request_body).unwrap().replace(&self.api_key, "*************");
1832            // Log the request body for debugging purposes
1833            tracing::info!("Request body: {}", body_for_debug);
1834        }
1835
1836        // Send the request and handle the response
1837        match client.post(url).headers(header).body(body).send().await.map_err(OpenAIToolError::RequestError) {
1838            Err(e) => {
1839                tracing::error!("Request error: {}", e);
1840                return Err(e);
1841            }
1842            Ok(response) if !response.status().is_success() => {
1843                let status = response.status();
1844                let error_text = response.text().await.unwrap_or_else(|_| "Failed to read error response".to_string());
1845                tracing::error!("API error (status: {}): {}", status, error_text);
1846                return Err(OpenAIToolError::Error(format!("API request failed with status {}: {}", status, error_text)));
1847            }
1848            Ok(response) => {
1849                let content = response.text().await.map_err(OpenAIToolError::RequestError)?;
1850
1851                if cfg!(test) {
1852                    tracing::info!("Response content: {}", content);
1853                }
1854
1855                let data = serde_json::from_str::<Response>(&content).map_err(OpenAIToolError::SerdeJsonError);
1856                return data;
1857            }
1858        }
1859    }
1860}