hanzo 0.3.23__py3-none-any.whl → 0.3.25__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 might be problematic. Click here for more details.

hanzo/interactive/repl.py CHANGED
@@ -35,16 +35,19 @@ class HanzoREPL:
35
35
  # Don't print welcome message here since it's already printed in cli.py
36
36
 
37
37
  # Set up command completer
38
+ cli_commands = ["chat", "ask", "agent", "node", "mcp", "network",
39
+ "auth", "config", "tools", "miner", "serve", "net",
40
+ "dev", "router"]
38
41
  completer = WordCompleter(
39
- list(self.commands.keys()) + ["chat", "agent", "cluster", "mcp", "network"],
42
+ list(self.commands.keys()) + cli_commands,
40
43
  ignore_case=True,
41
44
  )
42
45
 
43
46
  while self.running:
44
47
  try:
45
- # Get input
48
+ # Get input with simple prompt
46
49
  command = await self.session.prompt_async(
47
- "hanzo> ", completer=completer
50
+ "> ", completer=completer
48
51
  )
49
52
 
50
53
  if not command.strip():
@@ -58,8 +61,12 @@ class HanzoREPL:
58
61
  # Execute command
59
62
  if cmd in self.commands:
60
63
  await self.commands[cmd](args)
61
- else:
64
+ elif cmd in ["chat", "ask", "agent", "node", "mcp", "network", "auth", "config", "tools", "miner", "serve", "net", "dev", "router"]:
65
+ # Execute known CLI commands
62
66
  await self.execute_command(cmd, args)
67
+ else:
68
+ # Treat as chat message if not a known command
69
+ await self.chat_with_ai(command)
63
70
 
64
71
  except KeyboardInterrupt:
65
72
  continue
@@ -83,7 +90,7 @@ class HanzoREPL:
83
90
  All Hanzo CLI commands are available:
84
91
  - `chat <message>` - Chat with AI
85
92
  - `agent start` - Start an agent
86
- - `cluster status` - Check cluster status
93
+ - `node status` - Check node status
87
94
  - `mcp tools` - List MCP tools
88
95
  - `network agents` - List network agents
89
96
 
@@ -91,7 +98,7 @@ All Hanzo CLI commands are available:
91
98
  ```
92
99
  hanzo> chat How do I create a Python web server?
93
100
  hanzo> agent list
94
- hanzo> cluster start --models llama-3.2-3b
101
+ hanzo> node start --models llama-3.2-3b
95
102
  hanzo> mcp run read_file --arg path=README.md
96
103
  ```
97
104
 
@@ -114,53 +121,60 @@ hanzo> mcp run read_file --arg path=README.md
114
121
  async def show_status(self, args: str = ""):
115
122
  """Show system status."""
116
123
  status = {
117
- "cluster": await self.check_cluster_status(),
124
+ "node": await self.check_node_status(),
118
125
  "agents": await self.count_agents(),
119
126
  "auth": self.check_auth_status(),
120
127
  }
121
128
 
122
129
  self.console.print("[cyan]System Status:[/cyan]")
123
- self.console.print(f" Cluster: {status['cluster']}")
130
+ self.console.print(f" Node: {status['node']}")
124
131
  self.console.print(f" Agents: {status['agents']}")
125
132
  self.console.print(f" Auth: {status['auth']}")
126
133
 
127
134
  async def execute_command(self, cmd: str, args: str):
128
135
  """Execute a CLI command."""
129
- # Import here to avoid circular imports
136
+ import os
130
137
  import sys
131
-
132
- import click
133
-
134
- from .. import cli
135
-
136
- # Build command line
137
- argv = [cmd]
138
+ import shutil
139
+ import subprocess
140
+
141
+ # Find hanzo executable
142
+ hanzo_cmd = shutil.which("hanzo")
143
+ if not hanzo_cmd:
144
+ # Try using Python module directly
145
+ hanzo_cmd = sys.executable
146
+ argv = [hanzo_cmd, "-m", "hanzo", cmd]
147
+ else:
148
+ argv = [hanzo_cmd, cmd]
149
+
138
150
  if args:
139
151
  import shlex
140
-
141
152
  argv.extend(shlex.split(args))
142
153
 
143
- # Create a new context
154
+ # Execute as subprocess to avoid context issues
144
155
  try:
