Skip to content

fix(auth): make xAI OAuth pools multi-account resilient (salvage #62285) - #66123

Merged
kshitijk4poor merged 2 commits into
NousResearch:mainfrom
kshitijk4poor:salvage/62285-xai-oauth-multi-account
Jul 17, 2026
Merged

fix(auth): make xAI OAuth pools multi-account resilient (salvage #62285)#66123
kshitijk4poor merged 2 commits into
NousResearch:mainfrom
kshitijk4poor:salvage/62285-xai-oauth-multi-account

Conversation

@kshitijk4poor

Copy link
Copy Markdown
Collaborator

Summary

Salvage of #62285 onto current main — makes xAI OAuth credential pools work end-to-end with multiple accounts. Cherry-picked with @cresslank's authorship preserved, plus one maintainer hardening commit.

Four related failures prevented useful rotation across multiple xAI OAuth grants:

  1. hermes auth add xai-oauth routed through the singleton _save_xai_oauth_tokens, so every additional login overwrote the singleton-backed device_code entry instead of appending an independent account.
  2. xAI reports exhausted Grok credits as HTTP 403 with structured code personal-team-blocked:spending-limit. Hermes classified it as auth/entitlement and returned before mark_exhausted_and_rotate(), never trying the next account.
  3. Primary runtime credentials and the recovery pool can be separate pool instances; with no current_id, billing recovery could quarantine the wrong entry. Now passes the active runtime key as api_key_hint so the exact failed grant is quarantined.
  4. Direct xAI HTTP integrations resolved pool-only credentials through the singleton resolver, persisting rotated pairs to providers.xai-oauth while leaving the actual pool row stale. Now resolved/refreshed through the selected pool entry.

Changes

  • hermes_cli/auth_commands.py: append each xAI OAuth login as an independent manual:device_code pool entry; set active_provider only on first add (@cresslank)
  • agent/credential_pool.py: force-refresh the entry matching the failed bearer; serialize xAI single-use token rotation across concurrent pool instances (@cresslank)
  • agent/error_classifier.py: classify structured xAI personal-team-blocked:spending-limit as billing (@cresslank)
  • tools/xai_http.py, plugins/web/xai/provider.py: pool-only credential detection + api_key_hint-targeted refresh (@cresslank)
  • agent/agent_runtime_helpers.py: pass failed runtime key into billing rotation; preserve top-level string error (@cresslank)
  • Maintainer hardening (agent/credential_pool.py): consolidate the duplicated single-use-refresh lock scaffolding shared by the openai-codex and xai-oauth branches into a combined guard + _single_use_refresh_lock_timeout() helper, preserving each provider's distinct post-sync semantics (kshitijk4poor)

Validation

Result
Targeted suites (11 files, exact HEAD 30929eaea) 951 passed, 0 failed
Mutation check (spending-limit test vs pre-fix) fails pre-fix / passes post-fix
Behavior-parity probe (lock-timeout helper, both providers) identical (25.0 default, override respected)
E2E (single-use serialization, refactored path) exactly-once across 2 pool instances
ruff clean

Credit

Contributor commit 5d8834b91 by @cresslank (cherry-picked, authorship preserved); maintainer hardening 30929eaea. Closes #62285.

cresslank and others added 2 commits July 17, 2026 11:28
Keep each xAI OAuth auth-add login as an independent manual device-code pool entry and recognize xAI personal-team spending-limit 403 responses as billing exhaustion. Preserve the structured top-level error message so the failed credential is quarantined and the next healthy account is selected without attempting a pointless token refresh.

Route direct xAI HTTP consumers through the credential pool as well. Proactive and 401-reactive refreshes update the exact issuing manual entry, preserve validated xAI base URL overrides, and serialize single-use refresh-token rotation across concurrent pool instances.
…folding

The openai-codex and xai-oauth branches of _refresh_entry duplicated the
lock-timeout computation and _auth_store_lock acquisition. Extract the
shared scaffolding: a combined provider guard, a dispatch to the
provider-specific sync helper, and a _single_use_refresh_lock_timeout()
helper. Each provider's distinct post-sync decision logic (codex
needs-refresh short-circuit vs xai token-equality adoption) is preserved
verbatim. Behavior parity verified by the credential pool suite (98
passed) and a direct timeout-helper probe for both providers.

Follow-up to salvaged PR NousResearch#62285.
@kshitijk4poor
kshitijk4poor enabled auto-merge (rebase) July 17, 2026 06:04
@kshitijk4poor
kshitijk4poor merged commit 73ad913 into NousResearch:main Jul 17, 2026
31 checks passed
@alt-glitch alt-glitch added type/bug Something isn't working P3 Low — cosmetic, nice to have comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/cli CLI entry point, hermes_cli/, setup wizard comp/plugins Plugin system and bundled plugins comp/tools Tool registry, model_tools, toolsets provider/xai xAI (Grok) area/auth Authentication, OAuth, credential pools area/billing Account usage, credit usage, billing (cross-cutting) labels Jul 17, 2026

@tonydwb tonydwb left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review Summary

Verdict: Comment

Small fix PR (59 additions / 14 deletions). The changes cover desktop/session.py with a title-based body drop that opens split view plus preserves session token. Looks well-scoped.

No security issues, no hardcoded secrets, no debug artifacts. Clean fix pattern.


Reviewed by Hermes Agent (cron batch 2026-07-17)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/auth Authentication, OAuth, credential pools area/billing Account usage, credit usage, billing (cross-cutting) comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/cli CLI entry point, hermes_cli/, setup wizard comp/plugins Plugin system and bundled plugins comp/tools Tool registry, model_tools, toolsets P3 Low — cosmetic, nice to have provider/xai xAI (Grok) type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants