Skip to content

Commit 6ff0210

Browse files
PierrunoYTclaude
andcommitted
fix(bedrock): reset ARN-specific settings when selecting from the catalogue
Upstream now records the custom ARN's underlying model in awsCustomArnBaseModelId and prefers it over a model named in an inference-profile ARN. Selecting a discovered ARN kept that choice and the model limits from the previous ARN, so the new ARN could inherit the wrong model's capabilities. Clear them exactly as typing a new ARN does, and keep them when the current ARN is selected again. Also cover stale catalogue replies when explicit IAM credentials (access key, secret key, session token) change during discovery. Co-Authored-By: Claude Opus 5.5 <[email protected]>
1 parent 4fe4793 commit 6ff0210

3 files changed

Lines changed: 84 additions & 53 deletions

File tree

‎webview-ui/src/components/settings/providers/Bedrock.tsx‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,14 @@ export const Bedrock = ({
260260
apiConfiguration={apiConfiguration}
261261
onSelect={(arn) => {
262262
setApiConfigurationField("apiModelId", "custom-arn")
263+
if (arn === apiConfiguration.awsCustomArn) return
264+
// Like typing a new ARN: the underlying model and limits belong to the previous ARN.
263265
setApiConfigurationField("awsCustomArn", arn)
266+
setApiConfigurationField("awsCustomArnBaseModelId", "")
267+
setApiConfigurationField("modelMaxTokens", undefined)
268+
setApiConfigurationField("modelMaxThinkingTokens", undefined)
269+
setApiConfigurationField("reasoningEffort", undefined)
270+
setApiConfigurationField("awsModelContextWindow", undefined)
264271
}}
265272
/>
266273
)}

‎webview-ui/src/components/settings/providers/__tests__/Bedrock.spec.tsx‎

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -142,16 +142,13 @@ describe("Bedrock Component", () => {
142142
expect(!!screen.queryByRole("button", { name: "settings:providers.awsCatalogRefresh" })).toBe(visible)
143143
})
144144

