diff --git a/web/src/i18n/en.ts b/web/src/i18n/en.ts index 630c6c7e..6e84e720 100644 --- a/web/src/i18n/en.ts +++ b/web/src/i18n/en.ts @@ -1144,6 +1144,8 @@ export const en = { merge: 'Complete Aggregation', vote: 'Key Information Extraction', priority: 'Structured Integration', + addTool: 'Add Tool', + tool: 'Tool', }, userMemory: { userMemory: 'User Memory', @@ -1201,6 +1203,7 @@ export const en = { IMPLICIT_MEMORY: 'Implicit Memory', EMOTIONAL_MEMORY: 'Emotional Memory', EPISODIC_MEMORY: 'Episodic Memory', + FORGETTING_MANAGEMENT: 'Forgetting Management', endUserProfile: 'Core Profile', editEndUserProfile: 'Edit', @@ -1833,6 +1836,7 @@ Memory Bear: After the rebellion, regional warlordism intensified for several re status_code: 'Status Code', max_attempts: 'Max Retry Attempts', retry_interval: 'Retry Interval', + errorBranch: 'Error Branch', }, 'jinja-render': { template: 'Code', diff --git a/web/src/i18n/zh.ts b/web/src/i18n/zh.ts index b50ed1d8..48bddb00 100644 --- a/web/src/i18n/zh.ts +++ b/web/src/i18n/zh.ts @@ -633,6 +633,8 @@ export const zh = { merge: '完整汇总', vote: '关键信息提取', priority: '结构化整合', + addTool: '添加工具', + tool: '工具', }, // 角色管理相关翻译 role: { @@ -1280,6 +1282,7 @@ export const zh = { IMPLICIT_MEMORY: '隐性记忆', EMOTIONAL_MEMORY: '情绪记忆', EPISODIC_MEMORY: '情景记忆', + FORGETTING_MANAGEMENT: '遗忘', endUserProfile: '核心档案', editEndUserProfile: '编辑', @@ -1933,6 +1936,7 @@ export const zh = { status_code: '状态码', max_attempts: '最大重试次数', retry_interval: '重试间隔', + errorBranch: '异常分支', }, 'jinja-render': { template: '代码', @@ -2246,5 +2250,12 @@ export const zh = { orderPayInfo: '支付信息', create_time: '创建时间', }, + forgetDetail: { + title: '遗忘管理系统帮助AI智能管理记忆生命周期,通过自动识别低价值记忆、设置遗忘策略和执行定期清理,优化记忆库存储空间,提升检索效率。', + overviewTitle: '核心指标概览', + totalMemory: '记忆总量', + MemoryHealth: '记忆健康度', + riskOfForgetting: '遗忘风险', + } }, } \ No newline at end of file diff --git a/web/src/views/ApplicationConfig/Agent.tsx b/web/src/views/ApplicationConfig/Agent.tsx index f3e327ec..ce51c622 100644 --- a/web/src/views/ApplicationConfig/Agent.tsx +++ b/web/src/views/ApplicationConfig/Agent.tsx @@ -19,7 +19,6 @@ import type { MemoryConfig, AiPromptModalRef, Source, - ToolModalRef, ToolOption } from './types' import type { Model } from '@/views/ModelManagement/types' @@ -33,7 +32,6 @@ import { memoryConfigListUrl } from '@/api/memory' import CustomSelect from '@/components/CustomSelect' import aiPrompt from '@/assets/images/application/aiPrompt.png' import AiPromptModal from './components/AiPromptModal' -import ToolModal from './components/ToolModal' import ToolList from './components/ToolList' const DescWrapper: FC<{desc: string, className?: string}> = ({desc, className}) => { @@ -115,6 +113,7 @@ const Agent = forwardRef((_props, ref) => { const [variableList, setVariableList] = useState([]) const [isSave, setIsSave] = useState(false) const initialized = useRef(false) + const [toolList, setToolList] = useState([]) // 初始化完成标记 useEffect(() => { @@ -143,6 +142,11 @@ const Agent = forwardRef((_props, ref) => { if (isSave) return setIsSave(true) }, [values]) + useEffect(() => { + if (!initialized.current) return + if (isSave) return + setIsSave(true) + }, [toolList]) useEffect(() => { getModels() @@ -294,7 +298,11 @@ const Agent = forwardRef((_props, ref) => { ...(item.config || {}) })) } as KnowledgeConfig : null, - tools: toolList + tools: toolList.map(vo => ({ + tool_id: vo.tool_id, + operation: vo.operation, + enabled: vo.enabled + })) } console.log('params', rest, params) @@ -347,18 +355,6 @@ const Agent = forwardRef((_props, ref) => { form.setFieldValue('system_prompt', value) } - const toolModalRef = useRef(null) - const [toolList, setToolList] = useState([]) - const handleAddTool = () => { - toolModalRef.current?.handleOpen() - } - const updateTools = (tool: ToolOption) => { - const tools = [...toolList, tool] - setToolList(tools) - form.setFieldValue('tools', tools) - } - - console.log('toolList', toolList) return ( <> {loading && } @@ -469,10 +465,6 @@ const Agent = forwardRef((_props, ref) => { defaultModel={defaultModel} refresh={updatePrompt} /> - ); }); diff --git a/web/src/views/ApplicationConfig/components/AiPromptModal.tsx b/web/src/views/ApplicationConfig/components/AiPromptModal.tsx index f52c0675..b910e1b0 100644 --- a/web/src/views/ApplicationConfig/components/AiPromptModal.tsx +++ b/web/src/views/ApplicationConfig/components/AiPromptModal.tsx @@ -90,11 +90,19 @@ const AiPromptModal = forwardRef(({ switch (item.event) { case 'start': currentPromptValueRef.current = '' + if (editorRef.current?.clear) { + editorRef.current.clear(); + } break; case 'message': if (content) { currentPromptValueRef.current += content; - form.setFieldsValue({ current_prompt: currentPromptValueRef.current }) + if (editorRef.current?.appendText) { + editorRef.current.appendText(content); + editorRef.current.scrollToBottom(); + } else { + form.setFieldsValue({ current_prompt: currentPromptValueRef.current }) + } } if (desc) { setChatList(prev => { @@ -107,6 +115,8 @@ const AiPromptModal = forwardRef(({ break; case 'end': setLoading(false) + // 流结束时同步表单值 + form.setFieldsValue({ current_prompt: currentPromptValueRef.current }) break } }) diff --git a/web/src/views/ApplicationConfig/components/Editor/index.tsx b/web/src/views/ApplicationConfig/components/Editor/index.tsx index d381e003..0c5e2a86 100644 --- a/web/src/views/ApplicationConfig/components/Editor/index.tsx +++ b/web/src/views/ApplicationConfig/components/Editor/index.tsx @@ -4,7 +4,7 @@ import { LexicalComposer } from '@lexical/react/LexicalComposer'; import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin'; import { ContentEditable } from '@lexical/react/LexicalContentEditable'; import { LexicalErrorBoundary } from '@lexical/react/LexicalErrorBoundary'; -import { $getSelection } from 'lexical'; +import { $getSelection, $getRoot, $createParagraphNode, $createTextNode, $isParagraphNode, $isTextNode } from 'lexical'; import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'; import InitialValuePlugin from './plugin/InitialValuePlugin' import LineBreakPlugin from './plugin/LineBreakPlugin'; @@ -12,6 +12,9 @@ import InsertTextPlugin from './plugin/InsertTextPlugin'; export interface EditorRef { insertText: (text: string) => void; + appendText: (text: string) => void; + clear: () => void; + scrollToBottom: () => void; } interface LexicalEditorProps { @@ -46,6 +49,41 @@ const EditorContent = forwardRef(({ selection.insertText(text); } }); + }, + appendText: (text: string) => { + editor.update(() => { + const root = $getRoot(); + const lastChild = root.getLastChild(); + if (lastChild && $isParagraphNode(lastChild)) { + const lastTextNode = lastChild.getLastChild(); + if (lastTextNode && $isTextNode(lastTextNode)) { + const currentText = lastTextNode.getTextContent(); + lastTextNode.setTextContent(currentText + text); + } else { + const textNode = $createTextNode(text); + lastChild.append(textNode); + } + } else { + const paragraph = $createParagraphNode(); + const textNode = $createTextNode(text); + paragraph.append(textNode); + root.append(paragraph); + } + }); + }, + clear: () => { + editor.update(() => { + const root = $getRoot(); + root.clear(); + const paragraph = $createParagraphNode(); + root.append(paragraph); + }); + }, + scrollToBottom: () => { + const editorElement = editor.getRootElement(); + if (editorElement) { + editorElement.scrollTop = editorElement.scrollHeight; + } } }), [editor]); diff --git a/web/src/views/ApplicationConfig/components/Editor/plugin/InitialValuePlugin.tsx b/web/src/views/ApplicationConfig/components/Editor/plugin/InitialValuePlugin.tsx index b1054055..da373023 100644 --- a/web/src/views/ApplicationConfig/components/Editor/plugin/InitialValuePlugin.tsx +++ b/web/src/views/ApplicationConfig/components/Editor/plugin/InitialValuePlugin.tsx @@ -1,21 +1,37 @@ -import { type FC, useEffect } from 'react'; +import { type FC, useEffect, useRef } from 'react'; import { $getRoot, $createParagraphNode, $createTextNode } from 'lexical'; import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'; // 设置初始值的插件 const InitialValuePlugin: FC<{ value?: string }> = ({ value }) => { const [editor] = useLexicalComposerContext(); + const lastValueRef = useRef(undefined); useEffect(() => { - if (value) { + // 只有当value真正发生变化时才更新 + if (lastValueRef.current !== value) { editor.update(() => { const root = $getRoot(); + const currentText = root.getTextContent(); + + // 如果当前内容和新值相同,则不更新 + if (currentText === (value || '')) { + return; + } + root.clear(); - const paragraph = $createParagraphNode(); - const textNode = $createTextNode(value); - paragraph.append(textNode); - root.append(paragraph); + if (value) { + const paragraph = $createParagraphNode(); + const textNode = $createTextNode(value); + paragraph.append(textNode); + root.append(paragraph); + } else { + // 当value为undefined或空时,创建一个空段落 + const paragraph = $createParagraphNode(); + root.append(paragraph); + } }); + lastValueRef.current = value; } }, [editor, value]);