mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: configure multiple AI Bridge providers of the same type (#23948)
_Disclaimer: produced mostly by Claude Opus 4.6 following detailed planning._ ## Summary - Support multiple instances of the same AI Bridge provider type via indexed env vars (`CODER_AIBRIDGE_PROVIDER_<N>_<KEY>`), following the `CODER_EXTERNAL_AUTH_<N>_<KEY>` pattern - Existing single-provider env vars (`CODER_AIBRIDGE_OPENAI_KEY`, etc.) continue to work unchanged - Setting both a legacy env var and an indexed provider with the same name errors at startup to prevent silent misconfiguration - Mark legacy provider fields (`OpenAI`, `Anthropic`, `Bedrock`) as deprecated in `AIBridgeConfig` in favor of `Providers` ## Example ```sh CODER_AIBRIDGE_PROVIDER_0_TYPE=anthropic CODER_AIBRIDGE_PROVIDER_0_NAME=anthropic-corp CODER_AIBRIDGE_PROVIDER_0_KEY=sk-ant-corp-xxx CODER_AIBRIDGE_PROVIDER_0_BASE_URL=https://llm-proxy.internal.example.com/anthropic CODER_AIBRIDGE_PROVIDER_1_TYPE=anthropic CODER_AIBRIDGE_PROVIDER_1_NAME=anthropic-direct CODER_AIBRIDGE_PROVIDER_1_KEY=sk-ant-direct-yyy ``` Each instance is routed by name: - /api/v2/aibridge/**anthropic-corp**/v1/messages - /api/v2/aibridge/**anthropic-direct**/v1/messages Closes [AIGOV-157](https://linear.app/codercom/issue/AIGOV-157/spike-to-understand-if-there-is-a-simple-way-to-handle-multi-api-key) --------- Signed-off-by: Danny Kopping <danny@coder.com>
This commit is contained in:
@@ -1361,7 +1361,7 @@ func TestListChatModels(t *testing.T) {
|
||||
|
||||
ctx := testutil.Context(t, testutil.WaitLong)
|
||||
values := chatDeploymentValues(t)
|
||||
values.AI.BridgeConfig.OpenAI.Key = serpent.String("deployment-openai-key")
|
||||
values.AI.BridgeConfig.LegacyOpenAI.Key = serpent.String("deployment-openai-key")
|
||||
client := newChatClientWithDeploymentValues(t, values)
|
||||
_ = coderdtest.CreateFirstUser(t, client.Client)
|
||||
|
||||
@@ -1749,7 +1749,7 @@ func TestListChatProviders(t *testing.T) {
|
||||
|
||||
ctx := testutil.Context(t, testutil.WaitLong)
|
||||
values := chatDeploymentValues(t)
|
||||
values.AI.BridgeConfig.OpenAI.Key = serpent.String("deployment-openai-key")
|
||||
values.AI.BridgeConfig.LegacyOpenAI.Key = serpent.String("deployment-openai-key")
|
||||
client := newChatClientWithDeploymentValues(t, values)
|
||||
_ = coderdtest.CreateFirstUser(t, client.Client)
|
||||
|
||||
@@ -1903,7 +1903,7 @@ func TestCreateChatProvider(t *testing.T) {
|
||||
|
||||
ctx := testutil.Context(t, testutil.WaitLong)
|
||||
values := chatDeploymentValues(t)
|
||||
values.AI.BridgeConfig.OpenAI.Key = serpent.String("deployment-openai-key")
|
||||
values.AI.BridgeConfig.LegacyOpenAI.Key = serpent.String("deployment-openai-key")
|
||||
client := newChatClientWithDeploymentValues(t, values)
|
||||
_ = coderdtest.CreateFirstUser(t, client.Client)
|
||||
|
||||
@@ -2105,7 +2105,7 @@ func TestUpdateChatProvider(t *testing.T) {
|
||||
|
||||
ctx := testutil.Context(t, testutil.WaitLong)
|
||||
values := chatDeploymentValues(t)
|
||||
values.AI.BridgeConfig.OpenAI.Key = serpent.String("deployment-openai-key")
|
||||
values.AI.BridgeConfig.LegacyOpenAI.Key = serpent.String("deployment-openai-key")
|
||||
client := newChatClientWithDeploymentValues(t, values)
|
||||
_ = coderdtest.CreateFirstUser(t, client.Client)
|
||||
|
||||
@@ -2341,9 +2341,9 @@ func TestChatProviderAPIKeysFromDeploymentValues(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
values := chatDeploymentValues(t)
|
||||
values.AI.BridgeConfig.OpenAI.Key = serpent.String("deployment-openai-key")
|
||||
values.AI.BridgeConfig.Anthropic.Key = serpent.String("deployment-anthropic-key")
|
||||
values.AI.BridgeConfig.OpenAI.BaseURL = serpent.String("https://custom-openai.example.com")
|
||||
values.AI.BridgeConfig.LegacyOpenAI.Key = serpent.String("deployment-openai-key")
|
||||
values.AI.BridgeConfig.LegacyAnthropic.Key = serpent.String("deployment-anthropic-key")
|
||||
values.AI.BridgeConfig.LegacyOpenAI.BaseURL = serpent.String("https://custom-openai.example.com")
|
||||
|
||||
keys := coderd.ChatProviderAPIKeysFromDeploymentValues(values)
|
||||
require.Equal(t, chatprovider.ProviderAPIKeys{}, keys)
|
||||
@@ -2546,7 +2546,7 @@ func TestUserChatProviderConfigs(t *testing.T) {
|
||||
|
||||
ctx := testutil.Context(t, testutil.WaitLong)
|
||||
values := chatDeploymentValues(t)
|
||||
values.AI.BridgeConfig.OpenAI.Key = serpent.String("deployment-openai-key")
|
||||
values.AI.BridgeConfig.LegacyOpenAI.Key = serpent.String("deployment-openai-key")
|
||||
client := newChatClientWithDeploymentValues(t, values)
|
||||
_ = coderdtest.CreateFirstUser(t, client.Client)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user