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 (