hanzo 0.2.3__tar.gz → 0.2.5__tar.gz

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.

@@ -1,7 +1,7 @@
1
1
  .prism.log
2
2
  .vscode
3
3
  _dev
4
-
4
+ *.egg-info
5
5
  __pycache__
6
6
  .mypy_cache
7
7
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hanzo
3
- Version: 0.2.3
3
+ Version: 0.2.5
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
@@ -23,8 +23,12 @@ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
23
23
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
24
  Requires-Python: >=3.8
25
25
  Requires-Dist: click>=8.1.0
26
- Requires-Dist: hanzo-cli>=0.1.0
26
+ Requires-Dist: httpx>=0.23.0
27
+ Requires-Dist: prompt-toolkit>=3.0.0
28
+ Requires-Dist: pydantic>=2.0.0
29
+ Requires-Dist: pyyaml>=6.0
27
30
  Requires-Dist: rich>=13.0.0
31
+ Requires-Dist: typer>=0.9.0
28
32
  Provides-Extra: agents
29
33
  Requires-Dist: hanzo-agents>=0.1.0; extra == 'agents'
30
34
  Requires-Dist: hanzo-network>=0.1.0; extra == 'agents'
@@ -33,7 +37,6 @@ Requires-Dist: hanzoai>=1.0.0; extra == 'ai'
33
37
  Provides-Extra: all
34
38
  Requires-Dist: hanzo-aci>=0.2.8; extra == 'all'
35
39
  Requires-Dist: hanzo-agents>=0.1.0; extra == 'all'
36
- Requires-Dist: hanzo-mcp-client>=0.1.0; extra == 'all'
37
40
  Requires-Dist: hanzo-mcp>=0.7.0; extra == 'all'
38
41
  Requires-Dist: hanzo-memory>=1.0.0; extra == 'all'
39
42
  Requires-Dist: hanzo-network>=0.1.0; extra == 'all'
@@ -1,14 +1,18 @@
1
1
  [project]
2
2
  name = "hanzo"
3
- version = "0.2.3"
3
+ version = "0.2.5"
4
4
  description = "Hanzo AI - Complete AI Infrastructure Platform with CLI, Router, MCP, and Agent Runtime"
5
5
  authors = [
6
6
  {name = "Hanzo AI", email = "dev@hanzo.ai"},
7
7
  ]
8
8
  dependencies = [
9
- "hanzo-cli>=0.1.0",
10
9
  "click>=8.1.0",
11
10
  "rich>=13.0.0",
11
+ "typer>=0.9.0",
12
+ "prompt-toolkit>=3.0.0",
13
+ "httpx>=0.23.0",
14
+ "pydantic>=2.0.0",
15
+ "pyyaml>=6.0",
12
16
  ]
13
17
  readme = "README.md"
14
18
  requires-python = ">= 3.8"
@@ -45,7 +49,6 @@ all = [
45
49
  "hanzo-repl>=0.1.0",
46
50
  "hanzo-memory>=1.0.0",
47
51
  # "hanzo-router>=1.74.3", # TODO: Publish hanzo-router to PyPI
48
- "hanzo-mcp-client>=0.1.0",
49
52
  "hanzo-aci>=0.2.8",
50
53
  ]