145-
it("selects a discovered ARN into the edit buffer without saving or enabling routing", () => {
146-
render(
147-
<Bedrock
148-
apiConfiguration={{ awsRegion: "eu-west-3" }}
149-
setApiConfigurationField={mockSetApiConfigurationField}
150-
/>,
151-
)
145+
const discoveredArn = "arn:aws:bedrock:eu-west-3:123456789012:inference-profile/eu.model"
146+
147+
const selectDiscoveredArn = (apiConfiguration: ProviderSettings) => {
148+
render(<Bedrock apiConfiguration={apiConfiguration} setApiConfigurationField={mockSetApiConfigurationField} />)
152149
fireEvent.click(screen.getByRole("button", { name: "settings:providers.awsCatalogRefresh" }))
153150
const request = vi.mocked(vscode.postMessage).mock.calls[0][0]
154-
const arn = "arn:aws:bedrock:eu-west-3:123456789012:inference-profile/eu.model"
151+
const arn = discoveredArn
155152
act(() =>
156153
window.dispatchEvent(
157154
new MessageEvent("message", {
@@ -165,13 +162,30 @@ describe("Bedrock Component", () => {
165162
)
166163
const catalogSelect = screen.getByRole("option", { name: /Discovered/ }).closest("select")!
167164
fireEvent.change(catalogSelect, { target: { value: arn } })
165+
}
166+
167+
it("selects a discovered ARN into the edit buffer without saving or enabling routing", () => {
168+
selectDiscoveredArn({ awsRegion: "eu-west-3", awsCustomArnBaseModelId: "other", modelMaxTokens: 8192 })
169+
170+
// A new ARN starts from detection again, matching manual ARN entry.
168171
expect(mockSetApiConfigurationField.mock.calls).toEqual([
169172
["apiModelId", "custom-arn"],
170-
["awsCustomArn", arn],
173+
["awsCustomArn", discoveredArn],
174+
["awsCustomArnBaseModelId", ""],
175+
["modelMaxTokens", undefined],
176+
["modelMaxThinkingTokens", undefined],
177+
["reasoningEffort", undefined],
178+
["awsModelContextWindow", undefined],
171179
])
172180
expect(vscode.postMessage).toHaveBeenCalledTimes(1)
173181
})
174182

183+
it("keeps the underlying model choice when the current ARN is selected again", () => {
184+
selectDiscoveredArn({ awsRegion: "eu-west-3", awsCustomArn: discoveredArn, awsCustomArnBaseModelId: "other" })
185+
186+
expect(mockSetApiConfigurationField.mock.calls).toEqual([["apiModelId", "custom-arn"]])
187+
})
188+
175189
it.each(["awsGlobalInference", "awsCrossRegion"])("buffers explicit routing opt-in: %s", (label) => {
176190
render(
177191
<Bedrock

‎webview-ui/src/components/settings/providers/__tests__/BedrockCatalog.spec.tsx‎

Lines changed: 54 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -117,50 +117,60 @@ it.each([true, false])("sends only credentials for the selected mode (profile=%s
117117
})
118118
})
119119

120-
it.each([{ awsRegion: "us-east-1" }, { awsProfile: "other" }])(
121-
"ignores stale catalogue replies after connection settings change: %j",
122-
(change) => {
123-
const config: ProviderSettings = { awsRegion: "eu-west-3", awsUseProfile: true, awsProfile: "work" }
124-
const onSelect = vi.fn()
125-
const { rerender } = render(<BedrockCatalog apiConfiguration={config} onSelect={onSelect} />)
126-
fireEvent.click(screen.getByRole("button"))
127-
const first = vi.mocked(vscode.postMessage).mock.calls[0][0]
128-
expect(first.apiConfiguration).toEqual(expect.objectContaining(config))
129-
rerender(<BedrockCatalog apiConfiguration={{ ...config, ...change }} onSelect={onSelect} />)
130-
expect(vscode.postMessage).toHaveBeenLastCalledWith({
131-
type: BedrockModelsMessageType.cancelBedrockModels,
132-
requestId: first.requestId,
133-
})
134-
act(() =>
135-
window.dispatchEvent(
136-
new MessageEvent("message", {
137-
data: {
138-
type: BedrockModelsMessageType.bedrockModels,
139-
requestId: first.requestId,
140-
bedrockModels: [{ arn: "old", name: "Stale", kind: "global" }],
141-
},
142-
}),
143-
),
144-
)
145-
expect(screen.queryByRole("combobox")).not.toBeInTheDocument()
146-
fireEvent.click(screen.getByRole("button"))
147-
const second = vi.mocked(vscode.postMessage).mock.calls[2][0]
148-
act(() =>
149-
window.dispatchEvent(
150-
new MessageEvent("message", {
151-
data: {
152-
type: BedrockModelsMessageType.bedrockModels,
153-
requestId: second.requestId,
154-
bedrockModels: [{ arn: "new", name: "Current", kind: "geographic" }],
155-
},
156-
}),
157-
),
158-
)
159-
fireEvent.change(screen.getByRole("combobox"), { target: { value: "new" } })
160-
expect(onSelect).toHaveBeenCalledWith("new")
161-
expect(vscode.postMessage).toHaveBeenCalledTimes(3)
162-
},
163-
)
120+
const profileConfig: ProviderSettings = { awsRegion: "eu-west-3", awsUseProfile: true, awsProfile: "work" }
121+
const credentialsConfig: ProviderSettings = {
122+
awsRegion: "eu-west-3",
123+
awsAccessKey: "key",
124+
awsSecretKey: "secret",
125+
awsSessionToken: "session",
126+
}
127+
128+
it.each([
129+
{ config: profileConfig, change: { awsRegion: "us-east-1" } },
130+
{ config: profileConfig, change: { awsProfile: "other" } },
131+
{ config: credentialsConfig, change: { awsAccessKey: "rotated-key" } },
132+
{ config: credentialsConfig, change: { awsSecretKey: "rotated-secret" } },
133+
{ config: credentialsConfig, change: { awsSessionToken: "rotated-session" } },
134+
])("ignores stale catalogue replies after connection settings change: $change", ({ config, change }) => {
135+
const onSelect = vi.fn()
136+
const { rerender } = render(<BedrockCatalog apiConfiguration={config} onSelect={onSelect} />)
137+
fireEvent.click(screen.getByRole("button"))
138+
const first = vi.mocked(vscode.postMessage).mock.calls[0][0]
139+
expect(first.apiConfiguration).toEqual(expect.objectContaining(config))
140+
rerender(<BedrockCatalog apiConfiguration={{ ...config, ...change }} onSelect={onSelect} />)
141+
expect(vscode.postMessage).toHaveBeenLastCalledWith({
142+
type: BedrockModelsMessageType.cancelBedrockModels,
143+
requestId: first.requestId,
144+
})
145+
act(() =>
146+
window.dispatchEvent(
147+
new MessageEvent("message", {
148+
data: {
149+
type: BedrockModelsMessageType.bedrockModels,
150+
requestId: first.requestId,
151+
bedrockModels: [{ arn: "old", name: "Stale", kind: "global" }],
152+
},
153+
}),
154+
),
155+
)
156+
expect(screen.queryByRole("combobox")).not.toBeInTheDocument()
157+
fireEvent.click(screen.getByRole("button"))
158+
const second = vi.mocked(vscode.postMessage).mock.calls[2][0]
159+
act(() =>
160+
window.dispatchEvent(
161+
new MessageEvent("message", {
162+
data: {
163+
type: BedrockModelsMessageType.bedrockModels,
164+
requestId: second.requestId,
165+
bedrockModels: [{ arn: "new", name: "Current", kind: "geographic" }],
166+
},
167+
}),
168+
),
169+
)
170+
fireEvent.change(screen.getByRole("combobox"), { target: { value: "new" } })
171+
expect(onSelect).toHaveBeenCalledWith("new")
172+
expect(vscode.postMessage).toHaveBeenCalledTimes(3)
173+
})
164174

165175
it("shows discovery failures and allows retry without claiming availability", () => {
166176
render(<BedrockCatalog apiConfiguration={{ awsRegion: "eu-west-3" }} onSelect={vi.fn()} />)

0 commit comments

Comments
 (0)