// SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

use crate::error::OpenAIError;
use crate::types::mcp::{MCPListToolsTool, MCPTool};
use crate::types::responses::{
    CustomGrammarFormatParam, Filter, ImageDetail, ReasoningEffort, ResponseFormatJsonSchema,
    ResponseUsage,
};
use derive_builder::Builder;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use utoipa::ToSchema;

/// Role of messages in the API.
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Default, ToSchema)]
#[serde(rename_all = "lowercase")]
pub enum Role {
    #[default]
    User,
    Assistant,
    System,
    Developer,
}

/// Status of input/output items.
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Default, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum OutputStatus {
    InProgress,
    #[default]
    Completed,
    Incomplete,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
#[serde(untagged)]
pub enum InputParam {
    ///  A text input to the model, equivalent to a text input with the
    /// `user` role.
    Text(String),
    /// A list of one or many input items to the model, containing
    /// different content types.
    Items(Vec<InputItem>),
}

/// Content item used to generate a response.
///
/// This is a properly discriminated union based on the `type` field, using Rust's
/// type-safe enum with serde's tag attribute for efficient deserialization.
///
/// # OpenAPI Specification
/// Corresponds to the `Item` schema in the OpenAPI spec with a `type` discriminator.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
#[schema(no_recursion)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum Item {
    /// A message (type: "message").
    /// Can represent InputMessage (user/system/developer) or OutputMessage (assistant).
    ///
    /// InputMessage:
    ///     A message input to the model with a role indicating instruction following hierarchy.
    ///     Instructions given with the developer or system role take precedence over instructions given with the user role.
    /// OutputMessage:
    ///     A message output from the model.
    Message(MessageItem),

    /// The results of a file search tool call. See the
    /// [file search guide](https://platform.openai.com/docs/guides/tools-file-search) for more information.
    FileSearchCall(FileSearchToolCall),

    /// A tool call to a computer use tool. See the
    /// [computer use guide](https://platform.openai.com/docs/guides/tools-computer-use) for more information.
    ComputerCall(ComputerToolCall),

    /// The output of a computer tool call.
    ComputerCallOutput(ComputerCallOutputItemParam),

    /// The results of a web search tool call. See the
    /// [web search guide](https://platform.openai.com/docs/guides/tools-web-search) for more information.
    WebSearchCall(WebSearchToolCall),

    /// A tool call to run a function. See the
    ///
    /// [function calling guide](https://platform.openai.com/docs/guides/function-calling) for more information.
    FunctionCall(FunctionToolCall),

    /// The output of a function tool call.
    FunctionCallOutput(FunctionCallOutputItemParam),

    /// A description of the chain of thought used by a reasoning model while generating
    /// a response. Be sure to include these items in your `input` to the Responses API
    /// for subsequent turns of a conversation if you are manually
    /// [managing context](https://platform.openai.com/docs/guides/conversation-state).
    Reasoning(ReasoningItem),

    /// A compaction item generated by the [`v1/responses/compact` API](https://platform.openai.com/docs/api-reference/responses/compact).
    Compaction(CompactionSummaryItemParam),

    /// An image generation request made by the model.
    ImageGenerationCall(ImageGenToolCall),

    /// A tool call to run code.
    CodeInterpreterCall(CodeInterpreterToolCall),

    /// A tool call to run a command on the local shell.
    LocalShellCall(LocalShellToolCall),

    /// The output of a local shell tool call.
    LocalShellCallOutput(LocalShellToolCallOutput),

    /// A tool representing a request to execute one or more shell commands.
    ShellCall(FunctionShellCallItemParam),

    /// The streamed output items emitted by a shell tool call.
    ShellCallOutput(FunctionShellCallOutputItemParam),

    /// A tool call representing a request to create, delete, or update files using diff patches.
    ApplyPatchCall(ApplyPatchToolCallItemParam),

    /// The streamed output emitted by an apply patch tool call.
    ApplyPatchCallOutput(ApplyPatchToolCallOutputItemParam),

    /// A list of tools available on an MCP server.
    McpListTools(MCPListTools),

    /// A request for human approval of a tool invocation.
    McpApprovalRequest(MCPApprovalRequest),

    /// A response to an MCP approval request.
    McpApprovalResponse(MCPApprovalResponse),

    /// An invocation of a tool on an MCP server.
    McpCall(MCPToolCall),

    /// The output of a custom tool call from your code, being sent back to the model.
    CustomToolCallOutput(CustomToolCallOutput),

    /// A call to a custom tool created by the model.
    CustomToolCall(CustomToolCall),
}

/// Input item that can be used in the context for generating a response.
///
/// This represents the OpenAPI `InputItem` schema which is an `anyOf`:
/// 1. `EasyInputMessage` - Simple, user-friendly message input (can use string content)
/// 2. `Item` - Structured items with proper type discrimination (including InputMessage, OutputMessage, tool calls)
/// 3. `ItemReferenceParam` - Reference to an existing item by ID (type can be null)
///
/// Uses untagged deserialization because these types overlap in structure.
/// Order matters: more specific structures are tried first.
///
/// # OpenAPI Specification
/// Corresponds to the `InputItem` schema: `anyOf[EasyInputMessage, Item, ItemReferenceParam]`
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
#[serde(untagged)]
pub enum InputItem {
    /// A reference to an existing item by ID.
    /// Has a required `id` field and optional `type` (can be "item_reference" or null).
    /// Must be tried first as it's the most minimal structure.
    ItemReference(ItemReference),

    /// All structured items with proper type discrimination.
    /// Includes InputMessage, OutputMessage, and all tool calls/outputs.
    /// Uses the discriminated `Item` enum for efficient, type-safe deserialization.
    #[schema(no_recursion)]
    Item(Item),

    /// A simple, user-friendly message input (EasyInputMessage).
    /// Supports string content and can include assistant role for previous responses.
    /// Must be tried last as it's the most flexible structure.
    ///
    /// A message input to the model with a role indicating instruction following
    /// hierarchy. Instructions given with the `developer` or `system` role take
    /// precedence over instructions given with the `user` role. Messages with the
    /// `assistant` role are presumed to have been generated by the model in previous
    /// interactions.
    EasyMessage(EasyInputMessage),
}

/// A message item used within the `Item` enum.
///
/// Both InputMessage and OutputMessage have `type: "message"`, so we use an untagged
/// enum to distinguish them based on their structure:
/// - OutputMessage: role=assistant, required id & status fields
/// - InputMessage: role=user/system/developer, content is `Vec<ContentType>`, optional id/status
///
/// Note: EasyInputMessage is NOT included here - it's a separate variant in `InputItem`,
/// not part of the structured `Item` enum.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
#[serde(untagged)]
pub enum MessageItem {
    /// An output message from the model (role: assistant, has required id & status).
    /// This must come first as it has the most specific structure (required id and status fields).
    Output(OutputMessage),

    /// A structured input message (role: user/system/developer, content is `Vec<ContentType>`).
    /// Has structured content list and optional id/status fields.
    ///
    /// A message input to the model with a role indicating instruction following hierarchy.
    /// Instructions given with the `developer` or `system` role take precedence over instructions
    /// given with the `user` role.
    Input(InputMessage),
}

/// A reference to an existing item by ID.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct ItemReference {
    /// The type of item to reference. Can be "item_reference" or null.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub r#type: Option<ItemReferenceType>,
    /// The ID of the item to reference.
    pub id: String,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum ItemReferenceType {
    ItemReference,
}

/// Output from a function call that you're providing back to the model.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct FunctionCallOutputItemParam {
    /// The unique ID of the function tool call generated by the model.
    pub call_id: String,
    /// Text, image, or file output of the function tool call.
    pub output: FunctionCallOutput,
    /// The unique ID of the function tool call output.
    /// Populated when this item is returned via API.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub id: Option<String>,
    /// The status of the item. One of `in_progress`, `completed`, or `incomplete`.
    /// Populated when items are returned via API.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub status: Option<OutputStatus>,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
#[serde(untagged)]
pub enum FunctionCallOutput {
    /// A JSON string of the output of the function tool call.
    Text(String),
    Content(Vec<InputContent>), // TODO use shape which allows null from OpenAPI spec?
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct ComputerCallOutputItemParam {
    /// The ID of the computer tool call that produced the output.
    pub call_id: String,
    /// A computer screenshot image used with the computer use tool.
    pub output: ComputerScreenshotImage,
    /// The safety checks reported by the API that have been acknowledged by the developer.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub acknowledged_safety_checks: Option<Vec<ComputerCallSafetyCheckParam>>,
    /// The unique ID of the computer tool call output. Optional when creating.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub id: Option<String>,
    /// The status of the message input. One of `in_progress`, `completed`, or `incomplete`.
    /// Populated when input items are returned via API.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub status: Option<OutputStatus>, // TODO rename OutputStatus?
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum ComputerScreenshotImageType {
    ComputerScreenshot,
}

/// A computer screenshot image used with the computer use tool.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct ComputerScreenshotImage {
    /// Specifies the event type. For a computer screenshot, this property is always
    /// set to `computer_screenshot`.
    pub r#type: ComputerScreenshotImageType,
    /// The identifier of an uploaded file that contains the screenshot.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub file_id: Option<String>,
    /// The URL of the screenshot image.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub image_url: Option<String>,
}

/// Output from a local shell tool call that you're providing back to the model.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct LocalShellToolCallOutput {
    /// The unique ID of the local shell tool call generated by the model.
    pub id: String,

    /// A JSON string of the output of the local shell tool call.
    pub output: String,

    /// The status of the item. One of `in_progress`, `completed`, or `incomplete`.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub status: Option<OutputStatus>,
}

/// Output from a local shell command execution.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct LocalShellOutput {
    /// The stdout output from the command.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub stdout: Option<String>,

    /// The stderr output from the command.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub stderr: Option<String>,

    /// The exit code of the command.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub exit_code: Option<i32>,
}

/// An MCP approval response that you're providing back to the model.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct MCPApprovalResponse {
    /// The ID of the approval request being answered.
    pub approval_request_id: String,

    /// Whether the request was approved.
    pub approve: bool,

    /// The unique ID of the approval response
    #[serde(skip_serializing_if = "Option::is_none")]
    pub id: Option<String>,

    /// Optional reason for the decision.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub reason: Option<String>,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
#[serde(untagged)]
pub enum CustomToolCallOutputOutput {
    /// A string of the output of the custom tool call.
    Text(String),
    /// Text, image, or file output of the custom tool call.
    List(Vec<InputContent>),
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct CustomToolCallOutput {
    /// The call ID, used to map this custom tool call output to a custom tool call.
    pub call_id: String,

    /// The output from the custom tool call generated by your code.
    /// Can be a string or an list of output content.
    pub output: CustomToolCallOutputOutput,

    /// The unique ID of the custom tool call output in the OpenAI platform.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub id: Option<String>,
}

/// A simplified message input to the model (EasyInputMessage in the OpenAPI spec).
///
/// This is the most user-friendly way to provide messages, supporting both simple
/// string content and structured content. Role can include `assistant` for providing
/// previous assistant responses.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default, Builder, ToSchema)]
#[builder(
    name = "EasyInputMessageArgs",
    pattern = "mutable",
    setter(into, strip_option),
    default
)]
#[builder(build_fn(error = "OpenAIError"))]
pub struct EasyInputMessage {
    /// The type of the message input. Always set to `message`.
    /// Optional in the "easy" format — defaults to `message` when omitted.
    #[serde(default)]
    pub r#type: MessageType,
    /// The role of the message input. One of `user`, `assistant`, `system`, or `developer`.
    pub role: Role,
    /// Text, image, or audio input to the model, used to generate a response.
    /// Can also contain previous assistant responses.
    pub content: EasyInputContent,
}

