VS Code Agentic Chat shows model selection dropdown with full list of SaaS models when self-hosted AI Gateway is configured
Summary
On cloud-connected self-managed instances (online license) with a self-hosted AI Gateway and all features assigned to self-hosted models, the VS Code Agentic Chat model picker dropdown displays the full SaaS model catalog instead of being hidden. This creates compliance concerns for customers who need to demonstrate that their instance is not using SaaS models.
See this discussion for full context: #594381 (comment 3296406511)
Current Behavior
When a self-managed instance is configured with a self-hosted AI Gateway and a self-hosted model is assigned to the duo_agent_platform_agentic_chat feature:
- The VS Code model picker dropdown shows the full SaaS model list.
- The IDE receives
{ selectableModels: [full SaaS list], pinnedModel: null }from theaiChatAvailableModelsGraphQL query. - The IDE interprets this as "user can pick from these models, nothing is locked" and renders the dropdown.
Note: The data flow itself is correct — regardless of which model a user selects in the picker, the actual request routes to the self-hosted AI Gateway and the admin-configured self-hosted model. The dropdown is cosmetic but misleading.
Root Cause
The AvailableModelsResolver (ee/app/graphql/resolvers/ai/chat/available_models_resolver.rb) returns pinnedModel: null when a self-hosted model is configured. The chain of events:
FeatureSettingSelectionServicereturns anAi::FeatureSettingobject for theduo_agent_platform_agentic_chatfeature.- The resolver calls
pinned_model_data, which checksfeature_setting.user_model_selection_available?. Ai::FeatureSettingoverrides this method to returnfalse(ee/app/models/ai/feature_setting.rb, line 183–185), even though theFeatureConfigurableconcern it includes defines it astrue.- Because
user_model_selection_available?returnsfalse,pinned_model_datashort-circuits and returnsnilbefore checking whether a model is pinned.
Meanwhile, FetchModelDefinitionsService successfully fetches the cloud model catalog (since the instance is cloud-connected), so selectableModels is fully populated with SaaS models.
The intent of user_model_selection_available? returning false was to signal "users can't select models," but the effect is the opposite: it prevents the pinning signal that would tell the IDE to hide the dropdown.
The Rails web UI handles this correctly by passing a userModelSelectionEnabled flag to the frontend, which is used both to hide the model dropdown and to skip the aiChatAvailableModels query when user model selection is not available. The IDE (LSP) does not appear to receive or respect this flag.
Expected Behavior
When a self-hosted AI Gateway is configured and a self-hosted model is assigned to the agentic chat feature:
- The model picker dropdown should not be shown in the IDE.
- The
aiChatAvailableModelsquery should either not be called, or should return a response that signals to the IDE that model selection is unavailable (e.g., emptyselectableModelsand a populatedpinnedModel).
Steps to Reproduce
- Set up a self-managed GitLab instance (online license, Duo Enterprise) with a self-hosted AI Gateway.
- Configure a self-hosted model and assign it to the
duo_agent_platform_agentic_chatfeature. - Open VS Code with the GitLab Duo extension and start an Agentic Chat session.
- Observe the model picker dropdown — it shows the full SaaS model list.
Impact
Customers with compliance requirements who need to demonstrate that their instance is not using SaaS models see a misleading UI that suggests SaaS models are available and selectable. This creates unnecessary compliance concerns and erodes trust in the self-hosted configuration.
Relevant Code
- Resolver:
ee/app/graphql/resolvers/ai/chat/available_models_resolver.rb - Feature setting model:
ee/app/models/ai/feature_setting.rb(line 183–185,user_model_selection_available?) - Model definitions service:
ee/app/services/ai/model_selection/fetch_model_definitions_service.rb - Web UI flag:
ee/app/assets/javascripts/ai/duo_agentic_chat/components/duo_agentic_chat_state_manager.vue(line 275–278)