hanzo 0.3.21__tar.gz → 0.3.22__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.
- {hanzo-0.3.21 → hanzo-0.3.22}/PKG-INFO +1 -1
- {hanzo-0.3.21 → hanzo-0.3.22}/pyproject.toml +1 -1
- {hanzo-0.3.21 → hanzo-0.3.22}/src/hanzo/cli.py +1 -1
- {hanzo-0.3.21 → hanzo-0.3.22}/src/hanzo/dev.py +74 -30
- {hanzo-0.3.21 → hanzo-0.3.22}/.gitignore +0 -0
- {hanzo-0.3.21 → hanzo-0.3.22}/README.md +0 -0
- {hanzo-0.3.21 → hanzo-0.3.22}/src/hanzo/__init__.py +0 -0
- {hanzo-0.3.21 → hanzo-0.3.22}/src/hanzo/__main__.py +0 -0
- {hanzo-0.3.21 → hanzo-0.3.22}/src/hanzo/commands/__init__.py +0 -0
- {hanzo-0.3.21 → hanzo-0.3.22}/src/hanzo/commands/agent.py +0 -0
- {hanzo-0.3.21 → hanzo-0.3.22}/src/hanzo/commands/auth.py +0 -0
- {hanzo-0.3.21 → hanzo-0.3.22}/src/hanzo/commands/chat.py +0 -0
- {hanzo-0.3.21 → hanzo-0.3.22}/src/hanzo/commands/cluster.py +0 -0
- {hanzo-0.3.21 → hanzo-0.3.22}/src/hanzo/commands/config.py +0 -0
- {hanzo-0.3.21 → hanzo-0.3.22}/src/hanzo/commands/mcp.py +0 -0
- {hanzo-0.3.21 → hanzo-0.3.22}/src/hanzo/commands/miner.py +0 -0
- {hanzo-0.3.21 → hanzo-0.3.22}/src/hanzo/commands/network.py +0 -0
- {hanzo-0.3.21 → hanzo-0.3.22}/src/hanzo/commands/repl.py +0 -0
- {hanzo-0.3.21 → hanzo-0.3.22}/src/hanzo/commands/tools.py +0 -0
- {hanzo-0.3.21 → hanzo-0.3.22}/src/hanzo/fallback_handler.py +0 -0
- {hanzo-0.3.21 → hanzo-0.3.22}/src/hanzo/interactive/__init__.py +0 -0
- {hanzo-0.3.21 → hanzo-0.3.22}/src/hanzo/interactive/dashboard.py +0 -0
- {hanzo-0.3.21 → hanzo-0.3.22}/src/hanzo/interactive/repl.py +0 -0
- {hanzo-0.3.21 → hanzo-0.3.22}/src/hanzo/mcp_server.py +0 -0
- {hanzo-0.3.21 → hanzo-0.3.22}/src/hanzo/memory_manager.py +0 -0
- {hanzo-0.3.21 → hanzo-0.3.22}/src/hanzo/orchestrator_config.py +0 -0
- {hanzo-0.3.21 → hanzo-0.3.22}/src/hanzo/rate_limiter.py +0 -0
- {hanzo-0.3.21 → hanzo-0.3.22}/src/hanzo/repl.py +0 -0
- {hanzo-0.3.21 → hanzo-0.3.22}/src/hanzo/router/__init__.py +0 -0
- {hanzo-0.3.21 → hanzo-0.3.22}/src/hanzo/streaming.py +0 -0
- {hanzo-0.3.21 → hanzo-0.3.22}/src/hanzo/utils/__init__.py +0 -0
- {hanzo-0.3.21 → hanzo-0.3.22}/src/hanzo/utils/config.py +0 -0
- {hanzo-0.3.21 → hanzo-0.3.22}/src/hanzo/utils/net_check.py +0 -0
- {hanzo-0.3.21 → hanzo-0.3.22}/src/hanzo/utils/output.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hanzo
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.22
|
|
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
|
|
@@ -697,34 +697,35 @@ class HanzoDevREPL:
|
|
|
697
697
|
padding=(0, 1)
|
|
698
698
|
))
|
|
699
699
|
console.print()
|
|
700
|
+
|
|
701
|
+
# Check for available API keys and show status
|
|
702
|
+
from .fallback_handler import FallbackHandler
|
|
703
|
+
handler = FallbackHandler()
|
|
704
|
+
if not handler.fallback_order:
|
|
705
|
+
console.print("[yellow]⚠️ No API keys detected[/yellow]")
|
|
706
|
+
console.print("[dim]Set OPENAI_API_KEY or ANTHROPIC_API_KEY to enable AI[/dim]")
|
|
707
|
+
console.print()
|
|
708
|
+
else:
|
|
709
|
+
primary = handler.fallback_order[0][1]
|
|
710
|
+
console.print(f"[green]✅ Using {primary} for AI responses[/green]")
|
|
711
|
+
console.print()
|
|
700
712
|
|
|
701
713
|
while True:
|
|
702
714
|
try:
|
|
703
|
-
#
|
|
704
|
-
console.print("[dim white]╭" + "─" * 78 + "╮[/dim white]")
|
|
705
|
-
|
|
706
|
-
# Get input with styled prompt inside the box
|
|
707
|
-
console.print("[dim white]│[/dim white] ", end="")
|
|
708
|
-
|
|
715
|
+
# Simple prompt without box borders to avoid rendering issues
|
|
709
716
|
try:
|
|
710
|
-
#
|
|
711
|
-
# The visual box is drawn by console.print statements
|
|
717
|
+
# Add spacing to prevent UI cutoff at bottom
|
|
712
718
|
user_input = await asyncio.get_event_loop().run_in_executor(
|
|
713
719
|
None,
|
|
714
720
|
input,
|
|
715
|
-
'› ' #
|
|
721
|
+
'› ' # Clean prompt
|
|
716
722
|
)
|
|
717
|
-
|
|
718
|
-
# Draw input box border (bottom)
|
|
719
|
-
console.print("[dim white]╰" + "─" * 78 + "╯[/dim white]")
|
|
723
|
+
console.print() # Add spacing after input
|
|
720
724
|
|
|
721
725
|
except EOFError:
|
|
722
726
|
console.print() # New line before exit
|
|
723
|
-
console.print("[dim white]╰" + "─" * 78 + "╯[/dim white]")
|
|
724
727
|
break
|
|
725
728
|
except KeyboardInterrupt:
|
|
726
|
-
console.print() # Complete the box
|
|
727
|
-
console.print("[dim white]╰" + "─" * 78 + "╯[/dim white]")
|
|
728
729
|
console.print("\n[dim yellow]Use /exit to quit[/dim]")
|
|
729
730
|
continue
|
|
730
731
|
|
|
@@ -1044,8 +1045,25 @@ Examples:
|
|
|
1044
1045
|
await self._use_local_model(message)
|
|
1045
1046
|
return
|
|
1046
1047
|
|
|
1047
|
-
#
|
|
1048
|
-
|
|
1048
|
+
# Use the fallback handler to intelligently try available options
|
|
1049
|
+
from .fallback_handler import smart_chat
|
|
1050
|
+
response = await smart_chat(message, console=console)
|
|
1051
|
+
|
|
1052
|
+
if response:
|
|
1053
|
+
from rich.panel import Panel
|
|
1054
|
+
console.print()
|
|
1055
|
+
console.print(Panel(
|
|
1056
|
+
response,
|
|
1057
|
+
title="[bold cyan]AI Response[/bold cyan]",
|
|
1058
|
+
title_align="left",
|
|
1059
|
+
border_style="dim cyan",
|
|
1060
|
+
padding=(1, 2)
|
|
1061
|
+
))
|
|
1062
|
+
return
|
|
1063
|
+
|
|
1064
|
+
# Try OpenAI first explicitly (in case fallback handler missed it)
|
|
1065
|
+
openai_key = os.environ.get("OPENAI_API_KEY") or os.getenv("OPENAI_API_KEY")
|
|
1066
|
+
if openai_key:
|
|
1049
1067
|
try:
|
|
1050
1068
|
from openai import AsyncOpenAI
|
|
1051
1069
|
|
|
@@ -1578,13 +1596,10 @@ async def run_dev_orchestrator(**kwargs):
|
|
|
1578
1596
|
console_obj.print("[red]Failed to initialize network[/red]")
|
|
1579
1597
|
return
|
|
1580
1598
|
else:
|
|
1581
|
-
# Fallback to
|
|
1582
|
-
console_obj.print(f"[cyan]Mode:
|
|
1583
|
-
console_obj.print(
|
|
1584
|
-
f"Instances: {instances} (1 primary + {instances-1} critic{'s' if instances > 2 else ''})"
|
|
1585
|
-
)
|
|
1599
|
+
# Fallback to API mode
|
|
1600
|
+
console_obj.print(f"[cyan]Mode: AI Chat[/cyan]")
|
|
1601
|
+
console_obj.print(f"Model: {orchestrator_model}")
|
|
1586
1602
|
console_obj.print(f"MCP Tools: {'Enabled' if mcp_tools else 'Disabled'}")
|
|
1587
|
-
console_obj.print(f"Networking: {'Enabled' if network_mode else 'Disabled'}")
|
|
1588
1603
|
console_obj.print(f"Guardrails: {'Enabled' if guardrails else 'Disabled'}\n")
|
|
1589
1604
|
|
|
1590
1605
|
orchestrator = MultiClaudeOrchestrator(
|
|
@@ -2216,6 +2231,21 @@ class MultiClaudeOrchestrator(HanzoDevOrchestrator):
|
|
|
2216
2231
|
|
|
2217
2232
|
async def initialize(self):
|
|
2218
2233
|
"""Initialize all Claude instances with MCP networking."""
|
|
2234
|
+
# Check if Claude is available first
|
|
2235
|
+
claude_available = False
|
|
2236
|
+
try:
|
|
2237
|
+
import shutil
|
|
2238
|
+
if self.claude_code_path and Path(self.claude_code_path).exists():
|
|
2239
|
+
claude_available = True
|
|
2240
|
+
elif shutil.which("claude"):
|
|
2241
|
+
claude_available = True
|
|
2242
|
+
except:
|
|
2243
|
+
pass
|
|
2244
|
+
|
|
2245
|
+
if not claude_available:
|
|
2246
|
+
# Skip Claude instance initialization - will use API fallback silently
|
|
2247
|
+
return
|
|
2248
|
+
|
|
2219
2249
|
self.console.print("[cyan]Initializing Claude instances...[/cyan]")
|
|
2220
2250
|
|
|
2221
2251
|
for i in range(self.num_instances):
|
|
@@ -2237,7 +2267,8 @@ class MultiClaudeOrchestrator(HanzoDevOrchestrator):
|
|
|
2237
2267
|
if success:
|
|
2238
2268
|
self.console.print(f"[green]✓ Instance {i} started[/green]")
|
|
2239
2269
|
else:
|
|
2240
|
-
|
|
2270
|
+
# Don't show error, just skip silently
|
|
2271
|
+
pass
|
|
2241
2272
|
|
|
2242
2273
|
async def _create_instance_config(self, index: int, role: str) -> Dict:
|
|
2243
2274
|
"""Create configuration for a Claude instance."""
|
|
@@ -2377,7 +2408,12 @@ class MultiClaudeOrchestrator(HanzoDevOrchestrator):
|
|
|
2377
2408
|
|
|
2378
2409
|
# Check if instances are initialized
|
|
2379
2410
|
if not self.claude_instances:
|
|
2380
|
-
# No instances started, use
|
|
2411
|
+
# No instances started, use fallback handler for smart routing
|
|
2412
|
+
from .fallback_handler import smart_chat
|
|
2413
|
+
response = await smart_chat(task, console=self.console)
|
|
2414
|
+
if response:
|
|
2415
|
+
return {"output": response, "success": True}
|
|
2416
|
+
# If smart_chat fails, try direct API as last resort
|
|
2381
2417
|
return await self._call_api_model(task)
|
|
2382
2418
|
|
|
2383
2419
|
# Step 1: Primary execution
|
|
@@ -2530,11 +2566,12 @@ class MultiClaudeOrchestrator(HanzoDevOrchestrator):
|
|
|
2530
2566
|
"""Call API-based model and return structured response."""
|
|
2531
2567
|
import os
|
|
2532
2568
|
|
|
2533
|
-
# Try OpenAI
|
|
2534
|
-
|
|
2569
|
+
# Try OpenAI first (check environment variable properly)
|
|
2570
|
+
openai_key = os.environ.get("OPENAI_API_KEY") or os.getenv("OPENAI_API_KEY")
|
|
2571
|
+
if openai_key:
|
|
2535
2572
|
try:
|
|
2536
2573
|
from openai import AsyncOpenAI
|
|
2537
|
-
client = AsyncOpenAI()
|
|
2574
|
+
client = AsyncOpenAI(api_key=openai_key)
|
|
2538
2575
|
response = await client.chat.completions.create(
|
|
2539
2576
|
model="gpt-4",
|
|
2540
2577
|
messages=[{"role": "user", "content": prompt}],
|
|
@@ -2546,10 +2583,11 @@ class MultiClaudeOrchestrator(HanzoDevOrchestrator):
|
|
|
2546
2583
|
logger.error(f"OpenAI API error: {e}")
|
|
2547
2584
|
|
|
2548
2585
|
# Try Anthropic
|
|
2549
|
-
|
|
2586
|
+
anthropic_key = os.environ.get("ANTHROPIC_API_KEY") or os.getenv("ANTHROPIC_API_KEY")
|
|
2587
|
+
if anthropic_key:
|
|
2550
2588
|
try:
|
|
2551
2589
|
from anthropic import AsyncAnthropic
|
|
2552
|
-
client = AsyncAnthropic()
|
|
2590
|
+
client = AsyncAnthropic(api_key=anthropic_key)
|
|
2553
2591
|
response = await client.messages.create(
|
|
2554
2592
|
model="claude-3-5-sonnet-20241022",
|
|
2555
2593
|
messages=[{"role": "user", "content": prompt}],
|
|
@@ -2560,6 +2598,12 @@ class MultiClaudeOrchestrator(HanzoDevOrchestrator):
|
|
|
2560
2598
|
except Exception as e:
|
|
2561
2599
|
logger.error(f"Anthropic API error: {e}")
|
|
2562
2600
|
|
|
2601
|
+
# Try fallback handler as last resort
|
|
2602
|
+
from .fallback_handler import smart_chat
|
|
2603
|
+
response = await smart_chat(prompt, console=None) # No console to avoid duplicate messages
|
|
2604
|
+
if response:
|
|
2605
|
+
return {"output": response, "success": True}
|
|
2606
|
+
|
|
2563
2607
|
return {"output": "No API keys configured. Set OPENAI_API_KEY or ANTHROPIC_API_KEY", "success": False}
|
|
2564
2608
|
|
|
2565
2609
|
async def _validate_improvement(self, original: Dict, improved: Dict) -> bool:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|