async_openai/assistants/
runs.rs

1use crate::{
2    assistants::Steps,
3    config::Config,
4    error::OpenAIError,
5    types::assistants::{
6        CreateRunRequest, ListRunsResponse, ModifyRunRequest, RunObject,
7        SubmitToolOutputsRunRequest,
8    },
9    Client, RequestOptions,
10};
11
12#[cfg(not(target_family = "wasm"))]
13use crate::types::assistants::AssistantEventStream;
14
15/// Represents an execution run on a thread.
16///
17/// Related guide: [Assistants](https://platform.openai.com/docs/assistants/overview)
18pub struct Runs<'c, C: Config> {
19    pub thread_id: String,
20    client: &'c Client<C>,
21    pub(crate) request_options: RequestOptions,
22}
23
24impl<'c, C: Config> Runs<'c, C> {
25    pub fn new(client: &'c Client<C>, thread_id: &str) -> Self {
26        Self {
27            client,
28            thread_id: thread_id.into(),
29            request_options: RequestOptions::new(),
30        }
31    }
32
33    ///  [Steps] API group
34    pub fn steps(&self, run_id: &str) -> Steps<'_, C> {
35        Steps::new(self.client, &self.thread_id, run_id)
36    }
37
38    /// Create a run.
39    #[crate::byot(T0 = serde::Serialize, R = serde::de::DeserializeOwned)]
40    pub async fn create(&self, request: CreateRunRequest) -> Result<RunObject, OpenAIError> {
41        self.client
42            .post(
43                &format!("/threads/{}/runs", self.thread_id),
44                request,
45                &self.request_options,
46            )
47            .await
48    }
49
50    /// Create a run.
51    ///
52    /// byot: You must ensure "stream: true" in serialized `request`
53    #[cfg(not(target_family = "wasm"))]
54    #[crate::byot(
55        T0 = serde::Serialize,
56        R = serde::de::DeserializeOwned,
57        stream = "true",
58        where_clause = "R: std::marker::Send + 'static + TryFrom<eventsource_stream::Event, Error = OpenAIError>"
59    )]
60    #[allow(unused_mut)]
61    pub async fn create_stream(
62        &self,
63        mut request: CreateRunRequest,
64    ) -> Result<AssistantEventStream, OpenAIError> {
65        #[cfg(not(feature = "byot"))]
66        {
67            if request.stream.is_some() && !request.stream.unwrap() {
68                return Err(OpenAIError::InvalidArgument(
69                    "When stream is false, use Runs::create".into(),
70                ));
71            }
72
73            request.stream = Some(true);
74        }
75
76        Ok(self
77            .client
78            .post_stream_mapped_raw_events(
79                &format!("/threads/{}/runs", self.thread_id),
80                request,
81                &self.request_options,
82                TryFrom::try_from,
83            )
84            .await)
85    }
86
87    /// Retrieves a run.
88    #[crate::byot(T0 = std::fmt::Display, R = serde::de::DeserializeOwned)]
89    pub async fn retrieve(&self, run_id: &str) -> Result<RunObject, OpenAIError> {
90        self.client
91            .get(
92                &format!("/threads/{}/runs/{run_id}", self.thread_id),
93                &self.request_options,
94            )
95            .await
96    }
97
98    /// Modifies a run.
99    #[crate::byot(T0 = std::fmt::Display, T1 = serde::Serialize, R = serde::de::DeserializeOwned)]
100    pub async fn update(
101        &self,
102        run_id: &str,
103        request: ModifyRunRequest,
104    ) -> Result<RunObject, OpenAIError> {
105        self.client
106            .post(
107                &format!("/threads/{}/runs/{run_id}", self.thread_id),
108                request,
109                &self.request_options,
110            )
111            .await
112    }
113
114    /// Returns a list of runs belonging to a thread.
115    #[crate::byot(R = serde::de::DeserializeOwned)]
116    pub async fn list(&self) -> Result<ListRunsResponse, OpenAIError> {
117        self.client
118            .get(
119                &format!("/threads/{}/runs", self.thread_id),
120                &self.request_options,
121            )
122            .await
123    }
124
125    /// When a run has the status: "requires_action" and required_action.type is submit_tool_outputs, this endpoint can be used to submit the outputs from the tool calls once they're all completed. All outputs must be submitted in a single request.
126    #[crate::byot(T0 = std::fmt::Display, T1 = serde::Serialize, R = serde::de::DeserializeOwned)]
127    pub async fn submit_tool_outputs(
128        &self,
129        run_id: &str,
130        request: SubmitToolOutputsRunRequest,
131    ) -> Result<RunObject, OpenAIError> {
132        self.client
133            .post(
134                &format!(
135                    "/threads/{}/runs/{run_id}/submit_tool_outputs",
136                    self.thread_id
137                ),
138                request,
139                &self.request_options,
140            )
141            .await
142    }
143
144    /// byot: You must ensure "stream: true" in serialized `request`
145    #[cfg(not(target_family = "wasm"))]
146    #[crate::byot(
147        T0 = std::fmt::Display,
148        T1 = serde::Serialize,
149        R = serde::de::DeserializeOwned,
150        stream = "true",
151        where_clause = "R: std::marker::Send + 'static + TryFrom<eventsource_stream::Event, Error = OpenAIError>"
152    )]
153    #[allow(unused_mut)]
154    pub async fn submit_tool_outputs_stream(
155        &self,
156        run_id: &str,
157        mut request: SubmitToolOutputsRunRequest,
158    ) -> Result<AssistantEventStream, OpenAIError> {
159        #[cfg(not(feature = "byot"))]
160        {
161            if request.stream.is_some() && !request.stream.unwrap() {
162                return Err(OpenAIError::InvalidArgument(
163                    "When stream is false, use Runs::submit_tool_outputs".into(),
164                ));
165            }
166
167            request.stream = Some(true);
168        }
169
170        Ok(self
171            .client
172            .post_stream_mapped_raw_events(
173                &format!(
174                    "/threads/{}/runs/{run_id}/submit_tool_outputs",
175                    self.thread_id
176                ),
177                request,
178                &self.request_options,
179                TryFrom::try_from,
180            )
181            .await)
182    }
183
184    /// Cancels a run that is `in_progress`
185    #[crate::byot(T0 = std::fmt::Display, R = serde::de::DeserializeOwned)]
186    pub async fn cancel(&self, run_id: &str) -> Result<RunObject, OpenAIError> {
187        self.client
188            .post(
189                &format!("/threads/{}/runs/{run_id}/cancel", self.thread_id),
190                (),
191                &self.request_options,
192            )
193            .await
194    }
195}