hanzo 0.3.26__tar.gz → 0.3.27__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 might be problematic. Click here for more details.

Files changed (46) hide show
  1. {hanzo-0.3.26 → hanzo-0.3.27}/PKG-INFO +1 -1
  2. {hanzo-0.3.26 → hanzo-0.3.27}/pyproject.toml +1 -1
  3. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/__init__.py +1 -1
  4. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/tools/detector.py +127 -31
  5. {hanzo-0.3.26 → hanzo-0.3.27}/.gitignore +0 -0
  6. {hanzo-0.3.26 → hanzo-0.3.27}/README.md +0 -0
  7. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/__main__.py +0 -0
  8. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/base_agent.py +0 -0
  9. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/batch_orchestrator.py +0 -0
  10. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/cli.py +0 -0
  11. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/commands/__init__.py +0 -0
  12. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/commands/agent.py +0 -0
  13. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/commands/auth.py +0 -0
  14. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/commands/auth_broken.py +0 -0
  15. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/commands/chat.py +0 -0
  16. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/commands/config.py +0 -0
  17. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/commands/mcp.py +0 -0
  18. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/commands/miner.py +0 -0
  19. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/commands/network.py +0 -0
  20. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/commands/node.py +0 -0
  21. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/commands/repl.py +0 -0
  22. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/commands/router.py +0 -0
  23. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/commands/tools.py +0 -0
  24. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/dev.py +0 -0
  25. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/fallback_handler.py +0 -0
  26. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/interactive/__init__.py +0 -0
  27. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/interactive/dashboard.py +0 -0
  28. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/interactive/enhanced_repl.py +0 -0
  29. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/interactive/model_selector.py +0 -0
  30. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/interactive/repl.py +0 -0
  31. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/mcp_server.py +0 -0
  32. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/memory_manager.py +0 -0
  33. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/model_registry.py +0 -0
  34. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/orchestrator_config.py +0 -0
  35. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/rate_limiter.py +0 -0
  36. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/repl.py +0 -0
  37. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/router/__init__.py +0 -0
  38. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/streaming.py +0 -0
  39. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/tools/__init__.py +0 -0
  40. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/ui/__init__.py +0 -0
  41. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/ui/inline_startup.py +0 -0
  42. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/ui/startup.py +0 -0
  43. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/utils/__init__.py +0 -0
  44. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/utils/config.py +0 -0
  45. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/utils/net_check.py +0 -0
  46. {hanzo-0.3.26 → hanzo-0.3.27}/src/hanzo/utils/output.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hanzo
3
- Version: 0.3.26
3
+ Version: 0.3.27
4
4
  Summary: Hanzo AI - Complete AI Infrastructure Platform with CLI, Router, MCP, and Agent Runtime
5
5
  Project-URL: Homepage, https://hanzo.ai
6
6
  Project-URL: Repository, https://github.com/hanzoai/python-sdk
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "hanzo"
3
- version = "0.3.26"
3
+ version = "0.3.27"
4
4
  description = "Hanzo AI - Complete AI Infrastructure Platform with CLI, Router, MCP, and Agent Runtime"
5
5
  authors = [
6
6
  {name = "Hanzo AI", email = "dev@hanzo.ai"},
@@ -1,6 +1,6 @@
1
1
  """Hanzo - Complete AI Infrastructure Platform with CLI, Router, MCP, and Agent Runtime."""
2
2
 
3
- __version__ = "0.3.26"
3
+ __version__ = "0.3.27"
4
4
  __all__ = ["main", "cli", "__version__"]
5
5
 
6
6
  from .cli import cli, main
@@ -3,6 +3,7 @@
3
3
  import os
4
4
  import shutil
5
5
  import subprocess
6
+ import httpx
6
7
  from pathlib import Path
7
8
  from typing import Dict, List, Optional, Tuple
8
9
  from dataclasses import dataclass
@@ -33,12 +34,33 @@ class ToolDetector:
33
34
 
34
35
  # Define available tools with priority order
35
36
  TOOLS = [
37
+ # Hanzo Local Node - highest priority for privacy and local control
38
+ AITool(
39
+ name="hanzod",
40
+ command="hanzo node",
41
+ display_name="Hanzo Node (Local Private AI)",
42
+ provider="hanzo-local",
43
+ priority=0, # Highest priority - local and private
44
+ check_command=None, # Check via API endpoint
45
+ api_endpoint="http://localhost:8000/health",
46
+ env_var=None
47
+ ),
48
+ AITool(
49
+ name="hanzo-router",
50
+ command="hanzo router",
51
+ display_name="Hanzo Router (LLM Proxy)",
52
+ provider="hanzo-router",
53
+ priority=1,
54
+ check_command=None,
55
+ api_endpoint="http://localhost:4000/health",
56
+ env_var=None
57
+ ),
36
58
  AITool(
37
59
  name="claude-code",
38
60
  command="claude",
39
61
  display_name="Claude Code",
40
62
  provider="anthropic",
41
- priority=1,
63
+ priority=2,
42
64
  check_command="claude --version",
43
65
  env_var="ANTHROPIC_API_KEY"
44
66
  ),
@@ -47,7 +69,7 @@ class ToolDetector:
47
69
  command="hanzo dev",
48
70
  display_name="Hanzo Dev (Native)",
49
71
  provider="hanzo",
50
- priority=2,
72
+ priority=3,
51
73
  check_command="hanzo --version",
52
74
  env_var="HANZO_API_KEY"
53
75
  ),
@@ -56,7 +78,7 @@ class ToolDetector:
56
78
  command="openai",
57
79
  display_name="OpenAI Codex",
58
80
  provider="openai",
59
- priority=3,
81
+ priority=4,
60
82
  check_command="openai --version",
61
83
  env_var="OPENAI_API_KEY"
62
84
  ),
