diff --git a/models/spring-ai-mistral-ai/src/main/java/org/springframework/ai/mistralai/api/MistralAiApi.java b/models/spring-ai-mistral-ai/src/main/java/org/springframework/ai/mistralai/api/MistralAiApi.java index 2f9deb1cf4..70e4fc0d57 100644 --- a/models/spring-ai-mistral-ai/src/main/java/org/springframework/ai/mistralai/api/MistralAiApi.java +++ b/models/spring-ai-mistral-ai/src/main/java/org/springframework/ai/mistralai/api/MistralAiApi.java @@ -282,8 +282,6 @@ public enum ChatModel implements ChatModelDescription { // @formatter:off // Premier Models - @Deprecated(forRemoval = true) // Retirement planned the 31st of July 2026 - MAGISTRAL_MEDIUM("magistral-medium-latest"), CODESTRAL("codestral-latest"), // Free Models MINISTRAL_3B("ministral-3b-latest"), @@ -291,14 +289,7 @@ public enum ChatModel implements ChatModelDescription { MINISTRAL_14B("ministral-14b-latest"), MISTRAL_SMALL("mistral-small-latest"), MISTRAL_MEDIUM("mistral-medium-latest"), - MISTRAL_LARGE("mistral-large-latest"), - @Deprecated(forRemoval = true) // Retirement planned the 31st of July 2026 - DEVSTRAL("devstral-latest"), - @Deprecated(forRemoval = true) // Retirement planned the 31st of July 2026 - MAGISTRAL_SMALL("magistral-small-latest"), - // Free Models - Research - @Deprecated(forRemoval = true) // Retirement planned the 31st of July 2026 - OPEN_MISTRAL_NEMO("open-mistral-nemo"); + MISTRAL_LARGE("mistral-large-latest"); // @formatter:on private final String value; diff --git a/models/spring-ai-mistral-ai/src/test/java/org/springframework/ai/mistralai/MistralAiChatModelIT.java b/models/spring-ai-mistral-ai/src/test/java/org/springframework/ai/mistralai/MistralAiChatModelIT.java index ad1190ce79..092191923a 100644 --- a/models/spring-ai-mistral-ai/src/test/java/org/springframework/ai/mistralai/MistralAiChatModelIT.java +++ b/models/spring-ai-mistral-ai/src/test/java/org/springframework/ai/mistralai/MistralAiChatModelIT.java @@ -58,6 +58,7 @@ import org.springframework.ai.converter.ListOutputConverter; import org.springframework.ai.converter.MapOutputConverter; import org.springframework.ai.mistralai.api.MistralAiApi; +import org.springframework.ai.mistralai.api.MistralAiApi.ChatCompletionRequest.ReasoningEffort; import org.springframework.ai.mistralai.api.MistralAiApi.ChatCompletionRequest.ResponseFormat; import org.springframework.ai.model.tool.DefaultToolCallingManager; import org.springframework.ai.model.tool.ToolCallingManager; @@ -642,9 +643,10 @@ private static boolean hasMetadata(List assistantMessages, Str } private static Prompt createThinkingPrompt(MistralAiApi.ChatModel chatModel) { - var reasoningEffort = ThinkingModelUtils.provideReasoningEffort(chatModel); - var model = ThinkingModelUtils.provideChatModelValue(chatModel); - var chatOptions = MistralAiChatOptions.builder().model(model).reasoningEffort(reasoningEffort).build(); + var chatOptions = MistralAiChatOptions.builder() + .model(chatModel.getValue()) + .reasoningEffort(ReasoningEffort.HIGH) + .build(); var systemMessage = new SystemMessage("You are a helpful assistant providing accurate short answers."); var userMessage = new UserMessage( "What is the first planet of the solar system based on the mass in descending order?"); diff --git a/models/spring-ai-mistral-ai/src/test/java/org/springframework/ai/mistralai/ThinkingModelSource.java b/models/spring-ai-mistral-ai/src/test/java/org/springframework/ai/mistralai/ThinkingModelSource.java index fab5d54b24..3a01806360 100644 --- a/models/spring-ai-mistral-ai/src/test/java/org/springframework/ai/mistralai/ThinkingModelSource.java +++ b/models/spring-ai-mistral-ai/src/test/java/org/springframework/ai/mistralai/ThinkingModelSource.java @@ -30,7 +30,7 @@ */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) -@EnumSource(value = ChatModel.class, names = { "MAGISTRAL_MEDIUM", "MISTRAL_MEDIUM", "MISTRAL_SMALL" }) +@EnumSource(value = ChatModel.class, names = { "MISTRAL_MEDIUM", "MISTRAL_SMALL" }) public @interface ThinkingModelSource { } diff --git a/models/spring-ai-mistral-ai/src/test/java/org/springframework/ai/mistralai/ThinkingModelUtils.java b/models/spring-ai-mistral-ai/src/test/java/org/springframework/ai/mistralai/ThinkingModelUtils.java deleted file mode 100644 index 021455c151..0000000000 --- a/models/spring-ai-mistral-ai/src/test/java/org/springframework/ai/mistralai/ThinkingModelUtils.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2023-present the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.ai.mistralai; - -import java.util.Set; - -import org.springframework.ai.mistralai.api.MistralAiApi.ChatCompletionRequest.ReasoningEffort; -import org.springframework.ai.mistralai.api.MistralAiApi.ChatModel; -import org.springframework.util.Assert; - -/** - * @author Nicolas Krier - */ -public interface ThinkingModelUtils { - - // @formatter:off - Set THINKING_MODELS = Set.of( - ChatModel.MAGISTRAL_MEDIUM, - ChatModel.MISTRAL_MEDIUM, - ChatModel.MISTRAL_SMALL - ); - // @formatter:on - - static String provideChatModelValue(ChatModel chatModel) { - verifyChatModelIsReasoning(chatModel); - - // Mistral Medium Latest does not yet target model version 3.5, so this temporary - // workaround is used. - return ChatModel.MISTRAL_MEDIUM == chatModel ? "mistral-medium-3.5" : chatModel.getValue(); - } - - static ReasoningEffort provideReasoningEffort(ChatModel chatModel) { - verifyChatModelIsReasoning(chatModel); - - // Reasoning effort is not supported by Magistral Medium model. - return ChatModel.MAGISTRAL_MEDIUM == chatModel ? null : ReasoningEffort.HIGH; - } - - private static void verifyChatModelIsReasoning(ChatModel chatModel) { - Assert.isTrue(THINKING_MODELS.contains(chatModel), "Only reasoning model is supported!"); - } - -} diff --git a/models/spring-ai-mistral-ai/src/test/java/org/springframework/ai/mistralai/api/MistralAiApiIT.java b/models/spring-ai-mistral-ai/src/test/java/org/springframework/ai/mistralai/api/MistralAiApiIT.java index 1787b6e10e..5ebfa2c947 100644 --- a/models/spring-ai-mistral-ai/src/test/java/org/springframework/ai/mistralai/api/MistralAiApiIT.java +++ b/models/spring-ai-mistral-ai/src/test/java/org/springframework/ai/mistralai/api/MistralAiApiIT.java @@ -29,7 +29,6 @@ import reactor.core.publisher.Flux; import org.springframework.ai.mistralai.ThinkingModelSource; -import org.springframework.ai.mistralai.ThinkingModelUtils; import org.springframework.ai.mistralai.api.MistralAiApi.ChatCompletion; import org.springframework.ai.mistralai.api.MistralAiApi.ChatCompletionChunk; import org.springframework.ai.mistralai.api.MistralAiApi.ChatCompletionMessage; @@ -42,6 +41,7 @@ import org.springframework.ai.mistralai.api.MistralAiApi.ChatCompletionMessage.TextChunk; import org.springframework.ai.mistralai.api.MistralAiApi.ChatCompletionMessage.ToolCall; import org.springframework.ai.mistralai.api.MistralAiApi.ChatCompletionRequest; +import org.springframework.ai.mistralai.api.MistralAiApi.ChatCompletionRequest.ReasoningEffort; import org.springframework.ai.mistralai.api.MistralAiApi.ChatCompletionRequest.ToolChoice; import org.springframework.ai.mistralai.api.MistralAiApi.Embedding; import org.springframework.ai.mistralai.api.MistralAiApi.EmbeddingList; @@ -252,8 +252,8 @@ private static String extractReferencesAsJsonString() { } private static ChatCompletionRequest createChatCompletionRequest(MistralAiApi.ChatModel chatModel, boolean stream) { - var reasoningEffort = ThinkingModelUtils.provideReasoningEffort(chatModel); - var model = ThinkingModelUtils.provideChatModelValue(chatModel); + var reasoningEffort = ReasoningEffort.HIGH; + var model = chatModel.getValue(); var systemChatCompletionMessage = new ChatCompletionMessage( List.of(new TextChunk("You are a helpful assistant providing accurate short answers.")), Role.SYSTEM); var userChatCompletionMessage = new ChatCompletionMessage( diff --git a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/mistralai-chat.adoc b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/mistralai-chat.adoc index e83dd672a4..534349c7a4 100644 --- a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/mistralai-chat.adoc +++ b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/mistralai-chat.adoc @@ -262,7 +262,7 @@ For more information about structured outputs, see the xref:api/structured-outpu Mistral offers two approaches to reasoning: * Adjustable: Available on Mistral Small 4 and Mistral Medium 3.5 via the `reasoning_effort` parameter. Enables the model to think to varying degrees. -* Native: Available for the Magistral model family. These models always generate reasoning traces and are purpose-built for deep reasoning tasks. +* Native: Available for the Magistral model family. These models always generate reasoning traces and are purpose-built for deep reasoning tasks. They have been deprecated and are no longer available. === Reasoning Effort diff --git a/spring-ai-docs/src/main/antora/modules/ROOT/pages/upgrade-notes.adoc b/spring-ai-docs/src/main/antora/modules/ROOT/pages/upgrade-notes.adoc index c46c723e81..907b344620 100644 --- a/spring-ai-docs/src/main/antora/modules/ROOT/pages/upgrade-notes.adoc +++ b/spring-ai-docs/src/main/antora/modules/ROOT/pages/upgrade-notes.adoc @@ -1,6 +1,31 @@ [[upgrade-notes]] = Upgrade Notes +[[upgrading-to-2-1-0]] +== Upgrading to 2.1.0 + +=== Mistral AI Chat Models + +The following deprecated Mistral AI chat models have been removed from the `MistralAiApi.ChatModel` enumeration, as they are no longer available (retired on the 31st of July 2026): + +- `DEVSTRAL`, +- `MAGISTRAL_MEDIUM`, +- `MAGISTRAL_SMALL`, +- `OPEN_MISTRAL_NEMO`. + +==== Impact + +Using these models will now cause: + +- **Compilation failure**: If referenced directly from `MistralAiApi.ChatModel`. +- **Potentially unintended behavior**: If used via the `spring.ai.mistralai.chat.model` property, as Mistral AI redirects requests to these deprecated models to alternative models (for instance, `magistral-medium-latest` is redirected to `mistral-medium-3.5`). + +==== Migration + +Replace these models with active alternatives. Refer to the https://docs.mistral.ai/models/overview#legacy-models[Mistral AI Legacy Models documentation] for recommended replacements. + +You could consider switching to `MISTRAL_SMALL` or `MISTRAL_MEDIUM` with reasoning effort set to `MistralAiApi.ChatCompletionRequest.ReasoningEffort.HIGH` if you were using a Magistral model previously. + [[upgrading-to-2-0-1]] == Upgrading to 2.0.1