From 49dee40073ac7c8ced737e0c154d4046eddde1eb Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Fri, 13 Feb 2026 03:49:56 -0800 Subject: [PATCH] agent: Skip empty assistant messages for Mistral provider (#47579) This small change *may* help with #39211, #35025 or #39031 although I'm not positive it will fix it entirely. At a minimum, it should prevent sending invalid requests to the Mistral API, which return a 400 error and can prevent the thread from progressing if it gets stuck in a retry loop. This should prevent sending a message like `{ "role": "assistant", "content": "" }` if for some reason the thread contains a message with an empty text content and no tool calls. Some users (including myself) have encountered this with the Devstral 2 models, although it doesn't seem trivial to reproduce: https://github.com/zed-industries/zed/issues/37021#issuecomment-3728902562 When it occurs, error logs look something like this: ``` 2026-01-24T19:53:35-08:00 ERROR [crates/agent/src/thread.rs:984] invalid type: string "Failed to connect to Mistral API: 400 Bad Request {\"object\":\"error\",\"message\":\"Assistant message must have either content or tool_calls, but not none.\",\"type\":\"invalid_request_assistant_message\",\"param\":null,\"code\":\"3240\"}", expected struct EditFileToolOutput 2026-01-24T19:53:35-08:00 ERROR [crates/agent/src/thread.rs:984] invalid type: string "Failed to connect to Mistral API: 400 Bad Request {\"object\":\"error\",\"message\":\"Assistant message must have either content or tool_calls, but not none.\",\"type\":\"invalid_request_assistant_message\",\"param\":null,\"code\":\"3240\"}", expected struct EditFileToolOutput 2026-01-24T19:53:35-08:00 ERROR [crates/agent/src/thread.rs:984] invalid type: string "Failed to connect to Mistral API: 400 Bad Request {\"object\":\"error\",\"message\":\"Assistant message must have either content or tool_calls, but not none.\",\"type\":\"invalid_request_assistant_message\",\"param\":null,\"code\":\"3240\"}", expected struct EditFileToolOutput ``` Release Notes: - Fixed agent sometimes sending invalid messages to Mistral API --- crates/language_models/src/provider/mistral.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/crates/language_models/src/provider/mistral.rs b/crates/language_models/src/provider/mistral.rs index 542779803f9314cd6bf71b7beb48ddc429664159..a2d7c2925b74906acc6bbe62356ff80cf6a2967c 100644 --- a/crates/language_models/src/provider/mistral.rs +++ b/crates/language_models/src/provider/mistral.rs @@ -405,6 +405,9 @@ pub fn into_mistral( Role::Assistant => { for content in &message.content { match content { + MessageContent::Text(text) if text.is_empty() => { + // Mistral API returns a 400 if there's neither content nor tool_calls + } MessageContent::Text(text) => { messages.push(mistral::RequestMessage::Assistant { content: Some(mistral::MessageContent::Plain { @@ -853,6 +856,13 @@ mod tests { cache: false, reasoning_details: None, }, + // should skip empty assistant messages + LanguageModelRequestMessage { + role: Role::Assistant, + content: vec![MessageContent::Text("".into())], + cache: false, + reasoning_details: None, + }, ], temperature: Some(0.5), tools: vec![],