Skip to content

fix(codex): improve session discovery and diagnostics#328

Open
zzzhy11 wants to merge 1 commit intositeboon:mainfrom
zzzhy11:fix/codex-support-v2
Open

fix(codex): improve session discovery and diagnostics#328
zzzhy11 wants to merge 1 commit intositeboon:mainfrom
zzzhy11:fix/codex-support-v2

Conversation

@zzzhy11
Copy link

@zzzhy11 zzzhy11 commented Jan 22, 2026

Summary

This PR improves Codex support by addressing session attribution, manual triggering reliability, and diagnostics.

Changes

  • Attribute Codex sessions to a project even when sessions are created from subdirectories (path normalization + realpath candidates)
  • Prevent cross-provider session ID reuse (Codex no longer falls back to Cursor session IDs)
  • Add /api/codex/health safeguards (Codex CLI probe timeout + cached session stats)
  • Preserve existing error.code/error.details in Codex error mapping and strengthen JSONL message de-duplication
  • Make node-pty optional and gracefully degrade terminal startup with a bilingual fallback message

Testing

  • node --check on modified server modules
  • npm run build

Notes

  • This PR intentionally does not include any personal plans, local logs, or environment-specific secrets.

Summary by CodeRabbit

  • New Features

    • Added Codex session health monitoring and status checks
    • Enhanced provider-specific session handling for improved session management
  • Bug Fixes

    • Improved error messaging and handling for Codex operations with detailed error codes
    • Added graceful error handling when optional dependencies are unavailable
  • Chores

    • Made node-pty an optional dependency
    • Updated .gitignore for development tools and local configuration
    • Changed default approval policy settings for Codex

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

- Attribute Codex sessions to a project even when created from subdirectories (path normalization + realpath)

- Avoid cross-provider sessionId reuse for Codex

- Add /api/codex/health safeguards (CLI timeout + cached session stats)

- Preserve error codes/details in Codex error mapping and improve message deduplication

- Make node-pty optional and degrade terminal output with a bilingual message when unavailable
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 22, 2026

Walkthrough

This PR enhances Codex integration by making node-pty an optional dependency with graceful fallback, introducing Codex session caching and health checks, refining error handling with structured payloads, and updating approval policy defaults from 'untrusted' to 'never' across the application.

Changes

Cohort / File(s) Summary
Build & Dependencies
.gitignore, package.json
Added local toolchain ignores (.node/, node-v*-win-*.zip, .netlify) and relocated node-pty from required dependencies to optionalDependencies for graceful degradation.
PTY Module Initialization
server/index.js
Replaced static node-pty import with dynamic lazy-loading via getPtyModule; introduces cached promise-based loader and early exit with user-facing error when native bindings are unavailable.
Codex Error Handling
server/openai-codex.js
Added codexErrorToPayload mapper for structured error codes (CODEX_THREAD_NOT_FOUND, CODEX_AUTH_FAILED, CODEX_ERROR); integrated try/catch around resumeThread and main query path; changed default approvalPolicy from 'untrusted' to 'never'.
Codex Session Management
server/projects.js
Introduced Codex session cache (15s TTL) with scanAllCodexSessionsFiles and path encoding utilities; enhanced getCodexSessions with path normalization and candidate resolution; augmented getCodexSessionMessages with deduplication, pagination, and tool/function call parsing; updated getProjects and addProjectManually to populate codexSessions.
Codex Health & Monitoring
server/routes/codex.js
Added /health route with Codex CLI version check via subprocess spawning, Codex session health scan (capped at 5000 files) with TTL caching, and environment flag detection.
Frontend Session & Error Handling
src/components/ChatInterface.jsx
Implemented provider-specific session ID resolution (cursor vs. codex); enriched Codex error display with extracted codexErrorCode, codexErrorDetails, and contextual hints.
Localization Updates
src/i18n/locales/en/settings.json, src/i18n/locales/zh-CN/settings.json
Updated Codex technicalInfo default approvalPolicy from 'untrusted' to 'never' in both English and Chinese locales.

Sequence Diagrams

sequenceDiagram
    participant Client
    participant Server
    participant Cache as Session Cache
    participant FileSystem as File System
    
    Client->>Server: GET /health
    Server->>Cache: Check cached health data
    alt Cache Hit & Valid
        Cache-->>Server: Return cached health
    else Cache Miss or Stale
        Server->>FileSystem: Scan ~/.codex/sessions
        FileSystem-->>Server: Return .jsonl files (up to 5000)
        Server->>Server: Build health snapshot<br/>(timestamps, counts)
        Server->>Cache: Store in cache (TTL)
    end
    
    par Health CLI Check
        Server->>FileSystem: Spawn "codex --version"
        FileSystem-->>Server: CLI status & version
    end
    
    Server->>Server: Gather env flags<br/>(OpenAI vars)
    Server-->>Client: Return {cli, sessions, env}
