hermes: distinguish refreshable Claude auth
This commit is contained in:
parent
b12b28bdcb
commit
cf259f9746
@ -29,6 +29,11 @@
|
|||||||
function ProviderCard(props) {
|
function ProviderCard(props) {
|
||||||
const item = props.item || {};
|
const item = props.item || {};
|
||||||
const account = item.account || null;
|
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" },
|
return h(Card, { className: "provider-status-card" },
|
||||||
h(CardContent, { className: "provider-status-card-content" },
|
h(CardContent, { className: "provider-status-card-content" },
|
||||||
h("div", { className: "provider-status-card-heading" },
|
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")
|
h(Badge, { className: "provider-status-badge provider-status-badge--" + (item.state || "unobserved") }, item.state || "unobserved")
|
||||||
),
|
),
|
||||||
account ? h("div", { className: "provider-status-auth" },
|
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,
|
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)),
|
h("span", null, "Access token: " + when(account.token_expires_at)),
|
||||||
account.usage_url ? h("a", {
|
account.usage_url ? h("a", {
|
||||||
|
|||||||
@ -125,9 +125,14 @@ def _claude_account() -> dict[str, Any]:
|
|||||||
oauth = oauth if isinstance(oauth, dict) else {}
|
oauth = oauth if isinstance(oauth, dict) else {}
|
||||||
expires_at, token_live = _timestamp(oauth.get("expiresAt"))
|
expires_at, token_live = _timestamp(oauth.get("expiresAt"))
|
||||||
refresh_expires_at, refresh_live = _timestamp(oauth.get("refreshTokenExpiresAt"))
|
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 {
|
return {
|
||||||
"authenticated": authenticated,
|
"authenticated": authenticated,
|
||||||
|
"access_token_live": token_live,
|
||||||
|
"refreshable": refreshable,
|
||||||
"plan": oauth.get("subscriptionType") or "unknown",
|
"plan": oauth.get("subscriptionType") or "unknown",
|
||||||
"rate_limit_tier": oauth.get("rateLimitTier") or "unknown",
|
"rate_limit_tier": oauth.get("rateLimitTier") or "unknown",
|
||||||
"token_expires_at": expires_at,
|
"token_expires_at": expires_at,
|
||||||
@ -262,7 +267,14 @@ def provider_status_text() -> str:
|
|||||||
plan = f" · plan {account.get('plan', 'unknown')}" if account else ""
|
plan = f" · plan {account.get('plan', 'unknown')}" if account else ""
|
||||||
auth = ""
|
auth = ""
|
||||||
if account:
|
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(
|
lines.append(
|
||||||
f"{labels[key]}: {item['state']} · {item['calls']} completed · "
|
f"{labels[key]}: {item['state']} · {item['calls']} completed · "
|
||||||
f"{item['errors']} errors · {item['total_tokens']} tokens{plan}{auth}"
|
f"{item['errors']} errors · {item['total_tokens']} tokens{plan}{auth}"
|
||||||
|
|||||||
@ -217,6 +217,30 @@ def test_provider_status_accepts_iso_and_epoch_credential_expiry():
|
|||||||
assert epoch_live is True
|
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():
|
def test_agent_mounts_provider_status_dashboard_into_auto_router_plugin():
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user