hypercli-sdk 2026.4.13__tar.gz → 2026.4.13.post4__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.
Files changed (53) hide show
  1. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/PKG-INFO +1 -1
  2. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/hypercli/__init__.py +37 -1
  3. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/hypercli/agent.py +471 -0
  4. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/pyproject.toml +1 -1
  5. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/tests/test_claw.py +149 -0
  6. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/.gitignore +0 -0
  7. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/README.md +0 -0
  8. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/hypercli/agents.py +0 -0
  9. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/hypercli/billing.py +0 -0
  10. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/hypercli/client.py +0 -0
  11. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/hypercli/config.py +0 -0
  12. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/hypercli/files.py +0 -0
  13. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/hypercli/gateway.py +0 -0
  14. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/hypercli/http.py +0 -0
  15. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/hypercli/instances.py +0 -0
  16. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/hypercli/job/__init__.py +0 -0
  17. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/hypercli/job/base.py +0 -0
  18. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/hypercli/job/comfyui.py +0 -0
  19. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/hypercli/job/gradio.py +0 -0
  20. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/hypercli/jobs.py +0 -0
  21. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/hypercli/keys.py +0 -0
  22. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/hypercli/logs.py +0 -0
  23. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/hypercli/models.py +0 -0
  24. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/hypercli/openclaw/__init__.py +0 -0
  25. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/hypercli/openclaw/gateway.py +0 -0
  26. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/hypercli/renders.py +0 -0
  27. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/hypercli/shell.py +0 -0
  28. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/hypercli/user.py +0 -0
  29. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/hypercli/voice.py +0 -0
  30. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/hypercli/x402.py +0 -0
  31. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/tests/integration/conftest.py +0 -0
  32. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/tests/integration/test_agents.py +0 -0
  33. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/tests/integration/test_auth.py +0 -0
  34. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/tests/integration/test_billing.py +0 -0
  35. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/tests/integration/test_instances.py +0 -0
  36. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/tests/integration/test_jobs_dryrun.py +0 -0
  37. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/tests/integration/test_keys.py +0 -0
  38. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/tests/integration/test_renders.py +0 -0
  39. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/tests/test_agents.py +0 -0
  40. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/tests/test_apply_params.py +0 -0
  41. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/tests/test_bootstrap_console_test_key.py +0 -0
  42. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/tests/test_bootstrap_dev_test_keys.py +0 -0
  43. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/tests/test_config.py +0 -0
  44. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/tests/test_exec_shell_dryrun.py +0 -0
  45. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/tests/test_gateway.py +0 -0
  46. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/tests/test_gateway_retry.py +0 -0
  47. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/tests/test_graph_to_api.py +0 -0
  48. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/tests/test_http.py +0 -0
  49. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/tests/test_jobs.py +0 -0
  50. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/tests/test_keys.py +0 -0
  51. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/tests/test_models.py +0 -0
  52. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/tests/test_renders_subscription.py +0 -0
  53. {hypercli_sdk-2026.4.13 → hypercli_sdk-2026.4.13.post4}/tests/test_voice.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hypercli-sdk
3
- Version: 2026.4.13
3
+ Version: 2026.4.13.post4
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
@@ -48,6 +48,24 @@ from .agent import (
48
48
  HyperAgentSubscription,
49
49
  HyperAgentSubscriptionSummary,
50
50
  HyperAgentModel,
51
+ HyperAgentUsageSummary,
52
+ HyperAgentUsageHistoryEntry,
53
+ HyperAgentUsageHistory,
54
+ HyperAgentKeyUsageEntry,
55
+ HyperAgentKeyUsage,
56
+ HyperAgentTypePreset,
57
+ HyperAgentTypePlan,
58
+ HyperAgentTypeCatalog,
59
+ HyperAgentBillingProfileFields,
60
+ HyperAgentBillingInfo,
61
+ HyperAgentBillingProfileResponse,
62
+ HyperAgentBillingUser,
63
+ HyperAgentPaymentSubscription,
64
+ HyperAgentPaymentEntitlement,
65
+ HyperAgentPayment,
66
+ HyperAgentPaymentsResponse,
67
+ HyperAgentStripeCheckoutResponse,
68
+ HyperAgentX402CheckoutResponse,
51
69
  )