/// A structured message input to the model (InputMessage in the OpenAPI spec).
///
/// This variant requires structured content (not a simple string) and does not support
/// the `assistant` role (use OutputMessage for that). status is populated when items are returned via API.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default, Builder, ToSchema)]
#[builder(
    name = "InputMessageArgs",
    pattern = "mutable",
    setter(into, strip_option),
    default
)]
#[builder(build_fn(error = "OpenAIError"))]
pub struct InputMessage {
    /// A list of one or many input items to the model, containing different content types.
    pub content: Vec<InputContent>,
    /// The role of the message input. One of `user`, `system`, or `developer`.
    /// Note: `assistant` is NOT allowed here; use OutputMessage instead.
    pub role: InputRole,
    /// The status of the item. One of `in_progress`, `completed`, or `incomplete`.
    /// Populated when items are returned via API.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub status: Option<OutputStatus>,
    /////The type of the message input. Always set to `message`.
    //pub r#type: MessageType,
}

/// The role for an input message - can only be `user`, `system`, or `developer`.
/// This type ensures type safety by excluding the `assistant` role (use OutputMessage for that).
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Default, ToSchema)]
#[serde(rename_all = "lowercase")]
pub enum InputRole {
    #[default]
    User,
    System,
    Developer,
}

/// Content for EasyInputMessage - can be a simple string or structured list.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
#[serde(untagged)]
pub enum EasyInputContent {
    /// A text input to the model.
    Text(String),
    /// A list of one or many input items to the model, containing different content types.
    ContentList(Vec<InputContent>),
}

/// Parts of a message: text, image, file, or audio.
/// Also accepts `output_text` for replaying assistant turns in the "easy" input format.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum InputContent {
    /// A text input to the model.
    InputText(InputTextContent),
    /// An image input to the model. Learn about
    /// [image inputs](https://platform.openai.com/docs/guides/vision).
    InputImage(InputImageContent),
    /// A file input to the model.
    InputFile(InputFileContent),
    /// A video input to the model.
    InputVideo(InputVideoContent),
    /// An audio input to the model.
    InputAudio(InputAudioContent),
    /// An output text content item, accepted when replaying assistant messages
    /// in the "easy" input format (role: assistant with output_text content).
    OutputText(OutputTextContent),
    /// A refusal content item, accepted when replaying assistant messages.
    Refusal(RefusalContent),
}

/// Video content for input messages.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct InputVideoContent {
    /// The video input - can be a URL or base64 encoded data.
    pub video: String,
}

/// Audio content for input messages.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct InputAudioContent {
    /// The audio input - can be a URL or base64 encoded data.
    pub audio: String,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct InputTextContent {
    /// The text input to the model.
    pub text: String,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default, Builder, ToSchema)]
#[builder(
    name = "InputImageArgs",
    pattern = "mutable",
    setter(into, strip_option),
    default
)]
#[builder(build_fn(error = "OpenAIError"))]
pub struct InputImageContent {
    /// The detail level of the image to be sent to the model. One of `high`, `low`, or `auto`.
    /// Defaults to `auto`.
    #[serde(default)]
    pub detail: ImageDetail,
    /// The ID of the file to be sent to the model.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub file_id: Option<String>,
    /// The URL of the image to be sent to the model. A fully qualified URL or base64 encoded image
    /// in a data URL.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub image_url: Option<String>,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default, Builder, ToSchema)]
#[builder(
    name = "InputFileArgs",
    pattern = "mutable",
    setter(into, strip_option),
    default
)]
#[builder(build_fn(error = "OpenAIError"))]
pub struct InputFileContent {
    /// The content of the file to be sent to the model.
    #[serde(skip_serializing_if = "Option::is_none")]
    file_data: Option<String>,
    /// The ID of the file to be sent to the model.
    #[serde(skip_serializing_if = "Option::is_none")]
    file_id: Option<String>,
    /// The URL of the file to be sent to the model.
    #[serde(skip_serializing_if = "Option::is_none")]
    file_url: Option<String>,
    /// The name of the file to be sent to the model.
    #[serde(skip_serializing_if = "Option::is_none")]
    filename: Option<String>,
}

/// The conversation that this response belonged to. Input items and output items from this
/// response were automatically added to this conversation.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct Conversation {
    /// The unique ID of the conversation that this response was associated with.
    pub id: String,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
#[serde(untagged)]
pub enum ConversationParam {
    /// The unique ID of the conversation.
    ConversationID(String),
    /// The conversation that this response belongs to.
    Object(Conversation),
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, ToSchema)]
pub enum IncludeEnum {
    #[serde(rename = "file_search_call.results")]
    FileSearchCallResults,
    #[serde(rename = "web_search_call.results")]
    WebSearchCallResults,
    #[serde(rename = "web_search_call.action.sources")]
    WebSearchCallActionSources,
    #[serde(rename = "message.input_image.image_url")]
    MessageInputImageImageUrl,
    #[serde(rename = "computer_call_output.output.image_url")]
    ComputerCallOutputOutputImageUrl,
    #[serde(rename = "code_interpreter_call.outputs")]
    CodeInterpreterCallOutputs,
    #[serde(rename = "reasoning.encrypted_content")]
    ReasoningEncryptedContent,
    #[serde(rename = "message.output_text.logprobs")]
    MessageOutputTextLogprobs,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct ResponseStreamOptions {
    /// When true, stream obfuscation will be enabled. Stream obfuscation adds
    /// random characters to an `obfuscation` field on streaming delta events to
    /// normalize payload sizes as a mitigation to certain side-channel attacks.
    /// These obfuscation fields are included by default, but add a small amount
    /// of overhead to the data stream. You can set `include_obfuscation` to
    /// false to optimize for bandwidth if you trust the network links between
    /// your application and the OpenAI API.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub include_obfuscation: Option<bool>,
}

/// Builder for a Responses API request.
#[derive(Clone, Serialize, Deserialize, Debug, Default, Builder, PartialEq, ToSchema)]
#[builder(
    name = "CreateResponseArgs",
    pattern = "mutable",
    setter(into, strip_option),
    default
)]
#[builder(build_fn(error = "OpenAIError"))]
pub struct CreateResponse {
    /// Whether to run the model response in the background.
    /// [Learn more](https://platform.openai.com/docs/guides/background).
    #[serde(skip_serializing_if = "Option::is_none")]
    pub background: Option<bool>,

    /// The conversation that this response belongs to. Items from this conversation are prepended to
    ///  `input_items` for this response request.
    ///
    /// Input items and output items from this response are automatically added to this conversation after
    /// this response completes.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub conversation: Option<ConversationParam>,

    /// Specify additional output data to include in the model response. Currently supported
    /// values are:
    ///
    /// - `web_search_call.action.sources`: Include the sources of the web search tool call.
    ///
    /// - `code_interpreter_call.outputs`: Includes the outputs of python code execution in code
    ///   interpreter tool call items.
    ///
    /// - `computer_call_output.output.image_url`: Include image urls from the computer call
    ///   output.
    ///
    /// - `file_search_call.results`: Include the search results of the file search tool call.
    ///
    /// - `message.input_image.image_url`: Include image urls from the input message.
    ///
    /// - `message.output_text.logprobs`: Include logprobs with assistant messages.
    ///
    /// - `reasoning.encrypted_content`: Includes an encrypted version of reasoning tokens in
    ///   reasoning item outputs. This enables reasoning items to be used in multi-turn
    ///   conversations when using the Responses API statelessly (like when the `store` parameter is
    ///   set to `false`, or when an organization is enrolled in the zero data retention program).
    #[serde(skip_serializing_if = "Option::is_none")]
    pub include: Option<Vec<IncludeEnum>>,

    /// Text, image, or file inputs to the model, used to generate a response.
    ///
    /// Learn more:
    /// - [Text inputs and outputs](https://platform.openai.com/docs/guides/text)
    /// - [Image inputs](https://platform.openai.com/docs/guides/images)
    /// - [File inputs](https://platform.openai.com/docs/guides/pdf-files)
    /// - [Conversation state](https://platform.openai.com/docs/guides/conversation-state)
    /// - [Function calling](https://platform.openai.com/docs/guides/function-calling)
    pub input: InputParam,

    /// A system (or developer) message inserted into the model's context.
    ///
    /// When using along with `previous_response_id`, the instructions from a previous
    /// response will not be carried over to the next response. This makes it simple
    /// to swap out system (or developer) messages in new responses.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub instructions: Option<String>,

    /// An upper bound for the number of tokens that can be generated for a response, including
    /// visible output tokens and [reasoning tokens](https://platform.openai.com/docs/guides/reasoning).
    #[serde(skip_serializing_if = "Option::is_none")]
    pub max_output_tokens: Option<u32>,

    /// The maximum number of total calls to built-in tools that can be processed in a response. This
    /// maximum number applies across all built-in tool calls, not per individual tool. Any further
    /// attempts to call a tool by the model will be ignored.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub max_tool_calls: Option<u32>,

    /// Set of 16 key-value pairs that can be attached to an object. This can be
    /// useful for storing additional information about the object in a structured
    /// format, and querying for objects via API or the dashboard.
    ///
    /// Keys are strings with a maximum length of 64 characters. Values are
    /// strings with a maximum length of 512 characters.
    #[serde(skip_serializing_if = "Option::is_none")]
    #[schema(value_type = Object)]
    pub metadata: Option<serde_json::Value>,

    /// Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI
    /// offers a wide range of models with different capabilities, performance
    /// characteristics, and price points. Refer to the [model guide](https://platform.openai.com/docs/models)
    /// to browse and compare available models.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub model: Option<String>,

    /// Whether to allow the model to run tool calls in parallel.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub parallel_tool_calls: Option<bool>,

    /// The unique ID of the previous response to the model. Use this to create multi-turn conversations.
    /// Learn more about [conversation state](https://platform.openai.com/docs/guides/conversation-state).
    /// Cannot be used in conjunction with `conversation`.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub previous_response_id: Option<String>,

    /// Reference to a prompt template and its variables.
    /// [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts).
    #[serde(skip_serializing_if = "Option::is_none")]
    pub prompt: Option<Prompt>,

    /// Used by OpenAI to cache responses for similar requests to optimize your cache hit rates. Replaces
    /// the `user` field. [Learn more](https://platform.openai.com/docs/guides/prompt-caching).
    #[serde(skip_serializing_if = "Option::is_none")]
    pub prompt_cache_key: Option<String>,

    /// The retention policy for the prompt cache. Set to `24h` to enable extended prompt caching,
    /// which keeps cached prefixes active for longer, up to a maximum of 24 hours. [Learn
    /// more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention).
    #[serde(skip_serializing_if = "Option::is_none")]
    pub prompt_cache_retention: Option<PromptCacheRetention>,

