mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
fix: resolve model config provider via ai_provider_id (#26660)
- `site/src/pages/AISettingsPage/ProvidersPage/components/providerFormApiMap.ts`): `providerFormValuesToCreate` returns `type: "bedrock"` when the form type is `bedrock`, instead of `type: "anthropic"` with Bedrock settings. - Updated `providerFormApiMap.test.ts` to expect `type: "bedrock"` and `MockAIProviderBedrock` fixture in `entities.ts` to `type: "bedrock"`. Added Bedrock fixtures to `ModelsPageView` stories asserting the AWS Bedrock icon renders correctly. Refs: [CODAGT-549](https://linear.app/codercom/issue/CODAGT-549/bedrock-models-use-anthropic-styling-and-icons) > 🤖
This commit is contained in:
@@ -5,7 +5,9 @@ import type { ChatModelConfig } from "#/api/typesGenerated";
|
||||
import ModelsPageView from "./ModelsPageView";
|
||||
import {
|
||||
MockAnthropicProviderState,
|
||||
MockBedrockProviderState,
|
||||
MockOpenAIProviderState,
|
||||
mockBedrockClaude,
|
||||
mockClaude,
|
||||
mockDisabledModel,
|
||||
mockGPT5,
|
||||
@@ -17,8 +19,12 @@ const meta: Meta<typeof ModelsPageView> = {
|
||||
args: {
|
||||
isLoading: false,
|
||||
error: null,
|
||||
models: [mockGPT5, mockClaude, mockDisabledModel],
|
||||
providerStates: [MockOpenAIProviderState, MockAnthropicProviderState],
|
||||
models: [mockGPT5, mockClaude, mockDisabledModel, mockBedrockClaude],
|
||||
providerStates: [
|
||||
MockOpenAIProviderState,
|
||||
MockAnthropicProviderState,
|
||||
MockBedrockProviderState,
|
||||
],
|
||||
},
|
||||
parameters: {
|
||||
reactRouter: reactRouterParameters({
|
||||
@@ -45,6 +51,12 @@ export const Default: Story = {
|
||||
await expect(canvas.getByText("Claude Sonnet 4.5")).toBeInTheDocument();
|
||||
await expect(canvas.getAllByText("OpenAI").length).toBeGreaterThan(0);
|
||||
await expect(canvas.getByText("Anthropic")).toBeInTheDocument();
|
||||
await expect(
|
||||
canvas.getByText("Claude Sonnet 4.5 (Bedrock)"),
|
||||
).toBeInTheDocument();
|
||||
await expect(canvas.getByText("AWS Bedrock")).toBeInTheDocument();
|
||||
// The Bedrock model config should render the Bedrock provider icon.
|
||||
await expect(canvas.getByAltText("AWS Bedrock")).toBeInTheDocument();
|
||||
await expect(canvas.getAllByText("Enabled").length).toBeGreaterThan(0);
|
||||
await expect(canvas.getByText("Default")).toBeInTheDocument();
|
||||
await expect(canvas.getByText("Disabled")).toBeInTheDocument();
|
||||
|
||||
@@ -83,6 +83,31 @@ export const MockAnthropicProviderState: ProviderState = {
|
||||
modelConfigs: [mockClaude],
|
||||
};
|
||||
|
||||
const MockBedrockProviderConfig: ChatProviderConfig = {
|
||||
...MockOpenAIProviderConfig,
|
||||
id: "prov-bedrock",
|
||||
provider: "bedrock",
|
||||
display_name: "AWS Bedrock",
|
||||
};
|
||||
|
||||
export const mockBedrockClaude: ChatModelConfig = {
|
||||
...mockClaude,
|
||||
id: "model-bedrock-claude",
|
||||
provider: "bedrock",
|
||||
ai_provider_id: "prov-bedrock",
|
||||
model: "anthropic.claude-sonnet-4-5",
|
||||
display_name: "Claude Sonnet 4.5 (Bedrock)",
|
||||
};
|
||||
|
||||
export const MockBedrockProviderState: ProviderState = {
|
||||
...MockOpenAIProviderState,
|
||||
key: "prov-bedrock",
|
||||
provider: "bedrock",
|
||||
label: "AWS Bedrock",
|
||||
providerConfig: MockBedrockProviderConfig,
|
||||
modelConfigs: [mockBedrockClaude],
|
||||
};
|
||||
|
||||
export const MockCopilotProviderState: ProviderState = {
|
||||
...MockOpenAIProviderState,
|
||||
key: "prov-copilot",
|
||||
|
||||
@@ -139,8 +139,12 @@ describe("parseBedrockRegionFromBaseUrl", () => {
|
||||
});
|
||||
|
||||
describe("isBedrockProvider", () => {
|
||||
it("recognises a discriminated bedrock provider", () => {
|
||||
expect(isBedrockProvider(MockAIProviderBedrock)).toBe(true);
|
||||
it("recognises a legacy bedrock provider stored as type=anthropic", () => {
|
||||
const provider: AIProvider = {
|
||||
...MockAIProviderBedrock,
|
||||
type: "anthropic",
|
||||
};
|
||||
expect(isBedrockProvider(provider)).toBe(true);
|
||||
});
|
||||
|
||||
it("recognises a provider with explicit bedrock type", () => {
|
||||
@@ -332,9 +336,9 @@ describe("providerFormValuesToCreate", () => {
|
||||
});
|
||||
|
||||
describe("Bedrock", () => {
|
||||
it('maps Bedrock to a wire `type:"anthropic"`', () => {
|
||||
it('maps Bedrock to a wire `type:"bedrock"`', () => {
|
||||
const req = providerFormValuesToCreate(baseBedrockFormValues);
|
||||
expect(req.type).toBe("anthropic");
|
||||
expect(req.type).toBe("bedrock");
|
||||
});
|
||||
|
||||
it("derives the region from a canonical AWS URL", () => {
|
||||
@@ -669,10 +673,10 @@ describe("aiProviderToFormValues", () => {
|
||||
expect(values.smallFastModel).toBe("anthropic.claude-haiku-4-5");
|
||||
});
|
||||
|
||||
it("seeds Bedrock form values from an explicit Bedrock provider type", () => {
|
||||
it("seeds Bedrock form values from a legacy anthropic-typed provider", () => {
|
||||
const provider: AIProvider = {
|
||||
...MockAIProviderBedrock,
|
||||
type: "bedrock",
|
||||
type: "anthropic",
|
||||
};
|
||||
const values = aiProviderToFormValues(provider);
|
||||
expect(values.type).toBe("bedrock");
|
||||
@@ -723,12 +727,12 @@ describe("aiProviderToFormValues", () => {
|
||||
|
||||
it("handles a Bedrock provider whose settings are null", () => {
|
||||
// `isBedrockProvider` will return false, so the provider falls
|
||||
// through to the anthropic branch. The helper must not throw.
|
||||
// through to the generic branch. The helper must not throw.
|
||||
const provider: AIProvider = {
|
||||
...MockAIProviderBedrock,
|
||||
settings: null as unknown as AIProvider["settings"],
|
||||
};
|
||||
const values = aiProviderToFormValues(provider);
|
||||
expect(values.type).toBe("anthropic");
|
||||
expect(values.type).toBe("bedrock");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -146,7 +146,7 @@ export const providerFormValuesToCreate = (
|
||||
values.roleArn.trim(),
|
||||
);
|
||||
return {
|
||||
type: "anthropic",
|
||||
type: "bedrock",
|
||||
...base,
|
||||
settings: settings as AIProviderSettings,
|
||||
};
|
||||
|
||||
@@ -5574,13 +5574,14 @@ export const MockAIProviderAnthropic: TypesGen.AIProvider = {
|
||||
};
|
||||
|
||||
/**
|
||||
* Bedrock providers come over the wire with `type: "anthropic"` and a
|
||||
* `settings._type: "bedrock"` discriminator. `isBedrockProvider` and the
|
||||
* backend (see `coderd/ai_providers.go`) enforce this convention.
|
||||
* Bedrock providers come over the wire with `type: "bedrock"` and a
|
||||
* `settings._type: "bedrock"` discriminator. `isBedrockProvider` checks
|
||||
* both the type and the settings discriminator, and also accepts legacy
|
||||
* providers stored as `type: "anthropic"` with Bedrock settings.
|
||||
*/
|
||||
export const MockAIProviderBedrock: TypesGen.AIProvider = {
|
||||
id: "9c2e3b41-2e9f-4c97-9a4f-2e1a3d8f9f21",
|
||||
type: "anthropic",
|
||||
type: "bedrock",
|
||||
name: "bedrock",
|
||||
display_name: "Bedrock",
|
||||
base_url: "https://bedrock-runtime.us-east-2.amazonaws.com",
|
||||
|
||||
Reference in New Issue
Block a user