feat(webchat): enable reasoning display by default (#10020)

* feat(webchat): enable reasoning display by default

* fix(webchat): sync reasoning flag expectations and API docs
This commit is contained in:
Soulter
2026-09-10 10:36:24 +08:00
committed by GitHub
parent 5935430b1d
commit 6fb50cae91
17 changed files with 86 additions and 8 deletions
@@ -152,6 +152,10 @@ class InternalAgentSubStage(Stage):
if (enable_streaming := event.get_extra("enable_streaming")) is not None:
streaming_response = bool(enable_streaming)
show_reasoning = self.show_reasoning
if (enable_reasoning := event.get_extra("enable_reasoning")) is not None:
show_reasoning = bool(enable_reasoning)
has_provider_request = event.get_extra("provider_request") is not None
has_valid_message = bool(event.message_str and event.message_str.strip())
has_media_content = any(
@@ -300,7 +304,7 @@ class InternalAgentSubStage(Stage):
self.max_step,
self.show_tool_use,
self.show_tool_call_result,
show_reasoning=self.show_reasoning,
show_reasoning=show_reasoning,
buffer_intermediate_messages=self.buffer_intermediate_messages,
),
),
@@ -331,7 +335,7 @@ class InternalAgentSubStage(Stage):
self.max_step,
self.show_tool_use,
self.show_tool_call_result,
show_reasoning=self.show_reasoning,
show_reasoning=show_reasoning,
buffer_intermediate_messages=self.buffer_intermediate_messages,
),
),
@@ -362,7 +366,7 @@ class InternalAgentSubStage(Stage):
self.show_tool_use,
self.show_tool_call_result,
stream_to_general,
show_reasoning=self.show_reasoning,
show_reasoning=show_reasoning,
buffer_intermediate_messages=self.buffer_intermediate_messages,
):
yield
@@ -286,9 +286,13 @@ class ResultDecorateStage(Stage):
"provider configured.",
)
show_reasoning = self.show_reasoning
if (enable_reasoning := event.get_extra("enable_reasoning")) is not None:
show_reasoning = bool(enable_reasoning)
if (
not should_tts
and self.show_reasoning
and show_reasoning
and event.get_extra("_llm_reasoning_content")
):
# inject reasoning content to chain
@@ -4,6 +4,7 @@ WEBCHAT_REQUEST_FLAG_DEFAULTS = {
"enable_inline_genui": True,
"enable_default_system_prompt": True,
"enable_streaming": True,
"enable_reasoning": True,
}
+1
View File
@@ -129,6 +129,7 @@ class ChatFlags(BaseModel):
enable_inline_genui: bool = True
enable_default_system_prompt: bool = True
enable_streaming: bool = True
enable_reasoning: bool = True
class ChatMessageRegenerateRequest(OpenModel):
@@ -83,6 +83,10 @@ export type ChatFlags = {
* Enable streaming model output for this request. This value takes priority over the legacy top-level enable_streaming field.
*/
enable_streaming?: boolean;
/**
* Display reasoning content for this WebChat request independently of the global display_reasoning_text setting.
*/
enable_reasoning?: boolean;
};
export type ChatMessagePatchRequest = {
+8
View File
@@ -364,6 +364,7 @@
:staged-files="stagedNonImageFiles"
:disabled="sending"
:enable-streaming="enableStreaming"
:enable-reasoning="enableReasoning"
:is-recording="isRecording"
:is-running="
Boolean(currSessionId && isSessionRunning(currSessionId))
@@ -378,6 +379,7 @@
@send="sendCurrentMessage"
@stop="stopCurrentSession"
@toggle-streaming="toggleStreaming"
@toggle-reasoning="enableReasoning = !enableReasoning"
@remove-image="removeImage"
@remove-audio="removeAudio"
@remove-file="removeFile"
@@ -449,6 +451,7 @@
:staged-files="stagedNonImageFiles"
:disabled="sending"
:enable-streaming="enableStreaming"
:enable-reasoning="enableReasoning"
:is-recording="isRecording"
:is-running="
Boolean(currSessionId && isSessionRunning(currSessionId))
@@ -465,6 +468,7 @@
@send="sendCurrentMessage"
@stop="stopCurrentSession"
@toggle-streaming="toggleStreaming"
@toggle-reasoning="enableReasoning = !enableReasoning"
@remove-image="removeImage"
@remove-audio="removeAudio"
@remove-file="removeFile"
@@ -743,6 +747,7 @@ const threadSelection = reactive<{
selectedText: "",
});
const enableStreaming = ref(true);
const enableReasoning = ref(true);
const sendShortcut = ref<"enter" | "shift_enter">("enter");
let composerResizeObserver: ResizeObserver | null = null;
const {
@@ -1400,6 +1405,7 @@ async function sendCurrentMessage() {
parts: outgoingParts,
transport: transportMode.value,
enableStreaming: enableStreaming.value,
enableReasoning: enableReasoning.value,
selectedProvider: selection?.providerId || "",
selectedModel: selection?.modelName || "",
userRecord,
@@ -1521,6 +1527,7 @@ async function saveMessageEdit() {
sessionId: currSessionId.value,
sourceRecord: target,
enableStreaming: enableStreaming.value,
enableReasoning: enableReasoning.value,
selectedProvider: selection?.providerId || "",
selectedModel: selection?.modelName || "",
});
@@ -1556,6 +1563,7 @@ async function handleRegenerateMessage(
effectiveSelection?.providerId || "",
effectiveSelection?.modelName || "",
enableStreaming.value,
enableReasoning.value,
);
}
@@ -166,6 +166,22 @@
}}
</v-list-item-title>
</v-list-item>
<v-list-item
class="styled-menu-item"
rounded="md"
@click="$emit('toggleReasoning')"
>
<template v-slot:prepend>
<v-icon icon="mdi-brain" size="small"></v-icon>
</template>
<v-list-item-title>
{{
enableReasoning
? tm("reasoning.enabled")
: tm("reasoning.disabled")
}}
</v-list-item-title>
</v-list-item>
</StyledMenu>
</div>
@@ -355,6 +371,7 @@ interface Props {
stagedFiles?: StagedFileInfo[];
disabled: boolean;
enableStreaming: boolean;
enableReasoning: boolean;
isRecording: boolean;
isRunning: boolean;
sessionId?: string | null;
@@ -383,6 +400,7 @@ const emit = defineEmits<{
send: [];
stop: [];
toggleStreaming: [];
toggleReasoning: [];
removeImage: [index: number];
removeAudio: [];
removeFile: [index: number];
@@ -177,6 +177,7 @@
:staged-files="stagedNonImageFiles"
:disabled="sending || initializing"
:enable-streaming="enableStreaming"
:enable-reasoning="enableReasoning"
:is-recording="false"
:is-running="Boolean(currSessionId && isSessionRunning(currSessionId))"
:session-id="currSessionId || null"
@@ -186,6 +187,7 @@
@send="sendCurrentMessage"
@stop="stopCurrentSession"
@toggle-streaming="enableStreaming = !enableStreaming"
@toggle-reasoning="enableReasoning = !enableReasoning"
@remove-image="removeImage"
@remove-audio="removeAudio"
@remove-file="removeFile"
@@ -258,6 +260,7 @@ const currentSession = ref<Session | null>(null);
const draft = ref("");
const initializing = ref(false);
const enableStreaming = ref(true);
const enableReasoning = ref(true);
const shouldStickToBottom = ref(true);
const messagesContainer = ref<HTMLElement | null>(null);
const inputRef = ref<InstanceType<typeof ChatInput> | null>(null);
@@ -362,6 +365,7 @@ async function sendCurrentMessage() {
parts,
transport: transportMode.value,
enableStreaming: enableStreaming.value,
enableReasoning: enableReasoning.value,
selectedProvider: selection?.providerId || "",
selectedModel: selection?.modelName || "",
userRecord,
+18 -4
View File
@@ -4,11 +4,15 @@ import { fetchWithAuth } from "@/api/http";
export type TransportMode = "sse" | "websocket";
export function buildChatRequestFlags(enableStreaming = true) {
export function buildChatRequestFlags(
enableStreaming = true,
enableReasoning = true,
) {
return {
enable_inline_genui: true,
enable_default_system_prompt: true,
enable_streaming: enableStreaming,
enable_reasoning: enableReasoning,
};
}
@@ -109,6 +113,7 @@ interface SendMessageStreamOptions {
parts: MessagePart[];
transport: TransportMode;
enableStreaming?: boolean;
enableReasoning?: boolean;
selectedProvider?: string;
selectedModel?: string;
userRecord?: ChatRecord;
@@ -121,6 +126,7 @@ interface ContinueEditedMessageOptions {
sessionId: string;
sourceRecord: ChatRecord;
enableStreaming?: boolean;
enableReasoning?: boolean;
selectedProvider?: string;
selectedModel?: string;
}
@@ -374,6 +380,7 @@ export function useMessages(options: UseMessagesOptions) {
parts,
transport,
enableStreaming = true,
enableReasoning = true,
selectedProvider = "",
selectedModel = "",
botRecord,
@@ -389,6 +396,7 @@ export function useMessages(options: UseMessagesOptions) {
botRecord,
userRecord,
enableStreaming,
enableReasoning,
selectedProvider,
selectedModel,
);
@@ -401,6 +409,7 @@ export function useMessages(options: UseMessagesOptions) {
botRecord,
userRecord,
enableStreaming,
enableReasoning,
selectedProvider,
selectedModel,
skipUserHistory,
@@ -449,6 +458,7 @@ export function useMessages(options: UseMessagesOptions) {
sessionId,
sourceRecord,
enableStreaming = true,
enableReasoning = true,
selectedProvider = "",
selectedModel = "",
}: ContinueEditedMessageOptions) {
@@ -476,6 +486,7 @@ export function useMessages(options: UseMessagesOptions) {
botRecord,
undefined,
enableStreaming,
enableReasoning,
selectedProvider,
selectedModel,
true,
@@ -489,6 +500,7 @@ export function useMessages(options: UseMessagesOptions) {
selectedProvider = "",
selectedModel = "",
enableStreaming = true,
enableReasoning = true,
) {
if (!sessionId || botRecord.id == null) return;
const targetMessageId = botRecord.id;
@@ -524,7 +536,7 @@ export function useMessages(options: UseMessagesOptions) {
body: JSON.stringify({
selected_provider: selectedProvider,
selected_model: selectedModel,
flags: buildChatRequestFlags(enableStreaming),
flags: buildChatRequestFlags(enableStreaming, enableReasoning),
}),
signal: abort.signal,
},
@@ -619,6 +631,7 @@ export function useMessages(options: UseMessagesOptions) {
botRecord: ChatRecord,
userRecord: ChatRecord | undefined,
enableStreaming: boolean,
enableReasoning: boolean,
selectedProvider: string,
selectedModel: string,
skipUserHistory = false,
@@ -645,7 +658,7 @@ export function useMessages(options: UseMessagesOptions) {
body: JSON.stringify({
session_id: sessionId,
message: parts.map(partToPayload),
flags: buildChatRequestFlags(enableStreaming),
flags: buildChatRequestFlags(enableStreaming, enableReasoning),
selected_provider: selectedProvider,
selected_model: selectedModel,
_skip_user_history: skipUserHistory,
@@ -770,6 +783,7 @@ export function useMessages(options: UseMessagesOptions) {
botRecord: ChatRecord,
userRecord: ChatRecord | undefined,
enableStreaming: boolean,
enableReasoning: boolean,
selectedProvider: string,
selectedModel: string,
) {
@@ -795,7 +809,7 @@ export function useMessages(options: UseMessagesOptions) {
session_id: sessionId,
message_id: messageId,
message: parts.map(partToPayload),
flags: buildChatRequestFlags(enableStreaming),
flags: buildChatRequestFlags(enableStreaming, enableReasoning),
selected_provider: selectedProvider,
selected_model: selectedModel,
});
@@ -115,6 +115,8 @@
"title": "Config"
},
"reasoning": {
"enabled": "Reasoning enabled",
"disabled": "Reasoning disabled",
"thinking": "Thinking Process",
"summarySeparator": ", ",
"thinkSummary": "Thought {count} times",
@@ -115,6 +115,8 @@
"title": "設定"
},
"reasoning": {
"enabled": "思考内容の表示:オン",
"disabled": "思考内容の表示:オフ",
"thinking": "思考プロセス",
"summarySeparator": "、",
"thinkSummary": "思考 {count} 回",
@@ -115,6 +115,8 @@
"title": "Конфигурация"
},
"reasoning": {
"enabled": "Рассуждения включены",
"disabled": "Рассуждения выключены",
"thinking": "Рассуждение",
"summarySeparator": ", ",
"thinkSummary": "Размышлений: {count}",
@@ -115,6 +115,8 @@
"title": "配置文件"
},
"reasoning": {
"enabled": "思考内容已开启",
"disabled": "思考内容已关闭",
"thinking": "思考过程",
"summarySeparator": ",",
"thinkSummary": "思考了 {count} 次",
+5
View File
@@ -7118,6 +7118,11 @@
"type": "boolean",
"default": true,
"description": "Enable streaming model output for this request. This value takes priority over the legacy top-level enable_streaming field."
},
"enable_reasoning": {
"type": "boolean",
"default": true,
"description": "Display reasoning content for this WebChat request independently of the global display_reasoning_text setting."
}
},
"additionalProperties": false
+4
View File
@@ -5547,6 +5547,10 @@ components:
type: boolean
default: true
description: Enable streaming model output for this request. This value takes priority over the legacy top-level enable_streaming field.
enable_reasoning:
type: boolean
default: true
description: Display reasoning content for this WebChat request independently of the global display_reasoning_text setting.
additionalProperties: false
ChatRequest:
+1
View File
@@ -448,6 +448,7 @@ async def test_chat_stream_forwards_normalized_request_flags(chat_service_instan
"enable_inline_genui": True,
"enable_default_system_prompt": False,
"enable_streaming": False,
"enable_reasoning": True,
}
assert "enable_streaming" not in payload
finally:
+2
View File
@@ -10,6 +10,7 @@ def test_webchat_request_flags_use_defaults():
"enable_inline_genui": True,
"enable_default_system_prompt": True,
"enable_streaming": True,
"enable_reasoning": True,
}
@@ -29,6 +30,7 @@ def test_webchat_request_flags_prefer_nested_flags():
"enable_inline_genui": False,
"enable_default_system_prompt": False,
"enable_streaming": True,
"enable_reasoning": True,
}