Note: Use the Meai alias because the Mistral SDK has its own generated IChatClient interface.
Chat Client Five Random Words Streaming
1 2 3 4 5 6 7 8 91011121314151617181920
usingvarclient=newMistralClient(apiKey);Meai.IChatClientchatClient=client;varupdates=chatClient.GetStreamingResponseAsync([ new Meai.ChatMessage(Meai.ChatRole.User, "Generate 5 random words.") ],newMeai.ChatOptions{ModelId="mistral-small-latest",});vardeltas=newList<string>();awaitforeach(varupdateinupdates){if(!string.IsNullOrWhiteSpace(update.Text)){deltas.Add(update.Text);}}
Chat Client Five Random Words
1 2 3 4 5 6 7 8 91011
usingvarclient=newMistralClient(apiKey);Meai.IChatClientchatClient=client;varresponse=awaitchatClient.GetResponseAsync([ new Meai.ChatMessage(Meai.ChatRole.User, "Generate 5 random words.") ],newMeai.ChatOptions{ModelId="mistral-small-latest",});
Chat Client Get Service Returns Chat Client Metadata
MistralClient implements Microsoft.Extensions.AI.ISpeechToTextClient,
backed by Voxtral. GetTextAsync POSTs to /v1/audio/transcriptions
(default model: voxtral-mini-2507). GetStreamingTextAsync opens a WebSocket
to /v1/audio/transcriptions/realtime (default model:
voxtral-mini-transcribe-realtime-2602) and yields interim + final updates.
Exercises the Voxtral batch transcription endpoint end-to-end by:
1. Using Mistral TTS (/v1/audio/speech) to synthesize a short utterance.
2. Feeding the resulting audio bytes into
Meai.ISpeechToTextClient.GetTextAsync (default model: voxtral-mini-2507).
3. Asserting the returned text is non-empty.
Skips when MISTRAL_API_KEY is unset or the account has no voices available.
usingvarclient=newMistralClient(apiKey);VoiceListResponsevoices;try{voices=awaitclient.AudioVoices.ListAllVoicesAsync();}catch(ApiExceptionex){thrownewAssertInconclusiveException($"Mistral voice listing unavailable (HTTP {(int?)ex.StatusCode}); skipping live STT round-trip.",ex);}if(voices.Itemsisnot{Count:>0}items){thrownewAssertInconclusiveException("No voices available on this Mistral account; skipping live STT round-trip.");}varvoice=items[0];SpeechResponsespeech;try{speech=awaitclient.AudioSpeech.SpeechAsync(newSpeechRequest{Input="Hello from Voxtral.",VoiceId=voice.Id.ToString(),ResponseFormat=SpeechOutputFormat.Wav,});}catch(ApiExceptionex){thrownewAssertInconclusiveException($"Mistral TTS unavailable for this account (HTTP {(int?)ex.StatusCode}); skipping live STT round-trip.",ex);}varaudioBytes=Convert.FromBase64String(speech.AudioData);Meai.ISpeechToTextClientspeechClient=client;usingvaraudioStream=newMemoryStream(audioBytes);varresponse=awaitspeechClient.GetTextAsync(audioStream);
Voxtral realtime streaming transcription
Opens a Voxtral realtime WebSocket
(wss://api.mistral.ai/v1/audio/transcriptions/realtime) via
Meai.ISpeechToTextClient.GetStreamingTextAsync, streams ~1 s of synthesized
PCM 16-bit LE / 16 kHz silence to drive the session, and verifies at least a
SessionOpen + SessionClose update pair. A TranscriptionDone update with
non-empty text is asserted only when the server returns one — silent input
does not reliably trigger a transcription on Voxtral.
usingvarclient=newMistralClient(apiKey);// 1 second of PCM 16-bit LE / 16 kHz silence (~16 000 samples × 2 B/sample).varpcmSilence=newbyte[16000*2];usingvaraudio=newMemoryStream(pcmSilence);Meai.ISpeechToTextClientspeechClient=client;boolsessionOpened=false;boolsessionClosed=false;Meai.SpeechToTextResponseUpdate?finalUpdate=null;usingvartimeoutCts=newCancellationTokenSource(TimeSpan.FromSeconds(45));try{awaitforeach(varupdateinspeechClient.GetStreamingTextAsync(audio,cancellationToken:timeoutCts.Token)){if(update.Kind==Meai.SpeechToTextResponseUpdateKind.SessionOpen){sessionOpened=true;}elseif(update.Kind==Meai.SpeechToTextResponseUpdateKind.SessionClose){sessionClosed=true;}elseif(update.Kind==Meai.SpeechToTextResponseUpdateKind.TextUpdated){finalUpdate=update;}}}catch(System.Net.WebSockets.WebSocketExceptionex){thrownewAssertInconclusiveException($"Voxtral realtime endpoint unavailable (WebSocket error: {ex.Message}); skipping live streaming test.",ex);}// finalUpdate may be null when silent input doesn't trigger transcription —// that's expected and not a failure of the streaming plumbing itself.if(finalUpdateisnotnull){}
Voxtral chat with audio input
Exercises the audio-input branch of MistralClient.IChatClient end-to-end by:
1. Using Mistral TTS (/v1/audio/speech) to synthesize a short utterance.
2. Sending that audio to a Voxtral chat model (default
voxtral-small-latest) as a Meai.DataContent with media type
audio/wav, alongside a text prompt asking the model to repeat what it
heard.
3. Asserting the model returns text that mentions the original utterance.
Skips when MISTRAL_API_KEY is unset, the account has no voices, the TTS
endpoint refuses the request, or the Voxtral chat model isn't enabled for
this account.
usingvarclient=newMistralClient(apiKey);VoiceListResponsevoices;try{voices=awaitclient.AudioVoices.ListAllVoicesAsync();}catch(ApiExceptionex){thrownewAssertInconclusiveException($"Mistral voice listing unavailable (HTTP {(int?)ex.StatusCode}); skipping live chat-with-audio test.",ex);}if(voices.Itemsisnot{Count:>0}items){thrownewAssertInconclusiveException("No voices available on this Mistral account; skipping live chat-with-audio test.");}conststringutterance="The quick brown fox jumps over the lazy dog.";SpeechResponsespeech;try{speech=awaitclient.AudioSpeech.SpeechAsync(newSpeechRequest{Input=utterance,VoiceId=items[0].Id.ToString(),ResponseFormat=SpeechOutputFormat.Wav,});}catch(ApiExceptionex){thrownewAssertInconclusiveException($"Mistral TTS unavailable for this account (HTTP {(int?)ex.StatusCode}); skipping live chat-with-audio test.",ex);}varaudioBytes=Convert.FromBase64String(speech.AudioData);Meai.IChatClientchatClient=client;Meai.ChatResponseresponse;try{response=awaitchatClient.GetResponseAsync([ new Meai.ChatMessage(Meai.ChatRole.User, [ new Meai.TextContent("Repeat exactly what the speaker said in the audio, with no extra commentary."), new Meai.DataContent(audioBytes, mediaType: "audio/wav"), ]),],newMeai.ChatOptions{ModelId=VoxtralChatModelId,});}catch(ApiExceptionex)when(ex.StatusCodeisSystem.Net.HttpStatusCode.NotFoundorSystem.Net.HttpStatusCode.ForbiddenorSystem.Net.HttpStatusCode.BadRequest){thrownewAssertInconclusiveException($"Voxtral chat model '{VoxtralChatModelId}' not enabled for this account (HTTP {(int?)ex.StatusCode}); skipping live chat-with-audio test.",ex);}
Chat Client Get Service Returns Null For Unknown Key
usingvarclient=newMistralClient(apiKey);vargetWeatherTool=Meai.AIFunctionFactory.Create((stringlocation)=>$"The weather in {location} is 72°F and sunny.",name:"get_weather",description:"Gets the current weather for a given location.");Meai.IChatClientchatClient=client;varmessages=newList<Meai.ChatMessage>{new(Meai.ChatRole.User,"What is the weather in Paris?"),};// First turn: model requests tool callvarresponse=awaitchatClient.GetResponseAsync(messages,newMeai.ChatOptions{ModelId="mistral-small-latest",Tools=[getWeatherTool],});varfunctionCall=response.Messages.SelectMany(m=>m.Contents).OfType<Meai.FunctionCallContent>().FirstOrDefault();// Add assistant message with function call and tool resultmessages.AddRange(response.Messages);vartoolResult=awaitgetWeatherTool.InvokeAsync(functionCall!.Argumentsis{}args?newMeai.AIFunctionArguments(args):null);messages.Add(newMeai.ChatMessage(Meai.ChatRole.Tool,[ new Meai.FunctionResultContent(functionCall.CallId, toolResult),]));// Second turn: model should produce a final text responsevarfinalResponse=awaitchatClient.GetResponseAsync(messages,newMeai.ChatOptions{ModelId="mistral-small-latest",Tools=[getWeatherTool],});
Chat Client Tool Calling Single Turn
1 2 3 4 5 6 7 8 910111213141516171819202122
usingvarclient=newMistralClient(apiKey);vargetWeatherTool=Meai.AIFunctionFactory.Create((stringlocation)=>$"The weather in {location} is 72°F and sunny.",name:"get_weather",description:"Gets the current weather for a given location.");Meai.IChatClientchatClient=client;varresponse=awaitchatClient.GetResponseAsync([ new Meai.ChatMessage(Meai.ChatRole.User, "What is the weather in Paris?") ],newMeai.ChatOptions{ModelId="mistral-small-latest",Tools=[getWeatherTool],});varfunctionCall=response.Messages.SelectMany(m=>m.Contents).OfType<Meai.FunctionCallContent>().FirstOrDefault();
Chat Client Tool Calling Streaming
1 2 3 4 5 6 7 8 91011121314151617181920212223
usingvarclient=newMistralClient(apiKey);vargetWeatherTool=Meai.AIFunctionFactory.Create((stringlocation)=>$"The weather in {location} is 72°F and sunny.",name:"get_weather",description:"Gets the current weather for a given location.");Meai.IChatClientchatClient=client;varupdates=chatClient.GetStreamingResponseAsync([ new Meai.ChatMessage(Meai.ChatRole.User, "What is the weather in Paris?") ],newMeai.ChatOptions{ModelId="mistral-small-latest",Tools=[getWeatherTool],});varfunctionCalls=newList<Meai.FunctionCallContent>();awaitforeach(varupdateinupdates){functionCalls.AddRange(update.Contents.OfType<Meai.FunctionCallContent>());}