hypercli-cli 2026.3.8__tar.gz → 2026.3.13__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.
- {hypercli_cli-2026.3.8 → hypercli_cli-2026.3.13}/PKG-INFO +10 -10
- {hypercli_cli-2026.3.8 → hypercli_cli-2026.3.13}/README.md +6 -6
- hypercli_cli-2026.3.13/hypercli_cli/__init__.py +1 -0
- hypercli_cli-2026.3.8/hypercli_cli/claw.py → hypercli_cli-2026.3.13/hypercli_cli/agent.py +75 -64
- {hypercli_cli-2026.3.8 → hypercli_cli-2026.3.13}/hypercli_cli/agents.py +257 -136
- {hypercli_cli-2026.3.8 → hypercli_cli-2026.3.13}/hypercli_cli/cli.py +3 -3
- {hypercli_cli-2026.3.8 → hypercli_cli-2026.3.13}/hypercli_cli/embed.py +12 -12
- {hypercli_cli-2026.3.8 → hypercli_cli-2026.3.13}/hypercli_cli/onboard.py +24 -23
- {hypercli_cli-2026.3.8 → hypercli_cli-2026.3.13}/hypercli_cli/stt.py +3 -3
- {hypercli_cli-2026.3.8 → hypercli_cli-2026.3.13}/hypercli_cli/voice.py +15 -15
- {hypercli_cli-2026.3.8 → hypercli_cli-2026.3.13}/pyproject.toml +4 -4
- {hypercli_cli-2026.3.8 → hypercli_cli-2026.3.13}/tests/test_exec_shell_dryrun.py +4 -4
- hypercli_cli-2026.3.8/hypercli_cli/__init__.py +0 -1
- {hypercli_cli-2026.3.8 → hypercli_cli-2026.3.13}/.gitignore +0 -0
- {hypercli_cli-2026.3.8 → hypercli_cli-2026.3.13}/hypercli_cli/billing.py +0 -0
- {hypercli_cli-2026.3.8 → hypercli_cli-2026.3.13}/hypercli_cli/comfyui.py +0 -0
- {hypercli_cli-2026.3.8 → hypercli_cli-2026.3.13}/hypercli_cli/flow.py +0 -0
- {hypercli_cli-2026.3.8 → hypercli_cli-2026.3.13}/hypercli_cli/instances.py +0 -0
- {hypercli_cli-2026.3.8 → hypercli_cli-2026.3.13}/hypercli_cli/jobs.py +0 -0
- {hypercli_cli-2026.3.8 → hypercli_cli-2026.3.13}/hypercli_cli/keys.py +0 -0
- {hypercli_cli-2026.3.8 → hypercli_cli-2026.3.13}/hypercli_cli/output.py +0 -0
- {hypercli_cli-2026.3.8 → hypercli_cli-2026.3.13}/hypercli_cli/renders.py +0 -0
- {hypercli_cli-2026.3.8 → hypercli_cli-2026.3.13}/hypercli_cli/tui/__init__.py +0 -0
- {hypercli_cli-2026.3.8 → hypercli_cli-2026.3.13}/hypercli_cli/tui/job_monitor.py +0 -0
- {hypercli_cli-2026.3.8 → hypercli_cli-2026.3.13}/hypercli_cli/user.py +0 -0
- {hypercli_cli-2026.3.8 → hypercli_cli-2026.3.13}/hypercli_cli/wallet.py +0 -0
- {hypercli_cli-2026.3.8 → hypercli_cli-2026.3.13}/tests/test_jobs_list_tags.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hypercli-cli
|
|
3
|
-
Version: 2026.3.
|
|
3
|
+
Version: 2026.3.13
|
|
4
4
|
Summary: CLI for HyperCLI - GPU orchestration and LLM API
|
|
5
5
|
Project-URL: Homepage, https://hypercli.com
|
|
6
6
|
Project-URL: Documentation, https://docs.hypercli.com
|
|
@@ -9,7 +9,7 @@ Author-email: HyperCLI <support@hypercli.com>
|
|
|
9
9
|
License: MIT
|
|
10
10
|
Requires-Python: >=3.10
|
|
11
11
|
Requires-Dist: httpx>=0.27.0
|
|
12
|
-
Requires-Dist: hypercli-sdk>=2026.3.
|
|
12
|
+
Requires-Dist: hypercli-sdk>=2026.3.13
|
|
13
13
|
Requires-Dist: mutagen>=1.47.0
|
|
14
14
|
Requires-Dist: pyyaml>=6.0
|
|
15
15
|
Requires-Dist: rich>=14.2.0
|
|
@@ -19,11 +19,11 @@ Provides-Extra: all
|
|
|
19
19
|
Requires-Dist: argon2-cffi>=25.0.0; extra == 'all'
|
|
20
20
|
Requires-Dist: eth-account>=0.13.0; extra == 'all'
|
|
21
21
|
Requires-Dist: faster-whisper>=1.1.0; extra == 'all'
|
|
22
|
-
Requires-Dist: hypercli-sdk[comfyui]>=2026.3.
|
|
22
|
+
Requires-Dist: hypercli-sdk[comfyui]>=2026.3.13; extra == 'all'
|
|
23
23
|
Requires-Dist: web3>=7.0.0; extra == 'all'
|
|
24
24
|
Requires-Dist: x402[evm,httpx]>=2.0.0; extra == 'all'
|
|
25
25
|
Provides-Extra: comfyui
|
|
26
|
-
Requires-Dist: hypercli-sdk[comfyui]>=2026.3.
|
|
26
|
+
Requires-Dist: hypercli-sdk[comfyui]>=2026.3.13; extra == 'comfyui'
|
|
27
27
|
Provides-Extra: dev
|
|
28
28
|
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
29
29
|
Requires-Dist: ruff>=0.3.0; extra == 'dev'
|
|
@@ -78,14 +78,14 @@ hyper flow text-to-image "a cinematic portrait"
|
|
|
78
78
|
hyper flow text-to-image "a cinematic portrait" --x402
|
|
79
79
|
|
|
80
80
|
# HyperClaw checkout/config
|
|
81
|
-
hyper
|
|
82
|
-
hyper
|
|
83
|
-
hyper
|
|
84
|
-
hyper
|
|
85
|
-
hyper
|
|
81
|
+
hyper agent plans
|
|
82
|
+
hyper agent subscribe 1aiu
|
|
83
|
+
hyper agent config env
|
|
84
|
+
hyper agent exec <agent_id> "ls -la"
|
|
85
|
+
hyper agent shell <agent_id>
|
|
86
86
|
```
|
|
87
87
|
|
|
88
88
|
## Notes
|
|
89
89
|
|
|
90
90
|
- `hyper llm` command surface has been removed.
|
|
91
|
-
- For inference setup, use HyperClaw (`hyper
|
|
91
|
+
- For inference setup, use HyperClaw (`hyper agent config ...`) and your agent/client's OpenAI-compatible configuration.
|
|
@@ -39,14 +39,14 @@ hyper flow text-to-image "a cinematic portrait"
|
|
|
39
39
|
hyper flow text-to-image "a cinematic portrait" --x402
|
|
40
40
|
|
|
41
41
|
# HyperClaw checkout/config
|
|
42
|
-
hyper
|
|
43
|
-
hyper
|
|
44
|
-
hyper
|
|
45
|
-
hyper
|
|
46
|
-
hyper
|
|
42
|
+
hyper agent plans
|
|
43
|
+
hyper agent subscribe 1aiu
|
|
44
|
+
hyper agent config env
|
|
45
|
+
hyper agent exec <agent_id> "ls -la"
|
|
46
|
+
hyper agent shell <agent_id>
|
|
47
47
|
```
|
|
48
48
|
|
|
49
49
|
## Notes
|
|
50
50
|
|
|
51
51
|
- `hyper llm` command surface has been removed.
|
|
52
|
-
- For inference setup, use HyperClaw (`hyper
|
|
52
|
+
- For inference setup, use HyperClaw (`hyper agent config ...`) and your agent/client's OpenAI-compatible configuration.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "2026.3.13"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""HyperAgent inference commands"""
|
|
2
2
|
import asyncio
|
|
3
3
|
import json
|
|
4
4
|
import os
|
|
@@ -13,7 +13,7 @@ from .voice import app as voice_app
|
|
|
13
13
|
from .stt import transcribe as _stt_transcribe
|
|
14
14
|
from .embed import app as embed_app
|
|
15
15
|
|
|
16
|
-
app = typer.Typer(help="
|
|
16
|
+
app = typer.Typer(help="HyperAgent inference commands")
|
|
17
17
|
console = Console()
|
|
18
18
|
|
|
19
19
|
# Register subcommands
|
|
@@ -35,9 +35,9 @@ def transcribe(
|
|
|
35
35
|
"""Transcribe audio to text using faster-whisper (runs locally).
|
|
36
36
|
|
|
37
37
|
Examples:
|
|
38
|
-
hyper
|
|
39
|
-
hyper
|
|
40
|
-
hyper
|
|
38
|
+
hyper agent transcribe voice.ogg
|
|
39
|
+
hyper agent transcribe meeting.mp3 --model large-v3 --language en
|
|
40
|
+
hyper agent transcribe audio.wav --json -o transcript.json
|
|
41
41
|
"""
|
|
42
42
|
_stt_transcribe(audio_file, model, language, device, compute_type, json_output, output)
|
|
43
43
|
|
|
@@ -52,9 +52,9 @@ except ImportError:
|
|
|
52
52
|
X402_AVAILABLE = False
|
|
53
53
|
|
|
54
54
|
HYPERCLI_DIR = Path.home() / ".hypercli"
|
|
55
|
-
|
|
56
|
-
DEV_API_BASE = "https://
|
|
57
|
-
PROD_API_BASE = "https://api.
|
|
55
|
+
AGENT_KEY_PATH = HYPERCLI_DIR / "agent-key.json"
|
|
56
|
+
DEV_API_BASE = "https://api.dev.hypercli.com"
|
|
57
|
+
PROD_API_BASE = "https://api.hypercli.com"
|
|
58
58
|
|
|
59
59
|
|
|
60
60
|
def require_x402_deps():
|
|
@@ -70,7 +70,7 @@ def require_x402_deps():
|
|
|
70
70
|
def subscribe(
|
|
71
71
|
plan_id: str = typer.Argument("1aiu", help="Plan ID: 1aiu, 2aiu, 5aiu, 10aiu (default: 1aiu)"),
|
|
72
72
|
amount: str = typer.Argument(None, help="USDC amount to pay (e.g., '25' for $25). Duration scales proportionally."),
|
|
73
|
-
dev: bool = typer.Option(False, "--dev", help="Use dev API (
|
|
73
|
+
dev: bool = typer.Option(False, "--dev", help="Use dev API (api.dev.hypercli.com)")
|
|
74
74
|
):
|
|
75
75
|
"""Subscribe to a HyperClaw plan via x402 payment.
|
|
76
76
|
|
|
@@ -80,9 +80,9 @@ def subscribe(
|
|
|
80
80
|
- $1 → ~1.3 days
|
|
81
81
|
|
|
82
82
|
Examples:
|
|
83
|
-
hyper
|
|
84
|
-
hyper
|
|
85
|
-
hyper
|
|
83
|
+
hyper agent subscribe 1aiu 25 # Pay $25 for 32 days
|
|
84
|
+
hyper agent subscribe 1aiu 50 # Pay $50 for 64 days
|
|
85
|
+
hyper agent subscribe 5aiu 100 # Pay $100 for 5aiu plan
|
|
86
86
|
"""
|
|
87
87
|
require_x402_deps()
|
|
88
88
|
|
|
@@ -109,7 +109,7 @@ def subscribe(
|
|
|
109
109
|
|
|
110
110
|
# Save key (current)
|
|
111
111
|
HYPERCLI_DIR.mkdir(parents=True, exist_ok=True)
|
|
112
|
-
with open(
|
|
112
|
+
with open(AGENT_KEY_PATH, "w") as f:
|
|
113
113
|
json.dump(result, f, indent=2)
|
|
114
114
|
|
|
115
115
|
# Build history entry with key info
|
|
@@ -128,7 +128,7 @@ def subscribe(
|
|
|
128
128
|
}
|
|
129
129
|
|
|
130
130
|
# Load existing keys or start fresh
|
|
131
|
-
keys_history_path = HYPERCLI_DIR / "
|
|
131
|
+
keys_history_path = HYPERCLI_DIR / "agent-keys.yaml"
|
|
132
132
|
if keys_history_path.exists():
|
|
133
133
|
with open(keys_history_path) as f:
|
|
134
134
|
keys_data = yaml.safe_load(f) or {"keys": []}
|
|
@@ -147,9 +147,9 @@ def subscribe(
|
|
|
147
147
|
console.print(f"Duration: [bold]{result.get('duration_days', 30):.2f} days[/bold]")
|
|
148
148
|
console.print(f"Expires: {result['expires_at']}")
|
|
149
149
|
console.print(f"Limits: {result['tpm_limit']:,} TPM / {result['rpm_limit']:,} RPM")
|
|
150
|
-
console.print(f"\n[green]✓[/green] Key saved to [bold]{
|
|
150
|
+
console.print(f"\n[green]✓[/green] Key saved to [bold]{AGENT_KEY_PATH}[/bold]")
|
|
151
151
|
console.print(f"[green]✓[/green] Key history: [bold]{keys_history_path}[/bold]")
|
|
152
|
-
console.print("\nConfigure OpenClaw with: [bold]hyper
|
|
152
|
+
console.print("\nConfigure OpenClaw with: [bold]hyper agent openclaw-setup[/bold]")
|
|
153
153
|
|
|
154
154
|
|
|
155
155
|
async def _subscribe_async(account, plan_id: str, api_base: str, amount: str = None):
|
|
@@ -220,8 +220,8 @@ async def _subscribe_async(account, plan_id: str, api_base: str, amount: str = N
|
|
|
220
220
|
payment_headers = http_client.encode_payment_signature_header(payment_payload)
|
|
221
221
|
console.print(f"[green]✓[/green] Payment signed")
|
|
222
222
|
|
|
223
|
-
# Step 6: Retry with payment (include JWT if available from
|
|
224
|
-
jwt_path = HYPERCLI_DIR / "
|
|
223
|
+
# Step 6: Retry with payment (include JWT if available from agent login)
|
|
224
|
+
jwt_path = HYPERCLI_DIR / "agent-jwt.json"
|
|
225
225
|
if jwt_path.exists():
|
|
226
226
|
try:
|
|
227
227
|
with open(jwt_path) as f:
|
|
@@ -229,7 +229,7 @@ async def _subscribe_async(account, plan_id: str, api_base: str, amount: str = N
|
|
|
229
229
|
jwt_token = jwt_data.get("token", "")
|
|
230
230
|
if jwt_token:
|
|
231
231
|
payment_headers["Authorization"] = f"Bearer {jwt_token}"
|
|
232
|
-
console.print("[green]✓[/green] Attaching user auth (from
|
|
232
|
+
console.print("[green]✓[/green] Attaching user auth (from agent login)")
|
|
233
233
|
except Exception:
|
|
234
234
|
pass
|
|
235
235
|
|
|
@@ -259,12 +259,12 @@ async def _subscribe_async(account, plan_id: str, api_base: str, amount: str = N
|
|
|
259
259
|
def status():
|
|
260
260
|
"""Show current HyperClaw key status"""
|
|
261
261
|
|
|
262
|
-
if not
|
|
262
|
+
if not AGENT_KEY_PATH.exists():
|
|
263
263
|
console.print("[yellow]No HyperClaw key found.[/yellow]")
|
|
264
|
-
console.print("Subscribe with: [bold]hyper
|
|
264
|
+
console.print("Subscribe with: [bold]hyper agent subscribe <aiu>[/bold]")
|
|
265
265
|
raise typer.Exit(0)
|
|
266
266
|
|
|
267
|
-
with open(
|
|
267
|
+
with open(AGENT_KEY_PATH) as f:
|
|
268
268
|
key_data = json.load(f)
|
|
269
269
|
|
|
270
270
|
# Parse expiry
|
|
@@ -339,7 +339,7 @@ def plans(
|
|
|
339
339
|
console.print()
|
|
340
340
|
console.print(table)
|
|
341
341
|
console.print()
|
|
342
|
-
console.print("Subscribe with: [bold]hyper
|
|
342
|
+
console.print("Subscribe with: [bold]hyper agent subscribe <plan_id> <amount>[/bold]")
|
|
343
343
|
|
|
344
344
|
|
|
345
345
|
@app.command("models")
|
|
@@ -426,12 +426,12 @@ def login(
|
|
|
426
426
|
1. Signs a challenge with your wallet private key
|
|
427
427
|
2. Backend verifies signature, creates/finds your user
|
|
428
428
|
3. Creates an API key bound to your user account
|
|
429
|
-
4. Saves the key to ~/.hypercli/
|
|
429
|
+
4. Saves the key to ~/.hypercli/agent-key.json
|
|
430
430
|
|
|
431
431
|
After login, you can use:
|
|
432
432
|
hyper agents create Launch an OpenClaw agent pod
|
|
433
433
|
hyper agents list List your agents
|
|
434
|
-
hyper
|
|
434
|
+
hyper agent config Generate provider configs
|
|
435
435
|
"""
|
|
436
436
|
try:
|
|
437
437
|
from eth_account.messages import encode_defunct
|
|
@@ -492,17 +492,17 @@ def login(
|
|
|
492
492
|
team_id = login_data.get("team_id", "")
|
|
493
493
|
wallet_addr = login_data.get("wallet_address", account.address)
|
|
494
494
|
|
|
495
|
-
# Step 5: Create
|
|
495
|
+
# Step 5: Create an agent API key using the JWT
|
|
496
496
|
console.print("[bold]Creating API key...[/bold]")
|
|
497
497
|
with httpx.Client(timeout=15) as client:
|
|
498
498
|
resp = client.post(
|
|
499
499
|
f"{base_url}/api/keys",
|
|
500
|
-
json={"name": "
|
|
500
|
+
json={"name": "agent-cli"},
|
|
501
501
|
headers={"Authorization": f"Bearer {jwt_token}"},
|
|
502
502
|
)
|
|
503
503
|
if resp.status_code != 200:
|
|
504
504
|
# Save JWT anyway so user can still auth
|
|
505
|
-
jwt_path = HYPERCLI_DIR / "
|
|
505
|
+
jwt_path = HYPERCLI_DIR / "agent-jwt.json"
|
|
506
506
|
HYPERCLI_DIR.mkdir(parents=True, exist_ok=True)
|
|
507
507
|
with open(jwt_path, "w") as f:
|
|
508
508
|
json.dump({"token": jwt_token, "user_id": user_id, "team_id": team_id}, f, indent=2)
|
|
@@ -514,9 +514,9 @@ def login(
|
|
|
514
514
|
|
|
515
515
|
api_key = key_data.get("api_key", key_data.get("key", ""))
|
|
516
516
|
|
|
517
|
-
# Step 6: Save as
|
|
517
|
+
# Step 6: Save as agent key
|
|
518
518
|
HYPERCLI_DIR.mkdir(parents=True, exist_ok=True)
|
|
519
|
-
|
|
519
|
+
agent_key_data = {
|
|
520
520
|
"key": api_key,
|
|
521
521
|
"plan_id": login_data.get("plan_id", "free"),
|
|
522
522
|
"user_id": user_id,
|
|
@@ -526,22 +526,27 @@ def login(
|
|
|
526
526
|
"rpm_limit": 0,
|
|
527
527
|
"expires_at": "",
|
|
528
528
|
}
|
|
529
|
-
with open(
|
|
530
|
-
json.dump(
|
|
529
|
+
with open(AGENT_KEY_PATH, "w") as f:
|
|
530
|
+
json.dump(agent_key_data, f, indent=2)
|
|
531
531
|
|
|
532
|
-
console.print(f"[green]✓[/green] API key saved to [bold]{
|
|
532
|
+
console.print(f"[green]✓[/green] API key saved to [bold]{AGENT_KEY_PATH}[/bold]\n")
|
|
533
533
|
console.print(f" User: {user_id[:12]}...")
|
|
534
534
|
console.print(f" Team: {team_id[:12]}...")
|
|
535
535
|
console.print(f" Key: {api_key[:20]}...")
|
|
536
536
|
console.print(f" Wallet: {wallet_addr}")
|
|
537
537
|
console.print(f"\n[green]You're all set![/green]")
|
|
538
538
|
console.print(f" Launch agent: [bold]hyper agents create[/bold]")
|
|
539
|
-
console.print(f" Configure: [bold]hyper
|
|
539
|
+
console.print(f" Configure: [bold]hyper agent config openclaw --apply[/bold]")
|
|
540
540
|
|
|
541
541
|
|
|
542
542
|
OPENCLAW_CONFIG_PATH = Path.home() / ".openclaw" / "openclaw.json"
|
|
543
543
|
|
|
544
544
|
|
|
545
|
+
def _resolve_api_base(base_url: str | None = None, dev: bool = False) -> str:
|
|
546
|
+
"""Resolve API base from flag/env, then fall back to dev/prod defaults."""
|
|
547
|
+
return (base_url or os.environ.get("HYPERCLAW_API_BASE") or (DEV_API_BASE if dev else PROD_API_BASE)).rstrip("/")
|
|
548
|
+
|
|
549
|
+
|
|
545
550
|
def fetch_models(api_key: str, api_base: str = PROD_API_BASE) -> list[dict]:
|
|
546
551
|
"""Fetch available models from LiteLLM /v1/models (served by HyperClaw)."""
|
|
547
552
|
import httpx
|
|
@@ -555,7 +560,7 @@ def fetch_models(api_key: str, api_base: str = PROD_API_BASE) -> list[dict]:
|
|
|
555
560
|
data = resp.json().get("data", [])
|
|
556
561
|
# Known model metadata (context windows, reasoning, etc.)
|
|
557
562
|
MODEL_META = {
|
|
558
|
-
"kimi-k2.5": {"name": "Kimi K2.5", "reasoning":
|
|
563
|
+
"kimi-k2.5": {"name": "Kimi K2.5", "reasoning": True, "contextWindow": 262144},
|
|
559
564
|
"glm-5": {"name": "GLM-5", "reasoning": True, "contextWindow": 202752},
|
|
560
565
|
}
|
|
561
566
|
return [
|
|
@@ -577,7 +582,7 @@ def fetch_models(api_key: str, api_base: str = PROD_API_BASE) -> list[dict]:
|
|
|
577
582
|
{
|
|
578
583
|
"id": "kimi-k2.5",
|
|
579
584
|
"name": "Kimi K2.5",
|
|
580
|
-
"reasoning":
|
|
585
|
+
"reasoning": True,
|
|
581
586
|
"input": ["text"],
|
|
582
587
|
"contextWindow": 262144,
|
|
583
588
|
},
|
|
@@ -597,18 +602,18 @@ def openclaw_setup(
|
|
|
597
602
|
):
|
|
598
603
|
"""Patch OpenClaw config with your HyperClaw API key.
|
|
599
604
|
|
|
600
|
-
Reads key from ~/.hypercli/
|
|
605
|
+
Reads key from ~/.hypercli/agent-key.json, patches only the
|
|
601
606
|
models.providers.hyperclaw section in ~/.openclaw/openclaw.json.
|
|
602
607
|
Everything else in the config is left untouched.
|
|
603
608
|
"""
|
|
604
609
|
|
|
605
610
|
# Load HyperClaw key
|
|
606
|
-
if not
|
|
611
|
+
if not AGENT_KEY_PATH.exists():
|
|
607
612
|
console.print("[red]❌ No HyperClaw key found.[/red]")
|
|
608
|
-
console.print("Run: [bold]hyper
|
|
613
|
+
console.print("Run: [bold]hyper agent subscribe 1aiu <amount>[/bold]")
|
|
609
614
|
raise typer.Exit(1)
|
|
610
615
|
|
|
611
|
-
with open(
|
|
616
|
+
with open(AGENT_KEY_PATH) as f:
|
|
612
617
|
api_key = json.load(f).get("key", "")
|
|
613
618
|
|
|
614
619
|
if not api_key:
|
|
@@ -630,13 +635,13 @@ def openclaw_setup(
|
|
|
630
635
|
chat_models = [m for m in models if m.get("mode") != "embedding"]
|
|
631
636
|
embedding_models = [m for m in models if m.get("mode") == "embedding"]
|
|
632
637
|
config["models"]["providers"]["hyperclaw"] = {
|
|
633
|
-
"baseUrl": "https://api.
|
|
638
|
+
"baseUrl": "https://api.hypercli.com",
|
|
634
639
|
"apiKey": api_key,
|
|
635
640
|
"api": "anthropic-messages",
|
|
636
641
|
"models": chat_models,
|
|
637
642
|
}
|
|
638
643
|
config["models"]["providers"]["hyperclaw-embed"] = {
|
|
639
|
-
"baseUrl": "https://api.
|
|
644
|
+
"baseUrl": "https://api.hypercli.com/v1",
|
|
640
645
|
"apiKey": api_key,
|
|
641
646
|
"api": "openai-completions",
|
|
642
647
|
"models": embedding_models,
|
|
@@ -645,10 +650,10 @@ def openclaw_setup(
|
|
|
645
650
|
# Always set embedding provider (reuses same API key)
|
|
646
651
|
config.setdefault("agents", {}).setdefault("defaults", {})
|
|
647
652
|
config["agents"]["defaults"]["memorySearch"] = {
|
|
648
|
-
"provider": "
|
|
653
|
+
"provider": "openai",
|
|
649
654
|
"model": "qwen3-embedding-4b",
|
|
650
655
|
"remote": {
|
|
651
|
-
"baseUrl": "https://api.
|
|
656
|
+
"baseUrl": "https://api.hypercli.com/v1/",
|
|
652
657
|
"apiKey": api_key,
|
|
653
658
|
}
|
|
654
659
|
}
|
|
@@ -675,30 +680,32 @@ def openclaw_setup(
|
|
|
675
680
|
console.print(f" model: hyperclaw-embed/{m['id']}")
|
|
676
681
|
if default and chat_models:
|
|
677
682
|
console.print(f" default model: hyperclaw/{chat_models[0]['id']}")
|
|
678
|
-
console.print("\
|
|
683
|
+
console.print("\nOpenClaw will use the Anthropic-compatible /v1/messages endpoint.")
|
|
684
|
+
console.print("Run: [bold]openclaw gateway restart[/bold]")
|
|
679
685
|
|
|
680
686
|
|
|
681
687
|
# ---------------------------------------------------------------------------
|
|
682
|
-
# hyper
|
|
688
|
+
# hyper agent config — generate / apply provider configs for various tools
|
|
683
689
|
# ---------------------------------------------------------------------------
|
|
684
690
|
|
|
685
691
|
def _resolve_api_key(key: str | None) -> str:
|
|
686
|
-
"""Resolve API key from --key flag or ~/.hypercli/
|
|
692
|
+
"""Resolve API key from --key flag or ~/.hypercli/agent-key.json."""
|
|
687
693
|
if key:
|
|
688
694
|
return key
|
|
689
|
-
if
|
|
690
|
-
with open(
|
|
695
|
+
if AGENT_KEY_PATH.exists():
|
|
696
|
+
with open(AGENT_KEY_PATH) as f:
|
|
691
697
|
k = json.load(f).get("key", "")
|
|
692
698
|
if k:
|
|
693
699
|
return k
|
|
694
700
|
console.print("[red]❌ No API key found.[/red]")
|
|
695
701
|
console.print("Either pass [bold]--key sk-...[/bold] or subscribe first:")
|
|
696
|
-
console.print(" [bold]hyper
|
|
702
|
+
console.print(" [bold]hyper agent subscribe 1aiu[/bold]")
|
|
697
703
|
raise typer.Exit(1)
|
|
698
704
|
|
|
699
705
|
|
|
700
706
|
def _config_openclaw(api_key: str, models: list[dict], api_base: str = PROD_API_BASE) -> dict:
|
|
701
707
|
"""OpenClaw openclaw.json provider snippet (LLM + embeddings)."""
|
|
708
|
+
api_base = api_base.rstrip("/")
|
|
702
709
|
chat_models = [m for m in models if m.get("mode") != "embedding"]
|
|
703
710
|
embedding_models = [m for m in models if m.get("mode") == "embedding"]
|
|
704
711
|
return {
|
|
@@ -728,7 +735,7 @@ def _config_openclaw(api_key: str, models: list[dict], api_base: str = PROD_API_
|
|
|
728
735
|
**{f"hyperclaw-embed/{m['id']}": {"alias": m['id'].split('-')[0]} for m in embedding_models},
|
|
729
736
|
},
|
|
730
737
|
"memorySearch": {
|
|
731
|
-
"provider": "
|
|
738
|
+
"provider": "openai",
|
|
732
739
|
"model": "qwen3-embedding-4b",
|
|
733
740
|
"remote": {
|
|
734
741
|
"baseUrl": f"{api_base}/v1/",
|
|
@@ -740,8 +747,9 @@ def _config_openclaw(api_key: str, models: list[dict], api_base: str = PROD_API_
|
|
|
740
747
|
}
|
|
741
748
|
|
|
742
749
|
|
|
743
|
-
def _config_opencode(api_key: str, models: list[dict]) -> dict:
|
|
750
|
+
def _config_opencode(api_key: str, models: list[dict], api_base: str = PROD_API_BASE) -> dict:
|
|
744
751
|
"""OpenCode opencode.json provider snippet."""
|
|
752
|
+
api_base = api_base.rstrip("/")
|
|
745
753
|
model_entries = {}
|
|
746
754
|
for m in models:
|
|
747
755
|
model_entries[m["id"]] = {"name": m["id"]}
|
|
@@ -752,7 +760,7 @@ def _config_opencode(api_key: str, models: list[dict]) -> dict:
|
|
|
752
760
|
"npm": "@ai-sdk/openai-compatible",
|
|
753
761
|
"name": "HyperCLI",
|
|
754
762
|
"options": {
|
|
755
|
-
"baseURL": "
|
|
763
|
+
"baseURL": f"{api_base}/v1",
|
|
756
764
|
"apiKey": api_key,
|
|
757
765
|
},
|
|
758
766
|
"models": model_entries,
|
|
@@ -761,11 +769,12 @@ def _config_opencode(api_key: str, models: list[dict]) -> dict:
|
|
|
761
769
|
}
|
|
762
770
|
|
|
763
771
|
|
|
764
|
-
def _config_env(api_key: str, models: list[dict]) -> str:
|
|
772
|
+
def _config_env(api_key: str, models: list[dict], api_base: str = PROD_API_BASE) -> str:
|
|
765
773
|
"""Shell env vars for generic OpenAI-compatible tools."""
|
|
774
|
+
api_base = api_base.rstrip("/")
|
|
766
775
|
lines = [
|
|
767
776
|
f'export OPENAI_API_KEY="{api_key}"',
|
|
768
|
-
'export OPENAI_BASE_URL="
|
|
777
|
+
f'export OPENAI_BASE_URL="{api_base}/v1"',
|
|
769
778
|
f'# Available models: {", ".join(m["id"] for m in models)}',
|
|
770
779
|
]
|
|
771
780
|
return "\n".join(lines)
|
|
@@ -802,21 +811,23 @@ def config_cmd(
|
|
|
802
811
|
None,
|
|
803
812
|
help=f"Output format: {', '.join(FORMAT_CHOICES)}. Omit to show all.",
|
|
804
813
|
),
|
|
805
|
-
key: str = typer.Option(None, "--key", "-k", help="API key (sk-...). Falls back to ~/.hypercli/
|
|
814
|
+
key: str = typer.Option(None, "--key", "-k", help="API key (sk-...). Falls back to ~/.hypercli/agent-key.json"),
|
|
815
|
+
base_url: str = typer.Option(None, "--base-url", help="HyperClaw API base URL. Falls back to HYPERCLAW_API_BASE, then --dev/prod defaults"),
|
|
806
816
|
apply: bool = typer.Option(False, "--apply", help="Write config to the appropriate file (openclaw/opencode only)"),
|
|
807
817
|
dev: bool = typer.Option(False, "--dev", help="Use dev API"),
|
|
808
818
|
):
|
|
809
819
|
"""Generate provider configs for OpenClaw, OpenCode, and other tools.
|
|
810
820
|
|
|
811
821
|
Examples:
|
|
812
|
-
hyper
|
|
813
|
-
hyper
|
|
814
|
-
hyper
|
|
815
|
-
hyper
|
|
816
|
-
hyper
|
|
822
|
+
hyper agent config # Show all configs
|
|
823
|
+
hyper agent config openclaw # OpenClaw snippet
|
|
824
|
+
hyper agent config opencode --key sk-... # OpenCode with explicit key
|
|
825
|
+
hyper agent config openclaw --base-url https://api.dev.hypercli.com
|
|
826
|
+
hyper agent config openclaw --apply # Write directly to openclaw.json
|
|
827
|
+
hyper agent config env # Shell export lines
|
|
817
828
|
"""
|
|
818
829
|
api_key = _resolve_api_key(key)
|
|
819
|
-
api_base =
|
|
830
|
+
api_base = _resolve_api_base(base_url, dev)
|
|
820
831
|
|
|
821
832
|
# Validate key & fetch models
|
|
822
833
|
console.print(f"[dim]Validating key against {api_base}...[/dim]")
|
|
@@ -836,12 +847,12 @@ def config_cmd(
|
|
|
836
847
|
snippet = _config_openclaw(api_key, models, api_base)
|
|
837
848
|
_show_snippet("OpenClaw", "~/.openclaw/openclaw.json", snippet, apply, OPENCLAW_CONFIG_PATH)
|
|
838
849
|
elif fmt == "opencode":
|
|
839
|
-
snippet = _config_opencode(api_key, models)
|
|
850
|
+
snippet = _config_opencode(api_key, models, api_base)
|
|
840
851
|
target = Path.cwd() / "opencode.json"
|
|
841
852
|
_show_snippet("OpenCode", "opencode.json", snippet, apply, target)
|
|
842
853
|
elif fmt == "env":
|
|
843
854
|
console.print("[bold]── Shell Environment ──[/bold]")
|
|
844
|
-
console.print(_config_env(api_key, models))
|
|
855
|
+
console.print(_config_env(api_key, models, api_base))
|
|
845
856
|
console.print()
|
|
846
857
|
|
|
847
858
|
|