Skip to content

fix(chat): prefer server session row over stale cache in model dropdown#93623

Closed
sunlit-deng wants to merge 1 commit into
openclaw:mainfrom
sunlit-deng:fix/issue-93346-Bug---Model-dropdown-does-not
Closed

fix(chat): prefer server session row over stale cache in model dropdown#93623
sunlit-deng wants to merge 1 commit into
openclaw:mainfrom
sunlit-deng:fix/issue-93346-Bug---Model-dropdown-does-not

Conversation

@sunlit-deng

Copy link
Copy Markdown
Contributor

Summary

The chat model dropdown could show a cached model selection (e.g. codex/gpt-5.5)
while the active session was actually using the default/fallback model
(e.g. ollama/qwen3.5:9b). This happened because resolveChatModelOverrideValue
always preferred the local chatModelOverrides cache without cross-referencing
the server's session row.

When a user selects a model different from the default, the selection is stored
locally in chatModelOverrides and also sent to the server as a session patch.
But if the session later resets or drifts back to its default model (e.g. after
logout/login, session timeout, or model failover), the local cache retains the
old selection while the server reports the correct runtime model. The dropdown
then displays a misleading model.

Fix: In resolveChatModelOverrideValue(), when a cached override exists but
the server's active session row reports a different runtime model, prefer the
server value. The cached override is still used when the server has no model
data or when both values agree.

Fixes #93346

Linked context

Real behavior proof

Behavior addressed: Chat model dropdown now reflects actual runtime model
when the server session row differs from the locally cached override.

Real setup tested: Unit tests with vitest

Exact steps or command run after fix:

pnpm test -- --run ui/src/ui/chat-model-select-state.test.ts

After-fix evidence:

= test/vitest/vitest.ui.config.ts (1 test file)
= chat-model-select-state (10 tests)
Test Files 1 passed (1)
Tests 10 passed (10)
Start at 20:05:52
Duration 2.93s

New test case (prefers server session row over stale cached override):

  • Sets cached override to openai/gpt-5-mini
  • Server session row reports deepseek-chat (deepseek provider)
  • Expected: deepseek/deepseek-chat (server value wins)
  • The resolved currentOverride is correctly deepseek/deepseek-chat

Existing behavior preserved (normalizes cached bare overrides):

  • Sets cached override to gpt-5-mini (raw)
  • Server session row has no model (model: null)
  • Expected: openai/gpt-5-mini (cached value wins when server has no data)
  • The resolved currentOverride is correctly openai/gpt-5-mini

Observed result after the fix: All 10 tests pass, including 1 new test
covering the drift scenario. The fix is a pure state-selector change — no
component or server-side modifications needed.

What was not tested: E2E tests with live Gateway were not run. The fix is
a pure selector function change verified through unit tests.

Tests and validation

  • All existing 9 tests pass unchanged
  • New test verifies: cached override differs from server -> server wins
  • All 23 chat-model-ref.test.ts tests also pass
  • Ran pnpm check (lint + typecheck) — clean

Risk checklist

Did user-visible behavior change? (Yes)

  • When the server model differs from the cached override, the dropdown now shows
    the server's runtime model instead of the stale cached selection.

Did config, environment, or migration behavior change? (No)

Did security, auth, secrets, network, or tool execution behavior change? (No)

What is the highest-risk area?

  • Brief (<200ms) window where an in-flight model patch could be overridden by
    a slightly stale server response. The server value is authoritative once the
    patch is confirmed.

How is that risk mitigated?

  • The fix only prefers the server value when it differs from the cache.
    After the server confirms a patch, both values agree and the cache wins
    normally. The divergence only occurs when the session genuinely drifted.

Current review state

What is the next action?

  • Maintainer review

What is still waiting on author, maintainer, CI, or external proof?

  • This PR fixes the UI cache side of the issue. The Gateway session row still
    conflates selected and runtime model identity into a single model/modelProvider
    field. A follow-up could expose both fields separately for full transparency,
    but this change already makes the dropdown accurate.

Which bot or reviewer comments were addressed?

  • clawsweeper noted the cache-first picker as a source-level reproduction path;
    this PR directly addresses that by cross-referencing the server row.
    The Gateway row projection issue (selectedModel vs resolvedModel both
    mapped to row.model) is noted but not addressed here.

…model dropdown

