Skip to content

fix: navigate to the correct session ID when updating session state#275

Merged
viper151 merged 3 commits intomainfrom
fix/navigate-to-correct-session-id-using-codex
Jan 5, 2026
Merged

fix: navigate to the correct session ID when updating session state#275
viper151 merged 3 commits intomainfrom
fix/navigate-to-correct-session-id-using-codex

Conversation

@blackmammoth
Copy link
Collaborator

@blackmammoth blackmammoth commented Dec 31, 2025

TLDR:

  • Get codex sessions in windows correctly
  • Improve message counting logic
  • Fix session navigation. Replace the url with the actual session id after the first complete codex response.

This pull request introduces an improvement to the session management logic in the ChatInterface component. The main change ensures a smoother transition when a temporary session is replaced with a real session ID, preventing message loss and keeping the UI in sync.

Session transition enhancements:

  • Added a system session change marker (setIsSystemSessionChange(true)) to prevent messages from being cleared during session ID updates.
  • Ensured navigation to the new session by invoking onNavigateToSession, keeping the URL and selectedSession up to date.
  • Get the correct codex session files in windows.

Summary by CodeRabbit

  • Bug Fixes
    • Prevented message loss when sessions are created or finalized—chat history is now preserved when session IDs change and the UI navigates to the correct session context.
    • Improved session matching across project paths so sessions align reliably even with different path formats.
    • More accurate parsing and counting of Codex conversation messages to reflect true user and assistant exchanges.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 31, 2025

Walkthrough

Chat client handling now marks session transitions as system-initiated and navigates to real sessions using actualSessionId when provided. Server Codex completions include an actualSessionId, and project/session parsing/matching logic was improved to normalize paths and adjust payload parsing/counting.

Changes

Cohort / File(s) Change Summary
Chat UI: session transition handling
src/components/ChatInterface.jsx
Detects session-created and codex-complete events as system-initiated transitions, prefers latestMessage.actualSessionId (falling back to pending ID), sets isSystemSessionChange, updates currentSessionId, and calls onNavigateToSession while preserving messages and coexisting with temporary-ID replacement logic.
Codex completion payload
server/openai-codex.js
Codex completion event now includes actualSessionId: thread.id in the emitted payload alongside the existing sessionId.
Project / Codex session parsing & matching
server/projects.js
Normalizes Windows long paths and uses cleaned/relative comparisons when matching session cwd to project paths; parseCodexSessionFile now extracts the last user message from entry.payload.message (not payload.text) and counts assistant messages only when entry.payload?.type === 'message' && payload.role === 'assistant'.

Sequence Diagram

sequenceDiagram
    %% Styling (subtle colors via notes)
    actor Server as Server
    actor User as User/System
    participant Chat as ChatInterface
    participant Nav as NavigationHandler
    participant State as SessionState

    User->>Chat: send message / trigger session-created
    Server->>Chat: emit codex-complete (sessionId, actualSessionId)
    alt actualSessionId present
      Chat->>Chat: set currentSessionId = actualSessionId\nmark isSystemSessionChange
      Chat->>Nav: onNavigateToSession(actualSessionId)
      Nav->>State: update selected session & URL
      Note right of Chat: Messages preserved\n(no history cleared)
    else fallback to pending ID
      Chat->>Chat: replace temporary session id\nset isSystemSessionChange
      Chat->>Nav: onNavigateToSession(pendingId)
      Nav->>State: update selected session & URL
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 A new thread hops into view,
IDs align, the path is true,
Messages kept, no tale undone,
I nibble bugs and race the sun,
Hooray — sessions stitched, well-run! 🥕

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: fixing session navigation when the session ID is updated from a temporary pending ID to the actual Codex session ID.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@blackmammoth
Copy link
Collaborator Author

@viper151 This should work

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/components/ChatInterface.jsx (1)

3516-3550: Block-scope the codex-complete case and fix the console.log variable

The codex-complete case has two issues:

  1. Biome noSwitchDeclarations error: The const declarations at lines 3535–3536 must be wrapped in a block to prevent accidental cross-case access and hoisting bugs.
  2. Console.log bug: Line 3548 logs codexPendingSessionId instead of codexActualSessionId—the value actually being set by setCurrentSessionId().

Wrap the case body in braces, correct the logged variable, and optionally add && codexActualSessionId to the condition for defensive safety:

