api_openai 0.3.0

OpenAI's API for accessing large language models (LLMs).
Documentation
// src/components/output.rs
//! Structures related to output items generated by the model, such as messages, tool calls, and annotations.

/// Define a private namespace for all its items.
mod private
{
  use crate::components::common::{ VectorStoreFileAttributes, Reasoning };
  use crate::components::input::ListedInputContentPart;
  use crate::components::responses::OutputMessage;
  use crate::components::tools::
  {
    FileSearchToolCall,
    FunctionToolCall,
    WebSearchToolCall,
    ComputerToolCall,
  };

  // Standard library imports
  use core::fmt;
  // Serde imports
  use serde::{ Deserialize, Serialize };
  use serde::
  {
    de ::{ self, Deserializer, MapAccess, Visitor },
  };

  // --- Annotation Structs (Restored) ---

  /// Inner data for a file citation annotation.
  ///
  /// # Used By
  /// - `Annotation::FileCitation`
  /// - `MessageContentTextAnnotationsFileCitationObject` (within `assistants_shared.rs`)
  #[ derive( Debug, Serialize, Deserialize, Clone, PartialEq ) ]
  pub struct FileCitationAnnotation
  {
    /// The ID of the specific File the citation is from.
    pub file_id : String,
  }

  /// Inner data for a URL citation annotation.
  ///
  /// # Used By
  /// - `Annotation::UrlCitation`
  /// - `ChatCompletionResponseMessage` (within `chat_shared.rs`)
  #[ derive( Debug, Serialize, Deserialize, Clone, PartialEq ) ]
  pub struct UrlCitationAnnotation
  {
    /// The URL of the web resource.
    pub url : String,
    /// The title of the web resource.
    pub title : String,
  }

  /// Inner data for a file path annotation.
  ///
  /// # Used By
  /// - `Annotation::FilePath`
  /// - `MessageContentTextAnnotationsFilePathObject` (within `assistants_shared.rs`)
  #[ derive( Debug, Serialize, Deserialize, Clone, PartialEq ) ]
  pub struct FilePathAnnotation
  {
    /// The ID of the file that was generated.
    pub file_id : String,
  }

  /// Represents annotations embedded within output text content.
  /// These annotations provide context or references for parts of the text.
  ///
  /// # Used By
  /// - `OutputContentPart::Text`
  /// - `MessageContentTextObject` (within `assistants_shared.rs`)
  /// - `MessageDeltaTextContent` (within `assistants_shared.rs`)
  /// - `ResponseTextAnnotationDeltaEvent` (within `realtime_shared.rs`)
  #[ derive( Debug, Serialize, Clone, PartialEq ) ]
  pub enum Annotation
  {
    /// A citation within the message that points to a specific quote from a specific File.
    FileCitation
    {
      /// The text in the message content that needs to be replaced.
      text : String,
      /// The details of the file citation.
      file_citation : FileCitationAnnotation,
      /// The start index of the citation in the text.
      start_index : u32,
      /// The end index of the citation in the text.
      end_index : u32,
    },
    /// A citation for a web resource used to generate a model response.
    UrlCitation
    {
      /// The URL of the web resource.
      url : String,
      /// The title of the web resource.
      title : String,
      /// The start index of the citation in the text.
      start_index : u32,
      /// The end index of the citation in the text.
      end_index : u32,
    },
    /// A URL for the file that's generated when the assistant used the `code_interpreter` tool.
    FilePath
    {
      /// The text in the message content that needs to be replaced.
      text : String,
      /// The details of the file path.
      file_path : FilePathAnnotation,
      /// The start index of the file path in the text.
      start_index : u32,
      /// The end index of the file path in the text.
      end_index : u32,
    },
  }

