hypercli-sdk 2026.4.17__tar.gz → 2026.4.18__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.17 → hypercli_sdk-2026.4.18}/PKG-INFO +1 -1
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/hypercli/__init__.py +1 -1
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/hypercli/agent.py +33 -109
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/pyproject.toml +1 -1
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/tests/test_claw.py +2 -256
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/.gitignore +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/README.md +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/hypercli/agents.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/hypercli/billing.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/hypercli/client.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/hypercli/config.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/hypercli/files.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/hypercli/gateway.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/hypercli/http.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/hypercli/instances.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/hypercli/job/__init__.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/hypercli/job/base.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/hypercli/job/comfyui.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/hypercli/job/gradio.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/hypercli/jobs.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/hypercli/keys.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/hypercli/logs.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/hypercli/models.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/hypercli/openclaw/__init__.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/hypercli/openclaw/gateway.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/hypercli/renders.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/hypercli/shell.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/hypercli/user.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/hypercli/voice.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/hypercli/x402.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/tests/integration/conftest.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/tests/integration/test_agents.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/tests/integration/test_auth.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/tests/integration/test_billing.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/tests/integration/test_instances.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/tests/integration/test_jobs_dryrun.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/tests/integration/test_keys.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/tests/integration/test_renders.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/tests/test_agents.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/tests/test_apply_params.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/tests/test_bootstrap_console_test_key.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/tests/test_bootstrap_dev_test_keys.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/tests/test_config.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/tests/test_exec_shell_dryrun.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/tests/test_gateway.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/tests/test_gateway_retry.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/tests/test_graph_to_api.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/tests/test_http.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/tests/test_jobs.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/tests/test_keys.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/tests/test_models.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/tests/test_renders_subscription.py +0 -0
- {hypercli_sdk-2026.4.17 → hypercli_sdk-2026.4.18}/tests/test_voice.py +0 -0
|
@@ -221,6 +221,36 @@ class HyperAgentEntitlements:
|
|
|
221
221
|
)
|
|
222
222
|
|
|
223
223
|
|
|
224
|
+
@dataclass
|
|
225
|
+
class HyperAgentEntitlements:
|
|
226
|
+
"""Effective account entitlements computed by the backend."""
|
|
227
|
+
|
|
228
|
+
effective_plan_id: str
|
|
229
|
+
pooled_tpm_limit: int
|
|
230
|
+
pooled_rpm_limit: int
|
|
231
|
+
pooled_tpd: int
|
|
232
|
+
slot_inventory: dict[str, Any]
|
|
233
|
+
active_entitlement_count: int
|
|
234
|
+
|
|
235
|
+
@classmethod
|
|
236
|
+
def from_dict(cls, data: dict) -> "HyperAgentEntitlements":
|
|
237
|
+
payload = data.get("entitlements") if isinstance(data.get("entitlements"), dict) else data
|
|
238
|
+
return cls(
|
|
239
|
+
effective_plan_id=payload.get("effective_plan_id", data.get("effective_plan_id", "")),
|
|
240
|
+
pooled_tpm_limit=int(payload.get("pooled_tpm_limit", data.get("pooled_tpm_limit", 0)) or 0),
|
|
241
|
+
pooled_rpm_limit=int(payload.get("pooled_rpm_limit", data.get("pooled_rpm_limit", 0)) or 0),
|
|
242
|
+
pooled_tpd=int(payload.get("pooled_tpd", data.get("pooled_tpd", 0)) or 0),
|
|
243
|
+
slot_inventory=payload.get("slot_inventory") or data.get("slot_inventory") or {},
|
|
244
|
+
active_entitlement_count=int(
|
|
245
|
+
payload.get(
|
|
246
|
+
"active_entitlement_count",
|
|
247
|
+
data.get("active_entitlement_count", data.get("active_subscription_count", 0)),
|
|
248
|
+
)
|
|
249
|
+
or 0
|
|
250
|
+
),
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
|
|
224
254
|
@dataclass
|
|
225
255
|
class HyperAgentSubscriptionSummary:
|
|
226
256
|
"""Effective entitlement summary for an authenticated HyperClaw user."""
|
|
@@ -236,7 +266,6 @@ class HyperAgentSubscriptionSummary:
|
|
|
236
266
|
active_subscription_count: int
|
|
237
267
|
active_entitlement_count: int
|
|
238
268
|
entitlements: HyperAgentEntitlements
|
|
239
|
-
entitlement_items: list[HyperAgentEntitlement]
|
|
240
269
|
active_subscriptions: list[HyperAgentSubscription]
|
|
241
270
|
subscriptions: list[HyperAgentSubscription]
|
|
242
271
|
user: dict[str, Any]
|
|
@@ -257,7 +286,6 @@ class HyperAgentSubscriptionSummary:
|
|
|
257
286
|
active_subscription_count=int(data.get("active_subscription_count", 0) or 0),
|
|
258
287
|
active_entitlement_count=int(data.get("active_entitlement_count", data.get("active_subscription_count", 0)) or 0),
|
|
259
288
|
entitlements=HyperAgentEntitlements.from_dict(data),
|
|
260
|
-
entitlement_items=[HyperAgentEntitlement.from_dict(item) for item in data.get("entitlement_items", [])],
|
|
261
289
|
active_subscriptions=[HyperAgentSubscription.from_dict(item) for item in data.get("active_subscriptions", [])],
|
|
262
290
|
subscriptions=[HyperAgentSubscription.from_dict(item) for item in data.get("subscriptions", [])],
|
|
263
291
|
user=data.get("user") or {},
|
|
@@ -267,21 +295,6 @@ class HyperAgentSubscriptionSummary:
|
|
|
267
295
|
HyperAgentEntitlementsSummary = HyperAgentSubscriptionSummary
|
|
268
296
|
|
|
269
297
|
|
|
270
|
-
@dataclass
|
|
271
|
-
class HyperAgentSubscriptionMutationResult:
|
|
272
|
-
ok: bool
|
|
273
|
-
message: str
|
|
274
|
-
subscription: HyperAgentSubscription | None = None
|
|
275
|
-
|
|
276
|
-
@classmethod
|
|
277
|
-
def from_dict(cls, data: dict) -> "HyperAgentSubscriptionMutationResult":
|
|
278
|
-
return cls(
|
|
279
|
-
ok=bool(data.get("ok", False)),
|
|
280
|
-
message=str(data.get("message") or ""),
|
|
281
|
-
subscription=HyperAgentSubscription.from_dict(data["subscription"]) if data.get("subscription") else None,
|
|
282
|
-
)
|
|
283
|
-
|
|
284
|
-
|
|
285
298
|
@dataclass
|
|
286
299
|
class HyperAgentModel:
|
|
287
300
|
"""Available model on HyperAgent."""
|
|
@@ -888,102 +901,13 @@ class HyperAgent:
|
|
|
888
901
|
response.raise_for_status()
|
|
889
902
|
return HyperAgentEntitlementsSummary.from_dict(response.json())
|
|
890
903
|
|
|
891
|
-
def
|
|
892
|
-
response = self._http._session.get(
|
|
893
|
-
f"{self._control_base_url}/entitlements/instances",
|
|
894
|
-
headers={"Authorization": f"Bearer {self._api_key}"},
|
|
895
|
-
)
|
|
896
|
-
response.raise_for_status()
|
|
897
|
-
data = response.json()
|
|
898
|
-
return [HyperAgentEntitlement.from_dict(item) for item in data.get("items", [])]
|
|
899
|
-
|
|
900
|
-
def update_subscription(self, subscription_id: str, bundle: dict[str, int] | None) -> HyperAgentSubscriptionMutationResult:
|
|
904
|
+
def cancel_subscription(self, subscription_id: str) -> Dict[str, Any]:
|
|
901
905
|
response = self._http._session.post(
|
|
902
|
-
f"{self._control_base_url}/subscriptions/{subscription_id}/
|
|
906
|
+
f"{self._control_base_url}/subscriptions/{subscription_id}/cancel",
|
|
903
907
|
headers={"Authorization": f"Bearer {self._api_key}"},
|
|
904
|
-
json={"bundle": dict(bundle or {})},
|
|
905
908
|
)
|
|
906
909
|
response.raise_for_status()
|
|
907
|
-
return
|
|
908
|
-
|
|
909
|
-
def cancel_subscription(self, subscription_id: str) -> HyperAgentSubscriptionMutationResult:
|
|
910
|
-
return self.update_subscription(subscription_id, {})
|
|
911
|
-
|
|
912
|
-
def usage_summary(self) -> HyperAgentUsageSummary:
|
|
913
|
-
return HyperAgentUsageSummary.from_dict(self._control_get("/usage"))
|
|
914
|
-
|
|
915
|
-
def usage_history(self, days: int = 7) -> HyperAgentUsageHistory:
|
|
916
|
-
return HyperAgentUsageHistory.from_dict(self._control_get("/usage/history", params={"days": days}))
|
|
917
|
-
|
|
918
|
-
def key_usage(self, days: int = 7) -> HyperAgentKeyUsage:
|
|
919
|
-
return HyperAgentKeyUsage.from_dict(self._control_get("/usage/keys", params={"days": days}))
|
|
920
|
-
|
|
921
|
-
def agent_types(self) -> HyperAgentTypeCatalog:
|
|
922
|
-
return HyperAgentTypeCatalog.from_dict(self._control_get("/types"))
|
|
923
|
-
|
|
924
|
-
def billing_info(self) -> HyperAgentBillingInfo:
|
|
925
|
-
return HyperAgentBillingInfo.from_dict(self._control_get("/billing/info").get("company_billing", {}))
|
|
926
|
-
|
|
927
|
-
def billing_profile(self) -> HyperAgentBillingProfileResponse:
|
|
928
|
-
return HyperAgentBillingProfileResponse.from_dict(self._control_get("/billing/profile"))
|
|
929
|
-
|
|
930
|
-
def update_billing_profile(self, profile: HyperAgentBillingProfileFields) -> HyperAgentBillingProfileResponse:
|
|
931
|
-
return HyperAgentBillingProfileResponse.from_dict(
|
|
932
|
-
self._control_put("/billing/profile", payload=profile.to_dict())
|
|
933
|
-
)
|
|
934
|
-
|
|
935
|
-
def payments(
|
|
936
|
-
self,
|
|
937
|
-
*,
|
|
938
|
-
limit: int | None = None,
|
|
939
|
-
provider: str | None = None,
|
|
940
|
-
status: str | None = None,
|
|
941
|
-
) -> HyperAgentPaymentsResponse:
|
|
942
|
-
params: dict[str, Any] = {}
|
|
943
|
-
if limit is not None:
|
|
944
|
-
params["limit"] = limit
|
|
945
|
-
if provider:
|
|
946
|
-
params["provider"] = provider
|
|
947
|
-
if status:
|
|
948
|
-
params["status"] = status
|
|
949
|
-
return HyperAgentPaymentsResponse.from_dict(self._control_get("/billing/payments", params=params or None))
|
|
950
|
-
|
|
951
|
-
def payment(self, payment_id: str) -> HyperAgentPayment:
|
|
952
|
-
return HyperAgentPayment.from_dict(self._control_get(f"/billing/payments/{payment_id}"))
|
|
953
|
-
|
|
954
|
-
def create_stripe_checkout(
|
|
955
|
-
self,
|
|
956
|
-
*,
|
|
957
|
-
bundle: dict[str, int] | None = None,
|
|
958
|
-
quantity: int | None = None,
|
|
959
|
-
success_url: str | None = None,
|
|
960
|
-
cancel_url: str | None = None,
|
|
961
|
-
plan_id: str | None = None,
|
|
962
|
-
) -> HyperAgentStripeCheckoutResponse:
|
|
963
|
-
payload: dict[str, Any] = {}
|
|
964
|
-
if bundle is not None:
|
|
965
|
-
payload["bundle"] = dict(bundle)
|
|
966
|
-
if quantity is not None:
|
|
967
|
-
payload["quantity"] = quantity
|
|
968
|
-
if success_url is not None:
|
|
969
|
-
payload["success_url"] = success_url
|
|
970
|
-
if cancel_url is not None:
|
|
971
|
-
payload["cancel_url"] = cancel_url
|
|
972
|
-
path = f"/stripe/{plan_id}" if plan_id else "/stripe/checkout"
|
|
973
|
-
return HyperAgentStripeCheckoutResponse.from_dict(self._control_post(path, payload=payload))
|
|
974
|
-
|
|
975
|
-
def create_x402_checkout(
|
|
976
|
-
self,
|
|
977
|
-
*,
|
|
978
|
-
bundle: dict[str, int] | None = None,
|
|
979
|
-
quantity: int | None = None,
|
|
980
|
-
) -> HyperAgentX402CheckoutResponse:
|
|
981
|
-
payload: dict[str, Any] = {}
|
|
982
|
-
if bundle is not None:
|
|
983
|
-
payload["bundle"] = dict(bundle)
|
|
984
|
-
if quantity is not None:
|
|
985
|
-
payload["quantity"] = quantity
|
|
986
|
-
return HyperAgentX402CheckoutResponse.from_dict(self._control_post("/x402/checkout", payload=payload))
|
|
910
|
+
return response.json()
|
|
987
911
|
|
|
988
912
|
def discovery_health(self) -> Dict[str, Any]:
|
|
989
913
|
response = self._http._session.get(f"{self._api_base_without_v1()}/discovery/health")
|
|
@@ -7,7 +7,6 @@ from unittest.mock import Mock, patch, MagicMock
|
|
|
7
7
|
from hypercli import HyperCLI
|
|
8
8
|
from hypercli.agent import (
|
|
9
9
|
HyperAgent,
|
|
10
|
-
HyperAgentEntitlement,
|
|
11
10
|
HyperAgentEntitlements,
|
|
12
11
|
HyperAgentEntitlementsSummary,
|
|
13
12
|
HyperAgentPlan,
|
|
@@ -97,27 +96,9 @@ class TestHyperAgentDataclasses:
|
|
|
97
96
|
"pooled_tpm_limit": 2000,
|
|
98
97
|
"pooled_rpm_limit": 20,
|
|
99
98
|
"pooled_tpd": 2000000,
|
|
100
|
-
"billing_reset_at": "2026-04-15T00:00:00Z",
|
|
101
99
|
"slot_inventory": {"large": {"granted": 2, "used": 1, "available": 1}},
|
|
102
100
|
"active_entitlement_count": 1,
|
|
103
101
|
},
|
|
104
|
-
"entitlement_items": [
|
|
105
|
-
{
|
|
106
|
-
"id": "ent-1",
|
|
107
|
-
"user_id": "user-1",
|
|
108
|
-
"subscription_id": "sub-1",
|
|
109
|
-
"plan_id": "large",
|
|
110
|
-
"plan_name": "Large",
|
|
111
|
-
"provider": "STRIPE",
|
|
112
|
-
"status": "ACTIVE",
|
|
113
|
-
"expires_at": "2026-04-15T00:00:00Z",
|
|
114
|
-
"agent_tier": "large",
|
|
115
|
-
"features": {"voice": True},
|
|
116
|
-
"tags": ["customer=acme"],
|
|
117
|
-
"active_agent_count": 1,
|
|
118
|
-
"active_agent_ids": ["agent-1"],
|
|
119
|
-
}
|
|
120
|
-
],
|
|
121
102
|
"active_subscriptions": [
|
|
122
103
|
{
|
|
123
104
|
"id": "sub-1",
|
|
@@ -137,8 +118,6 @@ class TestHyperAgentDataclasses:
|
|
|
137
118
|
assert summary.active_subscription_count == 1
|
|
138
119
|
assert isinstance(summary.entitlements, HyperAgentEntitlements)
|
|
139
120
|
assert summary.entitlements.active_entitlement_count == 1
|
|
140
|
-
assert summary.billing_reset_at is not None
|
|
141
|
-
assert summary.entitlements.billing_reset_at is not None
|
|
142
121
|
assert summary.active_subscriptions[0].plan_id == "large"
|
|
143
122
|
assert isinstance(summary.entitlement_items[0], HyperAgentEntitlement)
|
|
144
123
|
assert summary.entitlement_items[0].tags == ["customer=acme"]
|
|
@@ -279,7 +258,6 @@ class TestHyperAgentClient:
|
|
|
279
258
|
"pooled_tpm_limit": 2000,
|
|
280
259
|
"pooled_rpm_limit": 20,
|
|
281
260
|
"pooled_tpd": 2000000,
|
|
282
|
-
"billing_reset_at": "2026-04-15T00:00:00Z",
|
|
283
261
|
"slot_inventory": {"large": {"granted": 2, "used": 1, "available": 1}},
|
|
284
262
|
"active_subscription_count": 1,
|
|
285
263
|
"active_entitlement_count": 1,
|
|
@@ -288,26 +266,9 @@ class TestHyperAgentClient:
|
|
|
288
266
|
"pooled_tpm_limit": 2000,
|
|
289
267
|
"pooled_rpm_limit": 20,
|
|
290
268
|
"pooled_tpd": 2000000,
|
|
291
|
-
"billing_reset_at": "2026-04-15T00:00:00Z",
|
|
292
269
|
"slot_inventory": {"large": {"granted": 2, "used": 1, "available": 1}},
|
|
293
270
|
"active_entitlement_count": 1,
|
|
294
271
|
},
|
|
295
|
-
"entitlement_items": [
|
|
296
|
-
{
|
|
297
|
-
"id": "ent-1",
|
|
298
|
-
"user_id": "user-1",
|
|
299
|
-
"plan_id": "large",
|
|
300
|
-
"plan_name": "Large",
|
|
301
|
-
"provider": "X402",
|
|
302
|
-
"status": "ACTIVE",
|
|
303
|
-
"expires_at": "2026-04-20T00:00:00Z",
|
|
304
|
-
"agent_tier": "large",
|
|
305
|
-
"features": {"voice": True},
|
|
306
|
-
"tags": ["customer=acme"],
|
|
307
|
-
"active_agent_count": 0,
|
|
308
|
-
"active_agent_ids": [],
|
|
309
|
-
}
|
|
310
|
-
],
|
|
311
272
|
"active_subscriptions": [],
|
|
312
273
|
"subscriptions": [],
|
|
313
274
|
"user": {"id": "user-1", "team_id": "team-1"},
|
|
@@ -318,242 +279,27 @@ class TestHyperAgentClient:
|
|
|
318
279
|
summary = agent.entitlements()
|
|
319
280
|
|
|
320
281
|
assert isinstance(summary, HyperAgentEntitlementsSummary)
|
|
321
|
-
assert summary.billing_reset_at is not None
|
|
322
282
|
assert summary.entitlements.slot_inventory["large"]["available"] == 1
|
|
323
|
-
assert summary.entitlement_items[0].provider == "X402"
|
|
324
283
|
mock_http._session.get.assert_called_with(
|
|
325
284
|
"https://api.hypercli.com/agents/entitlements",
|
|
326
285
|
headers={"Authorization": "Bearer sk-hyper-test"},
|
|
327
286
|
)
|
|
328
287
|
|
|
329
|
-
def test_entitlement_instances(self, mock_http):
|
|
330
|
-
mock_http._session.get.return_value.json.return_value = {
|
|
331
|
-
"items": [
|
|
332
|
-
{
|
|
333
|
-
"id": "ent-1",
|
|
334
|
-
"user_id": "user-1",
|
|
335
|
-
"subscription_id": None,
|
|
336
|
-
"plan_id": "large",
|
|
337
|
-
"plan_name": "Large",
|
|
338
|
-
"provider": "X402",
|
|
339
|
-
"status": "ACTIVE",
|
|
340
|
-
"expires_at": "2026-04-20T00:00:00Z",
|
|
341
|
-
"agent_tier": "large",
|
|
342
|
-
"features": {"voice": True},
|
|
343
|
-
"tags": ["customer=acme"],
|
|
344
|
-
"active_agent_count": 0,
|
|
345
|
-
"active_agent_ids": [],
|
|
346
|
-
}
|
|
347
|
-
]
|
|
348
|
-
}
|
|
349
|
-
mock_http._session.get.return_value.raise_for_status = Mock()
|
|
350
|
-
|
|
351
|
-
agent = HyperAgent(mock_http, agent_api_key="sk-hyper-test", agents_api_base_url="https://api.hypercli.com/agents")
|
|
352
|
-
entitlements = agent.entitlement_instances()
|
|
353
|
-
|
|
354
|
-
assert len(entitlements) == 1
|
|
355
|
-
assert entitlements[0].plan_id == "large"
|
|
356
|
-
assert entitlements[0].tags == ["customer=acme"]
|
|
357
|
-
mock_http._session.get.assert_called_with(
|
|
358
|
-
"https://api.hypercli.com/agents/entitlements/instances",
|
|
359
|
-
headers={"Authorization": "Bearer sk-hyper-test"},
|
|
360
|
-
)
|
|
361
|
-
|
|
362
288
|
def test_cancel_subscription(self, mock_http):
|
|
363
289
|
mock_http._session.post.return_value.json.return_value = {
|
|
364
290
|
"ok": True,
|
|
365
291
|
"message": "Subscription will be cancelled at the end of the current billing period",
|
|
366
|
-
"subscription": {
|
|
367
|
-
"id": "sub-1",
|
|
368
|
-
"user_id": "user-1",
|
|
369
|
-
"plan_id": "large",
|
|
370
|
-
"plan_name": "Large",
|
|
371
|
-
"provider": "STRIPE",
|
|
372
|
-
"status": "ACTIVE",
|
|
373
|
-
"cancel_at_period_end": True,
|
|
374
|
-
"can_cancel": True,
|
|
375
|
-
},
|
|
376
292
|
}
|
|
377
293
|
mock_http._session.post.return_value.raise_for_status = Mock()
|
|
378
294
|
|
|
379
295
|
agent = HyperAgent(mock_http, agent_api_key="sk-hyper-test", agents_api_base_url="https://api.hypercli.com/agents")
|
|
380
296
|
result = agent.cancel_subscription("sub-1")
|
|
381
297
|
|
|
382
|
-
assert result
|
|
383
|
-
assert result.subscription is not None
|
|
384
|
-
assert result.subscription.cancel_at_period_end is True
|
|
385
|
-
mock_http._session.post.assert_called_with(
|
|
386
|
-
"https://api.hypercli.com/agents/subscriptions/sub-1/update",
|
|
387
|
-
headers={"Authorization": "Bearer sk-hyper-test"},
|
|
388
|
-
json={"bundle": {}},
|
|
389
|
-
)
|
|
390
|
-
|
|
391
|
-
def test_update_subscription(self, mock_http):
|
|
392
|
-
mock_http._session.post.return_value.json.return_value = {
|
|
393
|
-
"ok": True,
|
|
394
|
-
"message": "Subscription upgraded immediately",
|
|
395
|
-
"subscription": {
|
|
396
|
-
"id": "sub-1",
|
|
397
|
-
"user_id": "user-1",
|
|
398
|
-
"plan_id": "large",
|
|
399
|
-
"plan_name": "Large",
|
|
400
|
-
"provider": "STRIPE",
|
|
401
|
-
"status": "ACTIVE",
|
|
402
|
-
"cancel_at_period_end": False,
|
|
403
|
-
"can_cancel": True,
|
|
404
|
-
},
|
|
405
|
-
}
|
|
406
|
-
mock_http._session.post.return_value.raise_for_status = Mock()
|
|
407
|
-
|
|
408
|
-
agent = HyperAgent(mock_http, agent_api_key="sk-hyper-test", agents_api_base_url="https://api.hypercli.com/agents")
|
|
409
|
-
result = agent.update_subscription("sub-1", {"large": 1})
|
|
410
|
-
|
|
411
|
-
assert result.ok is True
|
|
412
|
-
assert result.subscription is not None
|
|
413
|
-
assert result.subscription.plan_id == "large"
|
|
298
|
+
assert result["ok"] is True
|
|
414
299
|
mock_http._session.post.assert_called_with(
|
|
415
|
-
"https://api.hypercli.com/agents/subscriptions/sub-1/
|
|
300
|
+
"https://api.hypercli.com/agents/subscriptions/sub-1/cancel",
|
|
416
301
|
headers={"Authorization": "Bearer sk-hyper-test"},
|
|
417
|
-
json={"bundle": {"large": 1}},
|
|
418
302
|
)
|
|
419
|
-
|
|
420
|
-
def test_usage_endpoints(self, mock_http):
|
|
421
|
-
mock_http._session.get.side_effect = [
|
|
422
|
-
Mock(json=Mock(return_value={
|
|
423
|
-
"total_tokens": 100,
|
|
424
|
-
"prompt_tokens": 60,
|
|
425
|
-
"completion_tokens": 40,
|
|
426
|
-
"request_count": 5,
|
|
427
|
-
"active_keys": 2,
|
|
428
|
-
"current_tpm": 1000,
|
|
429
|
-
"current_rpm": 10,
|
|
430
|
-
"period": "30d",
|
|
431
|
-
}), raise_for_status=Mock()),
|
|
432
|
-
Mock(json=Mock(return_value={
|
|
433
|
-
"history": [{"date": "2026-04-13", "total_tokens": 100, "prompt_tokens": 60, "completion_tokens": 40, "requests": 5}],
|
|
434
|
-
"days": 7,
|
|
435
|
-
}), raise_for_status=Mock()),
|
|
436
|
-
Mock(json=Mock(return_value={
|
|
437
|
-
"keys": [{"key_hash": "key-1", "name": "Primary", "total_tokens": 100, "prompt_tokens": 60, "completion_tokens": 40, "requests": 5}],
|
|
438
|
-
"days": 7,
|
|
439
|
-
}), raise_for_status=Mock()),
|
|
440
|
-
]
|
|
441
|
-
|
|
442
|
-
agent = HyperAgent(mock_http, agent_api_key="sk-hyper-test", agents_api_base_url="https://api.hypercli.com/agents")
|
|
443
|
-
summary = agent.usage_summary()
|
|
444
|
-
history = agent.usage_history()
|
|
445
|
-
keys = agent.key_usage()
|
|
446
|
-
|
|
447
|
-
assert isinstance(summary, HyperAgentUsageSummary)
|
|
448
|
-
assert summary.total_tokens == 100
|
|
449
|
-
assert isinstance(history, HyperAgentUsageHistory)
|
|
450
|
-
assert history.history[0].date == "2026-04-13"
|
|
451
|
-
assert isinstance(keys, HyperAgentKeyUsage)
|
|
452
|
-
assert keys.keys[0].key_hash == "key-1"
|
|
453
|
-
|
|
454
|
-
def test_types_and_billing_endpoints(self, mock_http):
|
|
455
|
-
mock_http._session.get.side_effect = [
|
|
456
|
-
Mock(json=Mock(return_value={
|
|
457
|
-
"types": [{"id": "medium", "name": "Medium", "cpu": 1, "memory": 2, "cpu_limit": 1, "memory_limit": 2}],
|
|
458
|
-
"plans": [{"id": "2aiu", "name": "2 AIU", "price": 20, "agents": 1, "agent_type": "medium", "highlighted": True}],
|
|
459
|
-
}), raise_for_status=Mock()),
|
|
460
|
-
Mock(json=Mock(return_value={
|
|
461
|
-
"company_billing": {"address": ["HyperCLI"], "email": "support@hypercli.com"},
|
|
462
|
-
"profile": None,
|
|
463
|
-
}), raise_for_status=Mock()),
|
|
464
|
-
Mock(json=Mock(return_value={
|
|
465
|
-
"company_billing": {"address": ["HyperCLI"], "email": "support@hypercli.com"},
|
|
466
|
-
"profile": {"billing_name": "Test User"},
|
|
467
|
-
}), raise_for_status=Mock()),
|
|
468
|
-
]
|
|
469
|
-
mock_http._session.put.return_value.json.return_value = {
|
|
470
|
-
"company_billing": {"address": ["HyperCLI"], "email": "support@hypercli.com"},
|
|
471
|
-
"profile": {"billing_name": "Test User"},
|
|
472
|
-
"synced_stripe_customer_ids": ["cus_123"],
|
|
473
|
-
}
|
|
474
|
-
mock_http._session.put.return_value.raise_for_status = Mock()
|
|
475
|
-
|
|
476
|
-
agent = HyperAgent(mock_http, agent_api_key="sk-hyper-test", agents_api_base_url="https://api.hypercli.com/agents")
|
|
477
|
-
catalog = agent.agent_types()
|
|
478
|
-
info = agent.billing_info()
|
|
479
|
-
profile = agent.billing_profile()
|
|
480
|
-
updated = agent.update_billing_profile(HyperAgentBillingProfileFields(billing_name="Test User"))
|
|
481
|
-
|
|
482
|
-
assert isinstance(catalog, HyperAgentTypeCatalog)
|
|
483
|
-
assert catalog.types[0].id == "medium"
|
|
484
|
-
assert isinstance(info, HyperAgentBillingInfo)
|
|
485
|
-
assert info.email == "support@hypercli.com"
|
|
486
|
-
assert isinstance(profile, HyperAgentBillingProfileResponse)
|
|
487
|
-
assert profile.profile is not None
|
|
488
|
-
assert profile.profile.billing_name == "Test User"
|
|
489
|
-
assert updated.synced_stripe_customer_ids == ["cus_123"]
|
|
490
|
-
|
|
491
|
-
def test_payments_and_checkout_endpoints(self, mock_http):
|
|
492
|
-
mock_http._session.get.side_effect = [
|
|
493
|
-
Mock(json=Mock(return_value={
|
|
494
|
-
"items": [{
|
|
495
|
-
"id": "pay_123",
|
|
496
|
-
"user_id": "user-1",
|
|
497
|
-
"subscription_id": None,
|
|
498
|
-
"entitlement_id": None,
|
|
499
|
-
"provider": "STRIPE",
|
|
500
|
-
"status": "SUCCEEDED",
|
|
501
|
-
"amount": "2000",
|
|
502
|
-
"currency": "usd",
|
|
503
|
-
"external_payment_id": "pi_123",
|
|
504
|
-
"created_at": "2026-04-13T00:00:00Z",
|
|
505
|
-
"updated_at": "2026-04-13T00:00:00Z",
|
|
506
|
-
"user": {"id": "user-1", "email": "user@example.com", "wallet_address": None, "team_id": "team-1", "plan_id": "2aiu"},
|
|
507
|
-
"subscription": None,
|
|
508
|
-
"entitlement": None,
|
|
509
|
-
}]
|
|
510
|
-
}), raise_for_status=Mock()),
|
|
511
|
-
Mock(json=Mock(return_value={
|
|
512
|
-
"id": "pay_123",
|
|
513
|
-
"user_id": "user-1",
|
|
514
|
-
"subscription_id": None,
|
|
515
|
-
"entitlement_id": None,
|
|
516
|
-
"provider": "STRIPE",
|
|
517
|
-
"status": "SUCCEEDED",
|
|
518
|
-
"amount": "2000",
|
|
519
|
-
"currency": "usd",
|
|
520
|
-
"external_payment_id": "pi_123",
|
|
521
|
-
"created_at": "2026-04-13T00:00:00Z",
|
|
522
|
-
"updated_at": "2026-04-13T00:00:00Z",
|
|
523
|
-
"user": {"id": "user-1", "email": "user@example.com", "wallet_address": None, "team_id": "team-1", "plan_id": "2aiu"},
|
|
524
|
-
"subscription": None,
|
|
525
|
-
"entitlement": None,
|
|
526
|
-
}), raise_for_status=Mock()),
|
|
527
|
-
]
|
|
528
|
-
mock_http._session.post.side_effect = [
|
|
529
|
-
Mock(json=Mock(return_value={"checkout_url": "https://checkout.stripe.test/session"}), raise_for_status=Mock()),
|
|
530
|
-
Mock(json=Mock(return_value={
|
|
531
|
-
"ok": True,
|
|
532
|
-
"key": "sk-x402",
|
|
533
|
-
"plan_id": "2aiu",
|
|
534
|
-
"quantity": 1,
|
|
535
|
-
"bundle": {"medium": 1},
|
|
536
|
-
"amount_paid": "20.000000",
|
|
537
|
-
"duration_days": 30,
|
|
538
|
-
"expires_at": "2026-05-13T00:00:00Z",
|
|
539
|
-
"tpm_limit": 1000,
|
|
540
|
-
"rpm_limit": 10,
|
|
541
|
-
}), raise_for_status=Mock()),
|
|
542
|
-
]
|
|
543
|
-
|
|
544
|
-
agent = HyperAgent(mock_http, agent_api_key="sk-hyper-test", agents_api_base_url="https://api.hypercli.com/agents")
|
|
545
|
-
payments = agent.payments(limit=10, provider="stripe", status="succeeded")
|
|
546
|
-
payment = agent.payment("pay_123")
|
|
547
|
-
stripe = agent.create_stripe_checkout(bundle={"medium": 1})
|
|
548
|
-
x402 = agent.create_x402_checkout(bundle={"medium": 1})
|
|
549
|
-
|
|
550
|
-
assert isinstance(payments, HyperAgentPaymentsResponse)
|
|
551
|
-
assert payments.items[0].id == "pay_123"
|
|
552
|
-
assert payment.external_payment_id == "pi_123"
|
|
553
|
-
assert isinstance(stripe, HyperAgentStripeCheckoutResponse)
|
|
554
|
-
assert stripe.checkout_url == "https://checkout.stripe.test/session"
|
|
555
|
-
assert isinstance(x402, HyperAgentX402CheckoutResponse)
|
|
556
|
-
assert x402.plan_id == "2aiu"
|
|
557
303
|
|
|
558
304
|
def test_openai_client_creation(self, mock_http):
|
|
559
305
|
"""Test that OpenAI client is created with correct config."""
|
|
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
|
|
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
|