hanzo 0.3.24__tar.gz → 0.3.25__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.

Files changed (43) hide show
  1. {hanzo-0.3.24 → hanzo-0.3.25}/PKG-INFO +1 -1
  2. {hanzo-0.3.24 → hanzo-0.3.25}/pyproject.toml +1 -1
  3. {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/__init__.py +2 -2
  4. {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/cli.py +13 -5
  5. hanzo-0.3.25/src/hanzo/commands/auth.py +268 -0
  6. hanzo-0.3.24/src/hanzo/commands/auth.py → hanzo-0.3.25/src/hanzo/commands/auth_broken.py +80 -31
  7. {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/commands/chat.py +3 -0
  8. hanzo-0.3.25/src/hanzo/interactive/enhanced_repl.py +513 -0
  9. {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/interactive/repl.py +2 -2
  10. hanzo-0.3.25/src/hanzo/ui/__init__.py +13 -0
  11. hanzo-0.3.25/src/hanzo/ui/inline_startup.py +136 -0
  12. hanzo-0.3.25/src/hanzo/ui/startup.py +350 -0
  13. {hanzo-0.3.24 → hanzo-0.3.25}/.gitignore +0 -0
  14. {hanzo-0.3.24 → hanzo-0.3.25}/README.md +0 -0
  15. {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/__main__.py +0 -0
  16. {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/base_agent.py +0 -0
  17. {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/batch_orchestrator.py +0 -0
  18. {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/commands/__init__.py +0 -0
  19. {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/commands/agent.py +0 -0
  20. {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/commands/config.py +0 -0
  21. {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/commands/mcp.py +0 -0
  22. {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/commands/miner.py +0 -0
  23. {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/commands/network.py +0 -0
  24. {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/commands/node.py +0 -0
  25. {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/commands/repl.py +0 -0
  26. {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/commands/router.py +0 -0
  27. {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/commands/tools.py +0 -0
  28. {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/dev.py +0 -0
  29. {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/fallback_handler.py +0 -0
  30. {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/interactive/__init__.py +0 -0
  31. {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/interactive/dashboard.py +0 -0
  32. {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/mcp_server.py +0 -0
  33. {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/memory_manager.py +0 -0
  34. {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/model_registry.py +0 -0
  35. {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/orchestrator_config.py +0 -0
  36. {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/rate_limiter.py +0 -0
  37. {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/repl.py +0 -0
  38. {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/router/__init__.py +0 -0
  39. {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/streaming.py +0 -0
  40. {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/utils/__init__.py +0 -0
  41. {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/utils/config.py +0 -0
  42. {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/utils/net_check.py +0 -0
  43. {hanzo-0.3.24 → hanzo-0.3.25}/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.24
3
+ Version: 0.3.25
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "hanzo"
3
- version = "0.3.24"
3
+ version = "0.3.25"
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"},
@@ -1,6 +1,6 @@
1
1
  """Hanzo - Complete AI Infrastructure Platform with CLI, Router, MCP, and Agent Runtime."""
2
2
 
3
- __version__ = "0.3.2"
4
- __all__ = ["main", "cli"]
3
+ __version__ = "0.3.25"
4
+ __all__ = ["main", "cli", "__version__"]
5
5
 
6
6
  from .cli import cli, main
@@ -25,9 +25,11 @@ from .commands import (
25
25
  )
26
26
  from .utils.output import console
27
27
  from .interactive.repl import HanzoREPL
28
+ from .interactive.enhanced_repl import EnhancedHanzoREPL
29
+ from .ui.startup import show_startup
28
30
 
29
31
  # Version
30
- __version__ = "0.3.22"
32
+ __version__ = "0.3.23"
31
33
 
32
34
 
33
35
  @click.group(invoke_without_command=True)
@@ -55,14 +57,20 @@ def cli(ctx, verbose: bool, json: bool, config: Optional[str]):
55
57
 
56
58
  if os.environ.get("HANZO_COMPUTE_NODE") == "1":
57
59
  # Start as a compute node
58
-
59
60
  asyncio.run(start_compute_node(ctx))
60
61
  else:
62
+ # Show startup UI (unless in quiet mode)
63
+ if not ctx.obj.get("quiet") and not os.environ.get("HANZO_NO_STARTUP"):
64
+ show_startup(minimal=os.environ.get("HANZO_MINIMAL_UI") == "1")
65
+
61
66
  # Enter interactive REPL mode
62
- console.print("[bold cyan]Hanzo AI - Interactive Mode[/bold cyan]")
63
- console.print("Type 'help' for commands, 'exit' to quit\n")
64
67
  try:
65
- repl = HanzoREPL(console=console)
68
+ # Use enhanced REPL if available, otherwise fallback
69
+ use_enhanced = os.environ.get("HANZO_ENHANCED_REPL", "1") == "1"
70
+ if use_enhanced:
71
+ repl = EnhancedHanzoREPL(console=console)
72
+ else:
73
+ repl = HanzoREPL(console=console)
66
74
  asyncio.run(repl.run())
67
75
  except KeyboardInterrupt:
68
76
  console.print("\n[yellow]Interrupted[/yellow]")
@@ -0,0 +1,268 @@
1
+ """Authentication commands for Hanzo CLI."""
2
+
3
+ import os
4
+ import json
5
+ from pathlib import Path
6
+ from datetime import datetime
7
+ from typing import Optional
8
+
9
+ import click
10
+ from rich.prompt import Prompt
11
+ from rich.panel import Panel
12
+ from rich.table import Table
13
+ from rich import box
14
+
15
+ from ..utils.output import console
16
+
17
+
18
+ class AuthManager:
19
+ """Manage Hanzo authentication."""
20
+
21
+ def __init__(self):
22
+ self.config_dir = Path.home() / ".hanzo"
23
+ self.auth_file = self.config_dir / "auth.json"
24
+
25
+ def load_auth(self) -> dict:
26
+ """Load authentication data."""
27
+ if self.auth_file.exists():
28
+ try:
29
+ return json.loads(self.auth_file.read_text())
30
+ except:
31
+ pass
32
+ return {}
33
+
34
+ def save_auth(self, auth: dict):
35
+ """Save authentication data."""
36
+ self.config_dir.mkdir(exist_ok=True)
37
+ self.auth_file.write_text(json.dumps(auth, indent=2))
38
+
39
+ def is_authenticated(self) -> bool:
40
+ """Check if authenticated."""
41
+ if os.getenv("HANZO_API_KEY"):
42
+ return True
43
+ auth = self.load_auth()
44
+ return bool(auth.get("api_key") or auth.get("logged_in"))
45
+
46
+ def get_api_key(self) -> Optional[str]:
47
+ """Get API key."""
48
+ if os.getenv("HANZO_API_KEY"):
49
+ return os.getenv("HANZO_API_KEY")
50
+ auth = self.load_auth()
51
+ return auth.get("api_key")
52
+
53
+
54
+ @click.group(name="auth")
55
+ def auth_group():
56
+ """Manage Hanzo authentication."""
57
+ pass
58
+
59
+
60
+ @auth_group.command()
61
+ @click.option("--email", "-e", help="Email address")
62
+ @click.option("--password", "-p", help="Password (not recommended, use prompt)")
63
+ @click.option("--api-key", "-k", help="API key for direct authentication")
64
+ @click.option("--sso", is_flag=True, help="Use SSO authentication")
65
+ @click.pass_context
66
+ def login(ctx, email: str, password: str, api_key: str, sso: bool):
67
+ """Login to Hanzo AI."""
68
+ auth_mgr = AuthManager()
69
+
70
+ # Check if already authenticated
71
+ if auth_mgr.is_authenticated():
72
+ console.print("[yellow]Already authenticated[/yellow]")
73
+ auth = auth_mgr.load_auth()
74
+ if auth.get("email"):
75
+ console.print(f"Logged in as: {auth['email']}")
76
+ return
77
+
78
+ try:
79
+ if api_key:
80
+ # Direct API key authentication
81
+ console.print("Authenticating with API key...")
82
+ auth = {
83
+ "api_key": api_key,
84
+ "logged_in": True,
85
+ "last_login": datetime.now().isoformat()
86
+ }
87
+ auth_mgr.save_auth(auth)
88
+ console.print("[green]✓[/green] Successfully authenticated with API key")
89
+
90
+ elif sso:
91
+ # SSO authentication via browser
92
+ console.print("Opening browser for SSO login...")
93
+ console.print("If browser doesn't open, visit: https://iam.hanzo.ai/login")
94
+
95
+ # Try using hanzoai if available
96
+ try:
97
+ from hanzoai.auth import HanzoAuth
98
+ hanzo_auth = HanzoAuth()
99
+ # SSO not implemented yet
100
+ console.print("[yellow]SSO authentication not yet implemented[/yellow]")
101
+ return
102
+
103
+ auth = {
104
+ "email": result.get("email"),
105
+ "logged_in": True,
106
+ "last_login": datetime.now().isoformat()
107
+ }
108
+ auth_mgr.save_auth(auth)
109
+ console.print(f"[green]✓[/green] Logged in as {result.get('email')}")
110
+ except ImportError:
111
+ console.print("[yellow]SSO requires hanzoai package[/yellow]")
112
+ console.print("Install with: pip install hanzoai")
113
+
114
+ else:
115
+ # Email/password authentication
116
+ if not email:
117
+ email = Prompt.ask("Email")
118
+ if not password:
119
+ password = Prompt.ask("Password", password=True)
120
+
121
+ console.print("Authenticating...")
122
+
123
+ # Try using hanzoai if available
124
+ try:
125
+ from hanzoai.auth import HanzoAuth
126
+ hanzo_auth = HanzoAuth()
127
+ # Email auth not implemented yet
128
+ console.print("[yellow]Email authentication not yet implemented[/yellow]")
129
+ console.print("[dim]Saving credentials locally for development[/dim]")
130
+
131
+ auth = {
132
+ "email": email,
133
+ "logged_in": True,
134
+ "last_login": datetime.now().isoformat()
135
+ }
136
+ auth_mgr.save_auth(auth)
137
+ console.print(f"[green]✓[/green] Logged in as {email}")
138
+ except ImportError:
139
+ # Fallback to saving credentials locally
140
+ auth = {
141
+ "email": email,
142
+ "logged_in": True,
143
+ "last_login": datetime.now().isoformat()
144
+ }
145
+ auth_mgr.save_auth(auth)
146
+ console.print(f"[green]✓[/green] Credentials saved for {email}")
147
+
148
+ except Exception as e:
149
+ console.print(f"[red]Login failed: {e}[/red]")
150
+
151
+
152
+ @auth_group.command()
153
+ @click.pass_context
154
+ def logout(ctx):
155
+ """Logout from Hanzo AI."""
156
+ auth_mgr = AuthManager()
157
+
158
+ if not auth_mgr.is_authenticated():
159
+ console.print("[yellow]Not logged in[/yellow]")
160
+ return
161
+
162
+ try:
163
+ # Try using hanzoai if available
164
+ try:
165
+ from hanzoai.auth import HanzoAuth
166
+ hanzo_auth = HanzoAuth()
167
+ # Logout not implemented yet
168
+ pass
169
+ except ImportError:
170
+ pass # hanzoai not installed, just clear local auth
171
+
172
+ # Clear local auth
173
+ auth_mgr.save_auth({})
174
+
175
+ console.print("[green]✓[/green] Logged out successfully")
176
+
177
+ except Exception as e:
178
+ console.print(f"[red]Logout failed: {e}[/red]")
179
+
180
+
181
+ @auth_group.command()
182
+ @click.pass_context
183
+ def status(ctx):
184
+ """Show authentication status."""
185
+ auth_mgr = AuthManager()
186
+
187
+ # Create status table
188
+ table = Table(title="Authentication Status", box=box.ROUNDED)
189
+ table.add_column("Property", style="cyan")
190
+ table.add_column("Value", style="white")
191
+
192
+ if auth_mgr.is_authenticated():
193
+ auth = auth_mgr.load_auth()
194
+
195
+ table.add_row("Status", "✅ Authenticated")
196
+
197
+ # Show auth method
198
+ if os.getenv("HANZO_API_KEY"):
199
+ table.add_row("Method", "Environment Variable")
200
+ api_key = os.getenv("HANZO_API_KEY")
201
+ table.add_row("API Key", f"{api_key[:8]}...{api_key[-4:]}")
202
+ elif auth.get("api_key"):
203
+ table.add_row("Method", "API Key")
204
+ table.add_row("API Key", f"{auth['api_key'][:8]}...")
205
+ elif auth.get("email"):
206
+ table.add_row("Method", "Email/Password")
207
+ table.add_row("Email", auth['email'])
208
+
209
+ if auth.get("last_login"):
210
+ table.add_row("Last Login", auth['last_login'])
211
+
212
+ else:
213
+ table.add_row("Status", "❌ Not authenticated")
214
+ table.add_row("Action", "Run 'hanzo auth login' to authenticate")
215
+
216
+ console.print(table)
217
+
218
+
219
+ @auth_group.command()
220
+ def whoami():
221
+ """Show current user information."""
222
+ auth_mgr = AuthManager()
223
+
224
+ if not auth_mgr.is_authenticated():
225
+ console.print("[yellow]Not logged in[/yellow]")
226
+ console.print("[dim]Run 'hanzo auth login' to authenticate[/dim]")
227
+ return
228
+
229
+ auth = auth_mgr.load_auth()
230
+
231
+ # Create user info panel
232
+ lines = []
233
+
234
+ if auth.get("email"):
235
+ lines.append(f"[cyan]Email:[/cyan] {auth['email']}")
236
+
237
+ if os.getenv("HANZO_API_KEY"):
238
+ lines.append("[cyan]API Key:[/cyan] Set via environment")
239
+ elif auth.get("api_key"):
240
+ lines.append(f"[cyan]API Key:[/cyan] {auth['api_key'][:8]}...")
241
+
242
+ if auth.get("last_login"):
243
+ lines.append(f"[cyan]Last Login:[/cyan] {auth['last_login']}")
244
+
245
+ content = "\n".join(lines) if lines else "[dim]No user information available[/dim]"
246
+
247
+ console.print(Panel(
248
+ content,
249
+ title="[bold cyan]User Information[/bold cyan]",
250
+ box=box.ROUNDED
251
+ ))
252
+
253
+
254
+ @auth_group.command(name="set-key")
255
+ @click.argument("api_key")
256
+ def set_key(api_key: str):
257
+ """Set API key for authentication."""
258
+ auth_mgr = AuthManager()
259
+
260
+ auth = auth_mgr.load_auth()
261
+ auth["api_key"] = api_key
262
+ auth["logged_in"] = True
263
+ auth["last_login"] = datetime.now().isoformat()
264
+
265
+ auth_mgr.save_auth(auth)
266
+
267
+ console.print("[green]✓[/green] API key saved successfully")
268
+ console.print("[dim]You can now use Hanzo Cloud services[/dim]")
@@ -1,14 +1,56 @@
1
1
  """Authentication commands."""
2
2
 
3
3
  import os
4
+ import json
4
5
  from pathlib import Path
6
+ from datetime import datetime
7
+ from typing import Optional
5
8
 
6
9
  import click
7
10
  from rich.prompt import Prompt
11
+ from rich.panel import Panel
12
+ from rich.table import Table
13
+ from rich import box
8
14
 
9
15
  from ..utils.output import console
10
16
 
11
17
 
18
+ class AuthManager:
19
+ """Manage Hanzo authentication."""
20
+
21
+ def __init__(self):
22
+ self.config_dir = Path.home() / ".hanzo"
23
+ self.auth_file = self.config_dir / "auth.json"
24
+
25
+ def load_auth(self) -> dict:
26
+ """Load authentication data."""
27
+ if self.auth_file.exists():
28
+ try:
29
+ return json.loads(self.auth_file.read_text())
30
+ except:
31
+ pass
32
+ return {}
33
+
34
+ def save_auth(self, auth: dict):
35
+ """Save authentication data."""
36
+ self.config_dir.mkdir(exist_ok=True)
37
+ self.auth_file.write_text(json.dumps(auth, indent=2))
38
+
39
+ def is_authenticated(self) -> bool:
40
+ """Check if authenticated."""
41
+ if os.getenv("HANZO_API_KEY"):
42
+ return True
43
+ auth = self.load_auth()
44
+ return bool(auth.get("api_key") or auth.get("logged_in"))
45
+
46
+ def get_api_key(self) -> Optional[str]:
47
+ """Get API key."""
48
+ if os.getenv("HANZO_API_KEY"):
49
+ return os.getenv("HANZO_API_KEY")
50
+ auth = self.load_auth()
51
+ return auth.get("api_key")
52
+
53
+
12
54
  @click.group(name="auth")
13
55
  def auth_group():
14
56
  """Manage Hanzo authentication."""
@@ -83,24 +125,26 @@ async def login(ctx, email: str, password: str, api_key: str, sso: bool):
83
125
  @click.pass_context
84
126
  async def logout(ctx):
85
127
  """Logout from Hanzo AI."""
86
- try:
87
- from hanzoai.auth import HanzoAuth
88
- except ImportError:
89
- console.print("[red]Error:[/red] hanzoai not installed")
128
+ auth_mgr = AuthManager()
129
+
130
+ if not auth_mgr.is_authenticated():
131
+ console.print("[yellow]Not logged in[/yellow]")
90
132
  return
91
-
92
- auth = HanzoAuth()
93
-
133
+
94
134
  try:
95
- await auth.logout()
96
-
97
- # Remove saved credentials
98
- config_file = Path.home() / ".hanzo" / "auth.json"
99
- if config_file.exists():
100
- config_file.unlink()
101
-
135
+ # Try using hanzoai if available
136
+ try:
137
+ from hanzoai.auth import HanzoAuth
138
+ hanzo_auth = HanzoAuth()
139
+ await hanzo_auth.logout()
140
+ except ImportError:
141
+ pass # hanzoai not installed, just clear local auth
142
+
143
+ # Clear local auth
144
+ auth_mgr.save_auth({})
145
+
102
146
  console.print("[green]✓[/green] Logged out successfully")
103
-
147
+
104
148
  except Exception as e:
105
149
  console.print(f"[red]Logout failed: {e}[/red]")
106
150
 
@@ -109,22 +153,27 @@ async def logout(ctx):
109
153
  @click.pass_context
110
154
  async def status(ctx):
111
155
  """Show authentication status."""
112
- # Check environment variable
113
- if api_key := os.environ.get("HANZO_API_KEY"):
114
- console.print("[green]✓[/green] HANZO_API_KEY environment variable set")
115
- console.print(f" Key: {api_key[:8]}...{api_key[-4:]}")
116
-
117
- # Check saved credentials
118
- config_file = Path.home() / ".hanzo" / "auth.json"
119
- if config_file.exists():
120
- try:
121
- from hanzoai.auth import HanzoAuth
122
-
123
- auth = HanzoAuth()
124
- creds = await auth.load_credentials(config_file)
125
-
126
- console.print("[green]✓[/green] Saved credentials found")
127
- if email := creds.get("email"):
156
+ auth_mgr = AuthManager()
157
+
158
+ # Create status table
159
+ table = Table(title="Authentication Status", box=box.ROUNDED)
160
+ table.add_column("Property", style="cyan")
161
+ table.add_column("Value", style="white")
162
+
163
+ if auth_mgr.is_authenticated():
164
+ auth = auth_mgr.load_auth()
165
+
166
+ table.add_row("Status", "✅ Authenticated")
167
+
168
+ # Show auth method
169
+ if os.getenv("HANZO_API_KEY"):
170
+ table.add_row("Method", "Environment Variable")
171
+ api_key = os.getenv("HANZO_API_KEY")
172
+ table.add_row("API Key", f"{api_key[:8]}...{api_key[-4:]}")
173
+ elif auth.get("api_key"):
174
+ table.add_row("Method", "API Key")
175
+ table.add_row("API Key", f"{auth['api_key'][:8]}...")
176
+ elif auth.get("email"):
128
177
  console.print(f" Email: {email}")
129
178
  if org := creds.get("organization"):
130
179
  console.print(f" Organization: {org}")
@@ -1,11 +1,14 @@
1
1
  """Chat command for interactive AI conversations."""
2
2
 
3
3
  import asyncio
4
+ import os
4
5
  from typing import Optional
5
6
 
6
7
  import click
7
8
  import httpx
8
9
  from rich.markdown import Markdown
10
+ from rich.panel import Panel
11
+ from rich import box
9
12
 
10
13
  from ..utils.output import console
11
14