1#![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#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
21pub struct ExportSessionParams {
22 #[serde(default, skip_serializing_if = "Option::is_none")]
23 pub format: Option<models::ExportSessionFormat>,
24}
25
26#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
28pub struct GetSessionRunFeedbackParams {
29 #[serde(default, skip_serializing_if = "Option::is_none")]
30 pub message_id: Option<String>,
31}
32
33#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
35pub struct ListSessionsParams {
36 #[serde(default, skip_serializing_if = "Option::is_none")]
38 pub agent_id: Option<String>,
39 #[serde(default, skip_serializing_if = "Option::is_none")]
40 pub limit: Option<i64>,
41 #[serde(default, skip_serializing_if = "Option::is_none")]
43 pub cursor: Option<String>,
44}
45
46#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
48pub struct ListSessionTodosParams {
49 #[serde(default, skip_serializing_if = "Option::is_none")]
50 pub from: Option<String>,
51 #[serde(default, skip_serializing_if = "Option::is_none")]
52 pub to: Option<String>,
53}
54
55#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
57pub struct StreamSessionEventsParams {
58 #[serde(default, skip_serializing_if = "Option::is_none")]
61 pub token: Option<String>,
62 #[serde(skip)]
65 pub last_event_id: Option<String>,
66}
67
68#[derive(Debug, Clone)]
70pub struct SessionsApi {
71 pub(crate) client: Client,
72}
73
74impl Client {
75 pub fn sessions(&self) -> SessionsApi {
77 SessionsApi { client: self.clone() }
78 }
79}
80
81impl SessionsApi {
82 pub async fn activate_session_branch(&self, session_id: &str, branch_id: &str) -> Result<models::ActivateSessionBranchResponse> {
88 self.client
89 .request_json(Request {
90 method: Method::PUT,
91 path: format!("/api/v1/sessions/{}/branches/{}/activate", encode_path(session_id), encode_path(branch_id)),
92 query: NO_QUERY,
93 body: NO_BODY,
94 headers: Vec::new(),
95 idempotent: true,
96 })
97 .await
98 }
99
100 pub async fn bulk_delete_sessions(&self, body: &models::BulkDeleteSessionsRequest) -> Result<models::BulkDeleteSessionsResponse> {
110 self.client
111 .request_json(Request {
112 method: Method::POST,
113 path: "/api/v1/sessions/bulk-delete".to_string(),
114 query: NO_QUERY,
115 body: Some(body),
116 headers: Vec::new(),
117 idempotent: true,
118 })
119 .await
120 }
121
122 pub async fn close_session(&self, session_id: &str) -> Result<models::CloseSessionResponse> {
128 self.client
129 .request_json(Request {
130 method: Method::DELETE,
131 path: format!("/api/v1/sessions/{}", encode_path(session_id)),
132 query: NO_QUERY,
133 body: NO_BODY,
134 headers: Vec::new(),
135 idempotent: true,
136 })
137 .await
138 }
139
140 pub async fn confirm_session_todo(&self, session_id: &str, todo_id: &str, body: &serde_json::Map<String, serde_json::Value>) -> Result<models::Todo> {
146 self.client
147 .request_json(Request {
148 method: Method::POST,
149 path: format!("/api/v1/sessions/{}/todos/{}/confirm", encode_path(session_id), encode_path(todo_id)),
150 query: NO_QUERY,
151 body: Some(body),
152 headers: Vec::new(),
153 idempotent: true,
154 })
155 .await
156 }
157
158 pub async fn create(&self, body: &models::CreateSessionRequest) -> Result<models::Session> {
164 self.client
165 .request_json(Request {
166 method: Method::POST,
167 path: "/api/v1/sessions".to_string(),
168 query: NO_QUERY,
169 body: Some(body),
170 headers: Vec::new(),
171 idempotent: true,
172 })
173 .await
174 }
175
176 pub async fn create_session_annotation(&self, session_id: &str, body: &models::CreateSessionAnnotationRequest) -> Result<models::CreateSessionAnnotationResponse> {
182 self.client
183 .request_json(Request {
184 method: Method::POST,
185 path: format!("/api/v1/sessions/{}/annotations", encode_path(session_id)),
186 query: NO_QUERY,
187 body: Some(body),
188 headers: Vec::new(),
189 idempotent: true,
190 })
191 .await
192 }
193
194 pub async fn create_session_branch(&self, session_id: &str, body: &models::CreateSessionBranchRequest) -> Result<models::SessionBranch> {
200 self.client
201 .request_json(Request {
202 method: Method::POST,
203 path: format!("/api/v1/sessions/{}/branch", encode_path(session_id)),
204 query: NO_QUERY,
205 body: Some(body),
206 headers: Vec::new(),
207 idempotent: true,
208 })
209 .await
210 }
211
212 pub async fn create_session_share(&self, session_id: &str, body: &models::CreateSessionShareRequest) -> Result<models::CreateSessionShareResponse> {
218 self.client
219 .request_json(Request {
220 method: Method::POST,
221 path: format!("/api/v1/sessions/{}/share", encode_path(session_id)),
222 query: NO_QUERY,
223 body: Some(body),
224 headers: Vec::new(),
225 idempotent: true,
226 })
227 .await
228 }
229
230 pub async fn create_session_todo(&self, session_id: &str, body: &models::CreateSessionTodoRequest) -> Result<models::Todo> {
236 self.client
237 .request_json(Request {
238 method: Method::POST,
239 path: format!("/api/v1/sessions/{}/todos", encode_path(session_id)),
240 query: NO_QUERY,
241 body: Some(body),
242 headers: Vec::new(),
243 idempotent: true,
244 })
245 .await
246 }
247
248 pub async fn create_task(&self, body: &serde_json::Value) -> Result<serde_json::Map<String, serde_json::Value>> {
256 self.client
257 .request_json(Request {
258 method: Method::POST,
259 path: "/api/v1/todos".to_string(),
260 query: NO_QUERY,
261 body: Some(body),
262 headers: Vec::new(),
263 idempotent: true,
264 })
265 .await
266 }
267
268 pub async fn delete_session_annotation(&self, session_id: &str, annotation_id: &str) -> Result<models::DeleteSessionAnnotationResponse> {
274 self.client
275 .request_json(Request {
276 method: Method::DELETE,
277 path: format!("/api/v1/sessions/{}/annotations/{}", encode_path(session_id), encode_path(annotation_id)),
278 query: NO_QUERY,
279 body: NO_BODY,
280 headers: Vec::new(),
281 idempotent: true,
282 })
283 .await
284 }
285
286 pub async fn delete_session_todo(&self, session_id: &str, todo_id: &str) -> Result<models::DeleteSessionTodoResponse> {
295 self.client
296 .request_json(Request {
297 method: Method::DELETE,
298 path: format!("/api/v1/sessions/{}/todos/{}", encode_path(session_id), encode_path(todo_id)),
299 query: NO_QUERY,
300 body: NO_BODY,
301 headers: Vec::new(),
302 idempotent: true,
303 })
304 .await
305 }
306
307 pub async fn export(&self, session_id: &str, params: &ExportSessionParams) -> Result<models::SessionExport> {
318 self.client
319 .request_json(Request {
320 method: Method::GET,
321 path: format!("/api/v1/sessions/{}/export", encode_path(session_id)),
322 query: Some(params),
323 body: NO_BODY,
324 headers: Vec::new(),
325 idempotent: false,
326 })
327 .await
328 }
329
330 pub async fn get(&self, session_id: &str) -> Result<models::Session> {
336 self.client
337 .request_json(Request {
338 method: Method::GET,
339 path: format!("/api/v1/sessions/{}", encode_path(session_id)),
340 query: NO_QUERY,
341 body: NO_BODY,
342 headers: Vec::new(),
343 idempotent: false,
344 })
345 .await
346 }
347
348 pub async fn get_session_audit_log(&self, session_id: &str) -> Result<models::GetSessionAuditLogResponse> {
354 self.client
355 .request_json(Request {
356 method: Method::GET,
357 path: format!("/api/v1/sessions/{}/audit-log", encode_path(session_id)),
358 query: NO_QUERY,
359 body: NO_BODY,
360 headers: Vec::new(),
361 idempotent: false,
362 })
363 .await
364 }
365
366 pub async fn get_session_messages(&self, session_id: &str) -> Result<models::GetSessionMessagesResponse> {
385 self.client
386 .request_json(Request {
387 method: Method::GET,
388 path: format!("/api/v1/sessions/{}/messages", encode_path(session_id)),
389 query: NO_QUERY,
390 body: NO_BODY,
391 headers: Vec::new(),
392 idempotent: false,
393 })
394 .await
395 }
396
397 pub async fn get_session_run_feedback(&self, session_id: &str, run_id: &str, params: &GetSessionRunFeedbackParams) -> Result<serde_json::Value> {
403 self.client
404 .request_json(Request {
405 method: Method::GET,
406 path: format!("/api/v1/sessions/{}/runs/{}/feedback", encode_path(session_id), encode_path(run_id)),
407 query: Some(params),
408 body: NO_BODY,
409 headers: Vec::new(),
410 idempotent: false,
411 })
412 .await
413 }
414
415 pub async fn get_session_share(&self, session_id: &str) -> Result<models::GetSessionShareResponse> {
421 self.client
422 .request_json(Request {
423 method: Method::GET,
424 path: format!("/api/v1/sessions/{}/share", encode_path(session_id)),
425 query: NO_QUERY,
426 body: NO_BODY,
427 headers: Vec::new(),
428 idempotent: false,
429 })
430 .await
431 }
432
433 pub async fn list(&self, params: &ListSessionsParams) -> Result<models::ListSessionsResponse> {
439 self.client
440 .request_json(Request {
441 method: Method::GET,
442 path: "/api/v1/sessions".to_string(),
443 query: Some(params),
444 body: NO_BODY,
445 headers: Vec::new(),
446 idempotent: false,
447 })
448 .await
449 }
450
451 pub fn list_all<'a>(&'a self, params: &'a ListSessionsParams) -> impl Stream<Item = Result<models::ListSessionsResponseItem>> + 'a {
454 async_stream::try_stream! {
455 let mut guard = CursorGuard::new();
456 let mut cursor = params.cursor.clone();
457 loop {
458 let mut page_params = params.clone();
459 page_params.cursor = cursor.clone();
460 let page = self.list(&page_params).await?;
461 let items = page.items;
462 let was_empty = items.is_empty();
463 for item in items {
464 yield item;
465 }
466 match guard.advance(page.cursor, Some(page.has_more), was_empty) {
467 Some(next) => cursor = Some(next),
468 None => break,
469 }
470 }
471 }
472 }
473
474 pub async fn list_session_annotations(&self, session_id: &str) -> Result<models::ListSessionAnnotationsResponse> {
480 self.client
481 .request_json(Request {
482 method: Method::GET,
483 path: format!("/api/v1/sessions/{}/annotations", encode_path(session_id)),
484 query: NO_QUERY,
485 body: NO_BODY,
486 headers: Vec::new(),
487 idempotent: false,
488 })
489 .await
490 }
491
492 pub async fn list_session_artifacts(&self, session_id: &str) -> Result<models::ListSessionArtifactsResponse> {
498 self.client
499 .request_json(Request {
500 method: Method::GET,
501 path: format!("/api/v1/sessions/{}/artifacts", encode_path(session_id)),
502 query: NO_QUERY,
503 body: NO_BODY,
504 headers: Vec::new(),
505 idempotent: false,
506 })
507 .await
508 }
509
510 pub async fn list_session_branches(&self, session_id: &str) -> Result<models::ListSessionBranchesResponse> {
516 self.client
517 .request_json(Request {
518 method: Method::GET,
519 path: format!("/api/v1/sessions/{}/branches", encode_path(session_id)),
520 query: NO_QUERY,
521 body: NO_BODY,
522 headers: Vec::new(),
523 idempotent: false,
524 })
525 .await
526 }
527
528 pub async fn list_session_todos(&self, session_id: &str, params: &ListSessionTodosParams) -> Result<models::ListSessionTodosResponse> {
534 self.client
535 .request_json(Request {
536 method: Method::GET,
537 path: format!("/api/v1/sessions/{}/todos", encode_path(session_id)),
538 query: Some(params),
539 body: NO_BODY,
540 headers: Vec::new(),
541 idempotent: false,
542 })
543 .await
544 }
545
546 pub async fn list_todos(&self) -> Result<models::ListTodosResponse> {
550 self.client
551 .request_json(Request {
552 method: Method::GET,
553 path: "/api/v1/todos".to_string(),
554 query: NO_QUERY,
555 body: NO_BODY,
556 headers: Vec::new(),
557 idempotent: false,
558 })
559 .await
560 }
561
562 pub async fn resolve_shared_session(&self, share_id: &str) -> Result<models::ResolveSharedSessionResponse> {
566 self.client
567 .request_json(Request {
568 method: Method::GET,
569 path: format!("/api/v1/shared/{}", encode_path(share_id)),
570 query: NO_QUERY,
571 body: NO_BODY,
572 headers: Vec::new(),
573 idempotent: false,
574 })
575 .await
576 }
577
578 pub async fn revoke_session_share(&self, session_id: &str) -> Result<models::RevokeSessionShareResponse> {
584 self.client
585 .request_json(Request {
586 method: Method::DELETE,
587 path: format!("/api/v1/sessions/{}/share", encode_path(session_id)),
588 query: NO_QUERY,
589 body: NO_BODY,
590 headers: Vec::new(),
591 idempotent: true,
592 })
593 .await
594 }
595
596 pub async fn run_session_todo_now(&self, session_id: &str, todo_id: &str) -> Result<models::Todo> {
607 self.client
608 .request_json(Request {
609 method: Method::POST,
610 path: format!("/api/v1/sessions/{}/todos/{}/run", encode_path(session_id), encode_path(todo_id)),
611 query: NO_QUERY,
612 body: NO_BODY,
613 headers: Vec::new(),
614 idempotent: true,
615 })
616 .await
617 }
618
619 pub async fn send_session_message(&self, session_id: &str, body: &models::SendSessionMessageRequest) -> Result<models::SendSessionMessageResponse> {
629 self.client
630 .request_json(Request {
631 method: Method::POST,
632 path: format!("/api/v1/sessions/{}/messages", encode_path(session_id)),
633 query: NO_QUERY,
634 body: Some(body),
635 headers: Vec::new(),
636 idempotent: true,
637 })
638 .await
639 }
640
641 pub async fn set_session_run_feedback(&self, session_id: &str, run_id: &str, body: &serde_json::Map<String, serde_json::Value>) -> Result<models::RunFeedbackSet> {
647 self.client
648 .request_json(Request {
649 method: Method::PUT,
650 path: format!("/api/v1/sessions/{}/runs/{}/feedback", encode_path(session_id), encode_path(run_id)),
651 query: NO_QUERY,
652 body: Some(body),
653 headers: Vec::new(),
654 idempotent: true,
655 })
656 .await
657 }
658
659 pub fn stream_session_events(&self, session_id: &str, params: &StreamSessionEventsParams) -> EventStream {
667 let mut headers: Vec<(&'static str, String)> = Vec::new();
668 if let Some(value) = ¶ms.last_event_id {
669 headers.push(("Last-Event-ID", value.clone()));
670 }
671 self.client.request_stream(
672 &format!("/api/v1/sessions/{}/events", encode_path(session_id)),
673 Some(params),
674 headers,
675 )
676 }
677
678 pub async fn update(&self, session_id: &str, body: &models::UpdateSessionRequest) -> Result<models::Session> {
684 self.client
685 .request_json(Request {
686 method: Method::PUT,
687 path: format!("/api/v1/sessions/{}", encode_path(session_id)),
688 query: NO_QUERY,
689 body: Some(body),
690 headers: Vec::new(),
691 idempotent: true,
692 })
693 .await
694 }
695
696 pub async fn update_session_annotation(&self, session_id: &str, annotation_id: &str, body: &models::UpdateSessionAnnotationRequest) -> Result<serde_json::Value> {
702 self.client
703 .request_json(Request {
704 method: Method::PATCH,
705 path: format!("/api/v1/sessions/{}/annotations/{}", encode_path(session_id), encode_path(annotation_id)),
706 query: NO_QUERY,
707 body: Some(body),
708 headers: Vec::new(),
709 idempotent: true,
710 })
711 .await
712 }
713
714 pub async fn update_session_todo(&self, session_id: &str, todo_id: &str, body: &serde_json::Map<String, serde_json::Value>) -> Result<models::Todo> {
720 self.client
721 .request_json(Request {
722 method: Method::PATCH,
723 path: format!("/api/v1/sessions/{}/todos/{}", encode_path(session_id), encode_path(todo_id)),
724 query: NO_QUERY,
725 body: Some(body),
726 headers: Vec::new(),
727 idempotent: true,
728 })
729 .await
730 }
731}