hermes-hub/tests/test_grok_quota.py
Hermes Team 98b6e68617 fix(grok): убрать неверное утверждение про «разные кошельки»
Владелец прислал анонс x.ai/news/grok-hermes: доступ к Grok даётся по
подписке SuperGrok через OAuth, покупать кредиты API не требуется. Моя
формулировка в интерфейсе утверждала обратное — что подписка кредиты не
пополняет и это отдельный кошелёк. Это неверно, и оно уже попадало
пользователю на экран.

Установлено проверками:
- cli-chat-proxy.grok.com/v1/models принимает наш OAuth-токен -> 200,
  отдаёт grok-4.6;
- тот же прокси /chat/completions -> 426, требует версию Grok CLI
  не ниже 0.1.202, и она читается не из заголовков, которые я перебрал;
- api.x.ai/v1/responses (путь из документации Hermes) -> 402
  personal-team-blocked:spending-limit.

При этом подключён ochenstarik@gmail.com, а подписка SuperGrok — на
victor.trushenko@gmail.com. То есть отказ объясняется аккаунтом, а не
природой подписки, и утверждать иное я не мог.

Сообщение переписано на проверяемое: у аккаунта нет ни баланса, ни
лимита трат, а доступ даёт подписка на ЭТОМ же аккаунте либо купленные
кредиты. Само чтение биллинга остаётся — оно работает и показывает
настоящие числа.

Тесты: 422 passed, ruff чисто.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-24 20:06:21 +07:00

73 lines
3.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Квота Grok читается у провайдера, а не показывается как «Н/Д».
Владелец спросил: «где закончились лимиты?» — и показал экран, где
еженедельный лимит SuperGrok израсходован на 14%. Но вызовы через Hub
падали с 402.
Разгадка: это ДВА РАЗНЫХ кошелька. Подписка SuperGrok покрывает чат
grok.com, а программный доступ списывается с кредитов API. Их у аккаунта
ноль — подтверждено биллинговым эндпоинтом.
Раньше _collect_grok_quota строила пустые корзины и никуда не ходила,
поэтому Hub показывал «Н/Д» и объяснить ничего не мог.
"""
from __future__ import annotations
import json
from unittest.mock import MagicMock, patch
from antigravity_provider.router.quota_collector import AccountQuotaService
def _billing(prepaid: float, cap: float, used: float) -> MagicMock:
payload = {
"config": {
"currentPeriod": {"start": "2026-08-19T00:00:00+00:00", "end": "2026-08-26T00:00:00+00:00"},
"prepaidBalance": {"val": prepaid},
"onDemandCap": {"val": cap},
"onDemandUsed": {"val": used},
}
}
resp = MagicMock()
resp.__enter__.return_value.read.return_value = json.dumps(payload).encode("utf-8")
return resp
def _auth() -> dict:
return {"token": {"access_token": "tok"}}
def test_exhausted_account_explains_two_wallets():
"""Нулевой баланс объясняется, а не показывается прочерком."""
with patch("antigravity_provider.router.quota_collector.urllib.request.urlopen",
return_value=_billing(0, 0, 0)):
snap = AccountQuotaService()._collect_grok_quota("grok-orch", _auth())
assert snap.source == "provider_api"
assert "SuperGrok" in (snap.unavailable_reason or ""), "не объяснено, откуда берётся доступ"
assert all(b.status == "exhausted" for b in snap.buckets)
def test_zero_cap_does_not_fabricate_percent():
"""При нулевом лимите доля не определена — процент выдумывать нельзя."""
with patch("antigravity_provider.router.quota_collector.urllib.request.urlopen",
return_value=_billing(0, 0, 0)):
snap = AccountQuotaService()._collect_grok_quota("grok-orch", _auth())
on_demand = next(b for b in snap.buckets if b.id == "grok.on_demand")
assert on_demand.remaining_percent is None
assert on_demand.used_percent is None
assert on_demand.limit_absolute == 0
def test_account_with_credits_reports_real_percent():
"""Когда лимит есть, доля считается по измеренным значениям."""
with patch("antigravity_provider.router.quota_collector.urllib.request.urlopen",
return_value=_billing(50, 200, 50)):
snap = AccountQuotaService()._collect_grok_quota("grok-orch", _auth())
on_demand = next(b for b in snap.buckets if b.id == "grok.on_demand")
assert on_demand.used_percent == 25.0
assert on_demand.remaining_percent == 75.0
assert snap.unavailable_reason is None