From 5d16d9a0e7240ff4e6346bfee4890159da5a764e Mon Sep 17 00:00:00 2001
From: zhou zhou <3272660260@qq.com>
Date: 星期四, 19 三月 2026 11:40:51 +0800
Subject: [PATCH] #AI.记忆治理

---
 rsf-admin/src/layout/AiChatDrawer.jsx |   79 +++++++++++++++++++++++++++++++++++++++
 1 files changed, 78 insertions(+), 1 deletions(-)

diff --git a/rsf-admin/src/layout/AiChatDrawer.jsx b/rsf-admin/src/layout/AiChatDrawer.jsx
index e8e2a07..4b9a69e 100644
--- a/rsf-admin/src/layout/AiChatDrawer.jsx
+++ b/rsf-admin/src/layout/AiChatDrawer.jsx
@@ -31,10 +31,12 @@
 import AddCommentOutlinedIcon from "@mui/icons-material/AddCommentOutlined";
 import DeleteOutlineOutlinedIcon from "@mui/icons-material/DeleteOutlineOutlined";
 import EditOutlinedIcon from "@mui/icons-material/EditOutlined";
+import AutoDeleteOutlinedIcon from "@mui/icons-material/AutoDeleteOutlined";
+import HistoryOutlinedIcon from "@mui/icons-material/HistoryOutlined";
 import PushPinOutlinedIcon from "@mui/icons-material/PushPinOutlined";
 import PushPinIcon from "@mui/icons-material/PushPin";
 import SearchOutlinedIcon from "@mui/icons-material/SearchOutlined";
-import { getAiRuntime, getAiSessions, pinAiSession, removeAiSession, renameAiSession, streamAiChat } from "@/api/ai/chat";
+import { clearAiSessionMemory, getAiRuntime, getAiSessions, pinAiSession, removeAiSession, renameAiSession, retainAiSessionLatestRound, streamAiChat } from "@/api/ai/chat";
 
 const DEFAULT_PROMPT_CODE = "home.default";
 
@@ -70,6 +72,9 @@
             promptName: runtime?.promptName || "--",
             model: runtime?.model || "--",
             mountedMcpCount: runtime?.mountedMcpCount ?? 0,
+            recentMessageCount: runtime?.recentMessageCount ?? 0,
+            hasSummary: !!runtime?.memorySummary,
+            hasFacts: !!runtime?.memoryFacts,
         };
     }, [runtime]);
 
@@ -206,6 +211,42 @@
             await loadSessions(sessionKeyword);
         } catch (error) {
             const message = error.message || "閲嶅懡鍚嶄細璇濆け璐�";
+            setDrawerError(message);
+            notify(message, { type: "error" });
+        }
+    };
+
+    const handleClearMemory = async () => {
+        if (streaming || !sessionId) {
+            return;
+        }
+        try {
+            await clearAiSessionMemory(sessionId);
+            notify("浼氳瘽璁板繂宸叉竻绌�");
+            await Promise.all([
+                loadRuntime(sessionId),
+                loadSessions(sessionKeyword),
+            ]);
+        } catch (error) {
+            const message = error.message || "娓呯┖浼氳瘽璁板繂澶辫触";
+            setDrawerError(message);
+            notify(message, { type: "error" });
+        }
+    };
+
+    const handleRetainLatestRound = async () => {
+        if (streaming || !sessionId) {
+            return;
+        }
+        try {
+            await retainAiSessionLatestRound(sessionId);
+            notify("宸蹭粎淇濈暀褰撳墠杞蹇�");
+            await Promise.all([
+                loadRuntime(sessionId),
+                loadSessions(sessionKeyword),
+            ]);
+        } catch (error) {
+            const message = error.message || "淇濈暀褰撳墠杞蹇嗗け璐�";
             setDrawerError(message);
             notify(message, { type: "error" });
         }
@@ -470,6 +511,9 @@
                                 <Chip size="small" label={`Model: ${runtimeSummary.model}`} />
                                 <Chip size="small" label={`MCP: ${runtimeSummary.mountedMcpCount}`} />
                                 <Chip size="small" label={`History: ${persistedMessages.length}`} />
+                                <Chip size="small" label={`Recent: ${runtimeSummary.recentMessageCount}`} />
+                                <Chip size="small" color={runtimeSummary.hasSummary ? "success" : "default"} label={runtimeSummary.hasSummary ? "鏈夋憳瑕�" : "鏃犳憳瑕�"} />
+                                <Chip size="small" color={runtimeSummary.hasFacts ? "info" : "default"} label={runtimeSummary.hasFacts ? "鏈変簨瀹�" : "鏃犱簨瀹�"} />
                             </Stack>
                             <Stack direction="row" spacing={1} mt={1.5} flexWrap="wrap" useFlexGap>
                                 {quickLinks.map((item) => (
@@ -483,7 +527,40 @@
                                         {item.label}
                                     </Button>
                                 ))}
+                                <Button
+                                    size="small"
+                                    variant="outlined"
+                                    startIcon={<HistoryOutlinedIcon />}
+                                    onClick={handleRetainLatestRound}
+                                    disabled={!sessionId || streaming}
+                                >
+                                    浠呬繚鐣欏綋鍓嶈疆
+                                </Button>
+                                <Button
+                                    size="small"
+                                    variant="outlined"
+                                    color="warning"
+                                    startIcon={<AutoDeleteOutlinedIcon />}
+                                    onClick={handleClearMemory}
+                                    disabled={!sessionId || streaming}
+                                >
+                                    娓呯┖璁板繂
+                                </Button>
                             </Stack>
+                            {!!runtime?.memorySummary && (
+                                <Alert severity="info" sx={{ mt: 1.5 }}>
+                                    <Typography variant="body2" sx={{ whiteSpace: "pre-wrap" }}>
+                                        {runtime.memorySummary}
+                                    </Typography>
+                                </Alert>
+                            )}
+                            {!!runtime?.memoryFacts && (
+                                <Alert severity="success" sx={{ mt: 1.5 }}>
+                                    <Typography variant="body2" sx={{ whiteSpace: "pre-wrap" }}>
+                                        {runtime.memoryFacts}
+                                    </Typography>
+                                </Alert>
+                            )}
                             {loadingRuntime && (
                                 <Typography variant="body2" color="text.secondary" mt={1}>
                                     姝e湪鍔犺浇 AI 杩愯鏃朵俊鎭�...

--
Gitblit v1.9.1