The chat model dropdown could show a cached model selection (e.g. codex/gpt-5.5)
while the active session was actually using the default/fallback model. This
happened because resolveChatModelOverrideValue always preferred the local
chatModelOverrides cache without cross-referencing the server's session row.

Now when a cached override exists but the server shows a different runtime model,
the server value takes precedence — the dropdown reflects the actual model being used.
@openclaw-barnacle openclaw-barnacle Bot added app: web-ui App: web-ui size: XS triage: mock-only-proof Candidate: PR proof only shows tests, mocks, snapshots, lint, typecheck, or CI. labels Jun 16, 2026
@clawsweeper

clawsweeper Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper review: did not complete due to Codex infrastructure failure. Reviewed June 16, 2026, 8:40 AM ET / 12:40 UTC.

Summary
Review failed before ClawSweeper could summarize the requested change.

PR surface: Source +14, Tests +14. Total +28 across 2 files.

Reproducibility: unclear. The review failed before ClawSweeper could establish a reproduction path.

Review metrics: none identified.

Merge readiness
Not assessed.
Failure reason: invalid structured output.

This is a ClawSweeper/Codex infrastructure failure, not a PR readiness or patch-quality verdict.
Keep any merge decision on the normal maintainer review path until ClawSweeper can complete a fresh review.

Risk before merge

  • [P1] No close action taken because the review did not complete.

Maintainer options:

  1. Decide the mitigation before merge
    Retry the Codex review after fixing the execution failure.
  2. Pause or close
    Do not merge this PR until maintainers decide whether the risk is worth taking.

Next step before merge

  • Review did not complete, so no work-lane recommendation was made.
Review details

Best possible solution:

Retry the Codex review after fixing the execution failure.

Do we have a high-confidence way to reproduce the issue?

Unclear. The review failed before ClawSweeper could establish a reproduction path.

Is this the best way to solve the issue?

Unclear. Retry the review first so ClawSweeper can evaluate the actual issue and fix direction.

AGENTS.md: unclear because the file could not be read completely.

Codex review notes: model internal, reasoning high; reviewed against aebf0bbd2da7.

Evidence reviewed

PR surface:

Source +14, Tests +14. Total +28 across 2 files.

View PR surface stats
Area Files Added Removed Net
Source 1 17 3 +14
Tests 1 14 0 +14
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 2 31 3 +28

What I checked:

  • failure reason: invalid structured output.
  • codex failure detail: Codex review failed for this PR with exit 0 and wrote invalid JSON or schema-invalid output to /home/runner/work/clawsweeper/clawsweeper/artifacts/event/codex/93623.json: decision.rootCauseCluster.currentItemRelationship fixed_by_candidate requires a canonical PR.
  • codex stderr: No stderr captured.
  • codex stdout: ve."}],"itemCategory":"bug","reproductionStatus":"source_reproducible","reproductionConfidence":"high","requiresNewFeature":false,"requiresNewConfigOption":false,"requiresProductDecision":true,"reproductionAssessment":"Yes, source-reproducible: with a cached override set by switchChatModel and sessionsResult still holding the old row, this PR returns serverValue instead of the pending cached selection. I did not run a live browser/Gateway scenario in this read-only review.","solutionAssessment":"No: this is a plausible local mitigation, but not the best fix yet. The maintainable fix needs a selected/effective model contract and must preserve pending user selections while sessions.patch is in flight.","visionFit":"not_applicable","visionFitReason":"This is a pull request review, so VISION.md product-fit classification is not applicable.","visionFitEvidence":[],"implementationComplexity":".

Likely related people:

  • unknown: Codex failed before it could trace repository history. (role: review did not complete; confidence: low)
How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@vincentkoc vincentkoc self-assigned this Jun 16, 2026
@vincentkoc

Copy link
Copy Markdown
Member

Closing this patch because it regresses the normal in-flight model-switch path.

switchChatModel intentionally writes the local override before sessions.patch completes. While the server row still contains the previous model, this patch makes that stale row win, so every non-default switch renders the old selection for the whole pending RPC/refresh period.

The linked issue remains valid, but the durable fix needs an explicit selected-vs-effective model contract between Gateway and UI, with pending local selections preserved until confirmation. Focused UI tests passed, and fresh autoreview reproduced this blocker at high confidence.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app: web-ui App: web-ui size: XS triage: mock-only-proof Candidate: PR proof only shows tests, mocks, snapshots, lint, typecheck, or CI.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Model dropdown does not reflect effective runtime model after fallback/default drift

2 participants