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:

  1. The VS Code model picker dropdown shows the full SaaS model list.
  2. The IDE receives { selectableModels: [full SaaS list], pinnedModel: null } from the aiChatAvailableModels GraphQL query.
  3. 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:

  1. FeatureSettingSelectionService returns an Ai::FeatureSetting object for the duo_agent_platform_agentic_chat feature.
  2. The resolver calls pinned_model_data, which checks feature_setting.user_model_selection_available?.
  3. Ai::FeatureSetting overrides this method to return false (ee/app/models/ai/feature_setting.rb, line 183–185), even though the FeatureConfigurable concern it includes defines it as true.
  4. Because user_model_selection_available? returns false, pinned_model_data short-circuits and returns nil before 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 aiChatAvailableModels query should either not be called, or should return a response that signals to the IDE that model selection is unavailable (e.g., empty selectableModels and a populated pinnedModel).

Steps to Reproduce

  1. Set up a self-managed GitLab instance (online license, Duo Enterprise) with a self-hosted AI Gateway.
  2. Configure a self-hosted model and assign it to the duo_agent_platform_agentic_chat feature.
  3. Open VS Code with the GitLab Duo extension and start an Agentic Chat session.
  4. 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)
Edited by 🤖 GitLab Bot 🤖