use crate::error::{AreevError, Result};
use crate::types::*;
pub struct HttpClient {
client: reqwest::Client,
base_url: String,
memory_id: String,
api_key: Option<String>,
}
impl HttpClient {
pub fn new(base_url: &str, memory_id: &str, api_key: Option<&str>) -> Self {
Self {
client: reqwest::Client::new(),
base_url: base_url.trim_end_matches('/').to_string(),
memory_id: memory_id.to_string(),
api_key: api_key.map(|s| s.to_string()),
}
}
fn url(&self, path: &str) -> String {
format!(
"{}/api/memories/{}/{}",
self.base_url, self.memory_id, path
)
}
fn request(&self, method: reqwest::Method, path: &str) -> reqwest::RequestBuilder {
let mut req = self.client.request(method, self.url(path));
if let Some(ref key) = self.api_key {
req = req.header("X-API-Key", key);
}
req
}
pub async fn add(&self, req: &AddRequest) -> Result<AddResponse> {
let resp = self
.request(reqwest::Method::POST, "add")
.json(req)
.send()
.await?;
self.handle_response(resp).await
}
pub async fn recall(&self, req: &RecallRequest) -> Result<RecallResponse> {
let resp = self
.request(reqwest::Method::GET, "recall")
.query(req)
.send()
.await?;
self.handle_response(resp).await
}
pub async fn get(&self, hash: &str) -> Result<GetResponse> {
let resp = self
.request(reqwest::Method::GET, &format!("grains/{hash}"))
.send()
.await?;
self.handle_response(resp).await
}
pub async fn forget(&self, hash: &str) -> Result<()> {
let resp = self
.request(reqwest::Method::DELETE, &format!("grains/{hash}"))
.send()
.await?;
if resp.status().is_success() {
Ok(())
} else {
let status = resp.status().as_u16();
let message = resp.text().await.unwrap_or_default();
Err(AreevError::Api { status, message })
}
}
pub async fn remember(&self, req: &RememberRequest) -> Result<RememberResponse> {
let resp = self
.request(reqwest::Method::POST, "remember")
.json(req)
.send()
.await?;
self.handle_response(resp).await
}
pub async fn supersede(&self, req: &SupersedeRequest) -> Result<SupersedeResponse> {
let resp = self
.request(reqwest::Method::POST, "supersede")
.json(req)
.send()
.await?;
self.handle_response(resp).await
}
pub async fn harness_chat(
&self,
slug: &str,
req: &HarnessChatRequest,
) -> Result<HarnessChatResponse> {
let resp = self
.request(
reqwest::Method::POST,
&format!("harnesses/{slug}/chat"),
)
.json(req)
.send()
.await?;
self.handle_response(resp).await
}
pub async fn harness_chat_resume(
&self,
slug: &str,
req: &ChatResumeRequest,
) -> Result<HarnessChatResponse> {
let resp = self
.request(
reqwest::Method::POST,
&format!("harnesses/{slug}/chat/resume"),
)
.json(req)
.send()
.await?;
self.handle_response(resp).await
}
pub async fn cancel_harness_chat_session(
&self,
slug: &str,
session_id: &str,
) -> Result<()> {
let resp = self
.request(
reqwest::Method::DELETE,
&format!("harnesses/{slug}/chat/sessions/{session_id}"),
)
.send()
.await?;
if resp.status().is_success() || resp.status().as_u16() == 404 {
Ok(())
} else {
let status = resp.status().as_u16();
let message = resp.text().await.unwrap_or_default();
Err(AreevError::Api { status, message })
}
}
pub async fn health(&self) -> Result<HealthResponse> {
let resp = self
.client
.get(format!("{}/health", self.base_url))
.send()
.await?;
self.handle_response(resp).await
}
pub async fn stats(&self) -> Result<StatsResponse> {
let resp = self
.request(reqwest::Method::GET, "stats")
.send()
.await?;
self.handle_response(resp).await
}
pub async fn flush(&self) -> Result<()> {
let resp = self
.request(reqwest::Method::POST, "flush")
.send()
.await?;
if resp.status().is_success() {
Ok(())
} else {
let status = resp.status().as_u16();
let message = resp.text().await.unwrap_or_default();
Err(AreevError::Api { status, message })
}
}
async fn handle_response<T: serde::de::DeserializeOwned>(
&self,
resp: reqwest::Response,
) -> Result<T> {
if resp.status().is_success() {
Ok(resp.json().await?)
} else {
let status = resp.status().as_u16();
let message = resp.text().await.unwrap_or_default();
Err(AreevError::Api { status, message })
}
}
}