hanzo 0.3.9__py3-none-any.whl → 0.3.11__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/cli.py +86 -9
- hanzo/commands/auth.py +1 -1
- hanzo/commands/mcp.py +3 -3
- hanzo/interactive/repl.py +1 -1
- {hanzo-0.3.9.dist-info → hanzo-0.3.11.dist-info}/METADATA +2 -5
- {hanzo-0.3.9.dist-info → hanzo-0.3.11.dist-info}/RECORD +8 -8
- {hanzo-0.3.9.dist-info → hanzo-0.3.11.dist-info}/WHEEL +0 -0
- {hanzo-0.3.9.dist-info → hanzo-0.3.11.dist-info}/entry_points.txt +0 -0
hanzo/cli.py
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
import sys
|
|
4
4
|
import asyncio
|
|
5
|
+
import signal
|
|
6
|
+
import os
|
|
7
|
+
import subprocess
|
|
5
8
|
from typing import Optional
|
|
6
9
|
|
|
7
10
|
import click
|
|
@@ -115,7 +118,11 @@ def serve(ctx, name: str, port: int):
|
|
|
115
118
|
@click.pass_context
|
|
116
119
|
def net(ctx, name: str, port: int, network: str, models: tuple, max_jobs: int):
|
|
117
120
|
"""Start the Hanzo Network distributed AI compute node."""
|
|
118
|
-
|
|
121
|
+
try:
|
|
122
|
+
asyncio.run(start_compute_node(ctx, name, port, network, models, max_jobs))
|
|
123
|
+
except KeyboardInterrupt:
|
|
124
|
+
# Already handled in start_compute_node
|
|
125
|
+
pass
|
|
119
126
|
|
|
120
127
|
|
|
121
128
|
@cli.command()
|
|
@@ -133,7 +140,11 @@ def net(ctx, name: str, port: int, network: str, models: tuple, max_jobs: int):
|
|
|
133
140
|
@click.pass_context
|
|
134
141
|
def node(ctx, name: str, port: int, network: str, models: tuple, max_jobs: int):
|
|
135
142
|
"""Alias for 'hanzo net' - Start as a compute node for the Hanzo network."""
|
|
136
|
-
|
|
143
|
+
try:
|
|
144
|
+
asyncio.run(start_compute_node(ctx, name, port, network, models, max_jobs))
|
|
145
|
+
except KeyboardInterrupt:
|
|
146
|
+
# Already handled in start_compute_node
|
|
147
|
+
pass
|
|
137
148
|
|
|
138
149
|
|
|
139
150
|
async def start_compute_node(
|
|
@@ -204,8 +215,40 @@ async def start_compute_node(
|
|
|
204
215
|
console.print("API: http://localhost:52415/v1/chat/completions")
|
|
205
216
|
console.print("\nPress Ctrl+C to stop\n")
|
|
206
217
|
|
|
207
|
-
#
|
|
208
|
-
|
|
218
|
+
# Set up signal handlers for async version
|
|
219
|
+
stop_event = asyncio.Event()
|
|
220
|
+
|
|
221
|
+
def async_signal_handler(signum, frame):
|
|
222
|
+
console.print("\n[yellow]Stopping hanzo net...[/yellow]")
|
|
223
|
+
stop_event.set()
|
|
224
|
+
|
|
225
|
+
signal.signal(signal.SIGINT, async_signal_handler)
|
|
226
|
+
signal.signal(signal.SIGTERM, async_signal_handler)
|
|
227
|
+
|
|
228
|
+
# Run net with proper signal handling
|
|
229
|
+
try:
|
|
230
|
+
net_task = asyncio.create_task(net_run())
|
|
231
|
+
stop_task = asyncio.create_task(stop_event.wait())
|
|
232
|
+
|
|
233
|
+
# Wait for either net to complete or stop signal
|
|
234
|
+
done, pending = await asyncio.wait(
|
|
235
|
+
[net_task, stop_task],
|
|
236
|
+
return_when=asyncio.FIRST_COMPLETED
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
# Cancel pending tasks
|
|
240
|
+
for task in pending:
|
|
241
|
+
task.cancel()
|
|
242
|
+
try:
|
|
243
|
+
await task
|
|
244
|
+
except asyncio.CancelledError:
|
|
245
|
+
pass
|
|
246
|
+
|
|
247
|
+
# Check if we stopped due to signal
|
|
248
|
+
if stop_task in done:
|
|
249
|
+
console.print("[green]✓[/green] Node stopped gracefully")
|
|
250
|
+
except asyncio.CancelledError:
|
|
251
|
+
console.print("[yellow]Cancelled[/yellow]")
|
|
209
252
|
finally:
|
|
210
253
|
sys.argv = original_argv
|
|
211
254
|
else:
|
|
@@ -252,12 +295,46 @@ async def start_compute_node(
|
|
|
252
295
|
if models:
|
|
253
296
|
cmd_args.extend(["--default-model", models[0]])
|
|
254
297
|
|
|
255
|
-
# Run net command with detected python
|
|
256
|
-
process
|
|
257
|
-
|
|
258
|
-
|
|
298
|
+
# Run net command with detected python in a more signal-friendly way
|
|
299
|
+
# Create new process group for better signal handling
|
|
300
|
+
process = subprocess.Popen(
|
|
301
|
+
cmd_args,
|
|
302
|
+
env=env,
|
|
303
|
+
preexec_fn=os.setsid if hasattr(os, 'setsid') else None
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
# Set up signal handlers to forward to subprocess group
|
|
307
|
+
def signal_handler(signum, frame):
|
|
308
|
+
if process.poll() is None: # Process is still running
|
|
309
|
+
console.print("\n[yellow]Stopping hanzo net...[/yellow]")
|
|
310
|
+
try:
|
|
311
|
+
# Send signal to entire process group
|
|
312
|
+
if hasattr(os, 'killpg'):
|
|
313
|
+
os.killpg(os.getpgid(process.pid), signal.SIGTERM)
|
|
314
|
+
else:
|
|
315
|
+
process.terminate()
|
|
316
|
+
process.wait(timeout=5) # Wait up to 5 seconds
|
|
317
|
+
except subprocess.TimeoutExpired:
|
|
318
|
+
console.print("[yellow]Force stopping...[/yellow]")
|
|
319
|
+
if hasattr(os, 'killpg'):
|
|
320
|
+
os.killpg(os.getpgid(process.pid), signal.SIGKILL)
|
|
321
|
+
else:
|
|
322
|
+
process.kill()
|
|
323
|
+
process.wait()
|
|
324
|
+
except ProcessLookupError:
|
|
325
|
+
pass # Process already terminated
|
|
326
|
+
raise KeyboardInterrupt
|
|
327
|
+
|
|
328
|
+
# Register signal handlers
|
|
329
|
+
signal.signal(signal.SIGINT, signal_handler)
|
|
330
|
+
signal.signal(signal.SIGTERM, signal_handler)
|
|
331
|
+
|
|
332
|
+
# Wait for process to complete
|
|
333
|
+
returncode = process.wait()
|
|
334
|
+
|
|
335
|
+
if returncode != 0 and returncode != -2: # -2 is Ctrl+C
|
|
259
336
|
console.print(
|
|
260
|
-
f"[red]Net exited with code {
|
|
337
|
+
f"[red]Net exited with code {returncode}[/red]"
|
|
261
338
|
)
|
|
262
339
|
|
|
263
340
|
finally:
|
hanzo/commands/auth.py
CHANGED
|
@@ -144,7 +144,7 @@ async def status(ctx):
|
|
|
144
144
|
console.print(
|
|
145
145
|
f" Quota: {usage.get('tokens', 0)} / {quota}"
|
|
146
146
|
)
|
|
147
|
-
except:
|
|
147
|
+
except Exception:
|
|
148
148
|
console.print("[yellow]![/yellow] Credentials may be expired")
|
|
149
149
|
console.print("Run 'hanzo auth login' to refresh")
|
|
150
150
|
|
hanzo/commands/mcp.py
CHANGED
|
@@ -144,7 +144,7 @@ async def run(ctx, tool: str, arg: tuple, json_args: str):
|
|
|
144
144
|
# Try to parse value as JSON first
|
|
145
145
|
try:
|
|
146
146
|
args[key] = json.loads(value)
|
|
147
|
-
except:
|
|
147
|
+
except Exception:
|
|
148
148
|
args[key] = value
|
|
149
149
|
|
|
150
150
|
# Create server and run tool
|
|
@@ -189,7 +189,7 @@ async def run(ctx, tool: str, arg: tuple, json_args: str):
|
|
|
189
189
|
# Try to parse as JSON for pretty printing
|
|
190
190
|
data = json.loads(result)
|
|
191
191
|
console.print_json(data=data)
|
|
192
|
-
except:
|
|
192
|
+
except Exception:
|
|
193
193
|
# Display as text
|
|
194
194
|
console.print(result)
|
|
195
195
|
else:
|
|
@@ -207,7 +207,7 @@ async def run(ctx, tool: str, arg: tuple, json_args: str):
|
|
|
207
207
|
def install(ctx, path: str):
|
|
208
208
|
"""Install MCP server in Claude Desktop."""
|
|
209
209
|
try:
|
|
210
|
-
|
|
210
|
+
import hanzoai.mcp
|
|
211
211
|
except ImportError:
|
|
212
212
|
console.print("[red]Error:[/red] hanzo-mcp not installed")
|
|
213
213
|
console.print("Install with: pip install hanzo[mcp]")
|
hanzo/interactive/repl.py
CHANGED
|
@@ -167,7 +167,7 @@ hanzo> mcp run read_file --arg path=README.md
|
|
|
167
167
|
async with httpx.AsyncClient() as client:
|
|
168
168
|
response = await client.get("http://localhost:8000/health", timeout=1.0)
|
|
169
169
|
return "running" if response.status_code == 200 else "not responding"
|
|
170
|
-
except:
|
|
170
|
+
except Exception:
|
|
171
171
|
return "not running"
|
|
172
172
|
|
|
173
173
|
async def count_agents(self) -> int:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hanzo
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.11
|
|
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
|
|
@@ -14,16 +14,13 @@ Classifier: Intended Audience :: Developers
|
|
|
14
14
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
15
15
|
Classifier: Operating System :: OS Independent
|
|
16
16
|
Classifier: Programming Language :: Python :: 3
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
19
17
|
Classifier: Programming Language :: Python :: 3.10
|
|
20
18
|
Classifier: Programming Language :: Python :: 3.11
|
|
21
19
|
Classifier: Programming Language :: Python :: 3.12
|
|
22
20
|
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
23
21
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
24
|
-
Requires-Python: >=3.
|
|
22
|
+
Requires-Python: >=3.10
|
|
25
23
|
Requires-Dist: click>=8.1.0
|
|
26
|
-
Requires-Dist: hanzo-net>=0.1.12
|
|
27
24
|
Requires-Dist: httpx>=0.23.0
|
|
28
25
|
Requires-Dist: prompt-toolkit>=3.0.0
|
|
29
26
|
Requires-Dist: pydantic>=2.0.0
|
|
@@ -1,28 +1,28 @@
|
|
|
1
1
|
hanzo/__init__.py,sha256=f6N_RcJZ0F9ADrROlvPi1OrgwjF8cWQm34cml8hb1zk,169
|
|
2
2
|
hanzo/__main__.py,sha256=F3Vz0Ty3bdAj_8oxyETMIqxlmNRnJOAFB1XPxbyfouI,105
|
|
3
|
-
hanzo/cli.py,sha256=
|
|
3
|
+
hanzo/cli.py,sha256=9dNIUrGkLn1qQYbC3a_2Xun8bdvlIo2yZ-dWQACREMA,13846
|
|
4
4
|
hanzo/mcp_server.py,sha256=XVygFNn-9CVdu8c95sP7fQjIRtA8K7nsGpgQNe44BRg,460
|
|
5
5
|
hanzo/repl.py,sha256=sW1quuqGkJ_AqgjN2vLNdtWgKDlXIkXiO9Bo1QQI0G4,1089
|
|
6
6
|
hanzo/commands/__init__.py,sha256=7rh94TPNhdq4gJBJS0Ayf0fGNChQYCQCJcJPmYYehiQ,182
|
|
7
7
|
hanzo/commands/agent.py,sha256=DXCfuxHfmC90IoIOL6BJyp7h2yNUo-VIxrfl4OMh8CU,3480
|
|
8
|
-
hanzo/commands/auth.py,sha256=
|
|
8
|
+
hanzo/commands/auth.py,sha256=JrM-EV4XDHzNDJeGJMjAr69T0Rxez53HEzlNo0jQ8nE,11187
|
|
9
9
|
hanzo/commands/chat.py,sha256=GqBXHpaen3ySEt4q59mmAU4A8PxXZd8ozDw0HptNHYU,6725
|
|
10
10
|
hanzo/commands/cluster.py,sha256=7AVjD1nej1WzBoIz_qcNxRMKHRb05_8qt3z3xRREZ-s,15486
|
|
11
11
|
hanzo/commands/config.py,sha256=xAzM6n9GhdVIqtn7JrHfLRzj1sshmxCujo7iet2hHqE,7490
|
|
12
|
-
hanzo/commands/mcp.py,sha256=
|
|
12
|
+
hanzo/commands/mcp.py,sha256=u1uEKDY6gUIa7VymEnRzy0ZphdIKYoNwPSeffZaiKnk,7418
|
|
13
13
|
hanzo/commands/miner.py,sha256=_mZT9nQcT2QSSxI0rDDKuSBVdsg_uE_N_j3PXOHoj-Q,11677
|
|
14
14
|
hanzo/commands/network.py,sha256=wJDxGIxJqc6FzQhbAn0Mw-WGCPUeCOsxmdU6GCmOhgM,11408
|
|
15
15
|
hanzo/commands/repl.py,sha256=FwbBmjNDBZCUQlwKbMZl33r3f899rzI2a2-ZRoBe6kE,5977
|
|
16
16
|
hanzo/commands/tools.py,sha256=fG27wRweVmaFJowBpmwp5PgkRUtIF8bIlu_hGWr69Ss,10393
|
|
17
17
|
hanzo/interactive/__init__.py,sha256=ENHkGOqu-JYI05lqoOKDczJGl96oq6nM476EPhflAbI,74
|
|
18
18
|
hanzo/interactive/dashboard.py,sha256=XB5H_PMlReriCip-wW9iuUiJQOAtSATFG8EyhhFhItU,3842
|
|
19
|
-
hanzo/interactive/repl.py,sha256=
|
|
19
|
+
hanzo/interactive/repl.py,sha256=w69ZSiaJ7g2nYKE4SA0IDsQg-V6eYy3z0-mqw0VCYFU,5580
|
|
20
20
|
hanzo/router/__init__.py,sha256=_cRG9nHC_wwq17iVYZSUNBYiJDdByfLDVEuIQn5-ePM,978
|
|
21
21
|
hanzo/utils/__init__.py,sha256=5RRwKI852vp8smr4xCRgeKfn7dLEnHbdXGfVYTZ5jDQ,69
|
|
22
22
|
hanzo/utils/config.py,sha256=FD_LoBpcoF5dgJ7WL4o6LDp2pdOy8kS-dJ6iRO2GcGM,4728
|
|
23
23
|
hanzo/utils/net_check.py,sha256=YFbJ65SzfDYHkHLZe3n51VhId1VI3zhyx8p6BM-l6jE,3017
|
|
24
24
|
hanzo/utils/output.py,sha256=W0j3psF07vJiX4s02gbN4zYWfbKNsb8TSIoagBSf5vA,2704
|
|
25
|
-
hanzo-0.3.
|
|
26
|
-
hanzo-0.3.
|
|
27
|
-
hanzo-0.3.
|
|
28
|
-
hanzo-0.3.
|
|
25
|
+
hanzo-0.3.11.dist-info/METADATA,sha256=mcKJuuFGd5nF8_PkPD8M1XzCtpkIQ8zxsoI4B6FTwcc,4217
|
|
26
|
+
hanzo-0.3.11.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
27
|
+
hanzo-0.3.11.dist-info/entry_points.txt,sha256=pQLPMdqOXU_2BfTcMDhkqTCDNk_H6ApvYuSaWcuQOOw,171
|
|
28
|
+
hanzo-0.3.11.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|