feat(xai-oauth): add xAI Grok OAuth (SuperGrok Subscription) provider — port to extracted modules

Original commit b62c99797 by Jaaneek targeted six locations in
pre-refactor run_agent.py. Re-applied to the extracted post-PR locations:

  - api_mode dispatch → agent/agent_init.py
  - is_xai_responses build_api_kwargs → agent/chat_completion_helpers.py
  - codex_auth_retry block + 401 hint → agent/conversation_loop.py
  - _try_refresh_codex_client_credentials body → run_agent.py (kept)

The non-run_agent.py portions of the commit (auxiliary_client, codex
transport, hermes_cli/auth, tools/xai_http, tests, docs) merged cleanly
from main via the prior merge commit.

Co-authored-by: Jaaneek <Jaaneek@users.noreply.github.com>
This commit is contained in:
teknium1 2026-05-16 23:23:38 -07:00
parent 7d221aa1f2
commit b07524e53a
No known key found for this signature in database
4 changed files with 64 additions and 14 deletions

View file

@ -2449,15 +2449,60 @@ class AIAgent:
return run_codex_create_stream_fallback(self, api_kwargs, client)
def _try_refresh_codex_client_credentials(self, *, force: bool = True) -> bool:
if self.api_mode != "codex_responses" or self.provider != "openai-codex":
if self.api_mode != "codex_responses" or self.provider not in {"openai-codex", "xai-oauth"}:
return False
# Guard against silent account swap.
#
# When an agent is using a non-singleton credential — e.g. a manual
# pool entry (``hermes auth add xai-oauth``) whose tokens belong to
# a different account than the loopback_pkce singleton, or an agent
# constructed with an explicit ``api_key=`` arg — force-refreshing
# the singleton here and adopting its tokens silently re-routes the
# rest of the conversation onto the singleton's account. The
# credential pool's reactive recovery (``_recover_with_credential_pool``)
# is the right channel for that case; this path is the
# singleton-only fallback used when the pool can't recover, and
# MUST only fire when the agent really is on singleton tokens.
try:
if self.provider == "openai-codex":
from hermes_cli.auth import resolve_codex_runtime_credentials
singleton_now = resolve_codex_runtime_credentials(
refresh_if_expiring=False,
)
else:
from hermes_cli.auth import resolve_xai_oauth_runtime_credentials
singleton_now = resolve_xai_oauth_runtime_credentials(
refresh_if_expiring=False,
)
except Exception as exc:
logger.debug("%s singleton read failed: %s", self.provider, exc)
return False
singleton_key = str(singleton_now.get("api_key") or "").strip()
active_key = str(self.api_key or "").strip()
if singleton_key and active_key and singleton_key != active_key:
logger.debug(
"%s singleton tokens differ from the active api_key; "
"skipping singleton force-refresh to avoid silent account swap. "
"Reactive credential rotation should go through the pool.",
self.provider,
)
return False
try:
from hermes_cli.auth import resolve_codex_runtime_credentials
if self.provider == "openai-codex":
from hermes_cli.auth import resolve_codex_runtime_credentials
creds = resolve_codex_runtime_credentials(force_refresh=force)
creds = resolve_codex_runtime_credentials(force_refresh=force)
else:
from hermes_cli.auth import resolve_xai_oauth_runtime_credentials
creds = resolve_xai_oauth_runtime_credentials(force_refresh=force)
except Exception as exc:
logger.debug("Codex credential refresh failed: %s", exc)
logger.debug("%s credential refresh failed: %s", self.provider, exc)
return False
api_key = creds.get("api_key")
@ -2472,7 +2517,7 @@ class AIAgent:
self._client_kwargs["api_key"] = self.api_key
self._client_kwargs["base_url"] = self.base_url
if not self._replace_primary_openai_client(reason="codex_credential_refresh"):
if not self._replace_primary_openai_client(reason=f"{self.provider}_credential_refresh"):
return False
return True