async_openai/
runs.rs

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