Skip to content

Conversation

@daniel-lxs
Copy link
Member

@daniel-lxs daniel-lxs commented Nov 5, 2025

Problem

When switching between dynamic providers (like OpenRouter to Chutes), the extension would sometimes default to Claude Sonnet 4 instead of the provider's default model. This happened because configured model IDs from the previous provider were being used with the new provider, even when that model doesn't exist in the new provider's model list.

Additionally, when users switch providers after selecting a model, the router models for the new provider may not be loaded yet, causing a TypeError when the code tries to access properties on undefined objects (fixes #9047).

Root Cause

The issue was cross-contamination between providers. For example:

  1. User selects OpenRouter with model anthropic/claude-sonnet-4.5
  2. User switches to Chutes
  3. apiConfiguration.apiModelId still contains anthropic/claude-sonnet-4.5
  4. Chutes doesn't have this model, so it falls back to default
  5. But the fallback was inconsistently applied

Solution

1. Created reusable validation helper

Added getValidatedModelId() function that ensures the configured model ID exists in the current provider's available models before using it.

2. Applied to ALL dynamic providers

Updated all 10 dynamic providers that use routerModels:

  • OpenRouter
  • Requesty
  • Glama
  • Unbound
  • LiteLLM
  • Chutes (the main culprit)
  • DeepInfra
  • IO Intelligence
  • Roo
  • Vercel AI Gateway

3. Centralized default model logic

Created getProviderDefaultModelId() function to centralize provider default model logic and reduce import bloat.

4. Added optional chaining for TypeError prevention

Added optional chaining (?.) to all router model accesses to safely handle cases where router models are undefined during provider transitions.

Benefits

  • Consistent behavior: All dynamic providers handle model validation identically
  • DRY principle: Single validation logic instead of 10+ repeated implementations
  • Bug prevention: Eliminates cross-contamination when switching providers
  • Maintainability: Future changes only need to be made in one place
  • Type safety: All changes are properly typed
  • Enhanced robustness: Prevents TypeError during provider transitions

Testing

  • TypeScript compilation passes
  • ESLint passes with no warnings
  • All pre-commit hooks pass

Fixes #9047 and supersedes #9049

- Add getValidatedModelId() helper function to validate configured model IDs
- Apply validation to all 10 dynamic providers that use routerModels
- Fix issue where switching between dynamic providers would default to sonnet 4
- Ensure configured model ID exists in current provider before using it
- Centralize provider default model ID logic in getProviderDefaultModelId()

Fixes cross-contamination when switching from OpenRouter → Chutes (second time)
where apiModelId would contain OpenRouter's model ID that doesn't exist in Chutes
@daniel-lxs daniel-lxs requested review from cte, jr and mrubens as code owners November 5, 2025 16:47
@dosubot dosubot bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Nov 5, 2025
@roomote
Copy link
Contributor

roomote bot commented Nov 5, 2025

Rooviewer Clock   See task on Roo Cloud

All issues have been resolved.

  • Fix vercel-ai-gateway validation to pass raw config value to getValidatedModelId() for consistency with other dynamic providers
Previous reviews

Mention @roomote to ask your PR Fixer agent to address the feedback.

@dosubot dosubot bot added the bug Something isn't working label Nov 5, 2025
@hannesrudolph hannesrudolph added the Issue/PR - Triage New issue. Needs quick review to confirm validity and assign labels. label Nov 5, 2025
- Fix tests that were expecting old cross-contamination behavior
- Update expectations to match new validation logic that prevents using
  configured model IDs when they don't exist in current provider's models
- All tests now pass and validate the correct fallback-to-default behavior
- Pass raw apiConfiguration.vercelAiGatewayModelId to getValidatedModelId()
- Remove ?? defaultModelId fallback that bypassed validation logic
- Now consistent with all other dynamic providers (openrouter, requesty, etc)
- Ensures helper function properly validates undefined cases
@daniel-lxs daniel-lxs moved this from Triage to PR [Needs Review] in Roo Code Roadmap Nov 5, 2025
@hannesrudolph hannesrudolph added PR - Needs Review and removed Issue/PR - Triage New issue. Needs quick review to confirm validity and assign labels. labels Nov 5, 2025
Also fixes issue #9047 where switching providers after selecting a model causes TypeError when router models are undefined during transitions.
@dosubot dosubot bot added the lgtm This PR has been approved by a maintainer label Nov 5, 2025
@mrubens mrubens merged commit d4aeca4 into main Nov 5, 2025
12 checks passed
@mrubens mrubens deleted the fix/dynamic-provider-model-validation branch November 5, 2025 19:07
@github-project-automation github-project-automation bot moved this from New to Done in Roo Code Roadmap Nov 5, 2025
@github-project-automation github-project-automation bot moved this from PR [Needs Review] to Done in Roo Code Roadmap Nov 5, 2025