agentic_memory_mcp/tools/
memory_workspace_compare.rs1use 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
24pub 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
55pub 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 ¶ms.workspace_id,
66 ¶ms.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}