diff --git a/langgraph/src/components/ThreadSidebar.tsx b/langgraph/src/components/ThreadSidebar.tsx index e16fef9..aa20170 100644 --- a/langgraph/src/components/ThreadSidebar.tsx +++ b/langgraph/src/components/ThreadSidebar.tsx @@ -37,6 +37,13 @@ function getLocalTitle(threadId: string): string | null { } } +// Reject titles that look like UUIDs, short hashes, or empty strings +const BAD_TITLE = /^[0-9a-f-]{8,}$/i; +function sanitizeTitle(s: unknown): string | null { + if (typeof s !== "string" || !s.trim() || BAD_TITLE.test(s.trim())) return null; + return s.trim(); +} + function groupByDate(threads: ThreadItem[]): { label: string; threads: ThreadItem[] }[] { const now = new Date(); const groups: Record = {}; @@ -101,10 +108,10 @@ export function ThreadSidebar({ const filtered = threads.filter((t) => { const label = - getLocalTitle(t.thread_id) ?? - (t.metadata?.title as string) ?? - (t.metadata?.firstMessage as string) ?? - t.thread_id; + sanitizeTitle(getLocalTitle(t.thread_id)) ?? + sanitizeTitle(t.metadata?.title) ?? + sanitizeTitle(t.metadata?.firstMessage) ?? + "新对话"; return label.toLowerCase().includes(searchQuery.toLowerCase()); }); @@ -190,9 +197,9 @@ export function ThreadSidebar({ {groupThreads.map((t) => { const isActive = t.thread_id === currentThreadId; const itemLabel = - getLocalTitle(t.thread_id) ?? - (t.metadata?.title as string) ?? - (t.metadata?.firstMessage as string) ?? + sanitizeTitle(getLocalTitle(t.thread_id)) ?? + sanitizeTitle(t.metadata?.title) ?? + sanitizeTitle(t.metadata?.firstMessage) ?? "新对话"; const displayLabel = itemLabel.length > 16 ? itemLabel.slice(0, 16) + "…"