Skip to main content

hyper_agent_client/
client.rs

1use crate::error::ClientError;
2use crate::types::*;
3use hyper_agent_runtime::daemon;
4
5pub struct HyperAgentClient {
6    base_url: String,
7    http: reqwest::Client,
8    token: String,
9}
10
11impl HyperAgentClient {
12    pub fn new(base_url: &str, token: &str) -> Self {
13        Self {
14            base_url: base_url.to_string(),
15            http: reqwest::Client::new(),
16            token: token.to_string(),
17        }
18    }
19
20    pub fn from_port_file() -> Result<Self, ClientError> {
21        let port = daemon::read_port().ok_or(ClientError::NotRunning)?;
22        let token = daemon::read_token().ok_or(ClientError::NotRunning)?;
23        Ok(Self::new(&format!("http://127.0.0.1:{}", port), &token))
24    }
25
26    // Management
27    pub async fn health(&self) -> Result<HealthResponse, ClientError> {
28        self.get("/health").await
29    }
30
31    pub async fn status(&self) -> Result<ServerStatus, ClientError> {
32        self.get("/status").await
33    }
34
35    pub async fn shutdown(&self) -> Result<(), ClientError> {
36        self.post_empty("/shutdown").await
37    }
38
39    // Strategy
40    pub async fn run_strategy(&self, req: &RunStrategyRequest) -> Result<(), ClientError> {
41        let _: serde_json::Value = self.post("/strategies/run", req).await?;
42        Ok(())
43    }
44
45    pub async fn stop_strategy(&self, id: &str) -> Result<(), ClientError> {
46        self.post_empty(&format!("/strategies/{}/stop", id)).await
47    }
48
49    pub async fn list_strategies(&self) -> Result<Vec<StrategyInfo>, ClientError> {
50        self.get("/strategies").await
51    }
52
53    // Orders
54    pub async fn place_order(&self, req: &PlaceOrderRequest) -> Result<OrderResponse, ClientError> {
55        self.post("/orders", req).await
56    }
57
58    pub async fn cancel_order(&self, id: &str) -> Result<(), ClientError> {
59        self.delete(&format!("/orders/{}", id)).await
60    }
61
62    pub async fn list_orders(&self) -> Result<Vec<PositionInfo>, ClientError> {
63        self.get("/orders").await
64    }
65
66    // Positions
67    pub async fn get_positions(&self) -> Result<Vec<PositionInfo>, ClientError> {
68        self.get("/positions").await
69    }
70
71    pub async fn close_all(&self) -> Result<(), ClientError> {
72        self.post_empty("/positions/close-all").await
73    }
74
75    // Agent history
76    pub async fn agent_history(
77        &self,
78        agent_id: &str,
79        limit: usize,
80    ) -> Result<Vec<hyper_agent_ai::agent_loop::AgentLoopLog>, ClientError> {
81        self.get(&format!("/agents/{}/history?limit={}", agent_id, limit))
82            .await
83    }
84
85    // Agent adjustment history
86    pub async fn agent_adjustments(
87        &self,
88        agent_id: &str,
89        limit: usize,
90    ) -> Result<Vec<hyper_agent_ai::adjustment_history::AdjustmentRecord>, ClientError> {
91        self.get(&format!("/agents/{}/adjustments?limit={}", agent_id, limit))
92            .await
93    }
94
95    // Dashboard
96    pub async fn dashboard_stats(&self) -> Result<DashboardStats, ClientError> {
97        self.get("/dashboard/stats").await
98    }
99
100    pub async fn pnl_history(&self) -> Result<Vec<PnlPoint>, ClientError> {
101        self.get("/dashboard/pnl").await
102    }
103
104    pub async fn execution_quality(&self) -> Result<ExecutionQuality, ClientError> {
105        self.get("/dashboard/execution-quality").await
106    }
107
108    // Risk
109    pub async fn get_risk_exposure(&self) -> Result<serde_json::Value, ClientError> {
110        self.get("/risk/exposure").await
111    }
112
113    pub async fn get_circuit_breaker(&self) -> Result<serde_json::Value, ClientError> {
114        self.get("/risk/circuit-breaker").await
115    }
116
117    // HTTP helpers
118    async fn get<T: serde::de::DeserializeOwned>(&self, path: &str) -> Result<T, ClientError> {
119        let resp = self
120            .http
121            .get(format!("{}{}", self.base_url, path))
122            .header("Authorization", format!("Bearer {}", self.token))
123            .send()
124            .await
125            .map_err(ClientError::Http)?;
126        if !resp.status().is_success() {
127            let status = resp.status().as_u16();
128            let text = resp.text().await.unwrap_or_default();
129            return Err(ClientError::Server {
130                status,
131                message: text,
132            });
133        }
134        resp.json().await.map_err(ClientError::Http)
135    }
136
137    async fn post<B: serde::Serialize, T: serde::de::DeserializeOwned>(
138        &self,
139        path: &str,
140        body: &B,
141    ) -> Result<T, ClientError> {
142        let resp = self
143            .http
144            .post(format!("{}{}", self.base_url, path))
145            .header("Authorization", format!("Bearer {}", self.token))
146            .json(body)
147            .send()
148            .await
149            .map_err(ClientError::Http)?;
150        if !resp.status().is_success() {
151            let status = resp.status().as_u16();
152            let text = resp.text().await.unwrap_or_default();
153            return Err(ClientError::Server {
154                status,
155                message: text,
156            });
157        }
158        resp.json().await.map_err(ClientError::Http)
159    }
160
161    async fn post_empty(&self, path: &str) -> Result<(), ClientError> {
162        let resp = self
163            .http
164            .post(format!("{}{}", self.base_url, path))
165            .header("Authorization", format!("Bearer {}", self.token))
166            .send()
167            .await
168            .map_err(ClientError::Http)?;
169        if !resp.status().is_success() {
170            let status = resp.status().as_u16();
171            let text = resp.text().await.unwrap_or_default();
172            return Err(ClientError::Server {
173                status,
174                message: text,
175            });
176        }
177        Ok(())
178    }
179
180    async fn delete(&self, path: &str) -> Result<(), ClientError> {
181        let resp = self
182            .http
183            .delete(format!("{}{}", self.base_url, path))
184            .header("Authorization", format!("Bearer {}", self.token))
185            .send()
186            .await
187            .map_err(ClientError::Http)?;
188        if !resp.status().is_success() {
189            let status = resp.status().as_u16();
190            let text = resp.text().await.unwrap_or_default();
191            return Err(ClientError::Server {
192                status,
193                message: text,
194            });
195        }
196        Ok(())
197    }
198}
199
200// Re-export ensure_daemon from core
201pub use hyper_agent_runtime::client::ensure_daemon;