Two new OpenAI STT models, Spanish routing moves to AssemblyAI, and the API contract is corrected to match the router

The catalog publishes openai:gpt-transcribe and openai:gpt-live-transcribe as separate candidates, Spanish speech-to-text now routes to AssemblyAI Universal-3.5 Pro on its own measured numbers, and several OpenAPI descriptions are corrected where they described behavior the router never had.

New published router ids: openai:gpt-transcribe (buffered) and openai:gpt-live-transcribe (streaming) are now separate speech-to-text candidates rather than one combined board row, and xai:grok-voice-think-fast-2.0 is published. The catalog moves from 43 to 45 candidates, speech-to-text from 12 to 14.

openai:gpt-live-transcribe runs only on OpenAI's realtime transcription endpoint. Pinning it on POST /v1/transcribe or POST /v1/audio/transcriptions returns HTTP 400 naming the buffered models that are available, and automatic selection on those paths never picks it.

Spanish speech-to-text selection changes: quality routing that chose elevenlabs:scribe_v2 and measured-language latency routing that chose soniox:stt-rt-v5 both now choose assemblyai:universal-3-5-pro, which posts 3.5 percent streaming WER against ElevenLabs at 3.8 and the fastest endpoint on the board at 66 ms. Its Spanish figures were measured on universal-3-5-pro directly.

The published English WER and endpoint for AssemblyAI Universal-3.5 Pro were measured against the u3-rt-pro id, which AssemblyAI auto-routes to this model from 2026-08-07 and retires around 2026-09-25. That disclosure now travels with the board row, so it survives every regeneration of the catalog.

Claude Haiku 4.5 is sent upstream as the dated provider id claude-haiku-4-5-20251001. The public Speko model id anthropic:claude-haiku-4-5 is unchanged.

CORRECTION, not a change in behavior: the OpenAPI document previously listed mp3, opus, aac and flac as accepted values of response_format on POST /v1/audio/speech. The router has never served those and rejects them with HTTP 400. The document now lists what is actually accepted, pcm, pcm16 and wav, with pcm as the default. No request that previously succeeded stops succeeding.

POST /v1/audio/speech requires only input. model and voice are optional and model defaults to auto, so a language-tagged accent route can supply both.

Documented, previously undocumented, response behavior: a 502 when every upstream fails, carrying x-route, x-route-reason and x-speko-failover-count but not x-speko-first-byte-ms; and the split between router-generated JSON errors and a non-retryable upstream 4xx passed through with the upstream status, media type and body, which can be non-JSON.

Header semantics are now stated precisely. x-route is the display-cased Provider/model form rather than the provider:model form used for constraints, is the last attempted route on terminal failure, and reads none/none when nothing was attempted. x-speko-failover-count also counts candidates tried before a terminal failure. x-speko-first-byte-ms can be absent, and absence does not mean zero.

X-Speko-Max-Price and the routing-preview max_price parameter are stage-specific: USD per minute for speech-to-text, per 1M tokens for LLM, and per 1M characters for text-to-speech. Candidates with no published price are excluded when the constraint is set.

/healthz is documented as unauthenticated, returning 200 only when the loaded snapshot has at least one routable provider in each of speech-to-text, LLM and text-to-speech, and 503 with the per-stage readiness map otherwise.

/v1/models documents routable explicitly: only rows with routable true can be selected or pinned. Rows with routable false remain published as measured evidence and are rejected if pinned.

The OpenAPI response carries x-speko-cloud-run-revision and x-speko-release-sha when the runtime supplies them, and omits them when it does not.

LiveKit plugin: route headers are read before an error is raised, and a terminal response with no route headers now clears attribution instead of retaining the previous successful route. last_selection becomes None and provider/model fall back to speko / speko-router.

Pipecat plugin: a non-200 chat-completion or synthesize response now sets service.route to unknown/unknown rather than leaving the last successful route attached to a failed turn.

pipecat-speko requires Python 3.11 or newer; 3.10 support is removed. Dependencies tighten to aiohttp>=3.11.12,<4, loguru>=0.7.3,<0.8 and websockets>=13.1,<17, and a new examples extra installs the Daily/WebRTC runner dependencies.

livekit-plugins-speko declares requires-python >=3.10,<3.15, adds aiohttp>=3.10,<4, caps livekit-agents below 2, and adds an examples extra for the Silero VAD plugin.

LiveKit text-to-speech model pinning is documented: auto or unset leaves ranking unrestricted, while a catalog candidate id, upstream model name, or candidate-id suffix restricts routing to every matching candidate. Use the full provider:model id for an unambiguous pin.

Action: No migration is required. To use OpenAI streaming transcription, pin openai:gpt-live-transcribe on the transcription socket and send at least 24 kHz audio or let the router upsample.