@@ -65,7 +87,7 @@ class ToolDetector:
65
87
  command="gemini",
66
88
  display_name="Gemini CLI",
67
89
  provider="google",
68
- priority=4,
90
+ priority=5,
69
91
  check_command="gemini --version",
70
92
  env_var="GEMINI_API_KEY"
71
93
  ),
@@ -74,7 +96,7 @@ class ToolDetector:
74
96
  command="grok",
75
97
  display_name="Grok CLI",
76
98
  provider="xai",
77
- priority=5,
99
+ priority=6,
78
100
  check_command="grok --version",
79
101
  env_var="GROK_API_KEY"
80
102
  ),
@@ -83,7 +105,7 @@ class ToolDetector:
83
105
  command="openhands",
84
106
  display_name="OpenHands CLI",
85
107
  provider="openhands",
86
- priority=6,
108
+ priority=7,
87
109
  check_command="openhands --version",
88
110
  env_var=None
89
111
  ),
@@ -92,7 +114,7 @@ class ToolDetector:
92
114
  command="cursor",
93
115
  display_name="Cursor AI",
94
116
  provider="cursor",
95
- priority=7,
117
+ priority=8,
96
118
  check_command="cursor --version",
97
119
  env_var=None
98
120
  ),
@@ -101,7 +123,7 @@ class ToolDetector:
101
123
  command="codeium",
102
124
  display_name="Codeium",
103
125
  provider="codeium",
104
- priority=8,
126
+ priority=9,
105
127
  check_command="codeium --version",
106
128
  env_var="CODEIUM_API_KEY"
107
129
  ),
@@ -110,7 +132,7 @@ class ToolDetector:
110
132
  command="aider",
111
133
  display_name="Aider",
112
134
  provider="aider",
113
- priority=9,
135
+ priority=10,
114
136
  check_command="aider --version",
115
137
  env_var=None
116
138
  ),
@@ -119,7 +141,7 @@ class ToolDetector:
119
141
  command="continue",
120
142
  display_name="Continue Dev",
121
143
  provider="continue",
122
- priority=10,
144
+ priority=11,
123
145
  check_command="continue --version",
124
146
  env_var=None
125
147
  )
@@ -143,26 +165,51 @@ class ToolDetector:
143
165
 
144
166
  def detect_tool(self, tool: AITool) -> bool:
145
167
  """Detect if a specific tool is available."""
168
+ # Check API endpoint first (for services like hanzod)
169
+ if tool.api_endpoint:
170
+ try:
171
+ response = httpx.get(tool.api_endpoint, timeout=1.0)
172
+ if response.status_code == 200:
173
+ tool.detected = True
174
+ tool.version = "Running"
175
+
176
+ # Special handling for Hanzo services
177
+ if tool.name == "hanzod":
178
+ # Check if models are loaded
179
+ try:
180
+ models_response = httpx.get("http://localhost:8000/models", timeout=1.0)
181
+ if models_response.status_code == 200:
182
+ models = models_response.json()
183
+ if models:
184
+ tool.version = f"Running ({len(models)} models)"
185
+ except:
186
+ pass
187
+
188
+ return True
189
+ except:
190
+ pass
191
+
146
192
  # Check if command exists
