GitLab Duo Integration
Power GitLab Duo Chat and Code Suggestions with Ask Sage's FedRAMP-compliant AI models
About This Integration
GitLab Duo supports self-hosted model providers through its AI Gateway. This guide walks you through connecting Ask Sage's OpenAI-, Anthropic-, and Gemini-compatible passthrough surfaces to GitLab Duo Chat, Code Suggestions, and Duo Workflow — keeping your AI traffic within FedRAMP-compliant infrastructure.
Table of Contents
Instance-Specific Base URL: The endpoints shown reflect the instance at chat.asksage.ai. The api. prefix and path suffix stay the same across deployments — only the instance segment in the middle changes based on which Ask Sage instance you are logging into. Always use the instance approved by your organization and applicable regulatory requirements, and match the base URL in your configuration to the instance you authenticate against.
Prerequisites
Provider Surfaces
Ask Sage exposes three provider-compatible surfaces. Each maps to a GitLab model family, an endpoint, and a model-identifier prefix — you need the matching row when you add a model in GitLab.
| Provider | GitLab model family | Endpoint (base URL) | Identifier prefix |
|---|---|---|---|
| OpenAI | GPT | https://api.asksage.ai/server/openai/v1 | custom_openai/ |
| Anthropic | Claude | https://api.asksage.ai/server/anthropic | anthropic/ |
| Gemini | Gemini | https://api.asksage.ai/server/google/v1beta | gemini/ |
https://api.asksage.ai/server/anthropic without a trailing /v1. GitLab's AI Gateway appends /v1/messages automatically. Including /v1 in the endpoint produces a double path (/v1/v1/messages) and causes 404 errors. Step 1: Discover Available Model IDs
Ask Sage's available models depend on your subscription tier. Retrieve the list before configuring GitLab to confirm the model IDs your account can access:
curl -s https://api.asksage.ai/server/openai/v1/models \
-H "Authorization: Bearer $ASK_SAGE_API_KEY" \
| python -m json.tool | grep '"id"'When you enter model IDs in GitLab, prefix each with the matching provider identifier prefix. For example, anthropic/claude-sonnet-4-6 for a Claude model, or custom_openai/gpt5 for a GPT model.
anthropic/claude-sonnet-4-6— Anthropic Claude Sonnet 4.6custom_openai/gpt5— GPT-5gemini/gemini-2.5-flash— Google Gemini 2.5 Flash
Step 2: Verify Your API Key
Before configuring GitLab, confirm your API key and model IDs work by calling Ask Sage's passthrough surfaces directly. Use the surface that matches the provider you're configuring.
OpenAI-style passthrough
Use this when the GitLab model family is GPT and the identifier prefix is custom_openai/.
curl -X POST https://api.asksage.ai/server/openai/v1/chat/completions \
-H "Authorization: Bearer $ASK_SAGE_API_KEY" \
-H "Content-Type: application/json" \
-N \
-d '{
"model": "gpt5.5",
"stream": true,
"messages": [{"role": "user", "content": "Hello"}]
}'Anthropic-style passthrough
Use this when the GitLab model family is Claude and the identifier prefix is anthropic/. Auth may be supplied as Authorization: Bearer, x-access-tokens, or x-api-key.
curl -X POST https://api.asksage.ai/server/anthropic/v1/messages \
-H "Authorization: Bearer $ASK_SAGE_API_KEY" \
-H "Content-Type: application/json" \
-N \
-d '{
"model": "claude-sonnet-4-6",
"max_tokens": 1024,
"stream": true,
"messages": [{"role": "user", "content": "Hello"}]
}'Gemini-style passthrough
Use this when the GitLab model family is Gemini and the identifier prefix is gemini/. Authentication uses the x-access-tokens header. Model identifiers accept multiple formats: gemini-2.5-flash, models/gemini-2.5-pro, or publishers/google/models/gemini-2.5-pro.
curl -X POST \
'https://api.asksage.ai/server/google/v1beta/models/gemini-2.5-flash:streamGenerateContent' \
-H "x-access-tokens: $ASK_SAGE_API_KEY" \
-H "Content-Type: application/json" \
-N \
-d '{
"contents": [{"role": "user", "parts": [{"text": "Hello"}]}]
}'Step 3: Add Self-Hosted Models in GitLab
Add one model entry per Duo feature you want to configure.
In the upper-right corner, select Admin.
In the left sidebar, select GitLab Duo.
Under GitLab Duo Model Selection, select Configure models for GitLab Duo.
Select the Self-hosted models tab, then select Add self-hosted model.
Fill in the fields and select Save. See the recommended settings below.
Bearer token to the endpoint you configured. Duo Chat (recommended: a lightweight model)
| Field | Value |
|---|---|
| Name | Ask Sage — Duo Chat |
| Model family | GPT |
| Endpoint | https://api.asksage.ai/server/openai/v1 |
| Model identifier | custom_openai/gpt5-mini |
| API key | Your Ask Sage API key |
Code Suggestions — Completion (recommended: a capable recent model)
| Field | Value |
|---|---|
| Name | Ask Sage — Code Completion |
| Model family | Claude |
| Endpoint | https://api.asksage.ai/server/anthropic |
| Model identifier | anthropic/claude-opus-4-8 |
| API key | Your Ask Sage API key |
Code Suggestions — Generation (recommended: a frontier model)
| Field | Value |
|---|---|
| Name | Ask Sage — Code Generation |
| Model family | GPT |
| Endpoint | https://api.asksage.ai/server/openai/v1 |
| Model identifier | custom_openai/gpt5.5 |
| API key | Your Ask Sage API key |
Step 4: Assign Models to Duo Features
Navigate to Admin > GitLab Duo > Configure models for GitLab Duo and assign each model you created to its corresponding feature.
| Duo Feature | Recommended model entry |
|---|---|
| Duo Chat | Ask Sage — Duo Chat |
| Code generation | Ask Sage — Code Generation |
| Code completion | Ask Sage — Code Completion |
| Duo Workflow (agentic) | Ask Sage — Duo Chat (or a dedicated model) |
Step 5: Set the Request Timeout
GitLab's default 30-second timeout may be too short for slower models or long prompts.
Navigate to Admin > GitLab Duo > Change configuration > Request timeout and set a value appropriate for your use case:
| Use case | Recommended timeout |
|---|---|
| Fast models (GPT-4.1, Gemini Flash) | 60 seconds |
| Standard use | 120 seconds |
| Large prompts or slow models | 360 seconds |
Step 6: Verify
Health Check
Navigate to Admin > GitLab Duo > Run health check. This tests AI Gateway connectivity and confirms each configured model endpoint responds.
Rake Task
docker exec gitlab gitlab-rake "gitlab:duo:verify_self_hosted_setup[root]"Live Chat Test
Open any GitLab project and open the Duo Chat panel in the sidebar. Send a message — a response should stream within a few seconds. If nothing appears, check the logs:
# AI Gateway — outbound requests to Ask Sage
docker logs gitlab-aigw 2>&1 | grep -i "asksage\|error" | tail -20
# Workhorse — WebSocket / gRPC errors
docker exec gitlab bash -c "tail -50 /var/log/gitlab/gitlab-workhorse/current"Troubleshooting
On GitLab 19.2 and later, Workhorse reads the DAP service URL from ApplicationSetting, not Ai::Setting. If the value is only set on Ai::Setting, Workhorse reads nil and the WebSocket returns HTTP 500 with invalid target address "": missing address.
Diagnose:
docker exec gitlab gitlab-rails runner "
puts 'AppSetting: ' + ApplicationSetting.current.duo_agent_platform_service_url.inspect
fs = Ai::FeatureSetting.find_by(feature: :duo_agent_platform_agentic_chat)
puts 'Workhorse sees: ' + Gitlab::DuoWorkflow::Client.url_for(feature_setting: fs, user: User.find_by(username: 'root')).inspect
"Both values must print "gitlab-aigw:50052" — no URL scheme prefix. If either prints nil, set it:
docker exec gitlab gitlab-rails runner "ApplicationSetting.current.update!(duo_agent_platform_service_url: 'gitlab-aigw:50052', self_hosted_duo_agent_platform_service_secure: false)"When the GitLab license is a subscription-based online cloud license, GitLab instructs Workhorse to open a billing tracking stream to duo-workflow-svc.runway.gitlab.net:443. In an isolated Docker environment, the TLS certificate cannot be verified, so Workhorse aborts the WebSocket before any message reaches the AI Gateway. The Workhorse log contains: failed to open self-hosted tracking stream ... x509: certificate signed by unknown authority.
Diagnose:
docker exec gitlab gitlab-rails runner '
puts "online_cloud_license? = #{License.current&.online_cloud_license?}"
puts "should_bill? = #{Ai::SelfHostedDapBilling.should_bill?(Ai::FeatureSetting.find_by(feature: :duo_agent_platform_agentic_chat))}"
'If both print true, patch should_bill? to return false — this removes the cloud tracking stream from the Workhorse config. The patch survives gitlab-ctl restart but is lost on container recreation.
docker exec gitlab bash -c "sed -i 's/def self\.should_bill?(feature_setting)/def self.should_bill?(feature_setting)\n return false # local-dev: cloud tracking stream disabled/' /opt/gitlab/embedded/service/gitlab-rails/ee/lib/ai/self_hosted_dap_billing.rb"
docker exec gitlab gitlab-ctl restart pumaVerify the patch applied:
docker exec gitlab bash -c "grep -A2 'def self.should_bill' /opt/gitlab/embedded/service/gitlab-rails/ee/lib/ai/self_hosted_dap_billing.rb"Expected output: the line immediately after def self.should_bill? reads return false.
The AI Gateway container image does not include ss or netstat. Check the startup log instead:
docker logs gitlab-aigw 2>&1 | grep -E "gRPC server on port 50052|Started server"If the line is absent, the gRPC service did not start — often a JWKS-fetch race when the gateway started before GitLab was ready. Restart the gateway: docker restart gitlab-aigw
Ask Sage applies rate limits per API key. If you see 429s:
- Check your Ask Sage account tier limits
- Reduce concurrent Duo Chat sessions
- Switch to a model with higher rate limits on your plan
Solutions:
- Verify the model ID exactly matches what
/v1/modelsreturns — model IDs are case-sensitive - Confirm the identifier prefix matches the provider surface (
custom_openai/,anthropic/, orgemini/) - For Anthropic: enter the endpoint without
/v1— the AI Gateway appends it automatically - Confirm the model is available on your Ask Sage subscription tier
Additional Resources
- GitLab: Configure Duo features to use self-hosted models
- GitLab: Supported LLM serving platforms
- GitLab: Duo self-hosted overview