fix(web): disambiguate MCP language model selection for ask_codebase (#1137)
fixes #1137
what was happening
when calling ask_codebase over mcp with an explicit languageModel (or through /api/chat/blocking), it was failing with a 400 saying the model isn't configured.
the issue was that getLanguageModelKey generates ${provider}-${model}-${displayName}. since mcp clients often don't pass displayName (or only send { provider, model }), the lookup ended up comparing against undefined and failed even if the model was in config.json.
how this fixes previous attempts (#1408, #1414)
i saw the earlier discussion on #1408 where just dropping displayName broke setups having multiple configs for the same model (like different personas / reasoning efforts).
to properly handle brendan's feedback from earlier:
- if
displayNameis provided: matches exact(provider, model, displayName). - if
displayNameis omitted:- if there's only 1 matching config for that
(provider, model): picks it automatically (fixes the mcp bug). - if there are multiple configs sharing that
(provider, model): throws a clean 400 listing the availabledisplayNames so the caller knows what to pass to disambiguate. - if 0 match: returns the standard 400 not configured error.
- if there's only 1 matching config for that
- if no model is requested: falls back to the first configured model as before.
(paired with an ai assistant to help write out the tests and verify the edge cases).
tests
- added unit tests in
selectConfiguredLanguageModel.test.tscovering all branches (single candidate, exact match with display name, multiple candidate disambiguation error, unconfigured model, default fallback) -> 9/9 passed - ran full web workspace tests (
yarn workspace @sourcebot/web test) -> 139 test files passed (1,446 tests) - ran linter (
yarn workspace @sourcebot/web lint) -> clean, 0 errors
[!NOTE]
Low Risk
Localized validation change on the programmatic ask path with explicit error handling and unit tests; interactive chat routing is unchanged.
Overview
Fixes MCP ask_codebase (and the shared askCodebase path) rejecting valid { provider, model } requests because selection used getLanguageModelKey, which required displayName to line up.
selectConfiguredLanguageModel centralizes that logic: default to the first configured model when none is requested; with displayName, require an exact triple match; without it, auto-pick when provider/model is unique and return a 400 listing available displayName values when multiple configs share the same model. askCodebase now calls this helper instead of inline matching. Unit tests cover the branches; the changelog records the fix.
Reviewed by Cursor Bugbot for commit 687fee1386855a86eeb878023112425b90d49d09. Bugbot is set up for automated code reviews on this repo. Configure here.
Summary by cubic
Fixes MCP ask_codebase rejecting explicit language model selection when displayName is omitted, by matching uniquely on provider and model, returning a 400 with available names when configurations are ambiguous, and preserving the first-model fallback when no model is requested.
Bug Fixes
- Exact
provider/model/displayNamematches remain supported, and empty-stringdisplayNameis preserved in disambiguation messages. - Unconfigured models, duplicate unnamed configurations, and empty configurations return clear 400 validation errors.
- Adds unit coverage for all selection paths and updates the changelog.
Summary by CodeRabbit
- Bug Fixes
- Improved language-model selection for MCP
ask_codebase. - Models now match correctly with omitted or explicitly empty display names.
- Multiple matching configurations are clearly reported for easier resolution.
- Added clearer errors when requested models are unavailable or none are configured.
- The first configured model is selected automatically when no model is specified.
- Improved language-model selection for MCP
- Improvements
- The syncing badge now reflects live repository indexing activity.