fix(xai-oauth): recover from prelude SSE errors, gate reasoning replay, surface entitlement 403s

Original commit 31ba2b0cb by Teknium targeted run_codex_stream() at
its pre-refactor location in run_agent.py. Re-applied:

  - Prelude error retry/fallback → agent/codex_runtime.py (in
    run_codex_stream where the body now lives)
  - _decorate_xai_entitlement_error helper + _summarize_api_error
    wrapping → run_agent.py (these methods remained on AIAgent
    as @staticmethod's; cherry-pick applied them cleanly)

The xai-oauth provider gate, encrypted_content drop on replay, etc.
landed in agent/codex_responses_adapter.py via the prior merge from main.

Closes #8133, #14634

Co-authored-by: Teknium <127238744+teknium1@users.noreply.github.com>
This commit is contained in:
teknium1
2026-05-16 23:28:05 -07:00
parent 27df249564
commit 6362e71973
2 changed files with 75 additions and 6 deletions

View File

@ -1287,6 +1287,45 @@ class AIAgent:
trajectory = self._convert_to_trajectory_format(messages, user_query, completed)
_save_trajectory_to_file(trajectory, self.model, completed)
@staticmethod
def _decorate_xai_entitlement_error(detail: str) -> str:
"""Append a friendly hint when xAI's OAuth surface returns an
entitlement-shaped error.
xAI's ``/v1/responses`` endpoint replies to OAuth tokens that lack a
SuperGrok / X Premium subscription with HTTP 403 carrying a body like::
{"code": "The caller does not have permission to execute the
specified operation", "error": "You have either run out of
available resources or do not have an active Grok subscription.
Manage subscriptions at https://grok.com/..."}
The raw text is useful but the action the user needs to take (subscribe
on grok.com, or switch providers with ``/model``) isn't obvious from
the wire format. Detect the entitlement shape and append a hint.
Matched once per detail string — won't double-decorate if the upstream
already concatenated the same text.
"""
if not detail:
return detail
lower = detail.lower()
is_entitlement = (
"do not have an active grok subscription" in lower
or ("out of available resources" in lower and "grok" in lower)
or ("does not have permission" in lower and "grok" in lower)
)
if not is_entitlement:
return detail
hint = (
" — xAI OAuth account lacks SuperGrok / X Premium entitlement for "
"this model. Subscribe at https://grok.com or run `/model` to "
"switch providers."
)
if hint.strip() in detail:
return detail
return f"{detail}{hint}"
@staticmethod
def _summarize_api_error(error: Exception) -> str:
"""Extract a human-readable one-liner from an API error.
@ -1320,12 +1359,12 @@ class AIAgent:
if msg:
status_code = getattr(error, "status_code", None)
prefix = f"HTTP {status_code}: " if status_code else ""
return f"{prefix}{msg[:300]}"
return AIAgent._decorate_xai_entitlement_error(f"{prefix}{msg[:300]}")
# Fallback: truncate the raw string but give more room than 200 chars
status_code = getattr(error, "status_code", None)
prefix = f"HTTP {status_code}: " if status_code else ""
return f"{prefix}{raw[:500]}"
return AIAgent._decorate_xai_entitlement_error(f"{prefix}{raw[:500]}")
def _mask_api_key_for_logs(self, key: Optional[str]) -> Optional[str]:
if not key: