fix: keep chat mounted across view switches and same-thread reclicks (#19)

This commit is contained in:
jfilipiuk
2026-06-24 00:51:40 +02:00
committed by GitHub
parent 8c1e76e645
commit 80ff57e866
+27 -9
View File
@@ -31,6 +31,7 @@ import { HealthIndicator } from "@/app/components/HealthIndicator";
import { InspectorPanel } from "@/app/components/InspectorPanel";
import { setThreadAutoApprove } from "@/lib/autoApprove";
import type { MainChatReporter } from "@/lib/asyncAgents";
import { cn } from "@/lib/utils";
interface HomePageInnerProps {
config: DeploymentConfig;
@@ -46,7 +47,7 @@ function HomePageInner({
handleSaveConfig,
}: HomePageInnerProps) {
const client = useClient();
const [, setThreadId] = useQueryState("threadId");
const [threadId, setThreadId] = useQueryState("threadId");
const [sidebar, setSidebar] = useQueryState("sidebar");
const [view, setView] = useQueryState("view");
const [inspector, setInspector] = useQueryState("inspector");
@@ -191,10 +192,18 @@ function HomePageInner({
async (id: string) => {
setThreadAutoApprove(null, false);
setView(null);
const sameThread = threadId === id;
await setThreadId(id);
setChatSessionRevision((revision) => revision + 1);
// Only force a fresh ChatProvider mount when the thread actually
// changes. Clicking the active thread row (e.g. to return to chat from
// the Memory view) used to bump the revision unconditionally, which
// tore down ChatInterface and forced useStream to re-fetch the full
// thread `/history` — defeating the keep-chat-mounted layout.
if (!sameThread) {
setChatSessionRevision((revision) => revision + 1);
}
},
[setThreadId, setView]
[setThreadId, setView, threadId]
);
return (
@@ -385,11 +394,18 @@ function HomePageInner({
className="relative flex flex-col"
order={2}
>
{view === "skills" ? (
<SkillsMarketplace />
) : view === "memory" ? (
<MemoryPanel />
) : (
{/* Chat stays mounted across view switches. We hide it via
`display:none` (rather than unmounting) so flipping to
Skills/Memory and back is instant — no thread re-fetch, no
message-list rebuild, and any in-flight run keeps streaming
in the background. Cost is bounded: only the *current*
thread's state is held; no accumulation per switch. */}
<div
className={cn(
"flex h-full min-h-0 flex-1 flex-col",
view !== null && "hidden"
)}
>
<ChatProvider
key={chatSessionRevision}
activeAssistant={assistant}
@@ -401,7 +417,9 @@ function HomePageInner({
onNotifyReady={(fn) => setNotifyMainChat(() => fn)}
/>
</ChatProvider>
)}
</div>
{view === "skills" && <SkillsMarketplace />}
{view === "memory" && <MemoryPanel />}
</ResizablePanel>
{inspector && isDesktopLayout && (