portkey_sdk/service/
runs.rs

1use std::future::Future;
2
3use crate::model::{
4    CreateRunRequest, ListRunStepsResponse, ListRunsResponse, ModifyRunRequest, PaginationParams,
5    Run, RunStep, SubmitToolOutputsRequest,
6};
7use crate::{PortkeyClient, Result};
8
9/// Service for managing runs.
10///
11/// # Example
12///
13/// ```no_run
14/// use portkey_sdk::{PortkeyConfig, PortkeyClient, Result};
15/// use portkey_sdk::service::RunsService;
16/// use portkey_sdk::model::CreateRunRequest;
17///
18/// # async fn example() -> Result<()> {
19/// let config = PortkeyConfig::builder()
20///     .with_api_key("your-api-key")
21///     .build()?;
22/// let client = PortkeyClient::new(config)?;
23///
24///     let run = client.create_run(
25///         "thread_abc123",
26///         CreateRunRequest {
27///             assistant_id: "asst_abc123".to_string(),
28///             ..Default::default()
29///         }
30///     ).await?;
31///
32///     println!("Created run: {}", run.id);
33///     Ok(())
34/// # }
35/// ```
36pub trait RunsService {
37    /// Create a run.
38    fn create_run(
39        &self,
40        thread_id: &str,
41        request: CreateRunRequest,
42    ) -> impl Future<Output = Result<Run>>;
43
44    /// Retrieves a run.
45    fn retrieve_run(&self, thread_id: &str, run_id: &str) -> impl Future<Output = Result<Run>>;
46
47    /// Modifies a run.
48    fn modify_run(
49        &self,
50        thread_id: &str,
51        run_id: &str,
52        request: ModifyRunRequest,
53    ) -> impl Future<Output = Result<Run>>;
54
55    /// Returns a list of runs belonging to a thread.
56    fn list_runs(
57        &self,
58        thread_id: &str,
59        params: PaginationParams,
60    ) -> impl Future<Output = Result<ListRunsResponse>>;
61
62    /// When a run has the status: "requires_action" and required_action.type is submit_tool_outputs,
63    /// this endpoint can be used to submit the outputs from the tool calls once they're all completed.
64    fn submit_tool_outputs(
65        &self,
66        thread_id: &str,
67        run_id: &str,
68        request: SubmitToolOutputsRequest,
69    ) -> impl Future<Output = Result<Run>>;
70
71    /// Cancels a run that is in_progress.
72    fn cancel_run(&self, thread_id: &str, run_id: &str) -> impl Future<Output = Result<Run>>;
73
74    /// Create a thread and run it in one request.
75    fn create_thread_and_run(&self, request: CreateRunRequest)
76    -> impl Future<Output = Result<Run>>;
77
78    /// Retrieves a run step.
79    fn retrieve_run_step(
80        &self,
81        thread_id: &str,
82        run_id: &str,
83        step_id: &str,
84    ) -> impl Future<Output = Result<RunStep>>;
85
86    /// Returns a list of run steps belonging to a run.
87    fn list_run_steps(
88        &self,
89        thread_id: &str,
90        run_id: &str,
91        params: PaginationParams,
92    ) -> impl Future<Output = Result<ListRunStepsResponse>>;
93}
94
95impl RunsService for PortkeyClient {
96    async fn create_run(&self, thread_id: &str, request: CreateRunRequest) -> Result<Run> {
97        #[cfg(feature = "tracing")]
98        tracing::debug!(
99            target: crate::TRACING_TARGET_SERVICE,
100            thread_id = %thread_id,
101            "Creating run"
102        );
103
104        let response = self
105            .send_json(
106                reqwest::Method::POST,
107                &format!("/threads/{}/runs", thread_id),
108                &request,
109            )
110            .await?;
111        let response = response.error_for_status()?;
112        let run: Run = response.json().await?;
113
114        #[cfg(feature = "tracing")]
115        tracing::debug!(
116            target: crate::TRACING_TARGET_SERVICE,
117            "Run created successfully"
118        );
119
120        Ok(run)
121    }
122
123    async fn retrieve_run(&self, thread_id: &str, run_id: &str) -> Result<Run> {
124        #[cfg(feature = "tracing")]
125        tracing::debug!(
126            target: crate::TRACING_TARGET_SERVICE,
127            thread_id = %thread_id,
128            run_id = %run_id,
129            "Retrieving run"
130        );
131
132        let response = self
133            .send(
134                reqwest::Method::GET,
135                &format!("/threads/{}/runs/{}", thread_id, run_id),
136            )
137            .await?;
138        let response = response.error_for_status()?;
139        let run: Run = response.json().await?;
140
141        #[cfg(feature = "tracing")]
142        tracing::debug!(
143            target: crate::TRACING_TARGET_SERVICE,
144            "Run retrieved successfully"
145        );
146
147        Ok(run)
148    }
149
150    async fn modify_run(
151        &self,
152        thread_id: &str,
153        run_id: &str,
154        request: ModifyRunRequest,
155    ) -> Result<Run> {
156        #[cfg(feature = "tracing")]
157        tracing::debug!(
158            target: crate::TRACING_TARGET_SERVICE,
159            thread_id = %thread_id,
160            run_id = %run_id,
161            "Modifying run"
162        );
163
164        let response = self
165            .send_json(
166                reqwest::Method::POST,
167                &format!("/threads/{}/runs/{}", thread_id, run_id),
168                &request,
169            )
170            .await?;
171        let response = response.error_for_status()?;
172        let run: Run = response.json().await?;
173
174        #[cfg(feature = "tracing")]
175        tracing::debug!(
176            target: crate::TRACING_TARGET_SERVICE,
177            "Run modified successfully"
178        );
179
180        Ok(run)
181    }
182
183    async fn list_runs(
184        &self,
185        thread_id: &str,
186        params: PaginationParams<'_>,
187    ) -> Result<ListRunsResponse> {
188        #[cfg(feature = "tracing")]
189        tracing::debug!(
190            target: crate::TRACING_TARGET_SERVICE,
191            thread_id = %thread_id,
192            "Listing runs"
193        );
194
195        let query_params = params.to_query_params();
196        let query_params_refs: Vec<(&str, &str)> =
197            query_params.iter().map(|(k, v)| (*k, v.as_str())).collect();
198
199        let response = self
200            .send_with_params(
201                reqwest::Method::GET,
202                &format!("/threads/{}/runs", thread_id),
203                &query_params_refs,
204            )
205            .await?;
206        let response = response.error_for_status()?;
207        let runs: ListRunsResponse = response.json().await?;
208
209        #[cfg(feature = "tracing")]
210        tracing::debug!(
211            target: crate::TRACING_TARGET_SERVICE,
212            "Runs retrieved successfully"
213        );
214
215        Ok(runs)
216    }
217
218    async fn submit_tool_outputs(
219        &self,
220        thread_id: &str,
221        run_id: &str,
222        request: SubmitToolOutputsRequest,
223    ) -> Result<Run> {
224        #[cfg(feature = "tracing")]
225        tracing::debug!(
226            target: crate::TRACING_TARGET_SERVICE,
227            thread_id = %thread_id,
228            run_id = %run_id,
229            "Submitting tool outputs"
230        );
231
232        let response = self
233            .send_json(
234                reqwest::Method::POST,
235                &format!("/threads/{}/runs/{}/submit_tool_outputs", thread_id, run_id),
236                &request,
237            )
238            .await?;
239        let response = response.error_for_status()?;
240        let run: Run = response.json().await?;
241
242        #[cfg(feature = "tracing")]
243        tracing::debug!(
244            target: crate::TRACING_TARGET_SERVICE,
245            "Tool outputs submitted successfully"
246        );
247
248        Ok(run)
249    }
250
251    async fn cancel_run(&self, thread_id: &str, run_id: &str) -> Result<Run> {
252        #[cfg(feature = "tracing")]
253        tracing::debug!(
254            target: crate::TRACING_TARGET_SERVICE,
255            thread_id = %thread_id,
256            run_id = %run_id,
257            "Cancelling run"
258        );
259
260        let response = self
261            .send_json(
262                reqwest::Method::POST,
263                &format!("/threads/{}/runs/{}/cancel", thread_id, run_id),
264                &serde_json::json!({}),
265            )
266            .await?;
267        let response = response.error_for_status()?;
268        let run: Run = response.json().await?;
269
270        #[cfg(feature = "tracing")]
271        tracing::debug!(
272            target: crate::TRACING_TARGET_SERVICE,
273            "Run cancelled successfully"
274        );
275
276        Ok(run)
277    }
278
279    async fn create_thread_and_run(&self, request: CreateRunRequest) -> Result<Run> {
280        #[cfg(feature = "tracing")]
281        tracing::debug!(
282            target: crate::TRACING_TARGET_SERVICE,
283            "Creating thread and run"
284        );
285
286        let response = self
287            .send_json(reqwest::Method::POST, "/threads/runs", &request)
288            .await?;
289        let response = response.error_for_status()?;
290        let run: Run = response.json().await?;
291
292        #[cfg(feature = "tracing")]
293        tracing::debug!(
294            target: crate::TRACING_TARGET_SERVICE,
295            "Thread and run created successfully"
296        );
297
298        Ok(run)
299    }
300
301    async fn retrieve_run_step(
302        &self,
303        thread_id: &str,
304        run_id: &str,
305        step_id: &str,
306    ) -> Result<RunStep> {
307        #[cfg(feature = "tracing")]
308        tracing::debug!(
309            target: crate::TRACING_TARGET_SERVICE,
310            thread_id = %thread_id,
311            run_id = %run_id,
312            step_id = %step_id,
313            "Retrieving run step"
314        );
315
316        let response = self
317            .send(
318                reqwest::Method::GET,
319                &format!("/threads/{}/runs/{}/steps/{}", thread_id, run_id, step_id),
320            )
321            .await?;
322        let response = response.error_for_status()?;
323        let step: RunStep = response.json().await?;
324
325        #[cfg(feature = "tracing")]
326        tracing::debug!(
327            target: crate::TRACING_TARGET_SERVICE,
328            "Run step retrieved successfully"
329        );
330
331        Ok(step)
332    }
333
334    async fn list_run_steps(
335        &self,
336        thread_id: &str,
337        run_id: &str,
338        params: PaginationParams<'_>,
339    ) -> Result<ListRunStepsResponse> {
340        #[cfg(feature = "tracing")]
341        tracing::debug!(
342            target: crate::TRACING_TARGET_SERVICE,
343            thread_id = %thread_id,
344            run_id = %run_id,
345            "Listing run steps"
346        );
347
348        let query_params = params.to_query_params();
349        let query_params_refs: Vec<(&str, &str)> =
350            query_params.iter().map(|(k, v)| (*k, v.as_str())).collect();
351
352        let response = self
353            .send_with_params(
354                reqwest::Method::GET,
355                &format!("/threads/{}/runs/{}/steps", thread_id, run_id),
356                &query_params_refs,
357            )
358            .await?;
359        let response = response.error_for_status()?;
360        let steps: ListRunStepsResponse = response.json().await?;
361
362        #[cfg(feature = "tracing")]
363        tracing::debug!(
364            target: crate::TRACING_TARGET_SERVICE,
365            "Run steps retrieved successfully"
366        );
367
368        Ok(steps)
369    }
370}