use serde_json::{json, Value};
use super::HandlerContext;
pub fn memory_detect_updates(ctx: &HandlerContext, params: Value) -> Value {
use crate::intelligence::memory_update::UpdateDetector;
let content = match params.get("content").and_then(|v| v.as_str()) {
Some(c) => c.to_string(),
None => return json!({"error": "content is required"}),
};
let workspace = params
.get("workspace")
.and_then(|v| v.as_str())
.unwrap_or("default");
let detector = UpdateDetector::new();
ctx.storage
.with_connection(|conn| {
let candidates = detector.detect_updates(conn, &content, workspace)?;
Ok(json!({
"workspace": workspace,
"candidates": candidates,
"count": candidates.len(),
}))
})
.unwrap_or_else(|e| json!({"error": e.to_string()}))
}
pub fn memory_utility_score(ctx: &HandlerContext, params: Value) -> Value {
use crate::search::utility::UtilityTracker;
let id = match params.get("id").and_then(|v| v.as_i64()) {
Some(id) => id,
None => return json!({"error": "id is required"}),
};
let tracker = UtilityTracker::new();
ctx.storage
.with_connection(|conn| {
let score = tracker.get_utility(conn, id)?;
Ok(json!({
"memory_id": id,
"utility_score": score.score,
"retrievals": score.retrievals,
"useful_count": score.useful_count,
"last_retrieved": score.last_retrieved,
}))
})
.unwrap_or_else(|e| json!({"error": e.to_string()}))
}
pub fn memory_sentiment_analyze(ctx: &HandlerContext, params: Value) -> Value {
use crate::intelligence::emotional::SentimentAnalyzer;
use crate::storage::queries::get_memory;
let id = match params.get("id").and_then(|v| v.as_i64()) {
Some(id) => id,
None => return json!({"error": "id is required"}),
};
ctx.storage
.with_connection(|conn| {
let memory = get_memory(conn, id)?;
let analyzer = SentimentAnalyzer::new();
let sentiment = analyzer.analyze(&memory.content);
Ok(json!({
"memory_id": id,
"score": sentiment.score,
"label": sentiment.label.as_str(),
"confidence": sentiment.confidence,
"keywords": sentiment.keywords,
}))
})
.unwrap_or_else(|e| json!({"error": e.to_string()}))
}
pub fn memory_sentiment_timeline(ctx: &HandlerContext, params: Value) -> Value {
use crate::intelligence::emotional::SentimentAnalyzer;
let workspace = params
.get("workspace")
.and_then(|v| v.as_str())
.unwrap_or("default");
let from = params
.get("from")
.and_then(|v| v.as_str())
.unwrap_or("1970-01-01T00:00:00Z");
let to = params
.get("to")
.and_then(|v| v.as_str())
.unwrap_or("9999-12-31T23:59:59Z");
let limit: i64 = params
.get("limit")
.and_then(|v| v.as_i64())
.unwrap_or(50);
let analyzer = SentimentAnalyzer::new();
ctx.storage
.with_connection(|conn| {
let mut stmt = conn.prepare(
"SELECT id, content, created_at FROM memories
WHERE workspace = ?1
AND created_at >= ?2
AND created_at <= ?3
ORDER BY created_at ASC
LIMIT ?4",
)?;
let rows = stmt
.query_map(
rusqlite::params![workspace, from, to, limit],
|row| {
Ok((
row.get::<_, i64>(0)?,
row.get::<_, String>(1)?,
row.get::<_, String>(2)?,
))
},
)?
.collect::<Result<Vec<_>, _>>()
.map_err(crate::error::EngramError::Database)?;
let timeline: Vec<serde_json::Value> = rows
.iter()
.map(|(id, content, ts)| {
let s = analyzer.analyze(content);
json!({
"memory_id": id,
"timestamp": ts,
"score": s.score,
"label": s.label.as_str(),
})
})
.collect();
Ok(json!({
"workspace": workspace,
"from": from,
"to": to,
"entries": timeline,
"count": timeline.len(),
}))
})
.unwrap_or_else(|e| json!({"error": e.to_string()}))
}
pub fn memory_reflect(ctx: &HandlerContext, params: Value) -> Value {
use crate::intelligence::emotional::{ReflectionDepth, ReflectionEngine};
use crate::storage::queries::get_memory;
let ids: Vec<i64> = params
.get("ids")
.and_then(|v| v.as_array())
.map(|arr| arr.iter().filter_map(|v| v.as_i64()).collect())
.unwrap_or_default();
if ids.is_empty() {
return json!({"error": "ids array is required and must not be empty"});
}
let depth_str = params
.get("depth")
.and_then(|v| v.as_str())
.unwrap_or("surface");
let depth = match depth_str {
"analytical" => ReflectionDepth::Analytical,
"meta" => ReflectionDepth::Meta,
_ => ReflectionDepth::Surface,
};
ctx.storage
.with_connection(|conn| {
let mut pairs: Vec<(i64, String)> = Vec::new();
for &id in &ids {
if let Ok(m) = get_memory(conn, id) {
pairs.push((id, m.content));
}
}
let memory_refs: Vec<(i64, &str)> =
pairs.iter().map(|(id, c)| (*id, c.as_str())).collect();
let engine = ReflectionEngine::new();
let reflection = engine.create_reflection(conn, &memory_refs, depth)?;
Ok(json!({
"reflection": reflection.content,
"source_ids": reflection.source_ids,
"depth": reflection.depth.as_str(),
"insights": reflection.insights,
"created_at": reflection.created_at,
}))
})
.unwrap_or_else(|e| json!({"error": e.to_string()}))
}