feat(server): refactor handlers, router, state management, and memory tools

This commit is contained in:
Riz Ashraf committed 2026-10-02 07:27:37 +01:00
1 parent 87ddb01063
commit a083719cf1
36 files changed
+1899 -597

No files matched your search

+65 -19
View File
@@ -186,7 +186,8 @@ impl McpTool for CreateRelationsHandler {
let missing: Vec<_> = missing_nodes.into_iter().collect();
return Err(crate::error::AppError::Internal(format!(
"Error: Relations dropped due to missing entities: {}",
missing.join(", "))));
missing.join(", ")
)));
}
Ok("Relations created".to_string())
}
@@ -219,7 +220,8 @@ impl McpTool for AddObservationsHandler {
if !missing_entities.is_empty() {
return Err(crate::error::AppError::Internal(format!(
"Error: Observations dropped for missing entities: {}",
missing_entities.join(", "))));
missing_entities.join(", ")
)));
}
Ok("Observations added".to_string())
}
@@ -255,7 +257,8 @@ impl McpTool for DeleteEntitiesHandler {
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(", "))));
missing.join(", ")
)));
}
let idx = state.get_search_index();
@@ -298,7 +301,8 @@ impl McpTool for DeleteObservationsHandler {
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(", "))));
missing.join(", ")
)));
}
Ok("Observations deleted".to_string())
}
@@ -671,7 +675,11 @@ mod tests {
]
});
let res = create_handler.execute(args, state.clone()).await.map_err(|e| crate::error::AppError::Internal(e.to_string())).unwrap();
let res = create_handler
.execute(args, state.clone())
.await
.map_err(|e| crate::error::AppError::Internal(e.to_string()))
.unwrap();
assert_eq!(res, "Entities created");
// Ensure graph contains the entity
@@ -716,7 +724,11 @@ mod tests {
{"from": "A", "to": "B", "relation_type": "knows"}
]
});
let res = handler.execute(args, state.clone()).await.map_err(|e| crate::error::AppError::Internal(e.to_string())).unwrap();
let res = handler
.execute(args, state.clone())
.await
.map_err(|e| crate::error::AppError::Internal(e.to_string()))
.unwrap();
assert_eq!(res, "Relations created");
// Test semantic LLM schema feedback (User request)
@@ -725,7 +737,11 @@ mod tests {
{"source": "A", "target": "B", "relationType": "knows"}
]
});
let err_res = handler.execute(bad_args, state.clone()).await.unwrap_err().to_string();
let err_res = handler
.execute(bad_args, state.clone())
.await
.unwrap_err()
.to_string();
assert!(err_res.contains("Schema error:"));
assert!(err_res.contains("strictly uses 'from', 'to', and 'relation_type'"));
}
@@ -755,25 +771,35 @@ mod tests {
{"entity_name": "A", "contents": ["Obs 1", "Obs 2"]}
]
});
let res1 = add_obs.execute(args_obs, state.clone()).await.map_err(|e| crate::error::AppError::Internal(e.to_string())).unwrap();
let res1 = add_obs
.execute(args_obs, state.clone())
.await
.map_err(|e| crate::error::AppError::Internal(e.to_string()))
.unwrap();
assert_eq!(res1, "Observations added");
let read_graph = ReadGraphHandler;
let res2 = read_graph
.execute(json!({"namespace": "global"}), state.clone())
.await.map_err(|e| crate::error::AppError::Internal(e.to_string())).unwrap();
.await
.map_err(|e| crate::error::AppError::Internal(e.to_string()))
.unwrap();
assert!(res2.contains("Obs 1"));
assert!(res2.contains("Obs 2"));
let del_entity = DeleteEntitiesHandler;
let res4 = del_entity
.execute(json!({"entity_names": ["A"]}), state.clone())
.await.map_err(|e| crate::error::AppError::Internal(e.to_string())).unwrap();
.await
.map_err(|e| crate::error::AppError::Internal(e.to_string()))
.unwrap();
assert_eq!(res4, "Entities deleted");
let res5 = read_graph
.execute(json!({"namespace": "global"}), state.clone())
.await.map_err(|e| crate::error::AppError::Internal(e.to_string())).unwrap();
.await
.map_err(|e| crate::error::AppError::Internal(e.to_string()))
.unwrap();
assert!(!res5.contains("A"));
}
@@ -791,7 +817,9 @@ mod tests {
});
create_handler
.execute(args_ent, state.clone())
.await.map_err(|e| crate::error::AppError::Internal(e.to_string())).unwrap();
.await
.map_err(|e| crate::error::AppError::Internal(e.to_string()))
.unwrap();
let rel_handler = CreateRelationsHandler;
let args_rel = json!({
@@ -799,25 +827,35 @@ mod tests {
{"from": "X", "to": "Y", "relation_type": "depends_on", "namespace": "global"}
]
});
rel_handler.execute(args_rel, state.clone()).await.map_err(|e| crate::error::AppError::Internal(e.to_string())).unwrap();
rel_handler
.execute(args_rel, state.clone())
.await
.map_err(|e| crate::error::AppError::Internal(e.to_string()))
.unwrap();
let read_handler = ReadGraphHandler;
let res_read = read_handler
.execute(json!({"namespace": "global"}), state.clone())
.await.map_err(|e| crate::error::AppError::Internal(e.to_string())).unwrap();
.await
.map_err(|e| crate::error::AppError::Internal(e.to_string()))
.unwrap();
assert!(res_read.contains("X"));
assert!(res_read.contains("depends_on"));
let open_handler = OpenNodesHandler;
let res_open = open_handler
.execute(json!({"names": ["X"]}), state.clone())
.await.map_err(|e| crate::error::AppError::Internal(e.to_string())).unwrap();
.await
.map_err(|e| crate::error::AppError::Internal(e.to_string()))
.unwrap();
assert!(res_open.contains("Y"));
let viz_handler = VisualizeGraphHandler;
let res_viz = viz_handler
.execute(json!({"query": "X"}), state.clone())
.await.map_err(|e| crate::error::AppError::Internal(e.to_string())).unwrap();
.await
.map_err(|e| crate::error::AppError::Internal(e.to_string()))
.unwrap();
assert!(!res_viz.is_empty());
let condense = CondenseEntityHandler;
@@ -826,7 +864,9 @@ mod tests {
json!({"entity_name": "X", "summarized_observations": ["X condensed"]}),
state.clone(),
)
.await.map_err(|e| crate::error::AppError::Internal(e.to_string())).unwrap();
.await
.map_err(|e| crate::error::AppError::Internal(e.to_string()))
.unwrap();
assert_eq!(res_cond, "Entity condensed");
let merge = MergeEntitiesHandler;
@@ -835,11 +875,17 @@ mod tests {
json!({"source_entity": "X", "target_entity": "Y"}),
state.clone(),
)
.await.map_err(|e| crate::error::AppError::Internal(e.to_string())).unwrap();
.await
.map_err(|e| crate::error::AppError::Internal(e.to_string()))
.unwrap();
assert_eq!(res_merge, "Entities merged");
let orphans = FindOrphansHandler;
let res_orphans = orphans.execute(json!({}), state.clone()).await.map_err(|e| crate::error::AppError::Internal(e.to_string())).unwrap();
let res_orphans = orphans
.execute(json!({}), state.clone())
.await
.map_err(|e| crate::error::AppError::Internal(e.to_string()))
.unwrap();
assert!(!res_orphans.contains("Y"));
}
}