147
- tool.path = shutil.which(tool.command.split()[0])
148
- if tool.path:
149
- tool.detected = True
150
-
151
- # Try to get version
152
- if tool.check_command:
153
- try:
154
- result = subprocess.run(
155
- tool.check_command.split(),
156
- capture_output=True,
157
- text=True,
158
- timeout=2
159
- )
160
- if result.returncode == 0:
161
- tool.version = result.stdout.strip().split()[-1]
162
- except:
163
- pass
164
-
165
- return True
193
+ if tool.command:
194
+ tool.path = shutil.which(tool.command.split()[0])
195
+ if tool.path:
196
+ tool.detected = True
197
+
198
+ # Try to get version
199
+ if tool.check_command:
200
+ try:
201
+ result = subprocess.run(
202
+ tool.check_command.split(),
203
+ capture_output=True,
204
+ text=True,
205
+ timeout=2
206
+ )
207
+ if result.returncode == 0:
208
+ tool.version = result.stdout.strip().split()[-1]
209
+ except:
210
+ pass
211
+
212
+ return True
166
213
 
167
214
  # Check environment variable as fallback
168
215
  if tool.env_var and os.getenv(tool.env_var):
@@ -229,13 +276,25 @@ class ToolDetector:
229
276
  if self.detected_tools:
230
277
  default = self.detected_tools[0]
231
278
  self.console.print(f"\n[green]Default tool: {default.display_name}[/green]")
279
+
280
+ # Special message for Hanzo Node
281
+ if default.name == "hanzod":
282
+ self.console.print("[cyan]🔒 Using local private AI - your data stays on your machine[/cyan]")
283
+ self.console.print("[dim]Manage models with: hanzo node models[/dim]")
232
284
  else:
233
285
  self.console.print("\n[yellow]No AI coding tools detected.[/yellow]")
234
- self.console.print("[dim]Install Claude Code, OpenAI CLI, or other tools to enable AI features.[/dim]")
286
+ self.console.print("[dim]Start Hanzo Node for local AI: hanzo node start[/dim]")
287
+ self.console.print("[dim]Or install Claude Code, OpenAI CLI, etc.[/dim]")
235
288
 
236
289
  def get_tool_command(self, tool: AITool, prompt: str) -> List[str]:
237
290
  """Get the command to execute for a tool with a prompt."""
238
- if tool.name == "claude-code":
291
+ if tool.name == "hanzod":
292
+ # Use the local Hanzo node API
293
+ return ["hanzo", "ask", "--local", prompt]
294
+ elif tool.name == "hanzo-router":
295
+ # Use the router proxy
296
+ return ["hanzo", "ask", "--router", prompt]
297
+ elif tool.name == "claude-code":
239
298
  return ["claude", prompt]
240
299
  elif tool.name == "hanzo-dev":
241
300
  return ["hanzo", "dev", "--prompt", prompt]
@@ -257,6 +316,43 @@ class ToolDetector:
257
316
  def execute_with_tool(self, tool: AITool, prompt: str) -> Tuple[bool, str]:
258
317
  """Execute a prompt with a specific tool."""
259
318
  try:
319
+ # Special handling for Hanzo services
320
+ if tool.name == "hanzod":
321
+ # Use the local API directly
322
+ try:
323
+ response = httpx.post(
324
+ "http://localhost:8000/chat/completions",
325
+ json={
326
+ "messages": [{"role": "user", "content": prompt}],
327
+ "stream": False
328
+ },
329
+ timeout=30.0
330
+ )
331
+ if response.status_code == 200:
332
+ result = response.json()
333
+ return True, result.get("choices", [{}])[0].get("message", {}).get("content", "")
334
+ except Exception as e:
335
+ return False, f"Hanzo Node error: {e}"
336
+
337
+ elif tool.name == "hanzo-router":
338
+ # Use the router API
339
+ try:
340
+ response = httpx.post(
341
+ "http://localhost:4000/chat/completions",
342
+ json={
343
+ "messages": [{"role": "user", "content": prompt}],
344
+ "model": "gpt-3.5-turbo", # Router will route to best available
345
+ "stream": False
346
+ },
347
+ timeout=30.0
348
+ )
349
+ if response.status_code == 200:
350
+ result = response.json()
351
+ return True, result.get("choices", [{}])[0].get("message", {}).get("content", "")
352
+ except Exception as e:
353
+ return False, f"Router error: {e}"
354
+
355
+ # Default command execution
260
356
  command = self.get_tool_command(tool, prompt)
261
357
  result = subprocess.run(
262
358
  command,
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes