{"record":{"id":"478fda91b6c1cacd","repo":"Hmbown/CodeWhale","slug":"speech-synthesis-requires-provider-xiaomi-mimo","errorCode":null,"errorMessage":"speech synthesis requires provider 'xiaomi-mimo' (current: {})","messagePattern":"speech synthesis requires provider 'xiaomi-mimo' \\(current: (.+?)\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/client.rs","lineNumber":2337,"sourceCode":"                        \"provider catalog refresh failed; keeping existing rows\"\n                    );\n                }\n            }\n        });\n    }\n\n    /// Generate speech with Xiaomi MiMo TTS models.\n    ///\n    /// The spoken text is placed in an `assistant` message because Xiaomi\n    /// MiMo's TTS chat-completions surface expects that shape. The optional\n    /// `instruction` is a `user` message that controls style, voice design, or\n    /// voice-clone performance and is not spoken verbatim.\n    pub async fn synthesize_speech(\n        &self,\n        request: SpeechSynthesisRequest,\n    ) -> Result<SpeechSynthesisResponse> {\n        if self.api_provider != crate::config::ApiProvider::XiaomiMimo {\n            anyhow::bail!(\n                \"speech synthesis requires provider 'xiaomi-mimo' (current: {})\",\n                self.api_provider.as_str()\n            );\n        }\n\n        let model = request.model.trim().to_string();\n        if model.is_empty() {\n            anyhow::bail!(\"Speech model cannot be empty\");\n        }\n        let text = request.text.trim().to_string();\n        if text.is_empty() {\n            anyhow::bail!(\"Speech text cannot be empty\");\n        }\n\n        let audio_format = normalize_audio_format(&request.audio_format);\n        let model = wire_model_for_provider_route(self.api_provider, &self.base_url, &model);\n        let model_lower = model.to_ascii_lowercase();\n        let instruction = request","sourceCodeStart":2319,"sourceCodeEnd":2355,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/crates/tui/src/client.rs#L2319-L2355","documentation":"`synthesize_speech` implements Xiaomi MiMo's TTS chat-completions surface and is hard-gated to the `xiaomi-mimo` provider; the very first check compares `self.api_provider` against `ApiProvider::XiaomiMimo` and bails for anything else. The speech tool (`tools/speech.rs`) and the top-level speech command (`lib.rs`) both route through this method.","triggerScenarios":"Running the speech-synthesis command while the active provider is `deepseek`, `anthropic`, `openai`, or any custom provider — the request is rejected before model/text validation or any network call.","commonSituations":"Trying `/speech` or the TTS tool while in a normal coding session on another provider; switching providers in config but expecting TTS to work generically; embedding the client and calling `synthesize_speech` on a general-purpose client.","solutions":["Switch the active provider to xiaomi-mimo (`provider = \"xiaomi-mimo\"` in config, or the in-app provider switcher) and re-run the speech command.","Use an external TTS integration instead if you need speech on other providers — this client path is Xiaomi MiMo-only by design.","If embedding programmatically, construct the client bound to `ApiProvider::XiaomiMimo` before calling `synthesize_speech`."],"exampleFix":"# before\nprovider = \"deepseek\"\n# after\nprovider = \"xiaomi-mimo\"","handlingStrategy":"validation","validationCode":"fn can_synthesize_speech(provider: ApiProvider) -> bool {\n    provider == ApiProvider::XiaomiMimo\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Hide or disable the speech command in the UI unless the active provider is xiaomi-mimo.","When embedding, check `client.api_provider == ApiProvider::XiaomiMimo` before building speech features.","Surface the provider requirement in the command's help text."],"tags":["speech","tts","provider","validation","xiaomi-mimo"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}