From 9e31631d8f08e66f47cd18c01d3fb70dafe857cf Mon Sep 17 00:00:00 2001 From: balibabu Date: Tue, 23 Dec 2025 11:54:32 +0800 Subject: [PATCH] Feat: Add memory multi-select dropdown to recall and message operator forms. #4213 (#12106) ### What problem does this PR solve? Feat: Add memory multi-select dropdown to recall and message operator forms. #4213 ### Type of change - [x] New Feature (non-breaking change which adds functionality) --- web/src/components/memories-form-field.tsx | 33 +++++++++++++++++++ web/src/hooks/use-memory-request.ts | 30 +++++++++++++++++ web/src/interfaces/database/memory.ts | 11 +++++++ web/src/locales/en.ts | 2 ++ web/src/locales/zh.ts | 2 ++ .../pages/agent/form/message-form/index.tsx | 3 ++ .../message-form/use-show-response-status.ts | 4 +-- .../pages/agent/form/retrieval-form/next.tsx | 13 ++++---- .../form/tool-form/retrieval-form/index.tsx | 8 ++--- web/src/services/memory-service.ts | 2 +- 10 files changed, 95 insertions(+), 13 deletions(-) create mode 100644 web/src/components/memories-form-field.tsx create mode 100644 web/src/hooks/use-memory-request.ts create mode 100644 web/src/interfaces/database/memory.ts diff --git a/web/src/components/memories-form-field.tsx b/web/src/components/memories-form-field.tsx new file mode 100644 index 000000000..2d04a4921 --- /dev/null +++ b/web/src/components/memories-form-field.tsx @@ -0,0 +1,33 @@ +import { useFetchAllMemoryList } from '@/hooks/use-memory-request'; +import { useTranslation } from 'react-i18next'; +import { RAGFlowFormItem } from './ragflow-form'; +import { MultiSelect } from './ui/multi-select'; + +type MemoriesFormFieldProps = { + label: string; +}; + +export function MemoriesFormField({ label }: MemoriesFormFieldProps) { + const { t } = useTranslation(); + const memoryList = useFetchAllMemoryList(); + + const options = memoryList.data?.map((memory) => ({ + label: memory.name, + value: memory.id, + })); + + return ( + + {(field) => ( + + )} + + ); +} diff --git a/web/src/hooks/use-memory-request.ts b/web/src/hooks/use-memory-request.ts new file mode 100644 index 000000000..4c9e80e29 --- /dev/null +++ b/web/src/hooks/use-memory-request.ts @@ -0,0 +1,30 @@ +import { IMemory } from '@/interfaces/database/memory'; +import memoryService from '@/services/memory-service'; +import { useQuery } from '@tanstack/react-query'; + +export const enum MemoryApiAction { + FetchMemoryList = 'fetchMemoryList', +} + +export const useFetchAllMemoryList = () => { + const { data, isLoading, isError, refetch } = useQuery({ + queryKey: [MemoryApiAction.FetchMemoryList], + queryFn: async () => { + const { data: response } = await memoryService.getMemoryList( + { + params: { page_size: 100000000, page: 1 }, + data: {}, + }, + true, + ); + return response.data.memory_list ?? []; + }, + }); + + return { + data, + isLoading, + isError, + refetch, + }; +}; diff --git a/web/src/interfaces/database/memory.ts b/web/src/interfaces/database/memory.ts new file mode 100644 index 000000000..3f496f02c --- /dev/null +++ b/web/src/interfaces/database/memory.ts @@ -0,0 +1,11 @@ +export interface IMemory { + avatar: null; + description: null; + id: string; + memory_type: string[]; + name: string; + owner_name: string; + permissions: string; + storage_type: string; + tenant_id: string; +} diff --git a/web/src/locales/en.ts b/web/src/locales/en.ts index 8f4d2b754..f74bd3ba0 100644 --- a/web/src/locales/en.ts +++ b/web/src/locales/en.ts @@ -2128,6 +2128,8 @@ Important structured information may include: names, dates, locations, events, k immediately: 'Accepted response', streaming: 'Final response', }, + saveToMemory: 'Save to memory', + memory: 'Memory', }, llmTools: { bad_calculator: { diff --git a/web/src/locales/zh.ts b/web/src/locales/zh.ts index ff6c2e655..dfc72a44a 100644 --- a/web/src/locales/zh.ts +++ b/web/src/locales/zh.ts @@ -1940,6 +1940,8 @@ Tokenizer 会根据所选方式将内容存储为对应的数据结构。`, headerParameters: '请求头参数', requestBodyParameters: '请求体参数', }, + saveToMemory: '保存到Memory', + memory: 'Memory', }, footer: { profile: 'All rights reserved @ React', diff --git a/web/src/pages/agent/form/message-form/index.tsx b/web/src/pages/agent/form/message-form/index.tsx index 9a2b47017..7b09d52f2 100644 --- a/web/src/pages/agent/form/message-form/index.tsx +++ b/web/src/pages/agent/form/message-form/index.tsx @@ -1,3 +1,4 @@ +import { MemoriesFormField } from '@/components/memories-form-field'; import { BlockButton, Button } from '@/components/ui/button'; import { Form, @@ -40,6 +41,7 @@ function MessageForm({ node }: INextOperatorForm) { output_format: z.string().optional(), auto_play: z.boolean().optional(), status: z.number().optional(), + memory_ids: z.array(z.string()).optional(), }); const form = useForm({ @@ -159,6 +161,7 @@ function MessageForm({ node }: INextOperatorForm) { )} + ); diff --git a/web/src/pages/agent/form/message-form/use-show-response-status.ts b/web/src/pages/agent/form/message-form/use-show-response-status.ts index ceb8fceb9..4914f5197 100644 --- a/web/src/pages/agent/form/message-form/use-show-response-status.ts +++ b/web/src/pages/agent/form/message-form/use-show-response-status.ts @@ -18,13 +18,13 @@ export function useShowWebhookResponseStatus(form: UseFormReturn) { formData?.mode === AgentDialogueMode.Webhook && formData.execution_mode === WebhookExecutionMode.Streaming ); - }, []); + }, [getNode]); useEffect(() => { if (showWebhookResponseStatus && isEmpty(form.getValues('status'))) { form.setValue('status', 200, { shouldValidate: true, shouldDirty: true }); } - }, []); + }, [form, showWebhookResponseStatus]); return showWebhookResponseStatus; } diff --git a/web/src/pages/agent/form/retrieval-form/next.tsx b/web/src/pages/agent/form/retrieval-form/next.tsx index 848c94967..da82a105b 100644 --- a/web/src/pages/agent/form/retrieval-form/next.tsx +++ b/web/src/pages/agent/form/retrieval-form/next.tsx @@ -2,6 +2,7 @@ import { Collapse } from '@/components/collapse'; import { CrossLanguageFormField } from '@/components/cross-language-form-field'; import { FormContainer } from '@/components/form-container'; import { KnowledgeBaseFormField } from '@/components/knowledge-base-item'; +import { MemoriesFormField } from '@/components/memories-form-field'; import { MetadataFilter, MetadataFilterSchema, @@ -46,6 +47,7 @@ export const RetrievalPartialSchema = { use_kg: z.boolean(), toc_enhance: z.boolean(), ...MetadataFilterSchema, + memory_ids: z.array(z.string()).optional(), }; export const FormSchema = z.object({ @@ -109,12 +111,11 @@ function RetrievalForm({ node }: INextOperatorForm) { return (
- - - - - - + + + + + {t('flow.advancedSettings')}}> { return ( - - - - + + + {t('flow.advancedSettings')}}>