51
54
  ai = [
@@ -0,0 +1,6 @@
1
+ """Hanzo - Complete AI Infrastructure Platform with CLI, Router, MCP, and Agent Runtime."""
2
+
3
+ __version__ = "0.2.5"
4
+ __all__ = ["main", "cli"]
5
+
6
+ from .cli import main, cli
@@ -0,0 +1,6 @@
1
+ """Entry point for python -m hanzo_cli."""
2
+
3
+ from .cli import main
4
+
5
+ if __name__ == "__main__":
6
+ main()
@@ -0,0 +1,244 @@
1
+ """Main CLI entry point for Hanzo."""
2
+
3
+ import asyncio
4
+ import sys
5
+ from typing import Optional
6
+
7
+ import click
8
+ from rich.console import Console
9
+
10
+ from .commands import agent, auth, chat, cluster, config, mcp, miner, network, repl, tools
11
+ from .interactive.repl import HanzoREPL
12
+ from .utils.output import console
13
+
14
+ # Version
15
+ __version__ = "0.2.5"
16
+
17
+
18
+ @click.group(invoke_without_command=True)
19
+ @click.version_option(version=__version__, prog_name="hanzo")
20
+ @click.option("--verbose", "-v", is_flag=True, help="Verbose output")
21
+ @click.option("--json", is_flag=True, help="JSON output format")
22
+ @click.option("--config", "-c", type=click.Path(), help="Config file path")
23
+ @click.pass_context
24
+ def cli(ctx, verbose: bool, json: bool, config: Optional[str]):
25
+ """Hanzo AI - Unified CLI for local, private, and free AI.
26
+
27
+ Run without arguments to enter interactive mode.
28
+ """
29
+ # Ensure context object exists
30
+ ctx.ensure_object(dict)
31
+ ctx.obj["verbose"] = verbose
32
+ ctx.obj["json"] = json
33
+ ctx.obj["config"] = config
34
+ ctx.obj["console"] = console
35
+
36
+ # If no subcommand, enter interactive mode or start compute node
37
+ if ctx.invoked_subcommand is None:
38
+ # Check if we should start as a compute node
39
+ import os
40
+ if os.environ.get("HANZO_COMPUTE_NODE") == "1":
41
+ # Start as a compute node
42
+ from .commands import network
43
+ asyncio.run(start_compute_node(ctx))
44
+ else:
45
+ # Enter interactive REPL mode
46
+ console.print("[bold cyan]Hanzo AI - Interactive Mode[/bold cyan]")
47
+ console.print("Type 'help' for commands, 'exit' to quit\n")
48
+ try:
49
+ repl = HanzoREPL(console=console)
50
+ asyncio.run(repl.run())
51
+ except KeyboardInterrupt:
52
+ console.print("\n[yellow]Interrupted[/yellow]")
53
+ except EOFError:
54
+ console.print("\n[yellow]Goodbye![/yellow]")
55
+
56
+
57
+ # Register command groups
58
+ cli.add_command(agent.agent_group)
59
+ cli.add_command(auth.auth_group)
60
+ cli.add_command(cluster.cluster_group)
61
+ cli.add_command(mcp.mcp_group)
62
+ cli.add_command(miner.miner_group)
63
+ cli.add_command(chat.chat_command)
64
+ cli.add_command(repl.repl_group)
65
+ cli.add_command(tools.tools_group)
66
+ cli.add_command(network.network_group)
67
+ cli.add_command(config.config_group)
68
+
69
+
70
+ # Quick aliases
71
+ @cli.command()
72
+ @click.argument("prompt", nargs=-1, required=True)
73
+ @click.option("--model", "-m", default="llama-3.2-3b", help="Model to use")
74
+ @click.option("--local/--cloud", default=True, help="Use local or cloud model")
75
+ @click.pass_context
76
+ def ask(ctx, prompt: tuple, model: str, local: bool):
77
+ """Quick question to AI (alias for 'hanzo chat --once')."""
78
+ prompt_text = " ".join(prompt)
79
+ asyncio.run(chat.ask_once(ctx, prompt_text, model, local))
80
+
81
+
82
+ @cli.command()
83
+ @click.option("--name", "-n", default="hanzo-local", help="Cluster name")
84
+ @click.option("--port", "-p", default=8000, help="API port")
85
+ @click.pass_context
86
+ def serve(ctx, name: str, port: int):
87
+ """Start local AI cluster (alias for 'hanzo cluster start')."""
88
+ asyncio.run(cluster.start_cluster(ctx, name, port))
89
+
90
+
91
+ @cli.command()
92
+ @click.option("--name", "-n", help="Node name (auto-generated if not provided)")
93
+ @click.option("--port", "-p", default=52415, help="Node port (default: 52415 for hanzo/net)")
94
+ @click.option("--network", default="local", help="Network to join (mainnet/testnet/local)")
95
+ @click.option("--models", "-m", multiple=True, help="Models to serve (e.g., llama-3.2-3b)")
96
+ @click.option("--max-jobs", type=int, default=10, help="Max concurrent jobs")
97
+ @click.pass_context
98
+ def node(ctx, name: str, port: int, network: str, models: tuple, max_jobs: int):
99
+ """Start as a compute node for the Hanzo network using hanzo/net."""
100
+ asyncio.run(start_compute_node(ctx, name, port, network, models, max_jobs))
101
+
102
+
103
+ async def start_compute_node(ctx, name: str = None, port: int = 52415,
104
+ network: str = "mainnet", models: tuple = None,
105
+ max_jobs: int = 10):
106
+ """Start this instance as a compute node using hanzo/net."""
107
+ console = ctx.obj.get("console", Console())
108
+
109
+ console.print("[bold cyan]Starting Hanzo Net Compute Node[/bold cyan]")
110
+ console.print(f"Network: {network}")
111
+ console.print(f"Port: {port}")
112
+
113
+ try:
114
+ import subprocess
115
+ import sys
116
+ import os
117
+
118
+ # Check if hanzo/net is available
119
+ net_path = "/Users/z/work/hanzo/net"
120
+ if not os.path.exists(net_path):
121
+ # Try to find net in the Python environment
122
+ try:
123
+ import net
124
+ # net is installed as a package
125
+ console.print("[green]✓[/green] Using installed hanzo/net")
126
+
127
+ # Run net directly
128
+ from net.main import run as net_run
129
+
130
+ # Set up environment for net
131
+ if models:
132
+ os.environ["NET_MODELS"] = ",".join(models)
133
+ if name:
134
+ os.environ["NET_NODE_NAME"] = name
135
+
136
+ console.print(f"\n[green]✓[/green] Node initialized")
137
+ console.print(f" Port: {port}")
138
+ console.print(f" Models: {', '.join(models) if models else 'auto-detect'}")
139
+ console.print("\n[bold green]Hanzo Net is running![/bold green]")
140
+ console.print("WebUI: http://localhost:52415")
141
+ console.print("API: http://localhost:52415/v1/chat/completions")
142
+ console.print("\nPress Ctrl+C to stop\n")
143
+
144
+ # Run net
145
+ await net_run()
146
+
147
+ except ImportError:
148
+ # net not installed, try to run from source
149
+ console.print("[yellow]hanzo/net not installed, checking for source...[/yellow]")
150
+
151
+ if os.path.exists(net_path):
152
+ console.print(f"[green]✓[/green] Found hanzo/net at {net_path}")
153
+
154
+ # Add net to Python path
155
+ sys.path.insert(0, os.path.join(net_path, "src"))
156
+
157
+ # Import and run net
158
+ from net.main import run as net_run
159
+
160
+ console.print(f"\n[green]✓[/green] Starting net node")
161
+ console.print(f" Port: {port}")
162
+ console.print(f" Models: {', '.join(models) if models else 'auto-detect'}")
163
+ console.print("\n[bold green]Hanzo Net is running![/bold green]")
164
+ console.print("WebUI: http://localhost:52415")
165
+ console.print("API: http://localhost:52415/v1/chat/completions")
166
+ console.print("\nPress Ctrl+C to stop\n")
167
+
168
+ # Run net
169
+ await net_run()
170
+ else:
171
+ console.print("[red]Error:[/red] hanzo/net not found")
172
+ console.print("\nInstall hanzo/net:")
173
+ console.print(" git clone https://github.com/hanzoai/net.git")
174
+ console.print(" cd net && pip install -e .")
175
+ return
176
+ else:
177
+ # Run from source directory
178
+ console.print(f"[green]✓[/green] Using hanzo/net from {net_path}")
179
+
180
+ # Change to net directory and run
181
+ original_cwd = os.getcwd()
182
+ try:
183
+ os.chdir(net_path)
184
+
185
+ # Set up environment
186
+ env = os.environ.copy()
187
+ if models:
188
+ env["NET_MODELS"] = ",".join(models)
189
+ if name:
190
+ env["NET_NODE_NAME"] = name
191
+
192
+ console.print(f"\n[green]✓[/green] Starting net node")
193
+ console.print(f" Port: {port}")
194
+ console.print(f" Models: {', '.join(models) if models else 'auto-detect'}")
195
+ console.print("\n[bold green]Hanzo Net is running![/bold green]")
196
+ console.print("WebUI: http://localhost:52415")
197
+ console.print("API: http://localhost:52415/v1/chat/completions")
198
+ console.print("\nPress Ctrl+C to stop\n")
199
+
200
+ # Add src to path and run net
201
+ env["PYTHONPATH"] = os.path.join(net_path, "src") + ":" + env.get("PYTHONPATH", "")
202
+
203
+ # Run net command
204
+ process = subprocess.run(
205
+ [sys.executable, "-c", "from net.main import run; run()"],
206
+ env=env,
207
+ check=False
208
+ )
209
+
210
+ if process.returncode != 0 and process.returncode != -2: # -2 is Ctrl+C
211
+ console.print(f"[red]Net exited with code {process.returncode}[/red]")
212
+
213
+ finally:
214
+ os.chdir(original_cwd)
215
+
216
+ except KeyboardInterrupt:
217
+ console.print("\n[yellow]Shutting down node...[/yellow]")
218
+ console.print("[green]✓[/green] Node stopped")
219
+ except Exception as e:
220
+ console.print(f"[red]Error starting compute node: {e}[/red]")
221
+
222
+
223
+ @cli.command()
224
+ @click.pass_context
225
+ def dashboard(ctx):
226
+ """Open interactive dashboard."""
227
+ from .interactive.dashboard import run_dashboard
228
+ run_dashboard()
229
+
230
+
231
+ def main():
232
+ """Main entry point."""
233
+ try:
234
+ cli(auto_envvar_prefix="HANZO")
235
+ except KeyboardInterrupt:
236
+ console.print("\n[yellow]Interrupted by user[/yellow]")
237
+ sys.exit(0)
238
+ except Exception as e:
239
+ console.print(f"[red]Error: {e}[/red]")
240
+ sys.exit(1)
241
+
242
+
243
+ if __name__ == "__main__":
244
+ main()
@@ -0,0 +1,3 @@
1
+ """Command modules for Hanzo CLI."""
2
+
3
+ __all__ = ["agent", "auth", "chat", "cluster", "config", "mcp", "miner", "network", "repl", "tools"]
@@ -0,0 +1,112 @@
1
+ """Agent management commands."""
2
+
3
+ import asyncio
4
+ from typing import List, Optional
5
+
6
+ import click
7
+ from rich.table import Table
8
+
9
+ from ..utils.output import console, handle_errors
10
+
11
+
12
+ @click.group(name="agent")
13
+ def agent_group():
14
+ """Manage AI agents."""
15
+ pass
16
+
17
+
18
+ @agent_group.command()
19
+ @click.option("--name", "-n", required=True, help="Agent name")
20
+ @click.option("--model", "-m", default="llama-3.2-3b", help="Model to use")
21
+ @click.option("--description", "-d", help="Agent description")
22
+ @click.option("--local/--cloud", default=True, help="Use local or cloud model")
23
+ @click.pass_context
24
+ @handle_errors
25
+ async def create(ctx, name: str, model: str, description: Optional[str], local: bool):
26
+ """Create a new agent."""
27
+ try:
28
+ from hanzoai.agents import create_agent
29
+ except ImportError:
30
+ console.print("[red]Error:[/red] hanzo-agents not installed")
31
+ console.print("Install with: pip install hanzo[agents]")
32
+ return
33
+
34
+ base_url = "http://localhost:8000" if local else None
35
+
36
+ with console.status(f"Creating agent '{name}'..."):
37
+ agent = create_agent(
38
+ name=name,
39
+ model=model,
40
+ base_url=base_url
41
+ )
42
+
43
+ console.print(f"[green]✓[/green] Created agent: {name}")
44
+ console.print(f" Model: {model}")
45
+ console.print(f" Mode: {'local' if local else 'cloud'}")
46
+
47
+
48
+ @agent_group.command()
49
+ @click.pass_context
50
+ def list(ctx):
51
+ """List available agents."""
52
+ # TODO: Connect to agent registry
53
+ table = Table(title="Available Agents")
54
+ table.add_column("Name", style="cyan", no_wrap=True)
55
+ table.add_column("Model", style="green")
56
+ table.add_column("Status", style="yellow")
57
+ table.add_column("Description")
58
+
59
+ # Mock data for now
60
+ agents = [
61
+ ("helper", "llama-3.2-3b", "active", "General purpose assistant"),
62
+ ("coder", "codellama-7b", "idle", "Code generation specialist"),
63
+ ("researcher", "llama-3.2-3b", "idle", "Research and analysis"),
64
+ ]
65
+
66
+ for name, model, status, desc in agents:
67
+ table.add_row(name, model, status, desc)
68
+
69
+ console.print(table)
70
+
71
+
72
+ @agent_group.command()
73
+ @click.argument("agents", nargs=-1, required=True)
74
+ @click.option("--task", "-t", required=True, help="Task to execute")
75
+ @click.option("--parallel", "-p", is_flag=True, help="Run agents in parallel")
76
+ @click.option("--timeout", type=int, help="Timeout in seconds")
77
+ @click.pass_context
78
+ @handle_errors
79
+ async def run(ctx, agents: tuple, task: str, parallel: bool, timeout: Optional[int]):
80
+ """Run a task with specified agents."""
81
+ try:
82
+ from hanzoai.agents import create_network
83
+ except ImportError:
84
+ console.print("[red]Error:[/red] hanzo-agents not installed")
85
+ console.print("Install with: pip install hanzo[agents]")
86
+ return
87
+
88
+ agent_list = list(agents)
89
+
90
+ with console.status(f"Running task with {len(agent_list)} agents..."):
91
+ # Create network with agents
92
+ network = create_network(agents=agent_list)
93
+
94
+ # Run task
95
+ result = await asyncio.wait_for(
96
+ network.run(task),
97
+ timeout=timeout
98
+ ) if timeout else await network.run(task)
99
+
100
+ console.print("[green]Task completed![/green]")
101
+ console.print(result)
102
+
103
+
104
+ @agent_group.command()
105
+ @click.argument("agent")
106
+ @click.pass_context
107
+ def delete(ctx, agent: str):
108
+ """Delete an agent."""
109
+ if click.confirm(f"Delete agent '{agent}'?"):
110
+ console.print(f"[yellow]Deleted agent: {agent}[/yellow]")
111
+ else:
112
+ console.print("Cancelled")