agentic_memory_mcp/tools/
memory_temporal.rs1use std::sync::Arc;
4use tokio::sync::Mutex;
5
6use serde::Deserialize;
7use serde_json::{json, Value};
8
9use agentic_memory::{TemporalParams, TimeRange};
10
11use crate::session::SessionManager;
12use crate::types::{McpError, McpResult, ToolCallResult, ToolDefinition};
13
14#[derive(Debug, Deserialize)]
15struct TemporalInputParams {
16 range_a: RangeSpec,
17 range_b: RangeSpec,
18}
19
20#[derive(Debug, Deserialize)]
21#[serde(tag = "type")]
22enum RangeSpec {
23 #[serde(rename = "time_window")]
24 TimeWindow { start: u64, end: u64 },
25 #[serde(rename = "session")]
26 Session { session_id: u32 },
27 #[serde(rename = "sessions")]
28 Sessions { session_ids: Vec<u32> },
29}
30
31impl RangeSpec {
32 fn to_time_range(&self) -> TimeRange {
33 match self {
34 RangeSpec::TimeWindow { start, end } => TimeRange::TimeWindow {
35 start: *start,
36 end: *end,
37 },
38 RangeSpec::Session { session_id } => TimeRange::Session(*session_id),
39 RangeSpec::Sessions { session_ids } => TimeRange::Sessions(session_ids.clone()),
40 }
41 }
42}
43
44pub fn definition() -> ToolDefinition {
46 ToolDefinition {
47 name: "memory_temporal".to_string(),
48 description: Some("Compare knowledge across two time periods".to_string()),
49 input_schema: json!({
50 "type": "object",
51 "properties": {
52 "range_a": {
53 "oneOf": [
54 { "type": "object", "properties": { "type": { "const": "time_window" }, "start": { "type": "integer" }, "end": { "type": "integer" } } },
55 { "type": "object", "properties": { "type": { "const": "session" }, "session_id": { "type": "integer" } } },
56 { "type": "object", "properties": { "type": { "const": "sessions" }, "session_ids": { "type": "array" } } }
57 ]
58 },
59 "range_b": { "description": "Same structure as range_a" }
60 },
61 "required": ["range_a", "range_b"]
62 }),
63 }
64}
65
66pub async fn execute(
68 args: Value,
69 session: &Arc<Mutex<SessionManager>>,
70) -> McpResult<ToolCallResult> {
71 let params: TemporalInputParams =
72 serde_json::from_value(args).map_err(|e| McpError::InvalidParams(e.to_string()))?;
73
74 let temporal_params = TemporalParams {
75 range_a: params.range_a.to_time_range(),
76 range_b: params.range_b.to_time_range(),
77 };
78
79 let session = session.lock().await;
80
81 let result = session
82 .query_engine()
83 .temporal(session.graph(), temporal_params)
84 .map_err(|e| McpError::AgenticMemory(format!("Temporal comparison failed: {e}")))?;
85
86 Ok(ToolCallResult::json(&json!({
87 "added": result.added,
88 "corrected": result.corrected,
89 "unchanged": result.unchanged,
90 "potentially_stale": result.potentially_stale,
91 "summary": {
92 "added_count": result.added.len(),
93 "corrected_count": result.corrected.len(),
94 "unchanged_count": result.unchanged.len(),
95 "stale_count": result.potentially_stale.len(),
96 }
97 })))
98}