fix(xai): surface provider 'error' SSE frame in Codex fallback stream (#27184)

Original commit 2b193907d by Teknium added a new module-level
_StreamErrorEvent class and threaded its raise into
_run_codex_create_stream_fallback in pre-refactor run_agent.py.

  - _StreamErrorEvent class → run_agent.py (module-level, next to
    _qwen_portal_headers; class needs to be top-level for the codex
    runtime to import it)
  - The fallback event-loop's 'type=error' handler → agent/codex_runtime.py
    where run_codex_create_stream_fallback now lives. Imports
    _StreamErrorEvent lazily from run_agent to avoid circular import.

Co-authored-by: Teknium <127238744+teknium1@users.noreply.github.com>
This commit is contained in:
teknium1
2026-05-16 23:41:09 -07:00
parent 80fa92a491
commit aa05ffba53
2 changed files with 68 additions and 0 deletions

View File

@@ -284,6 +284,45 @@ def _qwen_portal_headers() -> dict:
}
class _StreamErrorEvent(Exception):
"""Synthesized provider error surfaced from a Responses ``error`` SSE frame.
Some Codex-style Responses backends (xAI for subscription/quota
failures, custom relays under malformed-tool-call conditions) emit a
standalone ``type=error`` frame instead of routing the failure
through ``response.failed`` or returning an HTTP 4xx. The fallback
streaming path raises this exception so ``_summarize_api_error`` and
``_extract_api_error_context`` see a familiar ``.body`` /
``.status_code`` shape and the entitlement detector can match the
underlying provider message ("do not have an active Grok
subscription", etc.).
"""
def __init__(
self,
message: str,
*,
code: Optional[str] = None,
param: Optional[str] = None,
status_code: Optional[int] = None,
) -> None:
super().__init__(message)
self.message = message
self.code = code
self.param = param
self.status_code = status_code
# OpenAI SDK-shaped body so _extract_api_error_context /
# _summarize_api_error / classify_api_error all pick it up.
self.body: Dict[str, Any] = {
"error": {
"message": message,
"code": code,
"param": param,
"type": "error",
}
}
class AIAgent:
"""
AI Agent with tool calling capabilities.