hanzo-mcp 0.6.12__py3-none-any.whl → 0.7.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of hanzo-mcp might be problematic. Click here for more details.
- hanzo_mcp/__init__.py +2 -2
- hanzo_mcp/analytics/__init__.py +5 -0
- hanzo_mcp/analytics/posthog_analytics.py +364 -0
- hanzo_mcp/cli.py +5 -5
- hanzo_mcp/cli_enhanced.py +7 -7
- hanzo_mcp/cli_plugin.py +91 -0
- hanzo_mcp/config/__init__.py +1 -1
- hanzo_mcp/config/settings.py +70 -7
- hanzo_mcp/config/tool_config.py +20 -6
- hanzo_mcp/dev_server.py +3 -3
- hanzo_mcp/prompts/project_system.py +1 -1
- hanzo_mcp/server.py +40 -3
- hanzo_mcp/server_enhanced.py +69 -0
- hanzo_mcp/tools/__init__.py +140 -31
- hanzo_mcp/tools/agent/__init__.py +85 -4
- hanzo_mcp/tools/agent/agent_tool.py +104 -6
- hanzo_mcp/tools/agent/agent_tool_v2.py +459 -0
- hanzo_mcp/tools/agent/clarification_protocol.py +220 -0
- hanzo_mcp/tools/agent/clarification_tool.py +68 -0
- hanzo_mcp/tools/agent/claude_cli_tool.py +125 -0
- hanzo_mcp/tools/agent/claude_desktop_auth.py +508 -0
- hanzo_mcp/tools/agent/cli_agent_base.py +191 -0
- hanzo_mcp/tools/agent/code_auth.py +436 -0
- hanzo_mcp/tools/agent/code_auth_tool.py +194 -0
- hanzo_mcp/tools/agent/codex_cli_tool.py +123 -0
- hanzo_mcp/tools/agent/critic_tool.py +376 -0
- hanzo_mcp/tools/agent/gemini_cli_tool.py +128 -0
- hanzo_mcp/tools/agent/grok_cli_tool.py +128 -0
- hanzo_mcp/tools/agent/iching_tool.py +380 -0
- hanzo_mcp/tools/agent/network_tool.py +273 -0
- hanzo_mcp/tools/agent/prompt.py +62 -20
- hanzo_mcp/tools/agent/review_tool.py +433 -0
- hanzo_mcp/tools/agent/swarm_tool.py +535 -0
- hanzo_mcp/tools/agent/swarm_tool_v2.py +594 -0
- hanzo_mcp/tools/common/__init__.py +15 -1
- hanzo_mcp/tools/common/base.py +5 -4
- hanzo_mcp/tools/common/batch_tool.py +103 -11
- hanzo_mcp/tools/common/config_tool.py +2 -2
- hanzo_mcp/tools/common/context.py +2 -2
- hanzo_mcp/tools/common/context_fix.py +26 -0
- hanzo_mcp/tools/common/critic_tool.py +196 -0
- hanzo_mcp/tools/common/decorators.py +208 -0
- hanzo_mcp/tools/common/enhanced_base.py +106 -0
- hanzo_mcp/tools/common/fastmcp_pagination.py +369 -0
- hanzo_mcp/tools/common/forgiving_edit.py +243 -0
- hanzo_mcp/tools/common/mode.py +116 -0
- hanzo_mcp/tools/common/mode_loader.py +105 -0
- hanzo_mcp/tools/common/paginated_base.py +230 -0
- hanzo_mcp/tools/common/paginated_response.py +307 -0
- hanzo_mcp/tools/common/pagination.py +226 -0
- hanzo_mcp/tools/common/permissions.py +1 -1
- hanzo_mcp/tools/common/personality.py +936 -0
- hanzo_mcp/tools/common/plugin_loader.py +287 -0
- hanzo_mcp/tools/common/stats.py +4 -4
- hanzo_mcp/tools/common/tool_list.py +4 -1
- hanzo_mcp/tools/common/truncate.py +101 -0
- hanzo_mcp/tools/common/validation.py +1 -1
- hanzo_mcp/tools/config/__init__.py +3 -1
- hanzo_mcp/tools/config/config_tool.py +1 -1
- hanzo_mcp/tools/config/mode_tool.py +209 -0
- hanzo_mcp/tools/database/__init__.py +1 -1
- hanzo_mcp/tools/editor/__init__.py +1 -1
- hanzo_mcp/tools/filesystem/__init__.py +48 -14
- hanzo_mcp/tools/filesystem/ast_multi_edit.py +562 -0
- hanzo_mcp/tools/filesystem/batch_search.py +3 -3
- hanzo_mcp/tools/filesystem/diff.py +2 -2
- hanzo_mcp/tools/filesystem/directory_tree_paginated.py +338 -0
- hanzo_mcp/tools/filesystem/rules_tool.py +235 -0
- hanzo_mcp/tools/filesystem/{unified_search.py → search_tool.py} +12 -12
- hanzo_mcp/tools/filesystem/{symbols_unified.py → symbols_tool.py} +104 -5
- hanzo_mcp/tools/filesystem/watch.py +3 -2
- hanzo_mcp/tools/jupyter/__init__.py +2 -2
- hanzo_mcp/tools/jupyter/jupyter.py +1 -1
- hanzo_mcp/tools/llm/__init__.py +3 -3
- hanzo_mcp/tools/llm/llm_tool.py +648 -143
- hanzo_mcp/tools/lsp/__init__.py +5 -0
- hanzo_mcp/tools/lsp/lsp_tool.py +512 -0
- hanzo_mcp/tools/mcp/__init__.py +2 -2
- hanzo_mcp/tools/mcp/{mcp_unified.py → mcp_tool.py} +3 -3
- hanzo_mcp/tools/memory/__init__.py +76 -0
- hanzo_mcp/tools/memory/knowledge_tools.py +518 -0
- hanzo_mcp/tools/memory/memory_tools.py +456 -0
- hanzo_mcp/tools/search/__init__.py +6 -0
- hanzo_mcp/tools/search/find_tool.py +581 -0
- hanzo_mcp/tools/search/unified_search.py +953 -0
- hanzo_mcp/tools/shell/__init__.py +11 -6
- hanzo_mcp/tools/shell/auto_background.py +203 -0
- hanzo_mcp/tools/shell/base_process.py +57 -29
- hanzo_mcp/tools/shell/bash_session_executor.py +1 -1
- hanzo_mcp/tools/shell/{bash_unified.py → bash_tool.py} +18 -34
- hanzo_mcp/tools/shell/command_executor.py +2 -2
- hanzo_mcp/tools/shell/{npx_unified.py → npx_tool.py} +16 -33
- hanzo_mcp/tools/shell/open.py +2 -2
- hanzo_mcp/tools/shell/{process_unified.py → process_tool.py} +1 -1
- hanzo_mcp/tools/shell/run_command_windows.py +1 -1
- hanzo_mcp/tools/shell/streaming_command.py +594 -0
- hanzo_mcp/tools/shell/uvx.py +47 -2
- hanzo_mcp/tools/shell/uvx_background.py +47 -2
- hanzo_mcp/tools/shell/{uvx_unified.py → uvx_tool.py} +16 -33
- hanzo_mcp/tools/todo/__init__.py +14 -19
- hanzo_mcp/tools/todo/todo.py +22 -1
- hanzo_mcp/tools/vector/__init__.py +1 -1
- hanzo_mcp/tools/vector/infinity_store.py +2 -2
- hanzo_mcp/tools/vector/project_manager.py +1 -1
- hanzo_mcp/types.py +23 -0
- hanzo_mcp-0.7.0.dist-info/METADATA +516 -0
- hanzo_mcp-0.7.0.dist-info/RECORD +180 -0
- {hanzo_mcp-0.6.12.dist-info → hanzo_mcp-0.7.0.dist-info}/entry_points.txt +1 -0
- hanzo_mcp/tools/common/palette.py +0 -344
- hanzo_mcp/tools/common/palette_loader.py +0 -108
- hanzo_mcp/tools/config/palette_tool.py +0 -179
- hanzo_mcp/tools/llm/llm_unified.py +0 -851
- hanzo_mcp-0.6.12.dist-info/METADATA +0 -339
- hanzo_mcp-0.6.12.dist-info/RECORD +0 -135
- hanzo_mcp-0.6.12.dist-info/licenses/LICENSE +0 -21
- {hanzo_mcp-0.6.12.dist-info → hanzo_mcp-0.7.0.dist-info}/WHEEL +0 -0
- {hanzo_mcp-0.6.12.dist-info → hanzo_mcp-0.7.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
"""Memory tools implementation for MCP.
|
|
2
|
+
|
|
3
|
+
This module provides MCP tools that use the hanzo-memory package as a library.
|
|
4
|
+
The hanzo-memory package provides embedded database and vector search capabilities.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Any, Dict, List, Optional, override, final
|
|
8
|
+
from mcp.server import FastMCP
|
|
9
|
+
from mcp.server.fastmcp import Context as MCPContext
|
|
10
|
+
|
|
11
|
+
from hanzo_mcp.tools.common.base import BaseTool
|
|
12
|
+
from hanzo_mcp.tools.common.context import create_tool_context
|
|
13
|
+
|
|
14
|
+
# Import from hanzo-memory package
|
|
15
|
+
try:
|
|
16
|
+
from hanzo_memory.services.memory import MemoryService, get_memory_service
|
|
17
|
+
from hanzo_memory.models.memory import Memory, MemoryWithScore
|
|
18
|
+
MEMORY_AVAILABLE = True
|
|
19
|
+
except ImportError:
|
|
20
|
+
MEMORY_AVAILABLE = False
|
|
21
|
+
raise ImportError(
|
|
22
|
+
"hanzo-memory package is required for memory tools. "
|
|
23
|
+
"Install it from ~/work/hanzo/ide/pkg/memory"
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class MemoryToolBase(BaseTool):
|
|
28
|
+
"""Base class for memory tools using hanzo-memory package."""
|
|
29
|
+
|
|
30
|
+
def __init__(self, user_id: str = "default", project_id: str = "default", **kwargs):
|
|
31
|
+
"""Initialize memory tool.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
user_id: User ID for memory operations
|
|
35
|
+
project_id: Project ID for memory operations
|
|
36
|
+
**kwargs: Additional configuration
|
|
37
|
+
"""
|
|
38
|
+
self.user_id = user_id
|
|
39
|
+
self.project_id = project_id
|
|
40
|
+
# Use the global memory service from hanzo-memory
|
|
41
|
+
self.service = get_memory_service()
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@final
|
|
45
|
+
class RecallMemoriesTool(MemoryToolBase):
|
|
46
|
+
"""Tool for recalling memories."""
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
@override
|
|
50
|
+
def name(self) -> str:
|
|
51
|
+
"""Get the tool name."""
|
|
52
|
+
return "recall_memories"
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
@override
|
|
56
|
+
def description(self) -> str:
|
|
57
|
+
"""Get the tool description."""
|
|
58
|
+
return """Recall memories relevant to one or more queries.
|
|
59
|
+
|
|
60
|
+
This tool searches through stored memories and returns relevant matches.
|
|
61
|
+
Supports different scopes: session, project, or global memories.
|
|
62
|
+
Multiple queries can be run in parallel for efficiency.
|
|
63
|
+
|
|
64
|
+
Usage:
|
|
65
|
+
recall_memories(queries=["user preferences", "previous conversations"])
|
|
66
|
+
recall_memories(queries=["project requirements"], scope="project")
|
|
67
|
+
recall_memories(queries=["coding standards"], scope="global")
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
@override
|
|
71
|
+
async def call(
|
|
72
|
+
self,
|
|
73
|
+
ctx: MCPContext,
|
|
74
|
+
queries: List[str],
|
|
75
|
+
limit: int = 10,
|
|
76
|
+
scope: str = "project"
|
|
77
|
+
) -> str:
|
|
78
|
+
"""Recall memories matching queries.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
ctx: MCP context
|
|
82
|
+
queries: Search queries
|
|
83
|
+
limit: Max results per query
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
Formatted memory results
|
|
87
|
+
"""
|
|
88
|
+
tool_ctx = create_tool_context(ctx)
|
|
89
|
+
await tool_ctx.set_tool_info(self.name)
|
|
90
|
+
|
|
91
|
+
await tool_ctx.info(f"Searching for {len(queries)} queries")
|
|
92
|
+
|
|
93
|
+
all_results = []
|
|
94
|
+
for query in queries:
|
|
95
|
+
# Use hanzo-memory's search_memories method
|
|
96
|
+
results = self.service.search_memories(
|
|
97
|
+
user_id=self.user_id,
|
|
98
|
+
query=query,
|
|
99
|
+
project_id=self.project_id,
|
|
100
|
+
limit=limit
|
|
101
|
+
)
|
|
102
|
+
all_results.extend(results)
|
|
103
|
+
|
|
104
|
+
# Deduplicate by memory_id
|
|
105
|
+
seen = set()
|
|
106
|
+
unique_results = []
|
|
107
|
+
for result in all_results:
|
|
108
|
+
if result.memory_id not in seen:
|
|
109
|
+
seen.add(result.memory_id)
|
|
110
|
+
unique_results.append(result)
|
|
111
|
+
|
|
112
|
+
if not unique_results:
|
|
113
|
+
return "No relevant memories found."
|
|
114
|
+
|
|
115
|
+
# Format results
|
|
116
|
+
formatted = [f"Found {len(unique_results)} relevant memories:\n"]
|
|
117
|
+
for i, memory in enumerate(unique_results, 1):
|
|
118
|
+
score = getattr(memory, 'similarity_score', 0.0)
|
|
119
|
+
formatted.append(f"{i}. {memory.content} (relevance: {score:.2f})")
|
|
120
|
+
|
|
121
|
+
return "\n".join(formatted)
|
|
122
|
+
|
|
123
|
+
@override
|
|
124
|
+
def register(self, mcp_server: FastMCP) -> None:
|
|
125
|
+
"""Register this tool with the MCP server."""
|
|
126
|
+
tool_self = self
|
|
127
|
+
|
|
128
|
+
@mcp_server.tool(name=self.name, description=self.description)
|
|
129
|
+
async def recall_memories(
|
|
130
|
+
ctx: MCPContext,
|
|
131
|
+
queries: List[str],
|
|
132
|
+
limit: int = 10,
|
|
133
|
+
scope: str = "project"
|
|
134
|
+
) -> str:
|
|
135
|
+
return await tool_self.call(ctx, queries=queries, limit=limit, scope=scope)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
@final
|
|
139
|
+
class CreateMemoriesTool(MemoryToolBase):
|
|
140
|
+
"""Tool for creating memories."""
|
|
141
|
+
|
|
142
|
+
@property
|
|
143
|
+
@override
|
|
144
|
+
def name(self) -> str:
|
|
145
|
+
"""Get the tool name."""
|
|
146
|
+
return "create_memories"
|
|
147
|
+
|
|
148
|
+
@property
|
|
149
|
+
@override
|
|
150
|
+
def description(self) -> str:
|
|
151
|
+
"""Get the tool description."""
|
|
152
|
+
return """Save one or more new pieces of information to memory.
|
|
153
|
+
|
|
154
|
+
This tool creates new memories from provided statements.
|
|
155
|
+
Each statement is stored as a separate memory.
|
|
156
|
+
|
|
157
|
+
Usage:
|
|
158
|
+
create_memories(statements=["User prefers dark mode", "User works in Python"])
|
|
159
|
+
"""
|
|
160
|
+
|
|
161
|
+
@override
|
|
162
|
+
async def call(
|
|
163
|
+
self,
|
|
164
|
+
ctx: MCPContext,
|
|
165
|
+
statements: List[str]
|
|
166
|
+
) -> str:
|
|
167
|
+
"""Create new memories.
|
|
168
|
+
|
|
169
|
+
Args:
|
|
170
|
+
ctx: MCP context
|
|
171
|
+
statements: Statements to memorize
|
|
172
|
+
|
|
173
|
+
Returns:
|
|
174
|
+
Success message
|
|
175
|
+
"""
|
|
176
|
+
tool_ctx = create_tool_context(ctx)
|
|
177
|
+
await tool_ctx.set_tool_info(self.name)
|
|
178
|
+
|
|
179
|
+
await tool_ctx.info(f"Creating {len(statements)} memories")
|
|
180
|
+
|
|
181
|
+
created_memories = []
|
|
182
|
+
for statement in statements:
|
|
183
|
+
# Use hanzo-memory's create_memory method
|
|
184
|
+
memory = self.service.create_memory(
|
|
185
|
+
user_id=self.user_id,
|
|
186
|
+
project_id=self.project_id,
|
|
187
|
+
content=statement,
|
|
188
|
+
metadata={"type": "statement"}
|
|
189
|
+
)
|
|
190
|
+
created_memories.append(memory)
|
|
191
|
+
|
|
192
|
+
return f"Successfully created {len(created_memories)} new memories."
|
|
193
|
+
|
|
194
|
+
@override
|
|
195
|
+
def register(self, mcp_server: FastMCP) -> None:
|
|
196
|
+
"""Register this tool with the MCP server."""
|
|
197
|
+
tool_self = self
|
|
198
|
+
|
|
199
|
+
@mcp_server.tool(name=self.name, description=self.description)
|
|
200
|
+
async def create_memories(
|
|
201
|
+
ctx: MCPContext,
|
|
202
|
+
statements: List[str]
|
|
203
|
+
) -> str:
|
|
204
|
+
return await tool_self.call(ctx, statements=statements)
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
@final
|
|
208
|
+
class UpdateMemoriesTool(MemoryToolBase):
|
|
209
|
+
"""Tool for updating memories."""
|
|
210
|
+
|
|
211
|
+
@property
|
|
212
|
+
@override
|
|
213
|
+
def name(self) -> str:
|
|
214
|
+
"""Get the tool name."""
|
|
215
|
+
return "update_memories"
|
|
216
|
+
|
|
217
|
+
@property
|
|
218
|
+
@override
|
|
219
|
+
def description(self) -> str:
|
|
220
|
+
"""Get the tool description."""
|
|
221
|
+
return """Update existing memories with corrected information.
|
|
222
|
+
|
|
223
|
+
This tool updates memories by ID with new content.
|
|
224
|
+
|
|
225
|
+
Usage:
|
|
226
|
+
update_memories(updates=[
|
|
227
|
+
{"id": "mem_1", "statement": "User prefers light mode"},
|
|
228
|
+
{"id": "mem_2", "statement": "User primarily works in TypeScript"}
|
|
229
|
+
])
|
|
230
|
+
"""
|
|
231
|
+
|
|
232
|
+
@override
|
|
233
|
+
async def call(
|
|
234
|
+
self,
|
|
235
|
+
ctx: MCPContext,
|
|
236
|
+
updates: List[Dict[str, str]]
|
|
237
|
+
) -> str:
|
|
238
|
+
"""Update memories.
|
|
239
|
+
|
|
240
|
+
Args:
|
|
241
|
+
ctx: MCP context
|
|
242
|
+
updates: List of {id, statement} dicts
|
|
243
|
+
|
|
244
|
+
Returns:
|
|
245
|
+
Success message
|
|
246
|
+
"""
|
|
247
|
+
tool_ctx = create_tool_context(ctx)
|
|
248
|
+
await tool_ctx.set_tool_info(self.name)
|
|
249
|
+
|
|
250
|
+
await tool_ctx.info(f"Updating {len(updates)} memories")
|
|
251
|
+
|
|
252
|
+
# Note: hanzo-memory's update methods are not fully implemented yet
|
|
253
|
+
# For now, we'll track what would be updated
|
|
254
|
+
success_count = 0
|
|
255
|
+
for update in updates:
|
|
256
|
+
memory_id = update.get("id")
|
|
257
|
+
statement = update.get("statement")
|
|
258
|
+
|
|
259
|
+
if memory_id and statement:
|
|
260
|
+
# The hanzo-memory service doesn't have update implemented yet
|
|
261
|
+
# When it's implemented, we would call:
|
|
262
|
+
# success = self.service.update_memory(self.user_id, memory_id, content=statement)
|
|
263
|
+
await tool_ctx.warning(f"Memory update not fully implemented in hanzo-memory yet: {memory_id}")
|
|
264
|
+
success_count += 1
|
|
265
|
+
|
|
266
|
+
return f"Would update {success_count} of {len(updates)} memories (update not fully implemented in hanzo-memory yet)."
|
|
267
|
+
|
|
268
|
+
@override
|
|
269
|
+
def register(self, mcp_server: FastMCP) -> None:
|
|
270
|
+
"""Register this tool with the MCP server."""
|
|
271
|
+
tool_self = self
|
|
272
|
+
|
|
273
|
+
@mcp_server.tool(name=self.name, description=self.description)
|
|
274
|
+
async def update_memories(
|
|
275
|
+
ctx: MCPContext,
|
|
276
|
+
updates: List[Dict[str, str]]
|
|
277
|
+
) -> str:
|
|
278
|
+
return await tool_self.call(ctx, updates=updates)
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
@final
|
|
282
|
+
class DeleteMemoriesTool(MemoryToolBase):
|
|
283
|
+
"""Tool for deleting memories."""
|
|
284
|
+
|
|
285
|
+
@property
|
|
286
|
+
@override
|
|
287
|
+
def name(self) -> str:
|
|
288
|
+
"""Get the tool name."""
|
|
289
|
+
return "delete_memories"
|
|
290
|
+
|
|
291
|
+
@property
|
|
292
|
+
@override
|
|
293
|
+
def description(self) -> str:
|
|
294
|
+
"""Get the tool description."""
|
|
295
|
+
return """Delete memories that are no longer relevant or incorrect.
|
|
296
|
+
|
|
297
|
+
This tool removes memories by their IDs.
|
|
298
|
+
|
|
299
|
+
Usage:
|
|
300
|
+
delete_memories(ids=["mem_1", "mem_2"])
|
|
301
|
+
"""
|
|
302
|
+
|
|
303
|
+
@override
|
|
304
|
+
async def call(
|
|
305
|
+
self,
|
|
306
|
+
ctx: MCPContext,
|
|
307
|
+
ids: List[str]
|
|
308
|
+
) -> str:
|
|
309
|
+
"""Delete memories.
|
|
310
|
+
|
|
311
|
+
Args:
|
|
312
|
+
ctx: MCP context
|
|
313
|
+
ids: Memory IDs to delete
|
|
314
|
+
|
|
315
|
+
Returns:
|
|
316
|
+
Success message
|
|
317
|
+
"""
|
|
318
|
+
tool_ctx = create_tool_context(ctx)
|
|
319
|
+
await tool_ctx.set_tool_info(self.name)
|
|
320
|
+
|
|
321
|
+
await tool_ctx.info(f"Deleting {len(ids)} memories")
|
|
322
|
+
|
|
323
|
+
success_count = 0
|
|
324
|
+
for memory_id in ids:
|
|
325
|
+
# Use hanzo-memory's delete_memory method
|
|
326
|
+
success = self.service.delete_memory(self.user_id, memory_id)
|
|
327
|
+
if success:
|
|
328
|
+
success_count += 1
|
|
329
|
+
|
|
330
|
+
return f"Successfully deleted {success_count} of {len(ids)} memories."
|
|
331
|
+
|
|
332
|
+
@override
|
|
333
|
+
def register(self, mcp_server: FastMCP) -> None:
|
|
334
|
+
"""Register this tool with the MCP server."""
|
|
335
|
+
tool_self = self
|
|
336
|
+
|
|
337
|
+
@mcp_server.tool(name=self.name, description=self.description)
|
|
338
|
+
async def delete_memories(
|
|
339
|
+
ctx: MCPContext,
|
|
340
|
+
ids: List[str]
|
|
341
|
+
) -> str:
|
|
342
|
+
return await tool_self.call(ctx, ids=ids)
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
@final
|
|
346
|
+
class ManageMemoriesTool(MemoryToolBase):
|
|
347
|
+
"""Tool for managing memories atomically."""
|
|
348
|
+
|
|
349
|
+
@property
|
|
350
|
+
@override
|
|
351
|
+
def name(self) -> str:
|
|
352
|
+
"""Get the tool name."""
|
|
353
|
+
return "manage_memories"
|
|
354
|
+
|
|
355
|
+
@property
|
|
356
|
+
@override
|
|
357
|
+
def description(self) -> str:
|
|
358
|
+
"""Get the tool description."""
|
|
359
|
+
return """Create, update, and/or delete memories in a single atomic operation.
|
|
360
|
+
|
|
361
|
+
This is the preferred way to modify memories as it allows multiple
|
|
362
|
+
operations to be performed together.
|
|
363
|
+
|
|
364
|
+
Usage:
|
|
365
|
+
manage_memories(
|
|
366
|
+
creations=["New fact 1", "New fact 2"],
|
|
367
|
+
updates=[{"id": "mem_1", "statement": "Updated fact"}],
|
|
368
|
+
deletions=["mem_old1", "mem_old2"]
|
|
369
|
+
)
|
|
370
|
+
"""
|
|
371
|
+
|
|
372
|
+
@override
|
|
373
|
+
async def call(
|
|
374
|
+
self,
|
|
375
|
+
ctx: MCPContext,
|
|
376
|
+
creations: Optional[List[str]] = None,
|
|
377
|
+
updates: Optional[List[Dict[str, str]]] = None,
|
|
378
|
+
deletions: Optional[List[str]] = None
|
|
379
|
+
) -> str:
|
|
380
|
+
"""Manage memories atomically.
|
|
381
|
+
|
|
382
|
+
Args:
|
|
383
|
+
ctx: MCP context
|
|
384
|
+
creations: Statements to create
|
|
385
|
+
updates: Memories to update
|
|
386
|
+
deletions: Memory IDs to delete
|
|
387
|
+
|
|
388
|
+
Returns:
|
|
389
|
+
Summary of operations
|
|
390
|
+
"""
|
|
391
|
+
tool_ctx = create_tool_context(ctx)
|
|
392
|
+
await tool_ctx.set_tool_info(self.name)
|
|
393
|
+
|
|
394
|
+
results = []
|
|
395
|
+
|
|
396
|
+
# Create memories
|
|
397
|
+
if creations:
|
|
398
|
+
await tool_ctx.info(f"Creating {len(creations)} memories")
|
|
399
|
+
created = []
|
|
400
|
+
for statement in creations:
|
|
401
|
+
memory = self.service.create_memory(
|
|
402
|
+
user_id=self.user_id,
|
|
403
|
+
project_id=self.project_id,
|
|
404
|
+
content=statement,
|
|
405
|
+
metadata={"type": "statement"}
|
|
406
|
+
)
|
|
407
|
+
created.append(memory)
|
|
408
|
+
results.append(f"Created {len(created)} memories")
|
|
409
|
+
|
|
410
|
+
# Update memories
|
|
411
|
+
if updates:
|
|
412
|
+
await tool_ctx.info(f"Updating {len(updates)} memories")
|
|
413
|
+
success_count = 0
|
|
414
|
+
for update in updates:
|
|
415
|
+
memory_id = update.get("id")
|
|
416
|
+
statement = update.get("statement")
|
|
417
|
+
|
|
418
|
+
if memory_id and statement:
|
|
419
|
+
# Update not fully implemented in hanzo-memory yet
|
|
420
|
+
await tool_ctx.warning(f"Memory update not fully implemented: {memory_id}")
|
|
421
|
+
success_count += 1
|
|
422
|
+
results.append(f"Would update {success_count} memories (update pending implementation)")
|
|
423
|
+
|
|
424
|
+
# Delete memories
|
|
425
|
+
if deletions:
|
|
426
|
+
await tool_ctx.info(f"Deleting {len(deletions)} memories")
|
|
427
|
+
success_count = 0
|
|
428
|
+
for memory_id in deletions:
|
|
429
|
+
success = self.service.delete_memory(self.user_id, memory_id)
|
|
430
|
+
if success:
|
|
431
|
+
success_count += 1
|
|
432
|
+
results.append(f"Deleted {success_count} memories")
|
|
433
|
+
|
|
434
|
+
if not results:
|
|
435
|
+
return "No memory operations performed."
|
|
436
|
+
|
|
437
|
+
return "Memory operations completed: " + ", ".join(results)
|
|
438
|
+
|
|
439
|
+
@override
|
|
440
|
+
def register(self, mcp_server: FastMCP) -> None:
|
|
441
|
+
"""Register this tool with the MCP server."""
|
|
442
|
+
tool_self = self
|
|
443
|
+
|
|
444
|
+
@mcp_server.tool(name=self.name, description=self.description)
|
|
445
|
+
async def manage_memories(
|
|
446
|
+
ctx: MCPContext,
|
|
447
|
+
creations: Optional[List[str]] = None,
|
|
448
|
+
updates: Optional[List[Dict[str, str]]] = None,
|
|
449
|
+
deletions: Optional[List[str]] = None
|
|
450
|
+
) -> str:
|
|
451
|
+
return await tool_self.call(
|
|
452
|
+
ctx,
|
|
453
|
+
creations=creations,
|
|
454
|
+
updates=updates,
|
|
455
|
+
deletions=deletions
|
|
456
|
+
)
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"""Search tools for finding code, files, and information."""
|
|
2
|
+
|
|
3
|
+
from .unified_search import UnifiedSearch, create_unified_search_tool
|
|
4
|
+
from .find_tool import FindTool, create_find_tool
|
|
5
|
+
|
|
6
|
+
__all__ = ["UnifiedSearch", "create_unified_search_tool", "FindTool", "create_find_tool"]
|