  // Manual Deserialization for Annotation enum based on the 'type' field
  impl< 'de > Deserialize< 'de > for Annotation
  {
    #[ allow( clippy::too_many_lines, reason = "Manual deserialization requires many lines." ) ]
    #[ inline ]
    fn deserialize< D >( deserializer : D ) -> Result< Self, D::Error >
    where
      D : Deserializer< 'de >,
    {
      #[ derive( Deserialize ) ]
      #[ serde( field_identifier, rename_all = "snake_case" ) ]
      enum Field
      {
        Type, Text, FileCitation, UrlCitation, FilePath, StartIndex, EndIndex, Url, Title
      }

      struct AnnotationVisitor;

      impl< 'de > Visitor< 'de > for AnnotationVisitor
      {
        type Value = Annotation;

        fn expecting( &self, formatter : &mut fmt::Formatter< '_ > ) -> fmt::Result
        {
          formatter.write_str( "struct Annotation" )
        }

        fn visit_map< V >( self, mut map : V ) -> Result< Annotation, V::Error >
        where
          V : MapAccess< 'de >,
        {
          let mut type_ : Option< String > = None;
          let mut text : Option< String > = None;
          let mut file_citation : Option< FileCitationAnnotation > = None;
          let mut url_citation : Option< UrlCitationAnnotation > = None;
          let mut file_path : Option< FilePathAnnotation > = None;
          let mut start_index : Option< u32 > = None;
          let mut end_index : Option< u32 > = None;
          let mut url : Option< String > = None;
          let mut title : Option< String > = None;

          while let Some( key ) = map.next_key()?
          {
            match key
            {
              Field::Type =>
              {
                if type_.is_some() { Err( de::Error::duplicate_field( "type" ) )? }
                type_ = Some( map.next_value()? );
              }
              Field::Text =>
              {
                if text.is_some() { Err( de::Error::duplicate_field( "text" ) )? }
                text = Some( map.next_value()? );
              }
              Field::FileCitation =>
              {
                if file_citation.is_some() { Err( de::Error::duplicate_field( "file_citation" ) )? }
                file_citation = Some( map.next_value()? );
              }
              Field::UrlCitation =>
              {
                if url_citation.is_some() { Err( de::Error::duplicate_field( "url_citation" ) )? }
                url_citation = Some( map.next_value()? );
              }
              Field::FilePath =>
              {
                if file_path.is_some() { Err( de::Error::duplicate_field( "file_path" ) )? }
                file_path = Some( map.next_value()? );
              }
              Field::StartIndex =>
              {
                if start_index.is_some() { Err( de::Error::duplicate_field( "start_index" ) )? }
                start_index = Some( map.next_value()? );
              }
              Field::EndIndex =>
              {
                if end_index.is_some() { Err( de::Error::duplicate_field( "end_index" ) )? }
                end_index = Some( map.next_value()? );
              }
              Field::Url =>
              {
                if url.is_some() { Err( de::Error::duplicate_field( "url" ) )? }
                url = Some( map.next_value()? );
              }
              Field::Title =>
              {
                if title.is_some() { Err( de::Error::duplicate_field( "title" ) )? }
                title = Some( map.next_value()? );
              }
            }
          }

          let type_ = type_.ok_or_else( || de::Error::missing_field( "type" ) )?;
          let start_index = start_index.ok_or_else( || de::Error::missing_field( "start_index" ) )?;
          let end_index = end_index.ok_or_else( || de::Error::missing_field( "end_index" ) )?;

          match type_.as_str()
          {
            "file_citation" =>
            {
              let text = text.ok_or_else( || de::Error::missing_field( "text" ) )?;
              let file_citation = file_citation.ok_or_else( || de::Error::missing_field( "file_citation" ) )?;
              Ok( Annotation::FileCitation { text, file_citation, start_index, end_index } )
            }
            "url_citation" =>
            {
              let url = url.ok_or_else( || de::Error::missing_field( "url" ) )?;
              let title = title.ok_or_else( || de::Error::missing_field( "title" ) )?;
              Ok( Annotation::UrlCitation { url, title, start_index, end_index } )
            }
            "file_path" =>
            {
              let text = text.ok_or_else( || de::Error::missing_field( "text" ) )?;
              let file_path = file_path.ok_or_else( || de::Error::missing_field( "file_path" ) )?;
              Ok( Annotation::FilePath { text, file_path, start_index, end_index } )
            }
            _ => Err( de::Error::unknown_variant( &type_, &[ "file_citation", "url_citation", "file_path" ] ) ),
          }
        }
      }

      const FIELDS : &[ &str ] = &[ "type", "text", "file_citation", "url_citation", "file_path", "start_index", "end_index" ];
      deserializer.deserialize_struct( "Annotation", FIELDS, AnnotationVisitor )
    }
  }

  // --- OutputItem Enum (Added) ---

  /// Represents the different types of items that can appear in the `output` array of a `Response`.
  /// Corresponds to the `OutputItem` schema in the `OpenAPI` spec.
  ///
  /// # Used By
  /// - `Response` (within `responses.rs`)
  #[ derive( Debug, Serialize, Deserialize, Clone, PartialEq ) ]
  #[ serde( tag = "type" ) ] // Use the 'type' field to discriminate variants
  pub enum OutputItem
  {
    /// An output message from the model.
    #[ serde( rename = "message" ) ]
    Message( OutputMessage ), // Use definition from responses.rs

