From 0f34a64e51ebff74d3e765425307c397ff20d653 Mon Sep 17 00:00:00 2001 From: Carlos Escalante Date: Sat, 4 Jul 2026 19:33:41 -0600 Subject: [PATCH] =?UTF-8?q?Assistant:=20reliable=20"Nueva=20conversaci?= =?UTF-8?q?=C3=B3n"=20reset?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clearing in place (setMessages + remount) left the conversation rendered — CopilotKit keeps chat state beyond agent.messages — so the button now reloads the page after deleting the thread: a fresh boot hydrates from the empty store and shows the welcome screen with suggestions, which previously only appeared after a manual refresh. Supporting changes: - CopilotChat gets an explicit agentId="wealthysmart" (without it, it resolves DEFAULT_AGENT_ID and can bind a different client agent instance than useAgent's). - The BFF answers CopilotChat's POST …/connect with an immediately-completed stream: the runtime's in-memory runner replays this PROCESS's event history, which resurrects cleared conversations and double-feeds hydration. The empty-messages hydration run against the DB store is the single restore path. Co-Authored-By: Claude Fable 5 --- frontend/server.ts | 16 ++++++++++++++++ frontend/src/pages/Asistente.tsx | 13 ++++++++++--- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/frontend/server.ts b/frontend/server.ts index 39df9b2..c05efc5 100644 --- a/frontend/server.ts +++ b/frontend/server.ts @@ -384,12 +384,28 @@ app.use("*", async (c, next) => { }); app.all("/api/copilotkit/*", async (c) => { + // CopilotChat fires POST …/agent//connect for explicit threadIds and + // the runtime's in-memory runner replays THIS PROCESS's event history — + // stale relative to the DB store (it resurrects cleared conversations and + // double-feeds page-load hydration). The empty-messages hydration run + // against MAF is our single restore path, so connect gets an + // immediately-completed stream instead. + if (new URL(c.req.url).pathname.endsWith("/connect")) { + return new Response("", { + status: 200, + headers: { "Content-Type": "text/event-stream" }, + }); + } + const cookieHeader = c.req.header("cookie") ?? ""; const match = cookieHeader.match(/(?:^|;\s*)ws_token=([^;]+)/); const token = match?.[1]; const agentHeaders: Record = token ? { Authorization: `Bearer ${token}` } : {}; + // Note: the browser's X-Client-Timezone header (set in App.tsx) reaches + // the backend without help — CopilotKit's runtime forwards authorization + // and all x-* headers to the agent (extractForwardableHeaders). const agent = new HttpAgent({ url: AGENT_URL, headers: agentHeaders }); // CK_MIDDLEWARES=off runs the stack bare — used to audit which of these diff --git a/frontend/src/pages/Asistente.tsx b/frontend/src/pages/Asistente.tsx index 4c0c307..9bb503a 100644 --- a/frontend/src/pages/Asistente.tsx +++ b/frontend/src/pages/Asistente.tsx @@ -82,11 +82,13 @@ export default function Asistente() { method: "DELETE", credentials: "include", }); - agent?.setMessages([]); - setConfirmClear(false); + // Full reload is the reliable reset: CopilotKit keeps chat state in + // more places than agent.messages (clearing it in place left the + // conversation rendered), while a fresh boot hydrates from the + // now-empty store and shows the welcome screen + suggestions. + window.location.reload(); } catch (err) { console.error("[asistente] clear thread failed:", err); - } finally { setClearing(false); } }; @@ -165,6 +167,11 @@ export default function Asistente() {