hanzo 0.3.22__py3-none-any.whl → 0.3.24__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/base_agent.py +516 -0
- hanzo/batch_orchestrator.py +988 -0
- hanzo/cli.py +7 -5
- hanzo/commands/chat.py +57 -16
- hanzo/commands/{cluster.py → node.py} +128 -128
- hanzo/commands/repl.py +5 -2
- hanzo/commands/router.py +152 -0
- hanzo/dev.py +407 -249
- hanzo/fallback_handler.py +79 -53
- hanzo/interactive/repl.py +52 -32
- hanzo/mcp_server.py +8 -3
- hanzo/memory_manager.py +146 -123
- hanzo/model_registry.py +399 -0
- hanzo/rate_limiter.py +60 -75
- hanzo/streaming.py +92 -71
- hanzo-0.3.24.dist-info/METADATA +276 -0
- {hanzo-0.3.22.dist-info → hanzo-0.3.24.dist-info}/RECORD +19 -15
- hanzo-0.3.22.dist-info/METADATA +0 -137
- {hanzo-0.3.22.dist-info → hanzo-0.3.24.dist-info}/WHEEL +0 -0
- {hanzo-0.3.22.dist-info → hanzo-0.3.24.dist-info}/entry_points.txt +0 -0
hanzo/commands/router.py
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"""Router command for starting Hanzo router proxy."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
import subprocess
|
|
6
|
+
from typing import Optional
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
import click
|
|
10
|
+
|
|
11
|
+
from ..utils.output import console
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@click.group(name="router")
|
|
15
|
+
def router_group():
|
|
16
|
+
"""Manage Hanzo router (LLM proxy)."""
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@router_group.command(name="start")
|
|
21
|
+
@click.option("--port", "-p", default=4000, help="Port to run router on")
|
|
22
|
+
@click.option("--config", "-c", help="Config file path")
|
|
23
|
+
@click.option("--detach", "-d", is_flag=True, help="Run in background")
|
|
24
|
+
@click.pass_context
|
|
25
|
+
def start_router(ctx, port: int, config: Optional[str], detach: bool):
|
|
26
|
+
"""Start the Hanzo router proxy server."""
|
|
27
|
+
# Find router directory
|
|
28
|
+
router_paths = [
|
|
29
|
+
Path.home() / "work" / "hanzo" / "router",
|
|
30
|
+
Path.home() / "hanzo" / "router",
|
|
31
|
+
Path.cwd().parent / "router",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
router_dir = None
|
|
35
|
+
for path in router_paths:
|
|
36
|
+
if path.exists() and (path / "litellm" / "proxy" / "proxy_server.py").exists():
|
|
37
|
+
router_dir = path
|
|
38
|
+
break
|
|
39
|
+
|
|
40
|
+
if not router_dir:
|
|
41
|
+
console.print("[red]Error:[/red] Hanzo router not found")
|
|
42
|
+
console.print("\nPlease clone the router:")
|
|
43
|
+
console.print(" git clone https://github.com/hanzoai/router.git ~/work/hanzo/router")
|
|
44
|
+
return
|
|
45
|
+
|
|
46
|
+
console.print(f"[green]✓[/green] Found router at {router_dir}")
|
|
47
|
+
|
|
48
|
+
# Prepare environment
|
|
49
|
+
env = os.environ.copy()
|
|
50
|
+
env["PYTHONPATH"] = str(router_dir) + ":" + env.get("PYTHONPATH", "")
|
|
51
|
+
|
|
52
|
+
# Build command
|
|
53
|
+
cmd = [
|
|
54
|
+
sys.executable,
|
|
55
|
+
"-m", "litellm.proxy.proxy_server",
|
|
56
|
+
"--port", str(port),
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
if config:
|
|
60
|
+
# Use provided config
|
|
61
|
+
config_path = Path(config)
|
|
62
|
+
if not config_path.exists():
|
|
63
|
+
console.print(f"[red]Error:[/red] Config file not found: {config}")
|
|
64
|
+
return
|
|
65
|
+
cmd.extend(["--config", str(config_path)])
|
|
66
|
+
else:
|
|
67
|
+
# Check for default config
|
|
68
|
+
default_config = router_dir / "config.yaml"
|
|
69
|
+
if default_config.exists():
|
|
70
|
+
cmd.extend(["--config", str(default_config)])
|
|
71
|
+
console.print(f"[dim]Using config: {default_config}[/dim]")
|
|
72
|
+
|
|
73
|
+
console.print(f"\n[bold cyan]Starting Hanzo Router on port {port}[/bold cyan]")
|
|
74
|
+
console.print(f"API endpoint: http://localhost:{port}/v1")
|
|
75
|
+
console.print("\nPress Ctrl+C to stop\n")
|
|
76
|
+
|
|
77
|
+
try:
|
|
78
|
+
# Change to router directory and run
|
|
79
|
+
os.chdir(router_dir)
|
|
80
|
+
|
|
81
|
+
if detach:
|
|
82
|
+
# Run in background
|
|
83
|
+
process = subprocess.Popen(
|
|
84
|
+
cmd,
|
|
85
|
+
env=env,
|
|
86
|
+
stdout=subprocess.DEVNULL,
|
|
87
|
+
stderr=subprocess.DEVNULL,
|
|
88
|
+
start_new_session=True
|
|
89
|
+
)
|
|
90
|
+
console.print(f"[green]✓[/green] Router started in background (PID: {process.pid})")
|
|
91
|
+
console.print(f"Check status: curl http://localhost:{port}/health")
|
|
92
|
+
else:
|
|
93
|
+
# Run in foreground
|
|
94
|
+
subprocess.run(cmd, env=env)
|
|
95
|
+
except KeyboardInterrupt:
|
|
96
|
+
console.print("\n[yellow]Router stopped[/yellow]")
|
|
97
|
+
except Exception as e:
|
|
98
|
+
console.print(f"[red]Error starting router: {e}[/red]")
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
@router_group.command(name="stop")
|
|
102
|
+
@click.option("--port", "-p", default=4000, help="Port router is running on")
|
|
103
|
+
def stop_router(port: int):
|
|
104
|
+
"""Stop the router."""
|
|
105
|
+
import signal
|
|
106
|
+
|
|
107
|
+
import psutil
|
|
108
|
+
|
|
109
|
+
found = False
|
|
110
|
+
for proc in psutil.process_iter(['pid', 'cmdline']):
|
|
111
|
+
try:
|
|
112
|
+
cmdline = proc.info['cmdline']
|
|
113
|
+
if cmdline and 'proxy_server' in ' '.join(cmdline) and str(port) in ' '.join(cmdline):
|
|
114
|
+
console.print(f"[yellow]Stopping router (PID: {proc.info['pid']})[/yellow]")
|
|
115
|
+
proc.send_signal(signal.SIGTERM)
|
|
116
|
+
proc.wait(timeout=5)
|
|
117
|
+
found = True
|
|
118
|
+
console.print("[green]✓[/green] Router stopped")
|
|
119
|
+
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.TimeoutExpired):
|
|
120
|
+
continue
|
|
121
|
+
|
|
122
|
+
if not found:
|
|
123
|
+
console.print(f"[yellow]No router found on port {port}[/yellow]")
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
@router_group.command(name="status")
|
|
127
|
+
@click.option("--port", "-p", default=4000, help="Port to check")
|
|
128
|
+
def router_status(port: int):
|
|
129
|
+
"""Check router status."""
|
|
130
|
+
import httpx
|
|
131
|
+
|
|
132
|
+
try:
|
|
133
|
+
response = httpx.get(f"http://localhost:{port}/health", timeout=2.0)
|
|
134
|
+
if response.status_code == 200:
|
|
135
|
+
console.print(f"[green]✓[/green] Router is running on port {port}")
|
|
136
|
+
|
|
137
|
+
# Try to get models
|
|
138
|
+
try:
|
|
139
|
+
models_response = httpx.get(f"http://localhost:{port}/models", timeout=2.0)
|
|
140
|
+
if models_response.status_code == 200:
|
|
141
|
+
data = models_response.json()
|
|
142
|
+
if "data" in data:
|
|
143
|
+
console.print(f"Available models: {len(data['data'])}")
|
|
144
|
+
except Exception:
|
|
145
|
+
pass
|
|
146
|
+
else:
|
|
147
|
+
console.print(f"[yellow]Router responding but unhealthy (status: {response.status_code})[/yellow]")
|
|
148
|
+
except httpx.ConnectError:
|
|
149
|
+
console.print(f"[red]Router not running on port {port}[/red]")
|
|
150
|
+
console.print("\nStart with: hanzo router start")
|
|
151
|
+
except Exception as e:
|
|
152
|
+
console.print(f"[red]Error checking router: {e}[/red]")
|