    /// **gpt-5 and o-series models only**
    /// Configuration options for [reasoning models](https://platform.openai.com/docs/guides/reasoning).
    #[serde(skip_serializing_if = "Option::is_none")]
    pub reasoning: Option<Reasoning>,

    /// A stable identifier used to help detect users of your application that may be violating OpenAI's
    /// usage policies.
    ///
    /// The IDs should be a string that uniquely identifies each user. We recommend hashing their username
    /// or email address, in order to avoid sending us any identifying information. [Learn
    /// more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers).
    #[serde(skip_serializing_if = "Option::is_none")]
    pub safety_identifier: Option<String>,

    /// Specifies the processing type used for serving the request.
    /// - If set to 'auto', then the request will be processed with the service tier configured in the Project settings. Unless otherwise configured, the Project will use 'default'.
    /// - If set to 'default', then the request will be processed with the standard pricing and performance for the selected model.
    /// - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or '[priority](https://openai.com/api-priority-processing/)', then the request will be processed with the corresponding service tier.
    /// - When not set, the default behavior is 'auto'.
    ///
    /// When the `service_tier` parameter is set, the response body will include the `service_tier` value based on the processing mode actually used to serve the request. This response value may be different from the value set in the parameter.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub service_tier: Option<ServiceTier>,

    /// Whether to store the generated model response for later retrieval via API.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub store: Option<bool>,

    /// If set to true, the model response data will be streamed to the client
    /// as it is generated using [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format).
    /// See the [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming)
    /// for more information.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub stream: Option<bool>,

    /// Options for streaming responses. Only set this when you set `stream: true`.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub stream_options: Option<ResponseStreamOptions>,

    /// What sampling temperature to use, between 0 and 2. Higher values like 0.8
    /// will make the output more random, while lower values like 0.2 will make it
    /// more focused and deterministic. We generally recommend altering this or
    /// `top_p` but not both.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub temperature: Option<f32>,

    /// Configuration options for a text response from the model. Can be plain
    /// text or structured JSON data. Learn more:
    /// - [Text inputs and outputs](https://platform.openai.com/docs/guides/text)
    /// - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub text: Option<ResponseTextParam>,

    /// How the model should select which tool (or tools) to use when generating
    /// a response. See the `tools` parameter to see how to specify which tools
    /// the model can call.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub tool_choice: Option<ToolChoiceParam>,

    /// An array of tools the model may call while generating a response. You
    /// can specify which tool to use by setting the `tool_choice` parameter.
    ///
    /// We support the following categories of tools:
    /// - **Built-in tools**: Tools that are provided by OpenAI that extend the
    ///   model's capabilities, like [web search](https://platform.openai.com/docs/guides/tools-web-search)
    ///   or [file search](https://platform.openai.com/docs/guides/tools-file-search). Learn more about
    ///   [built-in tools](https://platform.openai.com/docs/guides/tools).
    /// - **MCP Tools**: Integrations with third-party systems via custom MCP servers
    ///   or predefined connectors such as Google Drive and SharePoint. Learn more about
    ///   [MCP Tools](https://platform.openai.com/docs/guides/tools-connectors-mcp).
    /// - **Function calls (custom tools)**: Functions that are defined by you,
    ///   enabling the model to call your own code with strongly typed arguments
    ///   and outputs. Learn more about
    ///   [function calling](https://platform.openai.com/docs/guides/function-calling). You can also use
    ///   custom tools to call your own code.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub tools: Option<Vec<Tool>>,

    /// An integer between 0 and 20 specifying the number of most likely tokens to return at each
    /// token position, each with an associated log probability.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub top_logprobs: Option<u8>,

    /// An alternative to sampling with temperature, called nucleus sampling,
    /// where the model considers the results of the tokens with top_p probability
    /// mass. So 0.1 means only the tokens comprising the top 10% probability mass
    /// are considered.
    ///
    /// We generally recommend altering this or `temperature` but not both.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub top_p: Option<f32>,

    ///The truncation strategy to use for the model response.
    /// - `auto`: If the input to this Response exceeds
    ///   the model's context window size, the model will truncate the
    ///   response to fit the context window by dropping items from the beginning of the conversation.
    /// - `disabled` (default): If the input size will exceed the context window
    ///   size for a model, the request will fail with a 400 error.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub truncation: Option<Truncation>,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
#[serde(untagged)]
pub enum ResponsePromptVariables {
    String(String),
    Content(InputContent),
    Custom(serde_json::Value),
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct Prompt {
    /// The unique identifier of the prompt template to use.
    pub id: String,

    /// Optional version of the prompt template.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub version: Option<String>,

    /// Optional map of values to substitute in for variables in your
    /// prompt. The substitution values can either be strings, or other
    /// Response input types like images or files.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub variables: Option<ResponsePromptVariables>,
}

#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Default, ToSchema)]
#[serde(rename_all = "lowercase")]
pub enum ServiceTier {
    #[default]
    Auto,
    Default,
    Flex,
    Scale,
    Priority,
}

/// Truncation strategies.
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, ToSchema)]
#[serde(rename_all = "lowercase")]
pub enum Truncation {
    Auto,
    Disabled,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct Billing {
    pub payer: String,
}

/// o-series reasoning settings.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default, Builder, ToSchema)]
#[builder(
    name = "ReasoningArgs",
    pattern = "mutable",
    setter(into, strip_option),
    default
)]
#[builder(build_fn(error = "OpenAIError"))]
pub struct Reasoning {
    /// Constrains effort on reasoning for
    /// [reasoning models](https://platform.openai.com/docs/guides/reasoning).
    /// Currently supported values are `minimal`, `low`, `medium`, and `high`. Reducing
    /// reasoning effort can result in faster responses and fewer tokens used
    /// on reasoning in a response.
    ///
    /// Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub effort: Option<ReasoningEffort>,
    /// A summary of the reasoning performed by the model. This can be
    /// useful for debugging and understanding the model's reasoning process.
    /// One of `auto`, `concise`, or `detailed`.
    ///
    /// `concise` is supported for `computer-use-preview` models and all reasoning models after
    /// `gpt-5`.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub summary: Option<ReasoningSummary>,
}

/// o-series reasoning settings.
#[derive(Clone, Serialize, Debug, Deserialize, PartialEq, ToSchema)]
#[serde(rename_all = "lowercase")]
pub enum Verbosity {
    Low,
    Medium,
    High,
}

#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, ToSchema)]
#[serde(rename_all = "lowercase")]
pub enum ReasoningSummary {
    Auto,
    Concise,
    Detailed,
}

/// The retention policy for the prompt cache.
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, ToSchema)]
pub enum PromptCacheRetention {
    #[serde(rename = "in-memory")]
    InMemory,
    #[serde(rename = "24h")]
    Hours24,
}

/// Configuration for text response format.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct ResponseTextParam {
    /// An object specifying the format that the model must output.
    ///
    /// Configuring `{ "type": "json_schema" }` enables Structured Outputs,
    /// which ensures the model will match your supplied JSON schema. Learn more in the
    /// [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs).
    ///
    /// The default format is `{ "type": "text" }` with no additional options.
    ///
    /// **Not recommended for gpt-4o and newer models:**
    ///
    /// Setting to `{ "type": "json_object" }` enables the older JSON mode, which
    /// ensures the message the model generates is valid JSON. Using `json_schema`
    /// is preferred for models that support it.
    #[serde(default)]
    pub format: TextResponseFormatConfiguration,

    /// Constrains the verbosity of the model's response. Lower values will result in
    /// more concise responses, while higher values will result in more verbose responses.
    ///
    /// Currently supported values are `low`, `medium`, and `high`.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub verbosity: Option<Verbosity>,
}

#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, ToSchema)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum TextResponseFormatConfiguration {
    /// Default response format. Used to generate text responses.
    #[default]
    Text,
    /// JSON object response format. An older method of generating JSON responses.
    /// Using `json_schema` is recommended for models that support it.
    /// Note that the model will not generate JSON without a system or user message
    /// instructing it to do so.
    JsonObject,
    /// JSON Schema response format. Used to generate structured JSON responses.
    /// Learn more about [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs).
    JsonSchema(ResponseFormatJsonSchema),
}

/// Definitions for model-callable tools.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum Tool {
    /// Defines a function in your own code the model can choose to call. Learn more about [function
    /// calling](https://platform.openai.com/docs/guides/tools).
    Function(FunctionTool),
    /// A tool that searches for relevant content from uploaded files. Learn more about the [file search
    /// tool](https://platform.openai.com/docs/guides/tools-file-search).
    FileSearch(FileSearchTool),
    /// A tool that controls a virtual computer. Learn more about the [computer
    /// use tool](https://platform.openai.com/docs/guides/tools-computer-use).
    ComputerUsePreview(ComputerUsePreviewTool),
    /// Search the Internet for sources related to the prompt. Learn more about the
    /// [web search tool](https://platform.openai.com/docs/guides/tools-web-search).
    WebSearch(WebSearchTool),
    /// type: web_search_2025_08_26
    #[serde(rename = "web_search_2025_08_26")]
    WebSearch20250826(WebSearchTool),
    /// Give the model access to additional tools via remote Model Context Protocol
    /// (MCP) servers. [Learn more about MCP](https://platform.openai.com/docs/guides/tools-remote-mcp).
    Mcp(MCPTool),
    /// A tool that runs Python code to help generate a response to a prompt.
    CodeInterpreter(CodeInterpreterTool),
    /// A tool that generates images using a model like `gpt-image-1`.
    ImageGeneration(ImageGenTool),
    /// A tool that allows the model to execute shell commands in a local environment.
    LocalShell,
    /// A tool that allows the model to execute shell commands.
    Shell,
    /// A custom tool that processes input using a specified format. Learn more about   [custom
    /// tools](https://platform.openai.com/docs/guides/function-calling#custom-tools)
    Custom(CustomToolParam),
    /// This tool searches the web for relevant results to use in a response. Learn more about the [web search
    ///tool](https://platform.openai.com/docs/guides/tools-web-search).
    WebSearchPreview(WebSearchTool),
    /// type: web_search_preview_2025_03_11
    #[serde(rename = "web_search_preview_2025_03_11")]
    WebSearchPreview20250311(WebSearchTool),
    /// Allows the assistant to create, delete, or update files using unified diffs.
    ApplyPatch,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default, Builder, ToSchema)]
pub struct CustomToolParam {
    /// The name of the custom tool, used to identify it in tool calls.
    pub name: String,
    /// Optional description of the custom tool, used to provide more context.
    pub description: Option<String>,
    /// The input format for the custom tool. Default is unconstrained text.
    pub format: CustomToolParamFormat,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default, ToSchema)]
