diff --git a/qa/qa/resource/code_suggestions/direct_access.rb b/qa/qa/resource/code_suggestions/direct_access.rb
new file mode 100644
index 0000000000000000000000000000000000000000..8115d8b4f27dd8f3fc16382c1ff2842aa28dfabc
--- /dev/null
+++ b/qa/qa/resource/code_suggestions/direct_access.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+module QA
+  module Resource
+    module CodeSuggestions
+      class DirectAccess < Base
+        # https://docs.gitlab.com/ee/api/code_suggestions.html#fetch-direct-connection-information
+        def self.fetch_direct_connection_details(token)
+          response = Support::API.post(
+            "#{Runtime::Scenario.gitlab_address}/api/v4/code_suggestions/direct_access",
+            nil,
+            headers: { Authorization: "Bearer #{token}", 'Content-Type': 'application/json' }
+          )
+          raise "Unexpected status code #{response.code}" unless response.code == Support::API::HTTP_STATUS_CREATED
+
+          direct_connection_details = Support::API.parse_body(response)
+
+          raise "direct_connection[:base_url] should not be nil" if direct_connection_details[:base_url].nil?
+          raise "direct_connection[:token] should not be nil" if direct_connection_details[:token].nil?
+          raise "direct_connection[:headers] should not be nil" if direct_connection_details[:headers].nil?
+
+          direct_connection_details
+        end
+      end
+    end
+  end
+end
diff --git a/qa/qa/specs/features/ee/api/3_create/code_suggestions_spec.rb b/qa/qa/specs/features/ee/api/3_create/code_suggestions_spec.rb
index 7518fdb67b08f1b389bba3f092d0a5ddd3ceafcb..a689951e5e9e773ad96a5456f08ee574a63771f2 100644
--- a/qa/qa/specs/features/ee/api/3_create/code_suggestions_spec.rb
+++ b/qa/qa/specs/features/ee/api/3_create/code_suggestions_spec.rb
@@ -15,7 +15,7 @@ module QA
       end
 
       let(:token) { Resource::PersonalAccessToken.fabricate!.token }
-      let(:direct_access) { fetch_direct_connection_details(token) }
+      let(:direct_access) { Resource::CodeSuggestions::DirectAccess.fetch_direct_connection_details(token) }
 
       let(:context) do
         [
@@ -214,21 +214,6 @@ def get_direct_suggestion(prompt_data, type = 'completions')
           headers: direct_access[:headers], prompt_data: prompt_data)
       end
 
