hanzo-mcp 0.7.6__py3-none-any.whl → 0.8.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 +7 -1
- hanzo_mcp/__main__.py +1 -1
- hanzo_mcp/analytics/__init__.py +2 -2
- hanzo_mcp/analytics/posthog_analytics.py +76 -82
- hanzo_mcp/cli.py +31 -36
- hanzo_mcp/cli_enhanced.py +94 -72
- hanzo_mcp/cli_plugin.py +27 -17
- hanzo_mcp/config/__init__.py +2 -2
- hanzo_mcp/config/settings.py +112 -88
- hanzo_mcp/config/tool_config.py +32 -34
- hanzo_mcp/dev_server.py +66 -67
- hanzo_mcp/prompts/__init__.py +94 -12
- hanzo_mcp/prompts/enhanced_prompts.py +809 -0
- hanzo_mcp/prompts/example_custom_prompt.py +6 -5
- hanzo_mcp/prompts/project_todo_reminder.py +0 -1
- hanzo_mcp/prompts/tool_explorer.py +10 -7
- hanzo_mcp/server.py +17 -21
- hanzo_mcp/server_enhanced.py +15 -22
- hanzo_mcp/tools/__init__.py +56 -28
- hanzo_mcp/tools/agent/__init__.py +16 -19
- hanzo_mcp/tools/agent/agent.py +82 -65
- hanzo_mcp/tools/agent/agent_tool.py +152 -122
- hanzo_mcp/tools/agent/agent_tool_v1_deprecated.py +66 -62
- hanzo_mcp/tools/agent/clarification_protocol.py +55 -50
- hanzo_mcp/tools/agent/clarification_tool.py +11 -10
- hanzo_mcp/tools/agent/claude_cli_tool.py +21 -20
- hanzo_mcp/tools/agent/claude_desktop_auth.py +130 -144
- hanzo_mcp/tools/agent/cli_agent_base.py +59 -53
- hanzo_mcp/tools/agent/code_auth.py +102 -107
- hanzo_mcp/tools/agent/code_auth_tool.py +28 -27
- hanzo_mcp/tools/agent/codex_cli_tool.py +20 -19
- hanzo_mcp/tools/agent/critic_tool.py +86 -73
- hanzo_mcp/tools/agent/gemini_cli_tool.py +21 -20
- hanzo_mcp/tools/agent/grok_cli_tool.py +21 -20
- hanzo_mcp/tools/agent/iching_tool.py +404 -139
- hanzo_mcp/tools/agent/network_tool.py +89 -73
- hanzo_mcp/tools/agent/prompt.py +2 -1
- hanzo_mcp/tools/agent/review_tool.py +101 -98
- hanzo_mcp/tools/agent/swarm_alias.py +87 -0
- hanzo_mcp/tools/agent/swarm_tool.py +246 -161
- hanzo_mcp/tools/agent/swarm_tool_v1_deprecated.py +134 -92
- hanzo_mcp/tools/agent/tool_adapter.py +21 -11
- hanzo_mcp/tools/common/__init__.py +1 -1
- hanzo_mcp/tools/common/base.py +3 -5
- hanzo_mcp/tools/common/batch_tool.py +46 -39
- hanzo_mcp/tools/common/config_tool.py +120 -84
- hanzo_mcp/tools/common/context.py +1 -5
- hanzo_mcp/tools/common/context_fix.py +5 -3
- hanzo_mcp/tools/common/critic_tool.py +4 -8
- hanzo_mcp/tools/common/decorators.py +58 -56
- hanzo_mcp/tools/common/enhanced_base.py +29 -32
- hanzo_mcp/tools/common/fastmcp_pagination.py +91 -94
- hanzo_mcp/tools/common/forgiving_edit.py +91 -87
- hanzo_mcp/tools/common/mode.py +15 -17
- hanzo_mcp/tools/common/mode_loader.py +27 -24
- hanzo_mcp/tools/common/paginated_base.py +61 -53
- hanzo_mcp/tools/common/paginated_response.py +72 -79
- hanzo_mcp/tools/common/pagination.py +50 -53
- hanzo_mcp/tools/common/permissions.py +4 -4
- hanzo_mcp/tools/common/personality.py +186 -138
- hanzo_mcp/tools/common/plugin_loader.py +54 -54
- hanzo_mcp/tools/common/stats.py +65 -47
- hanzo_mcp/tools/common/test_helpers.py +31 -0
- hanzo_mcp/tools/common/thinking_tool.py +4 -8
- hanzo_mcp/tools/common/tool_disable.py +17 -12
- hanzo_mcp/tools/common/tool_enable.py +13 -14
- hanzo_mcp/tools/common/tool_list.py +36 -28
- hanzo_mcp/tools/common/truncate.py +23 -23
- hanzo_mcp/tools/config/__init__.py +4 -4
- hanzo_mcp/tools/config/config_tool.py +42 -29
- hanzo_mcp/tools/config/index_config.py +37 -34
- hanzo_mcp/tools/config/mode_tool.py +175 -55
- hanzo_mcp/tools/database/__init__.py +15 -12
- hanzo_mcp/tools/database/database_manager.py +77 -75
- hanzo_mcp/tools/database/graph.py +137 -91
- hanzo_mcp/tools/database/graph_add.py +30 -18
- hanzo_mcp/tools/database/graph_query.py +178 -102
- hanzo_mcp/tools/database/graph_remove.py +33 -28
- hanzo_mcp/tools/database/graph_search.py +97 -75
- hanzo_mcp/tools/database/graph_stats.py +91 -59
- hanzo_mcp/tools/database/sql.py +107 -79
- hanzo_mcp/tools/database/sql_query.py +30 -24
- hanzo_mcp/tools/database/sql_search.py +29 -25
- hanzo_mcp/tools/database/sql_stats.py +47 -35
- hanzo_mcp/tools/editor/neovim_command.py +25 -28
- hanzo_mcp/tools/editor/neovim_edit.py +21 -23
- hanzo_mcp/tools/editor/neovim_session.py +60 -54
- hanzo_mcp/tools/filesystem/__init__.py +31 -30
- hanzo_mcp/tools/filesystem/ast_multi_edit.py +329 -249
- hanzo_mcp/tools/filesystem/ast_tool.py +4 -4
- hanzo_mcp/tools/filesystem/base.py +1 -1
- hanzo_mcp/tools/filesystem/batch_search.py +316 -224
- hanzo_mcp/tools/filesystem/content_replace.py +4 -4
- hanzo_mcp/tools/filesystem/diff.py +71 -59
- hanzo_mcp/tools/filesystem/directory_tree.py +7 -7
- hanzo_mcp/tools/filesystem/directory_tree_paginated.py +49 -37
- hanzo_mcp/tools/filesystem/edit.py +4 -4
- hanzo_mcp/tools/filesystem/find.py +173 -80
- hanzo_mcp/tools/filesystem/find_files.py +73 -52
- hanzo_mcp/tools/filesystem/git_search.py +157 -104
- hanzo_mcp/tools/filesystem/grep.py +8 -8
- hanzo_mcp/tools/filesystem/multi_edit.py +4 -8
- hanzo_mcp/tools/filesystem/read.py +12 -10
- hanzo_mcp/tools/filesystem/rules_tool.py +59 -43
- hanzo_mcp/tools/filesystem/search_tool.py +263 -207
- hanzo_mcp/tools/filesystem/symbols_tool.py +94 -54
- hanzo_mcp/tools/filesystem/tree.py +35 -33
- hanzo_mcp/tools/filesystem/unix_aliases.py +13 -18
- hanzo_mcp/tools/filesystem/watch.py +37 -36
- hanzo_mcp/tools/filesystem/write.py +4 -8
- hanzo_mcp/tools/jupyter/__init__.py +4 -4
- hanzo_mcp/tools/jupyter/base.py +4 -5
- hanzo_mcp/tools/jupyter/jupyter.py +67 -47
- hanzo_mcp/tools/jupyter/notebook_edit.py +4 -4
- hanzo_mcp/tools/jupyter/notebook_read.py +4 -7
- hanzo_mcp/tools/llm/__init__.py +5 -7
- hanzo_mcp/tools/llm/consensus_tool.py +72 -52
- hanzo_mcp/tools/llm/llm_manage.py +101 -60
- hanzo_mcp/tools/llm/llm_tool.py +226 -166
- hanzo_mcp/tools/llm/provider_tools.py +25 -26
- hanzo_mcp/tools/lsp/__init__.py +1 -1
- hanzo_mcp/tools/lsp/lsp_tool.py +228 -143
- hanzo_mcp/tools/mcp/__init__.py +2 -3
- hanzo_mcp/tools/mcp/mcp_add.py +27 -25
- hanzo_mcp/tools/mcp/mcp_remove.py +7 -8
- hanzo_mcp/tools/mcp/mcp_stats.py +23 -22
- hanzo_mcp/tools/mcp/mcp_tool.py +129 -98
- hanzo_mcp/tools/memory/__init__.py +39 -21
- hanzo_mcp/tools/memory/knowledge_tools.py +124 -99
- hanzo_mcp/tools/memory/memory_tools.py +90 -108
- hanzo_mcp/tools/search/__init__.py +7 -2
- hanzo_mcp/tools/search/find_tool.py +297 -212
- hanzo_mcp/tools/search/unified_search.py +366 -314
- hanzo_mcp/tools/shell/__init__.py +8 -7
- hanzo_mcp/tools/shell/auto_background.py +56 -49
- hanzo_mcp/tools/shell/base.py +1 -1
- hanzo_mcp/tools/shell/base_process.py +75 -75
- hanzo_mcp/tools/shell/bash_session.py +2 -2
- hanzo_mcp/tools/shell/bash_session_executor.py +4 -4
- hanzo_mcp/tools/shell/bash_tool.py +24 -31
- hanzo_mcp/tools/shell/command_executor.py +12 -12
- hanzo_mcp/tools/shell/logs.py +43 -33
- hanzo_mcp/tools/shell/npx.py +13 -13
- hanzo_mcp/tools/shell/npx_background.py +24 -21
- hanzo_mcp/tools/shell/npx_tool.py +18 -22
- hanzo_mcp/tools/shell/open.py +19 -21
- hanzo_mcp/tools/shell/pkill.py +31 -26
- hanzo_mcp/tools/shell/process_tool.py +32 -32
- hanzo_mcp/tools/shell/processes.py +57 -58
- hanzo_mcp/tools/shell/run_background.py +24 -25
- hanzo_mcp/tools/shell/run_command.py +5 -5
- hanzo_mcp/tools/shell/run_command_windows.py +5 -5
- hanzo_mcp/tools/shell/session_storage.py +3 -3
- hanzo_mcp/tools/shell/streaming_command.py +141 -126
- hanzo_mcp/tools/shell/uvx.py +24 -25
- hanzo_mcp/tools/shell/uvx_background.py +35 -33
- hanzo_mcp/tools/shell/uvx_tool.py +18 -22
- hanzo_mcp/tools/todo/__init__.py +6 -2
- hanzo_mcp/tools/todo/todo.py +50 -37
- hanzo_mcp/tools/todo/todo_read.py +5 -8
- hanzo_mcp/tools/todo/todo_write.py +5 -7
- hanzo_mcp/tools/vector/__init__.py +40 -28
- hanzo_mcp/tools/vector/ast_analyzer.py +176 -143
- hanzo_mcp/tools/vector/git_ingester.py +170 -179
- hanzo_mcp/tools/vector/index_tool.py +96 -44
- hanzo_mcp/tools/vector/infinity_store.py +283 -228
- hanzo_mcp/tools/vector/mock_infinity.py +39 -40
- hanzo_mcp/tools/vector/project_manager.py +88 -78
- hanzo_mcp/tools/vector/vector.py +59 -42
- hanzo_mcp/tools/vector/vector_index.py +30 -27
- hanzo_mcp/tools/vector/vector_search.py +64 -45
- hanzo_mcp/types.py +6 -4
- {hanzo_mcp-0.7.6.dist-info → hanzo_mcp-0.8.0.dist-info}/METADATA +1 -1
- hanzo_mcp-0.8.0.dist-info/RECORD +185 -0
- hanzo_mcp-0.7.6.dist-info/RECORD +0 -182
- {hanzo_mcp-0.7.6.dist-info → hanzo_mcp-0.8.0.dist-info}/WHEEL +0 -0
- {hanzo_mcp-0.7.6.dist-info → hanzo_mcp-0.8.0.dist-info}/entry_points.txt +0 -0
- {hanzo_mcp-0.7.6.dist-info → hanzo_mcp-0.8.0.dist-info}/top_level.txt +0 -0
|
@@ -4,7 +4,8 @@ These tools use the hanzo-memory package to manage knowledge bases and facts,
|
|
|
4
4
|
supporting hierarchical organization (session, project, global).
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
from typing import Any, Dict, List, Optional,
|
|
7
|
+
from typing import Any, Dict, List, Optional, final, override
|
|
8
|
+
|
|
8
9
|
from mcp.server import FastMCP
|
|
9
10
|
from mcp.server.fastmcp import Context as MCPContext
|
|
10
11
|
|
|
@@ -13,24 +14,24 @@ from hanzo_mcp.tools.common.context import create_tool_context
|
|
|
13
14
|
|
|
14
15
|
# Import from hanzo-memory package
|
|
15
16
|
try:
|
|
16
|
-
from hanzo_memory.services.memory import MemoryService, get_memory_service
|
|
17
17
|
from hanzo_memory.models.memory import Memory, MemoryWithScore
|
|
18
|
-
from hanzo_memory.
|
|
18
|
+
from hanzo_memory.services.memory import MemoryService, get_memory_service
|
|
19
|
+
from hanzo_memory.models.knowledge import Fact, FactCreate, KnowledgeBase
|
|
20
|
+
|
|
19
21
|
KNOWLEDGE_AVAILABLE = True
|
|
20
22
|
except ImportError:
|
|
21
23
|
KNOWLEDGE_AVAILABLE = False
|
|
22
24
|
raise ImportError(
|
|
23
|
-
"hanzo-memory package is required for knowledge tools. "
|
|
24
|
-
"Install it from ~/work/hanzo/ide/pkg/memory"
|
|
25
|
+
"hanzo-memory package is required for knowledge tools. Install it from ~/work/hanzo/ide/pkg/memory"
|
|
25
26
|
)
|
|
26
27
|
|
|
27
28
|
|
|
28
29
|
class KnowledgeToolBase(BaseTool):
|
|
29
30
|
"""Base class for knowledge tools using hanzo-memory package."""
|
|
30
|
-
|
|
31
|
+
|
|
31
32
|
def __init__(self, user_id: str = "default", project_id: str = "default", **kwargs):
|
|
32
33
|
"""Initialize knowledge tool.
|
|
33
|
-
|
|
34
|
+
|
|
34
35
|
Args:
|
|
35
36
|
user_id: User ID for knowledge operations
|
|
36
37
|
project_id: Project ID for knowledge operations
|
|
@@ -45,13 +46,13 @@ class KnowledgeToolBase(BaseTool):
|
|
|
45
46
|
@final
|
|
46
47
|
class RecallFactsTool(KnowledgeToolBase):
|
|
47
48
|
"""Tool for recalling facts from knowledge bases."""
|
|
48
|
-
|
|
49
|
+
|
|
49
50
|
@property
|
|
50
51
|
@override
|
|
51
52
|
def name(self) -> str:
|
|
52
53
|
"""Get the tool name."""
|
|
53
54
|
return "recall_facts"
|
|
54
|
-
|
|
55
|
+
|
|
55
56
|
@property
|
|
56
57
|
@override
|
|
57
58
|
def description(self) -> str:
|
|
@@ -66,7 +67,7 @@ recall_facts(queries=["Python best practices"], kb_name="coding_standards")
|
|
|
66
67
|
recall_facts(queries=["API endpoints"], scope="project")
|
|
67
68
|
recall_facts(queries=["company policies"], scope="global", limit=5)
|
|
68
69
|
"""
|
|
69
|
-
|
|
70
|
+
|
|
70
71
|
@override
|
|
71
72
|
async def call(
|
|
72
73
|
self,
|
|
@@ -74,25 +75,25 @@ recall_facts(queries=["company policies"], scope="global", limit=5)
|
|
|
74
75
|
queries: List[str],
|
|
75
76
|
kb_name: Optional[str] = None,
|
|
76
77
|
scope: str = "project",
|
|
77
|
-
limit: int = 10
|
|
78
|
+
limit: int = 10,
|
|
78
79
|
) -> str:
|
|
79
80
|
"""Recall facts matching queries.
|
|
80
|
-
|
|
81
|
+
|
|
81
82
|
Args:
|
|
82
83
|
ctx: MCP context
|
|
83
84
|
queries: Search queries
|
|
84
85
|
kb_name: Optional knowledge base name to search in
|
|
85
86
|
scope: Scope level (session, project, global)
|
|
86
87
|
limit: Max results per query
|
|
87
|
-
|
|
88
|
+
|
|
88
89
|
Returns:
|
|
89
90
|
Formatted fact results
|
|
90
91
|
"""
|
|
91
92
|
tool_ctx = create_tool_context(ctx)
|
|
92
93
|
await tool_ctx.set_tool_info(self.name)
|
|
93
|
-
|
|
94
|
+
|
|
94
95
|
await tool_ctx.info(f"Searching for facts in scope: {scope}")
|
|
95
|
-
|
|
96
|
+
|
|
96
97
|
# Determine the appropriate IDs based on scope
|
|
97
98
|
if scope == "global":
|
|
98
99
|
user_id = "global"
|
|
@@ -104,26 +105,23 @@ recall_facts(queries=["company policies"], scope="global", limit=5)
|
|
|
104
105
|
else:
|
|
105
106
|
user_id = self.user_id
|
|
106
107
|
project_id = self.project_id
|
|
107
|
-
|
|
108
|
+
|
|
108
109
|
all_facts = []
|
|
109
110
|
for query in queries:
|
|
110
111
|
# Search for facts using memory service with fact metadata
|
|
111
112
|
search_query = f"fact: {query}"
|
|
112
113
|
if kb_name:
|
|
113
114
|
search_query = f"kb:{kb_name} {search_query}"
|
|
114
|
-
|
|
115
|
+
|
|
115
116
|
memories = self.service.search_memories(
|
|
116
|
-
user_id=user_id,
|
|
117
|
-
query=search_query,
|
|
118
|
-
project_id=project_id,
|
|
119
|
-
limit=limit
|
|
117
|
+
user_id=user_id, query=search_query, project_id=project_id, limit=limit
|
|
120
118
|
)
|
|
121
|
-
|
|
119
|
+
|
|
122
120
|
# Filter for fact-type memories
|
|
123
121
|
for memory in memories:
|
|
124
122
|
if memory.metadata and memory.metadata.get("type") == "fact":
|
|
125
123
|
all_facts.append(memory)
|
|
126
|
-
|
|
124
|
+
|
|
127
125
|
# Deduplicate by memory ID
|
|
128
126
|
seen = set()
|
|
129
127
|
unique_facts = []
|
|
@@ -131,10 +129,10 @@ recall_facts(queries=["company policies"], scope="global", limit=5)
|
|
|
131
129
|
if fact.memory_id not in seen:
|
|
132
130
|
seen.add(fact.memory_id)
|
|
133
131
|
unique_facts.append(fact)
|
|
134
|
-
|
|
132
|
+
|
|
135
133
|
if not unique_facts:
|
|
136
134
|
return "No relevant facts found."
|
|
137
|
-
|
|
135
|
+
|
|
138
136
|
# Format results
|
|
139
137
|
formatted = [f"Found {len(unique_facts)} relevant facts:\n"]
|
|
140
138
|
for i, fact in enumerate(unique_facts, 1):
|
|
@@ -142,40 +140,48 @@ recall_facts(queries=["company policies"], scope="global", limit=5)
|
|
|
142
140
|
if fact.metadata and fact.metadata.get("kb_name"):
|
|
143
141
|
kb_info = f" (KB: {fact.metadata['kb_name']})"
|
|
144
142
|
formatted.append(f"{i}. {fact.content}{kb_info}")
|
|
145
|
-
if
|
|
143
|
+
if (
|
|
144
|
+
fact.metadata and len(fact.metadata) > 2
|
|
145
|
+
): # More than just type and kb_name
|
|
146
146
|
# Show other metadata
|
|
147
|
-
other_meta = {
|
|
147
|
+
other_meta = {
|
|
148
|
+
k: v
|
|
149
|
+
for k, v in fact.metadata.items()
|
|
150
|
+
if k not in ["type", "kb_name"]
|
|
151
|
+
}
|
|
148
152
|
if other_meta:
|
|
149
153
|
formatted.append(f" Metadata: {other_meta}")
|
|
150
|
-
|
|
154
|
+
|
|
151
155
|
return "\n".join(formatted)
|
|
152
|
-
|
|
156
|
+
|
|
153
157
|
@override
|
|
154
158
|
def register(self, mcp_server: FastMCP) -> None:
|
|
155
159
|
"""Register this tool with the MCP server."""
|
|
156
160
|
tool_self = self
|
|
157
|
-
|
|
161
|
+
|
|
158
162
|
@mcp_server.tool(name=self.name, description=self.description)
|
|
159
163
|
async def recall_facts(
|
|
160
164
|
ctx: MCPContext,
|
|
161
165
|
queries: List[str],
|
|
162
166
|
kb_name: Optional[str] = None,
|
|
163
167
|
scope: str = "project",
|
|
164
|
-
limit: int = 10
|
|
168
|
+
limit: int = 10,
|
|
165
169
|
) -> str:
|
|
166
|
-
return await tool_self.call(
|
|
170
|
+
return await tool_self.call(
|
|
171
|
+
ctx, queries=queries, kb_name=kb_name, scope=scope, limit=limit
|
|
172
|
+
)
|
|
167
173
|
|
|
168
174
|
|
|
169
175
|
@final
|
|
170
176
|
class StoreFactsTool(KnowledgeToolBase):
|
|
171
177
|
"""Tool for storing facts in knowledge bases."""
|
|
172
|
-
|
|
178
|
+
|
|
173
179
|
@property
|
|
174
180
|
@override
|
|
175
181
|
def name(self) -> str:
|
|
176
182
|
"""Get the tool name."""
|
|
177
183
|
return "store_facts"
|
|
178
|
-
|
|
184
|
+
|
|
179
185
|
@property
|
|
180
186
|
@override
|
|
181
187
|
def description(self) -> str:
|
|
@@ -190,7 +196,7 @@ store_facts(facts=["Python uses indentation for blocks"], kb_name="python_basics
|
|
|
190
196
|
store_facts(facts=["API rate limit: 100/hour"], scope="project", kb_name="api_docs")
|
|
191
197
|
store_facts(facts=["Company founded in 2020"], scope="global", kb_name="company_info")
|
|
192
198
|
"""
|
|
193
|
-
|
|
199
|
+
|
|
194
200
|
@override
|
|
195
201
|
async def call(
|
|
196
202
|
self,
|
|
@@ -198,25 +204,25 @@ store_facts(facts=["Company founded in 2020"], scope="global", kb_name="company_
|
|
|
198
204
|
facts: List[str],
|
|
199
205
|
kb_name: str = "general",
|
|
200
206
|
scope: str = "project",
|
|
201
|
-
metadata: Optional[Dict[str, Any]] = None
|
|
207
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
202
208
|
) -> str:
|
|
203
209
|
"""Store new facts.
|
|
204
|
-
|
|
210
|
+
|
|
205
211
|
Args:
|
|
206
212
|
ctx: MCP context
|
|
207
213
|
facts: Facts to store
|
|
208
214
|
kb_name: Knowledge base name
|
|
209
215
|
scope: Scope level (session, project, global)
|
|
210
216
|
metadata: Optional metadata for all facts
|
|
211
|
-
|
|
217
|
+
|
|
212
218
|
Returns:
|
|
213
219
|
Success message
|
|
214
220
|
"""
|
|
215
221
|
tool_ctx = create_tool_context(ctx)
|
|
216
222
|
await tool_ctx.set_tool_info(self.name)
|
|
217
|
-
|
|
223
|
+
|
|
218
224
|
await tool_ctx.info(f"Storing {len(facts)} facts in {kb_name} (scope: {scope})")
|
|
219
|
-
|
|
225
|
+
|
|
220
226
|
# Determine the appropriate IDs based on scope
|
|
221
227
|
if scope == "global":
|
|
222
228
|
user_id = "global"
|
|
@@ -227,51 +233,53 @@ store_facts(facts=["Company founded in 2020"], scope="global", kb_name="company_
|
|
|
227
233
|
else:
|
|
228
234
|
user_id = self.user_id
|
|
229
235
|
project_id = self.project_id
|
|
230
|
-
|
|
236
|
+
|
|
231
237
|
created_facts = []
|
|
232
238
|
for fact_content in facts:
|
|
233
239
|
# Create fact as a memory with special metadata
|
|
234
240
|
fact_metadata = {"type": "fact", "kb_name": kb_name}
|
|
235
241
|
if metadata:
|
|
236
242
|
fact_metadata.update(metadata)
|
|
237
|
-
|
|
243
|
+
|
|
238
244
|
memory = self.service.create_memory(
|
|
239
245
|
user_id=user_id,
|
|
240
246
|
project_id=project_id,
|
|
241
247
|
content=f"fact: {fact_content}",
|
|
242
248
|
metadata=fact_metadata,
|
|
243
|
-
importance=1.5 # Facts have higher importance
|
|
249
|
+
importance=1.5, # Facts have higher importance
|
|
244
250
|
)
|
|
245
251
|
created_facts.append(memory)
|
|
246
|
-
|
|
252
|
+
|
|
247
253
|
return f"Successfully stored {len(created_facts)} facts in {kb_name}."
|
|
248
|
-
|
|
254
|
+
|
|
249
255
|
@override
|
|
250
256
|
def register(self, mcp_server: FastMCP) -> None:
|
|
251
257
|
"""Register this tool with the MCP server."""
|
|
252
258
|
tool_self = self
|
|
253
|
-
|
|
259
|
+
|
|
254
260
|
@mcp_server.tool(name=self.name, description=self.description)
|
|
255
261
|
async def store_facts(
|
|
256
262
|
ctx: MCPContext,
|
|
257
263
|
facts: List[str],
|
|
258
264
|
kb_name: str = "general",
|
|
259
265
|
scope: str = "project",
|
|
260
|
-
metadata: Optional[Dict[str, Any]] = None
|
|
266
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
261
267
|
) -> str:
|
|
262
|
-
return await tool_self.call(
|
|
268
|
+
return await tool_self.call(
|
|
269
|
+
ctx, facts=facts, kb_name=kb_name, scope=scope, metadata=metadata
|
|
270
|
+
)
|
|
263
271
|
|
|
264
272
|
|
|
265
273
|
@final
|
|
266
274
|
class SummarizeToMemoryTool(KnowledgeToolBase):
|
|
267
275
|
"""Tool for summarizing information and storing in memory."""
|
|
268
|
-
|
|
276
|
+
|
|
269
277
|
@property
|
|
270
278
|
@override
|
|
271
279
|
def name(self) -> str:
|
|
272
280
|
"""Get the tool name."""
|
|
273
281
|
return "summarize_to_memory"
|
|
274
|
-
|
|
282
|
+
|
|
275
283
|
@property
|
|
276
284
|
@override
|
|
277
285
|
def description(self) -> str:
|
|
@@ -286,7 +294,7 @@ summarize_to_memory(content="Long discussion about API design...", topic="API De
|
|
|
286
294
|
summarize_to_memory(content="User preferences...", topic="User Preferences", scope="session")
|
|
287
295
|
summarize_to_memory(content="Company guidelines...", topic="Guidelines", scope="global")
|
|
288
296
|
"""
|
|
289
|
-
|
|
297
|
+
|
|
290
298
|
@override
|
|
291
299
|
async def call(
|
|
292
300
|
self,
|
|
@@ -294,33 +302,38 @@ summarize_to_memory(content="Company guidelines...", topic="Guidelines", scope="
|
|
|
294
302
|
content: str,
|
|
295
303
|
topic: str,
|
|
296
304
|
scope: str = "project",
|
|
297
|
-
auto_facts: bool = True
|
|
305
|
+
auto_facts: bool = True,
|
|
298
306
|
) -> str:
|
|
299
307
|
"""Summarize content and store in memory.
|
|
300
|
-
|
|
308
|
+
|
|
301
309
|
Args:
|
|
302
310
|
ctx: MCP context
|
|
303
311
|
content: Content to summarize
|
|
304
312
|
topic: Topic or title for the summary
|
|
305
313
|
scope: Scope level (session, project, global)
|
|
306
314
|
auto_facts: Whether to extract facts automatically
|
|
307
|
-
|
|
315
|
+
|
|
308
316
|
Returns:
|
|
309
317
|
Success message with summary
|
|
310
318
|
"""
|
|
311
319
|
tool_ctx = create_tool_context(ctx)
|
|
312
320
|
await tool_ctx.set_tool_info(self.name)
|
|
313
|
-
|
|
321
|
+
|
|
314
322
|
await tool_ctx.info(f"Summarizing content about {topic}")
|
|
315
|
-
|
|
323
|
+
|
|
316
324
|
# Use the memory service to create a summary
|
|
317
325
|
# This would typically use an LLM to summarize, but for now we'll store as-is
|
|
318
|
-
summary =
|
|
319
|
-
|
|
326
|
+
summary = (
|
|
327
|
+
f"Summary of {topic}:\n{content[:500]}..."
|
|
328
|
+
if len(content) > 500
|
|
329
|
+
else content
|
|
330
|
+
)
|
|
331
|
+
|
|
320
332
|
# Store the summary as a memory
|
|
321
333
|
from hanzo_memory.services.memory import get_memory_service
|
|
334
|
+
|
|
322
335
|
memory_service = get_memory_service()
|
|
323
|
-
|
|
336
|
+
|
|
324
337
|
# Determine scope
|
|
325
338
|
if scope == "global":
|
|
326
339
|
user_id = "global"
|
|
@@ -331,50 +344,54 @@ summarize_to_memory(content="Company guidelines...", topic="Guidelines", scope="
|
|
|
331
344
|
else:
|
|
332
345
|
user_id = self.user_id
|
|
333
346
|
project_id = self.project_id
|
|
334
|
-
|
|
347
|
+
|
|
335
348
|
memory = memory_service.create_memory(
|
|
336
349
|
user_id=user_id,
|
|
337
350
|
project_id=project_id,
|
|
338
351
|
content=summary,
|
|
339
|
-
metadata={"topic": topic, "type": "summary", "scope": scope}
|
|
352
|
+
metadata={"topic": topic, "type": "summary", "scope": scope},
|
|
340
353
|
)
|
|
341
|
-
|
|
354
|
+
|
|
342
355
|
result = f"Stored summary of {topic} in {scope} memory."
|
|
343
|
-
|
|
356
|
+
|
|
344
357
|
# Optionally extract facts
|
|
345
358
|
if auto_facts:
|
|
346
359
|
# In a real implementation, this would use LLM to extract key facts
|
|
347
360
|
# For now, we'll just note it
|
|
348
|
-
result +=
|
|
349
|
-
|
|
361
|
+
result += (
|
|
362
|
+
"\n(Auto-fact extraction would extract key facts from the summary)"
|
|
363
|
+
)
|
|
364
|
+
|
|
350
365
|
return result
|
|
351
|
-
|
|
366
|
+
|
|
352
367
|
@override
|
|
353
368
|
def register(self, mcp_server: FastMCP) -> None:
|
|
354
369
|
"""Register this tool with the MCP server."""
|
|
355
370
|
tool_self = self
|
|
356
|
-
|
|
371
|
+
|
|
357
372
|
@mcp_server.tool(name=self.name, description=self.description)
|
|
358
373
|
async def summarize_to_memory(
|
|
359
374
|
ctx: MCPContext,
|
|
360
375
|
content: str,
|
|
361
376
|
topic: str,
|
|
362
377
|
scope: str = "project",
|
|
363
|
-
auto_facts: bool = True
|
|
378
|
+
auto_facts: bool = True,
|
|
364
379
|
) -> str:
|
|
365
|
-
return await tool_self.call(
|
|
380
|
+
return await tool_self.call(
|
|
381
|
+
ctx, content=content, topic=topic, scope=scope, auto_facts=auto_facts
|
|
382
|
+
)
|
|
366
383
|
|
|
367
384
|
|
|
368
385
|
@final
|
|
369
386
|
class ManageKnowledgeBasesTool(KnowledgeToolBase):
|
|
370
387
|
"""Tool for managing knowledge bases."""
|
|
371
|
-
|
|
388
|
+
|
|
372
389
|
@property
|
|
373
390
|
@override
|
|
374
391
|
def name(self) -> str:
|
|
375
392
|
"""Get the tool name."""
|
|
376
393
|
return "manage_knowledge_bases"
|
|
377
|
-
|
|
394
|
+
|
|
378
395
|
@property
|
|
379
396
|
@override
|
|
380
397
|
def description(self) -> str:
|
|
@@ -389,7 +406,7 @@ manage_knowledge_bases(action="create", kb_name="api_docs", description="API doc
|
|
|
389
406
|
manage_knowledge_bases(action="list", scope="project")
|
|
390
407
|
manage_knowledge_bases(action="delete", kb_name="old_docs")
|
|
391
408
|
"""
|
|
392
|
-
|
|
409
|
+
|
|
393
410
|
@override
|
|
394
411
|
async def call(
|
|
395
412
|
self,
|
|
@@ -397,23 +414,23 @@ manage_knowledge_bases(action="delete", kb_name="old_docs")
|
|
|
397
414
|
action: str,
|
|
398
415
|
kb_name: Optional[str] = None,
|
|
399
416
|
description: Optional[str] = None,
|
|
400
|
-
scope: str = "project"
|
|
417
|
+
scope: str = "project",
|
|
401
418
|
) -> str:
|
|
402
419
|
"""Manage knowledge bases.
|
|
403
|
-
|
|
420
|
+
|
|
404
421
|
Args:
|
|
405
422
|
ctx: MCP context
|
|
406
423
|
action: Action to perform (create, list, delete)
|
|
407
424
|
kb_name: Knowledge base name (for create/delete)
|
|
408
425
|
description: Description (for create)
|
|
409
426
|
scope: Scope level
|
|
410
|
-
|
|
427
|
+
|
|
411
428
|
Returns:
|
|
412
429
|
Result message
|
|
413
430
|
"""
|
|
414
431
|
tool_ctx = create_tool_context(ctx)
|
|
415
432
|
await tool_ctx.set_tool_info(self.name)
|
|
416
|
-
|
|
433
|
+
|
|
417
434
|
# Determine scope
|
|
418
435
|
if scope == "global":
|
|
419
436
|
user_id = "global"
|
|
@@ -424,46 +441,46 @@ manage_knowledge_bases(action="delete", kb_name="old_docs")
|
|
|
424
441
|
else:
|
|
425
442
|
user_id = self.user_id
|
|
426
443
|
project_id = self.project_id
|
|
427
|
-
|
|
444
|
+
|
|
428
445
|
if action == "create":
|
|
429
446
|
if not kb_name:
|
|
430
447
|
return "Error: kb_name required for create action"
|
|
431
|
-
|
|
448
|
+
|
|
432
449
|
# Create a knowledge base entry as a special memory
|
|
433
450
|
kb_metadata = {
|
|
434
451
|
"type": "knowledge_base",
|
|
435
452
|
"kb_name": kb_name,
|
|
436
453
|
"description": description or "",
|
|
437
|
-
"scope": scope
|
|
454
|
+
"scope": scope,
|
|
438
455
|
}
|
|
439
|
-
|
|
456
|
+
|
|
440
457
|
memory = self.service.create_memory(
|
|
441
458
|
user_id=user_id,
|
|
442
459
|
project_id=project_id,
|
|
443
460
|
content=f"Knowledge Base: {kb_name}\nDescription: {description or 'No description'}",
|
|
444
461
|
metadata=kb_metadata,
|
|
445
|
-
importance=2.0 # KBs have high importance
|
|
462
|
+
importance=2.0, # KBs have high importance
|
|
446
463
|
)
|
|
447
464
|
return f"Created knowledge base '{kb_name}' in {scope} scope."
|
|
448
|
-
|
|
465
|
+
|
|
449
466
|
elif action == "list":
|
|
450
467
|
# Search for knowledge base entries
|
|
451
468
|
kbs = self.service.search_memories(
|
|
452
469
|
user_id=user_id,
|
|
453
470
|
query="type:knowledge_base",
|
|
454
471
|
project_id=project_id,
|
|
455
|
-
limit=100
|
|
472
|
+
limit=100,
|
|
456
473
|
)
|
|
457
|
-
|
|
474
|
+
|
|
458
475
|
# Filter for KB-type memories
|
|
459
476
|
kb_list = []
|
|
460
477
|
for memory in kbs:
|
|
461
478
|
if memory.metadata and memory.metadata.get("type") == "knowledge_base":
|
|
462
479
|
kb_list.append(memory)
|
|
463
|
-
|
|
480
|
+
|
|
464
481
|
if not kb_list:
|
|
465
482
|
return f"No knowledge bases found in {scope} scope."
|
|
466
|
-
|
|
483
|
+
|
|
467
484
|
formatted = [f"Knowledge bases in {scope} scope:"]
|
|
468
485
|
for kb in kb_list:
|
|
469
486
|
name = kb.metadata.get("kb_name", "Unknown")
|
|
@@ -471,48 +488,56 @@ manage_knowledge_bases(action="delete", kb_name="old_docs")
|
|
|
471
488
|
desc_text = f" - {desc}" if desc else ""
|
|
472
489
|
formatted.append(f"- {name}{desc_text}")
|
|
473
490
|
return "\n".join(formatted)
|
|
474
|
-
|
|
491
|
+
|
|
475
492
|
elif action == "delete":
|
|
476
493
|
if not kb_name:
|
|
477
494
|
return "Error: kb_name required for delete action"
|
|
478
|
-
|
|
495
|
+
|
|
479
496
|
# Search for the KB entry
|
|
480
497
|
kbs = self.service.search_memories(
|
|
481
498
|
user_id=user_id,
|
|
482
499
|
query=f"type:knowledge_base kb_name:{kb_name}",
|
|
483
500
|
project_id=project_id,
|
|
484
|
-
limit=10
|
|
501
|
+
limit=10,
|
|
485
502
|
)
|
|
486
|
-
|
|
503
|
+
|
|
487
504
|
deleted_count = 0
|
|
488
505
|
for memory in kbs:
|
|
489
|
-
if (
|
|
490
|
-
memory.metadata
|
|
491
|
-
memory.metadata.get("
|
|
506
|
+
if (
|
|
507
|
+
memory.metadata
|
|
508
|
+
and memory.metadata.get("type") == "knowledge_base"
|
|
509
|
+
and memory.metadata.get("kb_name") == kb_name
|
|
510
|
+
):
|
|
492
511
|
# Note: delete_memory is not fully implemented
|
|
493
512
|
# but we'll call it anyway
|
|
494
513
|
self.service.delete_memory(user_id, memory.memory_id)
|
|
495
514
|
deleted_count += 1
|
|
496
|
-
|
|
515
|
+
|
|
497
516
|
if deleted_count > 0:
|
|
498
517
|
return f"Deleted knowledge base '{kb_name}'."
|
|
499
518
|
else:
|
|
500
519
|
return f"Knowledge base '{kb_name}' not found."
|
|
501
|
-
|
|
520
|
+
|
|
502
521
|
else:
|
|
503
522
|
return f"Unknown action: {action}. Use create, list, or delete."
|
|
504
|
-
|
|
523
|
+
|
|
505
524
|
@override
|
|
506
525
|
def register(self, mcp_server: FastMCP) -> None:
|
|
507
526
|
"""Register this tool with the MCP server."""
|
|
508
527
|
tool_self = self
|
|
509
|
-
|
|
528
|
+
|
|
510
529
|
@mcp_server.tool(name=self.name, description=self.description)
|
|
511
530
|
async def manage_knowledge_bases(
|
|
512
531
|
ctx: MCPContext,
|
|
513
532
|
action: str,
|
|
514
533
|
kb_name: Optional[str] = None,
|
|
515
534
|
description: Optional[str] = None,
|
|
516
|
-
scope: str = "project"
|
|
535
|
+
scope: str = "project",
|
|
517
536
|
) -> str:
|
|
518
|
-
return await tool_self.call(
|
|
537
|
+
return await tool_self.call(
|
|
538
|
+
ctx,
|
|
539
|
+
action=action,
|
|
540
|
+
kb_name=kb_name,
|
|
541
|
+
description=description,
|
|
542
|
+
scope=scope,
|
|
543
|
+
)
|