dynamo_async_openai/types/
message.rs

1// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2// SPDX-License-Identifier: Apache-2.0
3//
4// Based on https://github.com/64bit/async-openai/ by Himanshu Neema
5// Original Copyright (c) 2022 Himanshu Neema
6// Licensed under MIT License (see ATTRIBUTIONS-Rust.md)
7//
8// Modifications Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
9// Licensed under Apache 2.0
10
11use std::collections::HashMap;
12
13use derive_builder::Builder;
14use serde::{Deserialize, Serialize};
15
16use crate::error::OpenAIError;
17
18use super::{ImageDetail, ImageUrl, VideoUrl};
19
20#[derive(Clone, Serialize, Debug, Deserialize, PartialEq, Default)]
21#[serde(rename_all = "lowercase")]
22pub enum MessageRole {
23    #[default]
24    User,
25    Assistant,
26}
27
28#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
29#[serde(rename_all = "snake_case")]
30pub enum MessageStatus {
31    InProgress,
32    Incomplete,
33    Completed,
34}
35
36#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
37#[serde(rename_all = "snake_case")]
38pub enum MessageIncompleteDetailsType {
39    ContentFilter,
40    MaxTokens,
41    RunCancelled,
42    RunExpired,
43    RunFailed,
44}
45
46#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
47pub struct MessageIncompleteDetails {
48    /// The reason the message is incomplete.
49    pub reason: MessageIncompleteDetailsType,
50}
51
52///  Represents a message within a [thread](https://platform.openai.com/docs/api-reference/threads).
53#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
54pub struct MessageObject {
55    /// The identifier, which can be referenced in API endpoints.
56    pub id: String,
57    /// The object type, which is always `thread.message`.
58    pub object: String,
59    /// The Unix timestamp (in seconds) for when the message was created.
60    pub created_at: i32,
61    /// The [thread](https://platform.openai.com/docs/api-reference/threads) ID that this message belongs to.
62    pub thread_id: String,
63
64    /// The status of the message, which can be either `in_progress`, `incomplete`, or `completed`.
65    pub status: Option<MessageStatus>,
66
67    /// On an incomplete message, details about why the message is incomplete.
68    pub incomplete_details: Option<MessageIncompleteDetails>,
69
70    /// The Unix timestamp (in seconds) for when the message was completed.
71    pub completed_at: Option<u32>,
72
73    /// The Unix timestamp (in seconds) for when the message was marked as incomplete.
74    pub incomplete_at: Option<u32>,
75
76    /// The entity that produced the message. One of `user` or `assistant`.
77    pub role: MessageRole,
78
79    /// The content of the message in array of text and/or images.
80    pub content: Vec<MessageContent>,
81
82    /// If applicable, the ID of the [assistant](https://platform.openai.com/docs/api-reference/assistants) that authored this message.
83    pub assistant_id: Option<String>,
84
85    /// The ID of the [run](https://platform.openai.com/docs/api-reference/runs) associated with the creation of this message. Value is `null` when messages are created manually using the create message or create thread endpoints.
86    pub run_id: Option<String>,
87
88    /// A list of files attached to the message, and the tools they were added to.
89    pub attachments: Option<Vec<MessageAttachment>>,
90
91    pub metadata: Option<HashMap<String, serde_json::Value>>,
92}
93
94#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
95pub struct MessageAttachment {
96    /// The ID of the file to attach to the message.
97    pub file_id: String,
98    /// The tools to add this file to.
99    pub tools: Vec<MessageAttachmentTool>,
100}
101
102#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
103#[serde(tag = "type")]
104#[serde(rename_all = "snake_case")]
105pub enum MessageAttachmentTool {
106    CodeInterpreter,
107    FileSearch,
108}
109
110#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
111#[serde(tag = "type")]
112#[serde(rename_all = "snake_case")]
113pub enum MessageContent {
114    Text(MessageContentTextObject),
115    ImageFile(MessageContentImageFileObject),
116    ImageUrl(MessageContentImageUrlObject),
117    VideoUrl(MessageContentVideoUrlObject),
118    Refusal(MessageContentRefusalObject),
119}
120
121#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
122pub struct MessageContentRefusalObject {
123    pub refusal: String,
124}
125
126/// The text content that is part of a message.
127#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
128pub struct MessageContentTextObject {
129    pub text: TextData,
130}
131
132#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
133pub struct TextData {
134    /// The data that makes up the text.
135    pub value: String,
136    pub annotations: Vec<MessageContentTextAnnotations>,
137}
138
139#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
140#[serde(tag = "type")]
141#[serde(rename_all = "snake_case")]
142pub enum MessageContentTextAnnotations {
143    /// A citation within the message that points to a specific quote from a specific File associated with the assistant or the message. Generated when the assistant uses the "retrieval" tool to search files.
144    FileCitation(MessageContentTextAnnotationsFileCitationObject),
145    /// A URL for the file that's generated when the assistant used the `code_interpreter` tool to generate a file.
146    FilePath(MessageContentTextAnnotationsFilePathObject),
147}
148
149/// A citation within the message that points to a specific quote from a specific File associated with the assistant or the message. Generated when the assistant uses the "file_search" tool to search files.
150#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
151pub struct MessageContentTextAnnotationsFileCitationObject {
152    /// The text in the message content that needs to be replaced.
153    pub text: String,
154    pub file_citation: FileCitation,
155    pub start_index: u32,
156    pub end_index: u32,
157}
158
159#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
160pub struct FileCitation {
161    /// The ID of the specific File the citation is from.
162    pub file_id: String,
163    /// The specific quote in the file.
164    pub quote: Option<String>,
165}
166
167#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
168pub struct MessageContentTextAnnotationsFilePathObject {
169    /// The text in the message content that needs to be replaced.
170    pub text: String,
171    pub file_path: FilePath,
172    pub start_index: u32,
173    pub end_index: u32,
174}
175
176#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
177pub struct FilePath {
178    /// The ID of the file that was generated.
179    pub file_id: String,
180}
181
182/// References an image [File](https://platform.openai.com/docs/api-reference/files) in the content of a message.
183#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
184pub struct MessageContentImageFileObject {
185    pub image_file: ImageFile,
186}
187
188#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
189pub struct ImageFile {
190    /// The [File](https://platform.openai.com/docs/api-reference/files) ID of the image in the message content. Set `purpose="vision"` when uploading the File if you need to later display the file content.
191    pub file_id: String,
192    /// Specifies the detail level of the image if specified by the user. `low` uses fewer tokens, you can opt in to high resolution using `high`.
193    pub detail: Option<ImageDetail>,
194}
195
196/// References an image URL in the content of a message.
197#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
198pub struct MessageContentImageUrlObject {
199    pub image_url: ImageUrl,
200}
201
202/// References a video URL in the content of a message.
203#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
204pub struct MessageContentVideoUrlObject {
205    pub video_url: VideoUrl,
206}
207
208#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
209pub struct MessageRequestContentTextObject {
210    /// Text content to be sent to the model
211    pub text: String,
212}
213
214#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
215#[serde(untagged)]
216pub enum CreateMessageRequestContent {
217    /// The text contents of the message.
218    Content(String),
219    /// An array of content parts with a defined type, each can be of type `text` or images can be passed with `image_url` or `image_file`. Image types are only supported on [Vision-compatible models](https://platform.openai.com/docs/models/overview).
220    ContentArray(Vec<MessageContentInput>),
221}
222
223#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
224#[serde(tag = "type")]
225#[serde(rename_all = "snake_case")]
226pub enum MessageContentInput {
227    Text(MessageRequestContentTextObject),
228    ImageFile(MessageContentImageFileObject),
229    ImageUrl(MessageContentImageUrlObject),
230    VideoUrl(MessageContentVideoUrlObject),
231}
232#[derive(Clone, Serialize, Default, Debug, Deserialize, Builder, PartialEq)]
233#[builder(name = "CreateMessageRequestArgs")]
234#[builder(pattern = "mutable")]
235#[builder(setter(into, strip_option), default)]
236#[builder(derive(Debug))]
237#[builder(build_fn(error = "OpenAIError"))]
238pub struct CreateMessageRequest {
239    /// The role of the entity that is creating the message. Allowed values include:
240    /// - `user`: Indicates the message is sent by an actual user and should be used in most cases to represent user-generated messages.
241    /// - `assistant`: Indicates the message is generated by the assistant. Use this value to insert messages from the assistant into the conversation.
242    pub role: MessageRole,
243    /// The content of the message.
244    pub content: CreateMessageRequestContent,
245
246    /// A list of files attached to the message, and the tools they should be added to.
247    pub attachments: Option<Vec<MessageAttachment>>,
248
249    #[serde(skip_serializing_if = "Option::is_none")]
250    pub metadata: Option<HashMap<String, serde_json::Value>>,
251}
252
253#[derive(Clone, Serialize, Default, Debug, Deserialize, PartialEq)]
254pub struct ModifyMessageRequest {
255    #[serde(skip_serializing_if = "Option::is_none")]
256    pub metadata: Option<HashMap<String, serde_json::Value>>,
257}
258
259#[derive(Clone, Serialize, Default, Debug, Deserialize, PartialEq)]
260pub struct DeleteMessageResponse {
261    pub id: String,
262    pub deleted: bool,
263    pub object: String,
264}
265
266#[derive(Clone, Serialize, Default, Debug, Deserialize, PartialEq)]
267pub struct ListMessagesResponse {
268    pub object: String,
269    pub data: Vec<MessageObject>,
270    pub first_id: Option<String>,
271    pub last_id: Option<String>,
272    pub has_more: bool,
273}
274
275/// Represents a message delta i.e. any changed fields on a message during streaming.
276#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
277pub struct MessageDeltaObject {
278    /// The identifier of the message, which can be referenced in API endpoints.
279    pub id: String,
280    /// The object type, which is always `thread.message.delta`.
281    pub object: String,
282    /// The delta containing the fields that have changed on the Message.
283    pub delta: MessageDelta,
284}
285
286#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
287pub struct MessageDelta {
288    /// The entity that produced the message. One of `user` or `assistant`.
289    pub role: Option<MessageRole>,
290    ///  The content of the message in array of text and/or images.
291    pub content: Option<Vec<MessageDeltaContent>>,
292}
293
294#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
295#[serde(tag = "type")]
296#[serde(rename_all = "snake_case")]
297pub enum MessageDeltaContent {
298    ImageFile(MessageDeltaContentImageFileObject),
299    ImageUrl(MessageDeltaContentImageUrlObject),
300    VideoUrl(MessageDeltaContentVideoUrlObject),
301    Text(MessageDeltaContentTextObject),
302    Refusal(MessageDeltaContentRefusalObject),
303}
304
305#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
306pub struct MessageDeltaContentRefusalObject {
307    /// The index of the refusal part in the message.
308    pub index: i32,
309    pub refusal: Option<String>,
310}
311
312/// The text content that is part of a message.
313#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
314pub struct MessageDeltaContentTextObject {
315    /// The index of the content part in the message.
316    pub index: u32,
317    pub text: Option<MessageDeltaContentText>,
318}
319
320#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
321pub struct MessageDeltaContentText {
322    /// The data that makes up the text.
323    pub value: Option<String>,
324    pub annotations: Option<Vec<MessageDeltaContentTextAnnotations>>,
325}
326
327#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
328#[serde(tag = "type")]
329#[serde(rename_all = "snake_case")]
330pub enum MessageDeltaContentTextAnnotations {
331    FileCitation(MessageDeltaContentTextAnnotationsFileCitationObject),
332    FilePath(MessageDeltaContentTextAnnotationsFilePathObject),
333}
334
335/// A citation within the message that points to a specific quote from a specific File associated with the assistant or the message. Generated when the assistant uses the "file_search" tool to search files.
336#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
337pub struct MessageDeltaContentTextAnnotationsFileCitationObject {
338    /// The index of the annotation in the text content part.
339    pub index: u32,
340    /// The text in the message content that needs to be replaced.
341    pub text: Option<String>,
342    pub file_citation: Option<FileCitation>,
343    pub start_index: Option<u32>,
344    pub end_index: Option<u32>,
345}
346
347/// A URL for the file that's generated when the assistant used the `code_interpreter` tool to generate a file.
348#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
349pub struct MessageDeltaContentTextAnnotationsFilePathObject {
350    /// The index of the annotation in the text content part.
351    pub index: u32,
352    /// The text in the message content that needs to be replaced.
353    pub text: Option<String>,
354    pub file_path: Option<FilePath>,
355    pub start_index: Option<u32>,
356    pub end_index: Option<u32>,
357}
358
359/// References an image [File](https://platform.openai.com/docs/api-reference/files) in the content of a message.
360#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
361pub struct MessageDeltaContentImageFileObject {
362    /// The index of the content part in the message.
363    pub index: u32,
364
365    pub image_file: Option<ImageFile>,
366}
367
368#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
369pub struct MessageDeltaContentImageUrlObject {
370    /// The index of the content part in the message.
371    pub index: u32,
372
373    pub image_url: Option<ImageUrl>,
374}
375
376#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
377pub struct MessageDeltaContentVideoUrlObject {
378    /// The index of the content part in the message.
379    pub index: u32,
380
381    pub video_url: Option<VideoUrl>,
382}