async_openai/
threads.rs

1use crate::{
2    config::Config,
3    error::OpenAIError,
4    types::assistants::{
5        AssistantEventStream, CreateThreadAndRunRequest, CreateThreadRequest, DeleteThreadResponse,
6        ModifyThreadRequest, RunObject, ThreadObject,
7    },
8    Client, Messages, RequestOptions, Runs,
9};
10
11/// Create threads that assistants can interact with.
12///
13/// Related guide: [Assistants](https://platform.openai.com/docs/assistants/overview)
14pub struct Threads<'c, C: Config> {
15    client: &'c Client<C>,
16    pub(crate) request_options: RequestOptions,
17}
18
19impl<'c, C: Config> Threads<'c, C> {
20    pub fn new(client: &'c Client<C>) -> Self {
21        Self {
22            client,
23            request_options: RequestOptions::new(),
24        }
25    }
26
27    /// Call [Messages] group API to manage message in [thread_id] thread.
28    pub fn messages(&self, thread_id: &str) -> Messages<'_, C> {
29        Messages::new(self.client, thread_id)
30    }
31
32    /// Call [Runs] group API to manage runs in [thread_id] thread.
33    pub fn runs(&self, thread_id: &str) -> Runs<'_, C> {
34        Runs::new(self.client, thread_id)
35    }
36
37    /// Create a thread and run it in one request.
38    #[crate::byot(T0 = serde::Serialize, R = serde::de::DeserializeOwned)]
39    pub async fn create_and_run(
40        &self,
41        request: CreateThreadAndRunRequest,
42    ) -> Result<RunObject, OpenAIError> {
43        self.client
44            .post("/threads/runs", request, &self.request_options)
45            .await
46    }
47
48    /// Create a thread and run it in one request (streaming).
49    ///
50    /// byot: You must ensure "stream: true" in serialized `request`
51    #[crate::byot(
52        T0 = serde::Serialize,
53        R = serde::de::DeserializeOwned,
54        stream = "true",
55        where_clause = "R: std::marker::Send + 'static + TryFrom<eventsource_stream::Event, Error = OpenAIError>"
56    )]
57    #[allow(unused_mut)]
58    pub async fn create_and_run_stream(
59        &self,
60        mut request: CreateThreadAndRunRequest,
61    ) -> Result<AssistantEventStream, OpenAIError> {
62        #[cfg(not(feature = "byot"))]
63        {
64            if request.stream.is_some() && !request.stream.unwrap() {
65                return Err(OpenAIError::InvalidArgument(
66                    "When stream is false, use Threads::create_and_run".into(),
67                ));
68            }
69
70            request.stream = Some(true);
71        }
72        Ok(self
73            .client
74            .post_stream_mapped_raw_events(
75                "/threads/runs",
76                request,
77                &self.request_options,
78                TryFrom::try_from,
79            )
80            .await)
81    }
82
83    /// Create a thread.
84    #[crate::byot(T0 = serde::Serialize, R = serde::de::DeserializeOwned)]
85    pub async fn create(&self, request: CreateThreadRequest) -> Result<ThreadObject, OpenAIError> {
86        self.client
87            .post("/threads", request, &self.request_options)
88            .await
89    }
90
91    /// Retrieves a thread.
92    #[crate::byot(T0 = std::fmt::Display, R = serde::de::DeserializeOwned)]
93    pub async fn retrieve(&self, thread_id: &str) -> Result<ThreadObject, OpenAIError> {
94        self.client
95            .get(&format!("/threads/{thread_id}"), &self.request_options)
96            .await
97    }
98
99    /// Modifies a thread.
100    #[crate::byot(T0 = std::fmt::Display, T1 = serde::Serialize, R = serde::de::DeserializeOwned)]
101    pub async fn update(
102        &self,
103        thread_id: &str,
104        request: ModifyThreadRequest,
105    ) -> Result<ThreadObject, OpenAIError> {
106        self.client
107            .post(
108                &format!("/threads/{thread_id}"),
109                request,
110                &self.request_options,
111            )
112            .await
113    }
114
115    /// Delete a thread.
116    #[crate::byot(T0 = std::fmt::Display, R = serde::de::DeserializeOwned)]
117    pub async fn delete(&self, thread_id: &str) -> Result<DeleteThreadResponse, OpenAIError> {
118        self.client
119            .delete(&format!("/threads/{thread_id}"), &self.request_options)
120            .await
121    }
122}