From d7865939af2e896e1bc712eefb021437d0241132 Mon Sep 17 00:00:00 2001 From: teknium1 <127238744+teknium1@users.noreply.github.com> Date: Fri, 18 Sep 2026 00:42:06 -0700 Subject: [PATCH] fix(tts): xAI TTS availability probe prefers XAI_API_KEY like the synthesis paths `tools/tts_tool.py::_xai_requirements` (the provider check text_to_speech_tool dispatch consults) still resolved xAI credentials OAuth-first, while both TTS synthesis paths now pass `prefer_api_key=True`. Truthiness is unchanged, but a configured key no longer routes the availability probe through the OAuth pool (pool select / refresh) for a bearer the metered `/v1/tts` endpoint rejects. Docs: the streaming-TTS provider table now states the ordering. Part of the #113727 salvage of #113728 (@beardthelion); sibling site the PR missed. Co-authored-by: beardthelion --- tools/tts_tool.py | 5 ++++- website/docs/developer-guide/streaming-tts.md | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/tts_tool.py b/tools/tts_tool.py index 4d27cced65..37a8a3a26d 100644 --- a/tools/tts_tool.py +++ b/tools/tts_tool.py @@ -477,7 +477,10 @@ def _minimax_requirements() -> bool: def _xai_requirements() -> bool: try: from tools.xai_http import resolve_xai_http_credentials - return bool(resolve_xai_http_credentials().get("api_key")) + # Same ordering as _generate_xai_tts / XAIStreamer: an explicit key wins over the + # subscription OAuth bearer (which 403s on metered /v1/tts) — never touch the OAuth + # pool for an availability probe when a key is configured. See #87045, #113727. + return bool(resolve_xai_http_credentials(prefer_api_key=True).get("api_key")) except Exception: return False diff --git a/website/docs/developer-guide/streaming-tts.md b/website/docs/developer-guide/streaming-tts.md index 72981dff27..2cd77224e1 100644 --- a/website/docs/developer-guide/streaming-tts.md +++ b/website/docs/developer-guide/streaming-tts.md @@ -61,7 +61,7 @@ tts: | elevenlabs | chunked HTTP (`pcm_24000`) | yes | `ELEVENLABS_API_KEY` / `tts.elevenlabs` | | openai | chunked HTTP (`with_streaming_response`, `pcm`) | yes | `tts.openai.api_key` → env → managed gateway | | gemini | SSE (`streamGenerateContent?alt=sse`) | yes | `GEMINI_API_KEY` / `GOOGLE_API_KEY` | -| xai | WebSocket (`wss://api.x.ai/v1/tts`) | yes | xAI OAuth or `XAI_API_KEY` | +| xai | WebSocket (`wss://api.x.ai/v1/tts`) | yes | `XAI_API_KEY` preferred, else xAI OAuth (the subscription bearer 403s on metered TTS) | | edge, piper, kitten, neutts, mistral, minimax, deepinfra, … | — | no (per-sentence sync fallback) | as usual | All credential lookups go through `resolve_provider_secret()`