diff --git a/web/src/components/Chat/ChatContent.tsx b/web/src/components/Chat/ChatContent.tsx index ddb25838..2a86ad93 100644 --- a/web/src/components/Chat/ChatContent.tsx +++ b/web/src/components/Chat/ChatContent.tsx @@ -2,7 +2,7 @@ * @Author: ZhaoYing * @Date: 2025-12-10 16:46:17 * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-03-27 14:17:38 + * @Last Modified time: 2026-03-31 15:01:53 */ import { type FC, useRef, useEffect, useState } from 'react' import clsx from 'clsx' @@ -38,6 +38,22 @@ const ChatContent: FC = ({ const isScrolledToBottomRef = useRef(true); const audioRef = useRef(null) const [playingIndex, setPlayingIndex] = useState(null) + const [expandedReasoning, setExpandedReasoning] = useState>(new Set()) + const [manualToggledReasoning, setManualToggledReasoning] = useState>(new Set()) + + const toggleReasoning = (index: number) => { + setManualToggledReasoning(prev => new Set(prev).add(index)) + setExpandedReasoning(prev => { + const next = new Set(prev) + next.has(index) ? next.delete(index) : next.add(index) + return next + }) + } + + const isReasoningExpanded = (index: number) => { + if (manualToggledReasoning.has(index)) return expandedReasoning.has(index) + return !data[index]?.content + } const handlePlay = (index: number, audio_url: string, audio_status?: string) => { if (audio_status !== 'completed' && !audio_status) return @@ -120,7 +136,7 @@ const ChatContent: FC = ({ {labelFormat(item)} } - {item.meta_data?.files && item.meta_data?.files.length > 0 && + {item.meta_data?.files && item.meta_data?.files.length > 0 && {item.meta_data?.files?.map((file) => { if (file.type.includes('image')) { return ( @@ -174,6 +190,22 @@ const ChatContent: FC = ({ 'rb:mt-1.5': labelPosition === 'top', 'rb:mb-1.5': labelPosition === 'bottom', })}> + {item.meta_data?.reasoning_content &&
+ toggleReasoning(index)} + > + {t('memoryConversation.reasoning_content')} +
+
+ {isReasoningExpanded(index) && } +
} {item.status &&
} {item.subContent && renderRuntime && renderRuntime(item, index)} {/* Render message content using Markdown component */} diff --git a/web/src/components/Chat/index.tsx b/web/src/components/Chat/index.tsx index 49feaf33..f7c0f32e 100644 --- a/web/src/components/Chat/index.tsx +++ b/web/src/components/Chat/index.tsx @@ -27,12 +27,14 @@ const Chat: FC = ({ fileList, fileChange, className, - renderRuntime + renderRuntime, + conversationId }) => { return (
{/* Chat content display area */} void; className?: string; renderRuntime?: (item: ChatItem, index: number) => ReactNode; + conversationId?: string | null; } /** diff --git a/web/src/i18n/en.ts b/web/src/i18n/en.ts index 294b9bae..57e95d81 100644 --- a/web/src/i18n/en.ts +++ b/web/src/i18n/en.ts @@ -1787,6 +1787,11 @@ Memory Bear: After the rebellion, regional warlordism intensified for several re vision_id: 'Vision model', audio_id: 'Audio model', video_id: 'Video model', + onlyDelete: 'Only Delete Fill', + semanticFiltering: 'Semantic Filtering', + sceneFocus: 'Scene Focus', + loose: 'Loose', + strict: 'Strict', }, memoryConversation: { searchPlaceholder: 'Enter user ID...', diff --git a/web/src/i18n/zh.ts b/web/src/i18n/zh.ts index 38b2a76a..39d63399 100644 --- a/web/src/i18n/zh.ts +++ b/web/src/i18n/zh.ts @@ -1783,6 +1783,11 @@ export const zh = { vision_id: '视觉模型', audio_id: '音频模型', video_id: '视频模型', + onlyDelete: '仅删填充', + semanticFiltering: '语义过滤', + sceneFocus: '场景聚焦', + loose: '宽松', + strict: '严格', }, memoryConversation: { chatEmpty:'有什么我可以帮您的吗?', diff --git a/web/src/views/ApplicationConfig/Agent.tsx b/web/src/views/ApplicationConfig/Agent.tsx index 0cfdde05..07859527 100644 --- a/web/src/views/ApplicationConfig/Agent.tsx +++ b/web/src/views/ApplicationConfig/Agent.tsx @@ -2,7 +2,7 @@ * @Author: ZhaoYing * @Date: 2026-02-03 16:29:21 * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-03-27 18:13:51 + * @Last Modified time: 2026-03-31 16:50:10 */ import { useEffect, useRef, useState, forwardRef, useImperativeHandle, useMemo } from 'react'; import { useTranslation } from 'react-i18next' @@ -194,7 +194,7 @@ const Agent = forwardRef { - modelConfigModalRef.current?.handleOpen('model') + modelConfigModalRef.current?.handleOpen('model', { ...defaultModel, model_parameters : values?.model_parameters }) } /** * Clear all debugging chat sessions @@ -287,7 +287,7 @@ const Agent = forwardRef { const opening_statement = form.getFieldValue(['features', 'opening_statement']) - console.log('opening_statement', opening_statement, defaultModel, chatList) if (opening_statement?.enabled && opening_statement?.statement && opening_statement?.statement.trim() !== '') { const assistantMsg: ChatItem = { diff --git a/web/src/views/ApplicationConfig/TestChat/index.tsx b/web/src/views/ApplicationConfig/TestChat/index.tsx index de98b9a7..b3fca33f 100644 --- a/web/src/views/ApplicationConfig/TestChat/index.tsx +++ b/web/src/views/ApplicationConfig/TestChat/index.tsx @@ -2,7 +2,7 @@ * @Author: ZhaoYing * @Date: 2026-03-13 17:27:52 * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-03-26 15:35:13 + * @Last Modified time: 2026-03-31 16:04:15 */ import { type FC, useState, useRef, useEffect } from 'react' import { useTranslation } from 'react-i18next' @@ -171,6 +171,7 @@ const TestChat: FC = ({ ...lastMsg, content: lastMsg.content + content, meta_data: { + ...(lastMsg.meta_data || {}), audio_url: audio_url || lastMsg.meta_data?.audio_url, audio_status: audio_status || lastMsg.meta_data?.audio_status, citations: citations || lastMsg.meta_data?.citations @@ -180,6 +181,24 @@ const TestChat: FC = ({ return newList }) } + const updateAssistantReasoningMessage = (content: string) => { + if (!content) return + if (streamLoading) setStreamLoading(false) + setChatList(prev => { + const newList = [...prev] + const lastMsg = newList[newList.length - 1] + if (lastMsg?.role === 'assistant') { + newList[newList.length - 1] = { + ...lastMsg, + meta_data: { + ...(lastMsg.meta_data || {}), + reasoning_content: (lastMsg.meta_data?.reasoning_content || '') + content + } + } + } + return newList + }) + } const updateErrorAssistantMessage = (message_length: number) => { if (message_length > 0) return @@ -273,6 +292,10 @@ const TestChat: FC = ({ case 'start': if (conversation_id && conversationId !== conversation_id) setConversationId(conversation_id) break + case 'reasoning': + updateAssistantReasoningMessage(content) + if (conversation_id && conversationId !== conversation_id) setConversationId(conversation_id) + break case 'message': updateAssistantMessage(content) if (conversation_id && conversationId !== conversation_id) setConversationId(conversation_id) diff --git a/web/src/views/ApplicationConfig/components/Chat.tsx b/web/src/views/ApplicationConfig/components/Chat.tsx index 42ae43a9..c2abf17d 100644 --- a/web/src/views/ApplicationConfig/components/Chat.tsx +++ b/web/src/views/ApplicationConfig/components/Chat.tsx @@ -2,7 +2,7 @@ * @Author: ZhaoYing * @Date: 2026-02-03 16:27:39 * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-03-27 17:59:07 + * @Last Modified time: 2026-03-31 15:02:07 */ /** * Chat debugging component for application testing @@ -141,6 +141,36 @@ const Chat: FC = ({ } } /** Update assistant message with streaming content */ + const updateAssistantReasoningMessage = (content?: string, model_config_id?: string, conversation_id?: string) => { + if (!content || !model_config_id) return + updateChatList(prev => { + const targetIndex = prev.findIndex(item => item.model_config_id === model_config_id); + if (targetIndex !== -1) { + const modelChatList = [...prev] + const curModelChat = modelChatList[targetIndex] + const curChatMsgList = curModelChat.list || [] + const lastMsg = curChatMsgList[curChatMsgList.length - 1] + if (lastMsg && lastMsg.role === 'assistant') { + modelChatList[targetIndex] = { + ...modelChatList[targetIndex], + conversation_id, + list: [ + ...curChatMsgList.slice(0, curChatMsgList.length - 1), + { + ...lastMsg, + meta_data: { + reasoning_content: (lastMsg.meta_data?.reasoning_content || '') + (content || ''), + } + } + ] + } + } + return [...modelChatList] + } + return prev; + }) + } + /** Update assistant message with streaming content */ const updateAssistantMessage = (content?: string, model_config_id?: string, conversation_id?: string, audio_url?: string, citations?: any[]) => { if ((!content && !audio_url && (!citations || citations?.length < 1)) || !model_config_id) return updateChatList(prev => { @@ -160,6 +190,7 @@ const Chat: FC = ({ ...lastMsg, content: lastMsg.content + (content || ''), meta_data: { + ...(lastMsg.meta_data || {}), ...(audio_url !== undefined ? { audio_url, audio_status: 'pending' } : {}), citations: citations || lastMsg.meta_data?.citations } @@ -274,6 +305,9 @@ const Chat: FC = ({ }; switch (item.event) { + case 'model_reasoning': + updateAssistantReasoningMessage(content, model_config_id, conversation_id) + break; case 'model_message': updateAssistantMessage(content, model_config_id, conversation_id, audio_url) break; diff --git a/web/src/views/ApplicationConfig/components/ModelConfigModal.tsx b/web/src/views/ApplicationConfig/components/ModelConfigModal.tsx index 148afd5a..a80a5905 100644 --- a/web/src/views/ApplicationConfig/components/ModelConfigModal.tsx +++ b/web/src/views/ApplicationConfig/components/ModelConfigModal.tsx @@ -2,7 +2,7 @@ * @Author: ZhaoYing * @Date: 2026-02-03 16:28:07 * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-03-25 11:28:02 + * @Last Modified time: 2026-03-31 16:56:57 */ /** * Model Configuration Modal @@ -11,7 +11,7 @@ */ import { forwardRef, useImperativeHandle, useState, useEffect } from 'react'; -import { Form, type SelectProps } from 'antd'; +import { Form, type SelectProps, Checkbox } from 'antd'; import { useTranslation } from 'react-i18next'; import type { ModelConfig, ModelConfigModalRef, Config, Source } from '../types' @@ -70,7 +70,8 @@ const ModelConfigModal = forwardRef( if (source === 'model') { form.setFieldsValue({ ...(data?.model_parameters || {}), - default_model_config_id: data.default_model_config_id || '' + default_model_config_id: data.default_model_config_id || '', + capability: model?.capability || [] }) } else if (source === 'chat' || source === 'multi_agent') { if (model) { @@ -103,9 +104,12 @@ const ModelConfigModal = forwardRef( const handleChange: SelectProps['onChange'] = (_value, option) => { if (source === 'chat') { form.setFieldValue('label', (option as Model).name) - } else { - form.setFieldValue('capability', (option as Model).capability) } + + form.setFieldsValue({ + capability: (option as Model).capability, + deep_thinking: false, + }) } /** Expose methods to parent component */ @@ -115,8 +119,12 @@ const ModelConfigModal = forwardRef( })); useEffect(() => { - form.setFieldsValue({...(data?.model_parameters || {})}) + const { deep_thinking: _, ...rest } = data?.model_parameters || {} + form.setFieldsValue(rest) }, [values?.default_model_config_id]) + + + console.log('handleChange values', values) return ( ( /> } - {source === 'model' &&