Skip to main content

uarp_sdk/generated/api/
runs.rs

1// Code generated by @uarp/codegen from spec/openapi.json. DO NOT EDIT.
2//!
3//! Agent execution runs, SSE streaming, HITL, continuation
4
5#![allow(unused_imports, clippy::too_many_arguments)]
6
7use reqwest::Method;
8use serde::{Deserialize, Serialize};
9use futures_core::Stream;
10
11use crate::client::{Client, Request, NO_BODY, NO_QUERY};
12use crate::error::Result;
13use crate::generated::models;
14use crate::multipart::{field_text, FilePart};
15use crate::pagination::CursorGuard;
16use crate::sse::EventStream;
17use crate::util::encode_path;
18
19/// Query and header parameters for `getRun`.
20#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
21pub struct GetRunParams {
22    /// Set to `true` to include `changed_files` in the response. Opt-in because this endpoint is
23    /// polled and the paths live in their own key range: serving them unconditionally would add a
24    /// KV list to a hot read for every caller that never looks at them.
25    #[serde(default, skip_serializing_if = "Option::is_none")]
26    pub changed_files: Option<models::GetRunChangedFiles>,
27}
28
29/// Query and header parameters for `getRunFeedback`.
30#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
31pub struct GetRunFeedbackParams {
32    #[serde(default, skip_serializing_if = "Option::is_none")]
33    pub message_id: Option<String>,
34}
35
36/// Query and header parameters for `listRuns`.
37#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
38pub struct ListRunsParams {
39    #[serde(default, skip_serializing_if = "Option::is_none")]
40    pub agent_id: Option<String>,
41    #[serde(default, skip_serializing_if = "Option::is_none")]
42    pub session_id: Option<String>,
43    #[serde(default, skip_serializing_if = "Option::is_none")]
44    pub status: Option<String>,
45    #[serde(default, skip_serializing_if = "Option::is_none")]
46    pub limit: Option<i64>,
47    #[serde(default, skip_serializing_if = "Option::is_none")]
48    pub cursor: Option<String>,
49    /// `desc` (default) newest first, `asc` oldest first. Any other value is a 400 rather than a
50    /// silent default, so a typo surfaces as an error instead of as plausible-looking data.
51    ///
52    /// Use `asc` instead of paging toward the end: the cursor is opaque, so there is no way to jump
53    /// to the far end, but `asc` puts that end on page one.
54    #[serde(default, skip_serializing_if = "Option::is_none")]
55    pub order: Option<models::ListRunsOrder>,
56}
57
58/// Query and header parameters for `streamRunEvents`.
59#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
60pub struct StreamRunEventsParams {
61    /// Short-lived SSE/WebSocket token (mint via `POST /api/v1/auth/sse-tokens`) or full API key.
62    /// Used by browser EventSource which cannot set Authorization header.
63    #[serde(default, skip_serializing_if = "Option::is_none")]
64    pub token: Option<String>,
65    /// SSE resumption cursor. The browser's EventSource sets this automatically on reconnect;
66    /// servers replay events strictly after this id.
67    #[serde(skip)]
68    pub last_event_id: Option<String>,
69}
70
71/// Query and header parameters for `waitRun`.
72#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
73pub struct WaitRunParams {
74    /// Max seconds to wait. Default from server config (e.g. 60).
75    #[serde(default, skip_serializing_if = "Option::is_none")]
76    pub timeout_sec: Option<i64>,
77}
78
79/// Agent execution runs, SSE streaming, HITL, continuation
80#[derive(Debug, Clone)]
81pub struct RunsApi {
82    pub(crate) client: Client,
83}
84
85impl Client {
86    /// Agent execution runs, SSE streaming, HITL, continuation
87    pub fn runs(&self) -> RunsApi {
88        RunsApi { client: self.clone() }
89    }
90}
91
92impl RunsApi {
93    /// Approve a pending tool call (HITL)
94    ///
95    /// The body is optional; sending none approves without a message. `reject` has always taken a
96    /// body, and the asymmetry was an omission rather than a design.
97    ///
98    /// `POST /api/v1/runs/{runId}/approve`
99    ///
100    /// Required scopes: `runs:create`.
101    pub async fn approve_run(&self, run_id: &str, body: &models::RunApproveRequest) -> Result<models::ApproveRunResponse> {
102        self.client
103            .request_json(Request {
104                method: Method::POST,
105                path: format!("/api/v1/runs/{}/approve", encode_path(run_id)),
106                query: NO_QUERY,
107                body: Some(body),
108                headers: Vec::new(),
109                idempotent: true,
110            })
111            .await
112    }
113
114    /// Cancel a run
115    ///
116    /// `POST /api/v1/runs/{runId}/cancel`
117    ///
118    /// Required scopes: `runs:create`.
119    pub async fn cancel(&self, run_id: &str) -> Result<models::CancelRunResponse> {
120        self.client
121            .request_json(Request {
122                method: Method::POST,
123                path: format!("/api/v1/runs/{}/cancel", encode_path(run_id)),
124                query: NO_QUERY,
125                body: NO_BODY,
126                headers: Vec::new(),
127                idempotent: true,
128            })
129            .await
130    }
131
132    /// Continue a run from a continuation token
133    ///
134    /// Decodes the token, loads the checkpoint, and re-schedules the run.
135    ///
136    /// `POST /api/v1/runs/{runId}/continue`
137    ///
138    /// Required scopes: `runs:create`.
139    pub async fn continue_run(&self, run_id: &str, body: &models::ContinueRunRequest) -> Result<models::ContinueRunResponse> {
140        self.client
141            .request_json(Request {
142                method: Method::POST,
143                path: format!("/api/v1/runs/{}/continue", encode_path(run_id)),
144                query: NO_QUERY,
145                body: Some(body),
146                headers: Vec::new(),
147                idempotent: true,
148            })
149            .await
150    }
151
152    /// Create and schedule a run
153    ///
154    /// Creates a run and schedules it for execution. Recommended: send Idempotency-Key header to
155    /// avoid duplicate runs on retries; a repeated request with the same key returns the cached 202
156    /// response (same run_id). Pin a specific agent version with `version` to bypass the head
157    /// pointer.
158    ///
159    /// `POST /api/v1/runs`
160    ///
161    /// Required scopes: `runs:create`.
162    pub async fn create(&self, body: &models::CreateRunRequest) -> Result<models::Run> {
163        self.client
164            .request_json(Request {
165                method: Method::POST,
166                path: "/api/v1/runs".to_string(),
167                query: NO_QUERY,
168                body: Some(body),
169                headers: Vec::new(),
170                idempotent: true,
171            })
172            .await
173    }
174
175    /// Create checkpoint for a run
176    ///
177    /// `POST /api/v1/runs/{runId}/checkpoint`
178    ///
179    /// Required scopes: `runs:create`.
180    pub async fn create_run_checkpoint(&self, run_id: &str) -> Result<models::RunCheckpoint> {
181        self.client
182            .request_json(Request {
183                method: Method::POST,
184                path: format!("/api/v1/runs/{}/checkpoint", encode_path(run_id)),
185                query: NO_QUERY,
186                body: NO_BODY,
187                headers: Vec::new(),
188                idempotent: true,
189            })
190            .await
191    }
192
193    /// What will this run cost
194    ///
195    /// Prices a run before it happens, from the agent's own recent runs. Read-only: it dispatches
196    /// nothing and stores nothing, and it needs only `runs:read`.
197    ///
198    /// When the model has no known rate the answer is still 200 with `estimated_cost_usd: 0` and
199    /// `pricing: "unknown"` — read `basis.pricing` before showing the figure, or a client will
200    /// present “free” for “we have no idea”.
201    ///
202    /// `POST /api/v1/runs/estimate`
203    ///
204    /// Required scopes: `runs:read`.
205    pub async fn estimate_run_cost(&self, body: &models::EstimateRunCostRequest) -> Result<models::RunCostEstimate> {
206        self.client
207            .request_json(Request {
208                method: Method::POST,
209                path: "/api/v1/runs/estimate".to_string(),
210                query: NO_QUERY,
211                body: Some(body),
212                headers: Vec::new(),
213                idempotent: true,
214            })
215            .await
216    }
217
218    /// Export run events as JSONL
219    ///
220    /// `GET /api/v1/runs/{runId}/events/export`
221    ///
222    /// Required scopes: `runs:read`.
223    pub async fn export_run_events(&self, run_id: &str) -> Result<String> {
224        self.client
225            .request_text(Request {
226                method: Method::GET,
227                path: format!("/api/v1/runs/{}/events/export", encode_path(run_id)),
228                query: NO_QUERY,
229                body: NO_BODY,
230                headers: Vec::new(),
231                idempotent: false,
232            })
233            .await
234    }
235
236    /// Get run status and result
237    ///
238    /// `GET /api/v1/runs/{runId}`
239    ///
240    /// Required scopes: `runs:read`.
241    pub async fn get(&self, run_id: &str, params: &GetRunParams) -> Result<models::GetRunResponse> {
242        self.client
243            .request_json(Request {
244                method: Method::GET,
245                path: format!("/api/v1/runs/{}", encode_path(run_id)),
246                query: Some(params),
247                body: NO_BODY,
248                headers: Vec::new(),
249                idempotent: false,
250            })
251            .await
252    }
253
254    /// Get audit trail for a run
255    ///
256    /// `GET /api/v1/runs/{runId}/audit-log`
257    ///
258    /// Required scopes: `runs:read`.
259    pub async fn get_run_audit_log(&self, run_id: &str) -> Result<models::GetRunAuditLogResponse> {
260        self.client
261            .request_json(Request {
262                method: Method::GET,
263                path: format!("/api/v1/runs/{}/audit-log", encode_path(run_id)),
264                query: NO_QUERY,
265                body: NO_BODY,
266                headers: Vec::new(),
267                idempotent: false,
268            })
269            .await
270    }
271
272    /// Get user feedback for a run
273    ///
274    /// `GET /api/v1/runs/{runId}/feedback`
275    ///
276    /// Required scopes: `runs:read`.
277    pub async fn get_run_feedback(&self, run_id: &str, params: &GetRunFeedbackParams) -> Result<serde_json::Value> {
278        self.client
279            .request_json(Request {
280                method: Method::GET,
281                path: format!("/api/v1/runs/{}/feedback", encode_path(run_id)),
282                query: Some(params),
283                body: NO_BODY,
284                headers: Vec::new(),
285                idempotent: false,
286            })
287            .await
288    }
289
290    /// Get run queue position
291    ///
292    /// `GET /api/v1/runs/{runId}/queue-position`
293    ///
294    /// Required scopes: `runs:read`.
295    pub async fn get_run_queue_position(&self, run_id: &str) -> Result<models::GetRunQueuePositionResponse> {
296        self.client
297            .request_json(Request {
298                method: Method::GET,
299                path: format!("/api/v1/runs/{}/queue-position", encode_path(run_id)),
300                query: NO_QUERY,
301                body: NO_BODY,
302                headers: Vec::new(),
303                idempotent: false,
304            })
305            .await
306    }
307
308    /// List steps for a run
309    ///
310    /// Returns the ordered list of steps executed during a run, with per-step metrics including
311    /// tokens, cost, and tool calls.
312    ///
313    /// `GET /api/v1/runs/{runId}/steps`
314    ///
315    /// Required scopes: `runs:read`.
316    pub async fn get_run_steps(&self, run_id: &str) -> Result<models::GetRunStepsResponse> {
317        self.client
318            .request_json(Request {
319                method: Method::GET,
320                path: format!("/api/v1/runs/{}/steps", encode_path(run_id)),
321                query: NO_QUERY,
322                body: NO_BODY,
323                headers: Vec::new(),
324                idempotent: false,
325            })
326            .await
327    }
328
329    /// List all runs for tenant
330    ///
331    /// Ordered NEWEST FIRST, and that is a guarantee, not an accident of storage: page one is the
332    /// most recent runs. Do not page toward the end to find recent activity — a client that walks
333    /// `has_more` looking for the newest page now walks away from it. This was previously true only
334    /// of the handler, so clients hedged by paging or by re-sorting, and one shipped a twelve-hop
335    /// walk that reversed meaning the day the order changed. Note the sibling
336    /// `/api/v1/teams/{teamId}/runs` is deliberately the other way round — oldest first — because a
337    /// team transcript reads forward.
338    ///
339    /// `GET /api/v1/runs`
340    ///
341    /// Required scopes: `runs:read`.
342    pub async fn list(&self, params: &ListRunsParams) -> Result<models::ListRunsResponse> {
343        self.client
344            .request_json(Request {
345                method: Method::GET,
346                path: "/api/v1/runs".to_string(),
347                query: Some(params),
348                body: NO_BODY,
349                headers: Vec::new(),
350                idempotent: false,
351            })
352            .await
353    }
354
355    /// Stream every item returned by `listRuns`, following the `cursor` cursor until the server
356    /// reports no further pages.
357    pub fn list_all<'a>(&'a self, params: &'a ListRunsParams) -> impl Stream<Item = Result<models::Run>> + 'a {
358        async_stream::try_stream! {
359            let mut guard = CursorGuard::new();
360            let mut cursor = params.cursor.clone();
361            loop {
362                let mut page_params = params.clone();
363                page_params.cursor = cursor.clone();
364                let page = self.list(&page_params).await?;
365                let items = page.items;
366                let was_empty = items.is_empty();
367                for item in items {
368                    yield item;
369                }
370                match guard.advance(page.cursor, Some(page.has_more), was_empty) {
371                    Some(next) => cursor = Some(next),
372                    None => break,
373                }
374            }
375        }
376    }
377
378    /// List run artifacts
379    ///
380    /// `GET /api/v1/runs/{runId}/artifacts`
381    ///
382    /// Required scopes: `runs:read`.
383    pub async fn list_run_artifacts(&self, run_id: &str) -> Result<models::ListRunArtifactsResponse> {
384        self.client
385            .request_json(Request {
386                method: Method::GET,
387                path: format!("/api/v1/runs/{}/artifacts", encode_path(run_id)),
388                query: NO_QUERY,
389                body: NO_BODY,
390                headers: Vec::new(),
391                idempotent: false,
392            })
393            .await
394    }
395
396    /// List checkpoints for a run
397    ///
398    /// `GET /api/v1/runs/{runId}/checkpoints`
399    ///
400    /// Required scopes: `runs:read`.
401    pub async fn list_run_checkpoints(&self, run_id: &str) -> Result<models::ListRunCheckpointsResponse> {
402        self.client
403            .request_json(Request {
404                method: Method::GET,
405                path: format!("/api/v1/runs/{}/checkpoints", encode_path(run_id)),
406                query: NO_QUERY,
407                body: NO_BODY,
408                headers: Vec::new(),
409                idempotent: false,
410            })
411            .await
412    }
413
414    /// Pause a run
415    ///
416    /// `POST /api/v1/runs/{runId}/pause`
417    ///
418    /// Required scopes: `runs:create`.
419    pub async fn pause_run(&self, run_id: &str) -> Result<models::PauseRunResponse> {
420        self.client
421            .request_json(Request {
422                method: Method::POST,
423                path: format!("/api/v1/runs/{}/pause", encode_path(run_id)),
424                query: NO_QUERY,
425                body: NO_BODY,
426                headers: Vec::new(),
427                idempotent: true,
428            })
429            .await
430    }
431
432    /// Reject a pending tool call (HITL)
433    ///
434    /// `POST /api/v1/runs/{runId}/reject`
435    ///
436    /// Required scopes: `runs:create`.
437    pub async fn reject_run(&self, run_id: &str, body: &models::RejectRunRequest) -> Result<models::RejectRunResponse> {
438        self.client
439            .request_json(Request {
440                method: Method::POST,
441                path: format!("/api/v1/runs/{}/reject", encode_path(run_id)),
442                query: NO_QUERY,
443                body: Some(body),
444                headers: Vec::new(),
445                idempotent: true,
446            })
447            .await
448    }
449
450    /// Replay a run for determinism check
451    ///
452    /// `POST /api/v1/runs/{runId}/replay`
453    ///
454    /// Required scopes: `runs:read`.
455    pub async fn replay_run(&self, run_id: &str) -> Result<serde_json::Map<String, serde_json::Value>> {
456        self.client
457            .request_json(Request {
458                method: Method::POST,
459                path: format!("/api/v1/runs/{}/replay", encode_path(run_id)),
460                query: NO_QUERY,
461                body: NO_BODY,
462                headers: Vec::new(),
463                idempotent: true,
464            })
465            .await
466    }
467
468    /// Send user input response to a paused run
469    ///
470    /// `POST /api/v1/runs/{runId}/respond`
471    ///
472    /// Required scopes: `runs:create`.
473    pub async fn respond_to_run(&self, run_id: &str, body: &models::RespondToRunRequest) -> Result<models::RespondToRunResponse> {
474        self.client
475            .request_json(Request {
476                method: Method::POST,
477                path: format!("/api/v1/runs/{}/respond", encode_path(run_id)),
478                query: NO_QUERY,
479                body: Some(body),
480                headers: Vec::new(),
481                idempotent: true,
482            })
483            .await
484    }
485
486    /// Resume a run
487    ///
488    /// `POST /api/v1/runs/{runId}/resume`
489    ///
490    /// Required scopes: `runs:create`.
491    pub async fn resume(&self, run_id: &str) -> Result<models::ResumeRunResponse> {
492        self.client
493            .request_json(Request {
494                method: Method::POST,
495                path: format!("/api/v1/runs/{}/resume", encode_path(run_id)),
496                query: NO_QUERY,
497                body: NO_BODY,
498                headers: Vec::new(),
499                idempotent: true,
500            })
501            .await
502    }
503
504    /// Save user feedback/reaction for a run
505    ///
506    /// One reaction per (message, caller); a second PUT for the same `message_id` replaces the
507    /// first. `message_id` is whatever string the client attaches to a message — the platform
508    /// stores it verbatim (max 256 chars) and does not check it against the transcript, which today
509    /// carries no message identifier (see `getSessionMessages`). Unknown body fields are dropped.
510    /// There is no way to remove a reaction: `null` and `""` are rejected with 422 and DELETE is
511    /// 405 (measured 2026-09-10).
512    ///
513    /// `PUT /api/v1/runs/{runId}/feedback`
514    ///
515    /// Required scopes: `runs:create`.
516    pub async fn set_run_feedback(&self, run_id: &str, body: &models::SetRunFeedbackRequest) -> Result<models::RunFeedbackSet> {
517        self.client
518            .request_json(Request {
519                method: Method::PUT,
520                path: format!("/api/v1/runs/{}/feedback", encode_path(run_id)),
521                query: NO_QUERY,
522                body: Some(body),
523                headers: Vec::new(),
524                idempotent: true,
525            })
526            .await
527    }
528
529    /// Stream run events via SSE
530    ///
531    /// Real-time event stream for a run. Supports `Last-Event-ID` header (or `?last_event_id=`) for
532    /// reconnection. Stream closes when run reaches terminal status. Each event payload includes
533    /// `stream_type`: lifecycle (run.*), assistant (llm.chunk), tool (tool.*), or other — use it to
534    /// filter client-side. Browsers using EventSource (which cannot set Authorization headers)
535    /// should mint a 60-s SSE token via `POST /api/v1/auth/sse-tokens` and pass it as `?token=`.
536    ///
537    /// `GET /api/v1/runs/{runId}/events`
538    ///
539    /// Required scopes: `events:read`.
540    ///
541    /// Returns a server-sent event stream.
542    pub fn stream_run_events(&self, run_id: &str, params: &StreamRunEventsParams) -> EventStream {
543        let mut headers: Vec<(&'static str, String)> = Vec::new();
544        if let Some(value) = &params.last_event_id {
545            headers.push(("Last-Event-ID", value.clone()));
546        }
547        self.client.request_stream(
548            &format!("/api/v1/runs/{}/events", encode_path(run_id)),
549            Some(params),
550            headers,
551        )
552    }
553
554    /// Wait for run to reach terminal status
555    ///
556    /// If the run is already completed, failed, cancelled, timeout, or guardrail_blocked, returns
557    /// 200 with the run immediately. Otherwise polls until terminal status or timeout_sec. On
558    /// timeout returns 202 with status still_running.
559    ///
560    /// `GET /api/v1/runs/{runId}/wait`
561    ///
562    /// Required scopes: `runs:read`.
563    pub async fn wait_run(&self, run_id: &str, params: &WaitRunParams) -> Result<models::Run> {
564        self.client
565            .request_json(Request {
566                method: Method::GET,
567                path: format!("/api/v1/runs/{}/wait", encode_path(run_id)),
568                query: Some(params),
569                body: NO_BODY,
570                headers: Vec::new(),
571                idempotent: false,
572            })
573            .await
574    }
575}