diff --git a/studio/frontend/src/features/chat/runtime-provider.tsx b/studio/frontend/src/features/chat/runtime-provider.tsx index d01383b309..bdf4e528d8 100644 --- a/studio/frontend/src/features/chat/runtime-provider.tsx +++ b/studio/frontend/src/features/chat/runtime-provider.tsx @@ -1017,6 +1017,21 @@ function ActiveThreadSync({ if (!enabled) { return; } + const persisted = useChatRuntimeStore.getState().activeThreadId; + // On page reload aui mints a fresh `__LOCALID_*` for its draft thread. + // If we already have a persisted draft id, keep it so any RAG docs + // attached to that draft id stay visible — assistant-ui's internal + // chat history for the new mainThreadId starts empty either way, so + // this only affects what we treat as the active id for doc/RAG lookup. + if ( + mainThreadId + && persisted + && persisted !== mainThreadId + && persisted.startsWith("__LOCALID_") + && mainThreadId.startsWith("__LOCALID_") + ) { + return; + } setActiveThreadId(mainThreadId ?? null); }, [enabled, mainThreadId, setActiveThreadId]); diff --git a/studio/frontend/src/features/chat/stores/chat-runtime-store.ts b/studio/frontend/src/features/chat/stores/chat-runtime-store.ts index 1d1df695eb..05c77de896 100644 --- a/studio/frontend/src/features/chat/stores/chat-runtime-store.ts +++ b/studio/frontend/src/features/chat/stores/chat-runtime-store.ts @@ -36,6 +36,7 @@ export const CHAT_RAG_TOOL_ENABLED_KEY = "unsloth_chat_rag_tool_enabled"; // localStorage persistence here the user's external pick is silently // reset to the default on every page refresh. const LAST_EXTERNAL_CHECKPOINT_KEY = "unsloth_chat_last_external_checkpoint"; +const CHAT_ACTIVE_THREAD_KEY = "unsloth_chat_active_thread_id"; function loadLastExternalCheckpoint(): string | null { if (typeof window === "undefined") return null; @@ -610,7 +611,9 @@ export const useChatRuntimeStore = create((set, get) => ({ defaultChatTemplate: null, chatTemplateOverride: null, loadedChatTemplateOverride: null, - activeThreadId: null, + // Persisted across reloads so RAG documents uploaded under a draft + // thread id stay attached after the page refreshes. + activeThreadId: loadString(CHAT_ACTIVE_THREAD_KEY, "") || null, settingsPanelOpen: false, pendingAudioBase64: null, pendingAudioName: null, @@ -755,8 +758,10 @@ export const useChatRuntimeStore = create((set, get) => ({ activeGgufVariant: ggufVariant ?? null, }; }), - setActiveThreadId: (activeThreadId) => - set({ activeThreadId, contextUsage: null }), + setActiveThreadId: (activeThreadId) => { + saveString(CHAT_ACTIVE_THREAD_KEY, activeThreadId ?? ""); + set({ activeThreadId, contextUsage: null }); + }, setSettingsPanelOpen: (settingsPanelOpen) => set({ settingsPanelOpen }), clearCheckpoint: () => { // Mirror setCheckpoint's persistence behavior: dropping the