Conversation
Add prefix mismatch diagnostics
|
Warning Rate limit exceeded@riatzukiza has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 10 minutes and 25 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (2)
WalkthroughAdds a request-metrics subsystem and dashboard, integrates metrics into request flow, implements an auto-update checker, centralizes session utilities and session-manager changes (applyRequest now returns body+context), adds prompt-cache key utilities, recognizes gpt-5.2 model behavior, and updates tests/mocks. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant Updater as AutoUpdate (runAutoUpdateCheck)
participant Cache as Local Cache File
participant Local as package.json (local version)
participant Registry as npm Registry
participant UI as OpencodeClient UI (toast)
participant Cleaner as Cache Cleanup
Updater->>Cache: read persisted update state (lastChecked, lastNotifiedVersion)
alt recently checked (<=15m)
Cache-->>Updater: state (throttle) — stop
else
Updater->>Local: read local package version
Updater->>Registry: fetch metadata for `@openhax/codex`
Registry-->>Updater: registry metadata (latest)
Updater->>Updater: compare versions
alt newer version && not recently notified
Updater->>UI: attempt toast notification
UI-->>Updater: (ok/fail)
Updater->>Cache: update lastNotifiedVersion & timestamp
end
Updater->>Cleaner: cleanup old Codex install artifacts
Cleaner-->>Updater: results / errors
Updater->>Cache: write updated state (lastChecked, lastError?)
Cache-->>Updater: persist OK
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Possibly related issues
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (2 warnings, 1 inconclusive)
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. Comment |
|
/oc
/home/runner/work/codex/codex/lib/prompts/codex.ts /home/runner/work/codex/codex/lib/request/codex-fetcher.ts /home/runner/work/codex/codex/lib/server/dashboard.ts /home/runner/work/codex/codex/lib/session/session-manager.ts ✖ 7 problems (1 error, 6 warnings) ELIFECYCLE Command failed with exit code 1. |
…tion or class' Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
|
All ESLint issues have been successfully resolved:
The codebase now passes all ESLint checks with no errors or warnings. |
There was a problem hiding this comment.
Actionable comments posted: 7
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
⛔ Files ignored due to path filters (3)
README.mdis excluded by none and included by noneindex.tsis excluded by none and included by nonespec/issue-67-auto-update.mdis excluded by none and included by none
📒 Files selected for processing (7)
lib/metrics/request-metrics.ts(1 hunks)lib/request/codex-fetcher.ts(2 hunks)lib/server/dashboard.ts(1 hunks)lib/update/auto-update.ts(1 hunks)lib/utils/cache-config.ts(1 hunks)test/codex-fetcher.test.ts(1 hunks)test/request-metrics.test.ts(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
lib/server/dashboard.ts (3)
lib/cache/cache-metrics.ts (1)
getCachePerformanceReport(234-262)lib/metrics/request-metrics.ts (1)
getRequestMetricsSnapshot(180-182)lib/logger.ts (2)
logInfo(156-158)logWarn(160-162)
lib/request/codex-fetcher.ts (1)
lib/metrics/request-metrics.ts (1)
recordRequestMetrics(176-178)
test/request-metrics.test.ts (1)
lib/metrics/request-metrics.ts (3)
resetRequestMetrics(184-186)recordRequestMetrics(176-178)getRequestMetricsSnapshot(180-182)
🪛 GitHub Actions: CI
lib/request/codex-fetcher.ts
[warning] 44-44: Async function 'codexFetch' has a complexity of 34. Maximum allowed is 20.
[error] 44-44: Refactor this function to reduce its Cognitive Complexity from 33 to the 30 allowed sonarjs/cognitive-complexity.
🪛 GitHub Check: Lint & Typecheck
lib/server/dashboard.ts
[warning] 20-20:
'escapeHtml' is defined but never used. Allowed unused vars must match /^_/u
[warning] 15-15:
Assignment to property of function parameter 'res'
[warning] 9-9:
Assignment to property of function parameter 'res'
🔇 Additional comments (9)
lib/utils/cache-config.ts (1)
40-41: LGTM!The new
AUTO_UPDATE_STATEentry follows the established naming convention and integrates cleanly with the existing cache file structure.lib/update/auto-update.ts (1)
143-194: LGTM on the update check flow.The throttling, version comparison, notification deduplication (24hr cooldown), and cleanup sequence are well-structured. State persistence at each step ensures recovery from partial failures.
lib/server/dashboard.ts (3)
20-37: Unused function needed for security.The static analysis correctly identifies
escapeHtmlas unused. However, this function is essential for preventing XSS in the dashboard HTML generation (see comment on line 85).
8-18: Static analysis false positive on parameter mutations.The linter warnings about assigning to
res.statusCodeand callingres.setHeader()are false positives. MutatingServerResponseis the standard Node.js HTTP API pattern. These can be safely ignored or suppressed with// eslint-disable-next-lineif preferred.
144-168: LGTM: Robust server initialization.The server implementation correctly:
- Binds to localhost only (security)
- Uses dynamic port allocation (flexibility)
- Prevents multiple starts (idempotency)
- Skips in test environment (test isolation)
- Logs startup and handles errors gracefully
lib/metrics/request-metrics.ts (4)
1-50: LGTM: Well-structured type definitions.The three types provide a clean separation of concerns: input for recording, summary for individual requests, and snapshot for aggregated metrics. Optional fields are appropriately marked.
69-131: LGTM: Correct metric recording logic.The recording logic correctly:
- Increments all relevant counters
- Uses nullish coalescing for safe record updates
- Caps recent requests at 50 entries
- Creates complete request summaries with timestamps
133-155: LGTM: Safe snapshot generation.The snapshot uses spread operators to create shallow copies of records and the recent requests array, which is sufficient since the data structures contain primitives and immutable summaries.
157-186: LGTM: Clean public API with singleton pattern.The reset functionality comprehensively clears all tracked state, and the public API provides a clean interface to the singleton collector. This pattern is appropriate for application-wide metrics.
Co-authored-by: riatzukiza <riatzukiza@users.noreply.github.com>
There was a problem hiding this comment.
Actionable comments posted: 11
♻️ Duplicate comments (3)
lib/server/dashboard.ts (1)
68-68: Critical: XSS vulnerability in innerHTML concatenation.Line 68 directly concatenates user-controlled values (
ts,model,url,cache,tools,reasoning) intoinnerHTMLwithout escaping. If a request URL or model name contains malicious HTML/JavaScript, it will execute in the dashboard context.Implement HTML escaping for all interpolated values:
+ function escapeHtml(text) { + const div = document.createElement('div'); + div.textContent = text; + return div.innerHTML; + } for (const item of (recent.recentRequests || [])) { const tr = document.createElement('tr'); const ts = new Date(item.timestamp).toLocaleTimeString(); const model = item.model || ''; const url = item.url ? item.url : ''; const cache = item.promptCacheKey ? 'yes' : 'no'; const tools = item.toolCount + (item.toolChoice ? ' (' + item.toolChoice + ')' : ''); const reasoning = (item.reasoningEffort || item.reasoningSummary || item.textVerbosity) ? 'yes' : 'no'; - tr.innerHTML = '<td>' + ts + '</td>' + '<td>' + model + '</td>' + '<td><code>' + url + '</code></td>' + '<td>' + cache + '</td>' + '<td>' + tools + '</td>' + '<td>' + reasoning + '</td>'; + tr.innerHTML = '<td>' + escapeHtml(ts) + '</td>' + '<td>' + escapeHtml(model) + '</td>' + '<td><code>' + escapeHtml(url) + '</code></td>' + '<td>' + escapeHtml(cache) + '</td>' + '<td>' + escapeHtml(tools) + '</td>' + '<td>' + escapeHtml(reasoning) + '</td>'; tbody.appendChild(tr); }Alternatively, use safer DOM manipulation:
for (const item of (recent.recentRequests || [])) { const tr = document.createElement('tr'); - const ts = new Date(item.timestamp).toLocaleTimeString(); - const model = item.model || ''; - const url = item.url ? item.url : ''; - const cache = item.promptCacheKey ? 'yes' : 'no'; - const tools = item.toolCount + (item.toolChoice ? ' (' + item.toolChoice + ')' : ''); - const reasoning = (item.reasoningEffort || item.reasoningSummary || item.textVerbosity) ? 'yes' : 'no'; - tr.innerHTML = '<td>' + ts + '</td>' + '<td>' + model + '</td>' + '<td><code>' + url + '</code></td>' + '<td>' + cache + '</td>' + '<td>' + tools + '</td>' + '<td>' + reasoning + '</td>'; + ['timestamp', 'model', 'url', 'cache', 'tools', 'reasoning'].forEach(field => { + const td = document.createElement('td'); + let value; + if (field === 'timestamp') value = new Date(item.timestamp).toLocaleTimeString(); + else if (field === 'model') value = item.model || ''; + else if (field === 'url') { + const code = document.createElement('code'); + code.textContent = item.url || ''; + td.appendChild(code); + tr.appendChild(td); + return; + } + else if (field === 'cache') value = item.promptCacheKey ? 'yes' : 'no'; + else if (field === 'tools') value = item.toolCount + (item.toolChoice ? ' (' + item.toolChoice + ')' : ''); + else if (field === 'reasoning') value = (item.reasoningEffort || item.reasoningSummary || item.textVerbosity) ? 'yes' : 'no'; + td.textContent = value; + tr.appendChild(td); + }); - tbody.appendChild(tr); + tbody.appendChild(tr); }lib/session/session-manager.ts (2)
202-202: Critical: Type error -promptCacheKeynot inSessionContextinterface.Same type mismatch as line 174. Ensure
SessionContextincludespromptCacheKey.
215-215: Critical: Type error -promptCacheKeynot inSessionContextinterface.Same type mismatch as lines 174 and 202. Ensure
SessionContextincludespromptCacheKey.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.jsonand included by none
📒 Files selected for processing (5)
lib/prompts/codex.ts(2 hunks)lib/request/codex-fetcher.ts(3 hunks)lib/server/dashboard.ts(1 hunks)lib/session/session-manager.ts(6 hunks)lib/session/session-utils.ts(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (5)
lib/server/dashboard.ts (3)
lib/cache/cache-metrics.ts (1)
getCachePerformanceReport(234-262)lib/metrics/request-metrics.ts (1)
getRequestMetricsSnapshot(180-182)lib/logger.ts (2)
logInfo(156-158)logWarn(160-162)
lib/prompts/codex.ts (1)
lib/logger.ts (1)
logWarn(160-162)
lib/request/codex-fetcher.ts (3)
lib/types.ts (1)
Auth(249-249)lib/request/fetch-helpers.ts (2)
shouldRefreshToken(27-29)refreshAndUpdateToken(37-77)lib/metrics/request-metrics.ts (1)
recordRequestMetrics(176-178)
lib/session/session-utils.ts (2)
lib/types.ts (2)
RequestBody(159-181)SessionState(195-204)lib/request/prompt-cache.ts (1)
PROMPT_CACHE_FORK_KEYS(70-77)
lib/session/session-manager.ts (2)
lib/types.ts (2)
InputItem(148-154)CodexResponsePayload(220-228)lib/session/session-utils.ts (4)
isSystemLike(47-53)buildSessionKey(116-121)createSessionState(133-152)longestSharedPrefixLength(21-37)
🪛 GitHub Actions: CI
lib/request/codex-fetcher.ts
[error] 77-77: ReferenceError: url is not defined in extractRequestMetrics. Ensure 'url' is defined before returning request metrics.
[error] 1-1: transformRequestForCodex returned undefined during Codex fetch flow end-to-end.
🪛 GitHub Check: Lint & Typecheck
lib/request/codex-fetcher.ts
[failure] 77-77:
Cannot find name 'url'. Did you mean 'URL'?
lib/session/session-manager.ts
[failure] 230-230:
Property 'cached_tokens' does not exist on type '{}'.
[failure] 215-215:
Object literal may only specify known properties, and 'promptCacheKey' does not exist in type 'SessionContext'.
[failure] 202-202:
Object literal may only specify known properties, and 'promptCacheKey' does not exist in type 'SessionContext'.
[failure] 185-185:
Argument of type '{}' is not assignable to parameter of type 'InputItem[]'.
[failure] 174-174:
Object literal may only specify known properties, and 'promptCacheKey' does not exist in type 'SessionContext'.
🪛 GitHub Check: Test (20.x)
lib/request/codex-fetcher.ts
[failure] 77-77: test/codex-fetcher.test.ts > createCodexFetcher > uses empty tokens when auth type is not oauth
ReferenceError: url is not defined
❯ extractRequestMetrics lib/request/codex-fetcher.ts:77:4
❯ codexFetch lib/request/codex-fetcher.ts:117:20
❯ test/codex-fetcher.test.ts:294:3
[failure] 77-77: test/codex-fetcher.test.ts > createCodexFetcher > records responses only after successful handling
ReferenceError: url is not defined
❯ extractRequestMetrics lib/request/codex-fetcher.ts:77:4
❯ codexFetch lib/request/codex-fetcher.ts:117:20
❯ test/codex-fetcher.test.ts:278:3
[failure] 77-77: test/codex-fetcher.test.ts > createCodexFetcher > logs response metadata with the response stage
ReferenceError: url is not defined
❯ extractRequestMetrics lib/request/codex-fetcher.ts:77:4
❯ codexFetch lib/request/codex-fetcher.ts:117:20
❯ test/codex-fetcher.test.ts:242:3
[failure] 77-77: test/codex-fetcher.test.ts > createCodexFetcher > delegates non-ok responses to the error handler
ReferenceError: url is not defined
❯ extractRequestMetrics lib/request/codex-fetcher.ts:77:4
❯ codexFetch lib/request/codex-fetcher.ts:117:20
❯ test/codex-fetcher.test.ts:230:20
[failure] 77-77: test/codex-fetcher.test.ts > createCodexFetcher > passes hasTools flag to the success handler
ReferenceError: url is not defined
❯ extractRequestMetrics lib/request/codex-fetcher.ts:77:4
❯ codexFetch lib/request/codex-fetcher.ts:117:20
❯ test/codex-fetcher.test.ts:218:3
[failure] 77-77: test/codex-fetcher.test.ts > createCodexFetcher > uses refreshed auth when refresh succeeds
ReferenceError: url is not defined
❯ extractRequestMetrics lib/request/codex-fetcher.ts:77:4
❯ codexFetch lib/request/codex-fetcher.ts:117:20
❯ test/codex-fetcher.test.ts:186:3
[failure] 77-77: test/codex-fetcher.test.ts > createCodexFetcher > continues processing when token refresh succeeds
ReferenceError: url is not defined
❯ extractRequestMetrics lib/request/codex-fetcher.ts:77:4
❯ codexFetch lib/request/codex-fetcher.ts:117:20
❯ test/codex-fetcher.test.ts:165:3
[failure] 77-77: test/codex-fetcher.test.ts > createCodexFetcher > performs the Codex fetch flow end-to-end
ReferenceError: url is not defined
❯ extractRequestMetrics lib/request/codex-fetcher.ts:77:4
❯ codexFetch lib/request/codex-fetcher.ts:117:20
❯ test/codex-fetcher.test.ts:106:20
🪛 GitHub Check: Test (22.x)
lib/request/codex-fetcher.ts
[failure] 77-77: test/codex-fetcher.test.ts > createCodexFetcher > uses empty tokens when auth type is not oauth
ReferenceError: url is not defined
❯ extractRequestMetrics lib/request/codex-fetcher.ts:77:4
❯ codexFetch lib/request/codex-fetcher.ts:117:20
❯ test/codex-fetcher.test.ts:294:3
[failure] 77-77: test/codex-fetcher.test.ts > createCodexFetcher > records responses only after successful handling
ReferenceError: url is not defined
❯ extractRequestMetrics lib/request/codex-fetcher.ts:77:4
❯ codexFetch lib/request/codex-fetcher.ts:117:20
❯ test/codex-fetcher.test.ts:278:3
[failure] 77-77: test/codex-fetcher.test.ts > createCodexFetcher > logs response metadata with the response stage
ReferenceError: url is not defined
❯ extractRequestMetrics lib/request/codex-fetcher.ts:77:4
❯ codexFetch lib/request/codex-fetcher.ts:117:20
❯ test/codex-fetcher.test.ts:242:3
[failure] 77-77: test/codex-fetcher.test.ts > createCodexFetcher > delegates non-ok responses to the error handler
ReferenceError: url is not defined
❯ extractRequestMetrics lib/request/codex-fetcher.ts:77:4
❯ codexFetch lib/request/codex-fetcher.ts:117:20
❯ test/codex-fetcher.test.ts:230:20
[failure] 77-77: test/codex-fetcher.test.ts > createCodexFetcher > passes hasTools flag to the success handler
ReferenceError: url is not defined
❯ extractRequestMetrics lib/request/codex-fetcher.ts:77:4
❯ codexFetch lib/request/codex-fetcher.ts:117:20
❯ test/codex-fetcher.test.ts:218:3
[failure] 77-77: test/codex-fetcher.test.ts > createCodexFetcher > uses refreshed auth when refresh succeeds
ReferenceError: url is not defined
❯ extractRequestMetrics lib/request/codex-fetcher.ts:77:4
❯ codexFetch lib/request/codex-fetcher.ts:117:20
❯ test/codex-fetcher.test.ts:186:3
[failure] 77-77: test/codex-fetcher.test.ts > createCodexFetcher > continues processing when token refresh succeeds
ReferenceError: url is not defined
❯ extractRequestMetrics lib/request/codex-fetcher.ts:77:4
❯ codexFetch lib/request/codex-fetcher.ts:117:20
❯ test/codex-fetcher.test.ts:165:3
[failure] 77-77: test/codex-fetcher.test.ts > createCodexFetcher > performs the Codex fetch flow end-to-end
ReferenceError: url is not defined
❯ extractRequestMetrics lib/request/codex-fetcher.ts:77:4
❯ codexFetch lib/request/codex-fetcher.ts:117:20
❯ test/codex-fetcher.test.ts:106:20
🔇 Additional comments (24)
lib/request/codex-fetcher.ts (1)
44-55: Auth helper logic looks good, but double‑check ordering vs existing testsThe new
ensureValidAuthhelper centralizes refresh logic cleanly, and the pattern:
const { auth: currentAuth, response: authErrorResponse } = await ensureValidAuth();- early‑return on
authErrorResponseis sound and avoids using stale auth after a failed refresh.
One behavioral change is that auth is now resolved (and possibly refreshed) before
transformRequestForCodexand command handling. Given the test failure mentioningtransformRequestForCodex returned undefined, it’s worth confirming test expectations around:
- when
transformRequestForCodexis invoked, and- how mocks for it are configured in the “Codex fetch flow end‑to‑end” test.
Please review the relevant tests (especially the end‑to‑end Codex fetch test) to ensure their mocks and expectations still match this new call order, and adjust either the tests or the ordering if necessary.
Also applies to: 91-95
lib/prompts/codex.ts (4)
219-231: LGTM!The fallback handling is appropriate, logging the failure and delegating to the cache-or-bundled fallback path.
233-248: LGTM!The cache freshness check is correctly implemented, returning the cached content when valid or null to trigger a refetch.
281-284: LGTM!The refactored cache check correctly delegates to
checkFreshCacheand handles the result appropriately.
291-298: LGTM!The refactored error handling correctly delegates to
handleLatestTagFailureand returns the fallback result.lib/server/dashboard.ts (3)
83-122: LGTM!The route handlers are correctly implemented with appropriate responses for each endpoint.
127-151: LGTM!The server initialization is correctly guarded, bound to localhost, and includes appropriate error handling.
153-155: LGTM!The port getter is correctly implemented.
lib/session/session-utils.ts (8)
13-19: LGTM!The equality check using JSON stringify is appropriate for deep comparison, and the error handling is safe.
21-37: LGTM!The prefix length calculation is correctly implemented with proper edge case handling.
39-45: LGTM!The cache key sanitization correctly handles empty strings with a UUID fallback.
47-53: LGTM!The system-like role detection is correctly implemented with appropriate guards.
55-60: LGTM!The tool message detection correctly handles multiple role and type indicators.
62-89: LGTM!The conversation ID extraction checks comprehensive key variants and handles both metadata and body locations.
91-114: LGTM!The fork identifier extraction correctly normalizes values and checks both metadata and body locations.
116-121: LGTM!The session key construction is straightforward and uses a distinctive separator.
lib/session/session-manager.ts (8)
35-43: LGTM!The role summarization is correctly implemented.
45-57: LGTM!The suffix reuse detection correctly uses the imported
itemsEqualutility.
66-121: LGTM!The prefix change analysis correctly uses the imported
isSystemLikeutility and properly categorizes different change scenarios.
220-239: Approve the method structure, but see critical issue at line 230.The method signature and overall logic are correct, except for the property access error at line 230 (already flagged above).
241-258: LGTM!The metrics snapshot generation is correctly implemented.
260-275: LGTM!The session lookup correctly searches for both direct matches and prefix-forked sessions.
285-313: LGTM!The session pruning logic correctly handles both idle timeout and capacity limits.
315-321: LGTM!The session reset correctly uses the imported
createSessionStateutility.
- spec/config-env-review.md
- ib/request/model-config.ts - spec/gpt-52-support.md
- test/config.test.ts - test/request-transformer.test.ts
- lib/request/request-transformer.ts - test/config.test.ts - test/request-transformer.test.ts
- AGENTS.md - docs/development/CONFIG_FIELDS.md - docs/reasoning-effort-levels-update.md
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
lib/request/model-config.ts (1)
10-45: Fix model-normalization precedence: gpt-5.2 currently “wins” over generic codex matching.With the current ordering, inputs like
"gpt-5.2-codex"(or any string containing bothgpt-5-2andcodex) will return"gpt-5.2"(Line 33-35) before the generic codex checks (Line 39-41). If codex identification should take precedence (as it does elsewhere in this function), move thehasGpt52branch below the generic codex blocks.if (hasGpt51) { return "gpt-5.1"; } - if (hasGpt52) { - return "gpt-5.2"; - } if (contains("gpt-5-codex-mini") || contains("codex-mini-latest")) { return "gpt-5.1-codex-mini"; } if (contains("gpt-5-codex") || (contains("codex") && !contains("mini"))) { return "gpt-5-codex"; } + if (hasGpt52) { + return "gpt-5.2"; + } if (contains("gpt-5")) { return "gpt-5"; }lib/request/request-transformer.ts (1)
67-91: Blocker: guardsessionContextbefore callingaddCodexBridgeMessage(current CI failure).CI indicates
bridgeInjectedis read fromundefined, and the only relevant touchpoint here is passingsessionContextintoaddCodexBridgeMessage(Line 89). Add a defensive guard so callers without a populated state don’t crash.- workingInput = addCodexBridgeMessage(workingInput, hasNormalizedTools, sessionContext); + const bridgeContext = + sessionContext?.state && sessionContext.enabled ? sessionContext : undefined; + workingInput = addCodexBridgeMessage(workingInput, hasNormalizedTools, bridgeContext);
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
⛔ Files ignored due to path filters (9)
AGENTS.mdis excluded by none and included by noneCHANGELOG.mdis excluded by none and included by noneREADME.mdis excluded by none and included by noneconfig/full-opencode.jsonis excluded by none and included by nonedocs/development/CONFIG_FIELDS.mdis excluded by none and included by nonedocs/reasoning-effort-levels-update.mdis excluded by none and included by nonescripts/test-all-models.shis excluded by none and included by nonespec/config-env-review.mdis excluded by none and included by nonespec/gpt-52-support.mdis excluded by none and included by none
📒 Files selected for processing (4)
lib/request/model-config.ts(8 hunks)lib/request/request-transformer.ts(1 hunks)test/config.test.ts(1 hunks)test/request-transformer.test.ts(6 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
test/config.test.ts (1)
lib/request/request-transformer.ts (1)
getReasoningConfig(23-23)
🪛 GitHub Actions: CI
test/request-transformer.test.ts
[error] 89-89: Cannot read properties of undefined (reading 'bridgeInjected') in transformInputForCodex.
🔇 Additional comments (2)
lib/request/model-config.ts (1)
59-172: gpt-5.2 effort semantics are consistent and well-contained.Plumbing
isGpt52through defaults, xhigh gating, and normalization (none/minimal → low) looks coherent and matches the added tests.test/request-transformer.test.ts (1)
99-104: gpt-5.2 test coverage looks solid and matches the new behavior.Normalization variants, effort defaults/clamping, xhigh persistence for gpt-5.2, and default verbosity = low are all covered.
Also applies to: 174-190, 1184-1243
- lib/request/prompt-cache.ts - lib/session/session-utils.ts - lib/utils/prompt-cache-key.ts
- lib/prompts/codex.ts - lib/session/session-manager.ts - lib/update/auto-update.ts
- lib/server/dashboard.ts - lib/update/auto-update.ts
- lib/server/dashboard.ts - lib/update/auto-update.ts
- ib/request/codex-fetcher.ts - lib/update/auto-update.ts
- lib/prompts/codex.ts
- lib/session/session-manager.ts
- lib/session/session-manager.ts
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
lib/request/codex-fetcher.ts (1)
97-159: CI reports cognitive complexity still exceeds limit (33 vs 30 allowed).Per the PR objectives, ESLint reports this function's cognitive complexity at 33 (limit: 30). The helper extractions help but don't fully resolve the blocker. Consider extracting additional logic—for example, the session/command handling block (lines 115-120) or the response handling (lines 146-158)—into separate helpers.
One option to reduce complexity further:
+async function handleFetchResponse( + response: Response, + hasTools: boolean, + sessionManager: SessionManager, + sessionContext: unknown, +): Promise<Response> { + logRequest(LOG_STAGES.RESPONSE, { + status: response.status, + ok: response.ok, + statusText: response.statusText, + headers: Object.fromEntries(response.headers.entries()), + }); + + if (!response.ok) { + return await handleErrorResponse(response); + } + + const handledResponse = await handleSuccessResponse(response, hasTools); + await recordSessionResponseFromHandledResponse({ + sessionManager, + sessionContext, + handledResponse, + }); + return handledResponse; +}lib/session/session-manager.ts (1)
1-432: File size approaching maintainability limits.ESLint reports this file has 517 lines (exceeding the 500-line limit). While the current implementation is functional, consider extracting related functionality into separate modules in future refactors:
- Input normalization/comparison logic →
session-input-analyzer.ts- Session metrics/pruning →
session-lifecycle.ts- Content filtering →
session-content-filter.tsThis would improve testability and make the codebase easier to navigate.
♻️ Duplicate comments (1)
lib/update/auto-update.ts (1)
9-10:createRequireapproach may still fail in production builds.The past review flagged that path resolution for
package.jsoncan fail when the compiled output is in a different directory structure. WhilecreateRequire(import.meta.url)is more robust than__dirname, it still resolves../../package.jsonrelative to the compiled.jsfile location. If the build output places this file indist/update/, the path would resolve todist/package.jsonwhich likely doesn't exist.The
PACKAGE_VERSIONfallback tonull(line 15) means version detection silently fails—parseLocalVersionwill returnnulland auto-update checks will abort early (lines 156-159).Consider embedding the version at build time or verifying the path resolution works in your actual build output:
#!/bin/bash # Check where package.json ends up relative to the compiled auto-update.js fd -t f "auto-update.js" dist fd -t f "package.json"
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (9)
lib/prompts/codex.ts(2 hunks)lib/request/codex-fetcher.ts(3 hunks)lib/request/prompt-cache.ts(3 hunks)lib/server/dashboard.ts(1 hunks)lib/session/session-manager.ts(8 hunks)lib/session/session-utils.ts(1 hunks)lib/update/auto-update.ts(1 hunks)lib/utils/prompt-cache-key.ts(1 hunks)test/request-metrics.test.ts(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (7)
lib/server/dashboard.ts (3)
lib/cache/cache-metrics.ts (1)
getCachePerformanceReport(234-262)lib/metrics/request-metrics.ts (1)
getRequestMetricsSnapshot(180-182)lib/logger.ts (2)
logInfo(156-158)logWarn(160-162)
lib/prompts/codex.ts (1)
lib/logger.ts (1)
logWarn(160-162)
lib/request/codex-fetcher.ts (3)
lib/types.ts (1)
Auth(249-249)lib/request/fetch-helpers.ts (2)
shouldRefreshToken(27-29)refreshAndUpdateToken(37-77)lib/metrics/request-metrics.ts (1)
recordRequestMetrics(176-178)
lib/session/session-utils.ts (3)
lib/types.ts (2)
RequestBody(159-181)SessionState(195-204)lib/request/prompt-cache.ts (1)
PROMPT_CACHE_FORK_KEYS(71-78)lib/utils/prompt-cache-key.ts (1)
formatPromptCacheKey(30-53)
lib/update/auto-update.ts (3)
lib/utils/file-system-utils.ts (3)
getOpenCodePath(22-24)safeReadFile(56-62)safeWriteFile(42-48)lib/utils/cache-config.ts (1)
CACHE_FILES(31-42)lib/logger.ts (2)
logWarn(160-162)logInfo(156-158)
test/request-metrics.test.ts (1)
lib/metrics/request-metrics.ts (3)
resetRequestMetrics(184-186)recordRequestMetrics(176-178)getRequestMetricsSnapshot(180-182)
lib/request/prompt-cache.ts (1)
lib/utils/prompt-cache-key.ts (1)
formatPromptCacheKey(30-53)
🪛 GitHub Check: Lint & Typecheck
lib/server/dashboard.ts
[warning] 15-15:
Assignment to property of function parameter 'res'
[warning] 9-9:
Assignment to property of function parameter 'res'
lib/session/session-manager.ts
[warning] 255-255:
Assignment to property of function parameter 'context'
[warning] 254-254:
Assignment to property of function parameter 'context'
[warning] 251-251:
Assignment to property of function parameter 'body'
[warning] 250-250:
Assignment to property of function parameter 'body'
🔇 Additional comments (22)
lib/prompts/codex.ts (1)
218-229: Helper extraction addresses complexity.The new
handleLatestTagFailureandcheckFreshCachehelpers consolidate fallback logic and improve readability. The flow ingetCodexInstructionsis now cleaner.Also applies to: 279-289
lib/request/codex-fetcher.ts (2)
44-54: Clean auth validation extraction.
ensureValidAuthproperly encapsulates the token refresh logic with a discriminated return type. The early return pattern at lines 99-101 is clear.
56-95:extractRequestMetricsnow receives URL as parameter.This addresses the previous blocker where
urlwas out of scope. The URL normalization with try/catch fallback at lines 75-80 is a sensible defensive measure.test/request-metrics.test.ts (1)
8-98: Solid test coverage for request metrics.The test suite covers:
- Basic counts and field tracking
- Capacity limits (50 entries)
- Missing optional fields handling
- Per-model distributions
The
beforeEachreset ensures proper test isolation.lib/utils/prompt-cache-key.ts (2)
14-28: Default sanitizers generate UUIDs for empty inputs.This ensures cache keys are never empty. Note that
defaultSanitizeForkadds afork-prefix (line 25) while the caller inprompt-cache.tsuses a customsanitizeMetadataForkthat returns just"fork"for empty input. This inconsistency is intentional sinceprompt-cache.tsprovides custom sanitizers, but worth documenting.
30-53: LGTM!The
formatPromptCacheKeyfunction handles prefix deduplication correctly (lines 41-45) and the optional fork segment is cleanly appended.lib/request/prompt-cache.ts (2)
45-58: Renamed sanitizers maintain expected behavior.The custom
sanitizeMetadataBaseadds thecache_prefix internally (line 51), so passingprefix: ""toformatPromptCacheKeyis correct. ThesanitizeMetadataForkreturns a deterministic"fork"string for empty input rather than a UUID, which differs from the default but is intentional for this use case.
178-183: Clean integration withformatPromptCacheKey.The custom sanitizers and empty prefix configuration correctly delegate key formatting to the new utility while preserving existing behavior.
lib/update/auto-update.ts (3)
69-93: Timeout implementation is correct.The
AbortControllerwith 5-second timeout, properAbortErrordetection, and cleanup infinallyaddresses the previous concern about indefinite hangs.
122-146: Cache paths now usegetOpenCodePathconsistently.This addresses the previous concern about hardcoded paths not respecting
XDG_CACHE_HOME. The plugin path and cache files are all derived from the centralized utility.
148-199: Auto-update check flow is well-structured.The function follows a clear sequence: throttle check → version comparison → notification with 24-hour cooldown → artifact cleanup → state persistence. Error tracking via
lastErrorprovides debugging visibility.lib/server/dashboard.ts (6)
8-18: Helper functions look good; static analysis warnings are false positives.The unnecessary
newResaliases from previous reviews have been correctly removed. The static analysis warnings about parameter reassignment are false positives—modifyingServerResponseproperties is the standard Node.js pattern. If desired, you can suppress these with// eslint-disable-next-line no-param-reassigncomments, but it's not necessary.
20-93: XSS vulnerability has been properly addressed.The critical XSS issue from previous reviews has been fixed. The
escapeHtmlfunction is now defined in the inline script (lines 54-56) and is correctly applied to all user-controlled values before innerHTML concatenation (lines 74-80). This prevents injection attacks via malicious URLs or model names.
95-112: Handler functions are well-structured and correct.The route handlers properly delegate to the metrics and cache subsystems, and the separation between
/metrics(full data) and/recent(lightweight subset) is a good design choice for the auto-refreshing dashboard.
114-134: Routing logic is correct and defensive.The URL parsing handles null cases properly, and the switch statement with explicit returns ensures all routes are covered with a sensible 404 fallback.
136-163: Server startup logic is robust.The guards against multiple starts and test environments are appropriate, and the error handling properly logs both initialization and runtime errors. Using an ephemeral port (0) is a good choice for a local-only dashboard.
165-167: Port accessor is correct.Simple and correct implementation for exposing the dynamically assigned port.
lib/session/session-utils.ts (2)
6-24: Fallback hash collision resistance improved.The fallback hash now includes role/id-based fingerprinting and a random nonce, addressing the previous concern about arrays of the same length producing identical hashes. This is a solid improvement.
147-164: LGTM - redundant ternary has been removed.The createSessionState implementation is clean. The redundant ternary from the previous review has been resolved.
lib/session/session-manager.ts (3)
180-182: Past critical issues resolved.The previous type mismatch issues have been properly addressed. The new
buildContexthelper correctly constructsSessionContextobjects with all required fields (sessionId,enabled,preserveIds,isNew,state), and all return sites now use this helper.Also applies to: 203-204, 208-209, 279-287
191-191: Past property access issues resolved.Both critical fixes are in place:
- Line 191 correctly uses
body.inputinstead of the non-existentbody.messages- Line 223 correctly accesses
response.usage?.cached_tokenswithout the invalidprompt_tokens_detailsnestingAlso applies to: 223-223
212-232: All call sites ofrecordResponsehave been correctly updated to match the new signature. The call inresponse-recorder.tssafely passesSessionContextafter the type-narrowing guard clause at line 33, and the test call passes a validSessionContextobject. No further action needed.
- lib/session/session-manager.ts - lib/types.ts
- ib/request/codex-fetcher.ts - lib/request/request-transformer.ts - lib/session/session-manager.ts
- lib/request/codex-fetcher.ts - lib/request/request-transformer.ts - lib/session/session-manager.ts - test/config.test.ts - test/request-transformer.test.ts
- test/request-transformer.test.ts - test/session-manager.test.ts
- test/request-transformer.test.ts - test/session-manager.test.ts
- est/session-manager.test.ts
- test/session-manager.test.ts
- est/request-transformer.test.ts - test/session-manager.test.ts
- test/fetch-helpers.test.ts - test/request-transformer.test.ts - test/session-manager.test.ts
- est/fetch-helpers.test.ts
- lib/prompts/codex.ts - lib/update/auto-update.ts - test/codex-fetcher.test.ts
- lib/prompts/codex.ts - lib/session/session-manager.ts - lib/update/auto-update.ts - test/codex-fetcher.test.ts
…ariable' Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
lib/session/session-manager.ts (1)
69-137: Bug:_analyzePrefixChangereportsuser_message_changedwhen inputs are identical.
WhensharedPrefixLengthequals both array lengths,firstPreviousandfirstIncomingareundefined, causing the “both not system-like” branch to fire.Suggested fix:
function _analyzePrefixChange( previous: InputItem[], current: InputItem[], sharedPrefixLength: number, ): PrefixChangeAnalysis { + if (sharedPrefixLength >= previous.length && sharedPrefixLength >= current.length) { + return { cause: "unknown", details: { mismatchIndex: sharedPrefixLength } }; + } const firstPrevious = previous[sharedPrefixLength]; const firstIncoming = current[sharedPrefixLength]; @@ - if (!isSystemLike(firstPrevious) && !isSystemLike(firstIncoming)) { + if (!isSystemLike(firstPrevious) && !isSystemLike(firstIncoming)) { return { cause: "user_message_changed",Also applies to: 370-396
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (13)
lib/prompts/codex.ts(2 hunks)lib/request/codex-fetcher.ts(4 hunks)lib/request/fetch-helpers.ts(1 hunks)lib/request/request-transformer.ts(1 hunks)lib/session/session-manager.ts(8 hunks)lib/types.ts(1 hunks)lib/update/auto-update.ts(1 hunks)test/codex-fetcher.test.ts(1 hunks)test/config.test.ts(1 hunks)test/fetch-helpers.test.ts(3 hunks)test/index.test.ts(1 hunks)test/request-transformer.test.ts(9 hunks)test/session-manager.test.ts(11 hunks)
🧰 Additional context used
🧬 Code graph analysis (5)
lib/prompts/codex.ts (1)
lib/logger.ts (1)
logWarn(160-162)
test/session-manager.test.ts (2)
lib/session/session-manager.ts (1)
SessionManager(167-462)lib/types.ts (1)
RequestBody(159-183)
lib/request/codex-fetcher.ts (2)
lib/request/fetch-helpers.ts (3)
shouldRefreshToken(27-29)refreshAndUpdateToken(37-77)createCodexHeaders(215-238)lib/metrics/request-metrics.ts (1)
recordRequestMetrics(176-178)
lib/request/fetch-helpers.ts (2)
lib/logger.ts (1)
logRequest(133-150)lib/constants.ts (1)
LOG_STAGES(56-61)
lib/session/session-manager.ts (1)
lib/session/session-utils.ts (5)
isSystemLike(60-66)buildSessionKey(129-134)computeHash(6-24)createSessionState(147-164)longestSharedPrefixLength(34-50)
🪛 GitHub Actions: CI
lib/update/auto-update.ts
[warning] 69-69: eslint: Function 'compareSemver' has a complexity of 21. Maximum allowed is 20 (complexity).
[error] 69-69: sonarjs/cognitive-complexity: Refactor this function to reduce its Cognitive Complexity from 31 to the 30 allowed.
lib/request/codex-fetcher.ts
[warning] 32-32: eslint: Function 'createCodexFetcher' has too many lines (123). Maximum allowed is 120 (max-lines-per-function).
🪛 GitHub Check: Lint & Typecheck
lib/update/auto-update.ts
[failure] 69-69:
Refactor this function to reduce its Cognitive Complexity from 31 to the 30 allowed
[warning] 69-69:
Function 'compareSemver' has a complexity of 21. Maximum allowed is 20
test/session-manager.test.ts
[warning] 267-267:
'repeatedContext' is never reassigned. Use 'const' instead
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Test (20.x)
🔇 Additional comments (26)
test/config.test.ts (1)
145-161: LGTM on gpt-5.2 reasoning config tests.Good coverage of the new model behavior: default medium effort, xhigh support, and normalization of none/minimal to low. The summary assertion on xhigh (line 152) addresses prior feedback.
lib/update/auto-update.ts (1)
199-250: Update flow logic looks sound.The throttling, version comparison, notification deduplication (24h window), and artifact cleanup are well-structured. Error states are persisted appropriately for debugging.
test/codex-fetcher.test.ts (2)
48-51: Metrics mock is appropriate.The mock correctly isolates tests from actual metrics collection, matching the new
recordRequestMetricsintegration in production code.
57-58: Mock return shape aligns with updatedapplyRequestcontract.The change from a plain mock to returning
{ body, context }matches the session manager's new return structure used infetch-helpers.ts.lib/request/request-transformer.ts (1)
148-152: LGTM on dynamic verbosity default.The model-specific default ("low" for gpt-5.2, "medium" otherwise) is cleanly implemented. Using
??instead of||correctly handles edge cases wheretextVerbositymight be a defined falsy value.test/index.test.ts (1)
24-24: Mock correctly updated to match newapplyRequestcontract.The mock now returns
{ body, context }which aligns with the updatedSessionManager.applyRequestsignature that returnsSessionApplyResultinstead of justSessionContext.test/fetch-helpers.test.ts (3)
296-296: Mock correctly updated for newapplyRequestreturn shape.The mock returns
{ body: transformed, context: appliedContext }matching the updatedSessionApplyResultinterface.
337-337: Consistent mock update.
377-377: Consistent mock update.lib/prompts/codex.ts (4)
198-216: Well-structured helper for cache/bundled fallback.Clean implementation that centralizes the cache-read-or-bundled logic. The synchronous signature is appropriate since no async operations are performed.
218-229: Clean error handling wrapper.Consolidates the fallback behavior when latest tag retrieval fails. The
error: unknownparameter type is correct for catch blocks.
231-246: Focused helper for fresh cache validation.Returns
nullto signal the caller should refetch, which is a clear contract.
279-289: Improved flow using extracted helpers.The main function now delegates to the helpers appropriately, making the control flow clearer.
lib/request/fetch-helpers.ts (2)
168-175: Clean separation: transform then apply session context.The flow correctly:
- Computes the initial transform result
- Applies session context via
applyRequestif a session manager exists- Uses the resulting body and context for downstream processing
The fallback to original
sessionContextwhenapplyResult.contextis undefined handles edge cases appropriately.
177-198: Logging and return values correctly use the effective body.All downstream usage (logging,
updatedInit.body, and the return value) now consistently referencesresultingBody, ensuring the session-applied changes are properly propagated.test/session-manager.test.ts (4)
52-57: Test correctly adapted to newapplyRequestcontract.Properly destructures
{ body: updatedBody, context: updatedContext }and validates both the body and context properties.
64-77: Multi-turn test correctly chains context throughapplyRequestresults.The flow properly updates context references from each
applyRequestcall and validates the accumulated state.
198-204: Response recording test adapted correctly.Uses the context from
applyRequestresult forrecordResponse, matching the expected flow.
315-320: Good defensive handling with fallback.Using
applyResult.context ?? contexthandles the case whereapplyRequestmight not return a context, though in practice it always should when enabled.test/request-transformer.test.ts (4)
165-190: Reasoning-effort clamp/allow rules look consistent and well-tested.
The added cases for “xhigh downgrade on unsupported models” and the dedicated gpt‑5.2 block (default medium, clamp none/minimal to low, preserve xhigh) are clear and give good coverage for the new branching.
997-1023: Good test adaptation toSessionManager.applyRequest()returning{ body, context }.
CapturingfirstApply.body.prompt_cache_keyand usingapplied.context ?? sessionTwois a solid pattern for the updated contract and keeps the cache-key stability assertion meaningful.
1185-1244: Verify gpt‑5.2 defaults are intentionally different (xhigh allowed, verbosity low).
Tests now “lock in” gpt‑5.2 behavior (xhigh preserved + default verbosity low). If these defaults are policy decisions (vs temporary experimentation), consider adding a short comment near these tests explaining why they differ from gpt‑5.* to avoid future “cleanup” regressions.
1865-1866: Skipped edge-case mock updated correctly for new applyRequest return shape.
The mock returning{ body, context }matches the new API and should avoid test breakage if this test is later enabled.lib/session/session-manager.ts (1)
16-17: Env-context detection refactor is solid and more maintainable.
Centralized marker detection +extractContentText()keeps the env-stripping logic readable and should help reduce prompt-cache churn.Also applies to: 425-461
lib/request/codex-fetcher.ts (2)
56-95: The review comment is based on an incorrect assumption. TheRequestMetricsInputtype inlib/metrics/request-metrics.tsexplicitly definespromptCacheKey: boolean;, andextractRequestMetrics()correctly returns a boolean value for this field. There is no type mismatch—the function's output aligns with what the metrics system expects. ThepromptCacheKeyfield is intentionally designed as a boolean flag to track presence or absence of a cache key, not to store the actual cache string.Likely an incorrect or invalid review comment.
56-95: Empty tools array is incorrectly flagged as "has tools"—blocks proper response handling.
const hasTools = effectiveBody?.tools !== undefined;treatstools: []as true, causing the response to be handled as a tool request when no tools are actually available. This changes howhandleSuccessResponseprocesses the response: non-empty tools return the stream as-is (for tool use), while empty tools should convert SSE to JSON like non-tool requests.Fix:
- const hasTools = effectiveBody?.tools !== undefined; + const hasTools = Array.isArray(effectiveBody?.tools) && effectiveBody.tools.length > 0;Likely an incorrect or invalid review comment.
| public applyRequest(body: RequestBody, context?: SessionContext): SessionApplyResult { | ||
| const clonedBody = this.cloneRequestBody(body); | ||
|
|
||
| const refreshed = this.resetSessionInternal(state.id, true); | ||
| if (!refreshed) { | ||
| return undefined; | ||
| } | ||
| refreshed.lastInput = input; | ||
| refreshed.lastPrefixHash = inputHash; | ||
| refreshed.lastUpdated = Date.now(); | ||
| // eslint-disable-next-line no-param-reassign | ||
| body.prompt_cache_key = refreshed.promptCacheKey; | ||
| if (refreshed.store) { | ||
| // eslint-disable-next-line no-param-reassign | ||
| body.store = true; | ||
| } | ||
| return { | ||
| sessionId: refreshed.id, | ||
| enabled: true, | ||
| preserveIds: true, | ||
| isNew: true, | ||
| state: refreshed, | ||
| }; | ||
| } | ||
| if (!this.options.enabled || !context) { | ||
| return { body: clonedBody, context }; | ||
| } | ||
|
|
||
| const sharedPrefix = input.slice(0, sharedPrefixLength); | ||
| const { sessionId: forkSessionId, promptCacheKey: forkPromptCacheKey } = buildPrefixForkIds( | ||
| state.id, | ||
| state.promptCacheKey, | ||
| sharedPrefix, | ||
| ); | ||
| const forkState: SessionState = { | ||
| id: forkSessionId, | ||
| promptCacheKey: forkPromptCacheKey, | ||
| store: state.store, | ||
| lastInput: input, | ||
| lastPrefixHash: inputHash, | ||
| lastUpdated: Date.now(), | ||
| lastCachedTokens: state.lastCachedTokens, | ||
| bridgeInjected: state.bridgeInjected, | ||
| }; | ||
|
|
||
| this.sessions.set(forkSessionId, forkState); | ||
| logWarn("SessionManager: prefix mismatch detected, forking session", { | ||
| sessionId: state.id, | ||
| promptCacheKey: state.promptCacheKey, | ||
| forkSessionId, | ||
| forkPromptCacheKey, | ||
| sharedPrefixLength, | ||
| previousItems: state.lastInput.length, | ||
| incomingItems: input.length, | ||
| previousHash: state.lastPrefixHash, | ||
| incomingHash: inputHash, | ||
| prefixCause: prefixAnalysis.cause, | ||
| ...prefixAnalysis.details, | ||
| }); | ||
| // eslint-disable-next-line no-param-reassign | ||
| body.prompt_cache_key = forkPromptCacheKey; | ||
| if (forkState.store) { | ||
| // eslint-disable-next-line no-param-reassign | ||
| body.store = true; | ||
| } | ||
| return { | ||
| sessionId: forkSessionId, | ||
| enabled: true, | ||
| preserveIds: true, | ||
| isNew: true, | ||
| state: forkState, | ||
| }; | ||
| const existingState = this.sessions.get(context.sessionId) ?? context.state; | ||
| if (!existingState) { | ||
| return { body: clonedBody, context }; | ||
| } | ||
|
|
||
| state.lastInput = input; | ||
| state.lastPrefixHash = inputHash; | ||
| state.lastUpdated = Date.now(); | ||
| const nextInput = this.cloneInputItems(clonedBody.input); | ||
| const newState: SessionState = { | ||
| ...existingState, | ||
| lastInput: nextInput, | ||
| lastPrefixHash: nextInput.length ? computeHash(nextInput) : null, | ||
| lastUpdated: Date.now(), | ||
| }; | ||
| this.sessions.set(newState.id, newState); | ||
|
|
||
| return context; | ||
| } | ||
| const updatedContext: SessionContext = { | ||
| ...context, | ||
| isNew: false, | ||
| state: newState, | ||
| }; | ||
|
|
||
| public recordResponse( | ||
| context: SessionContext | undefined, | ||
| payload: CodexResponsePayload | undefined, | ||
| ): void { | ||
| if (!context?.enabled || !payload) { | ||
| return; | ||
| if (newState.promptCacheKey) { | ||
| clonedBody.prompt_cache_key = newState.promptCacheKey; | ||
| clonedBody.promptCacheKey = newState.promptCacheKey; | ||
| } | ||
|
|
||
| const state = context.state; | ||
| const cachedTokens = payload.usage?.cached_tokens; | ||
| if (typeof cachedTokens === "number") { | ||
| state.lastCachedTokens = cachedTokens; | ||
| logDebug("SessionManager: response usage", { | ||
| sessionId: state.id, | ||
| cachedTokens, | ||
| }); | ||
| } | ||
| state.lastUpdated = Date.now(); | ||
| return { body: clonedBody, context: updatedContext }; | ||
| } |
There was a problem hiding this comment.
Bug risk: cloning coerces input: null (and other non-array values) into a different shape.
cloneRequestBody() uses body.input ? ... : undefined, so null becomes undefined. Also, cloneInputItems() returns [] for non-arrays, so a truthy-but-malformed input becomes []. This can break the explicit “null input” behavior your tests cover elsewhere.
Safer approach: preserve null/undefined/non-array as-is, only deep-clone when it’s an array.
private cloneRequestBody(body: RequestBody): RequestBody {
- const clonedInput = body.input ? this.cloneInputItems(body.input) : undefined;
+ const clonedInput = Array.isArray(body.input) ? this.cloneInputItems(body.input) : body.input;
return {
...body,
input: clonedInput,
@@
private cloneInputItems(input: InputItem[] | undefined): InputItem[] {
- if (!Array.isArray(input)) {
- return [];
- }
+ if (!Array.isArray(input)) return [];(keeping cloneInputItems strict is fine once cloneRequestBody guards correctly).
Also applies to: 398-408, 410-419
🤖 Prompt for AI Agents
In lib/session/session-manager.ts around lines 242 to 275, cloneRequestBody and
cloneInputItems are coercing null/non-array inputs into undefined or [] which
changes the intended shape (breaking explicit null semantics); update
applyRequest to preserve input when it's null or a non-array by only
deep-cloning when Array.isArray(body.input) is true, and adjust usage so
cloneInputItems is called only for real arrays (or make cloneInputItems return
the original non-array value unchanged); make the same guard/fix in the other
affected regions (around lines 398-408 and 410-419) so null and undefined inputs
are left intact and only arrays are cloned.
- lib/update/auto-update.ts
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
test/session-manager.test.ts (2)
111-146: Test name contradicts behavior: it does expect a warn on user-only changes.
The title says “does not warn…”, but the assertion expects aprefix mismatchwarn withprefixCause: "user_message_changed"(Lines 137-145). Rename the test or change expectations.- it("does not warn on user-only content changes", () => { + it("warns on user-only content changes", () => {
309-321: Avoid mutating internal session state for ordering; prefer fake timers to make recency deterministic.
appliedContext.state.lastUpdated -= index(Line 320) couples the test to internal mutability and makes refactors riskier. Usingvi.useFakeTimers()+vi.setSystemTime()per iteration would keep the test black-box while still controlling ordering.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (2)
lib/update/auto-update.ts(1 hunks)test/session-manager.test.ts(12 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
test/session-manager.test.ts (2)
lib/session/session-manager.ts (1)
SessionManager(167-462)lib/types.ts (1)
RequestBody(159-183)
🔇 Additional comments (6)
test/session-manager.test.ts (2)
5-5: Good adaptation toapplyRequest()returning{ body, context }—keep the “assert then non-null” pattern consistent.
In most places you immediately usecontext!fromapplyRequest(). Where you already doexpect(updatedContext).toBeDefined()(Line 55), consider following the same pattern elsewhere (e.g.,firstApply.context!,secondApply.context!,applyResult.context!) to make failures read cleaner when the contract changes again.Also applies to: 52-57, 64-75, 198-205
257-271: Prior feedback addressed:repeatedContextis no longer pointlessly reassigned.
Looks clean now—no uselessrepeatedContext = ...reassignment, and the flow matches the new apply result shape.lib/update/auto-update.ts (4)
1-17: LGTM - Previous path resolution issues addressed.The use of
createRequireto loadpackage.jsoncorrectly resolves the production build path issue flagged in previous reviews. The module-level extraction ofPACKAGE_VERSIONensures the version is available regardless of the runtime directory structure, and usinggetOpenCodePathfor the state file path is consistent with the codebase's cache management approach.
19-42: LGTM - Clean state management.The state persistence logic is straightforward and resilient. Returning an empty object on parse errors (line 32) allows the system to gracefully recover from corrupted state files, and the throttling check (line 41) correctly prevents excessive registry queries.
44-127: LGTM - Semver implementation addresses previous issues.The refactored version comparison logic correctly addresses the previous complexity and prerelease handling concerns:
- Helper functions (
compareCoreParts,comparePrereleaseParts) have reduced the cognitive complexity ofcompareSemverto an acceptable level- Prerelease tag handling (lines 61-65) correctly parses and distinguishes numeric from alphanumeric identifiers
- The comparison logic (lines 80-113) properly implements semver precedence rules: stable > prerelease, longer prerelease > shorter, numeric < alphanumeric within prerelease
129-153: LGTM - Timeout handling properly implemented.The registry fetch correctly addresses the previous timeout concern. The
AbortControllerpattern (lines 130-131, 137) ensures requests don't hang indefinitely, thefinallyblock (line 151) prevents timer leaks, and the explicitAbortErrorcheck (line 145) provides clear timeout-specific logging.
- lib/session/session-manager.ts

No description provided.