mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: route extra ai_provider_types through OpenAI and Anthropic providers (#25722)
_Disclosure:_ _produced_ _with_ _Claude_ _Opus_ _4\.7_ AI Gateway only supports Anthropic (+Bedrock), OpenAI, and Copilot providers at present. All other types (Vercel, Gemini, etc) will be mapped to OpenAI since they support OpenAI-compatible endpoints.
This commit is contained in:
+25
-12
@@ -56,7 +56,6 @@ import (
|
||||
|
||||
"cdr.dev/slog/v3"
|
||||
"cdr.dev/slog/v3/sloggers/sloghuman"
|
||||
"github.com/coder/coder/v2/aibridge"
|
||||
"github.com/coder/coder/v2/buildinfo"
|
||||
"github.com/coder/coder/v2/cli/clilog"
|
||||
"github.com/coder/coder/v2/cli/cliui"
|
||||
@@ -3008,11 +3007,10 @@ func ReadAIProvidersFromEnv(logger slog.Logger, environ []string) ([]codersdk.AI
|
||||
return nil, xerrors.Errorf("provider %d: TYPE is required", i)
|
||||
}
|
||||
|
||||
switch p.Type {
|
||||
case aibridge.ProviderOpenAI, aibridge.ProviderAnthropic, aibridge.ProviderCopilot:
|
||||
default:
|
||||
return nil, xerrors.Errorf("provider %d: unknown TYPE %q (must be %s, %s, or %s)",
|
||||
i, p.Type, aibridge.ProviderOpenAI, aibridge.ProviderAnthropic, aibridge.ProviderCopilot)
|
||||
providerType := database.AIProviderType(p.Type)
|
||||
if !providerType.Valid() {
|
||||
return nil, xerrors.Errorf("provider %d: unknown TYPE %q (must be one of: %v)",
|
||||
i, p.Type, database.AllAIProviderTypeValues())
|
||||
}
|
||||
|
||||
var bedrockKey, bedrockSecret string
|
||||
@@ -3028,21 +3026,36 @@ func ReadAIProvidersFromEnv(logger slog.Logger, environ []string) ([]codersdk.AI
|
||||
)
|
||||
isBedrock := codersdk.IsBedrockConfigured(p.BedrockBaseURL, settings)
|
||||
|
||||
if p.Type != aibridge.ProviderAnthropic && isBedrock {
|
||||
return nil, xerrors.Errorf("provider %d (%s): BEDROCK_* fields are only supported with TYPE %q",
|
||||
i, p.Type, aibridge.ProviderAnthropic)
|
||||
// BEDROCK_* fields are accepted on anthropic (mutually exclusive
|
||||
// with KEYS) and required on bedrock. Any other TYPE rejecting
|
||||
// them prevents silently-ignored credentials.
|
||||
isBedrockType := providerType == database.AiProviderTypeBedrock
|
||||
isAnthropicType := providerType == database.AiProviderTypeAnthropic
|
||||
if !isAnthropicType && !isBedrockType && isBedrock {
|
||||
return nil, xerrors.Errorf("provider %d (%s): BEDROCK_* fields are only supported with TYPE %q or %q",
|
||||
i, p.Type, database.AiProviderTypeAnthropic, database.AiProviderTypeBedrock)
|
||||
}
|
||||
|
||||
if p.Type == aibridge.ProviderCopilot && len(p.Keys) > 0 {
|
||||
if isBedrockType && !isBedrock {
|
||||
return nil, xerrors.Errorf("provider %d (%s): TYPE %q requires BEDROCK_* fields to be configured",
|
||||
i, p.Type, database.AiProviderTypeBedrock)
|
||||
}
|
||||
|
||||
if isBedrockType && len(p.Keys) > 0 {
|
||||
return nil, xerrors.Errorf("provider %d (%s): KEY/KEYS are not supported for TYPE %q (use BEDROCK_* fields)",
|
||||
i, p.Type, database.AiProviderTypeBedrock)
|
||||
}
|
||||
|
||||
if providerType == database.AiProviderTypeCopilot && len(p.Keys) > 0 {
|
||||
return nil, xerrors.Errorf("provider %d (%s): KEY/KEYS are not supported for TYPE %q",
|
||||
i, p.Type, aibridge.ProviderCopilot)
|
||||
i, p.Type, database.AiProviderTypeCopilot)
|
||||
}
|
||||
|
||||
// An Anthropic provider authenticates either via a bearer
|
||||
// token (KEYS) or via Bedrock (BEDROCK_*), not both. Surface
|
||||
// the conflict here so misconfigured deployments fail before
|
||||
// any DB work happens at server startup.
|
||||
if p.Type == aibridge.ProviderAnthropic && len(p.Keys) > 0 && isBedrock {
|
||||
if isAnthropicType && len(p.Keys) > 0 && isBedrock {
|
||||
return nil, xerrors.Errorf("provider %d (%s): KEY/KEYS and BEDROCK_* fields are mutually exclusive",
|
||||
i, p.Type)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user