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/__init__.py +2 -2
- hanzo/base_agent.py +4 -5
- hanzo/batch_orchestrator.py +11 -11
- hanzo/cli.py +20 -10
- hanzo/commands/auth.py +206 -266
- hanzo/commands/auth_broken.py +377 -0
- hanzo/commands/chat.py +60 -16
- hanzo/commands/{cluster.py → node.py} +128 -128
- hanzo/commands/router.py +152 -0
- hanzo/dev.py +1 -1
- hanzo/fallback_handler.py +1 -1
- hanzo/interactive/enhanced_repl.py +513 -0
- hanzo/interactive/repl.py +54 -34
- hanzo/mcp_server.py +8 -3
- hanzo/memory_manager.py +1 -1
- hanzo/model_registry.py +2 -2
- hanzo/rate_limiter.py +1 -1
- hanzo/streaming.py +1 -1
- hanzo/ui/__init__.py +13 -0
- hanzo/ui/inline_startup.py +136 -0
- hanzo/ui/startup.py +350 -0
- hanzo-0.3.25.dist-info/METADATA +276 -0
- hanzo-0.3.25.dist-info/RECORD +43 -0
- hanzo-0.3.23.dist-info/METADATA +0 -137
- hanzo-0.3.23.dist-info/RECORD +0 -37
- {hanzo-0.3.23.dist-info → hanzo-0.3.25.dist-info}/WHEEL +0 -0
- {hanzo-0.3.23.dist-info → hanzo-0.3.25.dist-info}/entry_points.txt +0 -0
hanzo/ui/startup.py
ADDED
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Hanzo startup UI and changelog integration.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import json
|
|
7
|
+
import time
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Optional, List, Dict, Any
|
|
10
|
+
from datetime import datetime, timedelta
|
|
11
|
+
import httpx
|
|
12
|
+
from rich.console import Console
|
|
13
|
+
from rich.panel import Panel
|
|
14
|
+
from rich.table import Table
|
|
15
|
+
from rich.text import Text
|
|
16
|
+
from rich.align import Align
|
|
17
|
+
from rich.columns import Columns
|
|
18
|
+
from rich.markdown import Markdown
|
|
19
|
+
from rich import box
|
|
20
|
+
|
|
21
|
+
console = Console()
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class StartupUI:
|
|
25
|
+
"""Clean startup UI for Hanzo with changelog integration."""
|
|
26
|
+
|
|
27
|
+
def __init__(self):
|
|
28
|
+
self.config_dir = Path.home() / ".hanzo"
|
|
29
|
+
self.config_file = self.config_dir / "config.json"
|
|
30
|
+
self.changelog_cache = self.config_dir / "changelog_cache.json"
|
|
31
|
+
self.last_shown_file = self.config_dir / ".last_shown_version"
|
|
32
|
+
self.current_version = self._get_current_version()
|
|
33
|
+
|
|
34
|
+
def _get_current_version(self) -> str:
|
|
35
|
+
"""Get current Hanzo version."""
|
|
36
|
+
try:
|
|
37
|
+
from hanzo import __version__
|
|
38
|
+
return __version__
|
|
39
|
+
except:
|
|
40
|
+
return "0.3.23"
|
|
41
|
+
|
|
42
|
+
def _get_last_shown_version(self) -> Optional[str]:
|
|
43
|
+
"""Get the last version shown to user."""
|
|
44
|
+
if self.last_shown_file.exists():
|
|
45
|
+
return self.last_shown_file.read_text().strip()
|
|
46
|
+
return None
|
|
47
|
+
|
|
48
|
+
def _save_last_shown_version(self):
|
|
49
|
+
"""Save current version as last shown."""
|
|
50
|
+
self.config_dir.mkdir(exist_ok=True)
|
|
51
|
+
self.last_shown_file.write_text(self.current_version)
|
|
52
|
+
|
|
53
|
+
def _fetch_changelog(self) -> List[Dict[str, Any]]:
|
|
54
|
+
"""Fetch latest changelog from GitHub."""
|
|
55
|
+
try:
|
|
56
|
+
# Check cache first
|
|
57
|
+
if self.changelog_cache.exists():
|
|
58
|
+
cache_data = json.loads(self.changelog_cache.read_text())
|
|
59
|
+
cache_time = datetime.fromisoformat(cache_data["timestamp"])
|
|
60
|
+
if datetime.now() - cache_time < timedelta(hours=6):
|
|
61
|
+
return cache_data["entries"]
|
|
62
|
+
|
|
63
|
+
# Fetch from GitHub
|
|
64
|
+
response = httpx.get(
|
|
65
|
+
"https://api.github.com/repos/hanzoai/python-sdk/releases",
|
|
66
|
+
headers={"Accept": "application/vnd.github.v3+json"},
|
|
67
|
+
timeout=5
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
if response.status_code == 200:
|
|
71
|
+
releases = response.json()[:5] # Last 5 releases
|
|
72
|
+
entries = []
|
|
73
|
+
|
|
74
|
+
for release in releases:
|
|
75
|
+
entries.append({
|
|
76
|
+
"version": release["tag_name"],
|
|
77
|
+
"date": release["published_at"][:10],
|
|
78
|
+
"highlights": self._parse_highlights(release["body"])
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
# Cache the results
|
|
82
|
+
cache_data = {
|
|
83
|
+
"timestamp": datetime.now().isoformat(),
|
|
84
|
+
"entries": entries
|
|
85
|
+
}
|
|
86
|
+
self.changelog_cache.write_text(json.dumps(cache_data))
|
|
87
|
+
return entries
|
|
88
|
+
|
|
89
|
+
except Exception:
|
|
90
|
+
pass
|
|
91
|
+
|
|
92
|
+
# Fallback to static changelog
|
|
93
|
+
return self._get_static_changelog()
|
|
94
|
+
|
|
95
|
+
def _parse_highlights(self, body: str) -> List[str]:
|
|
96
|
+
"""Parse release highlights from markdown."""
|
|
97
|
+
if not body:
|
|
98
|
+
return []
|
|
99
|
+
|
|
100
|
+
highlights = []
|
|
101
|
+
lines = body.split("\n")
|
|
102
|
+
|
|
103
|
+
for line in lines:
|
|
104
|
+
line = line.strip()
|
|
105
|
+
if line.startswith("- ") or line.startswith("* "):
|
|
106
|
+
highlight = line[2:].strip()
|
|
107
|
+
if len(highlight) > 80:
|
|
108
|
+
highlight = highlight[:77] + "..."
|
|
109
|
+
highlights.append(highlight)
|
|
110
|
+
if len(highlights) >= 3:
|
|
111
|
+
break
|
|
112
|
+
|
|
113
|
+
return highlights
|
|
114
|
+
|
|
115
|
+
def _get_static_changelog(self) -> List[Dict[str, Any]]:
|
|
116
|
+
"""Get static changelog for offline mode."""
|
|
117
|
+
return [
|
|
118
|
+
{
|
|
119
|
+
"version": "v0.3.23",
|
|
120
|
+
"date": "2024-09-06",
|
|
121
|
+
"highlights": [
|
|
122
|
+
"✨ Added router management commands for LLM proxy control",
|
|
123
|
+
"🎯 Renamed cluster to node for better clarity",
|
|
124
|
+
"📚 Comprehensive documentation for all packages"
|
|
125
|
+
]
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"version": "v0.3.22",
|
|
129
|
+
"date": "2024-09-05",
|
|
130
|
+
"highlights": [
|
|
131
|
+
"🚀 Improved MCP tool performance with batch operations",
|
|
132
|
+
"🔧 Fixed file permission handling in Windows",
|
|
133
|
+
"💾 Added memory persistence for conversations"
|
|
134
|
+
]
|
|
135
|
+
}
|
|
136
|
+
]
|
|
137
|
+
|
|
138
|
+
def _create_welcome_panel(self) -> Panel:
|
|
139
|
+
"""Create the welcome panel with branding."""
|
|
140
|
+
# ASCII art logo
|
|
141
|
+
logo = """
|
|
142
|
+
██╗ ██╗ █████╗ ███╗ ██╗███████╗ ██████╗
|
|
143
|
+
██║ ██║██╔══██╗████╗ ██║╚══███╔╝██╔═══██╗
|
|
144
|
+
███████║███████║██╔██╗ ██║ ███╔╝ ██║ ██║
|
|
145
|
+
██╔══██║██╔══██║██║╚██╗██║ ███╔╝ ██║ ██║
|
|
146
|
+
██║ ██║██║ ██║██║ ╚████║███████╗╚██████╔╝
|
|
147
|
+
╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝╚══════╝ ╚═════╝
|
|
148
|
+
"""
|
|
149
|
+
|
|
150
|
+
# Create welcome text
|
|
151
|
+
welcome = Text()
|
|
152
|
+
welcome.append("Welcome to ", style="white")
|
|
153
|
+
welcome.append("Hanzo AI", style="bold cyan")
|
|
154
|
+
welcome.append(" • ", style="dim")
|
|
155
|
+
welcome.append(f"v{self.current_version}", style="green")
|
|
156
|
+
|
|
157
|
+
# Add subtitle
|
|
158
|
+
subtitle = Text("Your AI Infrastructure Platform", style="italic dim")
|
|
159
|
+
|
|
160
|
+
# Combine elements
|
|
161
|
+
content = Align.center(
|
|
162
|
+
Text.from_ansi(logo) + "\n" + welcome + "\n" + subtitle
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
return Panel(
|
|
166
|
+
content,
|
|
167
|
+
box=box.DOUBLE,
|
|
168
|
+
border_style="cyan",
|
|
169
|
+
padding=(1, 2)
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
def _create_whats_new_panel(self) -> Optional[Panel]:
|
|
173
|
+
"""Create What's New panel with recent changes."""
|
|
174
|
+
last_shown = self._get_last_shown_version()
|
|
175
|
+
|
|
176
|
+
# Only show if there's new content
|
|
177
|
+
if last_shown == self.current_version:
|
|
178
|
+
return None
|
|
179
|
+
|
|
180
|
+
changelog = self._fetch_changelog()
|
|
181
|
+
if not changelog:
|
|
182
|
+
return None
|
|
183
|
+
|
|
184
|
+
# Build content
|
|
185
|
+
content = Text()
|
|
186
|
+
content.append("🎉 What's New\n\n", style="bold yellow")
|
|
187
|
+
|
|
188
|
+
for entry in changelog[:2]: # Show last 2 versions
|
|
189
|
+
content.append(f" {entry['version']}", style="bold cyan")
|
|
190
|
+
content.append(f" ({entry['date']})\n", style="dim")
|
|
191
|
+
|
|
192
|
+
for highlight in entry['highlights'][:2]:
|
|
193
|
+
content.append(f" • {highlight}\n", style="white")
|
|
194
|
+
|
|
195
|
+
content.append("\n")
|
|
196
|
+
|
|
197
|
+
return Panel(
|
|
198
|
+
content,
|
|
199
|
+
title="[yellow]Recent Updates[/yellow]",
|
|
200
|
+
box=box.ROUNDED,
|
|
201
|
+
border_style="yellow",
|
|
202
|
+
padding=(0, 1)
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
def _create_quick_start_panel(self) -> Panel:
|
|
206
|
+
"""Create quick start tips panel."""
|
|
207
|
+
tips = [
|
|
208
|
+
("chat", "Start interactive AI chat"),
|
|
209
|
+
("node start", "Run local AI node"),
|
|
210
|
+
("router start", "Start LLM proxy"),
|
|
211
|
+
("repl", "Interactive Python + AI"),
|
|
212
|
+
("help", "Show all commands")
|
|
213
|
+
]
|
|
214
|
+
|
|
215
|
+
# Create table
|
|
216
|
+
table = Table(show_header=False, box=None, padding=(0, 2))
|
|
217
|
+
table.add_column("Command", style="cyan")
|
|
218
|
+
table.add_column("Description", style="dim")
|
|
219
|
+
|
|
220
|
+
for cmd, desc in tips:
|
|
221
|
+
table.add_row(f"hanzo {cmd}", desc)
|
|
222
|
+
|
|
223
|
+
return Panel(
|
|
224
|
+
table,
|
|
225
|
+
title="[green]Quick Start[/green]",
|
|
226
|
+
box=box.ROUNDED,
|
|
227
|
+
border_style="green",
|
|
228
|
+
padding=(0, 1)
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
def _create_status_panel(self) -> Panel:
|
|
232
|
+
"""Create status panel showing system state."""
|
|
233
|
+
items = []
|
|
234
|
+
|
|
235
|
+
# Check router status
|
|
236
|
+
try:
|
|
237
|
+
response = httpx.get("http://localhost:4000/health", timeout=1)
|
|
238
|
+
router_status = "🟢 Running" if response.status_code == 200 else "🔴 Offline"
|
|
239
|
+
except:
|
|
240
|
+
router_status = "⚫ Offline"
|
|
241
|
+
|
|
242
|
+
# Check node status
|
|
243
|
+
try:
|
|
244
|
+
response = httpx.get("http://localhost:8000/health", timeout=1)
|
|
245
|
+
node_status = "🟢 Running" if response.status_code == 200 else "🔴 Offline"
|
|
246
|
+
except:
|
|
247
|
+
node_status = "⚫ Offline"
|
|
248
|
+
|
|
249
|
+
# Check API key
|
|
250
|
+
api_key = os.getenv("HANZO_API_KEY")
|
|
251
|
+
api_status = "🟢 Configured" if api_key else "🟡 Not Set"
|
|
252
|
+
|
|
253
|
+
# Build status text
|
|
254
|
+
status = Text()
|
|
255
|
+
status.append("Router: ", style="bold")
|
|
256
|
+
status.append(f"{router_status} ", style="white")
|
|
257
|
+
status.append("Node: ", style="bold")
|
|
258
|
+
status.append(f"{node_status} ", style="white")
|
|
259
|
+
status.append("API: ", style="bold")
|
|
260
|
+
status.append(api_status, style="white")
|
|
261
|
+
|
|
262
|
+
return Panel(
|
|
263
|
+
Align.center(status),
|
|
264
|
+
box=box.ROUNDED,
|
|
265
|
+
border_style="blue",
|
|
266
|
+
padding=(0, 1)
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
def _check_for_updates(self) -> Optional[str]:
|
|
270
|
+
"""Check if updates are available."""
|
|
271
|
+
try:
|
|
272
|
+
response = httpx.get(
|
|
273
|
+
"https://pypi.org/pypi/hanzo/json",
|
|
274
|
+
timeout=3
|
|
275
|
+
)
|
|
276
|
+
if response.status_code == 200:
|
|
277
|
+
data = response.json()
|
|
278
|
+
latest = data["info"]["version"]
|
|
279
|
+
if latest != self.current_version:
|
|
280
|
+
return latest
|
|
281
|
+
except:
|
|
282
|
+
pass
|
|
283
|
+
return None
|
|
284
|
+
|
|
285
|
+
def show(self, minimal: bool = False):
|
|
286
|
+
"""Display the startup UI."""
|
|
287
|
+
console.clear()
|
|
288
|
+
|
|
289
|
+
if minimal:
|
|
290
|
+
# Minimal mode - just show compact welcome
|
|
291
|
+
console.print(
|
|
292
|
+
Panel(
|
|
293
|
+
f"[bold cyan]Hanzo AI[/bold cyan] • v{self.current_version} • [dim]Type [cyan]hanzo help[/cyan] for commands[/dim]",
|
|
294
|
+
box=box.ROUNDED,
|
|
295
|
+
padding=(0, 1)
|
|
296
|
+
)
|
|
297
|
+
)
|
|
298
|
+
return
|
|
299
|
+
|
|
300
|
+
# Full startup UI
|
|
301
|
+
panels = []
|
|
302
|
+
|
|
303
|
+
# Welcome panel
|
|
304
|
+
welcome = self._create_welcome_panel()
|
|
305
|
+
console.print(welcome)
|
|
306
|
+
|
|
307
|
+
# What's New (if applicable)
|
|
308
|
+
whats_new = self._create_whats_new_panel()
|
|
309
|
+
if whats_new:
|
|
310
|
+
console.print(whats_new)
|
|
311
|
+
self._save_last_shown_version()
|
|
312
|
+
|
|
313
|
+
# Quick start and status in columns
|
|
314
|
+
quick_start = self._create_quick_start_panel()
|
|
315
|
+
status = self._create_status_panel()
|
|
316
|
+
|
|
317
|
+
console.print(Columns([quick_start, status], equal=True, expand=True))
|
|
318
|
+
|
|
319
|
+
# Check for updates
|
|
320
|
+
latest = self._check_for_updates()
|
|
321
|
+
if latest:
|
|
322
|
+
console.print(
|
|
323
|
+
Panel(
|
|
324
|
+
f"[yellow]📦 Update available:[/yellow] v{latest} → Run [cyan]pip install --upgrade hanzo[/cyan]",
|
|
325
|
+
box=box.ROUNDED,
|
|
326
|
+
border_style="yellow",
|
|
327
|
+
padding=(0, 1)
|
|
328
|
+
)
|
|
329
|
+
)
|
|
330
|
+
|
|
331
|
+
# Footer
|
|
332
|
+
console.print(
|
|
333
|
+
Align.center(
|
|
334
|
+
Text("Get started with ", style="dim") +
|
|
335
|
+
Text("hanzo chat", style="bold cyan") +
|
|
336
|
+
Text(" or view docs at ", style="dim") +
|
|
337
|
+
Text("docs.hanzo.ai", style="blue underline")
|
|
338
|
+
)
|
|
339
|
+
)
|
|
340
|
+
console.print()
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
def show_startup(minimal: bool = False):
|
|
344
|
+
"""Show the startup UI."""
|
|
345
|
+
ui = StartupUI()
|
|
346
|
+
ui.show(minimal=minimal)
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
if __name__ == "__main__":
|
|
350
|
+
show_startup()
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hanzo
|
|
3
|
+
Version: 0.3.25
|
|
4
|
+
Summary: Hanzo AI - Complete AI Infrastructure Platform with CLI, Router, MCP, and Agent Runtime
|
|
5
|
+
Project-URL: Homepage, https://hanzo.ai
|
|
6
|
+
Project-URL: Repository, https://github.com/hanzoai/python-sdk
|
|
7
|
+
Project-URL: Documentation, https://docs.hanzo.ai/cli
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/hanzoai/python-sdk/issues
|
|
9
|
+
Author-email: Hanzo AI <dev@hanzo.ai>
|
|
10
|
+
Keywords: agents,ai,cli,hanzo,llm,local-ai,mcp,private-ai
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Requires-Dist: anthropic>=0.25.0
|
|
24
|
+
Requires-Dist: click>=8.1.0
|
|
25
|
+
Requires-Dist: httpx>=0.23.0
|
|
26
|
+
Requires-Dist: openai>=1.0.0
|
|
27
|
+
Requires-Dist: prompt-toolkit>=3.0.0
|
|
28
|
+
Requires-Dist: pydantic>=2.0.0
|
|
29
|
+
Requires-Dist: pyyaml>=6.0
|
|
30
|
+
Requires-Dist: rich>=13.0.0
|
|
31
|
+
Requires-Dist: typer>=0.9.0
|
|
32
|
+
Provides-Extra: agents
|
|
33
|
+
Requires-Dist: hanzo-agents>=0.1.0; extra == 'agents'
|
|
34
|
+
Requires-Dist: hanzo-network>=0.1.3; extra == 'agents'
|
|
35
|
+
Provides-Extra: ai
|
|
36
|
+
Requires-Dist: hanzoai>=1.0.0; extra == 'ai'
|
|
37
|
+
Provides-Extra: all
|
|
38
|
+
Requires-Dist: hanzo-aci>=0.2.8; extra == 'all'
|
|
39
|
+
Requires-Dist: hanzo-agents>=0.1.0; extra == 'all'
|
|
40
|
+
Requires-Dist: hanzo-mcp>=0.7.0; extra == 'all'
|
|
41
|
+
Requires-Dist: hanzo-memory>=1.0.0; extra == 'all'
|
|
42
|
+
Requires-Dist: hanzo-network>=0.1.3; extra == 'all'
|
|
43
|
+
Requires-Dist: hanzo-repl>=0.1.0; extra == 'all'
|
|
44
|
+
Requires-Dist: hanzoai>=1.0.0; extra == 'all'
|
|
45
|
+
Provides-Extra: dev
|
|
46
|
+
Requires-Dist: hanzo-aci>=0.2.8; extra == 'dev'
|
|
47
|
+
Provides-Extra: mcp
|
|
48
|
+
Requires-Dist: hanzo-mcp>=0.7.0; extra == 'mcp'
|
|
49
|
+
Provides-Extra: repl
|
|
50
|
+
Requires-Dist: hanzo-repl>=0.1.0; extra == 'repl'
|
|
51
|
+
Provides-Extra: router
|
|
52
|
+
Description-Content-Type: text/markdown
|
|
53
|
+
|
|
54
|
+
# Hanzo CLI and Orchestration Tools
|
|
55
|
+
|
|
56
|
+
[](https://pypi.org/project/hanzo/)
|
|
57
|
+
[](https://pypi.org/project/hanzo/)
|
|
58
|
+
|
|
59
|
+
Core CLI and orchestration tools for the Hanzo AI platform.
|
|
60
|
+
|
|
61
|
+
## Installation
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
pip install hanzo
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Features
|
|
68
|
+
|
|
69
|
+
- **Interactive Chat**: Chat with AI models through CLI
|
|
70
|
+
- **Node Management**: Run local AI inference nodes
|
|
71
|
+
- **Router Control**: Manage LLM proxy router
|
|
72
|
+
- **REPL Interface**: Interactive Python REPL with AI
|
|
73
|
+
- **Batch Orchestration**: Orchestrate multiple AI tasks
|
|
74
|
+
- **Memory Management**: Persistent conversation memory
|
|
75
|
+
|
|
76
|
+
## Usage
|
|
77
|
+
|
|
78
|
+
### CLI Commands
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
# Interactive chat
|
|
82
|
+
hanzo chat
|
|
83
|
+
|
|
84
|
+
# Use specific model
|
|
85
|
+
hanzo chat --model gpt-4
|
|
86
|
+
|
|
87
|
+
# Use router (local proxy)
|
|
88
|
+
hanzo chat --router
|
|
89
|
+
|
|
90
|
+
# Use cloud API
|
|
91
|
+
hanzo chat --cloud
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Node Management
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
# Start local node
|
|
98
|
+
hanzo node start
|
|
99
|
+
|
|
100
|
+
# Check status
|
|
101
|
+
hanzo node status
|
|
102
|
+
|
|
103
|
+
# List available models
|
|
104
|
+
hanzo node models
|
|
105
|
+
|
|
106
|
+
# Load specific model
|
|
107
|
+
hanzo node load llama2:7b
|
|
108
|
+
|
|
109
|
+
# Stop node
|
|
110
|
+
hanzo node stop
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Router Management
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
# Start router proxy
|
|
117
|
+
hanzo router start
|
|
118
|
+
|
|
119
|
+
# Check router status
|
|
120
|
+
hanzo router status
|
|
121
|
+
|
|
122
|
+
# List available models
|
|
123
|
+
hanzo router models
|
|
124
|
+
|
|
125
|
+
# View configuration
|
|
126
|
+
hanzo router config
|
|
127
|
+
|
|
128
|
+
# Stop router
|
|
129
|
+
hanzo router stop
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Interactive REPL
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
# Start REPL
|
|
136
|
+
hanzo repl
|
|
137
|
+
|
|
138
|
+
# In REPL:
|
|
139
|
+
> /help # Show help
|
|
140
|
+
> /models # List models
|
|
141
|
+
> /model gpt-4 # Switch model
|
|
142
|
+
> /clear # Clear context
|
|
143
|
+
> What is Python? # Ask questions
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Python API
|
|
147
|
+
|
|
148
|
+
### Batch Orchestration
|
|
149
|
+
|
|
150
|
+
```python
|
|
151
|
+
from hanzo.batch_orchestrator import BatchOrchestrator
|
|
152
|
+
|
|
153
|
+
orchestrator = BatchOrchestrator()
|
|
154
|
+
results = await orchestrator.run_batch([
|
|
155
|
+
"Summarize quantum computing",
|
|
156
|
+
"Explain machine learning",
|
|
157
|
+
"Define artificial intelligence"
|
|
158
|
+
])
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Memory Management
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
from hanzo.memory_manager import MemoryManager
|
|
165
|
+
|
|
166
|
+
memory = MemoryManager()
|
|
167
|
+
memory.add_to_context("user", "What is Python?")
|
|
168
|
+
memory.add_to_context("assistant", "Python is...")
|
|
169
|
+
context = memory.get_context()
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Fallback Handling
|
|
173
|
+
|
|
174
|
+
```python
|
|
175
|
+
from hanzo.fallback_handler import FallbackHandler
|
|
176
|
+
|
|
177
|
+
handler = FallbackHandler()
|
|
178
|
+
result = await handler.handle_with_fallback(
|
|
179
|
+
primary_fn=api_call,
|
|
180
|
+
fallback_fn=local_inference
|
|
181
|
+
)
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Configuration
|
|
185
|
+
|
|
186
|
+
### Environment Variables
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
# API settings
|
|
190
|
+
HANZO_API_KEY=your-api-key
|
|
191
|
+
HANZO_BASE_URL=https://api.hanzo.ai
|
|
192
|
+
|
|
193
|
+
# Router settings
|
|
194
|
+
HANZO_ROUTER_URL=http://localhost:4000/v1
|
|
195
|
+
|
|
196
|
+
# Node settings
|
|
197
|
+
HANZO_NODE_URL=http://localhost:8000/v1
|
|
198
|
+
HANZO_NODE_WORKERS=4
|
|
199
|
+
|
|
200
|
+
# Model preferences
|
|
201
|
+
HANZO_DEFAULT_MODEL=gpt-4
|
|
202
|
+
HANZO_FALLBACK_MODEL=llama2:7b
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Configuration File
|
|
206
|
+
|
|
207
|
+
Create `~/.hanzo/config.yaml`:
|
|
208
|
+
|
|
209
|
+
```yaml
|
|
210
|
+
api:
|
|
211
|
+
key: your-api-key
|
|
212
|
+
base_url: https://api.hanzo.ai
|
|
213
|
+
|
|
214
|
+
router:
|
|
215
|
+
url: http://localhost:4000/v1
|
|
216
|
+
auto_start: true
|
|
217
|
+
|
|
218
|
+
node:
|
|
219
|
+
url: http://localhost:8000/v1
|
|
220
|
+
workers: 4
|
|
221
|
+
models:
|
|
222
|
+
- llama2:7b
|
|
223
|
+
- mistral:7b
|
|
224
|
+
|
|
225
|
+
models:
|
|
226
|
+
default: gpt-4
|
|
227
|
+
fallback: llama2:7b
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## Architecture
|
|
231
|
+
|
|
232
|
+
### Components
|
|
233
|
+
|
|
234
|
+
- **CLI**: Command-line interface (`cli.py`)
|
|
235
|
+
- **Chat**: Interactive chat interface (`commands/chat.py`)
|
|
236
|
+
- **Node**: Local AI node management (`commands/node.py`)
|
|
237
|
+
- **Router**: LLM proxy management (`commands/router.py`)
|
|
238
|
+
- **REPL**: Interactive Python REPL (`interactive/repl.py`)
|
|
239
|
+
- **Orchestrator**: Batch task orchestration (`batch_orchestrator.py`)
|
|
240
|
+
- **Memory**: Conversation memory (`memory_manager.py`)
|
|
241
|
+
- **Fallback**: Resilient API handling (`fallback_handler.py`)
|
|
242
|
+
|
|
243
|
+
### Port Allocation
|
|
244
|
+
|
|
245
|
+
- **4000**: Router (LLM proxy)
|
|
246
|
+
- **8000**: Node (local AI)
|
|
247
|
+
- **9550-9553**: Desktop app integration
|
|
248
|
+
|
|
249
|
+
## Development
|
|
250
|
+
|
|
251
|
+
### Setup
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
cd pkg/hanzo
|
|
255
|
+
uv sync --all-extras
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Testing
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
# Run tests
|
|
262
|
+
pytest tests/
|
|
263
|
+
|
|
264
|
+
# With coverage
|
|
265
|
+
pytest tests/ --cov=hanzo
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### Building
|
|
269
|
+
|
|
270
|
+
```bash
|
|
271
|
+
uv build
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
## License
|
|
275
|
+
|
|
276
|
+
Apache License 2.0
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
hanzo/__init__.py,sha256=wyqd5nRy826-cL9Mow11ZIJKjPWDFHpltYUhi9M7Gqw,185
|
|
2
|
+
hanzo/__main__.py,sha256=F3Vz0Ty3bdAj_8oxyETMIqxlmNRnJOAFB1XPxbyfouI,105
|
|
3
|
+
hanzo/base_agent.py,sha256=ojPaSgFETYl7iARWnNpg8eyAt7sg8eKhn9xZThyvxRA,15324
|
|
4
|
+
hanzo/batch_orchestrator.py,sha256=vn6n5i9gTfZ4DtowFDd5iWgYKjgNTioIomkffKbipSM,35827
|
|
5
|
+
hanzo/cli.py,sha256=Iy39fmgN6kgq64tIXGcX3CPQVyDopg2Yatal9MRdKF0,19050
|
|
6
|
+
hanzo/dev.py,sha256=7EnQL8mfCmjHCAKlriSpg4VueipilEtLrPpWNSDOW8Q,105817
|
|
7
|
+
hanzo/fallback_handler.py,sha256=-OoUeF-ACjb1mZ86tKJLFuEttRa2pjBEHJY9a9IlOK4,10191
|
|
8
|
+
hanzo/mcp_server.py,sha256=wgTJen1z1g1T1_OxV2tsmlupBK5rBeFXTgQaUjaGiyY,655
|
|
9
|
+
hanzo/memory_manager.py,sha256=uhNE1Wt8dcArE-wZkvK9Os-_AOCTmE8hfZw_KfxqZbY,14893
|
|
10
|
+
hanzo/model_registry.py,sha256=cEO5kb_rpoTbZGK_5TeXCmhDhd1hZuF8H9YQi03jF6A,11921
|
|
11
|
+
hanzo/orchestrator_config.py,sha256=JV7DS8aVZwBJ9XzgkQronFwV_A50QyXG3MH_pKwmCB8,11006
|
|
12
|
+
hanzo/rate_limiter.py,sha256=8G9-uGMk8Y9Zun41mgnAV3zO5BjB739EbIDRKcxA6sg,10868
|
|
13
|
+
hanzo/repl.py,sha256=sW1quuqGkJ_AqgjN2vLNdtWgKDlXIkXiO9Bo1QQI0G4,1089
|
|
14
|
+
hanzo/streaming.py,sha256=HRMA3x-GnF31oGgQRkbB7D1uculVoJci2DChuBWGN9Q,10219
|
|
15
|
+
hanzo/commands/__init__.py,sha256=7rh94TPNhdq4gJBJS0Ayf0fGNChQYCQCJcJPmYYehiQ,182
|
|
16
|
+
hanzo/commands/agent.py,sha256=DXCfuxHfmC90IoIOL6BJyp7h2yNUo-VIxrfl4OMh8CU,3480
|
|
17
|
+
hanzo/commands/auth.py,sha256=SvC47tns2pSiR1I5swAceXoRgXgHG9R94-0Ycj9yCdU,8799
|
|
18
|
+
hanzo/commands/auth_broken.py,sha256=aNNAyTkoh8-el2_BbcHEvfdBNOer_3b_RXQoprWTs2w,12754
|
|
19
|
+
hanzo/commands/chat.py,sha256=HCu_Ha4PX3khK18ily6Yv-uC6tQyEdu15EAkpK_0STQ,8747
|
|
20
|
+
hanzo/commands/config.py,sha256=xAzM6n9GhdVIqtn7JrHfLRzj1sshmxCujo7iet2hHqE,7490
|
|
21
|
+
hanzo/commands/mcp.py,sha256=u1uEKDY6gUIa7VymEnRzy0ZphdIKYoNwPSeffZaiKnk,7418
|
|
22
|
+
hanzo/commands/miner.py,sha256=_mZT9nQcT2QSSxI0rDDKuSBVdsg_uE_N_j3PXOHoj-Q,11677
|
|
23
|
+
hanzo/commands/network.py,sha256=wJDxGIxJqc6FzQhbAn0Mw-WGCPUeCOsxmdU6GCmOhgM,11408
|
|
24
|
+
hanzo/commands/node.py,sha256=vzSbcm2-cO1-AZqPSA50t8nQUcnWQUCPT7UneD7HWIM,15402
|
|
25
|
+
hanzo/commands/repl.py,sha256=Frc7tVTThFz0M_vwyA-m4pmfGDUr0WZGsxdu6g0ylNU,6081
|
|
26
|
+
hanzo/commands/router.py,sha256=kB8snUM82cFk3znjFvs3jOJGqv5giKn8DiTkdbXnWYU,5332
|
|
27
|
+
hanzo/commands/tools.py,sha256=fG27wRweVmaFJowBpmwp5PgkRUtIF8bIlu_hGWr69Ss,10393
|
|
28
|
+
hanzo/interactive/__init__.py,sha256=ENHkGOqu-JYI05lqoOKDczJGl96oq6nM476EPhflAbI,74
|
|
29
|
+
hanzo/interactive/dashboard.py,sha256=XB5H_PMlReriCip-wW9iuUiJQOAtSATFG8EyhhFhItU,3842
|
|
30
|
+
hanzo/interactive/enhanced_repl.py,sha256=ZyrP22gvOGE6J3rOboW19RwAZXVid6YYns9rzNbSV4c,17952
|
|
31
|
+
hanzo/interactive/repl.py,sha256=PXpRw1Cfqdqy1pQsKLqz9AwKJBFZ_Y758MpDlJIb9ao,6938
|
|
32
|
+
hanzo/router/__init__.py,sha256=_cRG9nHC_wwq17iVYZSUNBYiJDdByfLDVEuIQn5-ePM,978
|
|
33
|
+
hanzo/ui/__init__.py,sha256=Ea22ereOm5Y0DDfyonA6qsO9Qkzofzd1CUE-VGW2lqw,241
|
|
34
|
+
hanzo/ui/inline_startup.py,sha256=7Y5dwqzt-L1J0F9peyqJ8XZgjHSua2nkItDTrLlBnhU,4265
|
|
35
|
+
hanzo/ui/startup.py,sha256=s7gP1QleQEIoCS1K0XBY7d6aufnwhicRLZDL7ej8ZZY,12235
|
|
36
|
+
hanzo/utils/__init__.py,sha256=5RRwKI852vp8smr4xCRgeKfn7dLEnHbdXGfVYTZ5jDQ,69
|
|
37
|
+
hanzo/utils/config.py,sha256=FD_LoBpcoF5dgJ7WL4o6LDp2pdOy8kS-dJ6iRO2GcGM,4728
|
|
38
|
+
hanzo/utils/net_check.py,sha256=YFbJ65SzfDYHkHLZe3n51VhId1VI3zhyx8p6BM-l6jE,3017
|
|
39
|
+
hanzo/utils/output.py,sha256=W0j3psF07vJiX4s02gbN4zYWfbKNsb8TSIoagBSf5vA,2704
|
|
40
|
+
hanzo-0.3.25.dist-info/METADATA,sha256=QyybsQ7W3TJVStEaHWs3ZYMEHiVeCndtsBqlsLge9Ck,6061
|
|
41
|
+
hanzo-0.3.25.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
42
|
+
hanzo-0.3.25.dist-info/entry_points.txt,sha256=pQLPMdqOXU_2BfTcMDhkqTCDNk_H6ApvYuSaWcuQOOw,171
|
|
43
|
+
hanzo-0.3.25.dist-info/RECORD,,
|