Hide admin memory details and fix memory config
This commit is contained in:
+42
-160
@@ -4,7 +4,6 @@ import {
|
||||
ActivityIcon,
|
||||
DatabaseIcon,
|
||||
RefreshCwIcon,
|
||||
SaveIcon,
|
||||
Trash2Icon,
|
||||
UserPlusIcon,
|
||||
UsersIcon,
|
||||
@@ -68,19 +67,6 @@ type MemoryEvent = {
|
||||
updated_at: string;
|
||||
};
|
||||
|
||||
type UserMemory = {
|
||||
content: string;
|
||||
line_count: number;
|
||||
updated_at?: string | null;
|
||||
};
|
||||
|
||||
type SkillMemory = {
|
||||
skill: string;
|
||||
content: string;
|
||||
line_count: number;
|
||||
updated_at?: string | null;
|
||||
};
|
||||
|
||||
const TOKEN_KEY = "zk-admin-token";
|
||||
|
||||
export default function AdminPage() {
|
||||
@@ -168,10 +154,6 @@ function AdminDashboard({
|
||||
const [accounts, setAccounts] = useState<AccountRow[]>([]);
|
||||
const [selectedAccountId, setSelectedAccountId] = useState("");
|
||||
const [events, setEvents] = useState<MemoryEvent[]>([]);
|
||||
const [userMemory, setUserMemory] = useState<UserMemory | null>(null);
|
||||
const [skillMemories, setSkillMemories] = useState<SkillMemory[]>([]);
|
||||
const [selectedSkill, setSelectedSkill] = useState("");
|
||||
const [memoryDraft, setMemoryDraft] = useState("");
|
||||
const [newAccountId, setNewAccountId] = useState("");
|
||||
const [notice, setNotice] = useState("");
|
||||
|
||||
@@ -179,10 +161,6 @@ function AdminDashboard({
|
||||
() => accounts.find((item) => item.account_id === selectedAccountId),
|
||||
[accounts, selectedAccountId],
|
||||
);
|
||||
const selectedSkillMemory = useMemo(
|
||||
() => skillMemories.find((item) => item.skill === selectedSkill),
|
||||
[skillMemories, selectedSkill],
|
||||
);
|
||||
|
||||
// biome-ignore lint/correctness/useExhaustiveDependencies: 首次进入后台时加载一次即可,后续由刷新按钮触发。
|
||||
useEffect(() => {
|
||||
@@ -195,14 +173,6 @@ function AdminDashboard({
|
||||
loadAccountMemory(selectedAccountId);
|
||||
}, [selectedAccountId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedSkillMemory) {
|
||||
setMemoryDraft(selectedSkillMemory.content);
|
||||
} else if (userMemory) {
|
||||
setMemoryDraft(userMemory.content);
|
||||
}
|
||||
}, [selectedSkillMemory, userMemory]);
|
||||
|
||||
async function refresh() {
|
||||
const [summaryPayload, accountPayload] = await Promise.all([
|
||||
adminFetch<AdminSummary>(token, "/summary"),
|
||||
@@ -217,25 +187,11 @@ function AdminDashboard({
|
||||
}
|
||||
|
||||
async function loadAccountMemory(accountId: string) {
|
||||
const [memoryPayload, userPayload, skillPayload] = await Promise.all([
|
||||
adminFetch<{ events: MemoryEvent[] }>(
|
||||
token,
|
||||
`/memory?account_id=${encodeURIComponent(accountId)}`,
|
||||
),
|
||||
adminFetch<UserMemory>(
|
||||
token,
|
||||
`/memory/user?account_id=${encodeURIComponent(accountId)}`,
|
||||
),
|
||||
adminFetch<SkillMemory[]>(
|
||||
token,
|
||||
`/memory/skills?account_id=${encodeURIComponent(accountId)}`,
|
||||
),
|
||||
]);
|
||||
const memoryPayload = await adminFetch<{ events: MemoryEvent[] }>(
|
||||
token,
|
||||
`/memory?account_id=${encodeURIComponent(accountId)}`,
|
||||
);
|
||||
setEvents(memoryPayload.events ?? []);
|
||||
setUserMemory(userPayload);
|
||||
setSkillMemories(skillPayload);
|
||||
setSelectedSkill("");
|
||||
setMemoryDraft(userPayload.content);
|
||||
}
|
||||
|
||||
async function createAccount() {
|
||||
@@ -264,34 +220,6 @@ function AdminDashboard({
|
||||
await refresh();
|
||||
}
|
||||
|
||||
async function saveMemory() {
|
||||
if (!selectedAccountId) return;
|
||||
if (selectedSkill) {
|
||||
await adminFetch(
|
||||
token,
|
||||
`/memory/skills/${encodeURIComponent(selectedSkill)}`,
|
||||
{
|
||||
method: "PUT",
|
||||
body: JSON.stringify({
|
||||
account_id: selectedAccountId,
|
||||
content: memoryDraft,
|
||||
}),
|
||||
},
|
||||
);
|
||||
setNotice(`已保存 ${selectedSkill} 记忆`);
|
||||
} else {
|
||||
await adminFetch(token, "/memory/user", {
|
||||
method: "PUT",
|
||||
body: JSON.stringify({
|
||||
account_id: selectedAccountId,
|
||||
content: memoryDraft,
|
||||
}),
|
||||
});
|
||||
setNotice("已保存用户记忆");
|
||||
}
|
||||
await loadAccountMemory(selectedAccountId);
|
||||
}
|
||||
|
||||
function logout() {
|
||||
localStorage.removeItem(TOKEN_KEY);
|
||||
onLogout();
|
||||
@@ -403,54 +331,8 @@ function AdminDashboard({
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-4 xl:grid-cols-[1fr_360px]">
|
||||
<div className="rounded-lg border bg-card">
|
||||
<div className="flex items-center justify-between border-b p-3">
|
||||
<div>
|
||||
<div className="font-medium">记忆编辑</div>
|
||||
<div className="text-muted-foreground text-xs">
|
||||
默认编辑用户记忆;选择 Skill 后编辑该 Skill 记忆。
|
||||
</div>
|
||||
</div>
|
||||
<Button size="sm" onClick={saveMemory}>
|
||||
<SaveIcon className="size-4" />
|
||||
保存
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex gap-2 border-b p-3">
|
||||
<Button
|
||||
variant={selectedSkill ? "outline" : "secondary"}
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
setSelectedSkill("");
|
||||
setMemoryDraft(userMemory?.content ?? "");
|
||||
}}
|
||||
>
|
||||
用户记忆
|
||||
</Button>
|
||||
<div className="flex min-w-0 flex-1 gap-2 overflow-x-auto">
|
||||
{skillMemories.map((item) => (
|
||||
<Button
|
||||
key={item.skill}
|
||||
variant={
|
||||
selectedSkill === item.skill ? "secondary" : "outline"
|
||||
}
|
||||
size="sm"
|
||||
onClick={() => setSelectedSkill(item.skill)}
|
||||
>
|
||||
{item.skill}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<textarea
|
||||
className="min-h-[420px] w-full resize-y bg-transparent p-4 font-mono text-sm outline-none"
|
||||
value={memoryDraft}
|
||||
onChange={(event) => setMemoryDraft(event.target.value)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-4">
|
||||
<div className="grid gap-4 xl:grid-cols-[360px_1fr]">
|
||||
<div className="grid gap-4 content-start">
|
||||
<div className="rounded-lg border bg-card">
|
||||
<div className="flex items-center gap-2 border-b p-3 font-medium">
|
||||
<ActivityIcon className="size-4" />
|
||||
@@ -476,42 +358,6 @@ function AdminDashboard({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="rounded-lg border bg-card">
|
||||
<div className="border-b p-3 font-medium">最近记忆事件</div>
|
||||
<div className="max-h-[360px] overflow-y-auto p-2">
|
||||
{events.length ? (
|
||||
events.map((event) => (
|
||||
<div
|
||||
key={event.id}
|
||||
className="mb-2 rounded-md border bg-muted/20 p-2 text-xs"
|
||||
>
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<span className="font-medium">{event.status}</span>
|
||||
<span className="text-muted-foreground">
|
||||
P{event.priority}
|
||||
</span>
|
||||
</div>
|
||||
<div className="mt-1 truncate text-muted-foreground">
|
||||
{event.session_id}
|
||||
</div>
|
||||
<div className="mt-1">
|
||||
{event.signals.join(" / ") || "无信号"}
|
||||
</div>
|
||||
{event.error ? (
|
||||
<div className="mt-1 text-destructive">
|
||||
{event.error}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<p className="p-4 text-center text-muted-foreground text-sm">
|
||||
暂无事件。
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{selectedAccountId ? (
|
||||
<Button
|
||||
variant="destructive"
|
||||
@@ -522,6 +368,42 @@ function AdminDashboard({
|
||||
</Button>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
<div className="rounded-lg border bg-card">
|
||||
<div className="border-b p-3 font-medium">最近记忆事件</div>
|
||||
<div className="max-h-[520px] overflow-y-auto p-2">
|
||||
{events.length ? (
|
||||
events.map((event) => (
|
||||
<div
|
||||
key={event.id}
|
||||
className="mb-2 rounded-md border bg-muted/20 p-2 text-xs"
|
||||
>
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<span className="font-medium">{event.status}</span>
|
||||
<span className="text-muted-foreground">
|
||||
P{event.priority}
|
||||
</span>
|
||||
</div>
|
||||
<div className="mt-1 truncate text-muted-foreground">
|
||||
{event.session_id}
|
||||
</div>
|
||||
<div className="mt-1">
|
||||
{event.signals.join(" / ") || "无信号"}
|
||||
</div>
|
||||
{event.error ? (
|
||||
<div className="mt-1 text-destructive">
|
||||
{event.error}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<p className="p-4 text-center text-muted-foreground text-sm">
|
||||
暂无事件。
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user