refactor: drop Manage prefix from consolidated smart MCP tools
This commit is contained in:
1 parent
e45db33297
commit
961abb01e7
8 files changed
+914
-100
No files matched your search
@@ -7,23 +7,23 @@ use serde_json::Value;
|
||||
use std::collections::HashSet;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub struct ManageStickyNotesHandler;
|
||||
pub struct StickyNotesHandler;
|
||||
|
||||
#[async_trait]
|
||||
impl McpTool for ManageStickyNotesHandler {
|
||||
impl McpTool for StickyNotesHandler {
|
||||
fn name(&self) -> &'static str {
|
||||
"manage_sticky_notes"
|
||||
"sticky_notes"
|
||||
}
|
||||
|
||||
fn schema(&self) -> Value {
|
||||
crate::mcp::tool_def::<ManageStickyNotesTool>(
|
||||
"manage_sticky_notes",
|
||||
"Manage ephemeral sticky notes with TTL (add, read, delete, clear)",
|
||||
crate::mcp::tool_def::<StickyNotesTool>(
|
||||
"sticky_notes",
|
||||
"Ephemeral sticky notes with TTL (add, read, delete, clear)",
|
||||
)
|
||||
}
|
||||
|
||||
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
|
||||
let req: ManageStickyNotesTool = serde_json::from_value(args).map_err(|e| e.to_string())?;
|
||||
let req: StickyNotesTool = serde_json::from_value(args).map_err(|e| e.to_string())?;
|
||||
match req.action {
|
||||
StickyNoteAction::Add => {
|
||||
let content = req.content.ok_or_else(|| {
|
||||
@@ -216,97 +216,72 @@ impl McpTool for ClearStickyNotesHandler {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LeaveHandoffMemoHandler;
|
||||
pub struct HandoffMemosHandler;
|
||||
|
||||
#[async_trait]
|
||||
impl McpTool for LeaveHandoffMemoHandler {
|
||||
impl McpTool for HandoffMemosHandler {
|
||||
fn name(&self) -> &'static str {
|
||||
"leave_handoff_memo"
|
||||
"handoff_memos"
|
||||
}
|
||||
|
||||
fn schema(&self) -> Value {
|
||||
crate::mcp::tool_def::<LeaveHandoffMemoTool>(
|
||||
"leave_handoff_memo",
|
||||
"Execute leave_handoff_memo",
|
||||
crate::mcp::tool_def::<HandoffMemosTool>(
|
||||
"handoff_memos",
|
||||
"Handoff memos across sessions (leave, read, clear)",
|
||||
)
|
||||
}
|
||||
|
||||
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
|
||||
let req: LeaveHandoffMemoTool = serde_json::from_value(args).map_err(|e| e.to_string())?;
|
||||
state.telemetry.handoff_memos.modify(|memos| {
|
||||
memos.push(crate::models::HandoffMemo {
|
||||
id: uuid::Uuid::new_v4().to_string(),
|
||||
author: "agy".to_string(),
|
||||
content: req.content,
|
||||
namespace: req.namespace,
|
||||
timestamp: crate::handlers::utils::now_secs(),
|
||||
expires_at: None,
|
||||
});
|
||||
if memos.len() > 200 {
|
||||
memos.remove(0);
|
||||
}
|
||||
});
|
||||
Ok("Handoff memo left".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ReadHandoffMemosHandler;
|
||||
|
||||
#[async_trait]
|
||||
impl McpTool for ReadHandoffMemosHandler {
|
||||
fn name(&self) -> &'static str {
|
||||
"read_handoff_memos"
|
||||
}
|
||||
|
||||
fn schema(&self) -> Value {
|
||||
crate::mcp::tool_def::<ReadHandoffMemosTool>(
|
||||
"read_handoff_memos",
|
||||
"Execute read_handoff_memos",
|
||||
)
|
||||
}
|
||||
|
||||
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
|
||||
let req: ReadHandoffMemosTool = serde_json::from_value(args).map_err(|e| e.to_string())?;
|
||||
let data = state.telemetry.handoff_memos.read_with(|items| {
|
||||
let filtered: Vec<_> = items
|
||||
.iter()
|
||||
.filter(|i| {
|
||||
if let Some(ns) = &req.namespace {
|
||||
&i.namespace == ns
|
||||
} else {
|
||||
true
|
||||
let req: HandoffMemosTool = serde_json::from_value(args).map_err(|e| e.to_string())?;
|
||||
match req.action {
|
||||
HandoffMemoAction::Leave => {
|
||||
let content = req.content.ok_or_else(|| {
|
||||
crate::error::AppError::Internal("content is required for 'leave' action".to_string())
|
||||
})?;
|
||||
let ns = req.namespace.unwrap_or_else(|| crate::models::default_namespace());
|
||||
state.telemetry.handoff_memos.modify(|memos| {
|
||||
memos.push(crate::models::HandoffMemo {
|
||||
id: uuid::Uuid::new_v4().to_string(),
|
||||
author: "agy".to_string(),
|
||||
content,
|
||||
namespace: ns,
|
||||
timestamp: crate::handlers::utils::now_secs(),
|
||||
expires_at: None,
|
||||
});
|
||||
if memos.len() > 200 {
|
||||
memos.remove(0);
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
Ok::<String, crate::error::AppError>(serde_json::to_string(&filtered)?)
|
||||
})?;
|
||||
Ok(data)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ClearHandoffMemosHandler;
|
||||
|
||||
#[async_trait]
|
||||
impl McpTool for ClearHandoffMemosHandler {
|
||||
fn name(&self) -> &'static str {
|
||||
"clear_handoff_memos"
|
||||
}
|
||||
|
||||
fn schema(&self) -> Value {
|
||||
crate::mcp::tool_def::<ClearHandoffMemosTool>(
|
||||
"clear_handoff_memos",
|
||||
"Execute clear_handoff_memos",
|
||||
)
|
||||
}
|
||||
|
||||
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
|
||||
let req: ClearHandoffMemosTool = serde_json::from_value(args).map_err(|e| e.to_string())?;
|
||||
let ids: HashSet<_> = req.ids.into_iter().collect();
|
||||
state
|
||||
.telemetry
|
||||
.handoff_memos
|
||||
.modify(|memos| memos.retain(|m| !ids.contains(&m.id)));
|
||||
Ok("Handoff memos cleared".to_string())
|
||||
});
|
||||
Ok("Handoff memo left.".to_string())
|
||||
}
|
||||
HandoffMemoAction::Read => {
|
||||
let data = state.telemetry.handoff_memos.read_with(|items| {
|
||||
let filtered: Vec<_> = items
|
||||
.iter()
|
||||
.filter(|i| {
|
||||
if let Some(ns) = &req.namespace {
|
||||
&i.namespace == ns
|
||||
} else {
|
||||
true
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
Ok::<String, crate::error::AppError>(serde_json::to_string(&filtered)?)
|
||||
})?;
|
||||
Ok(data)
|
||||
}
|
||||
HandoffMemoAction::Clear => {
|
||||
let ids: HashSet<_> = req.ids.unwrap_or_default().into_iter().collect();
|
||||
state.telemetry.handoff_memos.modify(|memos| {
|
||||
if ids.is_empty() {
|
||||
memos.clear();
|
||||
} else {
|
||||
memos.retain(|m| !ids.contains(&m.id));
|
||||
}
|
||||
});
|
||||
Ok("Handoff memos cleared.".to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -481,10 +456,10 @@ mod tests {
|
||||
let dir = tempdir().unwrap();
|
||||
let state = Arc::new(MemoryState::new(dir.path().to_str().unwrap()));
|
||||
|
||||
let handoff_handler = LeaveHandoffMemoHandler;
|
||||
let handoff_handler = HandoffMemosHandler;
|
||||
let args = json!({
|
||||
"action": "leave",
|
||||
"content": "Finished implementing graph tests",
|
||||
"author": "Antigravity",
|
||||
"namespace": "global"
|
||||
});
|
||||
|
||||
@@ -493,11 +468,10 @@ mod tests {
|
||||
.await
|
||||
.map_err(|e| crate::error::AppError::Internal(e.to_string()))
|
||||
.unwrap();
|
||||
assert_eq!(res, "Handoff memo left");
|
||||
assert_eq!(res, "Handoff memo left.");
|
||||
|
||||
let read_handoff = ReadHandoffMemosHandler;
|
||||
let res2 = read_handoff
|
||||
.execute(json!({"namespace": "global"}), state.clone())
|
||||
let res2 = handoff_handler
|
||||
.execute(json!({"action": "read", "namespace": "global"}), state.clone())
|
||||
.await
|
||||
.map_err(|e| crate::error::AppError::Internal(e.to_string()))
|
||||
.unwrap();
|
||||
@@ -532,7 +506,7 @@ mod tests {
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let state = Arc::new(MemoryState::new(dir.path().to_str().unwrap()));
|
||||
|
||||
let handler = ManageStickyNotesHandler;
|
||||
let handler = StickyNotesHandler;
|
||||
let invalid_args = serde_json::json!({
|
||||
"action": "invalid_action"
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user