hanzo 0.3.6__py3-none-any.whl → 0.3.8__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 +1 -1
- hanzo/__main__.py +1 -1
- hanzo/cli.py +86 -52
- hanzo/commands/__init__.py +12 -1
- hanzo/commands/agent.py +18 -21
- hanzo/commands/auth.py +63 -59
- hanzo/commands/chat.py +54 -35
- hanzo/commands/cluster.py +109 -78
- hanzo/commands/config.py +39 -38
- hanzo/commands/mcp.py +63 -42
- hanzo/commands/miner.py +71 -58
- hanzo/commands/network.py +64 -55
- hanzo/commands/repl.py +37 -30
- hanzo/commands/tools.py +52 -67
- hanzo/interactive/__init__.py +1 -1
- hanzo/interactive/dashboard.py +34 -44
- hanzo/interactive/repl.py +35 -32
- hanzo/mcp_server.py +7 -2
- hanzo/repl.py +13 -3
- hanzo/router/__init__.py +21 -9
- hanzo/utils/__init__.py +1 -1
- hanzo/utils/config.py +37 -35
- hanzo/utils/net_check.py +33 -29
- hanzo/utils/output.py +23 -18
- hanzo-0.3.8.dist-info/METADATA +138 -0
- hanzo-0.3.8.dist-info/RECORD +28 -0
- {hanzo-0.3.6.dist-info → hanzo-0.3.8.dist-info}/WHEEL +1 -2
- hanzo-0.3.8.dist-info/entry_points.txt +6 -0
- hanzo-0.3.6.dist-info/METADATA +0 -76
- hanzo-0.3.6.dist-info/RECORD +0 -29
- hanzo-0.3.6.dist-info/entry_points.txt +0 -2
- hanzo-0.3.6.dist-info/top_level.txt +0 -1
hanzo/__init__.py
CHANGED
hanzo/__main__.py
CHANGED
hanzo/cli.py
CHANGED
|
@@ -1,15 +1,26 @@
|
|
|
1
1
|
"""Main CLI entry point for Hanzo."""
|
|
2
2
|
|
|
3
|
-
import asyncio
|
|
4
3
|
import sys
|
|
4
|
+
import asyncio
|
|
5
5
|
from typing import Optional
|
|
6
6
|
|
|
7
7
|
import click
|
|
8
8
|
from rich.console import Console
|
|
9
9
|
|
|
10
|
-
from .commands import
|
|
11
|
-
|
|
10
|
+
from .commands import (
|
|
11
|
+
mcp,
|
|
12
|
+
auth,
|
|
13
|
+
chat,
|
|
14
|
+
repl,
|
|
15
|
+
agent,
|
|
16
|
+
miner,
|
|
17
|
+
tools,
|
|
18
|
+
config,
|
|
19
|
+
cluster,
|
|
20
|
+
network,
|
|
21
|
+
)
|
|
12
22
|
from .utils.output import console
|
|
23
|
+
from .interactive.repl import HanzoREPL
|
|
13
24
|
|
|
14
25
|
# Version
|
|
15
26
|
__version__ = "0.2.10"
|
|
@@ -23,7 +34,7 @@ __version__ = "0.2.10"
|
|
|
23
34
|
@click.pass_context
|
|
24
35
|
def cli(ctx, verbose: bool, json: bool, config: Optional[str]):
|
|
25
36
|
"""Hanzo AI - Unified CLI for local, private, and free AI.
|
|
26
|
-
|
|
37
|
+
|
|
27
38
|
Run without arguments to enter interactive mode.
|
|
28
39
|
"""
|
|
29
40
|
# Ensure context object exists
|
|
@@ -32,14 +43,15 @@ def cli(ctx, verbose: bool, json: bool, config: Optional[str]):
|
|
|
32
43
|
ctx.obj["json"] = json
|
|
33
44
|
ctx.obj["config"] = config
|
|
34
45
|
ctx.obj["console"] = console
|
|
35
|
-
|
|
46
|
+
|
|
36
47
|
# If no subcommand, enter interactive mode or start compute node
|
|
37
48
|
if ctx.invoked_subcommand is None:
|
|
38
49
|
# Check if we should start as a compute node
|
|
39
50
|
import os
|
|
51
|
+
|
|
40
52
|
if os.environ.get("HANZO_COMPUTE_NODE") == "1":
|
|
41
53
|
# Start as a compute node
|
|
42
|
-
|
|
54
|
+
|
|
43
55
|
asyncio.run(start_compute_node(ctx))
|
|
44
56
|
else:
|
|
45
57
|
# Enter interactive REPL mode
|
|
@@ -90,43 +102,60 @@ def serve(ctx, name: str, port: int):
|
|
|
90
102
|
|
|
91
103
|
@cli.command()
|
|
92
104
|
@click.option("--name", "-n", help="Node name (auto-generated if not provided)")
|
|
93
|
-
@click.option(
|
|
94
|
-
|
|
95
|
-
|
|
105
|
+
@click.option(
|
|
106
|
+
"--port", "-p", default=52415, help="Node port (default: 52415 for hanzo/net)"
|
|
107
|
+
)
|
|
108
|
+
@click.option(
|
|
109
|
+
"--network", default="local", help="Network to join (mainnet/testnet/local)"
|
|
110
|
+
)
|
|
111
|
+
@click.option(
|
|
112
|
+
"--models", "-m", multiple=True, help="Models to serve (e.g., llama-3.2-3b)"
|
|
113
|
+
)
|
|
96
114
|
@click.option("--max-jobs", type=int, default=10, help="Max concurrent jobs")
|
|
97
115
|
@click.pass_context
|
|
98
116
|
def net(ctx, name: str, port: int, network: str, models: tuple, max_jobs: int):
|
|
99
117
|
"""Start the Hanzo Network distributed AI compute node."""
|
|
100
|
-
start_compute_node(ctx, name, port, network, models, max_jobs)
|
|
118
|
+
asyncio.run(start_compute_node(ctx, name, port, network, models, max_jobs))
|
|
101
119
|
|
|
102
120
|
|
|
103
121
|
@cli.command()
|
|
104
122
|
@click.option("--name", "-n", help="Node name (auto-generated if not provided)")
|
|
105
|
-
@click.option(
|
|
106
|
-
|
|
107
|
-
|
|
123
|
+
@click.option(
|
|
124
|
+
"--port", "-p", default=52415, help="Node port (default: 52415 for hanzo/net)"
|
|
125
|
+
)
|
|
126
|
+
@click.option(
|
|
127
|
+
"--network", default="local", help="Network to join (mainnet/testnet/local)"
|
|
128
|
+
)
|
|
129
|
+
@click.option(
|
|
130
|
+
"--models", "-m", multiple=True, help="Models to serve (e.g., llama-3.2-3b)"
|
|
131
|
+
)
|
|
108
132
|
@click.option("--max-jobs", type=int, default=10, help="Max concurrent jobs")
|
|
109
133
|
@click.pass_context
|
|
110
134
|
def node(ctx, name: str, port: int, network: str, models: tuple, max_jobs: int):
|
|
111
135
|
"""Alias for 'hanzo net' - Start as a compute node for the Hanzo network."""
|
|
112
|
-
start_compute_node(ctx, name, port, network, models, max_jobs)
|
|
136
|
+
asyncio.run(start_compute_node(ctx, name, port, network, models, max_jobs))
|
|
113
137
|
|
|
114
138
|
|
|
115
|
-
def start_compute_node(
|
|
116
|
-
|
|
117
|
-
|
|
139
|
+
async def start_compute_node(
|
|
140
|
+
ctx,
|
|
141
|
+
name: str = None,
|
|
142
|
+
port: int = 52415,
|
|
143
|
+
network: str = "mainnet",
|
|
144
|
+
models: tuple = None,
|
|
145
|
+
max_jobs: int = 10,
|
|
146
|
+
):
|
|
118
147
|
"""Start this instance as a compute node using hanzo/net."""
|
|
119
|
-
from .utils.net_check import check_net_installation
|
|
120
|
-
|
|
148
|
+
from .utils.net_check import check_net_installation
|
|
149
|
+
|
|
121
150
|
console = ctx.obj.get("console", Console())
|
|
122
|
-
|
|
151
|
+
|
|
123
152
|
console.print("[bold cyan]Starting Hanzo Net Compute Node[/bold cyan]")
|
|
124
153
|
console.print(f"Network: {network}")
|
|
125
154
|
console.print(f"Port: {port}")
|
|
126
|
-
|
|
155
|
+
|
|
127
156
|
# Check hanzo/net availability
|
|
128
157
|
is_available, net_path, python_exe = check_net_installation()
|
|
129
|
-
|
|
158
|
+
|
|
130
159
|
if not is_available:
|
|
131
160
|
console.print("[red]Error:[/red] hanzo-net is not installed")
|
|
132
161
|
console.print("\nTo install hanzo-net from PyPI:")
|
|
@@ -135,23 +164,23 @@ def start_compute_node(ctx, name: str = None, port: int = 52415,
|
|
|
135
164
|
console.print(" git clone https://github.com/hanzoai/net.git ~/work/hanzo/net")
|
|
136
165
|
console.print(" cd ~/work/hanzo/net && pip install -e .")
|
|
137
166
|
return
|
|
138
|
-
|
|
167
|
+
|
|
139
168
|
try:
|
|
140
|
-
import subprocess
|
|
141
|
-
import sys
|
|
142
169
|
import os
|
|
143
|
-
|
|
170
|
+
import sys
|
|
171
|
+
import subprocess
|
|
172
|
+
|
|
144
173
|
# Use the checked net_path and python_exe
|
|
145
174
|
if not net_path:
|
|
146
175
|
# net is installed as a package
|
|
147
176
|
console.print("[green]✓[/green] Using installed hanzo/net")
|
|
148
|
-
|
|
177
|
+
|
|
149
178
|
# Set up sys.argv for net's argparse
|
|
150
179
|
original_argv = sys.argv.copy()
|
|
151
180
|
try:
|
|
152
181
|
# Build argv for net
|
|
153
182
|
sys.argv = ["hanzo-net"] # Program name
|
|
154
|
-
|
|
183
|
+
|
|
155
184
|
# Add options
|
|
156
185
|
if port != 52415:
|
|
157
186
|
sys.argv.extend(["--chatgpt-api-port", str(port)])
|
|
@@ -159,22 +188,24 @@ def start_compute_node(ctx, name: str = None, port: int = 52415,
|
|
|
159
188
|
sys.argv.extend(["--node-id", name])
|
|
160
189
|
if network != "local":
|
|
161
190
|
sys.argv.extend(["--discovery-module", network])
|
|
162
|
-
if models
|
|
191
|
+
if models:
|
|
163
192
|
sys.argv.extend(["--default-model", models[0]])
|
|
164
|
-
|
|
193
|
+
|
|
165
194
|
# Import and run net
|
|
166
195
|
from net.main import run as net_run
|
|
167
|
-
|
|
196
|
+
|
|
168
197
|
console.print(f"\n[green]✓[/green] Node initialized")
|
|
169
198
|
console.print(f" Port: {port}")
|
|
170
|
-
console.print(
|
|
199
|
+
console.print(
|
|
200
|
+
f" Models: {', '.join(models) if models else 'auto-detect'}"
|
|
201
|
+
)
|
|
171
202
|
console.print("\n[bold green]Hanzo Net is running![/bold green]")
|
|
172
203
|
console.print("WebUI: http://localhost:52415")
|
|
173
204
|
console.print("API: http://localhost:52415/v1/chat/completions")
|
|
174
205
|
console.print("\nPress Ctrl+C to stop\n")
|
|
175
|
-
|
|
206
|
+
|
|
176
207
|
# Run net
|
|
177
|
-
net_run()
|
|
208
|
+
await net_run()
|
|
178
209
|
finally:
|
|
179
210
|
sys.argv = original_argv
|
|
180
211
|
else:
|
|
@@ -184,28 +215,32 @@ def start_compute_node(ctx, name: str = None, port: int = 52415,
|
|
|
184
215
|
console.print(f"[green]✓[/green] Using hanzo/net venv")
|
|
185
216
|
else:
|
|
186
217
|
console.print("[yellow]⚠[/yellow] Using system Python")
|
|
187
|
-
|
|
218
|
+
|
|
188
219
|
# Change to net directory and run
|
|
189
220
|
original_cwd = os.getcwd()
|
|
190
221
|
try:
|
|
191
222
|
os.chdir(net_path)
|
|
192
|
-
|
|
223
|
+
|
|
193
224
|
# Set up environment
|
|
194
225
|
env = os.environ.copy()
|
|
195
226
|
if models:
|
|
196
227
|
env["NET_MODELS"] = ",".join(models)
|
|
197
228
|
if name:
|
|
198
229
|
env["NET_NODE_NAME"] = name
|
|
199
|
-
env["PYTHONPATH"] =
|
|
200
|
-
|
|
230
|
+
env["PYTHONPATH"] = (
|
|
231
|
+
os.path.join(net_path, "src") + ":" + env.get("PYTHONPATH", "")
|
|
232
|
+
)
|
|
233
|
+
|
|
201
234
|
console.print(f"\n[green]✓[/green] Starting net node")
|
|
202
235
|
console.print(f" Port: {port}")
|
|
203
|
-
console.print(
|
|
236
|
+
console.print(
|
|
237
|
+
f" Models: {', '.join(models) if models else 'auto-detect'}"
|
|
238
|
+
)
|
|
204
239
|
console.print("\n[bold green]Hanzo Net is running![/bold green]")
|
|
205
240
|
console.print("WebUI: http://localhost:52415")
|
|
206
241
|
console.print("API: http://localhost:52415/v1/chat/completions")
|
|
207
242
|
console.print("\nPress Ctrl+C to stop\n")
|
|
208
|
-
|
|
243
|
+
|
|
209
244
|
# Build command line args
|
|
210
245
|
cmd_args = [python_exe, "-m", "net.main"]
|
|
211
246
|
if port != 52415:
|
|
@@ -214,22 +249,20 @@ def start_compute_node(ctx, name: str = None, port: int = 52415,
|
|
|
214
249
|
cmd_args.extend(["--node-id", name])
|
|
215
250
|
if network != "local":
|
|
216
251
|
cmd_args.extend(["--discovery-module", network])
|
|
217
|
-
if models
|
|
252
|
+
if models:
|
|
218
253
|
cmd_args.extend(["--default-model", models[0]])
|
|
219
|
-
|
|
254
|
+
|
|
220
255
|
# Run net command with detected python
|
|
221
|
-
process = subprocess.run(
|
|
222
|
-
|
|
223
|
-
env=env,
|
|
224
|
-
check=False
|
|
225
|
-
)
|
|
226
|
-
|
|
256
|
+
process = subprocess.run(cmd_args, env=env, check=False)
|
|
257
|
+
|
|
227
258
|
if process.returncode != 0 and process.returncode != -2: # -2 is Ctrl+C
|
|
228
|
-
console.print(
|
|
229
|
-
|
|
259
|
+
console.print(
|
|
260
|
+
f"[red]Net exited with code {process.returncode}[/red]"
|
|
261
|
+
)
|
|
262
|
+
|
|
230
263
|
finally:
|
|
231
264
|
os.chdir(original_cwd)
|
|
232
|
-
|
|
265
|
+
|
|
233
266
|
except KeyboardInterrupt:
|
|
234
267
|
console.print("\n[yellow]Shutting down node...[/yellow]")
|
|
235
268
|
console.print("[green]✓[/green] Node stopped")
|
|
@@ -242,6 +275,7 @@ def start_compute_node(ctx, name: str = None, port: int = 52415,
|
|
|
242
275
|
def dashboard(ctx):
|
|
243
276
|
"""Open interactive dashboard."""
|
|
244
277
|
from .interactive.dashboard import run_dashboard
|
|
278
|
+
|
|
245
279
|
run_dashboard()
|
|
246
280
|
|
|
247
281
|
|
|
@@ -258,4 +292,4 @@ def main():
|
|
|
258
292
|
|
|
259
293
|
|
|
260
294
|
if __name__ == "__main__":
|
|
261
|
-
main()
|
|
295
|
+
main()
|
hanzo/commands/__init__.py
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
1
|
"""Command modules for Hanzo CLI."""
|
|
2
2
|
|
|
3
|
-
__all__ = [
|
|
3
|
+
__all__ = [
|
|
4
|
+
"agent",
|
|
5
|
+
"auth",
|
|
6
|
+
"chat",
|
|
7
|
+
"cluster",
|
|
8
|
+
"config",
|
|
9
|
+
"mcp",
|
|
10
|
+
"miner",
|
|
11
|
+
"network",
|
|
12
|
+
"repl",
|
|
13
|
+
"tools",
|
|
14
|
+
]
|
hanzo/commands/agent.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Agent management commands."""
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
-
from typing import
|
|
4
|
+
from typing import Optional
|
|
5
5
|
|
|
6
6
|
import click
|
|
7
7
|
from rich.table import Table
|
|
@@ -30,16 +30,12 @@ async def create(ctx, name: str, model: str, description: Optional[str], local:
|
|
|
30
30
|
console.print("[red]Error:[/red] hanzo-agents not installed")
|
|
31
31
|
console.print("Install with: pip install hanzo[agents]")
|
|
32
32
|
return
|
|
33
|
-
|
|
33
|
+
|
|
34
34
|
base_url = "http://localhost:8000" if local else None
|
|
35
|
-
|
|
35
|
+
|
|
36
36
|
with console.status(f"Creating agent '{name}'..."):
|
|
37
|
-
agent = create_agent(
|
|
38
|
-
|
|
39
|
-
model=model,
|
|
40
|
-
base_url=base_url
|
|
41
|
-
)
|
|
42
|
-
|
|
37
|
+
agent = create_agent(name=name, model=model, base_url=base_url)
|
|
38
|
+
|
|
43
39
|
console.print(f"[green]✓[/green] Created agent: {name}")
|
|
44
40
|
console.print(f" Model: {model}")
|
|
45
41
|
console.print(f" Mode: {'local' if local else 'cloud'}")
|
|
@@ -55,17 +51,17 @@ def list(ctx):
|
|
|
55
51
|
table.add_column("Model", style="green")
|
|
56
52
|
table.add_column("Status", style="yellow")
|
|
57
53
|
table.add_column("Description")
|
|
58
|
-
|
|
54
|
+
|
|
59
55
|
# Mock data for now
|
|
60
56
|
agents = [
|
|
61
57
|
("helper", "llama-3.2-3b", "active", "General purpose assistant"),
|
|
62
58
|
("coder", "codellama-7b", "idle", "Code generation specialist"),
|
|
63
59
|
("researcher", "llama-3.2-3b", "idle", "Research and analysis"),
|
|
64
60
|
]
|
|
65
|
-
|
|
61
|
+
|
|
66
62
|
for name, model, status, desc in agents:
|
|
67
63
|
table.add_row(name, model, status, desc)
|
|
68
|
-
|
|
64
|
+
|
|
69
65
|
console.print(table)
|
|
70
66
|
|
|
71
67
|
|
|
@@ -84,19 +80,20 @@ async def run(ctx, agents: tuple, task: str, parallel: bool, timeout: Optional[i
|
|
|
84
80
|
console.print("[red]Error:[/red] hanzo-agents not installed")
|
|
85
81
|
console.print("Install with: pip install hanzo[agents]")
|
|
86
82
|
return
|
|
87
|
-
|
|
83
|
+
|
|
88
84
|
agent_list = list(agents)
|
|
89
|
-
|
|
85
|
+
|
|
90
86
|
with console.status(f"Running task with {len(agent_list)} agents..."):
|
|
91
87
|
# Create network with agents
|
|
92
88
|
network = create_network(agents=agent_list)
|
|
93
|
-
|
|
89
|
+
|
|
94
90
|
# Run task
|
|
95
|
-
result =
|
|
96
|
-
network.run(task),
|
|
97
|
-
timeout
|
|
98
|
-
|
|
99
|
-
|
|
91
|
+
result = (
|
|
92
|
+
await asyncio.wait_for(network.run(task), timeout=timeout)
|
|
93
|
+
if timeout
|
|
94
|
+
else await network.run(task)
|
|
95
|
+
)
|
|
96
|
+
|
|
100
97
|
console.print("[green]Task completed![/green]")
|
|
101
98
|
console.print(result)
|
|
102
99
|
|
|
@@ -109,4 +106,4 @@ def delete(ctx, agent: str):
|
|
|
109
106
|
if click.confirm(f"Delete agent '{agent}'?"):
|
|
110
107
|
console.print(f"[yellow]Deleted agent: {agent}[/yellow]")
|
|
111
108
|
else:
|
|
112
|
-
console.print("Cancelled")
|
|
109
|
+
console.print("Cancelled")
|