OpenAiCompatibleTtsProvider sends response_format in the wrong case #209
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Split out of the #208 review (Jibril) rather than folded in, to keep that PR to its own provider.
The defect
OpenAiCompatibleTtsProvider.SpeechRequestserializes throughJsonSerializerDefaults.Web, so itsResponseFormatproperty goes over the wire asresponseFormat. The OpenAI audio-speech shape documents the field asresponse_format(snake_case), and every conformant server declares it that way.So the field is silently ignored by every endpoint this adapter talks to — OpenRouter, Kokoro-FastAPI, VoxCPM.cpp — and the server falls back to its own default.
Why nothing has broken
The adapter asks for
"mp3"atOpenAiCompatibleTtsProvider.cs:95, andmp3is also the shape's default. Intended value and fallback value coincide, so the ignored field is invisible.GeneratedAudiois taggedTtsAudioFormat.Mp3and happens to be correct.This is luck, not correctness. It breaks the moment either side moves:
TtsAudioFormat.Mp3regardless of what came back.The identical bug in
Qwen3TtsProviderwas not invisible, because there the intended format (WAV) differed from the default: the ignored key produced MP3, which the sidecar cannot encode without an ffmpeg binary, and every preset call returned 500. Confirmed live during #208:Fix
Same annotation as #208:
Test note
OpenAi_compatible_synthesis_posts_the_speech_shape_and_a_keyless_local_endpoint_worksassertsmodel,inputandvoicebut neverresponse_format, so it neither catches nor certifies this. When fixing, pin the key rather than only the value — asserting the value alone is what let the same bug through review in #208. The stub records what the client sends, so an assertion written against the buggy spelling is a false positive.Worth a sweep of the other adapters for the same class of mistake at the same time: any multi-word JSON property going out through
JsonSerializerDefaults.Webis a candidate.FishAudioTtsProvider'sreference_idis already pinned by an explicit test assertion, so it is known good.