hypercli-sdk 2026.4.13.post3__tar.gz → 2026.4.17__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_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/PKG-INFO +4 -1
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/README.md +3 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/hypercli/__init__.py +1 -1
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/hypercli/agents.py +18 -1
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/hypercli/voice.py +21 -7
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/pyproject.toml +1 -1
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/tests/integration/test_agents.py +40 -24
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/tests/test_agents.py +51 -1
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/tests/test_voice.py +11 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/.gitignore +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/hypercli/agent.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/hypercli/billing.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/hypercli/client.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/hypercli/config.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/hypercli/files.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/hypercli/gateway.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/hypercli/http.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/hypercli/instances.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/hypercli/job/__init__.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/hypercli/job/base.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/hypercli/job/comfyui.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/hypercli/job/gradio.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/hypercli/jobs.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/hypercli/keys.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/hypercli/logs.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/hypercli/models.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/hypercli/openclaw/__init__.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/hypercli/openclaw/gateway.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/hypercli/renders.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/hypercli/shell.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/hypercli/user.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/hypercli/x402.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/tests/integration/conftest.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/tests/integration/test_auth.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/tests/integration/test_billing.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/tests/integration/test_instances.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/tests/integration/test_jobs_dryrun.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/tests/integration/test_keys.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/tests/integration/test_renders.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/tests/test_apply_params.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/tests/test_bootstrap_console_test_key.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/tests/test_bootstrap_dev_test_keys.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/tests/test_claw.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/tests/test_config.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/tests/test_exec_shell_dryrun.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/tests/test_gateway.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/tests/test_gateway_retry.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/tests/test_graph_to_api.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/tests/test_http.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/tests/test_jobs.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/tests/test_keys.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/tests/test_models.py +0 -0
- {hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/tests/test_renders_subscription.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hypercli-sdk
|
|
3
|
-
Version: 2026.4.
|
|
3
|
+
Version: 2026.4.17
|
|
4
4
|
Summary: Python SDK for HyperCLI - GPU orchestration and HyperAgent API
|
|
5
5
|
Project-URL: Homepage, https://hypercli.com
|
|
6
6
|
Project-URL: Documentation, https://docs.hypercli.com
|
|
@@ -140,11 +140,14 @@ OpenClaw uses the generic deployment launch surface. `registry_url`, `registry_a
|
|
|
140
140
|
agent = client.deployments.create_openclaw(
|
|
141
141
|
name="docs-demo",
|
|
142
142
|
start=True,
|
|
143
|
+
heartbeat={"every": "0m"}, # disable upstream OpenClaw heartbeat runs
|
|
143
144
|
registry_url="git.nedos.co",
|
|
144
145
|
registry_auth={"username": "ci", "password": "token"},
|
|
145
146
|
)
|
|
146
147
|
```
|
|
147
148
|
|
|
149
|
+
`heartbeat` maps directly to upstream OpenClaw config at `config.agents.defaults.heartbeat`. Omit it to keep upstream defaults, or pass values such as `heartbeat={"every": "1h", "target": "last"}`.
|
|
150
|
+
|
|
148
151
|
## Error Handling
|
|
149
152
|
|
|
150
153
|
```python
|
|
@@ -109,11 +109,14 @@ OpenClaw uses the generic deployment launch surface. `registry_url`, `registry_a
|
|
|
109
109
|
agent = client.deployments.create_openclaw(
|
|
110
110
|
name="docs-demo",
|
|
111
111
|
start=True,
|
|
112
|
+
heartbeat={"every": "0m"}, # disable upstream OpenClaw heartbeat runs
|
|
112
113
|
registry_url="git.nedos.co",
|
|
113
114
|
registry_auth={"username": "ci", "password": "token"},
|
|
114
115
|
)
|
|
115
116
|
```
|
|
116
117
|
|
|
118
|
+
`heartbeat` maps directly to upstream OpenClaw config at `config.agents.defaults.heartbeat`. Omit it to keep upstream defaults, or pass values such as `heartbeat={"every": "1h", "target": "last"}`.
|
|
119
|
+
|
|
117
120
|
## Error Handling
|
|
118
121
|
|
|
119
122
|
```python
|
|
@@ -191,14 +191,23 @@ def _build_agent_launch(
|
|
|
191
191
|
registry_url: str | None = None,
|
|
192
192
|
registry_auth: dict | None = None,
|
|
193
193
|
gateway_token: str | None = None,
|
|
194
|
+
heartbeat: dict | None = None,
|
|
194
195
|
) -> tuple[dict, str]:
|
|
195
|
-
prepared_config =
|
|
196
|
+
prepared_config = copy.deepcopy(config or {})
|
|
196
197
|
nested_launch_keys = sorted(LAUNCH_CONFIG_KEYS.intersection(prepared_config.keys()))
|
|
197
198
|
if nested_launch_keys:
|
|
198
199
|
raise ValueError(
|
|
199
200
|
"Launch settings must be top-level fields, not nested under config: "
|
|
200
201
|
+ ", ".join(nested_launch_keys)
|
|
201
202
|
)
|
|
203
|
+
if heartbeat:
|
|
204
|
+
agents_cfg = dict(prepared_config.get("agents") or {})
|
|
205
|
+
defaults_cfg = dict(agents_cfg.get("defaults") or {})
|
|
206
|
+
heartbeat_cfg = dict(defaults_cfg.get("heartbeat") or {})
|
|
207
|
+
heartbeat_cfg.update(dict(heartbeat))
|
|
208
|
+
defaults_cfg["heartbeat"] = heartbeat_cfg
|
|
209
|
+
agents_cfg["defaults"] = defaults_cfg
|
|
210
|
+
prepared_config["agents"] = agents_cfg
|
|
202
211
|
env_map = dict(env or {})
|
|
203
212
|
if env:
|
|
204
213
|
env_map.update(env)
|
|
@@ -1015,6 +1024,7 @@ class Deployments:
|
|
|
1015
1024
|
registry_url: str = None,
|
|
1016
1025
|
registry_auth: dict = None,
|
|
1017
1026
|
gateway_token: str = None,
|
|
1027
|
+
heartbeat: dict = None,
|
|
1018
1028
|
meta_ui: dict = None,
|
|
1019
1029
|
dry_run: bool = False,
|
|
1020
1030
|
start: bool = True,
|
|
@@ -1045,6 +1055,7 @@ class Deployments:
|
|
|
1045
1055
|
registry_url=registry_url,
|
|
1046
1056
|
registry_auth=registry_auth,
|
|
1047
1057
|
gateway_token=gateway_token,
|
|
1058
|
+
heartbeat=heartbeat,
|
|
1048
1059
|
)
|
|
1049
1060
|
body: dict = {**launch_payload, "start": start}
|
|
1050
1061
|
if dry_run:
|
|
@@ -1083,6 +1094,7 @@ class Deployments:
|
|
|
1083
1094
|
registry_url: str = None,
|
|
1084
1095
|
registry_auth: dict = None,
|
|
1085
1096
|
gateway_token: str = None,
|
|
1097
|
+
heartbeat: dict = None,
|
|
1086
1098
|
meta_ui: dict = None,
|
|
1087
1099
|
dry_run: bool = False,
|
|
1088
1100
|
start: bool = True,
|
|
@@ -1110,6 +1122,7 @@ class Deployments:
|
|
|
1110
1122
|
registry_url=registry_url,
|
|
1111
1123
|
registry_auth=registry_auth,
|
|
1112
1124
|
gateway_token=gateway_token,
|
|
1125
|
+
heartbeat=heartbeat,
|
|
1113
1126
|
meta_ui=meta_ui,
|
|
1114
1127
|
dry_run=dry_run,
|
|
1115
1128
|
start=start,
|
|
@@ -1185,6 +1198,7 @@ class Deployments:
|
|
|
1185
1198
|
registry_url: str = None,
|
|
1186
1199
|
registry_auth: dict = None,
|
|
1187
1200
|
gateway_token: str = None,
|
|
1201
|
+
heartbeat: dict = None,
|
|
1188
1202
|
dry_run: bool = False,
|
|
1189
1203
|
) -> Agent:
|
|
1190
1204
|
"""Start a previously stopped agent.
|
|
@@ -1208,6 +1222,7 @@ class Deployments:
|
|
|
1208
1222
|
registry_url=registry_url,
|
|
1209
1223
|
registry_auth=registry_auth,
|
|
1210
1224
|
gateway_token=gateway_token,
|
|
1225
|
+
heartbeat=heartbeat,
|
|
1211
1226
|
)
|
|
1212
1227
|
body: dict[str, Any] = dict(launch_payload)
|
|
1213
1228
|
if dry_run:
|
|
@@ -1236,6 +1251,7 @@ class Deployments:
|
|
|
1236
1251
|
registry_url: str = None,
|
|
1237
1252
|
registry_auth: dict = None,
|
|
1238
1253
|
gateway_token: str = None,
|
|
1254
|
+
heartbeat: dict = None,
|
|
1239
1255
|
dry_run: bool = False,
|
|
1240
1256
|
openclaw_routes: dict | None = None,
|
|
1241
1257
|
openclaw_route_options: dict | None = None,
|
|
@@ -1259,6 +1275,7 @@ class Deployments:
|
|
|
1259
1275
|
registry_url=registry_url,
|
|
1260
1276
|
registry_auth=registry_auth,
|
|
1261
1277
|
gateway_token=gateway_token,
|
|
1278
|
+
heartbeat=heartbeat,
|
|
1262
1279
|
dry_run=dry_run,
|
|
1263
1280
|
)
|
|
1264
1281
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
"""Voice API client."""
|
|
4
|
+
import os
|
|
4
5
|
from pathlib import Path
|
|
5
6
|
from typing import TYPE_CHECKING
|
|
6
7
|
import base64
|
|
@@ -17,9 +18,22 @@ def _encode_reference_audio(ref_audio: bytes | str | Path) -> str:
|
|
|
17
18
|
return base64.b64encode(audio_bytes).decode()
|
|
18
19
|
|
|
19
20
|
|
|
21
|
+
def _default_voice_timeout() -> float:
|
|
22
|
+
raw_value = os.environ.get("HYPER_VOICE_TIMEOUT_SECONDS", "300").strip()
|
|
23
|
+
try:
|
|
24
|
+
return float(raw_value)
|
|
25
|
+
except ValueError:
|
|
26
|
+
return 300.0
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _resolve_voice_timeout(timeout: float | None) -> float:
|
|
30
|
+
if timeout is not None:
|
|
31
|
+
return float(timeout)
|
|
32
|
+
return _default_voice_timeout()
|
|
33
|
+
|
|
34
|
+
|
|
20
35
|
class VoiceAPI:
|
|
21
36
|
"""Voice capability API wrapper."""
|
|
22
|
-
|
|
23
37
|
DEFAULT_TIMEOUT = 300.0
|
|
24
38
|
|
|
25
39
|
def __init__(self, http: "HTTPClient"):
|
|
@@ -32,7 +46,7 @@ class VoiceAPI:
|
|
|
32
46
|
voice: str = "Chelsie",
|
|
33
47
|
language: str = "auto",
|
|
34
48
|
response_format: str = "mp3",
|
|
35
|
-
timeout: float =
|
|
49
|
+
timeout: float | None = None,
|
|
36
50
|
) -> bytes:
|
|
37
51
|
return self._http.post_bytes(
|
|
38
52
|
"/agents/voice/tts",
|
|
@@ -42,7 +56,7 @@ class VoiceAPI:
|
|
|
42
56
|
"language": language,
|
|
43
57
|
"response_format": response_format,
|
|
44
58
|
},
|
|
45
|
-
timeout=timeout,
|
|
59
|
+
timeout=_resolve_voice_timeout(timeout),
|
|
46
60
|
)
|
|
47
61
|
|
|
48
62
|
def clone(
|
|
@@ -53,7 +67,7 @@ class VoiceAPI:
|
|
|
53
67
|
language: str = "auto",
|
|
54
68
|
x_vector_only: bool = True,
|
|
55
69
|
response_format: str = "mp3",
|
|
56
|
-
timeout: float =
|
|
70
|
+
timeout: float | None = None,
|
|
57
71
|
) -> bytes:
|
|
58
72
|
return self._http.post_bytes(
|
|
59
73
|
"/agents/voice/clone",
|
|
@@ -64,7 +78,7 @@ class VoiceAPI:
|
|
|
64
78
|
"x_vector_only": x_vector_only,
|
|
65
79
|
"response_format": response_format,
|
|
66
80
|
},
|
|
67
|
-
timeout=timeout,
|
|
81
|
+
timeout=_resolve_voice_timeout(timeout),
|
|
68
82
|
)
|
|
69
83
|
|
|
70
84
|
def design(
|
|
@@ -74,7 +88,7 @@ class VoiceAPI:
|
|
|
74
88
|
description: str,
|
|
75
89
|
language: str = "auto",
|
|
76
90
|
response_format: str = "mp3",
|
|
77
|
-
timeout: float =
|
|
91
|
+
timeout: float | None = None,
|
|
78
92
|
) -> bytes:
|
|
79
93
|
return self._http.post_bytes(
|
|
80
94
|
"/agents/voice/design",
|
|
@@ -84,5 +98,5 @@ class VoiceAPI:
|
|
|
84
98
|
"language": language,
|
|
85
99
|
"response_format": response_format,
|
|
86
100
|
},
|
|
87
|
-
timeout=timeout,
|
|
101
|
+
timeout=_resolve_voice_timeout(timeout),
|
|
88
102
|
)
|
|
@@ -12,32 +12,48 @@ def _create_agent_with_available_tier(client: HyperCLI, name: str, tags: list[st
|
|
|
12
12
|
budget = client.deployments.budget()
|
|
13
13
|
slots = (budget or {}).get("slots") or {}
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
tiers = [
|
|
16
|
+
candidate
|
|
17
|
+
for candidate in ("large", "medium", "small")
|
|
18
|
+
if int((slots.get(candidate) or {}).get("available") or 0) > 0
|
|
19
|
+
]
|
|
20
|
+
if not tiers:
|
|
17
21
|
raise AssertionError("No available entitlement slots for integration agent tests")
|
|
18
22
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
23
|
+
last_error: Exception | None = None
|
|
24
|
+
for tier in tiers:
|
|
25
|
+
agent_id: str | None = None
|
|
26
|
+
try:
|
|
27
|
+
agent = client.deployments.create(
|
|
28
|
+
name=name,
|
|
29
|
+
size=tier,
|
|
30
|
+
start=False,
|
|
31
|
+
tags=tags,
|
|
32
|
+
)
|
|
33
|
+
agent_id = agent.id
|
|
34
|
+
client.deployments.start_openclaw(agent.id, dry_run=True)
|
|
35
|
+
return agent.id, tier
|
|
36
|
+
except APIError as exc:
|
|
37
|
+
if agent_id:
|
|
38
|
+
try:
|
|
39
|
+
client.deployments.delete(agent_id)
|
|
40
|
+
except APIError:
|
|
41
|
+
pass
|
|
42
|
+
if exc.status_code == 429:
|
|
43
|
+
last_error = AssertionError(
|
|
44
|
+
f"Budget reported '{tier}' available but dry-run start was rejected for slot exhaustion"
|
|
45
|
+
)
|
|
46
|
+
continue
|
|
47
|
+
if exc.status_code == 503 and "No connected clusters available for tags" in str(exc.detail):
|
|
48
|
+
last_error = AssertionError(
|
|
49
|
+
f"Tier '{tier}' has entitlement capacity but no connected clusters are advertising that tag"
|
|
50
|
+
)
|
|
51
|
+
continue
|
|
52
|
+
raise
|
|
53
|
+
|
|
54
|
+
if last_error:
|
|
55
|
+
raise last_error
|
|
56
|
+
raise AssertionError("Failed to create an integration agent with any available tier")
|
|
41
57
|
|
|
42
58
|
|
|
43
59
|
def test_list_agents_requires_agent_key(client, test_agent_api_key: str):
|
|
@@ -416,6 +416,27 @@ def test_build_agent_launch_includes_command_and_entrypoint():
|
|
|
416
416
|
assert launch["routes"] == {"web": {"port": 80, "prefix": ""}}
|
|
417
417
|
|
|
418
418
|
|
|
419
|
+
def test_build_agent_launch_merges_heartbeat_defaults():
|
|
420
|
+
launch, _gateway_token = _build_agent_launch(
|
|
421
|
+
{"agents": {"defaults": {"model": "openai/gpt-5.4", "heartbeat": {"target": "last"}}}},
|
|
422
|
+
heartbeat={"every": "0m", "includeSystemPromptSection": False},
|
|
423
|
+
gateway_token="gw-token",
|
|
424
|
+
)
|
|
425
|
+
|
|
426
|
+
assert launch["config"] == {
|
|
427
|
+
"agents": {
|
|
428
|
+
"defaults": {
|
|
429
|
+
"model": "openai/gpt-5.4",
|
|
430
|
+
"heartbeat": {
|
|
431
|
+
"target": "last",
|
|
432
|
+
"every": "0m",
|
|
433
|
+
"includeSystemPromptSection": False,
|
|
434
|
+
},
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
|
|
419
440
|
def test_build_openclaw_routes_defaults():
|
|
420
441
|
assert build_openclaw_routes() == {
|
|
421
442
|
"openclaw": {"port": 18789, "auth": False, "prefix": ""},
|
|
@@ -485,6 +506,35 @@ def test_create_openclaw_respects_explicit_empty_routes(agents_client):
|
|
|
485
506
|
assert posted_json["image"] == DEFAULT_OPENCLAW_IMAGE
|
|
486
507
|
assert posted_json["routes"] == {}
|
|
487
508
|
|
|
509
|
+
|
|
510
|
+
def test_create_openclaw_includes_heartbeat_when_requested(agents_client):
|
|
511
|
+
with patch("httpx.Client") as mock_client_class, patch("hypercli.agents.secrets.token_hex", return_value="gw-token-123"):
|
|
512
|
+
mock_client = MagicMock()
|
|
513
|
+
mock_response = Mock()
|
|
514
|
+
mock_response.status_code = 200
|
|
515
|
+
mock_response.json.return_value = {
|
|
516
|
+
"id": "agent-123",
|
|
517
|
+
"user_id": "user-456",
|
|
518
|
+
"pod_id": "pod-789",
|
|
519
|
+
"pod_name": "test-pod",
|
|
520
|
+
"state": "starting",
|
|
521
|
+
}
|
|
522
|
+
mock_client.post.return_value = mock_response
|
|
523
|
+
mock_client.__enter__.return_value = mock_client
|
|
524
|
+
mock_client.__exit__.return_value = False
|
|
525
|
+
mock_client_class.return_value = mock_client
|
|
526
|
+
|
|
527
|
+
agents_client.create_openclaw(
|
|
528
|
+
name="test-agent",
|
|
529
|
+
heartbeat={"every": "0m", "includeSystemPromptSection": False},
|
|
530
|
+
)
|
|
531
|
+
|
|
532
|
+
posted_json = mock_client.post.call_args[1]["json"]
|
|
533
|
+
assert posted_json["config"]["agents"]["defaults"]["heartbeat"] == {
|
|
534
|
+
"every": "0m",
|
|
535
|
+
"includeSystemPromptSection": False,
|
|
536
|
+
}
|
|
537
|
+
|
|
488
538
|
@pytest.fixture
|
|
489
539
|
def mock_http():
|
|
490
540
|
http = Mock(spec=HTTPClient)
|
|
@@ -970,7 +1020,7 @@ def test_agents_create_scoped_key(agents_client):
|
|
|
970
1020
|
"key_id": "key-123",
|
|
971
1021
|
"name": "agent-client",
|
|
972
1022
|
"api_key": "hyper_api_scoped",
|
|
973
|
-
"tags": ["agent
|
|
1023
|
+
"tags": ["agent:agent-123"],
|
|
974
1024
|
}
|
|
975
1025
|
mock_client.post.return_value = mock_response
|
|
976
1026
|
mock_client.__enter__.return_value = mock_client
|
|
@@ -70,3 +70,14 @@ def test_voice_design_posts_description():
|
|
|
70
70
|
VoiceAPI.DEFAULT_TIMEOUT,
|
|
71
71
|
)
|
|
72
72
|
]
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def test_voice_timeout_uses_env_default(monkeypatch):
|
|
76
|
+
monkeypatch.setenv("HYPER_VOICE_TIMEOUT_SECONDS", "720")
|
|
77
|
+
|
|
78
|
+
http = DummyVoiceHTTP()
|
|
79
|
+
voice = VoiceAPI(http)
|
|
80
|
+
|
|
81
|
+
voice.tts("hello")
|
|
82
|
+
|
|
83
|
+
assert http.calls[0][2] == 720.0
|
|
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
|
{hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/tests/integration/test_jobs_dryrun.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/tests/test_bootstrap_console_test_key.py
RENAMED
|
File without changes
|
{hypercli_sdk-2026.4.13.post3 → hypercli_sdk-2026.4.17}/tests/test_bootstrap_dev_test_keys.py
RENAMED
|
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
|