Skip to content

fix(web): stop rapid localStorage flip when removing a language model#1295

Merged
brendan-kellam merged 2 commits into
mainfrom
brendan/fix-language-model-selection-flip
Jun 10, 2026
Merged

fix(web): stop rapid localStorage flip when removing a language model#1295
brendan-kellam merged 2 commits into
mainfrom
brendan/fix-language-model-selection-flip

Conversation

@brendan-kellam

@brendan-kellam brendan-kellam commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

The selected-language-model state was owned by a useSelectedLanguageModel hook instantiated in three chat components (chatBox, chatBoxToolbar, chatThread), each running its own reset effect against the shared "selectedLanguageModel" localStorage key. Since usehooks-ts broadcasts a storage event on every write, those instances re-triggered each other into a rapid write loop when a model was removed.

Lift the state into a single LanguageModelProvider mounted once in the (app) layout. useSelectedLanguageModel is now a thin context consumer, so there is exactly one owner of the localStorage state and one reset effect. The reset is also made idempotent — it only writes when the resolved selection differs by key.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Resolved an issue where the selected language model would rapidly flip in local storage after removing a language model.

The selected-language-model state was owned by a useSelectedLanguageModel
hook instantiated in three chat components, each running its own reset
effect against the shared "selectedLanguageModel" localStorage key. Since
usehooks-ts broadcasts a storage event on every write, those instances
re-triggered each other into a rapid write loop when a model was removed.

Lift the state into a single LanguageModelProvider mounted once in the
(app) layout. The hook is now a thin context consumer, so there is exactly
one owner of the localStorage state and one reset effect. The reset is also
made idempotent (only writes when the resolved selection differs by key).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

This comment has been minimized.

@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 268124b7-a27c-41b5-8167-8114c5ed0e95

📥 Commits

Reviewing files that changed from the base of the PR and between 147aa95 and 1c031f5.

📒 Files selected for processing (9)
  • CHANGELOG.md
  • packages/web/src/app/(app)/askgh/[owner]/[repo]/components/landingPage.tsx
  • packages/web/src/app/(app)/chat/components/landingPageChatBox.tsx
  • packages/web/src/app/(app)/layout.tsx
  • packages/web/src/ee/features/chat/components/chatThread/chatThread.tsx
  • packages/web/src/features/chat/components/chatBox/chatBox.tsx
  • packages/web/src/features/chat/components/chatBox/chatBoxToolbar.tsx
  • packages/web/src/features/chat/languageModelContext.tsx
  • packages/web/src/features/chat/useSelectedLanguageModel.ts
💤 Files with no reviewable changes (2)
  • packages/web/src/app/(app)/askgh/[owner]/[repo]/components/landingPage.tsx
  • packages/web/src/app/(app)/chat/components/landingPageChatBox.tsx

Walkthrough

This PR centralizes language model selection from component prop-drilling to a React context provider at the root layout, with localStorage persistence that correctly resets when the stored selection is no longer available. All consumers are updated to remove languageModels props and use the context-driven hook instead.

Changes

Language Model Context Refactoring

Layer / File(s) Summary
Language model context definition and provider
packages/web/src/features/chat/languageModelContext.tsx
New client-side context and LanguageModelProvider manage selected model state via localStorage. The provider computes a fallback to the first available model and uses an effect to reset the selection when the stored model is no longer available in the provided list, only writing when the model key differs to avoid repeated storage loops.
Hook refactoring to context-driven selection
packages/web/src/features/chat/useSelectedLanguageModel.ts
useSelectedLanguageModel is rewritten to consume SelectedLanguageModelContext directly via useContext, removing the prior props-based fallback logic and effect-driven reset behavior driven by the languageModels argument.
Root layout provider wrapping
packages/web/src/app/(app)/layout.tsx
Root layout fetches configured language models on the server and wraps the entire app with LanguageModelProvider, making the context available to all nested components.
Component consumers update to remove languageModels prop
packages/web/src/features/chat/components/chatBox/chatBox.tsx, packages/web/src/features/chat/components/chatBox/chatBoxToolbar.tsx, packages/web/src/ee/features/chat/components/chatThread/chatThread.tsx, packages/web/src/app/(app)/askgh/[owner]/[repo]/components/landingPage.tsx, packages/web/src/app/(app)/chat/components/landingPageChatBox.tsx
ChatBox removes the languageModels prop from its interface and all consumers (ChatBoxToolbar, ChatThread, landing pages) stop passing languageModels and update useSelectedLanguageModel calls to use the argument-less hook.
Changelog documentation
CHANGELOG.md
Added entry documenting the fix for the language model selection no longer flipping in localStorage after a model is removed.

Sequence Diagram

sequenceDiagram
  participant Root as App Layout
  participant Provider as LanguageModelProvider
  participant Context as SelectedLanguageModelContext
  participant Consumer as ChatBox/Components
  
  Root->>Root: Fetch configured language models
  Root->>Provider: Pass languageModels list
  Provider->>Provider: Initialize localStorage entry
  Provider->>Provider: Compute fallback model (first in list)
  Provider->>Provider: useEffect validates stored selection
  Note over Provider: If stored model not in list,<br/>reset to fallback
  Provider->>Context: Provide selectedLanguageModel + setter
  Consumer->>Context: useSelectedLanguageModel()
  Consumer->>Consumer: Render with selected model
  Consumer->>Context: setSelectedLanguageModel(model)
  Context->>Provider: Update stored selection
  Provider->>Provider: Write to localStorage
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • msukkari
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and accurately describes the main fix: preventing rapid localStorage updates when a language model is removed by centralizing state management.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch brendan/fix-language-model-selection-flip

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.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@brendan-kellam brendan-kellam merged commit cfcabcb into main Jun 10, 2026
10 checks passed
@brendan-kellam brendan-kellam deleted the brendan/fix-language-model-selection-flip branch June 10, 2026 00:07
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