hyper_agent_client/
client.rs1use 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 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 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 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 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 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 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 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 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 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
200pub use hyper_agent_runtime::client::ensure_daemon;