Loading
sequenceDiagram
    participant Client
    participant Server
    participant SessionCache as Codex Sessions Cache
    participant FileSystem as File System
    
    Client->>Server: getCodexSessionMessages(sessionId, limit, offset)
    
    Server->>SessionCache: Check cache freshness
    alt Cache expired or missing
        Server->>FileSystem: Scan ~/.codex/sessions
        FileSystem-->>Server: Return session .jsonl files
        Server->>SessionCache: Refresh & store
    else Cache valid
        SessionCache-->>Server: Return cached list
    end
    
    Server->>FileSystem: Load sessionId .jsonl file
    FileSystem-->>Server: Return entries<br/>(event_msg, response_item, user_message)
    
    Server->>Server: Parse & deduplicate<br/>messages across entries
    Server->>Server: Apply pagination<br/>(limit, offset)
    Server->>Server: Preserve tokenUsage<br/>metadata
    
    Server-->>Client: Return deduped messages<br/>with pagination
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • #303: Modifies i18n settings and ChatInterface.jsx for Codex error display and session handling consistency.
  • #275: Touches ChatInterface.jsx session ID management and server/projects.js Codex session matching logic.

Suggested reviewers

  • blackmammoth
  • viper151

Poem

🐰 Hops through sessions with cache so bright,
Codex health checks running through the night,
Node-pty gracefully bows when missing,
Structured errors—no more guessing!
Approval set to 'never', policies refined,
A better integration, one line at a time. 🌟

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 47.06% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(codex): improve session discovery and diagnostics' directly aligns with the primary changes across multiple files that enhance Codex session handling, path normalization, error handling, and diagnostic capabilities.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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.

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: 1

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)

3866-3888: Wrap the Codex error case in a block to comply with Biome's noSwitchDeclarations rule.
The const declarations in this case (codexErrorCode, codexErrorDetails, codexErrorHint) are in the switch scope, which can cause TDZ issues if other cases reference them. Wrap the case body in {} to scope these bindings properly. This pattern is already used in adjacent cases like session-aborted and session-status.

🛠️ Suggested fix
-        case 'codex-error':
+        case 'codex-error': {
           // Handle Codex errors
           setIsLoading(false);
           setCanAbortSession(false);
           const codexErrorCode = latestMessage.code;
           const codexErrorDetails = latestMessage.details;
           const codexErrorHint = (() => {
             if (codexErrorCode === 'CODEX_THREAD_NOT_FOUND') {
               return '提示:请新建一个 Codex 会话,或在侧边栏重新选择有效会话后重试。';
             }
             if (codexErrorCode === 'CODEX_AUTH_FAILED') {
               return '提示:请检查 OPENAI_API_KEY / 本机 Codex 登录状态,然后访问 设置 → Codex → Health 查看诊断信息。';
             }
             return null;
           })();
           setChatMessages(prev => [...prev, {
             type: 'error',
             content: [latestMessage.error || 'Codex 出错', codexErrorHint, codexErrorDetails ? `详情:${codexErrorDetails}` : null]
               .filter(Boolean)
               .join('\n'),
             timestamp: new Date()
           }]);
-          break;
+          break;
+        }
🤖 Fix all issues with AI agents
In `@package.json`:
- Around line 97-99: The error message that mentions "Node.js 20" when handling
the optional dependency "node-pty" (in package.json optionalDependencies entry
for "node-pty": "^1.1.0-beta34") is incorrect; change the message to state the
actual minimum Node.js requirement for node-pty (Node.js 16+) or add a clear
comment documenting why the project enforces Node.js 20+ if that's intentional;
update the string where the runtime check or fallback logs the Node.js
requirement so it references "Node.js 16+" (or include the rationale for
requiring 20+) and ensure any user-facing docs/comments reflect the same
requirement.
🧹 Nitpick comments (4)
server/index.js (2)

1063-1073: Close the socket after terminal init fails.

After sending the error message, the socket stays open and will still accept inputs that go nowhere. Closing it makes the failure explicit and avoids lingering sessions.

