From 06816460eb905c1268dd24d15ff813249dfab8c9 Mon Sep 17 00:00:00 2001
From: xuanmiss <xuanmine@gmail.com>
Date: Wed, 30 Apr 2025 00:55:33 +0800
Subject: [PATCH] feat: options and ChatCompletionRequest add property
 enable_thinking. enable_thinking is used to control whether the Qwen3 model
 enables the thinking mode.

Signed-off-by: xuanmiss <xuanmine@gmail.com>
---
 .../ai/openai/OpenAiChatOptions.java          | 24 +++++++++++++++++--
 .../ai/openai/api/OpenAiApi.java              | 15 ++++++------
 2 files changed, 30 insertions(+), 9 deletions(-)

diff --git a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiChatOptions.java b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiChatOptions.java
index c5687add88d..c2a03cdc91c 100644
--- a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiChatOptions.java
+++ b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiChatOptions.java
@@ -193,6 +193,11 @@ public class OpenAiChatOptions implements ToolCallingChatOptions {
 	 */
 	private @JsonProperty("reasoning_effort") String reasoningEffort;
 
+	/**
+	 * Whether to enable the thinking mode
+	 */
+	private @JsonProperty("enable_thinking") Boolean enableThinking;
+
 	/**
 	 * Collection of {@link ToolCallback}s to be used for tool calling in the chat completion requests.
 	 */
@@ -259,6 +264,7 @@ public static OpenAiChatOptions fromOptions(OpenAiChatOptions fromOptions) {
 			.store(fromOptions.getStore())
 			.metadata(fromOptions.getMetadata())
 			.reasoningEffort(fromOptions.getReasoningEffort())
+			.enableThinking(fromOptions.getEnableThinking())
 			.build();
 	}
 
@@ -547,6 +553,14 @@ public void setReasoningEffort(String reasoningEffort) {
 		this.reasoningEffort = reasoningEffort;
 	}
 
+	public Boolean getEnableThinking() {
+		return this.enableThinking;
+	}
+
+	public void setEnableThinking(Boolean enableThinking) {
+		this.enableThinking = enableThinking;
+	}
+
 	@Override
 	public OpenAiChatOptions copy() {
 		return OpenAiChatOptions.fromOptions(this);
@@ -559,7 +573,7 @@ public int hashCode() {
 				this.streamOptions, this.seed, this.stop, this.temperature, this.topP, this.tools, this.toolChoice,
 				this.user, this.parallelToolCalls, this.toolCallbacks, this.toolNames, this.httpHeaders,
 				this.internalToolExecutionEnabled, this.toolContext, this.outputModalities, this.outputAudio,
-				this.store, this.metadata, this.reasoningEffort);
+				this.store, this.metadata, this.reasoningEffort, this.enableThinking);
 	}
 
 	@Override
@@ -591,7 +605,8 @@ public boolean equals(Object o) {
 				&& Objects.equals(this.outputModalities, other.outputModalities)
 				&& Objects.equals(this.outputAudio, other.outputAudio) && Objects.equals(this.store, other.store)
 				&& Objects.equals(this.metadata, other.metadata)
-				&& Objects.equals(this.reasoningEffort, other.reasoningEffort);
+				&& Objects.equals(this.reasoningEffort, other.reasoningEffort)
+				&& Objects.equals(this.enableThinking, other.enableThinking);
 	}
 
 	@Override
@@ -779,6 +794,11 @@ public Builder reasoningEffort(String reasoningEffort) {
 			return this;
 		}
 
+		public Builder enableThinking(boolean enableThinking) {
+			this.options.enableThinking = enableThinking;
+			return this;
+		}
+
 		public OpenAiChatOptions build() {
 			return this.options;
 		}
diff --git a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiApi.java b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiApi.java
index 3cc5d5b4864..7528296943f 100644
--- a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiApi.java
+++ b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiApi.java
@@ -979,7 +979,8 @@ public record ChatCompletionRequest(// @formatter:off
 			@JsonProperty("tool_choice") Object toolChoice,
 			@JsonProperty("parallel_tool_calls") Boolean parallelToolCalls,
 			@JsonProperty("user") String user,
-			@JsonProperty("reasoning_effort") String reasoningEffort) {
+			@JsonProperty("reasoning_effort") String reasoningEffort,
+			@JsonProperty("enable_thinking") Boolean enableThinking) {
 
 		/**
 		 * Shortcut constructor for a chat completion request with the given messages, model and temperature.
@@ -991,7 +992,7 @@ public record ChatCompletionRequest(// @formatter:off
 		public ChatCompletionRequest(List<ChatCompletionMessage> messages, String model, Double temperature) {
 			this(messages, model, null, null, null, null, null, null, null, null, null, null, null, null, null,
 					null, null, null, false, null, temperature, null,
-					null, null, null, null, null);
+					null, null, null, null, null, null);
 		}
 
 		/**
@@ -1005,7 +1006,7 @@ public ChatCompletionRequest(List<ChatCompletionMessage> messages, String model,
 			this(messages, model, null, null, null, null, null, null,
 					null, null, null, List.of(OutputModality.AUDIO, OutputModality.TEXT), audio, null, null,
 					null, null, null, stream, null, null, null,
-					null, null, null, null, null);
+					null, null, null, null, null, null);
 		}
 
 		/**
@@ -1020,7 +1021,7 @@ public ChatCompletionRequest(List<ChatCompletionMessage> messages, String model,
 		public ChatCompletionRequest(List<ChatCompletionMessage> messages, String model, Double temperature, boolean stream) {
 			this(messages, model, null, null, null, null, null, null, null, null, null,
 					null, null, null, null, null, null, null, stream, null, temperature, null,
-					null, null, null, null, null);
+					null, null, null, null, null, null);
 		}
 
 		/**
@@ -1036,7 +1037,7 @@ public ChatCompletionRequest(List<ChatCompletionMessage> messages, String model,
 				List<FunctionTool> tools, Object toolChoice) {
 			this(messages, model, null, null, null, null, null, null, null, null, null,
 					null, null, null, null, null, null, null, false, null, 0.8, null,
-					tools, toolChoice, null, null, null);
+					tools, toolChoice, null, null, null, null);
 		}
 
 		/**
@@ -1049,7 +1050,7 @@ public ChatCompletionRequest(List<ChatCompletionMessage> messages, String model,
 		public ChatCompletionRequest(List<ChatCompletionMessage> messages, Boolean stream) {
 			this(messages, null, null, null, null, null, null, null, null, null, null,
 					null, null, null, null, null, null, null, stream, null, null, null,
-					null, null, null, null, null);
+					null, null, null, null, null, null);
 		}
 
 		/**
@@ -1062,7 +1063,7 @@ public ChatCompletionRequest streamOptions(StreamOptions streamOptions) {
 			return new ChatCompletionRequest(this.messages, this.model, this.store, this.metadata, this.frequencyPenalty, this.logitBias, this.logprobs,
 			this.topLogprobs, this.maxTokens, this.maxCompletionTokens, this.n, this.outputModalities, this.audioParameters, this.presencePenalty,
 			this.responseFormat, this.seed, this.serviceTier, this.stop, this.stream, streamOptions, this.temperature, this.topP,
-			this.tools, this.toolChoice, this.parallelToolCalls, this.user, this.reasoningEffort);
+			this.tools, this.toolChoice, this.parallelToolCalls, this.user, this.reasoningEffort, this.enableThinking);
 		}
 
 		/**