fix(xai-oauth): entitlement-403 chain — final state (ce0e189d3 + 9818b9a1a + 6784c8079 + dffb602f3)

Collapses the four-commit xAI entitlement-403 chain to its final
on-main state, ported to the post-refactor module layout:

  - Added _is_entitlement_failure on AIAgent (run_agent.py) — detects
    Grok subscription-shape 403s on (401|403|None) status codes.
  - Added entitlement-skip branch to recover_with_credential_pool
    (agent/agent_runtime_helpers.py) — breaks the refresh-loop that
    Don's 100-iteration trace exposed when a Premium+ user hit a real
    entitlement issue.
  - Removed _decorate_xai_entitlement_error and unwrapped its two
    _summarize_api_error call sites — xAI's own body text already
    points users at grok.com/?_s=usage so we surface that verbatim
    (dffb602f3 reasoning: X Premium subs DO now work per xAI's
    2026-05-16 announcement, so editorialising would misdirect).
  - grok-4.3 1M context entry landed in agent/model_metadata.py
    via the prior merge — no additional port needed.

Tests already on disk (tests/run_agent/test_codex_xai_oauth_recovery.py)
assert _is_entitlement_failure shape and verbatim body surfacing.

Closes #27110.

Co-authored-by: Teknium <127238744+teknium1@users.noreply.github.com>
This commit is contained in:
teknium1 2026-05-16 23:33:18 -07:00
parent 408aa4fbc4
commit 6975a2d9ae
No known key found for this signature in database
2 changed files with 43 additions and 35 deletions

View file

@ -598,6 +598,15 @@ def recover_with_credential_pool(
return False, True
if effective_reason == FailoverReason.auth:
if agent._is_entitlement_failure(error_context, status_code):
_ra().logger.info(
"Credential %s — entitlement-shaped 403 from %s; "
"skipping pool refresh (account lacks subscription, "
"not a transient auth failure).",
status_code if status_code is not None else "auth",
agent.provider or "provider",
)
return False, has_retried_429
refreshed = pool.try_refresh_current()
if refreshed is not None:
_ra().logger.info(f"Credential auth failure — refreshed pool entry {getattr(refreshed, 'id', '?')}")