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 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:
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
- from hanzoai.mcp import create_server
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.9
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,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=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
7
7
  hanzo/commands/agent.py,sha256=DXCfuxHfmC90IoIOL6BJyp7h2yNUo-VIxrfl4OMh8CU,3480
8
- hanzo/commands/auth.py,sha256=gJ3V-E2AGAkKx3sIXKWLZkjzXC4P7yKI_vXt8zcbPLw,11177
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=FTF3PupRV2WfM65pgoaHhtJjNtshW2Wp3jzED6jyZf0,7417
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=T_YWXuF7qaEo9JmvdQdt1aMdnKJgE45LED-IpQX40EI,5570
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.9.dist-info/METADATA,sha256=9GbEl63cI17Q5mkGYQtBzvuXW4uVNAEKmErW4eT2x8I,4348
26
- hanzo-0.3.9.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
27
- hanzo-0.3.9.dist-info/entry_points.txt,sha256=pQLPMdqOXU_2BfTcMDhkqTCDNk_H6ApvYuSaWcuQOOw,171
28
- hanzo-0.3.9.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