hanzo 0.3.10__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 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
- asyncio.run(start_compute_node(ctx, name, port, network, models, max_jobs))
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
- asyncio.run(start_compute_node(ctx, name, port, network, models, max_jobs))
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
- # Run net
208
- await net_run()
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 = subprocess.run(cmd_args, env=env, check=False)
257
-
258
- if process.returncode != 0 and process.returncode != -2: # -2 is Ctrl+C
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 {process.returncode}[/red]"
337
+ f"[red]Net exited with code {returncode}[/red]"
261
338
  )
262
339
 
263
340
  finally:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hanzo
3
- Version: 0.3.10
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.8
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,6 +1,6 @@
1
1
  hanzo/__init__.py,sha256=f6N_RcJZ0F9ADrROlvPi1OrgwjF8cWQm34cml8hb1zk,169
2
2
  hanzo/__main__.py,sha256=F3Vz0Ty3bdAj_8oxyETMIqxlmNRnJOAFB1XPxbyfouI,105
3
- hanzo/cli.py,sha256=Vgo1VGFOa1nurZJIgGvgLxw-jqNKZJVp2nRG-CzbnhI,10340
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
@@ -22,7 +22,7 @@ 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.10.dist-info/METADATA,sha256=_KSdR3Za5yCrOdxOdPNsIpsWau6LI8Vfo3I5Ay0OXoo,4349
26
- hanzo-0.3.10.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
27
- hanzo-0.3.10.dist-info/entry_points.txt,sha256=pQLPMdqOXU_2BfTcMDhkqTCDNk_H6ApvYuSaWcuQOOw,171
28
- hanzo-0.3.10.dist-info/RECORD,,
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