Skip to main content

dynamo_async_openai/types/
message.rs

1// SPDX-FileCopyrightText: Copyright (c) 2025-2026 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-2026 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::{AudioUrl, 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    AudioUrl(MessageContentAudioUrlObject),
119    Refusal(MessageContentRefusalObject),
120}
121
122#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
123pub struct MessageContentRefusalObject {
124    pub refusal: String,
125}
126
127/// The text content that is part of a message.
128#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
129pub struct MessageContentTextObject {
130    pub text: TextData,
131}
132
133#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
134pub struct TextData {
135    /// The data that makes up the text.
136    pub value: String,
137    pub annotations: Vec<MessageContentTextAnnotations>,
138}
139
140#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
141#[serde(tag = "type")]
142#[serde(rename_all = "snake_case")]
143pub enum MessageContentTextAnnotations {
144    /// 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.
145    FileCitation(MessageContentTextAnnotationsFileCitationObject),
146    /// A URL for the file that's generated when the assistant used the `code_interpreter` tool to generate a file.
147    FilePath(MessageContentTextAnnotationsFilePathObject),
148}
149
150/// 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.
151#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
152pub struct MessageContentTextAnnotationsFileCitationObject {
153    /// The text in the message content that needs to be replaced.
154    pub text: String,
155    pub file_citation: FileCitation,
156    pub start_index: u32,
157    pub end_index: u32,
158}
159
160#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
161pub struct FileCitation {
162    /// The ID of the specific File the citation is from.
163    pub file_id: String,
164    /// The specific quote in the file.
165    pub quote: Option<String>,
166}
167
168#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
169pub struct MessageContentTextAnnotationsFilePathObject {
170    /// The text in the message content that needs to be replaced.
171    pub text: String,
172    pub file_path: FilePath,
173    pub start_index: u32,
174    pub end_index: u32,
175}
176
177#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
178pub struct FilePath {
179    /// The ID of the file that was generated.
180    pub file_id: String,
181}
182
183/// References an image [File](https://platform.openai.com/docs/api-reference/files) in the content of a message.
184#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
185pub struct MessageContentImageFileObject {
186    pub image_file: ImageFile,
187}
188
189#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
190pub struct ImageFile {
191    /// 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.
192    pub file_id: String,
193    /// 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`.
194    pub detail: Option<ImageDetail>,
195}
196
197/// References an image URL in the content of a message.
198#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
199pub struct MessageContentImageUrlObject {
200    pub image_url: ImageUrl,
201}
202
203/// References a video URL in the content of a message.
204#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
205pub struct MessageContentVideoUrlObject {
206    pub video_url: VideoUrl,
207}
208
209#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
210pub struct MessageContentAudioUrlObject {
211    pub audio_url: AudioUrl,
212}
213
214#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
215pub struct MessageRequestContentTextObject {
216    /// Text content to be sent to the model
217    pub text: String,
218}
219
220#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
221#[serde(untagged)]
222pub enum CreateMessageRequestContent {
223    /// The text contents of the message.
224    Content(String),
225    /// 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).
226    ContentArray(Vec<MessageContentInput>),
227}
228
229#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
230#[serde(tag = "type")]
231#[serde(rename_all = "snake_case")]
232pub enum MessageContentInput {
233    Text(MessageRequestContentTextObject),
234    ImageFile(MessageContentImageFileObject),
235    ImageUrl(MessageContentImageUrlObject),
236    VideoUrl(MessageContentVideoUrlObject),
237    AudioUrl(MessageContentAudioUrlObject),
238}
239#[derive(Clone, Serialize, Default, Debug, Deserialize, Builder, PartialEq)]
240#[builder(name = "CreateMessageRequestArgs")]
241#[builder(pattern = "mutable")]
242#[builder(setter(into, strip_option), default)]
243#[builder(derive(Debug))]
244#[builder(build_fn(error = "OpenAIError"))]
245pub struct CreateMessageRequest {
246    /// The role of the entity that is creating the message. Allowed values include:
247    /// - `user`: Indicates the message is sent by an actual user and should be used in most cases to represent user-generated messages.
248    /// - `assistant`: Indicates the message is generated by the assistant. Use this value to insert messages from the assistant into the conversation.
249    pub role: MessageRole,
250    /// The content of the message.
251    pub content: CreateMessageRequestContent,
252
253    /// A list of files attached to the message, and the tools they should be added to.
254    pub attachments: Option<Vec<MessageAttachment>>,
255
256    #[serde(skip_serializing_if = "Option::is_none")]
257    pub metadata: Option<HashMap<String, serde_json::Value>>,
258}
259
260#[derive(Clone, Serialize, Default, Debug, Deserialize, PartialEq)]
261pub struct ModifyMessageRequest {
262    #[serde(skip_serializing_if = "Option::is_none")]
263    pub metadata: Option<HashMap<String, serde_json::Value>>,
264}
265
266#[derive(Clone, Serialize, Default, Debug, Deserialize, PartialEq)]
267pub struct DeleteMessageResponse {
268    pub id: String,
269    pub deleted: bool,
270    pub object: String,
271}
272
273#[derive(Clone, Serialize, Default, Debug, Deserialize, PartialEq)]
274pub struct ListMessagesResponse {
275    pub object: String,
276    pub data: Vec<MessageObject>,
277    pub first_id: Option<String>,
278    pub last_id: Option<String>,
279    pub has_more: bool,
280}
281
282/// Represents a message delta i.e. any changed fields on a message during streaming.
283#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
284pub struct MessageDeltaObject {
285    /// The identifier of the message, which can be referenced in API endpoints.
286    pub id: String,
287    /// The object type, which is always `thread.message.delta`.
288    pub object: String,
289    /// The delta containing the fields that have changed on the Message.
290    pub delta: MessageDelta,
291}
292
293#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
294pub struct MessageDelta {
295    /// The entity that produced the message. One of `user` or `assistant`.
296    pub role: Option<MessageRole>,
297    ///  The content of the message in array of text and/or images.
298    pub content: Option<Vec<MessageDeltaContent>>,
299}
300
301#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
302#[serde(tag = "type")]
303#[serde(rename_all = "snake_case")]
304pub enum MessageDeltaContent {
305    ImageFile(MessageDeltaContentImageFileObject),
306    ImageUrl(MessageDeltaContentImageUrlObject),
307    VideoUrl(MessageDeltaContentVideoUrlObject),
308    AudioUrl(MessageDeltaContentAudioUrlObject),
309    Text(MessageDeltaContentTextObject),
310    Refusal(MessageDeltaContentRefusalObject),
311}
312
313#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
314pub struct MessageDeltaContentRefusalObject {
315    /// The index of the refusal part in the message.
316    pub index: i32,
317    pub refusal: Option<String>,
318}
319
320/// The text content that is part of a message.
321#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
322pub struct MessageDeltaContentTextObject {
323    /// The index of the content part in the message.
324    pub index: u32,
325    pub text: Option<MessageDeltaContentText>,
326}
327
328#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
329pub struct MessageDeltaContentText {
330    /// The data that makes up the text.
331    pub value: Option<String>,
332    pub annotations: Option<Vec<MessageDeltaContentTextAnnotations>>,
333}
334
335#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
336#[serde(tag = "type")]
337#[serde(rename_all = "snake_case")]
338pub enum MessageDeltaContentTextAnnotations {
339    FileCitation(MessageDeltaContentTextAnnotationsFileCitationObject),
340    FilePath(MessageDeltaContentTextAnnotationsFilePathObject),
341}
342
343/// 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.
344#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
345pub struct MessageDeltaContentTextAnnotationsFileCitationObject {
346    /// The index of the annotation in the text content part.
347    pub index: u32,
348    /// The text in the message content that needs to be replaced.
349    pub text: Option<String>,
350    pub file_citation: Option<FileCitation>,
351    pub start_index: Option<u32>,
352    pub end_index: Option<u32>,
353}
354
355/// A URL for the file that's generated when the assistant used the `code_interpreter` tool to generate a file.
356#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
357pub struct MessageDeltaContentTextAnnotationsFilePathObject {
358    /// The index of the annotation in the text content part.
359    pub index: u32,
360    /// The text in the message content that needs to be replaced.
361    pub text: Option<String>,
362    pub file_path: Option<FilePath>,
363    pub start_index: Option<u32>,
364    pub end_index: Option<u32>,
365}
366
367/// References an image [File](https://platform.openai.com/docs/api-reference/files) in the content of a message.
368#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
369pub struct MessageDeltaContentImageFileObject {
370    /// The index of the content part in the message.
371    pub index: u32,
372
373    pub image_file: Option<ImageFile>,
374}
375
376#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
377pub struct MessageDeltaContentImageUrlObject {
378    /// The index of the content part in the message.
379    pub index: u32,
380
381    pub image_url: Option<ImageUrl>,
382}
383
384#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
385pub struct MessageDeltaContentVideoUrlObject {
386    /// The index of the content part in the message.
387    pub index: u32,
388
389    pub video_url: Option<VideoUrl>,
390}
391
392#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
393pub struct MessageDeltaContentAudioUrlObject {
394    /// The index of the content part in the message.
395    pub index: u32,
396
397    pub audio_url: Option<AudioUrl>,
398}