Proposed fix: block-scope the codex-complete case
-        case 'codex-complete':
-          // Handle Codex session completion
-          const codexCompletedSessionId = latestMessage.sessionId || currentSessionId || sessionStorage.getItem('pendingSessionId');
-
-          if (codexCompletedSessionId === currentSessionId || !currentSessionId) {
-            setIsLoading(false);
-            setCanAbortSession(false);
-            setClaudeStatus(null);
-          }
-
-          if (codexCompletedSessionId) {
-            if (onSessionInactive) {
-              onSessionInactive(codexCompletedSessionId);
-            }
-            if (onSessionNotProcessing) {
-              onSessionNotProcessing(codexCompletedSessionId);
-            }
-          }
-
-          const codexPendingSessionId = sessionStorage.getItem('pendingSessionId');
-          const codexActualSessionId = latestMessage.actualSessionId || codexPendingSessionId;
-          if (codexPendingSessionId && !currentSessionId) {
-            setCurrentSessionId(codexActualSessionId);
-            setIsSystemSessionChange(true);
-            if (onNavigateToSession) {
-              onNavigateToSession(codexActualSessionId);
-            }
-            sessionStorage.removeItem('pendingSessionId');
-            console.log('Codex session complete, ID set to:', codexPendingSessionId);
-          }
-
-          if (selectedProject) {
-            safeLocalStorage.removeItem(`chat_messages_${selectedProject.name}`);
-          }
-          break;
+        case 'codex-complete': {
+          // Handle Codex session completion
+          const codexCompletedSessionId =
+            latestMessage.sessionId ||
+            currentSessionId ||
+            sessionStorage.getItem('pendingSessionId');
+
+          if (codexCompletedSessionId === currentSessionId || !currentSessionId) {
+            setIsLoading(false);
+            setCanAbortSession(false);
+            setClaudeStatus(null);
+          }
+
+          if (codexCompletedSessionId) {
+            if (onSessionInactive) {
+              onSessionInactive(codexCompletedSessionId);
+            }
+            if (onSessionNotProcessing) {
+              onSessionNotProcessing(codexCompletedSessionId);
+            }
+          }
+
+          const codexPendingSessionId = sessionStorage.getItem('pendingSessionId');
+          const codexActualSessionId = latestMessage.actualSessionId || codexPendingSessionId;
+
+          if (codexPendingSessionId && !currentSessionId && codexActualSessionId) {
+            setCurrentSessionId(codexActualSessionId);
+            setIsSystemSessionChange(true);
+            if (onNavigateToSession) {
+              onNavigateToSession(codexActualSessionId);
+            }
+            sessionStorage.removeItem('pendingSessionId');
+            console.log('Codex session complete, ID set to:', codexActualSessionId);
+          }
+
+          if (selectedProject) {
+            safeLocalStorage.removeItem(`chat_messages_${selectedProject.name}`);
+          }
+          break;
+        }

Note: Similar block-scoping should also be applied to other cases with const declarations (e.g., claude-response, codex-response, claude-complete, cursor-result) for consistency and to satisfy the linter across the switch statement.

🧹 Nitpick comments (1)
server/projects.js (1)

1203-1225: Codex session matching and message parsing improvements look good; consider defensively stringifying lastUserMessage

  • The updated getCodexSessions logic that:

    • strips leading \\?\ from both sessionData.cwd and projectPath, and
    • matches on direct equality or path.relative(cleanSessionCwd, cleanProjectPath) === ''
      is a reasonable way to align Codex sessions with projects on Windows and POSIX, including long-path prefixes and minor normalization differences.
  • In parseCodexSessionFile, switching to:

    • entry.payload.message for user_message events, and
    • counting only response_item entries where payload.type === 'message' and payload.role === 'assistant'
      better reflects the current Codex event schema and prevents over-counting non-message items.

One small robustness tweak: lastUserMessage is later used with .length and .substring, so if Codex ever changes shape and entry.payload.message is not a plain string, this will throw. You could defensively coerce to string:

-          if (entry.type === 'event_msg' && entry.payload?.type === 'user_message') {
-            messageCount++;
-            if (entry.payload.message) {
-              lastUserMessage = entry.payload.message;
-            }
-          }
+          if (entry.type === 'event_msg' && entry.payload?.type === 'user_message') {
+            messageCount++;
+            if (entry.payload.message != null) {
+              lastUserMessage = String(entry.payload.message);
+            }
+          }

This keeps the current behavior for string payloads but prevents surprises if the Codex SDK ever returns a non-string message.

Also applies to: 1278-1288

📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ba70ad8 and 9efe433.

📒 Files selected for processing (3)
  • server/openai-codex.js
  • server/projects.js
  • src/components/ChatInterface.jsx
🧰 Additional context used
🧬 Code graph analysis (2)
server/openai-codex.js (1)
src/components/ChatInterface.jsx (1)
  • currentSessionId (1680-1680)
src/components/ChatInterface.jsx (1)
server/openai-codex.js (1)
  • currentSessionId (205-205)
🪛 Biome (2.1.2)
src/components/ChatInterface.jsx

[error] 3536-3537: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)

🔇 Additional comments (2)
server/openai-codex.js (1)

281-285: Adding actualSessionId to Codex completion payload looks correct

Exposing actualSessionId: thread.id alongside sessionId cleanly supports the ChatInterface logic that now prefers the real thread ID but falls back to the pending ID, without changing existing consumers of sessionId. No issues from a backend/API perspective.

src/components/ChatInterface.jsx (1)

2971-2983: Marking session-created transitions as system-initiated is consistent with existing session-change handling

Setting isSystemSessionChange(true) when a new session is created ensures the subsequent selectedSession update won’t clear current chatMessages in loadMessages, matching the way Claude/Cursor system-initiated session switches are already treated. This looks correct and keeps the UX stable during ID replacement.

@viper151 viper151 merged commit 4086fda into main Jan 5, 2026
1 check passed
@viper151 viper151 deleted the fix/navigate-to-correct-session-id-using-codex branch January 7, 2026 08:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants