Skip to main content

agentic_memory_mcp/tools/
memory_workspace_compare.rs

1//! Tool: memory_workspace_compare — Compare a topic across memory contexts.
2
3use std::sync::Arc;
4use tokio::sync::Mutex;
5
6use serde::Deserialize;
7use serde_json::{json, Value};
8
9use crate::session::SessionManager;
10use crate::types::{McpError, McpResult, ToolCallResult, ToolDefinition};
11
12#[derive(Debug, Deserialize)]
13struct CompareParams {
14    workspace_id: String,
15    item: String,
16    #[serde(default = "default_max")]
17    max_per_context: usize,
18}
19
20fn default_max() -> usize {
21    5
22}
23
24/// Return the tool definition for memory_workspace_compare.
25pub fn definition() -> ToolDefinition {
26    ToolDefinition {
27        name: "memory_workspace_compare".to_string(),
28        description: Some(
29            "Compare how a topic appears across different memory contexts. Shows where \
30             a concept exists, what's different, and where it's missing."
31                .to_string(),
32        ),
33        input_schema: json!({
34            "type": "object",
35            "required": ["workspace_id", "item"],
36            "properties": {
37                "workspace_id": {
38                    "type": "string",
39                    "description": "ID of the workspace"
40                },
41                "item": {
42                    "type": "string",
43                    "description": "Topic/concept to compare across contexts"
44                },
45                "max_per_context": {
46                    "type": "integer",
47                    "default": 5,
48                    "description": "Maximum matches per context for comparison"
49                }
50            }
51        }),
52    }
53}
54
55/// Execute the memory_workspace_compare tool.
56pub async fn execute(
57    args: Value,
58    session: &Arc<Mutex<SessionManager>>,
59) -> McpResult<ToolCallResult> {
60    let params: CompareParams =
61        serde_json::from_value(args).map_err(|e| McpError::InvalidParams(e.to_string()))?;
62
63    let session = session.lock().await;
64    let comparison = session.workspace_manager().compare(
65        &params.workspace_id,
66        &params.item,
67        params.max_per_context,
68    )?;
69
70    let per_context: Vec<Value> = comparison
71        .matches_per_context
72        .iter()
73        .map(|(label, matches)| {
74            let match_items: Vec<Value> = matches
75                .iter()
76                .map(|m| {
77                    json!({
78                        "node_id": m.node_id,
79                        "content": m.content,
80                        "event_type": m.event_type,
81                        "confidence": m.confidence,
82                        "score": m.score,
83                    })
84                })
85                .collect();
86
87            json!({
88                "context": label,
89                "matches": match_items,
90            })
91        })
92        .collect();
93
94    Ok(ToolCallResult::json(&json!({
95        "item": comparison.item,
96        "found_in": comparison.found_in,
97        "missing_from": comparison.missing_from,
98        "details": per_context
99    })))
100}