openai_tools/
common.rs

1//! # Common Types and Structures
2//!
3//! This module contains common data structures and types used across the OpenAI Tools library.
4//! These structures represent core concepts like messages, token usage, and other shared
5//! components that are used by multiple API endpoints.
6//!
7//! ## Key Components
8//!
9//! - **Message**: Represents a single message in a conversation
10//! - **Usage**: Token usage statistics for API requests
11//!
12//! ## Example
13//!
14//! ```rust
15//! use openai_tools::common::{Message, Usage};
16//!
17//! // Create a user message
18//! let message = Message::new("user".to_string(), "Hello, world!".to_string());
19//!
20//! // Usage is typically returned by API responses
21//! let usage = Usage::new(
22//!     Some(10),    // input_tokens
23//!     None,        // input_tokens_details
24//!     Some(20),    // output_tokens
25//!     None,        // output_tokens_details
26//!     Some(10),    // prompt_tokens
27//!     Some(20),    // completion_tokens
28//!     Some(30),    // total_tokens
29//!     None,        // completion_tokens_details
30//! );
31//!
32//! println!("Total tokens used: {:?}", usage.total_tokens);
33//! ```
34
35use derive_new::new;
36use fxhash::FxHashMap;
37use serde::{Deserialize, Serialize};
38
39/// Token usage statistics for OpenAI API requests.
40///
41/// This structure contains detailed information about token consumption during
42/// API requests, including both input (prompt) and output (completion) tokens.
43/// Different fields may be populated depending on the specific API endpoint
44/// and model used.
45///
46/// # Fields
47///
48/// * `input_tokens` - Number of tokens in the input/prompt
49/// * `input_tokens_details` - Detailed breakdown of input token usage by category
50/// * `output_tokens` - Number of tokens in the output/completion
51/// * `output_tokens_details` - Detailed breakdown of output token usage by category
52/// * `prompt_tokens` - Legacy field for input tokens (may be deprecated)
53/// * `completion_tokens` - Legacy field for output tokens (may be deprecated)
54/// * `total_tokens` - Total number of tokens used (input + output)
55/// * `completion_tokens_details` - Detailed breakdown of completion token usage
56///
57/// # Note
58///
59/// Not all fields will be populated for every request. The availability of
60/// detailed token breakdowns depends on the model and API endpoint being used.
61///
62/// # Example
63///
64/// ```rust
65/// use openai_tools::common::Usage;
66///
67/// // Create usage statistics manually (typically done by API response parsing)
68/// let usage = Usage::new(
69///     Some(25),    // input tokens
70///     None,        // no detailed input breakdown
71///     Some(50),    // output tokens
72///     None,        // no detailed output breakdown
73///     Some(25),    // prompt tokens (legacy)
74///     Some(50),    // completion tokens (legacy)
75///     Some(75),    // total tokens
76///     None,        // no detailed completion breakdown
77/// );
78///
79/// if let Some(total) = usage.total_tokens {
80///     println!("Request used {} tokens total", total);
81/// }
82/// ```
83#[derive(Debug, Clone, Default, Deserialize, Serialize, new)]
84pub struct Usage {
85    pub input_tokens: Option<usize>,
86    pub input_tokens_details: Option<FxHashMap<String, usize>>,
87    pub output_tokens: Option<usize>,
88    pub output_tokens_details: Option<FxHashMap<String, usize>>,
89    pub prompt_tokens: Option<usize>,
90    pub completion_tokens: Option<usize>,
91    pub total_tokens: Option<usize>,
92    pub completion_tokens_details: Option<FxHashMap<String, usize>>,
93}
94
95/// Represents a single message in a conversation with an AI model.
96///
97/// Messages are the fundamental building blocks of conversations in chat-based
98/// AI interactions. Each message has a role (indicating who sent it) and content
99/// (the actual message text). Messages can also contain refusal information
100/// when the AI model declines to respond to certain requests.
101///
102/// # Roles
103///
104/// Common roles include:
105/// - **"system"**: System messages that set the behavior or context for the AI
106/// - **"user"**: Messages from the human user
107/// - **"assistant"**: Messages from the AI assistant
108/// - **"function"**: Messages related to function/tool calls (for advanced use cases)
109///
110/// # Fields
111///
112/// * `role` - The role of the message sender
113/// * `content` - The text content of the message
114/// * `refusal` - Optional refusal message if the AI declined to respond
115///
116/// # Example
117///
118/// ```rust
119/// use openai_tools::common::Message;
120///
121/// // Create a system message to set context
122/// let system_msg = Message::new(
123///     "system".to_string(),
124///     "You are a helpful assistant that explains complex topics simply.".to_string()
125/// );
126///
127/// // Create a user message
128/// let user_msg = Message::new(
129///     "user".to_string(),
130///     "What is quantum computing?".to_string()
131/// );
132///
133/// // Create an assistant response
134/// let assistant_msg = Message::new(
135///     "assistant".to_string(),
136///     "Quantum computing is a type of computation that uses quantum mechanics...".to_string()
137/// );
138///
139/// // Messages are typically used in vectors for conversation history
140/// let conversation = vec![system_msg, user_msg, assistant_msg];
141/// ```
142#[derive(Debug, Clone, Deserialize, Serialize)]
143pub struct Message {
144    pub role: String,
145    pub content: String,
146    #[serde(skip_serializing_if = "Option::is_none")]
147    pub refusal: Option<String>,
148}
149
150impl Message {
151    /// Creates a new `Message` with the specified role and content.
152    ///
153    /// This is the primary constructor for creating message instances.
154    /// The `refusal` field is automatically set to `None` and can be
155    /// modified separately if needed.
156    ///
157    /// # Arguments
158    ///
159    /// * `role` - The role of the message sender (e.g., "user", "assistant", "system")
160    /// * `message` - The text content of the message
161    ///
162    /// # Returns
163    ///
164    /// A new `Message` instance with the specified role and content.
165    ///
166    /// # Example
167    ///
168    /// ```rust
169    /// use openai_tools::common::Message;
170    ///
171    /// // Create various types of messages
172    /// let system_message = Message::new(
173    ///     "system".to_string(),
174    ///     "You are a helpful AI assistant.".to_string()
175    /// );
176    ///
177    /// let user_message = Message::new(
178    ///     "user".to_string(),
179    ///     "Hello! How are you today?".to_string()
180    /// );
181    ///
182    /// let assistant_message = Message::new(
183    ///     "assistant".to_string(),
184    ///     "Hello! I'm doing well, thank you for asking.".to_string()
185    /// );
186    ///
187    /// // Verify the message was created correctly
188    /// assert_eq!(user_message.role, "user");
189    /// assert_eq!(user_message.content, "Hello! How are you today?");
190    /// assert_eq!(user_message.refusal, None);
191    /// ```
192    pub fn new(role: String, message: String) -> Self {
193        Self {
194            role: String::from(role),
195            content: String::from(message),
196            refusal: None,
197        }
198    }
199}