52
70
  from .gateway import (
53
71
  GatewayClient,
@@ -60,7 +78,7 @@ from .gateway import (
60
78
  extract_gateway_chat_tool_calls,
61
79
  normalize_gateway_chat_message,
62
80
  )
63
- __version__ = "2026.4.13"
81
+ __version__ = "2026.4.13.post4"
64
82
  __all__ = [
65
83
  "HyperCLI",
66
84
  "configure",
@@ -148,6 +166,24 @@ __all__ = [
148
166
  "HyperAgentSubscription",
149
167
  "HyperAgentSubscriptionSummary",
150
168
  "HyperAgentModel",
169
+ "HyperAgentUsageSummary",
170
+ "HyperAgentUsageHistoryEntry",
171
+ "HyperAgentUsageHistory",
172
+ "HyperAgentKeyUsageEntry",
173
+ "HyperAgentKeyUsage",
174
+ "HyperAgentTypePreset",
175
+ "HyperAgentTypePlan",
176
+ "HyperAgentTypeCatalog",
177
+ "HyperAgentBillingProfileFields",
178
+ "HyperAgentBillingInfo",
179
+ "HyperAgentBillingProfileResponse",
180
+ "HyperAgentBillingUser",
181
+ "HyperAgentPaymentSubscription",
182
+ "HyperAgentPaymentEntitlement",
183
+ "HyperAgentPayment",
184
+ "HyperAgentPaymentsResponse",
185
+ "HyperAgentStripeCheckoutResponse",
186
+ "HyperAgentX402CheckoutResponse",
151
187
  # OpenClaw Gateway
152
188
  "GatewayClient",
153
189
  "GatewayError",
@@ -306,6 +306,374 @@ class HyperAgentModel:
306
306
  )
307
307
 
308
308
 
309
+ @dataclass
310
+ class HyperAgentUsageSummary:
311
+ total_tokens: int
312
+ prompt_tokens: int
313
+ completion_tokens: int
314
+ request_count: int
315
+ active_keys: int
316
+ current_tpm: int
317
+ current_rpm: int
318
+ period: str
319
+
320
+ @classmethod
321
+ def from_dict(cls, data: dict) -> "HyperAgentUsageSummary":
322
+ return cls(
323
+ total_tokens=int(data.get("total_tokens", 0) or 0),
324
+ prompt_tokens=int(data.get("prompt_tokens", 0) or 0),
325
+ completion_tokens=int(data.get("completion_tokens", 0) or 0),
326
+ request_count=int(data.get("request_count", 0) or 0),
327
+ active_keys=int(data.get("active_keys", 0) or 0),
328
+ current_tpm=int(data.get("current_tpm", 0) or 0),
329
+ current_rpm=int(data.get("current_rpm", 0) or 0),
330
+ period=str(data.get("period", "")),
331
+ )
332
+
333
+
334
+ @dataclass
335
+ class HyperAgentUsageHistoryEntry:
336
+ date: str
337
+ total_tokens: int
338
+ prompt_tokens: int
339
+ completion_tokens: int
340
+ requests: int
341
+
342
+ @classmethod
343
+ def from_dict(cls, data: dict) -> "HyperAgentUsageHistoryEntry":
344
+ return cls(
345
+ date=str(data.get("date", "")),
346
+ total_tokens=int(data.get("total_tokens", 0) or 0),
347
+ prompt_tokens=int(data.get("prompt_tokens", 0) or 0),
348
+ completion_tokens=int(data.get("completion_tokens", 0) or 0),
349
+ requests=int(data.get("requests", 0) or 0),
350
+ )
351
+
352
+
353
+ @dataclass
354
+ class HyperAgentUsageHistory:
355
+ history: list[HyperAgentUsageHistoryEntry]
356
+ days: int
357
+
358
+ @classmethod
359
+ def from_dict(cls, data: dict) -> "HyperAgentUsageHistory":
360
+ return cls(
361
+ history=[HyperAgentUsageHistoryEntry.from_dict(item) for item in data.get("history", [])],
362
+ days=int(data.get("days", 0) or 0),
363
+ )
364
+
365
+
366
+ @dataclass
367
+ class HyperAgentKeyUsageEntry:
368
+ key_hash: str
369
+ name: str
370
+ total_tokens: int
371
+ prompt_tokens: int
372
+ completion_tokens: int
373
+ requests: int
374
+
375
+ @classmethod
376
+ def from_dict(cls, data: dict) -> "HyperAgentKeyUsageEntry":
377
+ return cls(
378
+ key_hash=str(data.get("key_hash", "")),
379
+ name=str(data.get("name", "")),
380
+ total_tokens=int(data.get("total_tokens", 0) or 0),
381
+ prompt_tokens=int(data.get("prompt_tokens", 0) or 0),
382
+ completion_tokens=int(data.get("completion_tokens", 0) or 0),
383
+ requests=int(data.get("requests", 0) or 0),
384
+ )
385
+
386
+
387
+ @dataclass
388
+ class HyperAgentKeyUsage:
389
+ keys: list[HyperAgentKeyUsageEntry]
390
+ days: int
391
+
392
+ @classmethod
393
+ def from_dict(cls, data: dict) -> "HyperAgentKeyUsage":
394
+ return cls(
395
+ keys=[HyperAgentKeyUsageEntry.from_dict(item) for item in data.get("keys", [])],
396
+ days=int(data.get("days", 0) or 0),
397
+ )
398
+
399
+
400
+ @dataclass
401
+ class HyperAgentTypePreset:
402
+ id: str
403
+ name: str
404
+ cpu: float
405
+ memory: int
406
+ cpu_limit: float
407
+ memory_limit: int
408
+
409
+ @classmethod
410
+ def from_dict(cls, data: dict) -> "HyperAgentTypePreset":
411
+ return cls(
412
+ id=str(data.get("id", "")),
413
+ name=str(data.get("name", "")),
414
+ cpu=float(data.get("cpu", 0) or 0),
415
+ memory=int(data.get("memory", 0) or 0),
416
+ cpu_limit=float(data.get("cpu_limit", 0) or 0),
417
+ memory_limit=int(data.get("memory_limit", 0) or 0),
418
+ )
419
+
420
+
421
+ @dataclass
422
+ class HyperAgentTypePlan:
423
+ id: str
424
+ name: str
425
+ price: int
426
+ agents: int
427
+ agent_type: str
428
+ highlighted: bool
429
+
430
+ @classmethod
431
+ def from_dict(cls, data: dict) -> "HyperAgentTypePlan":
432
+ return cls(
433
+ id=str(data.get("id", "")),
434
+ name=str(data.get("name", "")),
435
+ price=int(data.get("price", 0) or 0),
436
+ agents=int(data.get("agents", 0) or 0),
437
+ agent_type=str(data.get("agent_type", "")),
438
+ highlighted=bool(data.get("highlighted", False)),
439
+ )
440
+
441
+
442
+ @dataclass
443
+ class HyperAgentTypeCatalog:
444
+ types: list[HyperAgentTypePreset]
445
+ plans: list[HyperAgentTypePlan]
446
+
447
+ @classmethod
448
+ def from_dict(cls, data: dict) -> "HyperAgentTypeCatalog":
449
+ return cls(
450
+ types=[HyperAgentTypePreset.from_dict(item) for item in data.get("types", [])],
451
+ plans=[HyperAgentTypePlan.from_dict(item) for item in data.get("plans", [])],
452
+ )
453
+
454
+
455
+ @dataclass
456
+ class HyperAgentBillingProfileFields:
457
+ billing_name: str | None = None
458
+ billing_company: str | None = None
459
+ billing_tax_id: str | None = None
460
+ billing_line1: str | None = None
461
+ billing_line2: str | None = None
462
+ billing_city: str | None = None
463
+ billing_state: str | None = None
464
+ billing_postal_code: str | None = None
465
+ billing_country: str | None = None
466
+
467
+ @classmethod
468
+ def from_dict(cls, data: dict) -> "HyperAgentBillingProfileFields":
469
+ return cls(
470
+ billing_name=data.get("billing_name"),
471
+ billing_company=data.get("billing_company"),
472
+ billing_tax_id=data.get("billing_tax_id"),
473
+ billing_line1=data.get("billing_line1"),
474
+ billing_line2=data.get("billing_line2"),
475
+ billing_city=data.get("billing_city"),
476
+ billing_state=data.get("billing_state"),
477
+ billing_postal_code=data.get("billing_postal_code"),
478
+ billing_country=data.get("billing_country"),
479
+ )
480
+
481
+ def to_dict(self) -> dict[str, str | None]:
482
+ return {
483
+ "billing_name": self.billing_name,
484
+ "billing_company": self.billing_company,
485
+ "billing_tax_id": self.billing_tax_id,
486
+ "billing_line1": self.billing_line1,
487
+ "billing_line2": self.billing_line2,
488
+ "billing_city": self.billing_city,
489
+ "billing_state": self.billing_state,
490
+ "billing_postal_code": self.billing_postal_code,
491
+ "billing_country": self.billing_country,
492
+ }
493
+
494
+
495
+ @dataclass
496
+ class HyperAgentBillingInfo:
497
+ address: list[str]
498
+ email: str
499
+
500
+ @classmethod
501
+ def from_dict(cls, data: dict) -> "HyperAgentBillingInfo":
502
+ return cls(
503
+ address=[str(item) for item in data.get("address", [])],
504
+ email=str(data.get("email", "")),
505
+ )
506
+
507
+
508
+ @dataclass
509
+ class HyperAgentBillingProfileResponse:
510
+ company_billing: HyperAgentBillingInfo
511
+ profile: HyperAgentBillingProfileFields | None
512
+ synced_stripe_customer_ids: list[str] | None = None
513
+
514
+ @classmethod
515
+ def from_dict(cls, data: dict) -> "HyperAgentBillingProfileResponse":
516
+ return cls(
517
+ company_billing=HyperAgentBillingInfo.from_dict(data.get("company_billing", {})),
518
+ profile=HyperAgentBillingProfileFields.from_dict(data["profile"]) if data.get("profile") else None,
519
+ synced_stripe_customer_ids=[str(item) for item in data.get("synced_stripe_customer_ids", [])] or None,
520
+ )
521
+
522
+
523
+ @dataclass
524
+ class HyperAgentBillingUser:
525
+ id: str
526
+ email: str | None
527
+ wallet_address: str | None
528
+ team_id: str | None
529
+ plan_id: str | None
530
+
531
+ @classmethod
532
+ def from_dict(cls, data: dict) -> "HyperAgentBillingUser":
533
+ return cls(
534
+ id=str(data.get("id", "")),
535
+ email=data.get("email"),
536
+ wallet_address=data.get("wallet_address"),
537
+ team_id=data.get("team_id"),
538
+ plan_id=data.get("plan_id"),
539
+ )
540
+
541
+
542
+ @dataclass
543
+ class HyperAgentPaymentSubscription:
544
+ id: str
545
+ plan_id: str
546
+ provider: str
547
+ status: str
548
+ current_period_end: datetime | None
549
+ stripe_subscription_id: str | None
550
+
551
+ @classmethod
552
+ def from_dict(cls, data: dict) -> "HyperAgentPaymentSubscription":
553
+ current_period_end = data.get("current_period_end")
554
+ return cls(
555
+ id=str(data.get("id", "")),
556
+ plan_id=str(data.get("plan_id", "")),
557
+ provider=str(data.get("provider", "")),
558
+ status=str(data.get("status", "")),
559
+ current_period_end=datetime.fromisoformat(str(current_period_end).replace("Z", "+00:00")) if current_period_end else None,
560
+ stripe_subscription_id=data.get("stripe_subscription_id"),
561
+ )
562
+
563
+
564
+ @dataclass
565
+ class HyperAgentPaymentEntitlement:
566
+ id: str
567
+ plan_id: str
568
+ provider: str
569
+ status: str
570
+ expires_at: datetime | None
571
+ agent_tier: str | None
572
+ features: dict[str, bool]
573
+ tags: list[str]
574
+
575
+ @classmethod
576
+ def from_dict(cls, data: dict) -> "HyperAgentPaymentEntitlement":
577
+ expires_at = data.get("expires_at")
578
+ return cls(
579
+ id=str(data.get("id", "")),
580
+ plan_id=str(data.get("plan_id", "")),
581
+ provider=str(data.get("provider", "")),
582
+ status=str(data.get("status", "")),
583
+ expires_at=datetime.fromisoformat(str(expires_at).replace("Z", "+00:00")) if expires_at else None,
584
+ agent_tier=data.get("agent_tier"),
585
+ features=data.get("features") or {},
586
+ tags=[str(item) for item in data.get("tags", [])],
587
+ )
588
+
589
+
590
+ @dataclass
591
+ class HyperAgentPayment:
592
+ id: str
593
+ user_id: str
594
+ subscription_id: str | None
595
+ entitlement_id: str | None
596
+ provider: str
597
+ status: str
598
+ amount: str
599
+ currency: str
600
+ external_payment_id: str | None
601
+ created_at: datetime | None
602
+ updated_at: datetime | None
603
+ user: HyperAgentBillingUser | None
604
+ subscription: HyperAgentPaymentSubscription | None
605
+ entitlement: HyperAgentPaymentEntitlement | None
606
+
607
+ @classmethod
608
+ def from_dict(cls, data: dict) -> "HyperAgentPayment":
609
+ created_at = data.get("created_at")
610
+ updated_at = data.get("updated_at")
611
+ return cls(
612
+ id=str(data.get("id", "")),
613
+ user_id=str(data.get("user_id", "")),
614
+ subscription_id=data.get("subscription_id"),
615
+ entitlement_id=data.get("entitlement_id"),
616
+ provider=str(data.get("provider", "")),
617
+ status=str(data.get("status", "")),
618
+ amount=str(data.get("amount", "")),
619
+ currency=str(data.get("currency", "")),
620
+ external_payment_id=data.get("external_payment_id"),
621
+ created_at=datetime.fromisoformat(str(created_at).replace("Z", "+00:00")) if created_at else None,
622
+ updated_at=datetime.fromisoformat(str(updated_at).replace("Z", "+00:00")) if updated_at else None,
623
+ user=HyperAgentBillingUser.from_dict(data["user"]) if data.get("user") else None,
624
+ subscription=HyperAgentPaymentSubscription.from_dict(data["subscription"]) if data.get("subscription") else None,
625
+ entitlement=HyperAgentPaymentEntitlement.from_dict(data["entitlement"]) if data.get("entitlement") else None,
626
+ )
627
+
628
+
629
+ @dataclass
630
+ class HyperAgentPaymentsResponse:
631
+ items: list[HyperAgentPayment]
632
+
633
+ @classmethod
634
+ def from_dict(cls, data: dict) -> "HyperAgentPaymentsResponse":
635
+ return cls(items=[HyperAgentPayment.from_dict(item) for item in data.get("items", [])])
636
+
637
+
638
+ @dataclass
639
+ class HyperAgentStripeCheckoutResponse:
640
+ checkout_url: str
641
+
642
+ @classmethod
643
+ def from_dict(cls, data: dict) -> "HyperAgentStripeCheckoutResponse":
644
+ return cls(checkout_url=str(data.get("checkout_url", "")))
645
+
646
+
647
+ @dataclass
648
+ class HyperAgentX402CheckoutResponse:
649
+ ok: bool
650
+ key: str
651
+ plan_id: str
652
+ quantity: int
653
+ bundle: dict[str, int]
654
+ amount_paid: str
655
+ duration_days: float
656
+ expires_at: datetime | None
657
+ tpm_limit: int
658
+ rpm_limit: int
659
+
660
+ @classmethod
661
+ def from_dict(cls, data: dict) -> "HyperAgentX402CheckoutResponse":
662
+ expires_at = data.get("expires_at")
663
+ return cls(
664
+ ok=bool(data.get("ok", False)),
665
+ key=str(data.get("key", "")),
666
+ plan_id=str(data.get("plan_id", "")),
667
+ quantity=int(data.get("quantity", 0) or 0),
668
+ bundle={str(k): int(v) for k, v in (data.get("bundle") or {}).items()},
669
+ amount_paid=str(data.get("amount_paid", "")),
670
+ duration_days=float(data.get("duration_days", 0) or 0),
671
+ expires_at=datetime.fromisoformat(str(expires_at).replace("Z", "+00:00")) if expires_at else None,
672
+ tpm_limit=int(data.get("tpm_limit", 0) or 0),
673
+ rpm_limit=int(data.get("rpm_limit", 0) or 0),
674
+ )
675
+
676
+
309
677
  class HyperAgent:
310
678
  """
311
679
  HyperAgent API client.
@@ -451,6 +819,33 @@ class HyperAgent:
451
819
  def _api_base_without_v1(self) -> str:
452
820
  return self._base_url.replace("/v1", "")
453
821
 
822
+ def _control_get(self, path: str, params: dict[str, Any] | None = None) -> dict[str, Any]:
823
+ response = self._http._session.get(
824
+ f"{self._control_base_url}{path}",
825
+ headers={"Authorization": f"Bearer {self._api_key}"},
826
+ params=params,
827
+ )
828
+ response.raise_for_status()
829
+ return response.json()
830
+
831
+ def _control_post(self, path: str, payload: dict[str, Any] | None = None) -> dict[str, Any]:
832
+ response = self._http._session.post(
833
+ f"{self._control_base_url}{path}",
834
+ headers={"Authorization": f"Bearer {self._api_key}"},
835
+ json=payload or {},
836
+ )
837
+ response.raise_for_status()
838
+ return response.json()
839
+
840
+ def _control_put(self, path: str, payload: dict[str, Any] | None = None) -> dict[str, Any]:
841
+ response = self._http._session.put(
842
+ f"{self._control_base_url}{path}",
843
+ headers={"Authorization": f"Bearer {self._api_key}"},
844
+ json=payload or {},
845
+ )
846
+ response.raise_for_status()
847
+ return response.json()
848
+
454
849
  def plans(self) -> List[HyperAgentPlan]:
455
850
  response = self._http._session.get(
456
851
  f"{self._control_base_url}/plans",
@@ -514,6 +909,82 @@ class HyperAgent:
514
909
  def cancel_subscription(self, subscription_id: str) -> HyperAgentSubscriptionMutationResult:
515
910
  return self.update_subscription(subscription_id, {})
516
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))
987
+
517
988
  def discovery_health(self) -> Dict[str, Any]:
518
989
  response = self._http._session.get(f"{self._api_base_without_v1()}/discovery/health")
519
990
  response.raise_for_status()
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "hypercli-sdk"
7
- version = "2026.4.13"
7
+ version = "2026.4.13.post4"
8
8
  description = "Python SDK for HyperCLI - GPU orchestration and HyperAgent API"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -15,6 +15,16 @@ from hypercli.agent import (
15
15
  HyperAgentSubscription,
16
16
  HyperAgentSubscriptionSummary,
17
17
  HyperAgentModel,
18
+ HyperAgentUsageSummary,
19
+ HyperAgentUsageHistory,
20
+ HyperAgentKeyUsage,
21
+ HyperAgentTypeCatalog,
22
+ HyperAgentBillingInfo,
23
+ HyperAgentBillingProfileFields,
24
+ HyperAgentBillingProfileResponse,
25
+ HyperAgentPaymentsResponse,
26
+ HyperAgentStripeCheckoutResponse,
27
+ HyperAgentX402CheckoutResponse,
18
28
  )
19
29
 
20
30
 
@@ -142,6 +152,7 @@ class TestHyperAgentClient:
142
152
  http = Mock()
143
153
  http._api_key = "test-key"
144
154
  http._session = Mock()
155
+ http._session.put = Mock()
145
156
  return http
146
157
 
147
158
  def test_discovery_health(self, mock_http):
@@ -405,6 +416,144 @@ class TestHyperAgentClient:
405
416
  headers={"Authorization": "Bearer sk-hyper-test"},
406
417
  json={"bundle": {"large": 1}},
407
418
  )
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"
408
557
 
409
558
  def test_openai_client_creation(self, mock_http):
410
559
  """Test that OpenAI client is created with correct config."""