hanzo-mcp 0.2.0__tar.gz → 0.3.1__tar.gz

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.

Files changed (63) hide show
  1. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/PKG-INFO +1 -1
  2. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/__init__.py +1 -1
  3. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/cli.py +110 -25
  4. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/server.py +26 -4
  5. hanzo_mcp-0.3.1/hanzo_mcp/tools/agent/base_provider.py +73 -0
  6. hanzo_mcp-0.3.1/hanzo_mcp/tools/agent/litellm_provider.py +45 -0
  7. hanzo_mcp-0.3.1/hanzo_mcp/tools/agent/lmstudio_agent.py +385 -0
  8. hanzo_mcp-0.3.1/hanzo_mcp/tools/agent/lmstudio_provider.py +219 -0
  9. hanzo_mcp-0.3.1/hanzo_mcp/tools/agent/provider_registry.py +120 -0
  10. hanzo_mcp-0.3.1/hanzo_mcp/tools/common/error_handling.py +86 -0
  11. hanzo_mcp-0.3.1/hanzo_mcp/tools/common/logging_config.py +84 -0
  12. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp.egg-info/PKG-INFO +1 -1
  13. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp.egg-info/SOURCES.txt +7 -0
  14. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/pyproject.toml +1 -1
  15. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/LICENSE +0 -0
  16. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/README.md +0 -0
  17. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/__init__.py +0 -0
  18. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/agent/__init__.py +0 -0
  19. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/agent/agent_tool.py +0 -0
  20. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/agent/prompt.py +0 -0
  21. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/agent/tool_adapter.py +0 -0
  22. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/common/__init__.py +0 -0
  23. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/common/base.py +0 -0
  24. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/common/context.py +0 -0
  25. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/common/permissions.py +0 -0
  26. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/common/session.py +0 -0
  27. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/common/think_tool.py +0 -0
  28. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/common/validation.py +0 -0
  29. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/common/version_tool.py +0 -0
  30. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/filesystem/__init__.py +0 -0
  31. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/filesystem/base.py +0 -0
  32. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/filesystem/content_replace.py +0 -0
  33. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/filesystem/directory_tree.py +0 -0
  34. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/filesystem/edit_file.py +0 -0
  35. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/filesystem/get_file_info.py +0 -0
  36. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/filesystem/read_files.py +0 -0
  37. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/filesystem/search_content.py +0 -0
  38. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/filesystem/write_file.py +0 -0
  39. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/jupyter/__init__.py +0 -0
  40. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/jupyter/base.py +0 -0
  41. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/jupyter/edit_notebook.py +0 -0
  42. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/jupyter/notebook_operations.py +0 -0
  43. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/jupyter/read_notebook.py +0 -0
  44. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/project/__init__.py +0 -0
  45. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/project/analysis.py +0 -0
  46. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/project/base.py +0 -0
  47. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/project/project_analyze.py +0 -0
  48. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/shell/__init__.py +0 -0
  49. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/shell/base.py +0 -0
  50. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/shell/command_executor.py +0 -0
  51. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/shell/run_command.py +0 -0
  52. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/shell/run_script.py +0 -0
  53. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/shell/script_tool.py +0 -0
  54. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp.egg-info/dependency_links.txt +0 -0
  55. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp.egg-info/entry_points.txt +0 -0
  56. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp.egg-info/requires.txt +0 -0
  57. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp.egg-info/top_level.txt +0 -0
  58. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/setup.cfg +0 -0
  59. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/setup.py +0 -0
  60. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/tests/test_cli.py +0 -0
  61. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/tests/test_server.py +0 -0
  62. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/tests/test_tools_registration.py +0 -0
  63. {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/tests/test_validation.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hanzo-mcp
3
- Version: 0.2.0
3
+ Version: 0.3.1
4
4
  Summary: MCP implementation of Hanzo capabilities
5
5
  Author-email: Hanzo Industries Inc <dev@hanzo.ai>
6
6
  License: MIT
@@ -1,3 +1,3 @@
1
1
  """Hanzo MCP - Implementation of Hanzo capabilities using MCP."""
2
2
 
3
- __version__ = "0.2.0"
3
+ __version__ = "0.3.1"
@@ -1,20 +1,42 @@
1
- """Command-line interface for the Hanzo MCP server."""
1
+ """Command-line interface for the Hanzo MCP server.
2
+
3
+ Includes logging configuration and enhanced error handling.
4
+ """
2
5
 
3
6
  import argparse
4
7
  import json
8
+ import logging
5
9
  import os
6
10
  import sys
7
11
  from pathlib import Path
8
12
  from typing import Any, cast
9
13
 
14
+ from hanzo_mcp import __version__
15
+ from hanzo_mcp.tools.common.logging_config import setup_logging
16
+
10
17
  from hanzo_mcp.server import HanzoServer
11
18
 
12
19
 
13
20
  def main() -> None:
14
21
  """Run the CLI for the Hanzo MCP server."""
22
+ # Initialize logger
23
+ logger = logging.getLogger(__name__)
24
+
25
+ # Check if 'version' is the first argument
26
+ if len(sys.argv) > 1 and sys.argv[1] == 'version':
27
+ print(f"hanzo-mcp {__version__}")
28
+ return
29
+
15
30
  parser = argparse.ArgumentParser(
16
31
  description="MCP server implementing Hanzo capabilities"
17
32
  )
33
+
34
+ parser.add_argument(
35
+ "--version",
36
+ action="version",
37
+ version=f"%(prog)s {__version__}",
38
+ help="Show the current version and exit"
39
+ )
18
40
 
19
41
  _ = parser.add_argument(
20
42
  "--transport",
@@ -23,6 +45,19 @@ def main() -> None:
23
45
  help="Transport protocol to use (default: stdio)",
24
46
  )
25
47
 
48
+ _ = parser.add_argument(
49
+ "--port",
50
+ type=int,
51
+ default=3001,
52
+ help="Port to use for SSE transport (default: 3001)",
53
+ )
54
+
55
+ _ = parser.add_argument(
56
+ "--host",
57
+ default="0.0.0.0",
58
+ help="Host to bind to for SSE transport (default: 0.0.0.0)",
59
+ )
60
+
26
61
  _ = parser.add_argument(
27
62
  "--name",
28
63
  default="claude-code",
@@ -39,26 +74,26 @@ def main() -> None:
39
74
  _ = parser.add_argument(
40
75
  "--project-dir", dest="project_dir", help="Set the project directory to analyze"
41
76
  )
42
-
77
+
43
78
  _ = parser.add_argument(
44
79
  "--agent-model",
45
80
  dest="agent_model",
46
81
  help="Specify the model name in LiteLLM format (e.g., 'openai/gpt-4o', 'anthropic/claude-3-sonnet')"
47
82
  )
48
-
83
+
49
84
  _ = parser.add_argument(
50
85
  "--agent-max-tokens",
51
86
  dest="agent_max_tokens",
52
87
  type=int,
53
88
  help="Specify the maximum tokens for agent responses"
54
89
  )
55
-
90
+
56
91
  _ = parser.add_argument(
57
92
  "--agent-api-key",
58
93
  dest="agent_api_key",
59
94
  help="Specify the API key for the LLM provider (for development/testing only)"
60
95
  )
61
-
96
+
62
97
  _ = parser.add_argument(
63
98
  "--agent-max-iterations",
64
99
  dest="agent_max_iterations",
@@ -66,7 +101,7 @@ def main() -> None:
66
101
  default=10,
67
102
  help="Maximum number of iterations for agent (default: 10)"
68
103
  )
69
-
104
+
70
105
  _ = parser.add_argument(
71
106
  "--agent-max-tool-uses",
72
107
  dest="agent_max_tool_uses",
@@ -74,7 +109,7 @@ def main() -> None:
74
109
  default=30,
75
110
  help="Maximum number of total tool uses for agent (default: 30)"
76
111
  )
77
-
112
+
78
113
  _ = parser.add_argument(
79
114
  "--enable-agent-tool",
80
115
  dest="enable_agent_tool",
@@ -82,7 +117,23 @@ def main() -> None:
82
117
  default=False,
83
118
  help="Enable the agent tool (disabled by default)"
84
119
  )
85
-
120
+
121
+ _ = parser.add_argument(
122
+ "--log-level",
123
+ dest="log_level",
124
+ choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
125
+ default="INFO",
126
+ help="Set the logging level (default: INFO)"
127
+ )
128
+
129
+ _ = parser.add_argument(
130
+ "--disable-file-logging",
131
+ dest="disable_file_logging",
132
+ action="store_true",
133
+ default=False,
134
+ help="Disable logging to file (logs to console only)"
135
+ )
136
+
86
137
  _ = parser.add_argument(
87
138
  "--disable-write-tools",
88
139
  dest="disable_write_tools",
@@ -103,6 +154,8 @@ def main() -> None:
103
154
  name: str = cast(str, args.name)
104
155
  install: bool = cast(bool, args.install)
105
156
  transport: str = cast(str, args.transport)
157
+ port: int = cast(int, args.port)
158
+ host: str = cast(str, args.host)
106
159
  project_dir: str | None = cast(str | None, args.project_dir)
107
160
  agent_model: str | None = cast(str | None, args.agent_model)
108
161
  agent_max_tokens: int | None = cast(int | None, args.agent_max_tokens)
@@ -111,17 +164,25 @@ def main() -> None:
111
164
  agent_max_tool_uses: int = cast(int, args.agent_max_tool_uses)
112
165
  enable_agent_tool: bool = cast(bool, args.enable_agent_tool)
113
166
  disable_write_tools: bool = cast(bool, args.disable_write_tools)
167
+ log_level: str = cast(str, args.log_level)
168
+ disable_file_logging: bool = cast(bool, args.disable_file_logging)
114
169
  allowed_paths: list[str] = (
115
170
  cast(list[str], args.allowed_paths) if args.allowed_paths else []
116
171
  )
117
172
 
173
+ # Setup logging
174
+ setup_logging(log_level=log_level, log_to_file=not disable_file_logging, testing="pytest" in sys.modules)
175
+ logger.debug(f"Hanzo MCP CLI started with arguments: {args}")
176
+
177
+
118
178
  if install:
119
- install_claude_desktop_config(name, allowed_paths, disable_write_tools)
179
+ install_claude_desktop_config(name, allowed_paths, host, port)
120
180
  return
121
181
 
122
182
  # If no allowed paths are specified, use the user's home directory
123
183
  if not allowed_paths:
124
184
  allowed_paths = [str(Path.home())]
185
+ logger.info(f"No allowed paths specified, using home directory: {allowed_paths[0]}")
125
186
 
126
187
  # If project directory is specified, add it to allowed paths
127
188
  if project_dir and project_dir not in allowed_paths:
@@ -140,25 +201,39 @@ def main() -> None:
140
201
  project_dir = allowed_paths[0]
141
202
 
142
203
  # Run the server
143
- server = HanzoServer(
144
- name=name,
145
- allowed_paths=allowed_paths,
146
- project_dir=project_dir, # Pass project_dir for initial working directory
147
- agent_model=agent_model,
148
- agent_max_tokens=agent_max_tokens,
149
- agent_api_key=agent_api_key,
150
- agent_max_iterations=agent_max_iterations,
151
- agent_max_tool_uses=agent_max_tool_uses,
152
- enable_agent_tool=enable_agent_tool,
153
- disable_write_tools=disable_write_tools
154
- )
155
- # Transport will be automatically cast to Literal['stdio', 'sse'] by the server
156
- server.run(transport=transport)
204
+ logger.info(f"Starting Hanzo MCP server with name: {name}")
205
+ logger.debug(f"Allowed paths: {allowed_paths}")
206
+ logger.debug(f"Project directory: {project_dir}")
207
+
208
+ try:
209
+ server = HanzoServer(
210
+ name=name,
211
+ allowed_paths=allowed_paths,
212
+ project_dir=project_dir, # Pass project_dir for initial working directory
213
+ agent_model=agent_model,
214
+ agent_max_tokens=agent_max_tokens,
215
+ agent_api_key=agent_api_key,
216
+ agent_max_iterations=agent_max_iterations,
217
+ agent_max_tool_uses=agent_max_tool_uses,
218
+ enable_agent_tool=enable_agent_tool,
219
+ disable_write_tools=disable_write_tools,
220
+ host=host,
221
+ port=port
222
+ )
223
+ logger.info(f"Server initialized successfully, running with transport: {transport}")
224
+ # Transport will be automatically cast to Literal['stdio', 'sse'] by the server
225
+ server.run(transport=transport)
226
+ except Exception as e:
227
+ logger.error(f"Error starting server: {str(e)}")
228
+ logger.exception("Server startup failed with exception:")
229
+ # Re-raise the exception for proper error handling
230
+ raise
157
231
 
158
232
 
159
233
  def install_claude_desktop_config(
160
234
  name: str = "claude-code", allowed_paths: list[str] | None = None,
161
- disable_write_tools: bool = False
235
+ disable_write_tools: bool = False,
236
+ host: str = "0.0.0.0", port: int = 3001
162
237
  ) -> None:
163
238
  """Install the server configuration in Claude Desktop.
164
239
 
@@ -168,6 +243,8 @@ def install_claude_desktop_config(
168
243
  disable_write_tools: Whether to disable write/edit tools (file writing, editing, notebook editing)
169
244
  to use IDE tools instead. Note: Shell commands can still modify files.
170
245
  (default: False)
246
+ host: Host to bind to for SSE transport (default: '0.0.0.0')
247
+ port: Port to use for SSE transport (default: 3001)
171
248
  """
172
249
  # Find the Claude Desktop config directory
173
250
  home: Path = Path.home()
@@ -197,11 +274,19 @@ def install_claude_desktop_config(
197
274
  else:
198
275
  # Allow home directory by default
199
276
  args.extend(["--allow-path", str(home)])
200
-
277
+
278
+ # Add host and port
279
+ args.extend(["--host", host])
280
+ args.extend(["--port", str(port)])
281
+
201
282
  # Add disable_write_tools flag if specified
202
283
  if disable_write_tools:
203
284
  args.append("--disable-write-tools")
204
285
 
286
+ # Add host and port
287
+ args.extend(["--host", host])
288
+ args.extend(["--port", str(port)])
289
+
205
290
  # Create config object
206
291
  config: dict[str, Any] = {
207
292
  "mcpServers": {name: {"command": str(script_path), "args": args}}
@@ -1,4 +1,7 @@
1
- """MCP server implementing Hanzo capabilities."""
1
+ """MCP server implementing Hanzo capabilities.
2
+
3
+ Includes improved error handling and debugging for tool execution.
4
+ """
2
5
 
3
6
  from typing import Literal, cast, final
4
7
 
@@ -13,7 +16,10 @@ from hanzo_mcp.tools.shell.command_executor import CommandExecutor
13
16
 
14
17
  @final
15
18
  class HanzoServer:
16
- """MCP server implementing Hanzo capabilities."""
19
+ """MCP server implementing Hanzo capabilities.
20
+
21
+ Includes improved error handling and debugging for tool execution.
22
+ """
17
23
 
18
24
  def __init__(
19
25
  self,
@@ -28,6 +34,8 @@ class HanzoServer:
28
34
  agent_max_tool_uses: int = 30,
29
35
  enable_agent_tool: bool = False,
30
36
  disable_write_tools: bool = False,
37
+ host: str = "0.0.0.0",
38
+ port: int = 3001,
31
39
  ):
32
40
  """Initialize the Hanzo server.
33
41
 
@@ -43,6 +51,8 @@ class HanzoServer:
43
51
  agent_max_tool_uses: Maximum number of total tool uses for agent (default: 30)
44
52
  enable_agent_tool: Whether to enable the agent tool (default: False)
45
53
  disable_write_tools: Whether to disable write/edit tools (default: False)
54
+ host: Host to bind to for SSE transport (default: '0.0.0.0')
55
+ port: Port to use for SSE transport (default: 3001)
46
56
  """
47
57
  self.mcp = mcp_instance if mcp_instance is not None else FastMCP(name)
48
58
 
@@ -55,7 +65,7 @@ class HanzoServer:
55
65
  permission_manager=self.permission_manager,
56
66
  verbose=False, # Set to True for debugging
57
67
  )
58
-
68
+
59
69
  # If project_dir is specified, set it as initial working directory for all sessions
60
70
  if project_dir:
61
71
  initial_session_id = name # Use server name as default session ID
@@ -83,7 +93,11 @@ class HanzoServer:
83
93
  self.agent_max_tool_uses = agent_max_tool_uses
84
94
  self.enable_agent_tool = enable_agent_tool
85
95
  self.disable_write_tools = disable_write_tools
86
-
96
+
97
+ # Store network options
98
+ self.host = host
99
+ self.port = port
100
+
87
101
  # Register all tools
88
102
  register_all_tools(
89
103
  mcp_server=self.mcp,
@@ -111,6 +125,14 @@ class HanzoServer:
111
125
  self.permission_manager.add_allowed_path(path)
112
126
  self.document_context.add_allowed_path(path)
113
127
 
128
+ # If using SSE, set the port and host in the environment variables
129
+ if transport == "sse":
130
+ import os
131
+ # Set environment variables for FastMCP settings
132
+ os.environ["FASTMCP_PORT"] = str(self.port)
133
+ os.environ["FASTMCP_HOST"] = self.host
134
+ print(f"Starting SSE server on {self.host}:{self.port}")
135
+
114
136
  # Run the server
115
137
  transport_type = cast(Literal["stdio", "sse"], transport)
116
138
  self.mcp.run(transport=transport_type)
@@ -0,0 +1,73 @@
1
+ """Base model provider for agent delegation.
2
+
3
+ Defines the interface for model providers.
4
+ """
5
+
6
+ import logging
7
+ from abc import ABC, abstractmethod
8
+ from typing import Any, Dict, List, Optional, Tuple
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+
13
+ class BaseModelProvider(ABC):
14
+ """Base class for model providers."""
15
+
16
+ @abstractmethod
17
+ async def initialize(self) -> None:
18
+ """Initialize the provider."""
19
+ pass
20
+
21
+ @abstractmethod
22
+ async def load_model(self, model_name: str, identifier: Optional[str] = None) -> str:
23
+ """Load a model.
24
+
25
+ Args:
26
+ model_name: The name of the model to load
27
+ identifier: Optional identifier for the model instance
28
+
29
+ Returns:
30
+ The identifier for the loaded model
31
+ """
32
+ pass
33
+
34
+ @abstractmethod
35
+ async def generate(
36
+ self,
37
+ model_id: str,
38
+ prompt: str,
39
+ system_prompt: Optional[str] = None,
40
+ max_tokens: int = 4096,
41
+ temperature: float = 0.7,
42
+ top_p: float = 0.95,
43
+ stop_sequences: Optional[List[str]] = None,
44
+ ) -> Tuple[str, Dict[str, Any]]:
45
+ """Generate a response from the model.
46
+
47
+ Args:
48
+ model_id: The identifier of the model to use
49
+ prompt: The prompt to send to the model
50
+ system_prompt: Optional system prompt to send to the model
51
+ max_tokens: Maximum number of tokens to generate
52
+ temperature: Sampling temperature
53
+ top_p: Top-p sampling parameter
54
+ stop_sequences: Optional list of strings that will stop generation
55
+
56
+ Returns:
57
+ A tuple of (generated text, metadata)
58
+ """
59
+ pass
60
+
61
+ @abstractmethod
62
+ async def unload_model(self, model_id: str) -> None:
63
+ """Unload a model.
64
+
65
+ Args:
66
+ model_id: The identifier of the model to unload
67
+ """
68
+ pass
69
+
70
+ @abstractmethod
71
+ async def shutdown(self) -> None:
72
+ """Shutdown the provider."""
73
+ pass
@@ -0,0 +1,45 @@
1
+ """LiteLLM provider for agent delegation.
2
+
3
+ Enables the use of various cloud LLM providers via LiteLLM.
4
+ """
5
+
6
+ import asyncio
7
+ import logging
8
+ import json
9
+ from typing import Any, Dict, List, Optional, Tuple
10
+
11
+ from hanzo_mcp.tools.agent.base_provider import BaseModelProvider
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+ # Define model capabilities
16
+ DEFAULT_MAX_TOKENS = 4096
17
+ DEFAULT_CONTEXT_WINDOW = 8192
18
+
19
+
20
+ class LiteLLMProvider(BaseModelProvider):
21
+ """Provider for cloud models via LiteLLM."""
22
+
23
+ def __init__(self):
24
+ """Initialize the LiteLLM provider."""
25
+ self.models = {}
26
+ self.initialized = False
27
+
28
+ async def initialize(self) -> None:
29
+ """Initialize the LiteLLM provider."""
30
+ if self.initialized:
31
+ return
32
+
33
+ try:
34
+ # Import LiteLLM
35
+ import litellm
36
+ self.litellm = litellm
37
+ self.initialized = True
38
+ logger.info("LiteLLM provider initialized successfully")
39
+ except ImportError:
40
+ logger.error("Failed to import LiteLLM")
41
+ logger.error("Install LiteLLM with 'pip install litellm'")
42
+ except Exception as e:
43
+ logger.error(f"Failed to initialize LiteLLM provider: {str(e)}")
44
+
45
+ async def load_model(self, model_name: str, identifier: Optional[str] = None