agent_first_http/sdk/
health.rs1use serde::{Deserialize, Serialize};
5
6use crate::sdk::client::Client;
7use crate::shared::error::{Error, ErrorCode};
8use crate::shared::profile_snapshot::ProfileSnapshot;
9
10#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct HealthResponse {
12 pub code: String,
13 pub status: String,
14 pub version: String,
15 pub uptime_s: u64,
16 #[serde(skip_serializing_if = "Option::is_none")]
17 pub backend: Option<BackendInfo>,
18 #[serde(skip_serializing_if = "Option::is_none")]
19 pub backend_error: Option<BackendError>,
20 #[serde(skip_serializing_if = "Option::is_none")]
22 pub profile: Option<ProfileSnapshot>,
23 #[serde(default)]
24 pub tabs_active: u32,
25 #[serde(skip_serializing_if = "Option::is_none")]
26 pub capabilities_url: Option<String>,
27}
28
29#[derive(Debug, Clone, Serialize, Deserialize)]
30pub struct BackendInfo {
31 pub family: String,
32 pub version: String,
33 pub connected: bool,
34}
35
36#[derive(Debug, Clone, Serialize, Deserialize)]
37pub struct BackendError {
38 pub error_code: ErrorCode,
39 pub error: String,
40}
41
42impl Client {
43 pub async fn health(&self) -> Result<HealthResponse, Error> {
46 let endpoint = self.effective_endpoint().await?;
47 let base = endpoint.http_base();
48 let url = format!("{base}/health");
49 let mut req = self.http().get(&url);
50 if let Some(token) = self.token() {
51 req = req.bearer_auth(token);
52 }
53 let resp = req
54 .send()
55 .await
56 .map_err(|e| Error::new(ErrorCode::HostUnreachable, format!("GET {url}: {e}")))?;
57 let status = resp.status();
58 let bytes = resp.bytes().await.map_err(|e| {
59 Error::new(
60 ErrorCode::InternalError,
61 format!("health: read response: {e}"),
62 )
63 })?;
64 if !status.is_success() {
65 if let Ok(err) = serde_json::from_slice::<Error>(&bytes) {
66 return Err(err);
67 }
68 return Err(Error::new(
69 ErrorCode::InternalError,
70 format!(
71 "health: status {status}; failed to decode error envelope: {}",
72 String::from_utf8_lossy(&bytes)
73 ),
74 ));
75 }
76 serde_json::from_slice::<HealthResponse>(&bytes).map_err(|e| {
77 Error::new(
78 ErrorCode::InternalError,
79 format!("health: decode response: {e}"),
80 )
81 })
82 }
83}