uarp_sdk/generated/api/missions.rs
1// Code generated by @uarp/codegen from spec/openapi.json. DO NOT EDIT.
2//!
3//! Mission Execution Framework: goal → objectives → authorization gate → execution →
4//! after-action review
5
6#![allow(unused_imports, clippy::too_many_arguments)]
7
8use reqwest::Method;
9use serde::{Deserialize, Serialize};
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::sse::EventStream;
16use crate::util::encode_path;
17
18/// Query and header parameters for `listMissions`.
19#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
20pub struct ListMissionsParams {
21 /// Scope to one chat session — a cheaper scan than the tenant-wide list.
22 #[serde(default, skip_serializing_if = "Option::is_none")]
23 pub session_id: Option<String>,
24 /// Capped at 200; a non-numeric or non-positive value falls back to 50.
25 #[serde(default, skip_serializing_if = "Option::is_none")]
26 pub limit: Option<i64>,
27}
28
29/// Mission Execution Framework: goal → objectives → authorization gate → execution →
30/// after-action review
31#[derive(Debug, Clone)]
32pub struct MissionsApi {
33 pub(crate) client: Client,
34}
35
36impl Client {
37 /// Mission Execution Framework: goal → objectives → authorization gate → execution →
38 /// after-action review
39 pub fn missions(&self) -> MissionsApi {
40 MissionsApi { client: self.clone() }
41 }
42}
43
44impl MissionsApi {
45 /// Abort a mission
46 ///
47 /// Terminal and not resumable. The in-flight walk is signalled to stop between objectives, so
48 /// an abort ends spending rather than only marking the record. The body is optional.
49 ///
50 /// MEF is gated twice: globally by the server flag and per tenant by `mef_config.enabled`. When
51 /// either is off the route answers **404** with a plain body — deliberately the same answer as
52 /// a mission that does not exist, so an opted-out tenant cannot discover the surface.
53 ///
54 /// `POST /api/v1/missions/{missionId}/abort`
55 ///
56 /// Required scopes: `agents:write`.
57 pub async fn abort_mission(&self, mission_id: &str, body: &models::AbortMissionRequest) -> Result<models::Mission> {
58 self.client
59 .request_json(Request {
60 method: Method::POST,
61 path: format!("/api/v1/missions/{}/abort", encode_path(mission_id)),
62 query: NO_QUERY,
63 body: Some(body),
64 headers: Vec::new(),
65 idempotent: true,
66 })
67 .await
68 }
69
70 /// Pass the authorization gate
71 ///
72 /// Moves a mission held at `awaiting_authorization` on to `executing`. It does not start the
73 /// walk — call `/run` after this.
74 ///
75 /// MEF is gated twice: globally by the server flag and per tenant by `mef_config.enabled`. When
76 /// either is off the route answers **404** with a plain body — deliberately the same answer as
77 /// a mission that does not exist, so an opted-out tenant cannot discover the surface.
78 ///
79 /// `POST /api/v1/missions/{missionId}/authorize`
80 ///
81 /// Required scopes: `agents:write`.
82 pub async fn authorize_mission(&self, mission_id: &str) -> Result<models::Mission> {
83 self.client
84 .request_json(Request {
85 method: Method::POST,
86 path: format!("/api/v1/missions/{}/authorize", encode_path(mission_id)),
87 query: NO_QUERY,
88 body: NO_BODY,
89 headers: Vec::new(),
90 idempotent: true,
91 })
92 .await
93 }
94
95 /// Read a mission
96 ///
97 /// The record as stored. Poll this alongside the event stream — the stream is the fast path,
98 /// this is the authoritative one.
99 ///
100 /// MEF is gated twice: globally by the server flag and per tenant by `mef_config.enabled`. When
101 /// either is off the route answers **404** with a plain body — deliberately the same answer as
102 /// a mission that does not exist, so an opted-out tenant cannot discover the surface.
103 ///
104 /// `GET /api/v1/missions/{missionId}`
105 ///
106 /// Required scopes: `agents:read`.
107 pub async fn get(&self, mission_id: &str) -> Result<models::Mission> {
108 self.client
109 .request_json(Request {
110 method: Method::GET,
111 path: format!("/api/v1/missions/{}", encode_path(mission_id)),
112 query: NO_QUERY,
113 body: NO_BODY,
114 headers: Vec::new(),
115 idempotent: false,
116 })
117 .await
118 }
119
120 /// Read the after-action review
121 ///
122 /// Available once the mission is terminal. Before that the answer is 404 — the review is built,
123 /// not partially accumulated, so there is nothing truthful to return early.
124 ///
125 /// MEF is gated twice: globally by the server flag and per tenant by `mef_config.enabled`. When
126 /// either is off the route answers **404** with a plain body — deliberately the same answer as
127 /// a mission that does not exist, so an opted-out tenant cannot discover the surface.
128 ///
129 /// `GET /api/v1/missions/{missionId}/aar`
130 ///
131 /// Required scopes: `agents:read`.
132 pub async fn get_mission_aar(&self, mission_id: &str) -> Result<models::Aar> {
133 self.client
134 .request_json(Request {
135 method: Method::GET,
136 path: format!("/api/v1/missions/{}/aar", encode_path(mission_id)),
137 query: NO_QUERY,
138 body: NO_BODY,
139 headers: Vec::new(),
140 idempotent: false,
141 })
142 .await
143 }
144
145 /// List missions
146 ///
147 /// Most recent first. Without `session_id` this is the tenant-wide list.
148 ///
149 /// MEF is gated twice: globally by the server flag and per tenant by `mef_config.enabled`. When
150 /// either is off the route answers **404** with a plain body — deliberately the same answer as
151 /// a mission that does not exist, so an opted-out tenant cannot discover the surface.
152 ///
153 /// `GET /api/v1/missions`
154 ///
155 /// Required scopes: `agents:read`.
156 pub async fn list(&self, params: &ListMissionsParams) -> Result<models::ListMissionsResponse> {
157 self.client
158 .request_json(Request {
159 method: Method::GET,
160 path: "/api/v1/missions".to_string(),
161 query: Some(params),
162 body: NO_BODY,
163 headers: Vec::new(),
164 idempotent: false,
165 })
166 .await
167 }
168
169 /// List a mission's objectives
170 ///
171 /// Full objective records, including budgets spent so far — `Mission.objective_ids` carries
172 /// only the ids.
173 ///
174 /// MEF is gated twice: globally by the server flag and per tenant by `mef_config.enabled`. When
175 /// either is off the route answers **404** with a plain body — deliberately the same answer as
176 /// a mission that does not exist, so an opted-out tenant cannot discover the surface.
177 ///
178 /// `GET /api/v1/missions/{missionId}/objectives`
179 ///
180 /// Required scopes: `agents:read`.
181 pub async fn list_mission_objectives(&self, mission_id: &str) -> Result<models::ListMissionObjectivesResponse> {
182 self.client
183 .request_json(Request {
184 method: Method::GET,
185 path: format!("/api/v1/missions/{}/objectives", encode_path(mission_id)),
186 query: NO_QUERY,
187 body: NO_BODY,
188 headers: Vec::new(),
189 idempotent: false,
190 })
191 .await
192 }
193
194 /// Pause a running mission
195 ///
196 /// Cooperative: the walk is asked to hold at the next safe point, so the record reaches
197 /// `paused` after the current objective settles, not at the moment of the call — poll for the
198 /// status change. Only a mission running **in this process** can be paused; anything else is
199 /// 409.
200 ///
201 /// MEF is gated twice: globally by the server flag and per tenant by `mef_config.enabled`. When
202 /// either is off the route answers **404** with a plain body — deliberately the same answer as
203 /// a mission that does not exist, so an opted-out tenant cannot discover the surface.
204 ///
205 /// `POST /api/v1/missions/{missionId}/pause`
206 ///
207 /// Required scopes: `agents:write`.
208 pub async fn pause_mission(&self, mission_id: &str) -> Result<models::PauseMissionResponse> {
209 self.client
210 .request_json(Request {
211 method: Method::POST,
212 path: format!("/api/v1/missions/{}/pause", encode_path(mission_id)),
213 query: NO_QUERY,
214 body: NO_BODY,
215 headers: Vec::new(),
216 idempotent: true,
217 })
218 .await
219 }
220
221 /// Resume a paused mission
222 ///
223 /// Returns the mission to `executing` and relaunches the walk. Verified objectives are reloaded
224 /// from their checkpoints and the blocked objective continues against its persisted budget, so
225 /// a resume does not re-spend what a completed objective already cost. A mission already
226 /// running answers 409.
227 ///
228 /// MEF is gated twice: globally by the server flag and per tenant by `mef_config.enabled`. When
229 /// either is off the route answers **404** with a plain body — deliberately the same answer as
230 /// a mission that does not exist, so an opted-out tenant cannot discover the surface.
231 ///
232 /// `POST /api/v1/missions/{missionId}/resume`
233 ///
234 /// Required scopes: `agents:write`.
235 pub async fn resume(&self, mission_id: &str) -> Result<models::ResumeMissionResponse> {
236 self.client
237 .request_json(Request {
238 method: Method::POST,
239 path: format!("/api/v1/missions/{}/resume", encode_path(mission_id)),
240 query: NO_QUERY,
241 body: NO_BODY,
242 headers: Vec::new(),
243 idempotent: true,
244 })
245 .await
246 }
247
248 /// Start executing a mission
249 ///
250 /// Answers immediately; the executor walk is detached. Watch progress on the event stream or by
251 /// polling the mission — this endpoint used to run the walk synchronously and was killed by the
252 /// edge proxy's two-minute timeout before a multi-objective mission could finish.
253 ///
254 /// A second call while a walk is in flight is a no-op that answers **200** with `accepted:
255 /// false` and `already_running: true`, not 202 and not an error: the executor is not safe under
256 /// concurrent walks over one mission. Requires status `executing` — anything else is 409,
257 /// including a mission still waiting on its authorization gate.
258 ///
259 /// MEF is gated twice: globally by the server flag and per tenant by `mef_config.enabled`. When
260 /// either is off the route answers **404** with a plain body — deliberately the same answer as
261 /// a mission that does not exist, so an opted-out tenant cannot discover the surface.
262 ///
263 /// `POST /api/v1/missions/{missionId}/run`
264 ///
265 /// Required scopes: `agents:write`.
266 pub async fn run(&self, mission_id: &str) -> Result<models::RunMissionResponse> {
267 self.client
268 .request_json(Request {
269 method: Method::POST,
270 path: format!("/api/v1/missions/{}/run", encode_path(mission_id)),
271 query: NO_QUERY,
272 body: NO_BODY,
273 headers: Vec::new(),
274 idempotent: true,
275 })
276 .await
277 }
278
279 /// Start a mission
280 ///
281 /// Two ways in. Supply `plan` and it is used as written. Omit it and the server's LLM planner
282 /// decomposes `goal`, which requires `available_agents` and a planner wired on the server —
283 /// without one the request is rejected with 400 rather than silently producing an empty
284 /// mission.
285 ///
286 /// MEF is gated twice: globally by the server flag and per tenant by `mef_config.enabled`. When
287 /// either is off the route answers **404** with a plain body — deliberately the same answer as
288 /// a mission that does not exist, so an opted-out tenant cannot discover the surface.
289 ///
290 /// `POST /api/v1/missions`
291 ///
292 /// Required scopes: `agents:write`.
293 pub async fn start_mission(&self, body: &models::StartMissionRequest) -> Result<models::MissionStartResponse> {
294 self.client
295 .request_json(Request {
296 method: Method::POST,
297 path: "/api/v1/missions".to_string(),
298 query: NO_QUERY,
299 body: Some(body),
300 headers: Vec::new(),
301 idempotent: true,
302 })
303 .await
304 }
305
306 /// Stream mission progress (SSE)
307 ///
308 /// Server-sent events, poll-backed. Event names: `connected` (handshake), `mission` (snapshot
309 /// on connect), `status_change`, `checkpoint_added` (one per new checkpoint id),
310 /// `aar_finalized`, and `terminal` as the last event before the server closes. The stream
311 /// closes itself on a terminal status so a client stops reconnecting, and is capped at 15
312 /// minutes per connection regardless — a long mission is expected to reconnect.
313 ///
314 /// MEF is gated twice: globally by the server flag and per tenant by `mef_config.enabled`. When
315 /// either is off the route answers **404** with a plain body — deliberately the same answer as
316 /// a mission that does not exist, so an opted-out tenant cannot discover the surface.
317 ///
318 /// `GET /api/v1/missions/{missionId}/events`
319 ///
320 /// Required scopes: `agents:read`.
321 ///
322 /// Returns a server-sent event stream.
323 pub fn stream_mission_events(&self, mission_id: &str) -> EventStream {
324 self.client.request_stream(
325 &format!("/api/v1/missions/{}/events", encode_path(mission_id)),
326 NO_QUERY,
327 Vec::new(),
328 )
329 }
330
331 /// Edit one objective's configuration
332 ///
333 /// Configuration only: assignment, budget ceilings, deadline, rules of engagement, commander's
334 /// intent, decision points, priority and text. Lifecycle stays with the executor — there is no
335 /// way to set `status` from here. An empty patch is rejected with 400 rather than answering 200
336 /// for a write that did nothing. Sending `assigned_agent_id` or `assigned_team_id` as an empty
337 /// string clears the assignment.
338 ///
339 /// MEF is gated twice: globally by the server flag and per tenant by `mef_config.enabled`. When
340 /// either is off the route answers **404** with a plain body — deliberately the same answer as
341 /// a mission that does not exist, so an opted-out tenant cannot discover the surface.
342 ///
343 /// `PATCH /api/v1/missions/{missionId}/objectives/{objectiveId}`
344 ///
345 /// Required scopes: `agents:write`.
346 pub async fn update_mission_objective(&self, mission_id: &str, objective_id: &str, body: &models::UpdateMissionObjectiveRequest) -> Result<models::Objective> {
347 self.client
348 .request_json(Request {
349 method: Method::PATCH,
350 path: format!("/api/v1/missions/{}/objectives/{}", encode_path(mission_id), encode_path(objective_id)),
351 query: NO_QUERY,
352 body: Some(body),
353 headers: Vec::new(),
354 idempotent: true,
355 })
356 .await
357 }
358}