mirror of
https://github.com/coder/coder.git
synced 2026-06-02 20:48:20 +00: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:
+11
-8
@@ -320,10 +320,13 @@ func (api *API) aiProvidersUpdate(rw http.ResponseWriter, r *http.Request) {
|
||||
if req.Settings != nil {
|
||||
existing = mergeAIProviderSettings(existing, *req.Settings)
|
||||
}
|
||||
// Bedrock settings are only meaningful for anthropic-typed
|
||||
// providers; rejecting the mismatch keeps a misconfiguration
|
||||
// from sitting silently in the encrypted blob.
|
||||
if existing.Bedrock != nil && old.Type != database.AiProviderTypeAnthropic {
|
||||
// Bedrock settings are only meaningful for anthropic- or
|
||||
// bedrock-typed providers; rejecting the mismatch keeps a
|
||||
// misconfiguration from sitting silently in the encrypted
|
||||
// blob.
|
||||
if existing.Bedrock != nil &&
|
||||
old.Type != database.AiProviderTypeAnthropic &&
|
||||
old.Type != database.AiProviderTypeBedrock {
|
||||
return errAIProviderBedrockTypeMismatch
|
||||
}
|
||||
settings, err := encodeAIProviderSettings(existing)
|
||||
@@ -382,7 +385,7 @@ func (api *API) aiProvidersUpdate(rw http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
if errors.Is(err, errAIProviderBedrockTypeMismatch) {
|
||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
||||
Message: "Bedrock settings are only valid for type=anthropic.",
|
||||
Message: "Bedrock settings are only valid for type=anthropic or type=bedrock.",
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -482,9 +485,9 @@ var errBedrockRejectsAPIKeys = xerrors.New("bedrock providers do not accept api_
|
||||
|
||||
// errAIProviderBedrockTypeMismatch is the sentinel returned from
|
||||
// inside the update transaction when the post-merge settings carry a
|
||||
// Bedrock block but the provider is not anthropic-typed; the outer
|
||||
// handler translates it into a 400.
|
||||
var errAIProviderBedrockTypeMismatch = xerrors.New("bedrock settings are only valid for type=anthropic")
|
||||
// Bedrock block but the provider is not anthropic- or bedrock-typed;
|
||||
// the outer handler translates it into a 400.
|
||||
var errAIProviderBedrockTypeMismatch = xerrors.New("bedrock settings are only valid for type=anthropic or type=bedrock")
|
||||
|
||||
// errAIProviderInvalidName is returned from lookupAIProvider when the
|
||||
// idOrName parameter is neither a UUID nor a syntactically-valid name.
|
||||
|
||||
@@ -327,28 +327,23 @@ func providersFromEnv(ctx context.Context, cfg codersdk.AIBridgeConfig, logger s
|
||||
dp := desiredAIProvider{
|
||||
Name: name,
|
||||
}
|
||||
switch p.Type {
|
||||
case aibridge.ProviderOpenAI:
|
||||
dp.Type = database.AiProviderTypeOpenai
|
||||
case aibridge.ProviderAnthropic:
|
||||
dp.Type = database.AiProviderTypeAnthropic
|
||||
case aibridge.ProviderCopilot:
|
||||
dp.Type = database.AiProviderTypeCopilot
|
||||
default:
|
||||
providerType := database.AIProviderType(p.Type)
|
||||
if !providerType.Valid() {
|
||||
logger.Warn(ctx, "skipping indexed AI provider with unsupported type",
|
||||
slog.F("name", name),
|
||||
slog.F("type", p.Type),
|
||||
)
|
||||
continue
|
||||
}
|
||||
dp.Type = providerType
|
||||
|
||||
dp.BaseURL = p.BaseURL
|
||||
// Bedrock fields only apply to Anthropic. Detection goes
|
||||
// through AIProviderBedrockSettings.IsConfigured() so the
|
||||
// legacy and indexed paths agree on what counts as a Bedrock
|
||||
// provider.
|
||||
// Bedrock fields apply to Anthropic and the dedicated Bedrock
|
||||
// type. Detection goes through
|
||||
// AIProviderBedrockSettings.IsConfigured() so the legacy and
|
||||
// indexed paths agree on what counts as a Bedrock provider.
|
||||
isBedrock := false
|
||||
if dp.Type == database.AiProviderTypeAnthropic {
|
||||
if dp.Type == database.AiProviderTypeAnthropic || dp.Type == database.AiProviderTypeBedrock {
|
||||
var accessKey, accessKeySecret string
|
||||
if len(p.BedrockAccessKeys) > 0 {
|
||||
accessKey = p.BedrockAccessKeys[0]
|
||||
|
||||
@@ -371,14 +371,15 @@ func TestSeedAIProvidersFromEnv(t *testing.T) {
|
||||
db, _ := dbtestutil.NewDB(t)
|
||||
ctx := testutil.Context(t, testutil.WaitShort)
|
||||
|
||||
// vercel is a valid ai_provider_type DB value but the aibridge
|
||||
// runtime has no constructor for it, so the seed switch falls
|
||||
// into the default branch and skips the row.
|
||||
// A TYPE that isn't part of the ai_provider_type enum falls
|
||||
// into the default branch and the row is skipped rather than
|
||||
// rejected, so deployments don't fail to start over a single
|
||||
// typo'd provider.
|
||||
cfg := codersdk.AIBridgeConfig{
|
||||
Providers: []codersdk.AIProviderConfig{
|
||||
{
|
||||
Type: "vercel",
|
||||
Name: "vercel-instance",
|
||||
Type: "not-a-real-provider",
|
||||
Name: "ghost",
|
||||
BaseURL: "https://example.com",
|
||||
},
|
||||
{
|
||||
|
||||
Generated
+1
-1
@@ -15071,7 +15071,7 @@ const docTemplate = `{
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"description": "Type is the provider type: \"openai\", \"anthropic\", or \"copilot\".",
|
||||
"description": "Type is the provider type. Valid values are: \"openai\",\n\"anthropic\", \"azure\", \"bedrock\", \"google\", \"openai-compat\",\n\"openrouter\", \"vercel\", \"copilot\".",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+1
-1
@@ -13475,7 +13475,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"description": "Type is the provider type: \"openai\", \"anthropic\", or \"copilot\".",
|
||||
"description": "Type is the provider type. Valid values are: \"openai\",\n\"anthropic\", \"azure\", \"bedrock\", \"google\", \"openai-compat\",\n\"openrouter\", \"vercel\", \"copilot\".",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user