#[serde(tag = "type", rename_all = "lowercase")]
pub enum CustomToolParamFormat {
    /// Unconstrained free-form text.
    #[default]
    Text,
    /// A grammar defined by the user.
    Grammar(CustomGrammarFormatParam),
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default, Builder, ToSchema)]
#[builder(
    name = "FileSearchToolArgs",
    pattern = "mutable",
    setter(into, strip_option),
    default
)]
#[builder(build_fn(error = "OpenAIError"))]
pub struct FileSearchTool {
    /// The IDs of the vector stores to search.
    pub vector_store_ids: Vec<String>,
    /// The maximum number of results to return. This number should be between 1 and 50 inclusive.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub max_num_results: Option<u32>,
    /// A filter to apply.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub filters: Option<Filter>,
    /// Ranking options for search.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub ranking_options: Option<RankingOptions>,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default, Builder, ToSchema)]
#[builder(
    name = "FunctionToolArgs",
    pattern = "mutable",
    setter(into, strip_option),
    default
)]
pub struct FunctionTool {
    /// The name of the function to call.
    pub name: String,
    /// A JSON schema object describing the parameters of the function.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub parameters: Option<serde_json::Value>,
    /// Whether to enforce strict parameter validation. Default `true`.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub strict: Option<bool>,
    /// A description of the function. Used by the model to determine whether or not to call the
    /// function.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct WebSearchToolFilters {
    /// Allowed domains for the search. If not provided, all domains are allowed.
    /// Subdomains of the provided domains are allowed as well.
    ///
    /// Example: `["pubmed.ncbi.nlm.nih.gov"]`
    #[serde(skip_serializing_if = "Option::is_none")]
    pub allowed_domains: Option<Vec<String>>,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default, Builder, ToSchema)]
#[builder(
    name = "WebSearchToolArgs",
    pattern = "mutable",
    setter(into, strip_option),
    default
)]
pub struct WebSearchTool {
    /// Filters for the search.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub filters: Option<WebSearchToolFilters>,
    /// The approximate location of the user.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub user_location: Option<WebSearchApproximateLocation>,
    /// High level guidance for the amount of context window space to use for the search. One of `low`,
    /// `medium`, or `high`. `medium` is the default.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub search_context_size: Option<WebSearchToolSearchContextSize>,
}

#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Default, ToSchema)]
#[serde(rename_all = "lowercase")]
pub enum WebSearchToolSearchContextSize {
    Low,
    #[default]
    Medium,
    High,
}

#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Default, ToSchema)]
#[serde(rename_all = "lowercase")]
pub enum ComputerEnvironment {
    Windows,
    Mac,
    Linux,
    Ubuntu,
    #[default]
    Browser,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default, Builder, ToSchema)]
#[builder(
    name = "ComputerUsePreviewToolArgs",
    pattern = "mutable",
    setter(into, strip_option),
    default
)]
pub struct ComputerUsePreviewTool {
    /// The type of computer environment to control.
    environment: ComputerEnvironment,
    /// The width of the computer display.
    display_width: u32,
    /// The height of the computer display.
    display_height: u32,
}

#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, ToSchema)]
pub enum RankVersionType {
    #[serde(rename = "auto")]
    Auto,
    #[serde(rename = "default-2024-11-15")]
    Default20241115,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct HybridSearch {
    /// The weight of the embedding in the reciprocal ranking fusion.
    pub embedding_weight: f32,
    /// The weight of the text in the reciprocal ranking fusion.
    pub text_weight: f32,
}

/// Options for search result ranking.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct RankingOptions {
    /// Weights that control how reciprocal rank fusion balances semantic embedding matches versus
    /// sparse keyword matches when hybrid search is enabled.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub hybrid_search: Option<HybridSearch>,
    /// The ranker to use for the file search.
    pub ranker: RankVersionType,
    /// The score threshold for the file search, a number between 0 and 1. Numbers closer to 1 will
    /// attempt to return only the most relevant results, but may return fewer results.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub score_threshold: Option<f32>,
}

#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Default, ToSchema)]
#[serde(rename_all = "lowercase")]
pub enum WebSearchApproximateLocationType {
    #[default]
    Approximate,
}

/// Approximate user location for web search.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default, Builder, ToSchema)]
#[builder(
    name = "WebSearchApproximateLocationArgs",
    pattern = "mutable",
    setter(into, strip_option),
    default
)]
#[builder(build_fn(error = "OpenAIError"))]
pub struct WebSearchApproximateLocation {
    /// The type of location approximation. Always `approximate`.
    pub r#type: WebSearchApproximateLocationType,
    /// Free text input for the city of the user, e.g. `San Francisco`.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub city: Option<String>,
    /// The two-letter [ISO country code](https://en.wikipedia.org/wiki/ISO_3166-1) of the user,
    /// e.g. `US`.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub country: Option<String>,
    /// Free text input for the region of the user, e.g. `California`.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub region: Option<String>,
    /// The [IANA timezone](https://timeapi.io/documentation/iana-timezones) of the user, e.g.
    /// `America/Los_Angeles`.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub timezone: Option<String>,
}

/// Container configuration for a code interpreter.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum CodeInterpreterToolContainer {
    /// Configuration for a code interpreter container. Optionally specify the IDs of the
    /// files to run the code on.
    Auto(CodeInterpreterContainerAuto),

    /// The container ID.
    #[serde(untagged)]
    ContainerID(String),
}

/// Auto configuration for code interpreter container.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default, ToSchema)]
pub struct CodeInterpreterContainerAuto {
    /// An optional list of uploaded files to make available to your code.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub file_ids: Option<Vec<String>>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub memory_limit: Option<u64>,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default, Builder, ToSchema)]
#[builder(
    name = "CodeInterpreterToolArgs",
    pattern = "mutable",
    setter(into, strip_option),
    default
)]
#[builder(build_fn(error = "OpenAIError"))]
pub struct CodeInterpreterTool {
    /// The code interpreter container. Can be a container ID or an object that
    /// specifies uploaded file IDs to make available to your code, along with an
    /// optional `memory_limit` setting.
    pub container: CodeInterpreterToolContainer,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct ImageGenToolInputImageMask {
    /// Base64-encoded mask image.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub image_url: Option<String>,
    /// File ID for the mask image.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub file_id: Option<String>,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default, ToSchema)]
#[serde(rename_all = "lowercase")]
pub enum InputFidelity {
    #[default]
    High,
    Low,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default, ToSchema)]
#[serde(rename_all = "lowercase")]
pub enum ImageGenToolModeration {
    #[default]
    Auto,
    Low,
}

/// Image generation tool definition.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default, Builder, ToSchema)]
#[builder(
    name = "ImageGenerationArgs",
    pattern = "mutable",
    setter(into, strip_option),
    default
)]
#[builder(build_fn(error = "OpenAIError"))]
pub struct ImageGenTool {
    /// Background type for the generated image. One of `transparent`,
    /// `opaque`, or `auto`. Default: `auto`.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub background: Option<ImageGenToolBackground>,
    /// Control how much effort the model will exert to match the style and features, especially facial features,
    /// of input images. This parameter is only supported for `gpt-image-1`. Unsupported
    /// for `gpt-image-1-mini`. Supports `high` and `low`. Defaults to `low`.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub input_fidelity: Option<InputFidelity>,
    /// Optional mask for inpainting. Contains `image_url`
    /// (string, optional) and `file_id` (string, optional).
    #[serde(skip_serializing_if = "Option::is_none")]
    pub input_image_mask: Option<ImageGenToolInputImageMask>,
    /// The image generation model to use. Default: `gpt-image-1`.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub model: Option<String>,
    /// Moderation level for the generated image. Default: `auto`.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub moderation: Option<ImageGenToolModeration>,
    /// Compression level for the output image. Default: 100.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub output_compression: Option<u8>,
    /// The output format of the generated image. One of `png`, `webp`, or
    /// `jpeg`. Default: `png`.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub output_format: Option<ImageGenToolOutputFormat>,
    /// Number of partial images to generate in streaming mode, from 0 (default value) to 3.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub partial_images: Option<u8>,
    /// The quality of the generated image. One of `low`, `medium`, `high`,
    /// or `auto`. Default: `auto`.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub quality: Option<ImageGenToolQuality>,
    /// The size of the generated image. One of `1024x1024`, `1024x1536`,
    /// `1536x1024`, or `auto`. Default: `auto`.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub size: Option<ImageGenToolSize>,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default, ToSchema)]
#[serde(rename_all = "lowercase")]
pub enum ImageGenToolBackground {
    Transparent,
    Opaque,
    #[default]
    Auto,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default, ToSchema)]
#[serde(rename_all = "lowercase")]
pub enum ImageGenToolOutputFormat {
    #[default]
    Png,
    Webp,
    Jpeg,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default, ToSchema)]
#[serde(rename_all = "lowercase")]
pub enum ImageGenToolQuality {
    Low,
    Medium,
    High,
    #[default]
    Auto,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default, ToSchema)]
