use anyhow::Result;
use serde::de::DeserializeOwned;
use serde_json::{json, Map, Value};
use super::types::*;
use super::{Memory, MemoryError};
pub const OPERATIONS: &[&str] = &[
"remember",
"recall",
"explain",
"forget",
"get",
"history",
"applyForgetting",
"consolidate",
];
fn parse<T: DeserializeOwned>(value: Value) -> Result<T> {
serde_json::from_value(value).map_err(|error| {
anyhow::Error::new(MemoryError::Invalid(format!("invalid request: {error}")))
})
}
fn object(value: Value) -> Result<Map<String, Value>> {
match value {
Value::Object(map) => Ok(map),
Value::Null => Ok(Map::new()),
_ => Err(MemoryError::Invalid("the request must be a JSON object".into()).into()),
}
}
fn take_string(map: &mut Map<String, Value>, key: &str) -> Result<String> {
match map.remove(key) {
Some(Value::String(value)) => Ok(value),
_ => Err(MemoryError::Invalid(format!("{key} is required and must be a string")).into()),
}
}
fn integral_floats(value: &mut Value) {
match value {
Value::Number(number) if number.is_f64() => {
if let Some(float) = number.as_f64() {
if float.fract() == 0.0 && float.abs() < 9_007_199_254_740_992.0 {
*number = (float as i64).into();
}
}
}
Value::Array(items) => items.iter_mut().for_each(integral_floats),
Value::Object(map) => map.values_mut().for_each(integral_floats),
_ => {}
}
}
fn dry_run_by_default(request: Value) -> Result<Value> {
let mut map = object(request)?;
map.entry("dryRun").or_insert(Value::Bool(true));
Ok(Value::Object(map))
}
fn to_value<T: serde::Serialize>(value: &T) -> Result<Value> {
Ok(serde_json::to_value(value)?)
}
impl Memory {
pub fn call(&self, op: &str, mut request: Value) -> Result<Value> {
integral_floats(&mut request);
match op {
"remember" => {
let mut map = object(request)?;
let inputs: Vec<RememberInput> = match map.remove("facts") {
Some(facts) if map.is_empty() => parse(facts)?,
Some(_) => {
return Err(MemoryError::Invalid(
"send either a fact or {\"facts\": [..]}, not both".into(),
)
.into())
}
None => vec![parse(Value::Object(map))?],
};
Ok(json!({ "remembered": self.remember_many(inputs)? }))
}
"recall" => {
let mut map = object(request)?;
let query = take_string(&mut map, "query")?;
let options: RecallOptions = parse(Value::Object(map))?;
Ok(json!({ "results": self.recall(&query, &options)? }))
}
"explain" => {
let mut map = object(request)?;
let query = take_string(&mut map, "query")?;
let id = take_string(&mut map, "id")?;
let options: RecallOptions = parse(Value::Object(map))?;
Ok(json!({ "explanation": self.explain(&query, &id, &options)? }))
}
"forget" => {
let mut map = object(request)?;
let scope: ForgetScope = parse(map.remove("scope").unwrap_or(Value::Null))?;
let options: ForgetOptions = parse(Value::Object(map))?;
to_value(&self.forget(&scope, &options)?)
}
"get" => {
let id = take_string(&mut object(request)?, "id")?;
Ok(json!({ "fact": self.get(&id)? }))
}
"history" => {
let id = take_string(&mut object(request)?, "id")?;
Ok(json!({ "history": self.history(&id)? }))
}
"applyForgetting" => {
let options: ForgetOptions = parse(dry_run_by_default(request)?)?;
to_value(&self.apply_forgetting(&options)?)
}
"consolidate" => {
let options: ConsolidateOptions = parse(dry_run_by_default(request)?)?;
to_value(&self.consolidate(&options)?)
}
other => Err(MemoryError::Invalid(format!(
"unknown memory operation {other:?}; expected one of {OPERATIONS:?}"
))
.into()),
}
}
}