hanzo-mcp 0.7.7__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 +6 -0
- 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.7.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.7.dist-info/RECORD +0 -182
- {hanzo_mcp-0.7.7.dist-info → hanzo_mcp-0.8.0.dist-info}/WHEEL +0 -0
- {hanzo_mcp-0.7.7.dist-info → hanzo_mcp-0.8.0.dist-info}/entry_points.txt +0 -0
- {hanzo_mcp-0.7.7.dist-info → hanzo_mcp-0.8.0.dist-info}/top_level.txt +0 -0
|
@@ -4,81 +4,107 @@ This module implements the AgentTool that leverages the hanzo-agents SDK
|
|
|
4
4
|
for sophisticated agent orchestration and execution.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
import asyncio
|
|
8
|
-
import json
|
|
9
|
-
import os
|
|
10
7
|
import re
|
|
11
8
|
import time
|
|
12
|
-
from typing import
|
|
9
|
+
from typing import (
|
|
10
|
+
Any,
|
|
11
|
+
Dict,
|
|
12
|
+
List,
|
|
13
|
+
Unpack,
|
|
14
|
+
Optional,
|
|
15
|
+
TypedDict,
|
|
16
|
+
final,
|
|
17
|
+
override,
|
|
18
|
+
)
|
|
13
19
|
|
|
14
|
-
from mcp.server.fastmcp import Context as MCPContext
|
|
15
20
|
from mcp.server import FastMCP
|
|
16
|
-
from
|
|
21
|
+
from mcp.server.fastmcp import Context as MCPContext
|
|
17
22
|
|
|
18
23
|
# Import hanzo-agents SDK
|
|
19
24
|
try:
|
|
20
25
|
from hanzo_agents import (
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
26
|
+
Tool,
|
|
27
|
+
Agent,
|
|
28
|
+
State,
|
|
29
|
+
History,
|
|
30
|
+
Network,
|
|
31
|
+
InferenceResult,
|
|
32
|
+
create_memory_kv,
|
|
33
|
+
sequential_router,
|
|
34
|
+
create_memory_vector,
|
|
25
35
|
)
|
|
26
36
|
from hanzo_agents.core.cli_agent import (
|
|
27
|
-
|
|
28
|
-
GeminiAgent,
|
|
37
|
+
GrokAgent,
|
|
38
|
+
GeminiAgent,
|
|
39
|
+
ClaudeCodeAgent,
|
|
40
|
+
OpenAICodexAgent,
|
|
29
41
|
)
|
|
42
|
+
|
|
30
43
|
HANZO_AGENTS_AVAILABLE = True
|
|
31
44
|
except ImportError:
|
|
32
45
|
HANZO_AGENTS_AVAILABLE = False
|
|
46
|
+
|
|
33
47
|
# Define stub classes when hanzo-agents is not available
|
|
34
48
|
class State:
|
|
35
49
|
"""Stub State class when hanzo-agents is not available."""
|
|
50
|
+
|
|
36
51
|
def __init__(self):
|
|
37
52
|
pass
|
|
53
|
+
|
|
38
54
|
def to_dict(self):
|
|
39
55
|
return {}
|
|
56
|
+
|
|
40
57
|
@classmethod
|
|
41
58
|
def from_dict(cls, data):
|
|
42
59
|
return cls()
|
|
43
|
-
|
|
60
|
+
|
|
44
61
|
class Tool:
|
|
45
62
|
"""Stub Tool class when hanzo-agents is not available."""
|
|
63
|
+
|
|
46
64
|
pass
|
|
47
|
-
|
|
65
|
+
|
|
48
66
|
class Agent:
|
|
49
67
|
"""Stub Agent class when hanzo-agents is not available."""
|
|
68
|
+
|
|
50
69
|
pass
|
|
51
|
-
|
|
70
|
+
|
|
52
71
|
class Network:
|
|
53
72
|
"""Stub Network class when hanzo-agents is not available."""
|
|
73
|
+
|
|
54
74
|
pass
|
|
55
|
-
|
|
75
|
+
|
|
56
76
|
class History:
|
|
57
77
|
"""Stub History class when hanzo-agents is not available."""
|
|
78
|
+
|
|
58
79
|
pass
|
|
59
|
-
|
|
80
|
+
|
|
60
81
|
class InferenceResult:
|
|
61
82
|
"""Stub InferenceResult class when hanzo-agents is not available."""
|
|
83
|
+
|
|
62
84
|
def __init__(self, agent=None, content=None, metadata=None):
|
|
63
85
|
self.agent = agent
|
|
64
86
|
self.content = content
|
|
65
87
|
self.metadata = metadata or {}
|
|
66
88
|
|
|
67
|
-
|
|
68
|
-
from hanzo_mcp.tools.common.context import ToolContext, create_tool_context
|
|
69
|
-
from hanzo_mcp.tools.common.permissions import PermissionManager
|
|
70
|
-
from hanzo_mcp.tools.filesystem import get_read_only_filesystem_tools, Edit, MultiEdit
|
|
89
|
+
|
|
71
90
|
from hanzo_mcp.tools.jupyter import get_read_only_jupyter_tools
|
|
72
|
-
from hanzo_mcp.tools.
|
|
73
|
-
from hanzo_mcp.tools.
|
|
74
|
-
from hanzo_mcp.tools.
|
|
91
|
+
from hanzo_mcp.tools.filesystem import Edit, MultiEdit, get_read_only_filesystem_tools
|
|
92
|
+
from hanzo_mcp.tools.common.base import BaseTool
|
|
93
|
+
from hanzo_mcp.tools.common.context import create_tool_context
|
|
75
94
|
from hanzo_mcp.tools.agent.critic_tool import CriticTool
|
|
76
|
-
from hanzo_mcp.tools.agent.review_tool import ReviewTool
|
|
77
95
|
from hanzo_mcp.tools.agent.iching_tool import IChingTool
|
|
96
|
+
from hanzo_mcp.tools.agent.review_tool import ReviewTool
|
|
97
|
+
from hanzo_mcp.tools.common.batch_tool import BatchTool
|
|
98
|
+
from hanzo_mcp.tools.common.permissions import PermissionManager
|
|
99
|
+
from hanzo_mcp.tools.agent.clarification_tool import ClarificationTool
|
|
100
|
+
from hanzo_mcp.tools.agent.clarification_protocol import (
|
|
101
|
+
AgentClarificationMixin,
|
|
102
|
+
)
|
|
78
103
|
|
|
79
104
|
|
|
80
105
|
class AgentToolParams(TypedDict, total=False):
|
|
81
106
|
"""Parameters for the AgentTool."""
|
|
107
|
+
|
|
82
108
|
prompts: str | list[str]
|
|
83
109
|
model: Optional[str]
|
|
84
110
|
use_memory: Optional[bool]
|
|
@@ -87,7 +113,7 @@ class AgentToolParams(TypedDict, total=False):
|
|
|
87
113
|
|
|
88
114
|
class MCPAgentState(State):
|
|
89
115
|
"""State for MCP agents."""
|
|
90
|
-
|
|
116
|
+
|
|
91
117
|
def __init__(self, prompts: List[str], context: Dict[str, Any]):
|
|
92
118
|
"""Initialize agent state."""
|
|
93
119
|
super().__init__()
|
|
@@ -95,25 +121,24 @@ class MCPAgentState(State):
|
|
|
95
121
|
self.context = context
|
|
96
122
|
self.current_prompt_index = 0
|
|
97
123
|
self.results = []
|
|
98
|
-
|
|
124
|
+
|
|
99
125
|
def to_dict(self) -> Dict[str, Any]:
|
|
100
126
|
"""Convert to dictionary."""
|
|
101
127
|
base_dict = super().to_dict()
|
|
102
|
-
base_dict.update(
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
128
|
+
base_dict.update(
|
|
129
|
+
{
|
|
130
|
+
"prompts": self.prompts,
|
|
131
|
+
"context": self.context,
|
|
132
|
+
"current_prompt_index": self.current_prompt_index,
|
|
133
|
+
"results": self.results,
|
|
134
|
+
}
|
|
135
|
+
)
|
|
108
136
|
return base_dict
|
|
109
|
-
|
|
137
|
+
|
|
110
138
|
@classmethod
|
|
111
139
|
def from_dict(cls, data: Dict[str, Any]) -> "MCPAgentState":
|
|
112
140
|
"""Create from dictionary."""
|
|
113
|
-
state = cls(
|
|
114
|
-
prompts=data.get("prompts", []),
|
|
115
|
-
context=data.get("context", {})
|
|
116
|
-
)
|
|
141
|
+
state = cls(prompts=data.get("prompts", []), context=data.get("context", {}))
|
|
117
142
|
state.current_prompt_index = data.get("current_prompt_index", 0)
|
|
118
143
|
state.results = data.get("results", [])
|
|
119
144
|
for k, v in data.items():
|
|
@@ -124,22 +149,22 @@ class MCPAgentState(State):
|
|
|
124
149
|
|
|
125
150
|
class MCPToolAdapter(Tool):
|
|
126
151
|
"""Adapter to wrap MCP tools for hanzo-agents."""
|
|
127
|
-
|
|
152
|
+
|
|
128
153
|
def __init__(self, mcp_tool: BaseTool, ctx: MCPContext):
|
|
129
154
|
"""Initialize adapter."""
|
|
130
155
|
self.mcp_tool = mcp_tool
|
|
131
156
|
self.ctx = ctx
|
|
132
|
-
|
|
157
|
+
|
|
133
158
|
@property
|
|
134
159
|
def name(self) -> str:
|
|
135
160
|
"""Get tool name."""
|
|
136
161
|
return self.mcp_tool.name
|
|
137
|
-
|
|
162
|
+
|
|
138
163
|
@property
|
|
139
164
|
def description(self) -> str:
|
|
140
165
|
"""Get tool description."""
|
|
141
166
|
return self.mcp_tool.description
|
|
142
|
-
|
|
167
|
+
|
|
143
168
|
async def execute(self, **kwargs) -> str:
|
|
144
169
|
"""Execute the MCP tool."""
|
|
145
170
|
return await self.mcp_tool.call(self.ctx, **kwargs)
|
|
@@ -147,84 +172,83 @@ class MCPToolAdapter(Tool):
|
|
|
147
172
|
|
|
148
173
|
class MCPAgent(Agent):
|
|
149
174
|
"""Agent that executes MCP tasks."""
|
|
150
|
-
|
|
175
|
+
|
|
151
176
|
name = "mcp_agent"
|
|
152
177
|
description = "Agent for executing MCP tasks"
|
|
153
|
-
|
|
154
|
-
def __init__(
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
178
|
+
|
|
179
|
+
def __init__(
|
|
180
|
+
self,
|
|
181
|
+
available_tools: List[BaseTool],
|
|
182
|
+
permission_manager: PermissionManager,
|
|
183
|
+
ctx: MCPContext,
|
|
184
|
+
model: str = "model://anthropic/claude-3-5-sonnet-20241022",
|
|
185
|
+
**kwargs,
|
|
186
|
+
):
|
|
160
187
|
"""Initialize MCP agent."""
|
|
161
188
|
super().__init__(model=model, **kwargs)
|
|
162
|
-
|
|
189
|
+
|
|
163
190
|
self.available_tools = available_tools
|
|
164
191
|
self.permission_manager = permission_manager
|
|
165
192
|
self.ctx = ctx
|
|
166
|
-
|
|
193
|
+
|
|
167
194
|
# Register MCP tools as agent tools
|
|
168
195
|
for mcp_tool in available_tools:
|
|
169
196
|
adapter = MCPToolAdapter(mcp_tool, ctx)
|
|
170
197
|
self.register_tool(adapter)
|
|
171
|
-
|
|
172
|
-
async def run(
|
|
198
|
+
|
|
199
|
+
async def run(
|
|
200
|
+
self, state: MCPAgentState, history: History, network: Network
|
|
201
|
+
) -> InferenceResult:
|
|
173
202
|
"""Execute the agent."""
|
|
174
203
|
# Get current prompt
|
|
175
204
|
if state.current_prompt_index >= len(state.prompts):
|
|
176
205
|
return InferenceResult(
|
|
177
206
|
agent=self.name,
|
|
178
207
|
content="All prompts completed",
|
|
179
|
-
metadata={"completed": True}
|
|
208
|
+
metadata={"completed": True},
|
|
180
209
|
)
|
|
181
|
-
|
|
210
|
+
|
|
182
211
|
prompt = state.prompts[state.current_prompt_index]
|
|
183
|
-
|
|
212
|
+
|
|
184
213
|
# Execute with tools
|
|
185
214
|
messages = [
|
|
186
215
|
{"role": "system", "content": self._get_system_prompt()},
|
|
187
|
-
{"role": "user", "content": prompt}
|
|
216
|
+
{"role": "user", "content": prompt},
|
|
188
217
|
]
|
|
189
|
-
|
|
218
|
+
|
|
190
219
|
# Add history context
|
|
191
220
|
for entry in history[-10:]:
|
|
192
221
|
if entry.role == "assistant":
|
|
193
|
-
messages.append({
|
|
194
|
-
"role": "assistant",
|
|
195
|
-
"content": entry.content
|
|
196
|
-
})
|
|
222
|
+
messages.append({"role": "assistant", "content": entry.content})
|
|
197
223
|
elif entry.role == "user":
|
|
198
|
-
messages.append({
|
|
199
|
-
|
|
200
|
-
"content": entry.content
|
|
201
|
-
})
|
|
202
|
-
|
|
224
|
+
messages.append({"role": "user", "content": entry.content})
|
|
225
|
+
|
|
203
226
|
# Call model
|
|
204
227
|
from hanzo_agents import ModelRegistry
|
|
228
|
+
|
|
205
229
|
adapter = ModelRegistry.get_adapter(self.model)
|
|
206
230
|
response = await adapter.chat(messages)
|
|
207
|
-
|
|
231
|
+
|
|
208
232
|
# Update state
|
|
209
233
|
state.current_prompt_index += 1
|
|
210
234
|
state.results.append(response)
|
|
211
|
-
|
|
235
|
+
|
|
212
236
|
# Return result
|
|
213
237
|
return InferenceResult(
|
|
214
238
|
agent=self.name,
|
|
215
239
|
content=response,
|
|
216
240
|
metadata={
|
|
217
241
|
"prompt_index": state.current_prompt_index - 1,
|
|
218
|
-
"total_prompts": len(state.prompts)
|
|
219
|
-
}
|
|
242
|
+
"total_prompts": len(state.prompts),
|
|
243
|
+
},
|
|
220
244
|
)
|
|
221
|
-
|
|
245
|
+
|
|
222
246
|
def _get_system_prompt(self) -> str:
|
|
223
247
|
"""Get system prompt for the agent."""
|
|
224
248
|
tool_descriptions = []
|
|
225
249
|
for tool in self.tools.values():
|
|
226
250
|
tool_descriptions.append(f"- {tool.name}: {tool.description}")
|
|
227
|
-
|
|
251
|
+
|
|
228
252
|
return f"""You are an AI assistant with access to the following tools:
|
|
229
253
|
|
|
230
254
|
{chr(10).join(tool_descriptions)}
|
|
@@ -243,20 +267,20 @@ Important guidelines:
|
|
|
243
267
|
@final
|
|
244
268
|
class AgentTool(AgentClarificationMixin, BaseTool):
|
|
245
269
|
"""Tool for delegating tasks to sub-agents using hanzo-agents SDK."""
|
|
246
|
-
|
|
270
|
+
|
|
247
271
|
@property
|
|
248
272
|
@override
|
|
249
273
|
def name(self) -> str:
|
|
250
274
|
"""Get the tool name."""
|
|
251
275
|
return "agent"
|
|
252
|
-
|
|
276
|
+
|
|
253
277
|
@property
|
|
254
278
|
@override
|
|
255
279
|
def description(self) -> str:
|
|
256
280
|
"""Get the tool description."""
|
|
257
281
|
if not HANZO_AGENTS_AVAILABLE:
|
|
258
282
|
return "Agent tool (hanzo-agents SDK not available - using fallback)"
|
|
259
|
-
|
|
283
|
+
|
|
260
284
|
at = [t.name for t in self.available_tools]
|
|
261
285
|
return f"""Launch a new agent that has access to the following tools: {at}.
|
|
262
286
|
|
|
@@ -277,7 +301,7 @@ Usage notes:
|
|
|
277
301
|
3. Each agent invocation is stateless
|
|
278
302
|
4. The agent's outputs should generally be trusted
|
|
279
303
|
5. Clearly tell the agent whether you expect it to write code or just do research"""
|
|
280
|
-
|
|
304
|
+
|
|
281
305
|
def __init__(
|
|
282
306
|
self,
|
|
283
307
|
permission_manager: PermissionManager,
|
|
@@ -292,11 +316,11 @@ Usage notes:
|
|
|
292
316
|
self.permission_manager = permission_manager
|
|
293
317
|
self.model_override = model
|
|
294
318
|
self.api_key_override = api_key
|
|
295
|
-
self.base_url_override = base_url
|
|
319
|
+
self.base_url_override = base_url
|
|
296
320
|
self.max_tokens_override = max_tokens
|
|
297
321
|
self.max_iterations = max_iterations
|
|
298
322
|
self.max_tool_uses = max_tool_uses
|
|
299
|
-
|
|
323
|
+
|
|
300
324
|
# Set up available tools
|
|
301
325
|
self.available_tools: list[BaseTool] = []
|
|
302
326
|
self.available_tools.extend(
|
|
@@ -305,21 +329,21 @@ Usage notes:
|
|
|
305
329
|
self.available_tools.extend(
|
|
306
330
|
get_read_only_jupyter_tools(self.permission_manager)
|
|
307
331
|
)
|
|
308
|
-
|
|
332
|
+
|
|
309
333
|
# Add edit tools
|
|
310
334
|
self.available_tools.append(Edit(self.permission_manager))
|
|
311
335
|
self.available_tools.append(MultiEdit(self.permission_manager))
|
|
312
|
-
|
|
336
|
+
|
|
313
337
|
# Add special tools
|
|
314
338
|
self.available_tools.append(ClarificationTool())
|
|
315
339
|
self.available_tools.append(CriticTool())
|
|
316
340
|
self.available_tools.append(ReviewTool())
|
|
317
341
|
self.available_tools.append(IChingTool())
|
|
318
|
-
|
|
342
|
+
|
|
319
343
|
self.available_tools.append(
|
|
320
344
|
BatchTool({t.name: t for t in self.available_tools})
|
|
321
345
|
)
|
|
322
|
-
|
|
346
|
+
|
|
323
347
|
@override
|
|
324
348
|
async def call(
|
|
325
349
|
self,
|
|
@@ -328,17 +352,17 @@ Usage notes:
|
|
|
328
352
|
) -> str:
|
|
329
353
|
"""Execute the tool with the given parameters."""
|
|
330
354
|
start_time = time.time()
|
|
331
|
-
|
|
355
|
+
|
|
332
356
|
# Create tool context
|
|
333
357
|
tool_ctx = create_tool_context(ctx)
|
|
334
358
|
await tool_ctx.set_tool_info(self.name)
|
|
335
|
-
|
|
359
|
+
|
|
336
360
|
# Extract parameters
|
|
337
361
|
prompts = params.get("prompts")
|
|
338
362
|
if prompts is None:
|
|
339
363
|
await tool_ctx.error("No prompts provided")
|
|
340
364
|
return "Error: At least one prompt must be provided."
|
|
341
|
-
|
|
365
|
+
|
|
342
366
|
# Handle both string and list inputs
|
|
343
367
|
if isinstance(prompts, str):
|
|
344
368
|
prompt_list = [prompts]
|
|
@@ -350,30 +374,32 @@ Usage notes:
|
|
|
350
374
|
else:
|
|
351
375
|
await tool_ctx.error("Invalid prompts parameter type")
|
|
352
376
|
return "Error: Parameter 'prompts' must be a string or list of strings."
|
|
353
|
-
|
|
377
|
+
|
|
354
378
|
# Validate absolute paths
|
|
355
379
|
absolute_path_pattern = r"/(?:[^/\s]+/)*[^/\s]+"
|
|
356
380
|
for prompt in prompt_list:
|
|
357
381
|
if not re.search(absolute_path_pattern, prompt):
|
|
358
382
|
await tool_ctx.error(f"Prompt missing absolute path: {prompt[:50]}...")
|
|
359
383
|
return "Error: All prompts must contain at least one absolute path."
|
|
360
|
-
|
|
384
|
+
|
|
361
385
|
# Require hanzo-agents SDK
|
|
362
386
|
if not HANZO_AGENTS_AVAILABLE:
|
|
363
387
|
await tool_ctx.error("hanzo-agents SDK is required but not available")
|
|
364
388
|
return "Error: hanzo-agents SDK is required for agent tool functionality. Please install it with: pip install hanzo-agents"
|
|
365
|
-
|
|
389
|
+
|
|
366
390
|
# Use hanzo-agents SDK
|
|
367
|
-
await tool_ctx.info(
|
|
368
|
-
|
|
391
|
+
await tool_ctx.info(
|
|
392
|
+
f"Launching {len(prompt_list)} agent(s) using hanzo-agents SDK"
|
|
393
|
+
)
|
|
394
|
+
|
|
369
395
|
# Determine model and agent type
|
|
370
396
|
model = params.get("model", self.model_override)
|
|
371
397
|
use_memory = params.get("use_memory", False)
|
|
372
398
|
memory_backend = params.get("memory_backend", "sqlite")
|
|
373
|
-
|
|
399
|
+
|
|
374
400
|
# Get appropriate agent class
|
|
375
401
|
agent_class = self._get_agent_class(model)
|
|
376
|
-
|
|
402
|
+
|
|
377
403
|
# Create state
|
|
378
404
|
state = MCPAgentState(
|
|
379
405
|
prompts=prompt_list,
|
|
@@ -382,16 +408,16 @@ Usage notes:
|
|
|
382
408
|
"api_key": self.api_key_override,
|
|
383
409
|
"base_url": self.base_url_override,
|
|
384
410
|
"max_tokens": self.max_tokens_override,
|
|
385
|
-
}
|
|
411
|
+
},
|
|
386
412
|
)
|
|
387
|
-
|
|
413
|
+
|
|
388
414
|
# Create memory if requested
|
|
389
415
|
memory_kv = None
|
|
390
416
|
memory_vector = None
|
|
391
417
|
if use_memory:
|
|
392
418
|
memory_kv = create_memory_kv(memory_backend)
|
|
393
419
|
memory_vector = create_memory_vector("simple")
|
|
394
|
-
|
|
420
|
+
|
|
395
421
|
# Create network
|
|
396
422
|
network = Network(
|
|
397
423
|
state=state,
|
|
@@ -401,12 +427,12 @@ Usage notes:
|
|
|
401
427
|
memory_vector=memory_vector,
|
|
402
428
|
max_steps=self.max_iterations * len(prompt_list),
|
|
403
429
|
)
|
|
404
|
-
|
|
430
|
+
|
|
405
431
|
# Execute
|
|
406
432
|
try:
|
|
407
433
|
final_state = await network.run()
|
|
408
434
|
execution_time = time.time() - start_time
|
|
409
|
-
|
|
435
|
+
|
|
410
436
|
# Format results
|
|
411
437
|
results = final_state.results
|
|
412
438
|
if len(results) == 1:
|
|
@@ -417,25 +443,25 @@ AGENT RESPONSE:
|
|
|
417
443
|
else:
|
|
418
444
|
formatted_results = []
|
|
419
445
|
for i, result in enumerate(results):
|
|
420
|
-
formatted_results.append(f"Agent {i+1} Result:\n{result}")
|
|
421
|
-
|
|
446
|
+
formatted_results.append(f"Agent {i + 1} Result:\n{result}")
|
|
447
|
+
|
|
422
448
|
formatted_result = f"""Multi-agent execution completed in {execution_time:.2f} seconds ({len(results)} agents).
|
|
423
449
|
|
|
424
450
|
AGENT RESPONSES:
|
|
425
451
|
{chr(10).join(formatted_results)}"""
|
|
426
|
-
|
|
452
|
+
|
|
427
453
|
await tool_ctx.info(f"Execution completed in {execution_time:.2f}s")
|
|
428
454
|
return formatted_result
|
|
429
|
-
|
|
455
|
+
|
|
430
456
|
except Exception as e:
|
|
431
457
|
await tool_ctx.error(f"Agent execution failed: {str(e)}")
|
|
432
458
|
return f"Error: {str(e)}"
|
|
433
|
-
|
|
459
|
+
|
|
434
460
|
def _get_agent_class(self, model: Optional[str]) -> type[Agent]:
|
|
435
461
|
"""Get appropriate agent class based on model."""
|
|
436
462
|
if not model:
|
|
437
463
|
model = "model://anthropic/claude-3-5-sonnet-20241022"
|
|
438
|
-
|
|
464
|
+
|
|
439
465
|
# Check for CLI agents
|
|
440
466
|
cli_agents = {
|
|
441
467
|
"claude_cli": ClaudeCodeAgent,
|
|
@@ -443,39 +469,43 @@ AGENT RESPONSES:
|
|
|
443
469
|
"gemini_cli": GeminiAgent,
|
|
444
470
|
"grok_cli": GrokAgent,
|
|
445
471
|
}
|
|
446
|
-
|
|
472
|
+
|
|
447
473
|
if model in cli_agents:
|
|
448
474
|
return cli_agents[model]
|
|
449
|
-
|
|
475
|
+
|
|
450
476
|
# Return generic MCP agent
|
|
451
|
-
return type(
|
|
452
|
-
"
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
477
|
+
return type(
|
|
478
|
+
"DynamicMCPAgent",
|
|
479
|
+
(MCPAgent,),
|
|
480
|
+
{
|
|
481
|
+
"model": model,
|
|
482
|
+
"__init__": lambda self: MCPAgent.__init__(
|
|
483
|
+
self,
|
|
484
|
+
available_tools=self.available_tools,
|
|
485
|
+
permission_manager=self.permission_manager,
|
|
486
|
+
ctx=self.ctx,
|
|
487
|
+
model=model,
|
|
488
|
+
),
|
|
489
|
+
},
|
|
490
|
+
)
|
|
491
|
+
|
|
462
492
|
@override
|
|
463
493
|
def register(self, mcp_server: FastMCP) -> None:
|
|
464
494
|
"""Register this agent tool with the MCP server."""
|
|
465
495
|
tool_self = self
|
|
466
|
-
|
|
496
|
+
|
|
467
497
|
@mcp_server.tool(name=self.name, description=self.description)
|
|
468
498
|
async def dispatch_agent(
|
|
469
499
|
prompts: str | list[str],
|
|
470
500
|
ctx: MCPContext,
|
|
471
501
|
model: Optional[str] = None,
|
|
472
502
|
use_memory: bool = False,
|
|
473
|
-
memory_backend: str = "sqlite"
|
|
503
|
+
memory_backend: str = "sqlite",
|
|
474
504
|
) -> str:
|
|
475
505
|
return await tool_self.call(
|
|
476
506
|
ctx,
|
|
477
507
|
prompts=prompts,
|
|
478
508
|
model=model,
|
|
479
509
|
use_memory=use_memory,
|
|
480
|
-
memory_backend=memory_backend
|
|
481
|
-
)
|
|
510
|
+
memory_backend=memory_backend,
|
|
511
|
+
)
|