feat: 完善知识图谱交互与 Agent/线程持久化

- 知识图谱画布、侧边栏、详情面板交互优化,新增图谱相关 API 与 hooks
- Agent 卡片与详情面板调整,对话页面重构
- 线程元数据持久化增强(base/memory/sql),knowledge 仓储与导出补充
- 网关路由 agents/knowledge/threads 同步更新

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
吉鑫升andClaude Opus 4.8 committed 2026-06-11 19:58:34 +08:00
1 parent ea78fe9726
commit f107ebc46d
25 files changed
+929 -279

No files matched your search

@@ -1,6 +1,8 @@
import { ChevronDown, ChevronRight, Search, X } from "lucide-react";
import { ChevronDown, ChevronRight, Eraser, Search, X } from "lucide-react";
import { useState } from "react";
import type { GraphBlacklistItem } from "@/core/knowledge/api";
import type { GraphNode, GraphStats, NodeKind } from "./graphTypes";
import {
getEdgeInfo,
@@ -19,16 +21,26 @@ interface GraphSidebarProps {
stats: GraphStats;
topNodes: Array<{ node: GraphNode; degree: number }>;
hiddenCount: number;
blacklistItems: GraphBlacklistItem[];
blacklistPending: boolean;
junkCandidateCount: number;
onSearchChange: (keyword: string) => void;
onSearchEnter: () => void;
onToggleNodeKind: (kind: NodeKind) => void;
onToggleEdgeLabel: (label: string) => void;
onRestoreHidden: () => void;
onRemoveBlacklist: (entryId: string) => void;
onCleanJunk: () => void;
onPickNode: (id: string) => void;
onClose: () => void;
}
type SectionKey = "nodeTypes" | "edgeTypes" | "graphStats" | "coreNodes";
type SectionKey =
| "nodeTypes"
| "edgeTypes"
| "graphStats"
| "coreNodes"
| "blacklist";
interface FilterSectionProps {
title: string;
@@ -69,6 +81,7 @@ export function GraphSidebar(props: GraphSidebarProps) {
edgeTypes: true,
graphStats: false,
coreNodes: false,
blacklist: true,
});
const toggleFilterSection = (key: SectionKey) => {
@@ -230,6 +243,49 @@ export function GraphSidebar(props: GraphSidebarProps) {
))}
</FilterSection>
) : null}
<FilterSection
title="图谱黑名单"
extra={`${props.blacklistItems.length} 个`}
collapsed={collapsedSections.blacklist}
onToggle={() => toggleFilterSection("blacklist")}
>
<div className="kg-search-hint">
黑名单中的主题 / 节点不会出现在图谱中。可在节点详情里加入黑名单。
</div>
<button
type="button"
className="kg-icon-button"
disabled={props.blacklistPending || props.junkCandidateCount === 0}
title="将单字符、纯数字符号、通用泛词等低价值主题批量加入黑名单"
onClick={props.onCleanJunk}
>
<Eraser size={13} /> 清理低价值主题
{props.junkCandidateCount > 0 ? `(${props.junkCandidateCount})` : ""}
</button>
{props.blacklistItems.length === 0 ? (
<div className="kg-search-hint">暂无黑名单条目。</div>
) : (
props.blacklistItems.map((item) => (
<div key={item.id} className="kg-check-row">
<span className="kg-check-row-main">
<span className="kg-check-label" title={item.label}>
{item.label}
</span>
</span>
<button
type="button"
className="kg-text-button"
disabled={props.blacklistPending}
title="移出黑名单,重新显示该节点"
onClick={() => props.onRemoveBlacklist(item.id)}
>
移除
</button>
</div>
))
)}
</FilterSection>
</div>
</aside>
);