Skip to content

Commit d3ee37a

Browse files
markturanskyuserclaudemergify[bot]
authored
fix(frontend): restore chat history when returning to a session (#1684)
## Summary - Replace async `params.then()` + `useState` with synchronous `React.use(params)` so route params are available from the first render - Eliminates a race condition where the AG-UI EventSource connection was deferred to a second render cycle, causing historical SSE events (chat history) to be missed on re-navigation - Simplifies `backHref` extraction from URL search params using `useMemo` instead of `useState` ## Root Cause The session detail page extracted `projectName` and `sessionName` from the async `params` Promise via `useEffect(() => { params.then(...) })`, initializing both as empty strings. This meant: 1. **First render**: empty strings → connection effect skipped (guard clause `if (\!projectName || \!sessionName) return`) 2. **Params resolve** → `setState` triggers re-render 3. **Second render**: correct values → connection effect fires via `aguiConnectRef` On fast re-navigation (navigate away, come back), this timing gap could cause the EventSource to miss the backend's SSE replay of historical events, resulting in an empty chat view despite the conversation context being intact on the backend. ## Test plan - [ ] Navigate to a session with existing messages, verify chat history loads - [ ] Navigate away from the session (click sidebar, go to sessions list) - [ ] Navigate back to the same session, verify chat history is still visible - [ ] Repeat with rapid back-and-forth navigation - [ ] Verify new messages can still be sent and received after re-navigation - [ ] `npm run build` passes with 0 errors, 0 warnings - [ ] `npx tsc --noEmit` passes - [ ] ESLint passes on changed file 🤖 Generated with [Claude Code](https://claude.ai/code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Optimized session detail page loading logic for improved performance and reliability. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Co-authored-by: user <u@example.com> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
1 parent 8e3bac3 commit d3ee37a

1 file changed

Lines changed: 12 additions & 18 deletions

File tree

  • components/frontend/src/app/projects/[name]/sessions/[sessionName]

components/frontend/src/app/projects/[name]/sessions/[sessionName]/page.tsx

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"use client";
22

3-
import { useState, useEffect, useMemo, useRef, useCallback } from "react";
3+
import { use, useState, useEffect, useMemo, useRef, useCallback } from "react";
44
import {
55
Loader2,
66
PanelRight,
@@ -117,9 +117,15 @@ export default function ProjectSessionDetailPage({
117117
}) {
118118
const router = useRouter();
119119
const queryClient = useQueryClient();
120-
const [projectName, setProjectName] = useState<string>("");
121-
const [sessionName, setSessionName] = useState<string>("");
122-
const [backHref, setBackHref] = useState<string | null>(null);
120+
const { name: projectName, sessionName } = use(params);
121+
const backHref = useMemo(() => {
122+
if (typeof window !== "undefined") {
123+
try {
124+
return new URL(window.location.href).searchParams.get("backHref");
125+
} catch {}
126+
}
127+
return null;
128+
}, []);
123129
const [contextModalOpen, setContextModalOpen] = useState(false);
124130
const [uploadModalOpen, setUploadModalOpen] = useState(false);
125131
const [repoChanging, setRepoChanging] = useState(false);
@@ -148,18 +154,6 @@ export default function ProjectSessionDetailPage({
148154
const [customWorkflowDialogOpen, setCustomWorkflowDialogOpen] =
149155
useState(false);
150156

151-
// Extract params
152-
useEffect(() => {
153-
params.then(({ name, sessionName: sName }) => {
154-
setProjectName(name);
155-
setSessionName(sName);
156-
try {
157-
const url = new URL(window.location.href);
158-
setBackHref(url.searchParams.get("backHref"));
159-
} catch {}
160-
});
161-
}, [params]);
162-
163157
// Session queue hook (localStorage-backed)
164158
const sessionQueue = useSessionQueue(projectName, sessionName);
165159

@@ -208,8 +202,8 @@ export default function ProjectSessionDetailPage({
208202
// Note: autoConnect is intentionally false to avoid SSR hydration mismatch
209203
// Connection is triggered manually in useEffect after client hydration
210204
const aguiStream = useAGUIStream({
211-
projectName: projectName || "",
212-
sessionName: sessionName || "",
205+
projectName,
206+
sessionName,
213207
autoConnect: false, // Manual connection after hydration
214208
onError: (err) => {
215209
console.error("AG-UI stream error:", err)

0 commit comments

Comments
 (0)