#[serde(rename_all = "lowercase")]
pub enum ImageGenToolSize {
    #[default]
    Auto,
    #[serde(rename = "1024x1024")]
    Size1024x1024,
    #[serde(rename = "1024x1536")]
    Size1024x1536,
    #[serde(rename = "1536x1024")]
    Size1536x1024,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
#[serde(rename_all = "lowercase")]
pub enum ToolChoiceAllowedMode {
    Auto,
    Required,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct ToolChoiceAllowed {
    /// Constrains the tools available to the model to a pre-defined set.
    ///
    /// `auto` allows the model to pick from among the allowed tools and generate a
    /// message.
    ///
    /// `required` requires the model to call one or more of the allowed tools.
    pub mode: ToolChoiceAllowedMode,
    /// A list of tool definitions that the model should be allowed to call.
    ///
    /// For the Responses API, the list of tool definitions might look like:
    /// ```json
    /// [
    ///   { "type": "function", "name": "get_weather" },
    ///   { "type": "mcp", "server_label": "deepwiki" },
    ///   { "type": "image_generation" }
    /// ]
    /// ```
    pub tools: Vec<serde_json::Value>,
}

/// The type of hosted tool the model should to use. Learn more about
/// [built-in tools](https://platform.openai.com/docs/guides/tools).
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ToolChoiceTypes {
    FileSearch,
    WebSearchPreview,
    ComputerUsePreview,
    CodeInterpreter,
    ImageGeneration,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct ToolChoiceFunction {
    /// The name of the function to call.
    pub name: String,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct ToolChoiceMCP {
    /// The name of the tool to call on the server.
    pub name: String,
    /// The label of the MCP server to use.
    pub server_label: String,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct ToolChoiceCustom {
    /// The name of the custom tool to call.
    pub name: String,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ToolChoiceParam {
    /// Constrains the tools available to the model to a pre-defined set.
    AllowedTools(ToolChoiceAllowed),

    /// Use this option to force the model to call a specific function.
    Function(ToolChoiceFunction),

    /// Use this option to force the model to call a specific tool on a remote MCP server.
    Mcp(ToolChoiceMCP),

    /// Use this option to force the model to call a custom tool.
    Custom(ToolChoiceCustom),

    /// Forces the model to call the apply_patch tool when executing a tool call.
    ApplyPatch,

    /// Forces the model to call the function shell tool when a tool call is required.
    Shell,

    /// Indicates that the model should use a built-in tool to generate a response.
    /// [Learn more about built-in tools](https://platform.openai.com/docs/guides/tools).
    #[serde(untagged)]
    Hosted(ToolChoiceTypes),

    /// Controls which (if any) tool is called by the model.
    ///
    /// `none` means the model will not call any tool and instead generates a message.
    ///
    /// `auto` means the model can pick between generating a message or calling one or
    /// more tools.
    ///
    /// `required` means the model must call one or more tools.
    #[serde(untagged)]
    Mode(ToolChoiceOptions),
}

#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, ToSchema)]
#[serde(rename_all = "lowercase")]
pub enum ToolChoiceOptions {
    None,
    Auto,
    Required,
}

/// An error that occurred while generating the response.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct ErrorObject {
    /// A machine-readable error code that was returned.
    pub code: String,
    /// A human-readable description of the error that was returned.
    pub message: String,
}

/// Details about an incomplete response.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct IncompleteDetails {
    /// The reason why the response is incomplete.
    pub reason: String,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct TopLogProb {
    pub bytes: Vec<u8>,
    pub logprob: f64,
    pub token: String,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct LogProb {
    pub bytes: Vec<u8>,
    pub logprob: f64,
    pub token: String,
    pub top_logprobs: Vec<TopLogProb>,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct ResponseTopLobProb {
    /// The log probability of this token.
    pub logprob: f64,
    /// A possible text token.
    pub token: String,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct ResponseLogProb {
    /// The log probability of this token.
    pub logprob: f64,
    /// A possible text token.
    pub token: String,
    /// The log probability of the top 20 most likely tokens.
    pub top_logprobs: Vec<ResponseTopLobProb>,
}

/// A simple text output from the model.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct OutputTextContent {
    /// The annotations of the text output.
    /// Defaults to empty when not provided (e.g., replaying assistant turns as input).
    #[serde(default)]
    pub annotations: Vec<Annotation>,
    pub logprobs: Option<Vec<LogProb>>,
    /// The text output from the model.
    pub text: String,
}

/// An annotation that applies to a span of output text.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum Annotation {
    /// A citation to a file.
    FileCitation(FileCitationBody),
    /// A citation for a web resource used to generate a model response.
    UrlCitation(UrlCitationBody),
    /// A citation for a container file used to generate a model response.
    ContainerFileCitation(ContainerFileCitationBody),
    /// A path to a file.
    FilePath(FilePath),
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct FileCitationBody {
    /// The ID of the file.
    file_id: String,
    /// The filename of the file cited.
    filename: String,
    /// The index of the file in the list of files.
    index: u32,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct UrlCitationBody {
    /// The index of the last character of the URL citation in the message.
    end_index: u32,
    /// The index of the first character of the URL citation in the message.
    start_index: u32,
    /// The title of the web resource.
    title: String,
    /// The URL of the web resource.
    url: String,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct ContainerFileCitationBody {
    /// The ID of the container file.
    container_id: String,
    /// The index of the last character of the container file citation in the message.
    end_index: u32,
    /// The ID of the file.
    file_id: String,
    /// The filename of the container file cited.
    filename: String,
    /// The index of the first character of the container file citation in the message.
    start_index: u32,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct FilePath {
    /// The ID of the file.
    file_id: String,
    /// The index of the file in the list of files.
    index: u32,
}

/// A refusal explanation from the model.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct RefusalContent {
    /// The refusal explanation from the model.
    pub refusal: String,
}

/// A message generated by the model.
///
/// `id` and `status` use `#[serde(default)]` so that clients can feed back a
/// previous assistant message without those fields (e.g. multi-turn
/// conversations where the caller only has the `output_text` content).
/// The `MessageItem` enum is `#[serde(untagged)]` and tries `Output` first;
/// without defaults the missing fields would cause deserialization to fall
/// through to `Input`, which rejects `role: "assistant"`.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct OutputMessage {
    /// The content of the output message.
    pub content: Vec<OutputMessageContent>,
    /// Optional when provided as input (e.g., replaying assistant turns in conversation history).
    /// Always present in model-generated output.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub id: Option<String>,
    /// The role of the output message. Always `assistant`.
    pub role: AssistantRole,
    /// Optional when provided as input (e.g., replaying assistant turns in conversation history).
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub status: Option<OutputStatus>,
    ///// The type of the output message. Always `message`.
    //pub r#type: MessageType,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default, ToSchema)]
#[serde(rename_all = "lowercase")]
pub enum MessageType {
    #[default]
    Message,
}

/// The role for an output message - always `assistant`.
/// This type ensures type safety by only allowing the assistant role.
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Default, ToSchema)]
#[serde(rename_all = "lowercase")]
pub enum AssistantRole {
    #[default]
    Assistant,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum OutputMessageContent {
    /// A text output from the model.
    OutputText(OutputTextContent),
    /// A refusal from the model.
    Refusal(RefusalContent),
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum OutputContent {
    /// A text output from the model.
    OutputText(OutputTextContent),
    /// A refusal from the model.
    Refusal(RefusalContent),
    /// Reasoning text from the model.
    ReasoningText(ReasoningTextContent),
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct ReasoningTextContent {
    /// The reasoning text from the model.
    pub text: String,
}

/// A reasoning item representing the model's chain of thought, including summary paragraphs.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct ReasoningItem {
    /// Unique identifier of the reasoning content.
    pub id: String,
    /// Reasoning summary content.
    pub summary: Vec<SummaryPart>,
    /// Reasoning text content.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub content: Option<Vec<ReasoningTextContent>>,
    /// The encrypted content of the reasoning item - populated when a response is generated with
    /// `reasoning.encrypted_content` in the `include` parameter.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub encrypted_content: Option<String>,
    /// The status of the item. One of `in_progress`, `completed`, or `incomplete`.
    /// Populated when items are returned via API.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub status: Option<OutputStatus>,
}

/// A single summary text fragment from reasoning.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct Summary {
    /// A summary of the reasoning output from the model so far.
    pub text: String,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum SummaryPart {
    SummaryText(Summary),
}

/// File search tool call output.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct FileSearchToolCall {
    /// The unique ID of the file search tool call.
    pub id: String,
    /// The queries used to search for files.
    pub queries: Vec<String>,
    /// The status of the file search tool call. One of `in_progress`, `searching`,
    /// `incomplete`,`failed`, or `completed`.
    pub status: FileSearchToolCallStatus,
    /// The results of the file search tool call.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub results: Option<Vec<FileSearchToolCallResult>>,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum FileSearchToolCallStatus {
    InProgress,
    Searching,
    Incomplete,
    Failed,
    Completed,
}

/// A single result from a file search.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct FileSearchToolCallResult {
    /// Set of 16 key-value pairs that can be attached to an object. This can be useful for storing
    /// additional information about the object in a structured format, and querying for objects
    /// API or the dashboard. Keys are strings with a maximum length of 64 characters
    /// . Values are strings with a maximum length of 512 characters, booleans, or numbers.
    pub attributes: HashMap<String, serde_json::Value>,
    /// The unique ID of the file.
    pub file_id: String,
    /// The name of the file.
    pub filename: String,
    /// The relevance score of the file - a value between 0 and 1.
    pub score: f32,
    /// The text that was retrieved from the file.
    pub text: String,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct ComputerCallSafetyCheckParam {
    /// The ID of the pending safety check.
    pub id: String,
    /// The type of the pending safety check.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub code: Option<String>,
    /// Details about the pending safety check.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub message: Option<String>,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum WebSearchToolCallStatus {
    InProgress,
    Searching,
    Completed,
    Failed,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct WebSearchActionSearchSource {
    /// The type of source. Always `url`.
    pub r#type: String,
    /// The URL of the source.
    pub url: String,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct WebSearchActionSearch {
    /// The search query.
    pub query: String,
    /// The sources used in the search.
    pub sources: Option<Vec<WebSearchActionSearchSource>>,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct WebSearchActionOpenPage {
    /// The URL opened by the model.
    pub url: Option<String>,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct WebSearchActionFind {
    /// The URL of the page searched for the pattern.
    pub url: String,
    /// The pattern or text to search for within the page.
    pub pattern: String,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum WebSearchToolCallAction {
    /// Action type "search" - Performs a web search query.
    Search(WebSearchActionSearch),
    /// Action type "open_page" - Opens a specific URL from search results.
    OpenPage(WebSearchActionOpenPage),
    /// Action type "find": Searches for a pattern within a loaded page.
    Find(WebSearchActionFind),
    /// Action type "find_in_page": https://platform.openai.com/docs/guides/tools-web-search#output-and-citations
    FindInPage(WebSearchActionFind),
}

/// Web search tool call output.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct WebSearchToolCall {
    /// An object describing the specific action taken in this web search call. Includes
    /// details on how the model used the web (search, open_page, find, find_in_page).
    pub action: WebSearchToolCallAction,
    /// The unique ID of the web search tool call.
    pub id: String,
    /// The status of the web search tool call.
    pub status: WebSearchToolCallStatus,
}

/// Output from a computer tool call.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct ComputerToolCall {
    pub action: ComputerAction,
    /// An identifier used when responding to the tool call with output.
    pub call_id: String,
    /// The unique ID of the computer call.
    pub id: String,
    /// The pending safety checks for the computer call.
    pub pending_safety_checks: Vec<ComputerCallSafetyCheckParam>,
    /// The status of the item. One of `in_progress`, `completed`, or `incomplete`.
    /// Populated when items are returned via API.
    pub status: OutputStatus,
}

/// A point in 2D space.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ToSchema)]
pub struct DragPoint {
    /// The x-coordinate.
    pub x: i32,
    /// The y-coordinate.
    pub y: i32,
}

/// Represents all user‐triggered actions.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ToSchema)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ComputerAction {
    /// A click action.
    Click(ClickParam),

    /// A double click action.
    DoubleClick(DoubleClickAction),

    /// A drag action.
    Drag(Drag),

    /// A collection of keypresses the model would like to perform.
    Keypress(KeyPressAction),

    /// A mouse move action.
    Move(Move),

    /// A screenshot action.
    Screenshot,

    /// A scroll action.
    Scroll(Scroll),

    /// An action to type in text.
    Type(Type),

    /// A wait action.
    Wait,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "lowercase")]
pub enum ClickButtonType {
    Left,
    Right,
    Wheel,
    Back,
    Forward,
}

/// A click action.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ToSchema)]
pub struct ClickParam {
    /// Indicates which mouse button was pressed during the click. One of `left`,
    /// `right`, `wheel`, `back`, or `forward`.
    pub button: ClickButtonType,
    /// The x-coordinate where the click occurred.
    pub x: i32,
    /// The y-coordinate where the click occurred.
    pub y: i32,
}

/// A double click action.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ToSchema)]
pub struct DoubleClickAction {
    /// The x-coordinate where the double click occurred.
    pub x: i32,
    /// The y-coordinate where the double click occurred.
    pub y: i32,
}

/// A drag action.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ToSchema)]
pub struct Drag {
    /// The path of points the cursor drags through.
    pub path: Vec<DragPoint>,
}

/// A keypress action.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ToSchema)]
pub struct KeyPressAction {
    /// The combination of keys the model is requesting to be pressed.
    /// This is an array of strings, each representing a key.
    pub keys: Vec<String>,
}

/// A mouse move action.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ToSchema)]
pub struct Move {
    /// The x-coordinate to move to.
    pub x: i32,
    /// The y-coordinate to move to.
    pub y: i32,
}

/// A scroll action.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ToSchema)]
pub struct Scroll {
    /// The horizontal scroll distance.
    pub scroll_x: i32,
    /// The vertical scroll distance.
    pub scroll_y: i32,
    /// The x-coordinate where the scroll occurred.
    pub x: i32,
    /// The y-coordinate where the scroll occurred.
    pub y: i32,
}

/// A typing (text entry) action.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ToSchema)]
pub struct Type {
    /// The text to type.
    pub text: String,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct FunctionToolCall {
    /// A JSON string of the arguments to pass to the function.
    pub arguments: String,
    /// The unique ID of the function tool call generated by the model.
    pub call_id: String,
    /// The name of the function to run.
    pub name: String,
    /// The unique ID of the function tool call.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub id: Option<String>,
    /// The status of the item. One of `in_progress`, `completed`, or `incomplete`.
    /// Populated when items are returned via API.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub status: Option<OutputStatus>, // TODO rename OutputStatus?
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum ImageGenToolCallStatus {
    InProgress,
    Completed,
    Generating,
    Failed,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct ImageGenToolCall {
    /// The unique ID of the image generation call.
    pub id: String,
    /// The generated image encoded in base64.
    pub result: Option<String>,
    /// The status of the image generation call.
    pub status: ImageGenToolCallStatus,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum CodeInterpreterToolCallStatus {
    InProgress,
    Completed,
    Incomplete,
    Interpreting,
    Failed,
}

/// Output of a code interpreter request.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct CodeInterpreterToolCall {
    /// The code to run, or null if not available.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub code: Option<String>,
    /// ID of the container used to run the code.
    pub container_id: String,
    /// The unique ID of the code interpreter tool call.
    pub id: String,
    /// The outputs generated by the code interpreter, such as logs or images.
    /// Can be null if no outputs are available.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub outputs: Option<Vec<CodeInterpreterToolCallOutput>>,
    /// The status of the code interpreter tool call.
    /// Valid values are `in_progress`, `completed`, `incomplete`, `interpreting`, and `failed`.
    pub status: CodeInterpreterToolCallStatus,
}

/// Individual result from a code interpreter: either logs or files.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum CodeInterpreterToolCallOutput {
    /// Code interpreter output logs
    Logs(CodeInterpreterOutputLogs),
    /// Code interpreter output image
    Image(CodeInterpreterOutputImage),
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct CodeInterpreterOutputLogs {
    /// The logs output from the code interpreter.
    pub logs: String,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct CodeInterpreterOutputImage {
    /// The URL of the image output from the code interpreter.
    pub url: String,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct CodeInterpreterFile {
    /// The ID of the file.
    file_id: String,
    /// The MIME type of the file.
    mime_type: String,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct LocalShellToolCall {
    /// Execute a shell command on the server.
    pub action: LocalShellExecAction,
    /// The unique ID of the local shell tool call generated by the model.
    pub call_id: String,
    /// The unique ID of the local shell call.
    pub id: String,
    /// The status of the local shell call.
    pub status: OutputStatus,
}

/// Define the shape of a local shell action (exec).
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct LocalShellExecAction {
    /// The command to run.
    pub command: Vec<String>,
    /// Environment variables to set for the command.
    pub env: HashMap<String, String>,
    /// Optional timeout in milliseconds for the command.
    pub timeout_ms: Option<u64>,
    /// Optional user to run the command as.
    pub user: Option<String>,
    /// Optional working directory to run the command in.
    pub working_directory: Option<String>,
}

/// Commands and limits describing how to run the shell tool call.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct FunctionShellActionParam {
    /// Ordered shell commands for the execution environment to run.
    pub commands: Vec<String>,
    /// Maximum wall-clock time in milliseconds to allow the shell commands to run.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub timeout_ms: Option<u64>,
    /// Maximum number of UTF-8 characters to capture from combined stdout and stderr output.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub max_output_length: Option<u64>,
}

/// Status values reported for shell tool calls.
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum FunctionShellCallItemStatus {
    InProgress,
    Completed,
    Incomplete,
}

/// A tool representing a request to execute one or more shell commands.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct FunctionShellCallItemParam {
    /// The unique ID of the shell tool call. Populated when this item is returned via API.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub id: Option<String>,
    /// The unique ID of the shell tool call generated by the model.
    pub call_id: String,
    /// The shell commands and limits that describe how to run the tool call.
    pub action: FunctionShellActionParam,
    /// The status of the shell call. One of `in_progress`, `completed`, or `incomplete`.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub status: Option<FunctionShellCallItemStatus>,
}

/// Indicates that the shell commands finished and returned an exit code.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct FunctionShellCallOutputExitOutcomeParam {
    /// The exit code returned by the shell process.
    pub exit_code: i32,
}

/// The exit or timeout outcome associated with this chunk.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum FunctionShellCallOutputOutcomeParam {
    Timeout,
    Exit(FunctionShellCallOutputExitOutcomeParam),
}

/// Captured stdout and stderr for a portion of a shell tool call output.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct FunctionShellCallOutputContentParam {
    /// Captured stdout output for this chunk of the shell call.
    pub stdout: String,
    /// Captured stderr output for this chunk of the shell call.
    pub stderr: String,
    /// The exit or timeout outcome associated with this chunk.
    pub outcome: FunctionShellCallOutputOutcomeParam,
}

/// The streamed output items emitted by a shell tool call.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct FunctionShellCallOutputItemParam {
    /// The unique ID of the shell tool call output. Populated when this item is returned via API.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub id: Option<String>,
    /// The unique ID of the shell tool call generated by the model.
    pub call_id: String,
    /// Captured chunks of stdout and stderr output, along with their associated outcomes.
    pub output: Vec<FunctionShellCallOutputContentParam>,
    /// The maximum number of UTF-8 characters captured for this shell call's combined output.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub max_output_length: Option<u64>,
}

/// Status values reported for apply_patch tool calls.
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum ApplyPatchCallStatusParam {
    InProgress,
    Completed,
}

/// Instruction for creating a new file via the apply_patch tool.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct ApplyPatchCreateFileOperationParam {
    /// Path of the file to create relative to the workspace root.
    pub path: String,
    /// Unified diff content to apply when creating the file.
    pub diff: String,
}

/// Instruction for deleting an existing file via the apply_patch tool.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct ApplyPatchDeleteFileOperationParam {
    /// Path of the file to delete relative to the workspace root.
    pub path: String,
}

/// Instruction for updating an existing file via the apply_patch tool.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct ApplyPatchUpdateFileOperationParam {
    /// Path of the file to update relative to the workspace root.
    pub path: String,
    /// Unified diff content to apply to the existing file.
    pub diff: String,
}

/// One of the create_file, delete_file, or update_file operations supplied to the apply_patch tool.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ApplyPatchOperationParam {
    CreateFile(ApplyPatchCreateFileOperationParam),
    DeleteFile(ApplyPatchDeleteFileOperationParam),
    UpdateFile(ApplyPatchUpdateFileOperationParam),
}

/// A tool call representing a request to create, delete, or update files using diff patches.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct ApplyPatchToolCallItemParam {
    /// The unique ID of the apply patch tool call. Populated when this item is returned via API.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub id: Option<String>,
    /// The unique ID of the apply patch tool call generated by the model.
    pub call_id: String,
    /// The status of the apply patch tool call. One of `in_progress` or `completed`.
    pub status: ApplyPatchCallStatusParam,
    /// The specific create, delete, or update instruction for the apply_patch tool call.
    pub operation: ApplyPatchOperationParam,
}

/// Outcome values reported for apply_patch tool call outputs.
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum ApplyPatchCallOutputStatusParam {
    Completed,
    Failed,
}

/// The streamed output emitted by an apply patch tool call.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct ApplyPatchToolCallOutputItemParam {
    /// The unique ID of the apply patch tool call output. Populated when this item is returned via API.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub id: Option<String>,
    /// The unique ID of the apply patch tool call generated by the model.
    pub call_id: String,
    /// The status of the apply patch tool call output. One of `completed` or `failed`.
    pub status: ApplyPatchCallOutputStatusParam,
    /// Optional human-readable log text from the apply patch tool (e.g., patch results or errors).
    #[serde(skip_serializing_if = "Option::is_none")]
    pub output: Option<String>,
}

/// Shell exec action
/// Execute a shell command.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct FunctionShellAction {
    /// A list of commands to run.
    pub commands: Vec<String>,
    /// Optional timeout in milliseconds for the commands.
    pub timeout_ms: Option<u64>,
    /// Optional maximum number of characters to return from each command.
    pub max_output_length: Option<u64>,
}

/// Status values reported for function shell tool calls.
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum LocalShellCallStatus {
    InProgress,
    Completed,
    Incomplete,
}

/// A tool call that executes one or more shell commands in a managed environment.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct FunctionShellCall {
    /// The unique ID of the function shell tool call. Populated when this item is returned via API.
    pub id: String,
    /// The unique ID of the function shell tool call generated by the model.
    pub call_id: String,
    /// The shell commands and limits that describe how to run the tool call.
    pub action: FunctionShellAction,
    /// The status of the shell call. One of `in_progress`, `completed`, or `incomplete`.
    pub status: LocalShellCallStatus,
    /// The ID of the entity that created this tool call.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub created_by: Option<String>,
}

/// The content of a shell tool call output that was emitted.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct FunctionShellCallOutputContent {
    /// The standard output that was captured.
    pub stdout: String,
    /// The standard error output that was captured.
    pub stderr: String,
    /// Represents either an exit outcome (with an exit code) or a timeout outcome for a shell call output chunk.
    #[serde(flatten)]
    pub outcome: FunctionShellCallOutputOutcome,
    /// The identifier of the actor that created the item.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub created_by: Option<String>,
}

/// Function shell call outcome
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum FunctionShellCallOutputOutcome {
    Timeout,
    Exit(FunctionShellCallOutputExitOutcome),
}

/// Indicates that the shell commands finished and returned an exit code.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct FunctionShellCallOutputExitOutcome {
    /// Exit code from the shell process.
    pub exit_code: i32,
}

/// The output of a shell tool call that was emitted.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct FunctionShellCallOutput {
    /// The unique ID of the shell call output. Populated when this item is returned via API.
    pub id: String,
    /// The unique ID of the shell tool call generated by the model.
    pub call_id: String,
    /// An array of shell call output contents
    pub output: Vec<FunctionShellCallOutputContent>,
    /// The maximum length of the shell command output. This is generated by the model and should be
    /// passed back with the raw output.
    pub max_output_length: Option<u64>,
    /// The identifier of the actor that created the item.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub created_by: Option<String>,
}

/// Status values reported for apply_patch tool calls.
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum ApplyPatchCallStatus {
    InProgress,
    Completed,
}

/// Instruction describing how to create a file via the apply_patch tool.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct ApplyPatchCreateFileOperation {
    /// Path of the file to create.
    pub path: String,
    /// Diff to apply.
    pub diff: String,
}

/// Instruction describing how to delete a file via the apply_patch tool.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct ApplyPatchDeleteFileOperation {
    /// Path of the file to delete.
    pub path: String,
}

/// Instruction describing how to update a file via the apply_patch tool.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct ApplyPatchUpdateFileOperation {
    /// Path of the file to update.
    pub path: String,
    /// Diff to apply.
    pub diff: String,
}

/// One of the create_file, delete_file, or update_file operations applied via apply_patch.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ApplyPatchOperation {
    CreateFile(ApplyPatchCreateFileOperation),
    DeleteFile(ApplyPatchDeleteFileOperation),
    UpdateFile(ApplyPatchUpdateFileOperation),
}

/// A tool call that applies file diffs by creating, deleting, or updating files.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct ApplyPatchToolCall {
    /// The unique ID of the apply patch tool call. Populated when this item is returned via API.
    pub id: String,
    /// The unique ID of the apply patch tool call generated by the model.
    pub call_id: String,
    /// The status of the apply patch tool call. One of `in_progress` or `completed`.
    pub status: ApplyPatchCallStatus,
    /// One of the create_file, delete_file, or update_file operations applied via apply_patch.
    pub operation: ApplyPatchOperation,
    /// The ID of the entity that created this tool call.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub created_by: Option<String>,
}

/// Outcome values reported for apply_patch tool call outputs.
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum ApplyPatchCallOutputStatus {
    Completed,
    Failed,
}

/// The output emitted by an apply patch tool call.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct ApplyPatchToolCallOutput {
    /// The unique ID of the apply patch tool call output. Populated when this item is returned via API.
    pub id: String,
    /// The unique ID of the apply patch tool call generated by the model.
    pub call_id: String,
    /// The status of the apply patch tool call output. One of `completed` or `failed`.
    pub status: ApplyPatchCallOutputStatus,
    /// Optional textual output returned by the apply patch tool.
    pub output: Option<String>,
    /// The ID of the entity that created this tool call output.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub created_by: Option<String>,
}

/// Output of an MCP server tool invocation.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct MCPToolCall {
    /// A JSON string of the arguments passed to the tool.
    pub arguments: String,
    /// The unique ID of the tool call.
    pub id: String,
    /// The name of the tool that was run.
    pub name: String,
    /// The label of the MCP server running the tool.
    pub server_label: String,
    /// Unique identifier for the MCP tool call approval request. Include this value
    /// in a subsequent `mcp_approval_response` input to approve or reject the corresponding
    /// tool call.
    pub approval_request_id: Option<String>,
    /// Error message from the call, if any.
    pub error: Option<String>,
    /// The output from the tool call.
    pub output: Option<String>,
    /// The status of the tool call. One of `in_progress`, `completed`, `incomplete`,
    /// `calling`, or `failed`.
    pub status: Option<MCPToolCallStatus>,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum MCPToolCallStatus {
    InProgress,
    Completed,
    Incomplete,
    Calling,
    Failed,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct MCPListTools {
    /// The unique ID of the list.
    pub id: String,
    /// The label of the MCP server.
    pub server_label: String,
    /// The tools available on the server.
    pub tools: Vec<MCPListToolsTool>,
    /// Error message if listing failed.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub error: Option<String>,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct MCPApprovalRequest {
    /// JSON string of arguments for the tool.
    pub arguments: String,
    /// The unique ID of the approval request.
    pub id: String,
    /// The name of the tool to run.
    pub name: String,
    /// The label of the MCP server making the request.
    pub server_label: String,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
#[serde(untagged)]
pub enum Instructions {
    /// A text input to the model, equivalent to a text input with the `developer` role.
    Text(String),
    /// A list of one or many input items to the model, containing different content types.
    Array(Vec<InputItem>),
}

/// The complete response returned by the Responses API.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
#[schema(no_recursion)]
pub struct Response {
    /// Whether to run the model response in the background.
    /// [Learn more](https://platform.openai.com/docs/guides/background).
    pub background: Option<bool>,

    /// Billing information for the response.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub billing: Option<Billing>,

    /// The conversation that this response belongs to. Input items and output
    /// items from this response are automatically added to this conversation.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub conversation: Option<Conversation>,

    /// Unix timestamp (in seconds) when this Response was created.
    pub created_at: u64,

    /// Unix timestamp (in seconds) of when this Response was completed.
    pub completed_at: Option<u64>,

    /// An error object returned when the model fails to generate a Response.
    pub error: Option<ErrorObject>,

    /// The frequency penalty applied during sampling, between -2.0 and 2.0.
    pub frequency_penalty: Option<f32>,

    /// Unique identifier for this response.
    pub id: String,

    /// Details about why the response is incomplete, if any.
    pub incomplete_details: Option<IncompleteDetails>,

    /// A system (or developer) message inserted into the model's context.
    ///
    /// When using along with `previous_response_id`, the instructions from a previous response
    /// will not be carried over to the next response. This makes it simple to swap out
    /// system (or developer) messages in new responses.
    pub instructions: Option<Instructions>,

    /// An upper bound for the number of tokens that can be generated for a response,
    /// including visible output tokens and
    /// [reasoning tokens](https://platform.openai.com/docs/guides/reasoning).
    pub max_output_tokens: Option<u32>,

    /// An upper bound on the number of tool calls the model can make.
    pub max_tool_calls: Option<u32>,

    /// Set of 16 key-value pairs that can be attached to an object. This can be
    /// useful for storing additional information about the object in a structured
    /// format, and querying for objects via API or the dashboard.
    ///
    /// Keys are strings with a maximum length of 64 characters. Values are strings
    /// with a maximum length of 512 characters.
    #[schema(value_type = Object)]
    pub metadata: Option<serde_json::Value>,

    /// Model ID used to generate the response, like gpt-4o or o3. OpenAI offers a
    /// wide range of models with different capabilities, performance characteristics,
    /// and price points. Refer to the [model guide](https://platform.openai.com/docs/models) to browse and compare available models.
    pub model: String,

    /// The object type of this resource - always set to `response`.
    pub object: String,

    /// An array of content items generated by the model.
    ///
    /// - The length and order of items in the output array is dependent on the model's response.
    /// - Rather than accessing the first item in the output array and assuming it's an assistant
    ///   message with the content generated by the model, you might consider using
    ///   the `output_text` property where supported in SDKs.
    pub output: Vec<OutputItem>,

    /// Whether to allow the model to run tool calls in parallel.
    pub parallel_tool_calls: Option<bool>,

    /// The presence penalty applied during sampling, between -2.0 and 2.0.
    pub presence_penalty: Option<f32>,

    /// The unique ID of the previous response to the model. Use this to create multi-turn conversations.
    /// Learn more about [conversation state](https://platform.openai.com/docs/guides/conversation-state).
    /// Cannot be used in conjunction with `conversation`.
    pub previous_response_id: Option<String>,

    /// Reference to a prompt template and its variables.
    /// [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts).
    #[serde(skip_serializing_if = "Option::is_none")]
    pub prompt: Option<Prompt>,

    /// Used by OpenAI to cache responses for similar requests to optimize your cache hit rates. Replaces
    /// the `user` field. [Learn more](https://platform.openai.com/docs/guides/prompt-caching).
    pub prompt_cache_key: Option<String>,

    /// The retention policy for the prompt cache. Set to `24h` to enable extended prompt caching,
    /// which keeps cached prefixes active for longer, up to a maximum of 24 hours. [Learn
    /// more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention).
    #[serde(skip_serializing_if = "Option::is_none")]
    pub prompt_cache_retention: Option<PromptCacheRetention>,

    /// **gpt-5 and o-series models only**
    /// Configuration options for [reasoning models](https://platform.openai.com/docs/guides/reasoning).
    pub reasoning: Option<Reasoning>,

    /// A stable identifier used to help detect users of your application that may be violating OpenAI's
    /// usage policies.
    pub safety_identifier: Option<String>,

    /// Specifies the processing type used for serving the request.
    pub service_tier: Option<ServiceTier>,

    /// The status of the response generation.
    /// One of `completed`, `failed`, `in_progress`, `cancelled`, `queued`, or `incomplete`.
    pub status: Status,

    /// Whether the response is stored for later retrieval.
    pub store: Option<bool>,

    /// What sampling temperature was used, between 0 and 2. Higher values like 0.8 make
    /// outputs more random, lower values like 0.2 make output more focused and deterministic.
    pub temperature: Option<f32>,

    /// Configuration options for a text response from the model. Can be plain
    /// text or structured JSON data.
    pub text: Option<ResponseTextParam>,

    /// How the model should select which tool (or tools) to use when generating
    /// a response.
    pub tool_choice: Option<ToolChoiceParam>,

    /// An array of tools the model may call while generating a response.
    pub tools: Option<Vec<Tool>>,

    /// An integer between 0 and 20 specifying the number of most likely tokens to return at each
    /// token position, each with an associated log probability.
    pub top_logprobs: Option<u8>,

    /// An alternative to sampling with temperature, called nucleus sampling,
    /// where the model considers the results of the tokens with top_p probability
    /// mass. So 0.1 means only the tokens comprising the top 10% probability mass
    /// are considered.
    pub top_p: Option<f32>,

    /// The truncation strategy to use for the model response.
    pub truncation: Option<Truncation>,

    /// Represents token usage details including input tokens, output tokens,
    /// a breakdown of output tokens, and the total tokens used.
    pub usage: Option<ResponseUsage>,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum Status {
    Completed,
    Failed,
    InProgress,
    Cancelled,
    Queued,
    Incomplete,
}

/// Output item
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
#[schema(no_recursion)]
#[serde(tag = "type")]
#[serde(rename_all = "snake_case")]
pub enum OutputItem {
    /// An output message from the model.
    Message(OutputMessage),
    /// The results of a file search tool call. See the
    /// [file search guide](https://platform.openai.com/docs/guides/tools-file-search)
    /// for more information.
    FileSearchCall(FileSearchToolCall),
    /// A tool call to run a function. See the
    /// [function calling guide](https://platform.openai.com/docs/guides/function-calling)
    /// for more information.
    FunctionCall(FunctionToolCall),
    /// The results of a web search tool call. See the
    /// [web search guide](https://platform.openai.com/docs/guides/tools-web-search)
    /// for more information.
    WebSearchCall(WebSearchToolCall),
    /// A tool call to a computer use tool. See the
    /// [computer use guide](https://platform.openai.com/docs/guides/tools-computer-use)
    /// for more information.
    ComputerCall(ComputerToolCall),
    /// A description of the chain of thought used by a reasoning model while generating
    /// a response. Be sure to include these items in your `input` to the Responses API for
    /// subsequent turns of a conversation if you are manually
    /// [managing context](https://platform.openai.com/docs/guides/conversation-state).
    Reasoning(ReasoningItem),
    /// A compaction item generated by the [`v1/responses/compact` API](https://platform.openai.com/docs/api-reference/responses/compact).
    Compaction(CompactionBody),
    /// An image generation request made by the model.
    ImageGenerationCall(ImageGenToolCall),
    /// A tool call to run code.
    CodeInterpreterCall(CodeInterpreterToolCall),
    /// A tool call to run a command on the local shell.
    LocalShellCall(LocalShellToolCall),
    /// A tool call that executes one or more shell commands in a managed environment.
    ShellCall(FunctionShellCall),
    /// The output of a shell tool call.
    ShellCallOutput(FunctionShellCallOutput),
    /// A tool call that applies file diffs by creating, deleting, or updating files.
    ApplyPatchCall(ApplyPatchToolCall),
    /// The output emitted by an apply patch tool call.
    ApplyPatchCallOutput(ApplyPatchToolCallOutput),
    /// An invocation of a tool on an MCP server.
    McpCall(MCPToolCall),
    /// A list of tools available on an MCP server.
    McpListTools(MCPListTools),
    /// A request for human approval of a tool invocation.
    McpApprovalRequest(MCPApprovalRequest),
    /// A call to a custom tool created by the model.
    CustomToolCall(CustomToolCall),
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
#[non_exhaustive]
pub struct CustomToolCall {
    /// An identifier used to map this custom tool call to a tool call output.
    pub call_id: String,
    /// The input for the custom tool call generated by the model.
    pub input: String,
    /// The name of the custom tool being called.
    pub name: String,
    /// The unique ID of the custom tool call in the OpenAI platform.
    pub id: String,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct DeleteResponse {
    pub object: String,
    pub deleted: bool,
    pub id: String,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct AnyItemReference {
    pub r#type: Option<String>,
    pub id: String,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ItemResourceItem {
    Message(MessageItem),
    FileSearchCall(FileSearchToolCall),
    ComputerCall(ComputerToolCall),
    ComputerCallOutput(ComputerCallOutputItemParam),
    WebSearchCall(WebSearchToolCall),
    FunctionCall(FunctionToolCall),
    FunctionCallOutput(FunctionCallOutputItemParam),
    ImageGenerationCall(ImageGenToolCall),
    CodeInterpreterCall(CodeInterpreterToolCall),
    LocalShellCall(LocalShellToolCall),
    LocalShellCallOutput(LocalShellToolCallOutput),
    ShellCall(FunctionShellCallItemParam),
    ShellCallOutput(FunctionShellCallOutputItemParam),
    ApplyPatchCall(ApplyPatchToolCallItemParam),
    ApplyPatchCallOutput(ApplyPatchToolCallOutputItemParam),
    McpListTools(MCPListTools),
    McpApprovalRequest(MCPApprovalRequest),
    McpApprovalResponse(MCPApprovalResponse),
    McpCall(MCPToolCall),
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
#[serde(untagged)]
pub enum ItemResource {
    ItemReference(AnyItemReference),
    Item(ItemResourceItem),
}

/// A list of Response items.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct ResponseItemList {
    /// The type of object returned, must be `list`.
    pub object: String,
    /// The ID of the first item in the list.
    pub first_id: Option<String>,
    /// The ID of the last item in the list.
    pub last_id: Option<String>,
    /// Whether there are more items in the list.
    pub has_more: bool,
    /// The list of items.
    pub data: Vec<ItemResource>,
}

#[derive(Clone, Serialize, Deserialize, Debug, Default, Builder, PartialEq, ToSchema)]
#[builder(
    name = "TokenCountsBodyArgs",
    pattern = "mutable",
    setter(into, strip_option),
    default
)]
#[builder(build_fn(error = "OpenAIError"))]
pub struct TokenCountsBody {
    /// The conversation that this response belongs to. Items from this
    /// conversation are prepended to `input_items` for this response request.
    /// Input items and output items from this response are automatically added to this
    /// conversation after this response completes.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub conversation: Option<ConversationParam>,

    /// Text, image, or file inputs to the model, used to generate a response
    #[serde(skip_serializing_if = "Option::is_none")]
    pub input: Option<InputParam>,

    /// A system (or developer) message inserted into the model's context.
    ///
    /// When used along with `previous_response_id`, the instructions from a previous response will
    /// not be carried over to the next response. This makes it simple to swap out system (or
    /// developer) messages in new responses.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub instructions: Option<String>,

    /// Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a
    /// wide range of models with different capabilities, performance characteristics,
    /// and price points. Refer to the [model guide](https://platform.openai.com/docs/models)
    /// to browse and compare available models.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub model: Option<String>,

    /// Whether to allow the model to run tool calls in parallel.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub parallel_tool_calls: Option<bool>,

    /// The unique ID of the previous response to the model. Use this to create multi-turn
    /// conversations. Learn more about [conversation state](https://platform.openai.com/docs/guides/conversation-state).
    /// Cannot be used in conjunction with `conversation`.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub previous_response_id: Option<String>,

    /// **gpt-5 and o-series models only**
    /// Configuration options for [reasoning models](https://platform.openai.com/docs/guides/reasoning).
    #[serde(skip_serializing_if = "Option::is_none")]
    pub reasoning: Option<Reasoning>,

    /// Configuration options for a text response from the model. Can be plain
    /// text or structured JSON data. Learn more:
    /// - [Text inputs and outputs](https://platform.openai.com/docs/guides/text)
    /// - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub text: Option<ResponseTextParam>,

    /// How the model should select which tool (or tools) to use when generating
    /// a response. See the `tools` parameter to see how to specify which tools
    /// the model can call.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub tool_choice: Option<ToolChoiceParam>,

    /// An array of tools the model may call while generating a response. You can specify which tool
    /// to use by setting the `tool_choice` parameter.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub tools: Option<Vec<Tool>>,

    ///The truncation strategy to use for the model response.
    /// - `auto`: If the input to this Response exceeds
    ///   the model's context window size, the model will truncate the
    ///   response to fit the context window by dropping items from the beginning of the conversation.
    /// - `disabled` (default): If the input size will exceed the context window
    ///   size for a model, the request will fail with a 400 error.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub truncation: Option<Truncation>,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct TokenCountsResource {
    pub object: String,
    pub input_tokens: u32,
}

/// A compaction item generated by the `/v1/responses/compact` API.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct CompactionSummaryItemParam {
    /// The ID of the compaction item.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub id: Option<String>,
    /// The encrypted content of the compaction summary.
    pub encrypted_content: String,
}

/// A compaction item generated by the `/v1/responses/compact` API.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct CompactionBody {
    /// The unique ID of the compaction item.
    pub id: String,
    /// The encrypted content that was produced by compaction.
    pub encrypted_content: String,
    /// The identifier of the actor that created the item.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub created_by: Option<String>,
}

/// Request to compact a conversation.
#[derive(Clone, Serialize, Default, Debug, Deserialize, Builder, PartialEq, ToSchema)]
#[builder(name = "CompactResponseRequestArgs")]
#[builder(pattern = "mutable")]
#[builder(setter(into, strip_option), default)]
#[builder(derive(Debug))]
#[builder(build_fn(error = "OpenAIError"))]
pub struct CompactResponseRequest {
    /// Model ID used to generate the response, like `gpt-5` or `o3`. OpenAI offers a wide range of models
    /// with different capabilities, performance characteristics, and price points. Refer to the
    /// [model guide](https://platform.openai.com/docs/models) to browse and compare available models.
    pub model: String,

    /// Text, image, or file inputs to the model, used to generate a response
    #[serde(skip_serializing_if = "Option::is_none")]
    pub input: Option<InputParam>,

    /// The unique ID of the previous response to the model. Use this to create multi-turn
    /// conversations. Learn more about [conversation state](https://platform.openai.com/docs/guides/conversation-state).
    /// Cannot be used in conjunction with `conversation`.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub previous_response_id: Option<String>,

    /// A system (or developer) message inserted into the model's context.
    ///
    /// When used along with `previous_response_id`, the instructions from a previous response will
    /// not be carried over to the next response. This makes it simple to swap out system (or
    /// developer) messages in new responses.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub instructions: Option<String>,
}

/// The compacted response object.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
pub struct CompactResource {
    /// The unique identifier for the compacted response.
    pub id: String,
    /// The object type. Always `response.compaction`.
    pub object: String,
    /// The compacted list of output items. This is a list of all user messages,
    /// followed by a single compaction item.
    pub output: Vec<OutputItem>,
    /// Unix timestamp (in seconds) when the compacted conversation was created.
    pub created_at: u64,
    /// Token accounting for the compaction pass, including cached, reasoning, and total tokens.
    pub usage: ResponseUsage,
}

#[cfg(test)]
mod tests {
    use super::*;

    /// Issue #6: Assistant messages with output_text content should deserialize
    /// without requiring `id` and `status` fields. Clients replay previous
    /// assistant turns in conversation history without output metadata.
    #[test]
    fn test_assistant_output_text_without_id_status() {
        let json = r#"{
            "role": "assistant",
            "content": [{"type": "output_text", "text": "Hello!"}],
            "type": "message"
        }"#;
        let item: InputItem = serde_json::from_str(json)
            .expect("assistant output_text without id/status should deserialize");
        match &item {
            InputItem::Item(Item::Message(MessageItem::Output(out_msg))) => {
                assert!(out_msg.id.is_none());
                assert!(out_msg.status.is_none());
                assert_eq!(out_msg.content.len(), 1);
            }
            other => panic!("expected OutputMessage, got {:?}", other),
        }
    }

    /// Issue #6 extended: full multi-turn conversation with output_text history.
    #[test]
    fn test_multiturn_with_output_text_history() {
        let json = r#"{
            "model": "test-model",
            "input": [
                {"role": "user", "content": "hi", "type": "message"},
                {
                    "role": "assistant",
                    "content": [{"type": "output_text", "text": "Hello!"}],
                    "type": "message"
                },
                {"role": "user", "content": "bye", "type": "message"}
            ],
            "stream": false
        }"#;
        let request: CreateResponse = serde_json::from_str(json)
            .expect("multi-turn with output_text history should deserialize");
        match &request.input {
            InputParam::Items(items) => assert_eq!(items.len(), 3),
            other => panic!("expected Items, got {:?}", other),
        }
    }

    /// Issue #7: Reasoning items in the input array should deserialize.
    #[test]
    fn test_reasoning_item_in_input() {
        let json = r#"{
            "type": "reasoning",
            "id": "rs_1",
            "summary": [{"text": "thinking", "type": "summary_text"}]
        }"#;
        let item: InputItem =
            serde_json::from_str(json).expect("reasoning item should deserialize");
        match &item {
            InputItem::Item(Item::Reasoning(r)) => {
                assert_eq!(r.id, "rs_1");
                assert_eq!(r.summary.len(), 1);
            }
            other => panic!("expected Reasoning item, got {:?}", other),
        }
    }

    /// OutputMessage with id and status should still work (backwards compat).
    #[test]
    fn test_output_message_with_id_and_status() {
        let json = r#"{
            "role": "assistant",
            "id": "msg_abc123",
            "status": "completed",
            "content": [{"type": "output_text", "text": "Hello!"}],
            "type": "message"
        }"#;
        let item: InputItem = serde_json::from_str(json)
            .expect("output message with id/status should still deserialize");
        match &item {
            InputItem::Item(Item::Message(MessageItem::Output(out_msg))) => {
                assert_eq!(out_msg.id.as_deref(), Some("msg_abc123"));
                assert_eq!(out_msg.status, Some(OutputStatus::Completed));
            }
            other => panic!("expected OutputMessage, got {:?}", other),
        }
    }
}
