diff --git a/src/components/chat/chatStorage.ts b/src/components/chat/chatStorage.ts index 1a540e5..3574362 100644 --- a/src/components/chat/chatStorage.ts +++ b/src/components/chat/chatStorage.ts @@ -68,14 +68,6 @@ const toSessionSummary = (session: ChatSessionRecord): ChatSessionSummary => ({ updatedAt: session.updatedAt, }); -const buildSessionTitle = (messages: Message[]) => { - const firstUserMessage = messages.find((message) => message.role === "user"); - if (!firstUserMessage) return "新对话"; - const title = firstUserMessage.content.replace(/\s+/g, " ").trim(); - if (!title) return "新对话"; - return title.length > 24 ? `${title.slice(0, 24)}...` : title; -}; - const getDb = () => openDB(CHAT_DB_NAME, CHAT_DB_VERSION, { upgrade(db) { @@ -170,7 +162,7 @@ const migrateLegacyLocalStorage = async () => { const now = Date.now(); const sessionRecord: ChatSessionRecord = { id: createId(), - title: buildSessionTitle(legacyState.messages), + title: "新对话", createdAt: now, updatedAt: now, sessionId: legacyState.sessionId, @@ -244,9 +236,8 @@ export const saveActiveChatState = async ( const now = Date.now(); const storageSessionId = state.storageSessionId ?? createId(); - const computedTitle = buildSessionTitle(state.messages); const preferredTitle = state.title?.trim(); - const finalTitle = preferredTitle || computedTitle; + const finalTitle = preferredTitle || existingSession?.title || "新对话"; const nextRecord: ChatSessionRecord = { id: storageSessionId, title: finalTitle, @@ -278,6 +269,26 @@ export const listChatSessions = async (): Promise => { .map(toSessionSummary); }; +export const updateChatSessionTitle = async ( + storageSessionId: string, + title: string, +): Promise => { + if (typeof window === "undefined") return; + + const normalizedTitle = title.trim(); + if (!normalizedTitle) return; + + const db = await getDb(); + const session = await db.get(SESSION_STORE, storageSessionId); + if (!session) return; + + await db.put(SESSION_STORE, { + ...session, + title: normalizedTitle, + updatedAt: Date.now(), + }); +}; + export const createEmptyChatSession = async (): Promise => { if (typeof window === "undefined") return emptyLoadedChatState(); diff --git a/src/components/chat/hooks/useAgentChatSession.ts b/src/components/chat/hooks/useAgentChatSession.ts index f3105cd..f4219a2 100644 --- a/src/components/chat/hooks/useAgentChatSession.ts +++ b/src/components/chat/hooks/useAgentChatSession.ts @@ -25,6 +25,7 @@ import { loadActiveChatState, loadChatSessionById, saveActiveChatState, + updateChatSessionTitle, } from "../chatStorage"; type UseAgentChatSessionOptions = { @@ -110,6 +111,7 @@ export const useAgentChatSession = ({ const abortRef = useRef(null); const sessionIdRef = useRef(undefined); const cancelPromiseRef = useRef | null>(null); + const titleUpdateNonceRef = useRef(0); useEffect(() => { sessionIdRef.current = sessionId; @@ -130,6 +132,7 @@ export const useAgentChatSession = ({ sessionIdRef.current = loadedState.sessionId; hydrationCompletedRef.current = true; hydrationNonceRef.current += 1; + titleUpdateNonceRef.current += 1; setMessages(loadedState.messages); setSessionTitle(loadedState.title); @@ -308,6 +311,19 @@ export const useAgentChatSession = ({ const nextTitle = event.title.trim(); if (nextTitle) { setSessionTitle(nextTitle); + const currentStorageSessionId = storageSessionIdRef.current; + if (currentStorageSessionId) { + const currentNonce = ++titleUpdateNonceRef.current; + void updateChatSessionTitle(currentStorageSessionId, nextTitle) + .then(() => listChatSessions()) + .then((sessions) => { + if (titleUpdateNonceRef.current !== currentNonce) return; + setChatSessions(sessions); + }) + .catch((error) => { + console.error("[GlobalChatbox] Failed to persist session title:", error); + }); + } } } else if (event.type === "done") { setMessages((prev) => @@ -431,6 +447,7 @@ export const useAgentChatSession = ({ setSessionId(undefined); sessionIdRef.current = undefined; storageSessionIdRef.current = undefined; + titleUpdateNonceRef.current += 1; setIsStreaming(false); }, []); @@ -445,6 +462,7 @@ export const useAgentChatSession = ({ const sessions = await listChatSessions(); hydrationNonceRef.current += 1; + titleUpdateNonceRef.current += 1; storageSessionIdRef.current = newState.storageSessionId; sessionIdRef.current = newState.sessionId; setMessages(newState.messages); @@ -469,6 +487,7 @@ export const useAgentChatSession = ({ ]); hydrationNonceRef.current += 1; + titleUpdateNonceRef.current += 1; storageSessionIdRef.current = nextState.storageSessionId; sessionIdRef.current = nextState.sessionId; setBranchTransition(null); @@ -501,6 +520,7 @@ export const useAgentChatSession = ({ if (!nextActiveSessionId) { hydrationNonceRef.current += 1; + titleUpdateNonceRef.current += 1; storageSessionIdRef.current = undefined; sessionIdRef.current = undefined; setBranchTransition(null); @@ -517,6 +537,7 @@ export const useAgentChatSession = ({ listChatSessions(), ]); hydrationNonceRef.current += 1; + titleUpdateNonceRef.current += 1; storageSessionIdRef.current = nextState.storageSessionId; sessionIdRef.current = nextState.sessionId; setBranchTransition(null);