From 52ae914e1711923086fd694c9832605a72220612 Mon Sep 17 00:00:00 2001 From: zhaoying Date: Tue, 31 Mar 2026 15:43:18 +0800 Subject: [PATCH 1/4] feat(web): rag content api --- web/src/assets/images/conversation/ai.png | Bin 0 -> 6364 bytes web/src/assets/images/conversation/user.png | Bin 0 -> 7990 bytes web/src/components/PageScrollList/index.tsx | 16 ++++-- web/src/components/RbModal/index.css | 3 ++ web/src/i18n/en.ts | 7 +++ web/src/i18n/zh.ts | 6 +++ web/src/views/UserMemoryDetail/Rag.tsx | 6 +-- .../components/ConversationMemory.tsx | 48 ++++++++++++++---- 8 files changed, 68 insertions(+), 18 deletions(-) create mode 100644 web/src/assets/images/conversation/ai.png create mode 100644 web/src/assets/images/conversation/user.png diff --git a/web/src/assets/images/conversation/ai.png b/web/src/assets/images/conversation/ai.png new file mode 100644 index 0000000000000000000000000000000000000000..3783a5436736da0e92bf5c19a27081878ca1ec33 GIT binary patch literal 6364 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 { /** API endpoint URL */ url: string; /** Function to render each list item */ - renderItem: (item: T) => React.ReactNode; + renderItem: (item: T, index: number) => React.ReactNode; /** Query parameters for API request */ query?: Q; /** Number of columns in grid layout */ @@ -57,6 +57,8 @@ interface PageScrollListProps> { className?: string; needLoading?: boolean; heightClass?: string; + gutter?: [number, number] | number; + onTotalChange?: (total: number) => void; } const defaultHeightClass = 'rb:h-[calc(100vh-116px)]!'; @@ -70,6 +72,8 @@ const PageScrollList = forwardRef(>({ className = '', needLoading = true, heightClass, + gutter = [12, 12], + onTotalChange, }: PageScrollListProps, ref: React.Ref) => { /** Expose refresh method to parent component */ useImperativeHandle(ref, () => ({ @@ -88,6 +92,7 @@ const PageScrollList = forwardRef(>({ const pageRef = useRef(1); const loadingRef = useRef(false); const hasMoreRef = useRef(true); + const [total, setTotal] = useState(0); /** Load more data from API with pagination */ const loadMoreData = (reset?: boolean) => { @@ -107,6 +112,9 @@ const PageScrollList = forwardRef(>({ setData(prev => reset ? results : [...prev, ...results]); hasMoreRef.current = response.page?.hasnext; setHasMore(response.page?.hasnext); + const newTotal = response.page?.total || 0; + setTotal(newTotal); + onTotalChange?.(newTotal); }) .catch(() => { hasMoreRef.current = false; @@ -156,11 +164,11 @@ const PageScrollList = forwardRef(>({ {/* Render grid list or empty state */} {data.length > 0 ? ( {data.map((item, index) => ( - {renderItem(item)} + {renderItem(item, index)} ))} diff --git a/web/src/components/RbModal/index.css b/web/src/components/RbModal/index.css index 8dabc4ab..56d95248 100644 --- a/web/src/components/RbModal/index.css +++ b/web/src/components/RbModal/index.css @@ -1,3 +1,6 @@ +.rb-modal { + top: 40px; +} .rb-modal .ant-modal-footer .ant-btn { height: 32px !important; padding: 0 15px !important; diff --git a/web/src/i18n/en.ts b/web/src/i18n/en.ts index 2975796a..294b9bae 100644 --- a/web/src/i18n/en.ts +++ b/web/src/i18n/en.ts @@ -627,6 +627,8 @@ export const en = { vision: 'Vision', audio: 'Audio', video: 'Video', + thinking: 'Deep Thinking', + is_thinking: 'Deep Thinking Support', }, knowledgeBase: { home: 'Home', @@ -1421,6 +1423,7 @@ export const en = { citation: 'Citation and Attribution', citation_desc: 'Display the attribution of source documents and generated content', invalidVariablesTitle: "The following undefined variables are referenced in the conversation opening. Do you want to save the opening configuration?", + deep_thinking: 'Enable Deep Thinking', apps: 'My Apps', sharing: 'Sharing', @@ -1594,6 +1597,8 @@ export const en = { core_entities: 'Core Entities', communityDetailEmptyDesc: 'Click on a community in the chart on the left to view details', communityLoadingTip: 'Generating community graph', + assistant: 'AI Assistant', + totalRagMemory: 'Total number of memories', }, space: { createSpace: 'Create Space', @@ -1828,6 +1833,8 @@ Memory Bear: After the rebellion, regional warlordism intensified for several re memoryTipTitle: 'Are you sure you want to enable conversation memory? Conversations will be saved to the memory store.', stopAudioRecorder: 'Stop Recording', startAudioRecorder: 'Start Recording', + citations: 'Citations', + reasoning_content: 'Deep reasoning Content', }, login: { title: 'Red Bear Memory Science', diff --git a/web/src/i18n/zh.ts b/web/src/i18n/zh.ts index 3edd84e3..38b2a76a 100644 --- a/web/src/i18n/zh.ts +++ b/web/src/i18n/zh.ts @@ -795,6 +795,7 @@ export const zh = { citation: '引用和归属', citation_desc: '显示源文档和生成内容的归属部分', invalidVariablesTitle: "对话开场白中引用了以下未定义的变量,是否保存开场白配置?", + deep_thinking: '开启深度思考', apps: '我的应用', sharing: '共享', @@ -1274,6 +1275,8 @@ export const zh = { vision: '视觉', audio: '音频', video: '视频', + thinking: '深度思考', + is_thinking: '支持深度思考', }, timezones: { 'Asia/Shanghai': '中国标准时间 (UTC+8)', @@ -1592,6 +1595,8 @@ export const zh = { core_entities: '核心实体', communityDetailEmptyDesc: '点击左侧图表中的社区查看详情', communityLoadingTip: '社区图谱生成中', + assistant: 'AI 助手', + totalRagMemory: '记忆总数', }, space: { createSpace: '创建空间', @@ -1825,6 +1830,7 @@ export const zh = { stopAudioRecorder: '停止录音', startAudioRecorder: '开始录音', citations: '引用', + reasoning_content: '深度思考内容', }, login: { title: '红熊记忆科学', diff --git a/web/src/views/UserMemoryDetail/Rag.tsx b/web/src/views/UserMemoryDetail/Rag.tsx index f770fafc..a11d4295 100644 --- a/web/src/views/UserMemoryDetail/Rag.tsx +++ b/web/src/views/UserMemoryDetail/Rag.tsx @@ -2,7 +2,7 @@ * @Author: ZhaoYing * @Date: 2026-02-03 17:57:11 * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-03-27 10:26:31 + * @Last Modified time: 2026-03-31 15:29:45 */ /** * RAG User Memory Detail View @@ -114,7 +114,7 @@ const Rag: FC = () => { } return ( - + { - + diff --git a/web/src/views/UserMemoryDetail/components/ConversationMemory.tsx b/web/src/views/UserMemoryDetail/components/ConversationMemory.tsx index f956eca4..c209274b 100644 --- a/web/src/views/UserMemoryDetail/components/ConversationMemory.tsx +++ b/web/src/views/UserMemoryDetail/components/ConversationMemory.tsx @@ -2,38 +2,64 @@ * @Author: ZhaoYing * @Date: 2026-02-03 18:34:04 * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-03-27 10:28:53 + * @Last Modified time: 2026-03-31 15:35:13 */ -import { type FC } from 'react' +import { type FC, useState } from 'react' import { useTranslation } from 'react-i18next' import { useParams } from 'react-router-dom' +import { Divider, Flex } from 'antd' +import clsx from 'clsx' import RbCard from '@/components/RbCard/Card' import PageScrollList from '@/components/PageScrollList' import Markdown from '@/components/Markdown' import { getRagContentUrl } from '@/api/memory' +interface DataItem { + role: 'user' | 'assistant'; + content: string; +} + const ConversationMemory: FC = () => { const { t } = useTranslation() const { id } = useParams() + const [total, setTotal] = useState(0) return ( {t('userMemory.conversationMemory')}} headerType="borderless" - headerClassName="rb:min-h-[54px]! rb:pt-0! rb:mb-0! rb:font-[MiSans-Bold] rb:font-bold" - bodyClassName="rb:p-4! rb:pt-0! rb:h-[calc(100%-54px)]!" + headerClassName="rb:min-h-[54px]! rb:pt-0! rb:mb-0!" + bodyClassName="rb:p-4! rb:pt-0! rb:pb-1! rb:h-[calc(100%-54px)]!" className="rb:h-full!" + extra={
{t('userMemory.totalRagMemory')}: {total}
} > - + url={getRagContentUrl} query={{ end_user_id: id }} column={1} - renderItem={(item: string) => ( -
- + gutter={0} + onTotalChange={setTotal} + renderItem={(item, index) => ( +
+ {index !== 0 && } + +
+
+
+ {item.role === 'assistant' ? t('userMemory.assistant') : t('userMemory.user')} +
+ +
+
)} className="rb:h-full!" From b40f4829cb20d4091f9735debf4c23f6e9363a06 Mon Sep 17 00:00:00 2001 From: zhaoying Date: Tue, 31 Mar 2026 15:48:19 +0800 Subject: [PATCH 2/4] feat(web): custom model add thinking capability --- .../components/CustomModelModal.tsx | 53 ++++++++++++------- web/src/views/ModelManagement/types.ts | 7 +-- 2 files changed, 39 insertions(+), 21 deletions(-) diff --git a/web/src/views/ModelManagement/components/CustomModelModal.tsx b/web/src/views/ModelManagement/components/CustomModelModal.tsx index abede886..01cc0fd6 100644 --- a/web/src/views/ModelManagement/components/CustomModelModal.tsx +++ b/web/src/views/ModelManagement/components/CustomModelModal.tsx @@ -2,7 +2,7 @@ * @Author: ZhaoYing * @Date: 2026-02-03 16:49:28 * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-03-25 14:07:10 + * @Last Modified time: 2026-03-31 13:56:18 */ /** * Custom Model Modal @@ -11,7 +11,7 @@ */ import { forwardRef, useEffect, useImperativeHandle, useState } from 'react'; -import { Form, Input, App, Checkbox, Button } from 'antd'; +import { Form, Input, App, Checkbox, Button, Row, Col } from 'antd'; import { useTranslation } from 'react-i18next'; import type { CustomModelForm, ModelListItem, CustomModelModalRef, CustomModelModalProps } from '../types'; @@ -72,6 +72,7 @@ const CustomModelModal = forwardRef( is_vision: capability?.includes('vision') || false, is_video: capability?.includes('video') || false, is_audio: capability?.includes('audio') || false, + is_thinking: capability?.includes('thinking') || false, }); } else { setIsEdit(false); @@ -101,7 +102,7 @@ const CustomModelModal = forwardRef( form .validateFields() .then((values) => { - const { logo, type, is_vision, is_video, is_audio, is_omni, ...rest } = values; + const { logo, type, is_vision, is_video, is_audio, is_omni, is_thinking, ...rest } = values; const formData: CustomModelForm = { ...rest, type, @@ -120,6 +121,9 @@ const CustomModelModal = forwardRef( capability.push('video') } } + if (is_thinking) { + capability.push('thinking') + } formData.capability = capability formData.is_omni = is_omni @@ -238,21 +242,34 @@ const CustomModelModal = forwardRef( - {!['embedding', 'rerank'].includes(modelType as string) && - <> - - {t('modelNew.is_omni')} - - - {t('modelNew.is_vision')} - - - {t('modelNew.is_video')} - - - {t('modelNew.is_audio')} - - + {['llm', 'chat'].includes(modelType as string) && + + + + {t('modelNew.is_omni')} + + + + + {t('modelNew.is_vision')} + + + + + {t('modelNew.is_video')} + + + + + {t('modelNew.is_audio')} + + + + + {t('modelNew.is_thinking')} + + + } diff --git a/web/src/views/ModelManagement/types.ts b/web/src/views/ModelManagement/types.ts index 1662775f..cafac4b3 100644 --- a/web/src/views/ModelManagement/types.ts +++ b/web/src/views/ModelManagement/types.ts @@ -2,7 +2,7 @@ * @Author: ZhaoYing * @Date: 2026-02-03 16:50:18 * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-03-25 12:28:10 + * @Last Modified time: 2026-03-31 15:48:02 */ /** * Type definitions for Model Management @@ -295,7 +295,8 @@ export interface CustomModelForm { is_video?: boolean; is_audio?: boolean; is_omni?: boolean; - capability?: string[]; + is_thinking?: boolean; + capability?: Capability[]; } /** @@ -324,7 +325,7 @@ export interface BaseRef { modelListDetailRefresh?: () => void; } -export type Capability = 'vision' | 'audio' | 'video'; +export type Capability = 'vision' | 'audio' | 'video' | 'thinking'; export interface Model { name: string; type: string; From ca255304d919cf7b38408447140b7f426c71bd39 Mon Sep 17 00:00:00 2001 From: zhaoying Date: Tue, 31 Mar 2026 18:07:32 +0800 Subject: [PATCH 3/4] feat(web): agent support deep thinking --- web/src/components/Chat/ChatContent.tsx | 36 ++++++++- web/src/components/Chat/index.tsx | 4 +- web/src/components/Chat/types.ts | 6 +- web/src/i18n/en.ts | 5 ++ web/src/i18n/zh.ts | 5 ++ web/src/views/ApplicationConfig/Agent.tsx | 7 +- .../ApplicationConfig/TestChat/index.tsx | 25 +++++- .../ApplicationConfig/components/Chat.tsx | 36 ++++++++- .../components/ModelConfigModal.tsx | 30 ++++++-- web/src/views/ApplicationConfig/types.ts | 3 +- web/src/views/Conversation/index.tsx | 76 +++++++++++++++---- web/src/views/Conversation/types.ts | 3 +- 12 files changed, 203 insertions(+), 33 deletions(-) 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' &&