agent_first_http/sdk/
takeover.rs1use serde::{Deserialize, Serialize};
4
5use crate::sdk::client::Client;
6use crate::shared::error::{Error, ErrorCode};
7
8#[derive(Debug, Clone, Serialize)]
9struct TakeoverHandoffRequest<'a> {
10 #[serde(skip_serializing_if = "Option::is_none")]
11 ttl_s: Option<u64>,
12 #[serde(skip_serializing_if = "Option::is_none")]
13 tab_id: Option<&'a str>,
14}
15
16#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
17pub struct TakeoverHandoffResponse {
18 pub takeover_url: String,
19 pub takeover_url_expires_at_rfc3339: String,
20 pub takeover_url_ttl_s: u64,
21 pub takeover_url_scope: String,
22}
23
24impl Client {
25 pub async fn takeover_handoff(
27 &self,
28 ttl_s: Option<u64>,
29 tab_id: Option<&str>,
30 ) -> Result<TakeoverHandoffResponse, Error> {
31 let endpoint = self.effective_endpoint().await?;
32 let base = endpoint.http_base();
33 let url = format!("{base}/takeover/handoff");
34 let body = TakeoverHandoffRequest { ttl_s, tab_id };
35 let mut req = self.http().post(&url).json(&body);
36 if let Some(token) = self.token() {
37 req = req.bearer_auth(token);
38 }
39 let resp = req
40 .send()
41 .await
42 .map_err(|e| Error::new(ErrorCode::HostUnreachable, format!("POST {url}: {e}")))?;
43 let status = resp.status();
44 let bytes = resp.bytes().await.map_err(|e| {
45 Error::new(
46 ErrorCode::InternalError,
47 format!("takeover_handoff: read response: {e}"),
48 )
49 })?;
50 if !status.is_success() {
51 if let Ok(err) = serde_json::from_slice::<Error>(&bytes) {
52 return Err(err);
53 }
54 return Err(Error::new(
55 ErrorCode::InternalError,
56 format!(
57 "takeover_handoff: status {status}; failed to decode error envelope: {}",
58 String::from_utf8_lossy(&bytes)
59 ),
60 ));
61 }
62 serde_json::from_slice::<TakeoverHandoffResponse>(&bytes).map_err(|e| {
63 Error::new(
64 ErrorCode::InternalError,
65 format!("takeover_handoff: decode response: {e}"),
66 )
67 })
68 }
69}