feat: add memory management actions and local filters in memory settings (#1467)

* Add MVP memory management actions

* Fix memory settings locale coverage

* Polish memory management interactions

* Add memory search and type filters

* Refine memory settings review feedback

* docs: simplify memory settings review setup

* fix: restore memory updater compatibility helpers

* fix: address memory settings review feedback

* docs: soften memory sample review wording

---------

Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
Co-authored-by: JeffJiang <for-eleven@hotmail.com>
This commit is contained in:
Admire
2026-03-29 13:14:45 +08:00
committed by GitHub
parent 481494b9c0
commit 7eb3a150b5
18 changed files with 1025 additions and 130 deletions
+3 -2
View File
@@ -4,7 +4,6 @@ function getBaseOrigin() {
if (typeof window !== "undefined") {
return window.location.origin;
}
return undefined;
}
@@ -13,7 +12,9 @@ export function getBackendBaseURL() {
return new URL(
env.NEXT_PUBLIC_BACKEND_BASE_URL,
getBaseOrigin(),
).toString();
)
.toString()
.replace(/\/+$/, "");
} else {
return "";
}
+19
View File
@@ -311,6 +311,25 @@ export const enUS: Translations = {
"DeerFlow automatically learns from your conversations in the background. These memories help DeerFlow understand you better and deliver a more personalized experience.",
empty: "No memory data to display.",
rawJson: "Raw JSON",
clearAll: "Clear all memory",
clearAllConfirmTitle: "Clear all memory?",
clearAllConfirmDescription:
"This will remove all saved summaries and facts. This action cannot be undone.",
clearAllSuccess: "All memory cleared",
factDeleteConfirmTitle: "Delete this fact?",
factDeleteConfirmDescription:
"This fact will be removed from memory immediately. This action cannot be undone.",
factDeleteSuccess: "Fact deleted",
noFacts: "No saved facts yet.",
summaryReadOnly:
"Summary sections are read-only for now. You can currently clear all memory or delete individual facts.",
memoryFullyEmpty: "No memory saved yet.",
factPreviewLabel: "Fact to delete",
searchPlaceholder: "Search memory",
filterAll: "All",
filterFacts: "Facts",
filterSummaries: "Summaries",
noMatches: "No matching memory found.",
markdown: {
overview: "Overview",
userContext: "User context",
+17 -1
View File
@@ -247,7 +247,23 @@ export interface Translations {
description: string;
empty: string;
rawJson: string;
markdown: {
clearAll: string;
clearAllConfirmTitle: string;
clearAllConfirmDescription: string;
clearAllSuccess: string;
factDeleteConfirmTitle: string;
factDeleteConfirmDescription: string;
factDeleteSuccess: string;
noFacts: string;
summaryReadOnly: string;
memoryFullyEmpty: string;
factPreviewLabel: string;
searchPlaceholder: string;
filterAll: string;
filterFacts: string;
filterSummaries: string;
noMatches: string;
markdown: {
overview: string;
userContext: string;
work: string;
+18
View File
@@ -298,6 +298,24 @@ export const zhCN: Translations = {
"DeerFlow 会在后台不断从你的对话中自动学习。这些记忆能帮助 DeerFlow 更好地理解你,并提供更个性化的体验。",
empty: "暂无可展示的记忆数据。",
rawJson: "原始 JSON",
clearAll: "清空全部记忆",
clearAllConfirmTitle: "要清空全部记忆吗?",
clearAllConfirmDescription:
"这会删除所有已保存的摘要和事实。此操作无法撤销。",
clearAllSuccess: "已清空全部记忆",
factDeleteConfirmTitle: "要删除这条事实吗?",
factDeleteConfirmDescription:
"这条事实会立即从记忆中删除。此操作无法撤销。",
factDeleteSuccess: "事实已删除",
noFacts: "还没有保存的事实。",
summaryReadOnly: "摘要分区当前仍为只读。现在你可以清空全部记忆或删除单条事实。",
memoryFullyEmpty: "还没有保存任何记忆。",
factPreviewLabel: "即将删除的事实",
searchPlaceholder: "搜索记忆",
filterAll: "全部",
filterFacts: "事实",
filterSummaries: "摘要",
noMatches: "没有找到匹配的记忆。",
markdown: {
overview: "概览",
userContext: "用户上下文",
+34 -4
View File
@@ -2,8 +2,38 @@ import { getBackendBaseURL } from "../config";
import type { UserMemory } from "./types";
export async function loadMemory() {
const memory = await fetch(`${getBackendBaseURL()}/api/memory`);
const json = await memory.json();
return json as UserMemory;
async function readMemoryResponse(
response: Response,
fallbackMessage: string,
): Promise<UserMemory> {
if (!response.ok) {
const errorData = (await response.json().catch(() => ({}))) as {
detail?: string;
};
throw new Error(errorData.detail ?? `${fallbackMessage}: ${response.statusText}`);
}
return response.json() as Promise<UserMemory>;
}
export async function loadMemory(): Promise<UserMemory> {
const response = await fetch(`${getBackendBaseURL()}/api/memory`);
return readMemoryResponse(response, "Failed to fetch memory");
}
export async function clearMemory(): Promise<UserMemory> {
const response = await fetch(`${getBackendBaseURL()}/api/memory`, {
method: "DELETE",
});
return readMemoryResponse(response, "Failed to clear memory");
}
export async function deleteMemoryFact(factId: string): Promise<UserMemory> {
const response = await fetch(
`${getBackendBaseURL()}/api/memory/facts/${encodeURIComponent(factId)}`,
{
method: "DELETE",
},
);
return readMemoryResponse(response, "Failed to delete memory fact");
}
+25 -2
View File
@@ -1,6 +1,7 @@
import { useQuery } from "@tanstack/react-query";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { loadMemory } from "./api";
import { clearMemory, deleteMemoryFact, loadMemory } from "./api";
import type { UserMemory } from "./types";
export function useMemory() {
const { data, isLoading, error } = useQuery({
@@ -9,3 +10,25 @@ export function useMemory() {
});
return { memory: data ?? null, isLoading, error };
}
export function useClearMemory() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: () => clearMemory(),
onSuccess: (memory) => {
queryClient.setQueryData<UserMemory>(["memory"], memory);
},
});
}
export function useDeleteMemoryFact() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (factId: string) => deleteMemoryFact(factId),
onSuccess: (memory) => {
queryClient.setQueryData<UserMemory>(["memory"], memory);
},
});
}