mirror of
https://github.com/coder/coder.git
synced 2026-06-02 20:48:20 +00:00
feat: register multiple Copilot providers for business and enterprise upstreams (#23811)
## Description Adds support for multiple Copilot provider instances to route requests to different Copilot upstreams (individual, business, enterprise). Each instance has its own name and base URL, enabling per-upstream metrics, logs, circuit breakers, API dump, and routing. ## Changes * Add Copilot business and enterprise provider names and host constants * Register three Copilot provider instances in aibridged (default, business, enterprise) * Update `defaultAIBridgeProvider` in `aibridgeproxy` to route new Copilot hosts to their corresponding providers ## Related * Depends on: https://github.com/coder/aibridge/pull/240 * Closes: https://github.com/coder/aibridge/issues/152 Note: documentation changes will be added in a follow-up PR. _Disclaimer: initially produced by Claude Opus 4.6, heavily modified and reviewed by @ssncferreira ._
This commit is contained in:
+6
-2
@@ -857,13 +857,17 @@ aibridgeproxy:
|
||||
# Comma-separated list of AI provider domains for which HTTPS traffic will be
|
||||
# decrypted and routed through AI Bridge. Requests to other domains will be
|
||||
# tunneled directly without decryption. Supported domains: api.anthropic.com,
|
||||
# api.openai.com, api.individual.githubcopilot.com.
|
||||
# (default: api.anthropic.com,api.openai.com,api.individual.githubcopilot.com,
|
||||
# api.openai.com, api.individual.githubcopilot.com,
|
||||
# api.business.githubcopilot.com, api.enterprise.githubcopilot.com.
|
||||
# (default:
|
||||
# api.anthropic.com,api.openai.com,api.individual.githubcopilot.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,
|
||||
# type: string-array)
|
||||
domain_allowlist:
|
||||
- api.anthropic.com
|
||||
- api.openai.com
|
||||
- api.individual.githubcopilot.com
|
||||
- api.business.githubcopilot.com
|
||||
- api.enterprise.githubcopilot.com
|
||||
# URL of an upstream HTTP proxy to chain tunneled (non-allowlisted) requests
|
||||
# through. Format: http://[user:pass@]host:port or https://[user:pass@]host:port.
|
||||
# (default: <unset>, type: string)
|
||||
|
||||
@@ -20,6 +20,14 @@ const HeaderCoderToken = "X-Coder-AI-Governance-Token" //nolint:gosec // This is
|
||||
// request forwarded to aibridged for cross-service log correlation.
|
||||
const HeaderCoderRequestID = "X-Coder-AI-Governance-Request-Id"
|
||||
|
||||
// Copilot provider.
|
||||
const (
|
||||
ProviderCopilotBusiness = "copilot-business"
|
||||
HostCopilotBusiness = "api.business.githubcopilot.com"
|
||||
ProviderCopilotEnterprise = "copilot-enterprise"
|
||||
HostCopilotEnterprise = "api.enterprise.githubcopilot.com"
|
||||
)
|
||||
|
||||
// IsBYOK reports whether the request is using BYOK mode, determined
|
||||
// by the presence of the X-Coder-AI-Governance-Token header.
|
||||
func IsBYOK(header http.Header) bool {
|
||||
|
||||
+11
-9
@@ -3923,15 +3923,17 @@ Write out the current server config as YAML to stdout.`,
|
||||
YAML: "key_file",
|
||||
},
|
||||
{
|
||||
Name: "AI Bridge Proxy Domain Allowlist",
|
||||
Description: "Comma-separated list of AI provider domains for which HTTPS traffic will be decrypted and routed through AI Bridge. Requests to other domains will be tunneled directly without decryption. Supported domains: api.anthropic.com, api.openai.com, api.individual.githubcopilot.com.",
|
||||
Flag: "aibridge-proxy-domain-allowlist",
|
||||
Env: "CODER_AIBRIDGE_PROXY_DOMAIN_ALLOWLIST",
|
||||
Value: &c.AI.BridgeProxyConfig.DomainAllowlist,
|
||||
Default: "api.anthropic.com,api.openai.com,api.individual.githubcopilot.com",
|
||||
Hidden: true,
|
||||
Group: &deploymentGroupAIBridgeProxy,
|
||||
YAML: "domain_allowlist",
|
||||
Name: "AI Bridge Proxy Domain Allowlist",
|
||||
Description: "Comma-separated list of AI provider domains for which HTTPS traffic will be decrypted and routed through AI Bridge. " +
|
||||
"Requests to other domains will be tunneled directly without decryption. " +
|
||||
"Supported domains: api.anthropic.com, api.openai.com, api.individual.githubcopilot.com, api.business.githubcopilot.com, api.enterprise.githubcopilot.com.",
|
||||
Flag: "aibridge-proxy-domain-allowlist",
|
||||
Env: "CODER_AIBRIDGE_PROXY_DOMAIN_ALLOWLIST",
|
||||
Value: &c.AI.BridgeProxyConfig.DomainAllowlist,
|
||||
Default: "api.anthropic.com,api.openai.com,api.individual.githubcopilot.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com",
|
||||
Hidden: true,
|
||||
Group: &deploymentGroupAIBridgeProxy,
|
||||
YAML: "domain_allowlist",
|
||||
},
|
||||
{
|
||||
Name: "AI Bridge Proxy Upstream Proxy",
|
||||
|
||||
@@ -776,6 +776,10 @@ func defaultAIBridgeProvider(host string) string {
|
||||
return aibridge.ProviderOpenAI
|
||||
case HostCopilot:
|
||||
return aibridge.ProviderCopilot
|
||||
case agplaibridge.HostCopilotBusiness:
|
||||
return agplaibridge.ProviderCopilotBusiness
|
||||
case agplaibridge.HostCopilotEnterprise:
|
||||
return agplaibridge.ProviderCopilotEnterprise
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
"github.com/coder/aibridge"
|
||||
"github.com/coder/aibridge/config"
|
||||
agplaibridge "github.com/coder/coder/v2/coderd/aibridge"
|
||||
"github.com/coder/coder/v2/coderd/tracing"
|
||||
"github.com/coder/coder/v2/codersdk"
|
||||
"github.com/coder/coder/v2/enterprise/aibridged"
|
||||
@@ -37,18 +38,31 @@ func newAIBridgeDaemon(coderAPI *coderd.API) (*aibridged.Server, error) {
|
||||
// Setup supported providers with circuit breaker config.
|
||||
providers := []aibridge.Provider{
|
||||
aibridge.NewOpenAIProvider(aibridge.OpenAIConfig{
|
||||
Name: aibridge.ProviderOpenAI,
|
||||
BaseURL: cfg.OpenAI.BaseURL.String(),
|
||||
Key: cfg.OpenAI.Key.String(),
|
||||
CircuitBreaker: cbConfig,
|
||||
SendActorHeaders: cfg.SendActorHeaders.Value(),
|
||||
}),
|
||||
aibridge.NewAnthropicProvider(aibridge.AnthropicConfig{
|
||||
Name: aibridge.ProviderAnthropic,
|
||||
BaseURL: cfg.Anthropic.BaseURL.String(),
|
||||
Key: cfg.Anthropic.Key.String(),
|
||||
CircuitBreaker: cbConfig,
|
||||
SendActorHeaders: cfg.SendActorHeaders.Value(),
|
||||
}, getBedrockConfig(cfg.Bedrock)),
|
||||
aibridge.NewCopilotProvider(aibridge.CopilotConfig{
|
||||
Name: aibridge.ProviderCopilot,
|
||||
CircuitBreaker: cbConfig,
|
||||
}),
|
||||
aibridge.NewCopilotProvider(aibridge.CopilotConfig{
|
||||
Name: agplaibridge.ProviderCopilotBusiness,
|
||||
BaseURL: "https://" + agplaibridge.HostCopilotBusiness,
|
||||
CircuitBreaker: cbConfig,
|
||||
}),
|
||||
aibridge.NewCopilotProvider(aibridge.CopilotConfig{
|
||||
Name: agplaibridge.ProviderCopilotEnterprise,
|
||||
BaseURL: "https://" + agplaibridge.HostCopilotEnterprise,
|
||||
CircuitBreaker: cbConfig,
|
||||
}),
|
||||
}
|
||||
|
||||
@@ -483,7 +483,7 @@ require (
|
||||
github.com/anthropics/anthropic-sdk-go v1.19.0
|
||||
github.com/brianvoe/gofakeit/v7 v7.14.0
|
||||
github.com/coder/agentapi-sdk-go v0.0.0-20250505131810-560d1d88d225
|
||||
github.com/coder/aibridge v1.0.8-0.20260331124826-77d597aa123b
|
||||
github.com/coder/aibridge v1.0.8-0.20260331143727-519b082ad666
|
||||
github.com/coder/aisdk-go v0.0.9
|
||||
github.com/coder/boundary v0.8.4-0.20260304164748-566aeea939ab
|
||||
github.com/coder/preview v1.0.8
|
||||
|
||||
@@ -314,8 +314,8 @@ github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2 h1:aBangftG7EVZoUb69Os
|
||||
github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2/go.mod h1:qwXFYgsP6T7XnJtbKlf1HP8AjxZZyzxMmc+Lq5GjlU4=
|
||||
github.com/coder/agentapi-sdk-go v0.0.0-20250505131810-560d1d88d225 h1:tRIViZ5JRmzdOEo5wUWngaGEFBG8OaE1o2GIHN5ujJ8=
|
||||
github.com/coder/agentapi-sdk-go v0.0.0-20250505131810-560d1d88d225/go.mod h1:rNLVpYgEVeu1Zk29K64z6Od8RBP9DwqCu9OfCzh8MR4=
|
||||
github.com/coder/aibridge v1.0.8-0.20260331124826-77d597aa123b h1:geM9hIle5JCLUlnzEIladbpltBGyDH5R+bUv9+eDCME=
|
||||
github.com/coder/aibridge v1.0.8-0.20260331124826-77d597aa123b/go.mod h1:u6WvGLMQQbk3ByeOw+LBdVgDNc/v/ujAtUc6MfvzQb4=
|
||||
github.com/coder/aibridge v1.0.8-0.20260331143727-519b082ad666 h1:y4bqYPv4N4nIFpQ2XumBKj9suQJqFSGWQvKtUsN1t8c=
|
||||
github.com/coder/aibridge v1.0.8-0.20260331143727-519b082ad666/go.mod h1:u6WvGLMQQbk3ByeOw+LBdVgDNc/v/ujAtUc6MfvzQb4=
|
||||
github.com/coder/aisdk-go v0.0.9 h1:Vzo/k2qwVGLTR10ESDeP2Ecek1SdPfZlEjtTfMveiVo=
|
||||
github.com/coder/aisdk-go v0.0.9/go.mod h1:KF6/Vkono0FJJOtWtveh5j7yfNrSctVTpwgweYWSp5M=
|
||||
github.com/coder/boundary v0.8.4-0.20260304164748-566aeea939ab h1:HrlxyTmMQpOHfSKzRU1vf5TxrmV6vL5OiWq+Dvn5qh0=
|
||||
|
||||
Reference in New Issue
Block a user