145
- # Save original argv
146
- orig_argv = sys.argv
147
- sys.argv = ["hanzo"] + argv
148
-
149
- # Execute command
150
- ctx = click.Context(cli.cli)
151
- cli.cli.invoke(ctx)
152
-
153
- except SystemExit:
154
- # Catch exit from commands
155
- pass
156
+ result = subprocess.run(
157
+ argv,
158
+ capture_output=True,
159
+ text=True,
160
+ timeout=30,
161
+ env=os.environ.copy() # Pass environment variables
162
+ )
163
+
164
+ if result.stdout:
165
+ self.console.print(result.stdout.rstrip())
166
+ if result.stderr and result.returncode != 0:
167
+ self.console.print(f"[red]{result.stderr.rstrip()}[/red]")
168
+
169
+ except subprocess.TimeoutExpired:
170
+ self.console.print("[red]Command timed out[/red]")
171
+ except FileNotFoundError:
172
+ self.console.print("[red]Command not found. Make sure 'hanzo' is installed.[/red]")
156
173
  except Exception as e:
157
174
  self.console.print(f"[red]Command error: {e}[/red]")
158
- finally:
159
- # Restore argv
160
- sys.argv = orig_argv
161
175
 
162
- async def check_cluster_status(self) -> str:
163
- """Check if cluster is running."""
176
+ async def check_node_status(self) -> str:
177
+ """Check if node is running."""
164
178
  try:
165
179
  import httpx
166
180
 
@@ -185,3 +199,9 @@ hanzo> mcp run read_file --arg path=README.md
185
199
  return "authenticated (saved)"
186
200
  else:
187
201
  return "not authenticated"
202
+
203
+ async def chat_with_ai(self, message: str):
204
+ """Chat with AI when user types natural language."""
205
+ # For natural language input, try to use it as a chat message
206
+ # Default to cloud mode to avoid needing local server
207
+ await self.execute_command("ask", f"--cloud {message}")
hanzo/mcp_server.py CHANGED
@@ -6,11 +6,16 @@ import click
6
6
 
7
7
 
8
8
  def main():
9
- """Start the Hanzo MCP server."""
9
+ """Start the Hanzo MCP server.
10
+
11
+ This wrapper defers to hanzo_mcp.cli:main so that the CLI can parse
12
+ transport flags and configure logging BEFORE importing any heavy modules,
13
+ preventing stdio protocol corruption.
14
+ """
10
15
  try:
11
- from hanzo_mcp.server import main as mcp_main
16
+ from hanzo_mcp.cli import main as cli_main
12
17
 
13
- mcp_main()
18
+ cli_main()
14
19
  except ImportError:
15
20
  click.echo(
16
21
  "Error: hanzo-mcp is not installed. Please run: pip install hanzo[mcp] or pip install hanzo[all]",
hanzo/memory_manager.py CHANGED
@@ -116,7 +116,7 @@ class MemoryManager:
116
116
  try:
117
117
  with open(self.session_file, "r") as f:
118
118
  self.session_context = json.load(f)
119
- except:
119
+ except Exception:
120
120
  self.session_context = {}
121
121
  else:
122
122
  self.session_context = {
hanzo/model_registry.py CHANGED
@@ -6,9 +6,9 @@ eliminating duplication and ensuring consistency across the codebase.
6
6
 
7
7
  from __future__ import annotations
8
8
 
9
- from dataclasses import dataclass, field
10
- from typing import Dict, List, Optional, Set
11
9
  from enum import Enum
10
+ from typing import Set, Dict, List, Optional
11
+ from dataclasses import field, dataclass
12
12
 
13
13
 
14
14
  class ModelProvider(Enum):
hanzo/rate_limiter.py CHANGED
@@ -218,7 +218,7 @@ class ErrorRecovery:
218
218
  if isinstance(e, error_type):
219
219
  try:
220
220
  return await handler(*args, **kwargs)
221
- except:
221
+ except Exception:
222
222
  pass # Fallback failed, continue with retry
223
223
 
224
224
  # Calculate backoff
hanzo/streaming.py CHANGED
@@ -273,7 +273,7 @@ async def stream_with_fallback(message: str, console: Console = None) -> Optiona
273
273
  # Try Ollama streaming
274
274
  try:
275
275
  return await handler.stream_ollama(message)
276
- except:
276
+ except Exception:
277
277
  pass
278
278
 
279
279
  # Fallback to non-streaming with simulated effect
hanzo/ui/__init__.py ADDED
@@ -0,0 +1,13 @@
1
+ """
2
+ Hanzo UI components for CLI.
3
+ """
4
+
5
+ from .startup import show_startup, StartupUI
6
+ from .inline_startup import show_inline_startup, show_status
7
+
8
+ __all__ = [
9
+ "show_startup",
10
+ "StartupUI",
11
+ "show_inline_startup",
12
+ "show_status"
13
+ ]
@@ -0,0 +1,136 @@
1
+ """
2
+ Inline startup notifications for Hanzo commands.
3
+ """
4
+
5
+ import os
6
+ import json
7
+ from pathlib import Path
8
+ from datetime import datetime, timedelta
9
+ from typing import Optional
10
+ from rich.console import Console
11
+ from rich.panel import Panel
12
+ from rich.text import Text
13
+ from rich import box
14
+
15
+ console = Console()
16
+
17
+
18
+ class InlineStartup:
19
+ """Lightweight inline startup notifications."""
20
+
21
+ def __init__(self):
22
+ self.config_dir = Path.home() / ".hanzo"
23
+ self.last_shown_file = self.config_dir / ".last_inline_shown"
24
+ self.show_interval = timedelta(hours=24) # Show once per day
25
+
26
+ def should_show(self) -> bool:
27
+ """Check if we should show inline startup."""
28
+ # Check environment variable
29
+ if os.environ.get("HANZO_NO_STARTUP") == "1":
30
+ return False
31
+
32
+ # Check last shown time
33
+ if self.last_shown_file.exists():
34
+ try:
35
+ last_shown = datetime.fromisoformat(
36
+ self.last_shown_file.read_text().strip()
37
+ )
38
+ if datetime.now() - last_shown < self.show_interval:
39
+ return False
40
+ except:
41
+ pass
42
+
43
+ return True
44
+
45
+ def mark_shown(self):
46
+ """Mark inline startup as shown."""
47
+ self.config_dir.mkdir(exist_ok=True)
48
+ self.last_shown_file.write_text(datetime.now().isoformat())
49
+
50
+ def show_mini(self, command: str = None):
51
+ """Show mini inline startup."""
52
+ if not self.should_show():
53
+ return
54
+
55
+ # Build message
56
+ message = Text()
57
+ message.append("✨ ", style="yellow")
58
+ message.append("Hanzo AI ", style="bold cyan")
59
+ message.append("v0.3.23", style="green")
60
+
61
+ # Add what's new teaser
62
+ message.append(" • ", style="dim")
63
+ message.append("What's new: ", style="dim")
64
+ message.append("Router management, improved docs", style="yellow dim")
65
+
66
+ # Show panel
67
+ console.print(
68
+ Panel(
69
+ message,
70
+ box=box.MINIMAL,
71
+ border_style="cyan",
72
+ padding=(0, 1)
73
+ )
74
+ )
75
+
76
+ self.mark_shown()
77
+
78
+ def show_command_hint(self, command: str):
79
+ """Show command-specific hints."""
80
+ hints = {
81
+ "chat": "💡 Tip: Use --model to change AI model, --router for local proxy",
82
+ "node": "💡 Tip: Run 'hanzo node start' to enable local AI inference",
83
+ "router": "💡 Tip: Router provides unified access to 100+ LLM providers",
84
+ "repl": "💡 Tip: REPL combines Python with AI assistance",
85
+ "agent": "💡 Tip: Agents can work in parallel with 'hanzo agent swarm'"
86
+ }
87
+
88
+ hint = hints.get(command)
89
+ if hint and os.environ.get("HANZO_SHOW_HINTS") != "0":
90
+ console.print(f"[dim]{hint}[/dim]")
91
+
92
+ def show_status_bar(self):
93
+ """Show a compact status bar."""
94
+ items = []
95
+
96
+ # Check router
97
+ try:
98
+ import httpx
99
+ response = httpx.get("http://localhost:4000/health", timeout=0.5)
100
+ if response.status_code == 200:
101
+ items.append("[green]Router ✓[/green]")
102
+ except:
103
+ pass
104
+
105
+ # Check node
106
+ try:
107
+ import httpx
108
+ response = httpx.get("http://localhost:8000/health", timeout=0.5)
109
+ if response.status_code == 200:
110
+ items.append("[green]Node ✓[/green]")
111
+ except:
112
+ pass
113
+
114
+ # Check API key
115
+ if os.environ.get("HANZO_API_KEY"):
116
+ items.append("[green]API ✓[/green]")
117
+ else:
118
+ items.append("[yellow]API ⚠[/yellow]")
119
+
120
+ if items:
121
+ status = " • ".join(items)
122
+ console.print(f"[dim]Status: {status}[/dim]")
123
+
124
+
125
+ def show_inline_startup(command: str = None):
126
+ """Show inline startup notification."""
127
+ startup = InlineStartup()
128
+ startup.show_mini(command)
129
+ if command:
130
+ startup.show_command_hint(command)
131
+
132
+
133
+ def show_status():
134
+ """Show compact status bar."""
135
+ startup = InlineStartup()
136
+ startup.show_status_bar()