    /// A call to the file search tool.
    #[ serde( rename = "file_search_call" ) ]
    FileSearchCall( FileSearchToolCall ),

    /// A call to a function tool.
    #[ serde( rename = "function_call" ) ]
    FunctionCall( FunctionToolCall ),

    /// A call to the web search tool.
    #[ serde( rename = "web_search_call" ) ]
    WebSearchCall( WebSearchToolCall ),

    /// A call to the computer use tool.
    #[ serde( rename = "computer_call" ) ]
    ComputerCall( ComputerToolCall ),

    /// Reasoning steps taken by the model.
    #[ serde( rename = "reasoning" ) ]
    Reasoning( Reasoning ), // Corrected name
  }

  // --- OutputContentPart Definition ---
  /// Represents parts of the output content within a response message.
  /// Corresponds to the `OutputContent` schema in the `OpenAPI` spec.
  ///
  /// # Used By
  /// - `OutputMessage` (within `responses.rs`)
  #[ derive( Debug, Serialize, Deserialize, Clone, PartialEq ) ]
  #[ serde( tag = "type" ) ]
  pub enum OutputContentPart
  {
    /// Text content generated by the model.
    #[ serde( rename = "output_text" ) ]
    Text
    {
      /// The text content.
      text : String,
      /// Any annotations associated with the text (e.g., citations).
      #[ serde( default ) ]
      annotations : Vec< Annotation >,
    },
    /// A refusal message generated by the model.
    #[ serde( rename = "refusal" ) ]
    Refusal
    {
      /// The refusal explanation.
      refusal : String,
    },
    // Note : Other output types like audio might be added here in the future
  }

  // --- FileSearchResultItem (Moved from file_search.rs for dependency reasons) ---
  // Note : Ideally, this would stay in file_search.rs, but OutputItem needs it.
  // Consider refactoring later if this becomes problematic.
  /// Represents a single item found during a file search.
  ///
  /// # Used By
  /// - `FileSearchToolCall` (within `tools/file_search.rs`)
  #[ derive( Debug, Serialize, Deserialize, Clone, PartialEq ) ]
  pub struct FileSearchResultItem
  {
      /// The ID of the file containing the result.
      pub file_id : String,
      /// The name of the file containing the result.
      pub filename : String,
      /// The relevance score of the result (between 0 and 1).
      pub score : f64,
      /// Attributes associated with the file.
      #[ serde( default ) ]
      pub attributes : VectorStoreFileAttributes,
      /// Content chunks from the file (only included if requested).
      #[ serde( default ) ]
      pub content : Vec< ListedInputContentPart >,
  }

  // --- ComputerScreenshotImage (Moved from computer_use.rs for dependency reasons) ---
  // Note : Ideally, this would stay in computer_use.rs.
  /// Represents the output of a computer tool action, typically a screenshot.
  ///
  /// # Used By
  /// - `ComputerToolCallOutput` (within `tools/computer_use.rs`)
  #[ derive( Debug, Serialize, Deserialize, Clone, PartialEq ) ]
  pub struct ComputerScreenshotImage
  {
    /// The URL of the screenshot image.
    #[ serde( skip_serializing_if = "Option::is_none" ) ]
    pub image_url : Option< String >,
    /// The identifier of an uploaded file that contains the screenshot.
    #[ serde( skip_serializing_if = "Option::is_none" ) ]
    pub file_id : Option< String >,
  }


} // end mod private

crate ::mod_interface!
{
  exposed use
  {
    FileCitationAnnotation,
    UrlCitationAnnotation,
    FilePathAnnotation,
    Annotation,
    OutputItem,
    OutputContentPart, // Expose the newly defined enum
    // ReasoningItem, // No longer a placeholder here
    // Expose moved structs
    FileSearchResultItem,
    ComputerScreenshotImage,
  };

  // Re-export types used within the exposed items
  own use crate::components::
  {
    common ::{ VectorStoreFileAttributes, Reasoning }, // Corrected ReasoningItem to Reasoning
    input ::ListedInputContentPart,
    tools ::
    {
      FileSearchToolCall,
      FunctionToolCall,
      WebSearchToolCall,
      ComputerToolCall,
    },
    // Import OutputMessage from responses.rs
    responses ::OutputMessage,
  };
}