diff --git a/studio/frontend/src/features/chat/chat-page.tsx b/studio/frontend/src/features/chat/chat-page.tsx index 7a86950633..84fae04080 100644 --- a/studio/frontend/src/features/chat/chat-page.tsx +++ b/studio/frontend/src/features/chat/chat-page.tsx @@ -174,7 +174,8 @@ function InlineSidebar({ function TopBarActions({ onNewThread, onNewCompare, -}: { onNewThread: () => void; onNewCompare: () => void }) { + showCompare, +}: { onNewThread: () => void; onNewCompare: () => void; showCompare: boolean }) { const { state } = useSidebar(); if (state !== "collapsed") { return null; @@ -189,14 +190,16 @@ function TopBarActions({ New Chat - - - - - Compare - + {showCompare ? ( + + + + + Compare + + ) : null} ); } @@ -215,6 +218,11 @@ export function ChatPage(): ReactElement { const lorasFromStore = useChatRuntimeStore((state) => state.loras); const modelsError = useChatRuntimeStore((state) => state.modelsError); const { refresh, selectModel, ejectModel } = useChatModelRuntime(); + const canCompare = useMemo(() => { + const selected = inferenceParams.checkpoint; + if (!selected) return false; + return lorasFromStore.some((lora) => lora.id === selected); + }, [inferenceParams.checkpoint, lorasFromStore]); const handleCheckpointChange = useCallback( (value: string, meta?: { isLora: boolean }) => { @@ -277,6 +285,7 @@ export function ChatPage(): ReactElement { onSelect={setView} onNewThread={handleNewThread} onNewCompare={handleNewCompare} + showCompare={canCompare} /> @@ -287,6 +296,7 @@ export function ChatPage(): ReactElement {
(); +function fallbackTitleFromUserText(userText: string): string { + const firstLine = (userText || "").split(/\r?\n/, 1)[0] ?? ""; + const cleaned = firstLine.replace(/\s+/g, " ").trim(); + const max = 48; + if (!cleaned) return "New Chat"; + return cleaned.slice(0, max) + (cleaned.length > max ? "..." : ""); +} + function toThreadMessage(m: MessageRecord): ThreadMessage { const base = { id: m.id, @@ -342,7 +350,7 @@ function createDexieAdapter( const userText = extractTextParts(firstUser) || "New Chat"; if (!autoTitle) { - const title = userText.slice(0, 60) + (userText.length > 60 ? "..." : ""); + const title = fallbackTitleFromUserText(userText); await db.threads.update(remoteId, { title }); if (pairId) { const paired = await db.threads @@ -394,7 +402,7 @@ function createDexieAdapter( (await generateTitleWithModel({ userText, })) || - (userText.slice(0, 60) + (userText.length > 60 ? "..." : "")); + fallbackTitleFromUserText(userText); await db.threads.update(remoteId, { title }); if (pairId) { 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 682ea2ccce..10d5957906 100644 --- a/studio/frontend/src/features/chat/stores/chat-runtime-store.ts +++ b/studio/frontend/src/features/chat/stores/chat-runtime-store.ts @@ -57,7 +57,7 @@ export const useChatRuntimeStore = create((set) => ({ loras: [], warmingByThreadId: {}, runningByThreadId: {}, - autoTitle: loadBool(AUTO_TITLE_KEY, true), + autoTitle: loadBool(AUTO_TITLE_KEY, false), modelsError: null, setParams: (params) => set({ params }), setModels: (models) => set({ models }), diff --git a/studio/frontend/src/features/chat/thread-sidebar.tsx b/studio/frontend/src/features/chat/thread-sidebar.tsx index e1645e77bb..369dc30769 100644 --- a/studio/frontend/src/features/chat/thread-sidebar.tsx +++ b/studio/frontend/src/features/chat/thread-sidebar.tsx @@ -62,11 +62,13 @@ export function ThreadSidebar({ onSelect, onNewThread, onNewCompare, + showCompare, }: { view: ChatView; onSelect: (view: ChatView) => void; onNewThread: () => void; onNewCompare: () => void; + showCompare: boolean; }) { const allThreads = useLiveQuery( () => db.threads.orderBy("createdAt").reverse().toArray(), @@ -112,12 +114,14 @@ export function ThreadSidebar({ New Chat - - - - Compare - - + {showCompare ? ( + + + + Compare + + + ) : null}