♻️ Proposed tweak
                     const ptyModule = await getPtyModule();
                     if (!ptyModule) {
                         ws.send(JSON.stringify({
                             type: 'output',
                             data: '[ERROR] node-pty is not available, cannot start an interactive terminal. Please use Node.js 20 and reinstall dependencies with C++ Build Tools available, or skip the terminal feature.\r\n[错误] node-pty 不可用,无法启动交互终端。请使用 Node.js 20 并在具备 C++ Build Tools 的环境重新安装依赖,或跳过终端功能。'
                         }));
+                        ws.close(1011, 'Terminal unavailable');
                         return;
                     }

79-87: Add error logging and retry capability to node-pty import handler.

The current silent catch prevents visibility into why node-pty might fail to load. Logging the error and resetting the cached promise enables both better diagnostics and retry capability if the optional dependency is installed after startup.

♻️ Proposed improvement
 let ptyModulePromise = null;
 async function getPtyModule() {
     if (!ptyModulePromise) {
         ptyModulePromise = import('node-pty')
             .then((mod) => mod?.default || mod)
-            .catch(() => null);
+            .catch((err) => {
+                console.warn('[WARN] node-pty load failed:', err);
+                ptyModulePromise = null;
+                return null;
+            });
     }
     return ptyModulePromise;
 }
server/routes/codex.js (1)

17-76: Avoid exposing absolute session paths in the health response.

recent currently returns full filesystem paths. Consider returning paths relative to the sessions dir (or just filenames) to avoid leaking user-home paths.

♻️ Proposed tweak
   sessions.recent = stats
     .filter(Boolean)
     .sort((a, b) => b.mtimeMs - a.mtimeMs)
     .slice(0, 5)
-    .map((s) => ({ file: s.file, mtime: new Date(s.mtimeMs).toISOString() }));
+    .map((s) => ({
+      file: path.relative(codexSessionsDir, s.file),
+      mtime: new Date(s.mtimeMs).toISOString()
+    }));
server/projects.js (1)

211-226: Consider logging errors in directory traversal.

The empty catch {} block at line 224 silently swallows all errors during recursive directory scanning. While ignoring ENOENT is reasonable, permission errors or other issues might be worth logging for debugging purposes.

Suggested improvement
       } catch (error) {
+        if (error.code !== 'ENOENT') {
+          console.warn(`Could not read directory ${dir}:`, error.message);
+        }
       }

Comment on lines +97 to +99
"optionalDependencies": {
"node-pty": "^1.1.0-beta34"
},
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

node-pty 1.1.0-beta34 Node.js version compatibility requirements

💡 Result:

node-pty v1.1.0-beta34 requires Node.js 16 (or newer) — or Electron 19 when used inside Electron. [1][2]

Sources:
[1] microsoft/node-pty README (requirements).
[2] node-pty v1.1.0-beta34 release.


🏁 Script executed:

cat -n package.json | grep -A 5 -B 5 '"engines"'

Repository: siteboon/claudecodeui

Length of output: 47


🏁 Script executed:

wc -l package.json

Repository: siteboon/claudecodeui

Length of output: 81


🏁 Script executed:

cat -n package.json

Repository: siteboon/claudecodeui

Length of output: 4073


🏁 Script executed:

rg "node-pty" --type js --type ts -B 2 -A 2

Repository: siteboon/claudecodeui

Length of output: 873


🏁 Script executed:

rg "Node.js 20" -B 5 -A 5

Repository: siteboon/claudecodeui

Length of output: 892


Clarify Node.js version requirement in error message.

The optional dependency handling is correctly implemented with graceful fallback. However, the error message references Node.js 20 as a requirement, whereas node-pty 1.1.0-beta34 only requires Node.js 16+. Either update the error message to reflect the actual minimum requirement, or document why Node.js 20+ is being enforced.

🤖 Prompt for AI Agents
In `@package.json` around lines 97 - 99, The error message that mentions "Node.js
20" when handling the optional dependency "node-pty" (in package.json
optionalDependencies entry for "node-pty": "^1.1.0-beta34") is incorrect; change
the message to state the actual minimum Node.js requirement for node-pty
(Node.js 16+) or add a clear comment documenting why the project enforces
Node.js 20+ if that's intentional; update the string where the runtime check or
fallback logs the Node.js requirement so it references "Node.js 16+" (or include
the rationale for requiring 20+) and ensure any user-facing docs/comments
reflect the same requirement.

@blackmammoth
Copy link
Collaborator

@zzzhy11 What issue did you face that this PR solves? Can you also share your reproduction steps for the error?

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