hanzo 0.2.3__py3-none-any.whl → 0.2.6__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.

@@ -0,0 +1,333 @@
1
+ """Network commands for agent networks."""
2
+
3
+ import asyncio
4
+ from typing import List, Optional, Dict, Any
5
+
6
+ import click
7
+ from rich.table import Table
8
+ from rich.progress import Progress, SpinnerColumn, TextColumn
9
+
10
+ from ..utils.output import console, handle_errors
11
+
12
+
13
+ @click.group(name="network")
14
+ def network_group():
15
+ """Manage agent networks."""
16
+ pass
17
+
18
+
19
+ @network_group.command()
20
+ @click.argument("prompt")
21
+ @click.option("--agents", "-a", type=int, default=3, help="Number of agents")
22
+ @click.option("--model", "-m", help="Model to use")
23
+ @click.option("--mode", type=click.Choice(["local", "distributed", "hybrid"]), default="hybrid", help="Execution mode")
24
+ @click.option("--consensus", is_flag=True, help="Require consensus")
25
+ @click.option("--timeout", "-t", type=int, default=300, help="Timeout in seconds")
26
+ @click.pass_context
27
+ async def dispatch(ctx, prompt: str, agents: int, model: str, mode: str, consensus: bool, timeout: int):
28
+ """Dispatch work to agent network."""
29
+ try:
30
+ from hanzo_network import NetworkDispatcher
31
+ except ImportError:
32
+ console.print("[red]Error:[/red] hanzo-network not installed")
33
+ console.print("Install with: pip install hanzo[network]")
34
+ return
35
+
36
+ dispatcher = NetworkDispatcher(mode=mode)
37
+
38
+ with Progress(
39
+ SpinnerColumn(),
40
+ TextColumn("[progress.description]{task.description}"),
41
+ console=console,
42
+ ) as progress:
43
+ task = progress.add_task("Dispatching to network...", total=None)
44
+
45
+ try:
46
+ # Create job
47
+ job = await dispatcher.create_job(
48
+ prompt=prompt,
49
+ num_agents=agents,
50
+ model=model,
51
+ consensus=consensus,
52
+ timeout=timeout
53
+ )
54
+
55
+ progress.update(task, description=f"Job {job['id']} - Finding agents...")
56
+
57
+ # Execute job
58
+ result = await dispatcher.execute_job(job)
59
+
60
+ progress.update(task, completed=True)
61
+
62
+ except Exception as e:
63
+ progress.stop()
64
+ console.print(f"[red]Dispatch failed: {e}[/red]")
65
+ return
66
+
67
+ # Show results
68
+ console.print(f"\n[green]✓[/green] Job completed")
69
+ console.print(f" ID: {result['job_id']}")
70
+ console.print(f" Agents: {result['num_agents']}")
71
+ console.print(f" Duration: {result['duration']}s")
72
+
73
+ if consensus:
74
+ console.print(f" Consensus: {result.get('consensus_reached', False)}")
75
+
76
+ console.print("\n[cyan]Results:[/cyan]")
77
+
78
+ if consensus and result.get("consensus_result"):
79
+ console.print(result["consensus_result"])
80
+ else:
81
+ for i, agent_result in enumerate(result["agent_results"], 1):
82
+ console.print(f"\n[yellow]Agent {i} ({agent_result['agent_id']}):[/yellow]")
83
+ console.print(agent_result["result"])
84
+
85
+
86
+ @network_group.command()
87
+ @click.option("--mode", type=click.Choice(["local", "distributed", "all"]), default="all", help="Network mode")
88
+ @click.pass_context
89
+ async def agents(ctx, mode: str):
90
+ """List available agents in network."""
91
+ try:
92
+ from hanzo_network import get_network_agents
93
+ except ImportError:
94
+ console.print("[red]Error:[/red] hanzo-network not installed")
95
+ return
96
+
97
+ with console.status("Discovering agents..."):
98
+ try:
99
+ agents = await get_network_agents(mode=mode)
100
+ except Exception as e:
101
+ console.print(f"[red]Failed to discover agents: {e}[/red]")
102
+ return
103
+
104
+ if not agents:
105
+ console.print("[yellow]No agents found[/yellow]")
106
+ if mode == "local":
107
+ console.print("Start local agents with: hanzo agent start")
108
+ return
109
+
110
+ # Group by type
111
+ local_agents = [a for a in agents if a["type"] == "local"]
112
+ network_agents = [a for a in agents if a["type"] == "network"]
113
+
114
+ if local_agents:
115
+ table = Table(title="Local Agents")
116
+ table.add_column("ID", style="cyan")
117
+ table.add_column("Name", style="green")
118
+ table.add_column("Model", style="yellow")
119
+ table.add_column("Status", style="blue")
120
+ table.add_column("Jobs", style="magenta")
121
+
122
+ for agent in local_agents:
123
+ table.add_row(
124
+ agent["id"][:8],
125
+ agent["name"],
126
+ agent.get("model", "default"),
127
+ agent["status"],
128
+ str(agent.get("jobs_completed", 0))
129
+ )
130
+
131
+ console.print(table)
132
+
133
+ if network_agents:
134
+ table = Table(title="Network Agents")
135
+ table.add_column("ID", style="cyan")
136
+ table.add_column("Location", style="green")
137
+ table.add_column("Model", style="yellow")
138
+ table.add_column("Latency", style="blue")
139
+ table.add_column("Cost", style="magenta")
140
+
141
+ for agent in network_agents:
142
+ table.add_row(
143
+ agent["id"][:8],
144
+ agent.get("location", "unknown"),
145
+ agent.get("model", "various"),
146
+ f"{agent.get('latency', 0)}ms",
147
+ f"${agent.get('cost_per_token', 0):.4f}"
148
+ )
149
+
150
+ console.print(table)
151
+
152
+
153
+ @network_group.command()
154
+ @click.option("--active", is_flag=True, help="Show only active jobs")
155
+ @click.option("--limit", "-n", type=int, default=10, help="Number of jobs to show")
156
+ @click.pass_context
157
+ async def jobs(ctx, active: bool, limit: int):
158
+ """List network jobs."""
159
+ try:
160
+ from hanzo_network import get_network_jobs
161
+ except ImportError:
162
+ console.print("[red]Error:[/red] hanzo-network not installed")
163
+ return
164
+
165
+ with console.status("Loading jobs..."):
166
+ try:
167
+ jobs = await get_network_jobs(active_only=active, limit=limit)
168
+ except Exception as e:
169
+ console.print(f"[red]Failed to load jobs: {e}[/red]")
170
+ return
171
+
172
+ if not jobs:
173
+ console.print("[yellow]No jobs found[/yellow]")
174
+ return
175
+
176
+ table = Table(title="Network Jobs")
177
+ table.add_column("ID", style="cyan")
178
+ table.add_column("Status", style="green")
179
+ table.add_column("Agents", style="yellow")
180
+ table.add_column("Created", style="blue")
181
+ table.add_column("Duration", style="magenta")
182
+
183
+ for job in jobs:
184
+ table.add_row(
185
+ job["id"][:8],
186
+ job["status"],
187
+ str(job["num_agents"]),
188
+ job["created_at"],
189
+ f"{job.get('duration', 0)}s" if job.get("duration") else "-"
190
+ )
191
+
192
+ console.print(table)
193
+
194
+
195
+ @network_group.command()
196
+ @click.argument("job_id")
197
+ @click.pass_context
198
+ async def job(ctx, job_id: str):
199
+ """Show job details."""
200
+ try:
201
+ from hanzo_network import get_job_details
202
+ except ImportError:
203
+ console.print("[red]Error:[/red] hanzo-network not installed")
204
+ return
205
+
206
+ with console.status("Loading job details..."):
207
+ try:
208
+ job = await get_job_details(job_id)
209
+ except Exception as e:
210
+ console.print(f"[red]Failed to load job: {e}[/red]")
211
+ return
212
+
213
+ console.print(f"[cyan]Job {job_id}[/cyan]")
214
+ console.print(f" Status: {job['status']}")
215
+ console.print(f" Created: {job['created_at']}")
216
+ console.print(f" Agents: {job['num_agents']}")
217
+ console.print(f" Mode: {job['mode']}")
218
+
219
+ if job["status"] == "completed":
220
+ console.print(f" Duration: {job['duration']}s")
221
+ console.print(f" Cost: ${job.get('total_cost', 0):.4f}")
222
+
223
+ console.print(f"\n[cyan]Prompt:[/cyan]")
224
+ console.print(job["prompt"])
225
+
226
+ if job["status"] == "completed" and job.get("results"):
227
+ console.print("\n[cyan]Results:[/cyan]")
228
+ for i, result in enumerate(job["results"], 1):
229
+ console.print(f"\n[yellow]Agent {i}:[/yellow]")
230
+ console.print(result["content"])
231
+
232
+
233
+ @network_group.command()
234
+ @click.option("--name", "-n", default="default", help="Swarm name")
235
+ @click.option("--agents", "-a", type=int, default=5, help="Number of agents")
236
+ @click.option("--model", "-m", help="Model to use")
237
+ @click.pass_context
238
+ async def swarm(ctx, name: str, agents: int, model: str):
239
+ """Start a local agent swarm."""
240
+ try:
241
+ from hanzo_network import LocalSwarm
242
+ except ImportError:
243
+ console.print("[red]Error:[/red] hanzo-network not installed")
244
+ return
245
+
246
+ swarm = LocalSwarm(name=name, size=agents, model=model)
247
+
248
+ with Progress(
249
+ SpinnerColumn(),
250
+ TextColumn("[progress.description]{task.description}"),
251
+ console=console,
252
+ ) as progress:
253
+ task = progress.add_task("Starting swarm...", total=None)
254
+
255
+ try:
256
+ await swarm.start()
257
+ progress.update(task, completed=True)
258
+ except Exception as e:
259
+ progress.stop()
260
+ console.print(f"[red]Failed to start swarm: {e}[/red]")
261
+ return
262
+
263
+ console.print(f"[green]✓[/green] Swarm '{name}' started with {agents} agents")
264
+ console.print("Use 'hanzo network dispatch --mode local' to send work to swarm")
265
+ console.print("\nPress Ctrl+C to stop swarm")
266
+
267
+ try:
268
+ # Keep swarm running
269
+ await swarm.run_forever()
270
+ except KeyboardInterrupt:
271
+ console.print("\n[yellow]Stopping swarm...[/yellow]")
272
+ await swarm.stop()
273
+ console.print("[green]✓[/green] Swarm stopped")
274
+
275
+
276
+ @network_group.command()
277
+ @click.pass_context
278
+ async def stats(ctx):
279
+ """Show network statistics."""
280
+ try:
281
+ from hanzo_network import get_network_stats
282
+ except ImportError:
283
+ console.print("[red]Error:[/red] hanzo-network not installed")
284
+ return
285
+
286
+ with console.status("Loading network stats..."):
287
+ try:
288
+ stats = await get_network_stats()
289
+ except Exception as e:
290
+ console.print(f"[red]Failed to load stats: {e}[/red]")
291
+ return
292
+
293
+ console.print("[cyan]Network Statistics[/cyan]")
294
+ console.print(f" Total agents: {stats['total_agents']}")
295
+ console.print(f" Active agents: {stats['active_agents']}")
296
+ console.print(f" Total jobs: {stats['total_jobs']}")
297
+ console.print(f" Active jobs: {stats['active_jobs']}")
298
+ console.print(f" Success rate: {stats['success_rate']}%")
299
+
300
+ console.print(f"\n[cyan]Performance:[/cyan]")
301
+ console.print(f" Average latency: {stats['avg_latency']}ms")
302
+ console.print(f" Average job time: {stats['avg_job_time']}s")
303
+ console.print(f" Throughput: {stats['throughput']} jobs/min")
304
+
305
+ console.print(f"\n[cyan]Economics:[/cyan]")
306
+ console.print(f" Total tokens: {stats['total_tokens']:,}")
307
+ console.print(f" Average cost: ${stats['avg_cost']:.4f}/job")
308
+ console.print(f" Total cost: ${stats['total_cost']:.2f}")
309
+
310
+
311
+ @network_group.command()
312
+ @click.option("--enable/--disable", default=True, help="Enable or disable discovery")
313
+ @click.pass_context
314
+ async def discovery(ctx, enable: bool):
315
+ """Configure network discovery."""
316
+ try:
317
+ from hanzo_network import configure_discovery
318
+ except ImportError:
319
+ console.print("[red]Error:[/red] hanzo-network not installed")
320
+ return
321
+
322
+ try:
323
+ await configure_discovery(enabled=enable)
324
+
325
+ if enable:
326
+ console.print("[green]✓[/green] Network discovery enabled")
327
+ console.print("Your agents will be discoverable by the network")
328
+ else:
329
+ console.print("[green]✓[/green] Network discovery disabled")
330
+ console.print("Your agents will only be accessible locally")
331
+
332
+ except Exception as e:
333
+ console.print(f"[red]Failed to configure discovery: {e}[/red]")
hanzo/commands/repl.py ADDED
@@ -0,0 +1,186 @@
1
+ """REPL command for interactive AI sessions."""
2
+
3
+ import os
4
+ import sys
5
+ from typing import Optional
6
+
7
+ import click
8
+
9
+ from ..utils.output import console
10
+
11
+
12
+ @click.group(name="repl")
13
+ def repl_group():
14
+ """Interactive REPL for AI and MCP tools."""
15
+ pass
16
+
17
+
18
+ @repl_group.command()
19
+ @click.option("--model", "-m", help="Default model to use")
20
+ @click.option("--local/--cloud", default=False, help="Use local cluster")
21
+ @click.option("--ipython", is_flag=True, help="Use IPython interface")
22
+ @click.option("--tui", is_flag=True, help="Use TUI interface")
23
+ @click.option("--voice", is_flag=True, help="Enable voice mode")
24
+ @click.pass_context
25
+ def start(ctx, model: str, local: bool, ipython: bool, tui: bool, voice: bool):
26
+ """Start interactive REPL (like Claude Code in terminal)."""
27
+ try:
28
+ # Set up environment
29
+ if model:
30
+ os.environ["HANZO_DEFAULT_MODEL"] = model
31
+ if local:
32
+ os.environ["HANZO_USE_LOCAL"] = "true"
33
+ if voice:
34
+ os.environ["HANZO_ENABLE_VOICE"] = "true"
35
+
36
+ if ipython:
37
+ from hanzo_repl.ipython_repl import main
38
+ elif tui:
39
+ from hanzo_repl.textual_repl import main
40
+ else:
41
+ from hanzo_repl.cli import main
42
+
43
+ console.print("[cyan]Starting Hanzo REPL...[/cyan]")
44
+ console.print("All MCP tools available. Type 'help' for commands.\n")
45
+
46
+ sys.exit(main())
47
+
48
+ except ImportError:
49
+ console.print("[red]Error:[/red] hanzo-repl not installed")
50
+ console.print("Install with: pip install hanzo[repl]")
51
+ console.print("\nFeatures:")
52
+ console.print(" • Direct access to 70+ MCP tools")
53
+ console.print(" • Chat with AI that can use tools")
54
+ console.print(" • IPython magic commands")
55
+ console.print(" • Beautiful TUI interface")
56
+ console.print(" • Voice mode (optional)")
57
+
58
+
59
+ @repl_group.command()
60
+ @click.pass_context
61
+ def info(ctx):
62
+ """Show REPL information and status."""
63
+ try:
64
+ from hanzo_repl import __version__
65
+ import hanzo_mcp
66
+
67
+ console.print("[cyan]Hanzo REPL[/cyan]")
68
+ console.print(f" Version: {__version__}")
69
+ console.print(f" MCP Tools: {len(hanzo_mcp.get_all_tools())}")
70
+
71
+ # Check available interfaces
72
+ interfaces = []
73
+ try:
74
+ import IPython
75
+ interfaces.append("IPython")
76
+ except ImportError:
77
+ pass
78
+
79
+ try:
80
+ import textual
81
+ interfaces.append("TUI")
82
+ except ImportError:
83
+ pass
84
+
85
+ try:
86
+ import speech_recognition
87
+ interfaces.append("Voice")
88
+ except ImportError:
89
+ pass
90
+
91
+ console.print(f" Interfaces: {', '.join(interfaces) or 'Basic'}")
92
+
93
+ # Check LLM providers
94
+ providers = []
95
+ if os.environ.get("OPENAI_API_KEY"):
96
+ providers.append("OpenAI")
97
+ if os.environ.get("ANTHROPIC_API_KEY"):
98
+ providers.append("Anthropic")
99
+ if os.environ.get("HANZO_API_KEY"):
100
+ providers.append("Hanzo AI")
101
+
102
+ console.print(f" Providers: {', '.join(providers) or 'None configured'}")
103
+
104
+ if not providers:
105
+ console.print("\n[yellow]No LLM providers configured[/yellow]")
106
+ console.print("Set one of: OPENAI_API_KEY, ANTHROPIC_API_KEY, HANZO_API_KEY")
107
+
108
+ except ImportError:
109
+ console.print("[red]Error:[/red] hanzo-repl not installed")
110
+
111
+
112
+ @repl_group.command()
113
+ @click.option("--interface", type=click.Choice(["all", "ipython", "tui", "voice"]), default="all")
114
+ @click.pass_context
115
+ def install_extras(ctx, interface: str):
116
+ """Install optional REPL components."""
117
+ import subprocess
118
+
119
+ packages = {
120
+ "ipython": ["ipython>=8.0.0", "jupyter>=1.0.0"],
121
+ "tui": ["textual>=0.41.0", "textual-dev>=1.2.0"],
122
+ "voice": ["speechrecognition>=3.10.0", "pyttsx3>=2.90", "pyaudio>=0.2.11"]
123
+ }
124
+
125
+ if interface == "all":
126
+ to_install = []
127
+ for pkgs in packages.values():
128
+ to_install.extend(pkgs)
129
+ else:
130
+ to_install = packages.get(interface, [])
131
+
132
+ if to_install:
133
+ console.print(f"[cyan]Installing {interface} components...[/cyan]")
134
+ cmd = [sys.executable, "-m", "pip", "install"] + to_install
135
+
136
+ try:
137
+ subprocess.run(cmd, check=True)
138
+ console.print(f"[green]✓[/green] Installed {interface} components")
139
+ except subprocess.CalledProcessError:
140
+ console.print(f"[red]Failed to install components[/red]")
141
+ console.print("Try manually: pip install hanzo-repl[voice]")
142
+
143
+
144
+ @repl_group.command()
145
+ @click.argument("command", nargs=-1, required=True)
146
+ @click.option("--model", "-m", help="Model to use")
147
+ @click.pass_context
148
+ def exec(ctx, command: tuple, model: str):
149
+ """Execute a command in REPL and exit."""
150
+ try:
151
+ from hanzo_repl import create_repl
152
+ import asyncio
153
+
154
+ repl = create_repl(model=model)
155
+ command_str = " ".join(command)
156
+
157
+ async def run():
158
+ result = await repl.execute(command_str)
159
+ console.print(result)
160
+
161
+ asyncio.run(run())
162
+
163
+ except ImportError:
164
+ console.print("[red]Error:[/red] hanzo-repl not installed")
165
+ except Exception as e:
166
+ console.print(f"[red]Error: {e}[/red]")
167
+
168
+
169
+ @repl_group.command()
170
+ @click.pass_context
171
+ def demo(ctx):
172
+ """Run REPL demo showcasing features."""
173
+ try:
174
+ from hanzo_repl.demos import run_demo
175
+
176
+ console.print("[cyan]Running Hanzo REPL demo...[/cyan]\n")
177
+ run_demo()
178
+
179
+ except ImportError:
180
+ console.print("[red]Error:[/red] hanzo-repl not installed")
181
+ console.print("\nThe demo would show:")
182
+ console.print(" • File operations with MCP tools")
183
+ console.print(" • Code search and analysis")
184
+ console.print(" • AI chat with tool usage")
185
+ console.print(" • IPython magic commands")
186
+ console.print(" • Voice interaction (if available)")