#![allow(dead_code)]
use anyhow::{anyhow, Context, Result};
use reqwest::blocking::Client;
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
use std::time::Duration;
const BASE_URL: &str = "https://api.mem0.ai";
pub struct Mem0Client {
http: Client,
api_key: String,
user_id: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Memory {
#[serde(default)]
pub id: String,
#[serde(default)]
pub memory: String,
#[serde(default)]
pub score: Option<f64>,
#[serde(default)]
pub metadata: Option<Value>,
}
impl Mem0Client {
pub fn new(api_key: impl Into<String>, user_id: impl Into<String>) -> Result<Self> {
let http = Client::builder().timeout(Duration::from_secs(20)).build()?;
Ok(Self {
http,
api_key: api_key.into(),
user_id: user_id.into(),
})
}
pub fn add(&self, text: &str, metadata: Option<Value>) -> Result<Value> {
let body = json!({
"messages": [{ "role": "user", "content": text }],
"user_id": self.user_id,
"metadata": metadata.unwrap_or(json!({})),
});
let resp = self
.http
.post(format!("{}/v1/memories/", BASE_URL))
.header("Authorization", format!("Token {}", self.api_key))
.header("Content-Type", "application/json")
.json(&body)
.send()
.context("mem0 add: request failed")?;
let status = resp.status();
let payload: Value = resp
.json()
.unwrap_or_else(|_| json!({"error": "non-json response"}));
if !status.is_success() {
return Err(anyhow!("mem0 add HTTP {}: {}", status, payload));
}
Ok(payload)
}
pub fn search(&self, query: &str, limit: usize) -> Result<Vec<Memory>> {
let body = json!({
"query": query,
"user_id": self.user_id,
"limit": limit,
});
let resp = self
.http
.post(format!("{}/v1/memories/search/", BASE_URL))
.header("Authorization", format!("Token {}", self.api_key))
.header("Content-Type", "application/json")
.json(&body)
.send()
.context("mem0 search: request failed")?;
let status = resp.status();
if !status.is_success() {
let txt = resp.text().unwrap_or_default();
return Err(anyhow!("mem0 search HTTP {}: {}", status, txt));
}
let payload: Value = resp.json().context("mem0 search: parse json")?;
let arr = payload
.get("results")
.cloned()
.or_else(|| Some(payload.clone()))
.and_then(|v| v.as_array().cloned())
.unwrap_or_default();
let mut out = Vec::with_capacity(arr.len());
for v in arr {
if let Ok(m) = serde_json::from_value::<Memory>(v) {
out.push(m);
}
}
Ok(out)
}
}