hermes: distinguish refreshable Claude auth

This commit is contained in:
jenkins 2026-08-12 02:31:34 -03:00
parent b12b28bdcb
commit cf259f9746
3 changed files with 44 additions and 3 deletions

View File

@ -29,6 +29,11 @@
function ProviderCard(props) {
const item = props.item || {};
const account = item.account || null;
const authLabel = account && account.access_token_live === false && account.refreshable
? "Authentication refreshable"
: account && account.authenticated
? "Authentication ready"
: "Authentication unavailable";
return h(Card, { className: "provider-status-card" },
h(CardContent, { className: "provider-status-card-content" },
h("div", { className: "provider-status-card-heading" },
@ -39,7 +44,7 @@
h(Badge, { className: "provider-status-badge provider-status-badge--" + (item.state || "unobserved") }, item.state || "unobserved")
),
account ? h("div", { className: "provider-status-auth" },
h("span", { className: account.authenticated ? "is-good" : "is-bad" }, account.authenticated ? "Authentication ready" : "Authentication unavailable"),
h("span", { className: account.authenticated ? "is-good" : "is-bad" }, authLabel),
account.rate_limit_tier && account.rate_limit_tier !== "unknown" ? h("span", null, "Tier: " + account.rate_limit_tier) : null,
h("span", null, "Access token: " + when(account.token_expires_at)),
account.usage_url ? h("a", {

View File

@ -125,9 +125,14 @@ def _claude_account() -> dict[str, Any]:
oauth = oauth if isinstance(oauth, dict) else {}
expires_at, token_live = _timestamp(oauth.get("expiresAt"))
refresh_expires_at, refresh_live = _timestamp(oauth.get("refreshTokenExpiresAt"))
authenticated = bool(oauth.get("accessToken")) and token_live is not False
refreshable = bool(oauth.get("refreshToken")) and refresh_live is not False
authenticated = (
bool(oauth.get("accessToken")) and token_live is not False
) or refreshable
return {
"authenticated": authenticated,
"access_token_live": token_live,
"refreshable": refreshable,
"plan": oauth.get("subscriptionType") or "unknown",
"rate_limit_tier": oauth.get("rateLimitTier") or "unknown",
"token_expires_at": expires_at,
@ -262,7 +267,14 @@ def provider_status_text() -> str:
plan = f" · plan {account.get('plan', 'unknown')}" if account else ""
auth = ""
if account:
auth = " · auth ready" if account.get("authenticated") else " · auth unavailable"
if account.get("access_token_live") is False and account.get("refreshable"):
auth = " · auth refreshable"
else:
auth = (
" · auth ready"
if account.get("authenticated")
else " · auth unavailable"
)
lines.append(
f"{labels[key]}: {item['state']} · {item['calls']} completed · "
f"{item['errors']} errors · {item['total_tokens']} tokens{plan}{auth}"

View File

@ -217,6 +217,30 @@ def test_provider_status_accepts_iso_and_epoch_credential_expiry():
assert epoch_live is True
def test_claude_account_treats_a_live_refresh_token_as_refreshable(
tmp_path, monkeypatch
):
status = sys.modules["hermes_auto_router"].provider_status_text.__globals__
module = sys.modules[status["provider_status_payload"].__module__]
path = tmp_path / ".credentials.json"
path.write_text(json.dumps({
"claudeAiOauth": {
"accessToken": "expired-access",
"refreshToken": "live-refresh",
"expiresAt": 1,
"refreshTokenExpiresAt": 32_472_192_000,
"subscriptionType": "max",
}
}), encoding="utf-8")
monkeypatch.setattr(module, "CLAUDE_AUTH_PATH", path)
account = module._claude_account()
assert account["authenticated"] is True
assert account["access_token_live"] is False
assert account["refreshable"] is True
def test_agent_mounts_provider_status_dashboard_into_auto_router_plugin():
import yaml