fix: /model command now switches active model#635
fix: /model command now switches active model#635CoderLuii wants to merge 1 commit intositeboon:mainfrom
Conversation
📝 WalkthroughWalkthroughThe changes implement model selection through a Changes
Sequence DiagramsequenceDiagram
actor User
participant Server
participant Hook as useChatComposerState
participant Storage as Local Storage
participant UI as ProviderSelectionEmptyState
User->>Server: Send /model command with target model
Server->>User: Return response with newModel field
User->>Hook: Trigger model command handler
Hook->>Hook: Extract newModel from response.data
Hook->>Storage: Persist model under 'claude-model' key
Hook->>UI: Update claudeModel state
UI->>UI: Render model option with current value available
Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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 |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/components/chat/hooks/useChatComposerState.ts`:
- Around line 174-177: The /model command handler in useChatComposerState always
calls setClaudeModel and writes 'claude-model' to storage even when the active
provider is cursor/codex/gemini; update useChatComposerState to accept
setCursorModel, setCodexModel, and setGeminiModel (in addition to
setClaudeModel), read the current provider value, and route updates: call the
corresponding setter
(setCursorModel/setCodexModel/setGeminiModel/setClaudeModel) and write the
matching key ('cursor-model'/'codex-model'/'gemini-model'/'claude-model') to
safeLocalStorage when data.newModel is present so the /model command updates the
correct provider's active model.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 15b1b26a-b7bf-4aca-bc66-ddd3ef52e817
📒 Files selected for processing (4)
server/routes/commands.jssrc/components/chat/hooks/useChatComposerState.tssrc/components/chat/view/ChatInterface.tsxsrc/components/chat/view/subcomponents/ProviderSelectionEmptyState.tsx
| if (data.newModel) { | ||
| setClaudeModel(data.newModel); | ||
| safeLocalStorage.setItem('claude-model', data.newModel); | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify how /model is handled and whether provider-specific setters are wired.
rg -n -C3 "case 'model'|newModel|setClaudeModel|setCursorModel|setCodexModel|setGeminiModel|claude-model|cursor-model|codex-model|gemini-model" \
server/routes/commands.js \
src/components/chat/hooks/useChatComposerState.ts \
src/components/chat/view/ChatInterface.tsxRepository: siteboon/claudecodeui
Length of output: 5536
🏁 Script executed:
#!/bin/bash
# Check if provider state is accessible and how other models are initialized/stored
rg -n "handleBuiltInCommand|setProvider|setCodexModel|setCursorModel|setGeminiModel" \
src/components/chat/hooks/useChatComposerState.ts -A 5 -B 2 | head -100Repository: siteboon/claudecodeui
Length of output: 886
🏁 Script executed:
#!/bin/bash
# Search for localStorage patterns to see if other providers use different keys
rg -n "localStorage|setItem|getItem" src/components/chat/hooks/useChatComposerState.tsRepository: siteboon/claudecodeui
Length of output: 763
🏁 Script executed:
#!/bin/bash
# Check how the command gets dispatched and what context it has
rg -n "case 'model':" -A 10 -B 5 server/routes/commands.jsRepository: siteboon/claudecodeui
Length of output: 47
🏁 Script executed:
#!/bin/bash
# Find model command handling with broader search
rg -n "model" server/routes/commands.js | grep -E "(case|'model'|\bmodel\b)" | head -20Repository: siteboon/claudecodeui
Length of output: 545
🏁 Script executed:
#!/bin/bash
# Look for how other models are initialized from storage
rg -n "cursorModel|codexModel|geminiModel" src/components/chat/hooks/useChatComposerState.ts -B 3 -A 3 | head -80Repository: siteboon/claudecodeui
Length of output: 2421
🏁 Script executed:
#!/bin/bash
# Search for provider state handling in chat interface
rg -n "provider.*setClaudeModel|provider.*setCursorModel|if.*provider.*model" src/components/chat/Repository: siteboon/claudecodeui
Length of output: 47
🏁 Script executed:
#!/bin/bash
# Find where models are initialized from localStorage
rg -n "useState.*Model|getItem.*model|CLAUDE_MODELS|CURSOR_MODELS|CODEX_MODELS|GEMINI_MODELS" \
src/components/chat/hooks/useChatComposerState.ts -B 2 -A 2 | head -100Repository: siteboon/claudecodeui
Length of output: 47
🏁 Script executed:
#!/bin/bash
# Check parent component to see how model state is created
rg -n "useChatComposerState|claudeModel|cursorModel" src/components/chat/view/ChatInterface.tsx \
| grep -E "(useState|const.*Model|useChatComposerState)" | head -20Repository: siteboon/claudecodeui
Length of output: 170
🏁 Script executed:
#!/bin/bash
# Read the hook file to find where models are initialized
head -150 src/components/chat/hooks/useChatComposerState.ts | tail -100Repository: siteboon/claudecodeui
Length of output: 3234
🏁 Script executed:
#!/bin/bash
# Look for useState calls and model initialization
rg -n "useState|setClaudeModel|setCursorModel|setCodexModel|setGeminiModel" \
src/components/chat/hooks/useChatComposerState.ts | head -30Repository: siteboon/claudecodeui
Length of output: 851
🏁 Script executed:
#!/bin/bash
# Check ChatInterface.tsx to see where all model state is defined
rg -n "claudeModel|cursorModel|codexModel|geminiModel|useState" \
src/components/chat/view/ChatInterface.tsx | head -40Repository: siteboon/claudecodeui
Length of output: 384
🏁 Script executed:
#!/bin/bash
# Look for setCursor, setCodex, setGemini setters in ChatInterface
rg -n "setCursor|setCodex|setGemini|setClaudeModel" \
src/components/chat/view/ChatInterface.tsxRepository: siteboon/claudecodeui
Length of output: 361
🏁 Script executed:
#!/bin/bash
# Check what ChatComposer component does with the other model setters
rg -n "setCursorModel|setCodexModel|setGeminiModel" \
src/components/chat/ -A 3 -B 3 | grep -E "\.tsx:|\.ts:" | head -40Repository: siteboon/claudecodeui
Length of output: 3001
🏁 Script executed:
#!/bin/bash
# Check if there's documentation or comments about /model being Claude-only
rg -n "model.*command|/model|claude.*only" \
server/routes/commands.js docs/ README.md 2>/dev/null | head -20Repository: siteboon/claudecodeui
Length of output: 719
/model command handler should support all providers, not just Claude.
The handler at lines 174-177 always calls setClaudeModel() and updates claude-model storage, regardless of the active provider. When a non-Claude provider (cursor, codex, or gemini) is active, running /model fails to update that provider's active model.
To fix: Pass setCursorModel, setCodexModel, and setGeminiModel into useChatComposerState and route the update based on the current provider state:
case 'model':
if (data.newModel) {
if (provider === 'cursor') {
setCursorModel(data.newModel);
safeLocalStorage.setItem('cursor-model', data.newModel);
} else if (provider === 'codex') {
setCodexModel(data.newModel);
safeLocalStorage.setItem('codex-model', data.newModel);
} else if (provider === 'gemini') {
setGeminiModel(data.newModel);
safeLocalStorage.setItem('gemini-model', data.newModel);
} else {
setClaudeModel(data.newModel);
safeLocalStorage.setItem('claude-model', data.newModel);
}
}The README documents support for "Claude, GPT, and Gemini model families," confirming /model should work across all providers.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/components/chat/hooks/useChatComposerState.ts` around lines 174 - 177,
The /model command handler in useChatComposerState always calls setClaudeModel
and writes 'claude-model' to storage even when the active provider is
cursor/codex/gemini; update useChatComposerState to accept setCursorModel,
setCodexModel, and setGeminiModel (in addition to setClaudeModel), read the
current provider value, and route updates: call the corresponding setter
(setCursorModel/setCodexModel/setGeminiModel/setClaudeModel) and write the
matching key ('cursor-model'/'codex-model'/'gemini-model'/'claude-model') to
safeLocalStorage when data.newModel is present so the /model command updates the
correct provider's active model.
what
/model <name>in the Chat tab shows a response message but never switches the active model.why
three layers were broken:
server/routes/commands.jsdidn't include the requested model name in the responsecase "model"handler only rendered a display messagesetClaudeModelnever reached the composer hook that handles built-in commandsfix
newModelwhen args are providedsetClaudeModel(newModel)and persistsclaude-modelsetClaudeModelis threaded intouseChatComposerStatebehavior
/model <name>now switches the active model in Chat/modelwith no args still shows current model info without switchingSummary by CodeRabbit
New Features
/modelcommand to switch between Claude modelsImprovements