-      # https://docs.gitlab.com/ee/api/code_suggestions.html#fetch-direct-connection-information
-      def fetch_direct_connection_details(token)
-        response = Support::API.post("#{Runtime::Scenario.gitlab_address}/api/v4/code_suggestions/direct_access", nil,
-          headers: { Authorization: "Bearer #{token}", 'Content-Type': 'application/json' })
-        expect(response.code).to eq(Support::API::HTTP_STATUS_CREATED)
-
-        direct_connection_details = parse_body(response)
-
-        expect(direct_connection_details[:base_url]).not_to be_empty
-        expect(direct_connection_details[:token]).not_to be_empty
-        expect(direct_connection_details[:headers]).not_to be_empty
-
-        direct_connection_details
-      end
-
       def request_code_suggestion(url:, token:, prompt_data:, headers: {})
         response = Support::API.post(
           url,
diff --git a/qa/qa/specs/features/ee/browser_ui/16_ai_powered/duo_chat/duo_chat_spec.rb b/qa/qa/specs/features/ee/browser_ui/16_ai_powered/duo_chat/duo_chat_spec.rb
index 3e10866fd4ac79aec14e39ad6cad1cffc90981a2..9afe0c0e83971c92dc6c2f40d3ae2da451852840 100644
--- a/qa/qa/specs/features/ee/browser_ui/16_ai_powered/duo_chat/duo_chat_spec.rb
+++ b/qa/qa/specs/features/ee/browser_ui/16_ai_powered/duo_chat/duo_chat_spec.rb
@@ -5,6 +5,13 @@ module QA
   RSpec.describe 'Ai-powered', product_group: :duo_chat do
     describe 'Duo Chat' do
       let(:project) { create(:project, name: 'duo-chat-project') }
+      let(:token) { Resource::PersonalAccessToken.fabricate!.token }
+      let(:direct_access) { Resource::CodeSuggestions::DirectAccess.fetch_direct_connection_details(token) }
+      # Determine whether we are running against dotcom or a self managed cloud connector by checking
+      # the base_url of the direct connection endpoint. This lets us determine the expected response.
+      # As an orchestrated test we use an ai-gateway with a fake model, so we can assert part of the prompt
+      # https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist/-/blob/f2fec5c1ae697a7ced9b07e6812a80f3e1f2009a/ai_gateway/models/mock.py#L140
+      let(:expected_response) { direct_access[:base_url].include?('gitlab.com') ? 'GitLab' : 'mock' }
 
       shared_examples 'Duo Chat' do |testcase|
         it 'gets a response back from Duo Chat', testcase: testcase do
@@ -31,16 +38,10 @@ module QA
       context 'when initiating Duo Chat' do
         context 'on GitLab.com', :external_ai_provider,
           only: { pipeline: %i[staging staging-canary canary production] } do
-          let(:expected_response) { 'GitLab' }
-
           it_behaves_like 'Duo Chat', 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/441192'
         end
 
         context 'on Self-managed', :blocking, :orchestrated, :ai_gateway do
-          # As an orchestrated test we use an ai-gateway with a fake model, so we can assert part of the prompt
-          # https://gitlab.com/gitlab-org/gitlab/-/blob/481a3af0ded95cb24fc1e34b004d104c72ed95e4/ee/lib/gitlab/llm/chain/agents/zero_shot/executor.rb#L229-229
-          let(:expected_response) { 'mock' }
-
           it_behaves_like 'Duo Chat', 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/464684'
         end
       end
diff --git a/qa/qa/specs/features/ee/browser_ui/3_create/web_ide/duo_chat_in_web_ide_spec.rb b/qa/qa/specs/features/ee/browser_ui/3_create/web_ide/duo_chat_in_web_ide_spec.rb
index 2a5d15a7d8ae65f01ea7dfa767312bde386843de..f91032c1c0a50aa430f844edeaef266f1bc70533 100644
--- a/qa/qa/specs/features/ee/browser_ui/3_create/web_ide/duo_chat_in_web_ide_spec.rb
+++ b/qa/qa/specs/features/ee/browser_ui/3_create/web_ide/duo_chat_in_web_ide_spec.rb
@@ -24,6 +24,13 @@ module QA
       end
 
       let(:project) { create(:project, :with_readme, name: 'webide-duo-chat-project') }
+      let(:token) { Resource::PersonalAccessToken.fabricate!.token }
+      let(:direct_access) { Resource::CodeSuggestions::DirectAccess.fetch_direct_connection_details(token) }
+      # Determine whether we are running against dotcom or a self managed cloud connector by checking
+      # the base_url of the direct connection endpoint. This lets us determine the expected response.
+      # As an orchestrated test we use an ai-gateway with a fake model, so we can assert part of the prompt
+      # https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist/-/blob/f2fec5c1ae697a7ced9b07e6812a80f3e1f2009a/ai_gateway/models/mock.py#L140
+      let(:expected_response) { direct_access[:base_url].include?('gitlab.com') ? 'GitLab' : 'mock' }
 
       before do
         load_web_ide
@@ -31,16 +38,10 @@ module QA
 
       context 'on GitLab.com', :external_ai_provider,
         only: { pipeline: %i[staging staging-canary canary production] } do
-        let(:expected_response) { 'GitLab' }
-
         it_behaves_like 'Duo Chat', 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/443762'
       end
 
       context 'on Self-managed', :orchestrated, :ai_gateway do
-        # As an orchestrated test we use an ai-gateway with a fake model, so we can assert part of the prompt
-        # https://gitlab.com/gitlab-org/gitlab/-/blob/481a3af0ded95cb24fc1e34b004d104c72ed95e4/ee/lib/gitlab/llm/chain/agents/zero_shot/executor.rb#L229-229
-        let(:expected_response) { 'mock' }
-
         it_behaves_like 'Duo Chat', 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/468854'
       end
     end