fix(graph): implement fuzzy substring matching for DeleteObservationsTool to improve LLM UX

This commit is contained in:
Riz Ashraf committed 2026-10-10 12:18:00 +01:00
1 parent 7c9e901c12
commit cfcd42f41e
1 file changed
+34 -16
+34 -16
View File
@@ -409,30 +409,48 @@ impl McpTool for DeleteObservationsHandler {
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: DeleteObservationsTool =
serde_json::from_value(args).map_err(|e| e.to_string())?;
let mut missing = Vec::new();
state.read_graph(|g| {
for d in &req.deletions {
if !g.entities.contains_key(&d.entity_name) {
missing.push(d.entity_name.clone());
}
}
});
if !missing.is_empty() {
return Err(crate::error::AppError::Internal(format!(
"Error: Entities not found: {}. Please use the search_nodes or read_graph tools to verify the exact entity names.",
missing.join(", ")
)));
}
let mut missing_entities = Vec::new();
let mut missing_observations = Vec::new();
state.modify_graph(|master| {
for d in req.deletions {
if let Some(e) = master.entities.get_mut(&d.entity_name) {
let to_rem: HashSet<_> = d.observations.into_iter().collect();
e.observations.retain(|o| !to_rem.contains(o));
for target in d.observations {
let target_clean = target.trim();
if target_clean.is_empty() { continue; }
let initial_len = e.observations.len();
e.observations.retain(|o| {
let o_clean = o.trim();
// Exact match OR substantial substring match (to forgive LLM whitespace/newline errors)
!(o_clean == target_clean || (target_clean.len() >= 10 && o_clean.contains(target_clean)))
});
if e.observations.len() == initial_len {
missing_observations.push(target);
}
}
} else {
missing_entities.push(d.entity_name);
}
}
});
if !missing_entities.is_empty() {
return Err(crate::error::AppError::Internal(format!(
"Error: Entities not found: {}. Please use search_nodes to verify the exact entity names.",
missing_entities.join(", ")
)));
}
if !missing_observations.is_empty() {
return Err(crate::error::AppError::Internal(format!(
"Error: Failed to find {} observation(s) to delete. Make sure you provide a sufficiently long exact substring match.",
missing_observations.len()
)));
}
Ok("Observations deleted".to_string())
}
}