From ec3f8e20c431103a6878c2d96bf303706c045012 Mon Sep 17 00:00:00 2001 From: Amp Date: Sun, 20 Sep 2026 14:51:01 +0000 Subject: [PATCH 1/6] fix(bedrock): discover regional models and clarify inference routing Amp-Thread-ID: https://ampcode.com/threads/T-01a0bf0f-6f0a-724b-8d1f-69c1f1bfe3fc --- packages/types/src/providers/bedrock.ts | 32 ++ packages/types/src/vscode-extension-host.ts | 4 + pnpm-lock.yaml | 277 ++++++++++++++++++ src/api/providers/__tests__/bedrock.spec.ts | 25 ++ src/api/providers/bedrock.ts | 34 +-- .../fetchers/__tests__/bedrock.spec.ts | 94 ++++++ src/api/providers/fetchers/bedrock.ts | 68 +++++ ...webviewMessageHandler.routerModels.spec.ts | 39 +++ src/core/webview/webviewMessageHandler.ts | 19 ++ src/eslint-suppressions.json | 2 +- src/package.json | 5 +- webview-ui/playwright/gallery/stories.tsx | 33 +++ .../src/components/settings/ApiOptions.tsx | 1 + .../components/settings/providers/Bedrock.tsx | 75 ++++- .../settings/providers/BedrockCatalog.tsx | 106 +++++++ .../providers/__tests__/Bedrock.spec.tsx | 25 ++ .../providers/__tests__/Bedrock.visual.tsx | 12 + .../__tests__/BedrockCatalog.spec.tsx | 65 ++++ .../__screenshots__/bedrock-routing-geo.png | Bin 0 -> 73773 bytes .../bedrock-routing-global.png | Bin 0 -> 74312 bytes webview-ui/src/i18n/locales/en/settings.json | 21 +- 21 files changed, 898 insertions(+), 39 deletions(-) create mode 100644 src/api/providers/fetchers/__tests__/bedrock.spec.ts create mode 100644 src/api/providers/fetchers/bedrock.ts create mode 100644 webview-ui/src/components/settings/providers/BedrockCatalog.tsx create mode 100644 webview-ui/src/components/settings/providers/__tests__/Bedrock.visual.tsx create mode 100644 webview-ui/src/components/settings/providers/__tests__/BedrockCatalog.spec.tsx create mode 100644 webview-ui/src/components/settings/providers/__tests__/__screenshots__/bedrock-routing-geo.png create mode 100644 webview-ui/src/components/settings/providers/__tests__/__screenshots__/bedrock-routing-global.png diff --git a/packages/types/src/providers/bedrock.ts b/packages/types/src/providers/bedrock.ts index 7f5d6b214b..655611b13e 100644 --- a/packages/types/src/providers/bedrock.ts +++ b/packages/types/src/providers/bedrock.ts @@ -4,6 +4,17 @@ import type { ModelInfo } from "../model.js" export type BedrockModelId = keyof typeof bedrockModels +export const BedrockModelsMessageType = { + requestBedrockModels: "requestBedrockModels", + bedrockModels: "bedrockModels", +} as const + +export interface BedrockCatalogEntry { + arn: string + name: string + kind: "regional" | "geographic" | "global" | "application" +} + export const bedrockDefaultModelId: BedrockModelId = "anthropic.claude-sonnet-4-5-20250929-v1:0" export const bedrockDefaultPromptRouterModelId: BedrockModelId = "anthropic.claude-3-sonnet-20240229-v1:0" @@ -704,3 +715,24 @@ export const BEDROCK_SERVICE_TIER_PRICING = { FLEX: 0.5, // 50% discount from standard PRIORITY: 1.75, // 75% premium over standard } as const + +/** Resolve the bundled model selection without silently opting into a routing geography. */ +export function getBedrockInferenceModelId( + modelId: string, + region?: string, + crossRegion?: boolean, + global?: boolean, +): string { + const existingPrefix = ["global.", ...AWS_INFERENCE_PROFILE_MAPPING.map(([, prefix]) => prefix)].find((prefix) => + modelId.startsWith(prefix), + ) + if (existingPrefix) modelId = modelId.slice(existingPrefix.length) + if (global && BEDROCK_GLOBAL_INFERENCE_MODEL_IDS.some((id) => id === modelId)) { + return `global.${modelId}` + } + const prefix = + crossRegion && region + ? AWS_INFERENCE_PROFILE_MAPPING.find(([pattern]) => region.startsWith(pattern))?.[1] + : undefined + return prefix ? `${prefix}${modelId}` : modelId +} diff --git a/packages/types/src/vscode-extension-host.ts b/packages/types/src/vscode-extension-host.ts index 5f6b579779..1b19c7e285 100644 --- a/packages/types/src/vscode-extension-host.ts +++ b/packages/types/src/vscode-extension-host.ts @@ -16,6 +16,7 @@ import { RouterModelsMessageType, type ModelRecord, type RouterModels } from "./ import { LmStudioModelsMessageType } from "./providers/lm-studio.js" import { OllamaModelsMessageType } from "./providers/ollama.js" import { OpenAiModelsMessageType } from "./providers/openai.js" +import { BedrockModelsMessageType, type BedrockCatalogEntry } from "./providers/bedrock.js" import { VsCodeLmModelsMessageType } from "./providers/vscode-llm.js" import type { OpenAiCodexRateLimitInfo } from "./providers/openai-codex-rate-limits.js" import type { SkillMetadata } from "./skills.js" @@ -45,6 +46,7 @@ export interface ExtensionMessage { | typeof RouterModelsMessageType.routerModels | "zooGatewayCredentialsReady" | typeof OpenAiModelsMessageType.openAiModels + | typeof BedrockModelsMessageType.bedrockModels | typeof OllamaModelsMessageType.ollamaModels | typeof LmStudioModelsMessageType.lmStudioModels | typeof VsCodeLmModelsMessageType.vsCodeLmModels @@ -141,6 +143,7 @@ export interface ExtensionMessage { clineMessage?: ClineMessage routerModels?: RouterModels openAiModels?: string[] + bedrockModels?: BedrockCatalogEntry[] ollamaModels?: ModelRecord lmStudioModels?: ModelRecord vsCodeLmModels?: { vendor?: string; family?: string; version?: string; id?: string }[] @@ -490,6 +493,7 @@ export interface WebviewMessage { | typeof RouterModelsMessageType.flushRouterModels | typeof RouterModelsMessageType.requestRouterModels | typeof OpenAiModelsMessageType.requestOpenAiModels + | typeof BedrockModelsMessageType.requestBedrockModels | typeof OllamaModelsMessageType.requestOllamaModels | typeof LmStudioModelsMessageType.requestLmStudioModels | "requestRooModels" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 47f526185f..78e25a36b4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -424,6 +424,9 @@ importers: '@anthropic-ai/vertex-sdk': specifier: ^0.19.0 version: 0.19.0(zod@3.25.76) + '@aws-sdk/client-bedrock': + specifier: ^3.922.0 + version: 3.1136.0 '@aws-sdk/client-bedrock-runtime': specifier: ^3.922.0 version: 3.1078.0 @@ -1036,6 +1039,10 @@ packages: resolution: {integrity: sha512-GGIpsHOk+zMRQMgxd+5D7Kfhpe6qzyGP4shGzb7NwYqAEleCW9PgX5xXuVQEESkhGX5kqMkDPfT+gg6PN2gczg==} engines: {node: '>=20.0.0'} + '@aws-sdk/client-bedrock@3.1136.0': + resolution: {integrity: sha512-7WJt7duGYkrjdfv/AuRupzK0DJ0S1C/JzDNdwCFPv3ljGqpIu3N1OGrcUrTRJhnkUQQ0F7LMt0Ubw04ZLS3LVA==} + engines: {node: '>=20.0.0'} + '@aws-sdk/client-cognito-identity@3.1078.0': resolution: {integrity: sha512-BYy0X/+GMXlitKShxkdTsCexWwDrn8usY2Y2Z06M5MSi4aRT3Ce5ilyA6OubQUqOWfsmDMYrm8oBNaTIcQFyrg==} engines: {node: '>=20.0.0'} @@ -1044,6 +1051,10 @@ packages: resolution: {integrity: sha512-WRWEgIq6vx+NU6ot3VrRu4Jovj9MIObitSi6of/GV5THDDPccBhivCRNkWJutMM+m3GvdeI3l/UbGNcoOobxOA==} engines: {node: '>=20.0.0'} + '@aws-sdk/core@3.978.0': + resolution: {integrity: sha512-2yX9LUmxPklVjSGTb8dfnWRJSiFQ3TeH2nn7G1mdKHTfnabzF0+gfrS8rYfLWmZrQ8A3mEcxMJjRc51dL5KWaA==} + engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-cognito-identity@3.972.52': resolution: {integrity: sha512-m+akZFJsghShferf2xsMw0Hogl1jNIJl2zUoZBNTFyWvlaOj1aK5sMTzcnw8m1dICvlQ+lC4T1OPGGsmZ+ezXA==} engines: {node: '>=20.0.0'} @@ -1052,34 +1063,66 @@ packages: resolution: {integrity: sha512-+KDA3uc/HZ1vIneGu5QMQb0gAXDYrm2vOE60+BJ7lS0YinMQ5i2oV4PR1A16XkF6K1IbSwjEHd1hQIIgMsK48w==} engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-env@3.972.71': + resolution: {integrity: sha512-JN+JHruYZw3GUZB8YGAlDk4wTDPOEAEEdEzj5nS0xodWR4smzHsN7PnK2j6IeOsDIj2aqua5DSbhXl9Gtf90FQ==} + engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-http@3.972.55': resolution: {integrity: sha512-1gBfkWY3RWeBlCoB9lIJjXMx45/54wxcgfzv6BY9otTmMrZPcNPi1v+MwZxxaCUg441NV3jsr1efnFNCXiW70g==} engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-http@3.972.73': + resolution: {integrity: sha512-uyYYnJOnlis8uQzaYGPd7N1JoioCoNpXgnkXYixsWJXHXgXyYi8WXJSDfofxJeWfQIGWLe2Nwyq60Uc7MZdVOg==} + engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-ini@3.972.60': resolution: {integrity: sha512-CV2md+PXvABwRjApWGhQ0wACy9WSFIhnUGrovLcjnjBCd/46TbuivLADtkF8IWNjtCQmQ+2IagSaxqBYqXBNAQ==} engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-ini@3.973.16': + resolution: {integrity: sha512-i++ly+0Uxa+u3ebSSyr0S/3CFhFJDxCXT3+Zj+mW2bXenEx5bKGCdTIKFu39SgXBNhWDjex/8cXUx9MUTMCrTw==} + engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-login@3.972.59': resolution: {integrity: sha512-JG4S9yyA1GFzJdJXqLKrUzZbyK+VDp2QIsJD7YOicJHAhqymfHpDJIok2dLnhOdVB0I37RjdC53uOwCMVS00gw==} engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-login@3.972.78': + resolution: {integrity: sha512-eUtswnXu0+Ii9ieRK+0L7aPFV3Z/dnW2VntJzjBP9xs8s+8p5nBNuymIXtXwZ+5r5+XJP3e32nMkuZ/r0HozEA==} + engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-node@3.972.62': resolution: {integrity: sha512-S6Slq3Tx7bvFk5yc34XNADyZYTX2HUXvaFAnowGRQnhjBO8J/mP62Fn7lxvJwjaDyYm/7gh9h6HEHaltRyMFXw==} engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-node@3.972.83': + resolution: {integrity: sha512-jdso7ejzfRnatxMUZK4S/U6KbaDPCvfIV4XL+IQAPFDBt5rj5Fq595euqlK8Le4lNCMFR9oUpt+1l0aMgaayOQ==} + engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-process@3.972.53': resolution: {integrity: sha512-EhfH+MQlqOMCkXIVa8MMObPzAQqwTTtxA7KhEJiyPeuNVA8PLOOUpgK7nBrgaDaGiIDLN/9LpGdaHuDjomeRTw==} engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-process@3.972.71': + resolution: {integrity: sha512-lYmXJa4gvq4xN1lrT5NiP5vIYYKcGWAdj8y+8o6dlcateB5eF3Dn8DtmjjHKfMBrTPAMr2pebIiX/UOj8c1/UA==} + engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-sso@3.972.59': resolution: {integrity: sha512-h8793pOjcImx0SB+VcLONcaQQ57VAvKVuqyewQMRKqqH+CSXsG2dwOeLMUJPMxLdNvL7dXOM0ueTukyNUnu5mA==} engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-sso@3.973.15': + resolution: {integrity: sha512-6Jhcf4v0pSFdjk1EW2kvzuEBKD+UZ2uNcHUIglKKLndD20YhvkL2kdmDOV5/j4mYuWWwe/a1FQ1aomU86/Cg5Q==} + engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-web-identity@3.972.59': resolution: {integrity: sha512-VoyO9+vl3XVmpZwn4obskrWIkrA/Jf3lSe1E3ZERlaN9u0D4YZ6+HywC3+L98QOXqZesEfedk67gRER8tK8+8w==} engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-web-identity@3.972.77': + resolution: {integrity: sha512-uylIQSUWpfLuH2LovxEEfwzJGM/SabLOfLMg6YXu/E8jJEKUdpdILCVCQCdFvHyu/7dLJOHPMfrSwduxO56NkQ==} + engines: {node: '>=20.0.0'} + '@aws-sdk/credential-providers@3.1078.0': resolution: {integrity: sha512-V9Tr3MrNWUfTGgTMIr+WJaMC/VDbXY57BzrGDuyDZn7+vgZjAEG6nI5nMdfnTGdvV9wq1n0zZPYW2RDfcsWNCw==} engines: {node: '>=20.0.0'} @@ -1100,10 +1143,18 @@ packages: resolution: {integrity: sha512-A8PIePF9NIIOJ/4Lg1rl9xm/+QaKkHGetq+Z9wb5B+3Da31YYXRo8n7IDMh5C+HQI5eyEmjrwkGWVdYtnLtbXQ==} engines: {node: '>=20.0.0'} + '@aws-sdk/nested-clients@3.997.45': + resolution: {integrity: sha512-mooq9Q+jLa18VoM7HouczmslZU60iiB0aKc/Ztnq/luIL1ud0z4DnYprLR/ZO1gp331S9tJctM1HZr7u6YKBXQ==} + engines: {node: '>=20.0.0'} + '@aws-sdk/signature-v4-multi-region@3.996.38': resolution: {integrity: sha512-C379Sk+MiFZCfWZphKlMyLHKxV22OjoGM5KJjj5IJNJcOCWL4IGIpnEGzv1FQiRwhYXfq55SJMfxlqPE08JJ9g==} engines: {node: '>=20.0.0'} + '@aws-sdk/signature-v4-multi-region@3.996.46': + resolution: {integrity: sha512-L+2xZTye/2T96f3lwCws0Zw6GG2JHZW9e8FpVgGBeeExSKyeoZ6CWRpBml/7DNiK/O26jrgPM9F+Ay8VkgzUWQ==} + engines: {node: '>=20.0.0'} + '@aws-sdk/token-providers@3.1078.0': resolution: {integrity: sha512-/uyXLBGu3Lw1GbBA2X66hcOMnKtMcqAIF+3/eHfxBQmUeXF2sdqozDPrTfEr/TnSd0D6deZar+eVyhEqqWu29w==} engines: {node: '>=20.0.0'} @@ -1112,14 +1163,30 @@ packages: resolution: {integrity: sha512-cbietrLlHPhhmbnMPTuDS4Zj/KNGhY+3vVhn6dwjO6Dqzrwothzg2srtcY34T9mlICsTXn34avDoWLHSntP54A==} engines: {node: '>=20.0.0'} + '@aws-sdk/token-providers@3.1129.0': + resolution: {integrity: sha512-Sbl3rpzQdsG4ZK2zh0JWUYyZPKKorJlVOddA2T0DVbKJFrsW8J6wgnslxxUH04+WaBMr4A1HzJZvZX0xUvkniA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/token-providers@3.1136.0': + resolution: {integrity: sha512-CHjdpFszuNTUEQ2z1F85pOiHxpLe0fDyvTUoNAZ7YczdTMEfU6TSA7FVZelAM67L/g6xcS31U64HuBl42dSKCA==} + engines: {node: '>=20.0.0'} + '@aws-sdk/types@3.973.15': resolution: {integrity: sha512-IULn8uBV/SMtmOIANsm4WHXIOtVPBWfOWs3WGL0j/sI+KhaYehvOw0ET+9urnn8MBpiijuU/0JOpuwKOE451PQ==} engines: {node: '>=20.0.0'} + '@aws-sdk/types@3.974.5': + resolution: {integrity: sha512-LkwLL2BLbC6wNNm4JaH9mbEqBMdOZCct6VAYqhdN4U1xrWM+fUJQEfbHwQgDypapOWTRtlk25akb5afM0P8CIQ==} + engines: {node: '>=20.0.0'} + '@aws-sdk/xml-builder@3.972.33': resolution: {integrity: sha512-ezbwz9WpuLctm6o7P2t2naDhVVPI5jFGrVefVybhcKGjU57VIyT46pQVO0RI2RYkUdhdj2Z9uSIlAzGZE9NW9A==} engines: {node: '>=20.0.0'} + '@aws-sdk/xml-builder@3.972.40': + resolution: {integrity: sha512-wlFmCIGUlwF4zx/kncw+bmxTQh1HeSJq4mYV/V5cZUSJadDP3kXvGW8Rn21cimj/7y9ju+47oYWXi97vF7czaA==} + engines: {node: '>=20.0.0'} + '@aws/lambda-invoke-store@0.3.0': resolution: {integrity: sha512-sl4Bm6yiMNYrZKkqqDFWN0UfnWhlS8ivKxrYl+6t0gCLrqr8y3B2IqZZbFRkfaVVp7C/baApyh71P+LeE1A2sQ==} engines: {node: '>=18.0.0'} @@ -3079,14 +3146,30 @@ packages: resolution: {integrity: sha512-qoiY4nrk5OCu1+eIR1VB8l5DmON/oKiqrd5zZFAhXJXjJlLWQusKEW/SkBDAtGDcPaz86m9kfcE1lngU0GlM6A==} engines: {node: '>=18.0.0'} + '@smithy/core@3.34.1': + resolution: {integrity: sha512-dLcOUxz8YCv1RZUMKq6GbyUf95pLbrqh34bPvpCZ1+CByFF31BEAFewZjsGCnVsZTKdThNENfGyAgk2TJqVwSw==} + engines: {node: '>=18.0.0'} + '@smithy/credential-provider-imds@4.4.6': resolution: {integrity: sha512-B2WQ/PV/H6Jeg3lrIq6bKUfa6Hy01mtK7CGs6lhjzHA6k4aagldH6T6eEjnzKl4HI0cJnAsxfJ19pgb5PV+CVQ==} engines: {node: '>=18.0.0'} + '@smithy/credential-provider-imds@4.5.2': + resolution: {integrity: sha512-A9uSdn72ozbRUSit0eib0TW7nXuNPlaeM0zcGkJ+nE6tFcSDbnmtwoxbTCFBukVQcszDAyvsd7+rTduPTXpygg==} + engines: {node: '>=18.0.0'} + '@smithy/fetch-http-handler@5.6.3': resolution: {integrity: sha512-CwCc/7SMTj45y97MUnDTbTaxvtAsiNNRm81z3abROIuMbMsC2Iy5EKfkkVdsKrz8WExQAAMx1EJapq+9j4fFTQ==} engines: {node: '>=18.0.0'} + '@smithy/fetch-http-handler@5.8.0': + resolution: {integrity: sha512-ycSJu3tFAQ4v04CBB0agqFMVsSQ1iG3yw+SpgxRqKfaURpQD4CZ8Wn0zPMmSnOuTpTh65Vz+EA0rMrw089wvkA==} + engines: {node: '>=18.0.0'} + + '@smithy/node-http-handler@4.12.1': + resolution: {integrity: sha512-ThMkboGeONWXAelq9FvGsuJC4rOi+qyC4/zhUF58xYpxUg5sQKx2VXZYJmtNjr4dSuBJ1HeJXETQILCz3wOHvw==} + engines: {node: '>=18.0.0'} + '@smithy/node-http-handler@4.9.3': resolution: {integrity: sha512-qZTa4gQFUo8RM02rk6q5UVTDLNrQ1oS20LsepBzqq1QBVc/EHJ03OOUADcqMZiXHArW+Y7+OGY0BpdTwZRq/Yg==} engines: {node: '>=18.0.0'} @@ -3095,10 +3178,18 @@ packages: resolution: {integrity: sha512-QgHflghMoPxCJ9axiCVh8KZfbC9fuP6vkXXyK//E3cq7nLaSSyyLj0GAoqVWezYeDQmXIZhmlRvLE16jsqDK6g==} engines: {node: '>=18.0.0'} + '@smithy/signature-v4@5.7.3': + resolution: {integrity: sha512-7ImGm+FkHRLcBaRttIAMZ6bzJZWb2cJGoYjq46F2UjycujWzrL9GEN9h4w7eQyXJYnltrUhxbbieBAIRrdqpow==} + engines: {node: '>=18.0.0'} + '@smithy/types@4.15.1': resolution: {integrity: sha512-x3L0XSACF6UYzKpa9biqiRMgvH5+wnFFew9Tm/grFYqgaupPwx/+ojDPpPJM8dZON3S9tjz5U+PQYsCBd1Mw5Q==} engines: {node: '>=18.0.0'} + '@smithy/types@4.18.0': + resolution: {integrity: sha512-CgB6HHWer/vrKps24ulRIbpcpb7K4xAU7SkZ7YHzBPlwHsvsrCJFEXK421s+cJzX+ZrqtA/TuU5w1HzI7k9N8A==} + engines: {node: '>=18.0.0'} + '@stablelib/base64@1.0.1': resolution: {integrity: sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==} @@ -9029,6 +9120,18 @@ snapshots: '@smithy/types': 4.15.1 tslib: 2.8.1 + '@aws-sdk/client-bedrock@3.1136.0': + dependencies: + '@aws-sdk/core': 3.978.0 + '@aws-sdk/credential-provider-node': 3.972.83 + '@aws-sdk/token-providers': 3.1136.0 + '@aws-sdk/types': 3.974.5 + '@smithy/core': 3.34.1 + '@smithy/fetch-http-handler': 5.8.0 + '@smithy/node-http-handler': 4.12.1 + '@smithy/types': 4.18.0 + tslib: 2.8.1 + '@aws-sdk/client-cognito-identity@3.1078.0': dependencies: '@aws-sdk/core': 3.974.27 @@ -9051,6 +9154,17 @@ snapshots: bowser: 2.14.1 tslib: 2.8.1 + '@aws-sdk/core@3.978.0': + dependencies: + '@aws-sdk/types': 3.974.5 + '@aws-sdk/xml-builder': 3.972.40 + '@aws/lambda-invoke-store': 0.3.0 + '@smithy/core': 3.34.1 + '@smithy/signature-v4': 5.7.3 + '@smithy/types': 4.18.0 + bowser: 2.14.1 + tslib: 2.8.1 + '@aws-sdk/credential-provider-cognito-identity@3.972.52': dependencies: '@aws-sdk/nested-clients': 3.997.27 @@ -9067,6 +9181,14 @@ snapshots: '@smithy/types': 4.15.1 tslib: 2.8.1 + '@aws-sdk/credential-provider-env@3.972.71': + dependencies: + '@aws-sdk/core': 3.978.0 + '@aws-sdk/types': 3.974.5 + '@smithy/core': 3.34.1 + '@smithy/types': 4.18.0 + tslib: 2.8.1 + '@aws-sdk/credential-provider-http@3.972.55': dependencies: '@aws-sdk/core': 3.974.27 @@ -9077,6 +9199,16 @@ snapshots: '@smithy/types': 4.15.1 tslib: 2.8.1 + '@aws-sdk/credential-provider-http@3.972.73': + dependencies: + '@aws-sdk/core': 3.978.0 + '@aws-sdk/types': 3.974.5 + '@smithy/core': 3.34.1 + '@smithy/fetch-http-handler': 5.8.0 + '@smithy/node-http-handler': 4.12.1 + '@smithy/types': 4.18.0 + tslib: 2.8.1 + '@aws-sdk/credential-provider-ini@3.972.60': dependencies: '@aws-sdk/core': 3.974.27 @@ -9093,6 +9225,22 @@ snapshots: '@smithy/types': 4.15.1 tslib: 2.8.1 + '@aws-sdk/credential-provider-ini@3.973.16': + dependencies: + '@aws-sdk/core': 3.978.0 + '@aws-sdk/credential-provider-env': 3.972.71 + '@aws-sdk/credential-provider-http': 3.972.73 + '@aws-sdk/credential-provider-login': 3.972.78 + '@aws-sdk/credential-provider-process': 3.972.71 + '@aws-sdk/credential-provider-sso': 3.973.15 + '@aws-sdk/credential-provider-web-identity': 3.972.77 + '@aws-sdk/nested-clients': 3.997.45 + '@aws-sdk/types': 3.974.5 + '@smithy/core': 3.34.1 + '@smithy/credential-provider-imds': 4.5.2 + '@smithy/types': 4.18.0 + tslib: 2.8.1 + '@aws-sdk/credential-provider-login@3.972.59': dependencies: '@aws-sdk/core': 3.974.27 @@ -9102,6 +9250,15 @@ snapshots: '@smithy/types': 4.15.1 tslib: 2.8.1 + '@aws-sdk/credential-provider-login@3.972.78': + dependencies: + '@aws-sdk/core': 3.978.0 + '@aws-sdk/nested-clients': 3.997.45 + '@aws-sdk/types': 3.974.5 + '@smithy/core': 3.34.1 + '@smithy/types': 4.18.0 + tslib: 2.8.1 + '@aws-sdk/credential-provider-node@3.972.62': dependencies: '@aws-sdk/credential-provider-env': 3.972.53 @@ -9116,6 +9273,20 @@ snapshots: '@smithy/types': 4.15.1 tslib: 2.8.1 + '@aws-sdk/credential-provider-node@3.972.83': + dependencies: + '@aws-sdk/credential-provider-env': 3.972.71 + '@aws-sdk/credential-provider-http': 3.972.73 + '@aws-sdk/credential-provider-ini': 3.973.16 + '@aws-sdk/credential-provider-process': 3.972.71 + '@aws-sdk/credential-provider-sso': 3.973.15 + '@aws-sdk/credential-provider-web-identity': 3.972.77 + '@aws-sdk/types': 3.974.5 + '@smithy/core': 3.34.1 + '@smithy/credential-provider-imds': 4.5.2 + '@smithy/types': 4.18.0 + tslib: 2.8.1 + '@aws-sdk/credential-provider-process@3.972.53': dependencies: '@aws-sdk/core': 3.974.27 @@ -9124,6 +9295,14 @@ snapshots: '@smithy/types': 4.15.1 tslib: 2.8.1 + '@aws-sdk/credential-provider-process@3.972.71': + dependencies: + '@aws-sdk/core': 3.978.0 + '@aws-sdk/types': 3.974.5 + '@smithy/core': 3.34.1 + '@smithy/types': 4.18.0 + tslib: 2.8.1 + '@aws-sdk/credential-provider-sso@3.972.59': dependencies: '@aws-sdk/core': 3.974.27 @@ -9134,6 +9313,16 @@ snapshots: '@smithy/types': 4.15.1 tslib: 2.8.1 + '@aws-sdk/credential-provider-sso@3.973.15': + dependencies: + '@aws-sdk/core': 3.978.0 + '@aws-sdk/nested-clients': 3.997.45 + '@aws-sdk/token-providers': 3.1129.0 + '@aws-sdk/types': 3.974.5 + '@smithy/core': 3.34.1 + '@smithy/types': 4.18.0 + tslib: 2.8.1 + '@aws-sdk/credential-provider-web-identity@3.972.59': dependencies: '@aws-sdk/core': 3.974.27 @@ -9143,6 +9332,15 @@ snapshots: '@smithy/types': 4.15.1 tslib: 2.8.1 + '@aws-sdk/credential-provider-web-identity@3.972.77': + dependencies: + '@aws-sdk/core': 3.978.0 + '@aws-sdk/nested-clients': 3.997.45 + '@aws-sdk/types': 3.974.5 + '@smithy/core': 3.34.1 + '@smithy/types': 4.18.0 + tslib: 2.8.1 + '@aws-sdk/credential-providers@3.1078.0': dependencies: '@aws-sdk/client-cognito-identity': 3.1078.0 @@ -9198,6 +9396,17 @@ snapshots: '@smithy/types': 4.15.1 tslib: 2.8.1 + '@aws-sdk/nested-clients@3.997.45': + dependencies: + '@aws-sdk/core': 3.978.0 + '@aws-sdk/signature-v4-multi-region': 3.996.46 + '@aws-sdk/types': 3.974.5 + '@smithy/core': 3.34.1 + '@smithy/fetch-http-handler': 5.8.0 + '@smithy/node-http-handler': 4.12.1 + '@smithy/types': 4.18.0 + tslib: 2.8.1 + '@aws-sdk/signature-v4-multi-region@3.996.38': dependencies: '@aws-sdk/types': 3.973.15 @@ -9205,6 +9414,13 @@ snapshots: '@smithy/types': 4.15.1 tslib: 2.8.1 + '@aws-sdk/signature-v4-multi-region@3.996.46': + dependencies: + '@aws-sdk/types': 3.974.5 + '@smithy/signature-v4': 5.7.3 + '@smithy/types': 4.18.0 + tslib: 2.8.1 + '@aws-sdk/token-providers@3.1078.0': dependencies: '@aws-sdk/core': 3.974.27 @@ -9223,16 +9439,44 @@ snapshots: '@smithy/types': 4.15.1 tslib: 2.8.1 + '@aws-sdk/token-providers@3.1129.0': + dependencies: + '@aws-sdk/core': 3.978.0 + '@aws-sdk/nested-clients': 3.997.45 + '@aws-sdk/types': 3.974.5 + '@smithy/core': 3.34.1 + '@smithy/types': 4.18.0 + tslib: 2.8.1 + + '@aws-sdk/token-providers@3.1136.0': + dependencies: + '@aws-sdk/core': 3.978.0 + '@aws-sdk/nested-clients': 3.997.45 + '@aws-sdk/types': 3.974.5 + '@smithy/core': 3.34.1 + '@smithy/types': 4.18.0 + tslib: 2.8.1 + '@aws-sdk/types@3.973.15': dependencies: '@smithy/types': 4.15.1 tslib: 2.8.1 + '@aws-sdk/types@3.974.5': + dependencies: + '@smithy/types': 4.18.0 + tslib: 2.8.1 + '@aws-sdk/xml-builder@3.972.33': dependencies: '@smithy/types': 4.15.1 tslib: 2.8.1 + '@aws-sdk/xml-builder@3.972.40': + dependencies: + '@smithy/types': 4.18.0 + tslib: 2.8.1 + '@aws/lambda-invoke-store@0.3.0': {} '@azu/format-text@1.0.2': {} @@ -11269,18 +11513,41 @@ snapshots: '@smithy/types': 4.15.1 tslib: 2.8.1 + '@smithy/core@3.34.1': + dependencies: + '@smithy/types': 4.18.0 + tslib: 2.8.1 + '@smithy/credential-provider-imds@4.4.6': dependencies: '@smithy/core': 3.29.1 '@smithy/types': 4.15.1 tslib: 2.8.1 + '@smithy/credential-provider-imds@4.5.2': + dependencies: + '@smithy/core': 3.34.1 + '@smithy/types': 4.18.0 + tslib: 2.8.1 + '@smithy/fetch-http-handler@5.6.3': dependencies: '@smithy/core': 3.29.1 '@smithy/types': 4.15.1 tslib: 2.8.1 + '@smithy/fetch-http-handler@5.8.0': + dependencies: + '@smithy/core': 3.34.1 + '@smithy/types': 4.18.0 + tslib: 2.8.1 + + '@smithy/node-http-handler@4.12.1': + dependencies: + '@smithy/core': 3.34.1 + '@smithy/types': 4.18.0 + tslib: 2.8.1 + '@smithy/node-http-handler@4.9.3': dependencies: '@smithy/core': 3.29.1 @@ -11293,10 +11560,20 @@ snapshots: '@smithy/types': 4.15.1 tslib: 2.8.1 + '@smithy/signature-v4@5.7.3': + dependencies: + '@smithy/core': 3.34.1 + '@smithy/types': 4.18.0 + tslib: 2.8.1 + '@smithy/types@4.15.1': dependencies: tslib: 2.8.1 + '@smithy/types@4.18.0': + dependencies: + tslib: 2.8.1 + '@stablelib/base64@1.0.1': {} '@standard-schema/spec@1.1.0': {} diff --git a/src/api/providers/__tests__/bedrock.spec.ts b/src/api/providers/__tests__/bedrock.spec.ts index 917bccfa00..4e4cb6a297 100644 --- a/src/api/providers/__tests__/bedrock.spec.ts +++ b/src/api/providers/__tests__/bedrock.spec.ts @@ -94,6 +94,31 @@ describe("AwsBedrockHandler", () => { }) }) + it.each(["isn't supported", "isn’t supported.", "is not supported"])( + "explains inference-profile errors with wording %s", + async (wording) => { + handler["client"].send = vi + .fn() + .mockRejectedValue(new Error(`Invocation with on-demand throughput ${wording}`)) + const consume = async () => { + for await (const chunk of handler.createMessage("system", [{ role: "user", content: "hello" }])) { + void chunk + } + } + await expect(consume()).rejects.toThrow("Try enabling cross-region inference in settings") + }, + ) + + it("preserves a newly discovered foundation-model ID rather than invoking the default Claude model", () => { + const provider = new AwsBedrockHandler({ + apiModelId: "custom-arn", + awsRegion: "eu-west-3", + awsCustomArn: "arn:aws:bedrock:eu-west-3::foundation-model/mistral.new-model-v1:0", + }) + expect(provider.getModel().id).toBe("mistral.new-model-v1:0") + expect(provider.getModel().info.supportsReasoningBudget).not.toBe(true) + }) + describe("getModel", () => { it("should return the correct model info for a standard model", () => { const modelInfo = handler.getModel() diff --git a/src/api/providers/bedrock.ts b/src/api/providers/bedrock.ts index 9c42005545..490855ea9f 100644 --- a/src/api/providers/bedrock.ts +++ b/src/api/providers/bedrock.ts @@ -30,7 +30,7 @@ import { BEDROCK_DEFAULT_CONTEXT, AWS_INFERENCE_PROFILE_MAPPING, BEDROCK_1M_CONTEXT_MODEL_IDS, - BEDROCK_GLOBAL_INFERENCE_MODEL_IDS, + getBedrockInferenceModelId, BEDROCK_SERVICE_TIER_MODEL_IDS, BEDROCK_SERVICE_TIER_PRICING, SERVICE_TIER_KEY, @@ -352,9 +352,9 @@ export class AwsBedrockHandler extends BaseProvider implements SingleCompletionH } // Helper to guess model info from custom modelId string if not in bedrockModels - private guessModelInfoFromId(modelId: string): Partial { + private guessModelInfoFromId(modelId: string): ModelInfo { // Define a mapping for model ID patterns and their configurations - const modelConfigMap: Record> = { + const modelConfigMap: Record = { "claude-4": { maxTokens: 8192, contextWindow: 200_000, @@ -1163,9 +1163,8 @@ export class AwsBedrockHandler extends BaseProvider implements SingleCompletionH // Use heuristics for model info, then allow overrides from ProviderSettings const guessed = this.guessModelInfoFromId(modelId) model = { - id: bedrockDefaultModelId, + id: modelId || bedrockDefaultModelId, info: { - ...JSON.parse(JSON.stringify(bedrockModels[bedrockDefaultModelId])), ...guessed, }, } @@ -1216,21 +1215,12 @@ export class AwsBedrockHandler extends BaseProvider implements SingleCompletionH //a model was selected from the drop down modelConfig = this.getModelById(this.options.apiModelId as string) - // Apply Global Inference prefix if enabled and supported (takes precedence over cross-region) - const baseIdForGlobal = this.parseBaseModelId(modelConfig.id) - if ( - this.options.awsUseGlobalInference && - BEDROCK_GLOBAL_INFERENCE_MODEL_IDS.includes(baseIdForGlobal as any) - ) { - modelConfig.id = `global.${baseIdForGlobal}` - } - // Otherwise, add cross-region inference prefix if enabled - else if (this.options.awsUseCrossRegionInference && this.options.awsRegion) { - const prefix = AwsBedrockHandler.getPrefixForRegion(this.options.awsRegion) - if (prefix) { - modelConfig.id = `${prefix}${modelConfig.id}` - } - } + modelConfig.id = getBedrockInferenceModelId( + modelConfig.id, + this.options.awsRegion, + this.options.awsUseCrossRegionInference, + this.options.awsUseGlobalInference, + ) } // Check if 1M context is enabled for supported Claude 4 models @@ -1547,7 +1537,7 @@ Please try: logLevel: "error", }, ON_DEMAND_NOT_SUPPORTED: { - patterns: ["with on-demand throughput isn’t supported."], + patterns: ["on-demand throughput isn't supported", "on-demand throughput is not supported"], messageTemplate: ` 1. Try enabling cross-region inference in settings. 2. Or, create an inference profile and then leverage the "Use custom ARN..." option of the model selector in settings.`, @@ -1612,7 +1602,7 @@ Please check: return "THROTTLING" } - const errorMessage = error.message.toLowerCase() + const errorMessage = error.message.toLowerCase().replace(/[‘’]/g, "'") const errorName = error.name.toLowerCase() // Check each error type's patterns in order of specificity (most specific first) diff --git a/src/api/providers/fetchers/__tests__/bedrock.spec.ts b/src/api/providers/fetchers/__tests__/bedrock.spec.ts new file mode 100644 index 0000000000..f2a990a45a --- /dev/null +++ b/src/api/providers/fetchers/__tests__/bedrock.spec.ts @@ -0,0 +1,94 @@ +import { BedrockClient, ListFoundationModelsCommand } from "@aws-sdk/client-bedrock" +import { fromIni } from "@aws-sdk/credential-providers" +import { getBedrockCatalog } from "../bedrock" + +const { send, destroy, pages } = vi.hoisted(() => ({ send: vi.fn(), destroy: vi.fn(), pages: vi.fn() })) +vi.mock("@aws-sdk/client-bedrock", () => ({ + BedrockClient: vi.fn().mockImplementation(function () { + return { send, destroy } + }), + ListFoundationModelsCommand: vi.fn(), + paginateListInferenceProfiles: (...args: unknown[]) => pages(...args), +})) +vi.mock("@aws-sdk/credential-providers", () => ({ fromIni: vi.fn(() => "profile-provider") })) +vi.mock("../../../../utils/networkProxy", () => ({ getSystemProxyUrl: () => undefined })) + +beforeEach(() => { + vi.clearAllMocks() +}) + +it("uses the selected region and credentials, and includes every profile page with explicit routing labels", async () => { + send.mockResolvedValue({ + modelSummaries: [ + { modelArn: "foundation-new", modelName: "New model", responseStreamingSupported: true }, + { modelArn: "no-stream", responseStreamingSupported: false }, + ], + }) + pages.mockImplementation(async function* () { + yield { + inferenceProfileSummaries: [ + { + inferenceProfileArn: "geo", + inferenceProfileId: "eu.model", + status: "ACTIVE", + type: "SYSTEM_DEFINED", + }, + ], + } + yield { + inferenceProfileSummaries: [ + { + inferenceProfileArn: "world", + inferenceProfileId: "global.model", + status: "ACTIVE", + type: "SYSTEM_DEFINED", + }, + { + inferenceProfileArn: "app", + inferenceProfileId: "application", + status: "ACTIVE", + type: "APPLICATION", + }, + { inferenceProfileArn: "inactive", status: "CREATING" }, + ], + } + }) + const result = await getBedrockCatalog({ + awsRegion: "eu-west-3", + awsAccessKey: "key", + awsSecretKey: "secret", + awsSessionToken: "session", + }) + expect(BedrockClient).toHaveBeenCalledWith( + expect.objectContaining({ + region: "eu-west-3", + credentials: { accessKeyId: "key", secretAccessKey: "secret", sessionToken: "session" }, + }), + ) + expect(ListFoundationModelsCommand).toHaveBeenCalledWith({ byOutputModality: "TEXT", byInferenceType: "ON_DEMAND" }) + expect(result).toHaveLength(4) + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ arn: "foundation-new", kind: "regional" }), + expect.objectContaining({ arn: "geo", kind: "geographic" }), + expect.objectContaining({ arn: "world", kind: "global" }), + expect.objectContaining({ arn: "app", kind: "application" }), + ]), + ) + expect(destroy).toHaveBeenCalledOnce() +}) + +it("uses a profile and releases the client on permission failure without fabricating availability", async () => { + send.mockRejectedValue(new Error("AccessDenied")) + await expect( + getBedrockCatalog({ awsRegion: "us-east-1", awsUseProfile: true, awsProfile: "work" }), + ).rejects.toThrow("AccessDenied") + expect(fromIni).toHaveBeenCalledWith({ profile: "work", ignoreCache: true }) + expect(BedrockClient).toHaveBeenCalledWith(expect.objectContaining({ credentials: "profile-provider" })) + expect(destroy).toHaveBeenCalledOnce() +}) + +it("does not silently use the default credential chain when API-key authentication is selected", async () => { + await expect(getBedrockCatalog({ awsRegion: "eu-west-3", awsUseApiKey: true })).rejects.toThrow("IAM credentials") + expect(BedrockClient).not.toHaveBeenCalled() +}) diff --git a/src/api/providers/fetchers/bedrock.ts b/src/api/providers/fetchers/bedrock.ts new file mode 100644 index 0000000000..961a887868 --- /dev/null +++ b/src/api/providers/fetchers/bedrock.ts @@ -0,0 +1,68 @@ +import { BedrockClient, ListFoundationModelsCommand, paginateListInferenceProfiles } from "@aws-sdk/client-bedrock" +import { fromIni } from "@aws-sdk/credential-providers" +import { NodeHttpHandler } from "@smithy/node-http-handler" +import { HttpsProxyAgent } from "https-proxy-agent" +import { HttpProxyAgent } from "http-proxy-agent" +import type { BedrockCatalogEntry, ProviderSettings } from "@roo-code/types" +import { getSystemProxyUrl } from "../../../utils/networkProxy" + +/** Query the regional control plane, not a custom inference/runtime endpoint. */ +export async function getBedrockCatalog(options: ProviderSettings): Promise { + if (!options.awsRegion) throw new Error("Select an AWS region before refreshing the catalogue.") + if (options.awsUseApiKey) + throw new Error("Catalogue discovery requires AWS IAM credentials or an AWS profile, not a Bedrock API key.") + const proxy = getSystemProxyUrl() + const client = new BedrockClient({ + region: options.awsRegion, + maxAttempts: 2, + credentials: + options.awsUseProfile && options.awsProfile + ? fromIni({ profile: options.awsProfile, ignoreCache: true }) + : options.awsAccessKey && options.awsSecretKey + ? { + accessKeyId: options.awsAccessKey, + secretAccessKey: options.awsSecretKey, + sessionToken: options.awsSessionToken, + } + : undefined, + requestHandler: new NodeHttpHandler({ + requestTimeout: 30_000, + ...(proxy ? { httpAgent: new HttpProxyAgent(proxy), httpsAgent: new HttpsProxyAgent(proxy) } : {}), + }), + }) + const signal = AbortSignal.timeout(30_000) + try { + const result: BedrockCatalogEntry[] = [] + const foundations = await client.send( + new ListFoundationModelsCommand({ byOutputModality: "TEXT", byInferenceType: "ON_DEMAND" }), + { abortSignal: signal }, + ) + for (const model of foundations.modelSummaries ?? []) { + if (model.modelArn && model.responseStreamingSupported && model.modelLifecycle?.status !== "LEGACY") { + result.push({ + arn: model.modelArn, + name: model.modelName ?? model.modelId ?? model.modelArn, + kind: "regional", + }) + } + } + for await (const page of paginateListInferenceProfiles({ client }, {}, { abortSignal: signal })) { + for (const profile of page.inferenceProfileSummaries ?? []) { + if (!profile.inferenceProfileArn || profile.status !== "ACTIVE") continue + result.push({ + arn: profile.inferenceProfileArn, + name: profile.inferenceProfileName ?? profile.inferenceProfileId ?? profile.inferenceProfileArn, + kind: + profile.type === "APPLICATION" + ? "application" + : profile.inferenceProfileId?.startsWith("global.") + ? "global" + : "geographic", + }) + } + } + return result.sort((a, b) => a.name.localeCompare(b.name)) + } finally { + client.destroy() + } +} diff --git a/src/core/webview/__tests__/webviewMessageHandler.routerModels.spec.ts b/src/core/webview/__tests__/webviewMessageHandler.routerModels.spec.ts index 5a4b3e7be3..d0d1ca485c 100644 --- a/src/core/webview/__tests__/webviewMessageHandler.routerModels.spec.ts +++ b/src/core/webview/__tests__/webviewMessageHandler.routerModels.spec.ts @@ -5,6 +5,7 @@ import { providerIdentifiers, retiredProviderIdentifiers, RouterModelsMessageType, + BedrockModelsMessageType, } from "@roo-code/types" import { webviewMessageHandler } from "../webviewMessageHandler" @@ -57,6 +58,10 @@ vi.mock("vscode", () => ({ // Mock modelCache getModels/flushModels used by the handler const getModelsMock = vi.fn() const flushModelsMock = vi.fn() +const getBedrockCatalogMock = vi.fn() +vi.mock("../../../api/providers/fetchers/bedrock", () => ({ + getBedrockCatalog: (...args: unknown[]) => getBedrockCatalogMock(...args), +})) vi.mock("../../../api/providers/fetchers/modelCache", () => ({ getModels: (...args: any[]) => getModelsMock(...args), flushModels: (...args: any[]) => flushModelsMock(...args), @@ -102,6 +107,40 @@ describe("webviewMessageHandler - requestRouterModels provider filter", () => { }) }) + it("discovers Bedrock models using unsaved settings and correlates the response without persisting credentials", async () => { + const apiConfiguration = { awsRegion: "eu-west-3", awsAccessKey: "draft-key", awsSecretKey: "draft-secret" } + const models = [{ arn: "profile", name: "EU model", kind: "geographic" }] + getBedrockCatalogMock.mockResolvedValue(models) + await webviewMessageHandler(mockProvider, { + type: BedrockModelsMessageType.requestBedrockModels, + requestId: "draft", + apiConfiguration, + }) + expect(getBedrockCatalogMock).toHaveBeenCalledWith(apiConfiguration) + expect(mockProvider.contextProxy.setValue).not.toHaveBeenCalled() + expect(mockProvider.postMessageToWebview).toHaveBeenCalledWith({ + type: BedrockModelsMessageType.bedrockModels, + requestId: "draft", + bedrockModels: models, + }) + }) + + it("returns a correlated, sanitized Bedrock discovery failure", async () => { + getBedrockCatalogMock.mockRejectedValue(new Error("secret credential detail")) + await webviewMessageHandler(mockProvider, { + type: BedrockModelsMessageType.requestBedrockModels, + requestId: "failed", + }) + expect(mockProvider.postMessageToWebview).toHaveBeenCalledWith( + expect.objectContaining({ + type: BedrockModelsMessageType.bedrockModels, + requestId: "failed", + error: expect.stringContaining("listing"), + }), + ) + expect(JSON.stringify(mockProvider.postMessageToWebview.mock.calls)).not.toContain("secret credential detail") + }) + it("returns explicit removal error for requestRooModels", async () => { await webviewMessageHandler(mockProvider as any, { type: "requestRooModels" } as any) diff --git a/src/core/webview/webviewMessageHandler.ts b/src/core/webview/webviewMessageHandler.ts index 0dad65a480..709114d52e 100644 --- a/src/core/webview/webviewMessageHandler.ts +++ b/src/core/webview/webviewMessageHandler.ts @@ -27,6 +27,7 @@ import { LmStudioModelsMessageType, OllamaModelsMessageType, OpenAiModelsMessageType, + BedrockModelsMessageType, RouterModelsMessageType, VsCodeLmModelsMessageType, isTelemetryOptedIn, @@ -40,6 +41,7 @@ import { saveTaskMessages } from "../task-persistence" import { importRooTaskHistory } from "../task-persistence/importRooTaskHistory" import { ClineProvider } from "./ClineProvider" +import { getBedrockCatalog } from "../../api/providers/fetchers/bedrock" import { handleCheckpointRestoreOperation } from "./checkpointRestoreHandler" import { generateErrorDiagnostics } from "./diagnosticsHandler" import { @@ -1106,6 +1108,23 @@ export const webviewMessageHandler = async ( // For providers that need credentials, use their specific handlers await flushModels({ provider: routerNameFlush } as GetModelsOptions, true) break + case BedrockModelsMessageType.requestBedrockModels: { + try { + const bedrockModels = await getBedrockCatalog(message.apiConfiguration ?? {}) + await provider.postMessageToWebview({ + type: BedrockModelsMessageType.bedrockModels, + requestId: message.requestId, + bedrockModels, + }) + } catch { + await provider.postMessageToWebview({ + type: BedrockModelsMessageType.bedrockModels, + requestId: message.requestId, + error: "Could not load the regional catalogue. Check IAM credentials/profile, network access, and listing permissions (bedrock:ListFoundationModels / bedrock:ListInferenceProfiles). This discovery flow requires IAM authentication.", + }) + } + break + } case RouterModelsMessageType.requestRouterModels: { const { apiConfiguration } = await provider.getState() diff --git a/src/eslint-suppressions.json b/src/eslint-suppressions.json index d90272962b..be2a7ab366 100644 --- a/src/eslint-suppressions.json +++ b/src/eslint-suppressions.json @@ -296,7 +296,7 @@ }, "api/providers/bedrock.ts": { "@typescript-eslint/no-explicit-any": { - "count": 34 + "count": 33 } }, "api/providers/deepseek.ts": { diff --git a/src/package.json b/src/package.json index 3e873ebbf7..023af40f37 100644 --- a/src/package.json +++ b/src/package.json @@ -461,9 +461,9 @@ "dependencies": { "@anthropic-ai/sdk": "^0.109.0", "@anthropic-ai/vertex-sdk": "^0.19.0", + "@aws-sdk/client-bedrock": "^3.922.0", "@aws-sdk/client-bedrock-runtime": "^3.922.0", "@aws-sdk/credential-providers": "^3.922.0", - "@smithy/node-http-handler": "^4.0.0", "@google/genai": "^1.29.1", "@lmstudio/sdk": "^1.1.1", "@mistralai/mistralai": "^1.9.18", @@ -474,6 +474,7 @@ "@roo-code/ipc": "workspace:^", "@roo-code/telemetry": "workspace:^", "@roo-code/types": "workspace:^", + "@smithy/node-http-handler": "^4.0.0", "ai-sdk-provider-poe": "2.0.18", "async-mutex": "^0.5.0", "axios": "^1.18.1", @@ -489,9 +490,9 @@ "get-folder-size": "^5.0.0", "global-agent": "^3.0.0", "google-auth-library": "^10.2.0", + "gray-matter": "^4.0.3", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.0", - "gray-matter": "^4.0.3", "i18next": "^25.0.0", "ignore": "^7.0.3", "isbinaryfile": "^5.0.7", diff --git a/webview-ui/playwright/gallery/stories.tsx b/webview-ui/playwright/gallery/stories.tsx index 04ca36b2c6..ab9a080264 100644 --- a/webview-ui/playwright/gallery/stories.tsx +++ b/webview-ui/playwright/gallery/stories.tsx @@ -12,6 +12,39 @@ const mermaidGantt = `gantt Ship release :active, release, after scope, 3d` export const stories: Record = { + "bedrock-routing": async ({ global = false }) => { + const [{ AppProviders }, { Bedrock }, { providerIdentifiers }] = await Promise.all([ + import("../AppProviders"), + import("@/components/settings/providers/Bedrock"), + import("@roo-code/types"), + ]) + function Routing() { + const [config, setConfig] = useState({ + apiProvider: providerIdentifiers.bedrock, + apiModelId: "anthropic.claude-sonnet-4-5-20250929-v1:0", + awsRegion: "eu-west-3", + awsUseProfile: true, + awsProfile: "default", + awsUseCrossRegionInference: true, + awsUseGlobalInference: global === true, + }) + return ( +
+ + setConfig((previous) => ({ ...previous, [field]: value })) + } + /> +
+ ) + } + return ( + + + + ) + }, "accessibility-contrast": async () => { const { AccessibilityContrastGallery } = await import("@/components/ui/__tests__/AccessibilityContrast.visual.fixture") diff --git a/webview-ui/src/components/settings/ApiOptions.tsx b/webview-ui/src/components/settings/ApiOptions.tsx index 714b507774..4b39f9a14b 100644 --- a/webview-ui/src/components/settings/ApiOptions.tsx +++ b/webview-ui/src/components/settings/ApiOptions.tsx @@ -542,6 +542,7 @@ const ApiOptions = ({ apiConfiguration={apiConfiguration} setApiConfigurationField={setApiConfigurationField} selectedModelInfo={selectedModelInfo} + organizationAllowList={organizationAllowList} simplifySettings={fromWelcomeView} /> )} diff --git a/webview-ui/src/components/settings/providers/Bedrock.tsx b/webview-ui/src/components/settings/providers/Bedrock.tsx index ed554f126d..6ae2b8a427 100644 --- a/webview-ui/src/components/settings/providers/Bedrock.tsx +++ b/webview-ui/src/components/settings/providers/Bedrock.tsx @@ -6,6 +6,10 @@ import { type ProviderSettings, type ModelInfo, type BedrockServiceTier, + type OrganizationAllowList, + providerIdentifiers, + getBedrockInferenceModelId, + bedrockDefaultModelId, BEDROCK_REGIONS, BEDROCK_1M_CONTEXT_MODEL_IDS, BEDROCK_GLOBAL_INFERENCE_MODEL_IDS, @@ -16,17 +20,39 @@ import { useAppTranslation } from "@src/i18n/TranslationContext" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, StandardTooltip } from "@src/components/ui" import { inputEventTransform, noTransform } from "../transforms" +import { BedrockCatalog } from "./BedrockCatalog" type BedrockProps = { apiConfiguration: ProviderSettings setApiConfigurationField: (field: keyof ProviderSettings, value: ProviderSettings[keyof ProviderSettings]) => void selectedModelInfo?: ModelInfo + organizationAllowList?: OrganizationAllowList simplifySettings?: boolean } -export const Bedrock = ({ apiConfiguration, setApiConfigurationField, selectedModelInfo }: BedrockProps) => { +export const Bedrock = ({ + apiConfiguration, + setApiConfigurationField, + selectedModelInfo, + organizationAllowList, +}: BedrockProps) => { const { t } = useAppTranslation() const [awsEndpointSelected, setAwsEndpointSelected] = useState(!!apiConfiguration?.awsBedrockEndpointEnabled) + const allowCatalog = + !organizationAllowList || + organizationAllowList.allowAll || + organizationAllowList.providers[providerIdentifiers.bedrock]?.allowAll + const customArn = apiConfiguration.awsCustomArn + const requestModelId = customArn + ? customArn.includes(":foundation-model/") + ? getBedrockInferenceModelId(customArn.split(":foundation-model/")[1]) + : customArn + : getBedrockInferenceModelId( + apiConfiguration.apiModelId || bedrockDefaultModelId, + apiConfiguration.awsRegion, + apiConfiguration.awsUseCrossRegionInference, + apiConfiguration.awsUseGlobalInference, + ) // Check if the selected model supports 1M context (supported Claude 4 models) const supports1MContextBeta = @@ -179,22 +205,47 @@ export const Bedrock = ({ apiConfiguration, setApiConfigurationField, selectedMo )} {supportsGlobalInference && ( +
+ { + // Global Inference takes priority over cross-region when both are enabled + setApiConfigurationField("awsUseGlobalInference", checked) + }}> + {t("settings:providers.awsGlobalInference")} + +
+ {t("settings:providers.awsGlobalInferenceDescription")} +
+
+ )} +
{ - // Global Inference takes priority over cross-region when both are enabled - setApiConfigurationField("awsUseGlobalInference", checked) + setApiConfigurationField("awsUseCrossRegionInference", checked) }}> - {t("settings:providers.awsGlobalInference")} + {t("settings:providers.awsCrossRegion")} +
+ {t("settings:providers.awsCrossRegionDescription")} +
+
+
+ {t("settings:providers.awsRequestModelId")} {requestModelId} +
+
+ {t(customArn ? "settings:providers.awsArnRouting" : "settings:providers.awsBundledModels")} +
+ {allowCatalog && ( + { + setApiConfigurationField("apiModelId", "custom-arn") + setApiConfigurationField("awsCustomArn", arn) + }} + /> )} - { - setApiConfigurationField("awsUseCrossRegionInference", checked) - }}> - {t("settings:providers.awsCrossRegion")} - {selectedModelInfo?.supportsPromptCache && ( <> void +}) { + const { t } = useAppTranslation() + const [models, setModels] = useState() + const [error, setError] = useState(false) + const [loading, setLoading] = useState(false) + const requestId = useRef() + const { awsRegion, awsAccessKey, awsSecretKey, awsSessionToken, awsProfile, awsUseProfile, awsUseApiKey } = + apiConfiguration + useEffect(() => { + requestId.current = undefined + setModels(undefined) + setLoading(false) + setError(false) + const listener = ({ data }: MessageEvent) => { + if ( + data.type !== BedrockModelsMessageType.bedrockModels || + !requestId.current || + data.requestId !== requestId.current + ) + return + requestId.current = undefined + setLoading(false) + setError(!!data.error) + setModels(data.error ? undefined : (data.bedrockModels ?? [])) + } + window.addEventListener("message", listener) + return () => { + requestId.current = undefined + window.removeEventListener("message", listener) + } + }, [awsRegion, awsAccessKey, awsSecretKey, awsSessionToken, awsProfile, awsUseProfile, awsUseApiKey]) + return ( +
+ +
+ {t("settings:providers.awsCatalogDescription")} +
+ {error && ( +
+ {t("settings:providers.awsCatalogError")} +
+ )} + {models && ( + <> + + + + )} +
+ ) +} diff --git a/webview-ui/src/components/settings/providers/__tests__/Bedrock.spec.tsx b/webview-ui/src/components/settings/providers/__tests__/Bedrock.spec.tsx index b827024859..5750d0f977 100644 --- a/webview-ui/src/components/settings/providers/__tests__/Bedrock.spec.tsx +++ b/webview-ui/src/components/settings/providers/__tests__/Bedrock.spec.tsx @@ -85,6 +85,31 @@ describe("Bedrock Component", () => { vi.clearAllMocks() }) + it.each([ + [false, false, "anthropic.claude-sonnet-4-5-20250929-v1:0"], + [true, false, "eu.anthropic.claude-sonnet-4-5-20250929-v1:0"], + [true, true, "global.anthropic.claude-sonnet-4-5-20250929-v1:0"], + ] as const)( + "previews the effective model for cross-region=%s global=%s", + (awsUseCrossRegionInference, awsUseGlobalInference, expected) => { + render( + , + ) + expect(screen.getByTestId("bedrock-request-model")).toHaveTextContent(expected) + expect(screen.getByText("settings:providers.awsGlobalInferenceDescription")).toBeInTheDocument() + expect(screen.getByText("settings:providers.awsCrossRegionDescription")).toBeInTheDocument() + expect(mockSetApiConfigurationField).not.toHaveBeenCalled() + }, + ) + it("should show text field when VPC endpoint checkbox is checked", () => { // Initial render with checkbox unchecked const apiConfiguration: Partial = { diff --git a/webview-ui/src/components/settings/providers/__tests__/Bedrock.visual.tsx b/webview-ui/src/components/settings/providers/__tests__/Bedrock.visual.tsx new file mode 100644 index 0000000000..c7a37f44f9 --- /dev/null +++ b/webview-ui/src/components/settings/providers/__tests__/Bedrock.visual.tsx @@ -0,0 +1,12 @@ +import { expect, test } from "../../../../../playwright/coverage-fixture" + +for (const global of [false, true]) { + test(`shows Bedrock routing scope and effective ID (global=${global})`, async ({ page }) => { + await page.goto("/") + await page.waitForFunction(() => typeof window.mount === "function") + await page.evaluate((global) => window.mount({ story: "bedrock-routing", props: { global } }), global) + await expect(page.locator("[data-playwright-mounted]")).toHaveScreenshot( + `bedrock-routing-${global ? "global" : "geo"}.png`, + ) + }) +} diff --git a/webview-ui/src/components/settings/providers/__tests__/BedrockCatalog.spec.tsx b/webview-ui/src/components/settings/providers/__tests__/BedrockCatalog.spec.tsx new file mode 100644 index 0000000000..786465392e --- /dev/null +++ b/webview-ui/src/components/settings/providers/__tests__/BedrockCatalog.spec.tsx @@ -0,0 +1,65 @@ +import { act, fireEvent, render, screen } from "@/utils/test-utils" +import { BedrockModelsMessageType, type ProviderSettings } from "@roo-code/types" +import { vscode } from "@/utils/vscode" +import { BedrockCatalog } from "../BedrockCatalog" + +vi.mock("@/utils/vscode", () => ({ vscode: { postMessage: vi.fn() } })) + +beforeEach(() => vi.clearAllMocks()) + +it.each([{ awsRegion: "us-east-1" }, { awsProfile: "other" }])( + "ignores stale catalogue replies after connection settings change: %j", + (change) => { + const config: ProviderSettings = { awsRegion: "eu-west-3", awsUseProfile: true, awsProfile: "work" } + const onSelect = vi.fn() + const { rerender } = render() + fireEvent.click(screen.getByRole("button")) + const first = vi.mocked(vscode.postMessage).mock.calls[0][0] + expect(first.apiConfiguration).toEqual(expect.objectContaining(config)) + rerender() + act(() => + window.dispatchEvent( + new MessageEvent("message", { + data: { + type: BedrockModelsMessageType.bedrockModels, + requestId: first.requestId, + bedrockModels: [{ arn: "old", name: "Stale", kind: "global" }], + }, + }), + ), + ) + expect(screen.queryByRole("combobox")).not.toBeInTheDocument() + fireEvent.click(screen.getByRole("button")) + const second = vi.mocked(vscode.postMessage).mock.calls[1][0] + act(() => + window.dispatchEvent( + new MessageEvent("message", { + data: { + type: BedrockModelsMessageType.bedrockModels, + requestId: second.requestId, + bedrockModels: [{ arn: "new", name: "Current", kind: "geographic" }], + }, + }), + ), + ) + fireEvent.change(screen.getByRole("combobox"), { target: { value: "new" } }) + expect(onSelect).toHaveBeenCalledWith("new") + expect(vscode.postMessage).toHaveBeenCalledTimes(2) + }, +) + +it("shows discovery failures and allows retry without claiming availability", () => { + render() + fireEvent.click(screen.getByRole("button")) + const request = vi.mocked(vscode.postMessage).mock.calls[0][0] + act(() => + window.dispatchEvent( + new MessageEvent("message", { + data: { type: BedrockModelsMessageType.bedrockModels, requestId: request.requestId, error: "denied" }, + }), + ), + ) + expect(screen.getByRole("alert")).toBeInTheDocument() + expect(screen.getByRole("button")).toBeEnabled() + expect(screen.queryByRole("combobox")).not.toBeInTheDocument() +}) diff --git a/webview-ui/src/components/settings/providers/__tests__/__screenshots__/bedrock-routing-geo.png b/webview-ui/src/components/settings/providers/__tests__/__screenshots__/bedrock-routing-geo.png new file mode 100644 index 0000000000000000000000000000000000000000..6b65f287e83f24d90f96b6f9867b50a12f452205 GIT binary patch literal 73773 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 B3_Jh; literal 0 HcmV?d00001 diff --git a/webview-ui/src/components/settings/providers/__tests__/__screenshots__/bedrock-routing-global.png b/webview-ui/src/components/settings/providers/__tests__/__screenshots__/bedrock-routing-global.png new file mode 100644 index 0000000000000000000000000000000000000000..90d52959ab2b597285f3308bce5c3f2fd9987f12 GIT binary patch literal 74312 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

GBxh^f6?VS9O2*BYmkyW? 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 Sv=zYLVCm}^YroS(hW`(#xLczD literal 0 HcmV?d00001 diff --git a/webview-ui/src/i18n/locales/en/settings.json b/webview-ui/src/i18n/locales/en/settings.json index 77f8a4f86d..771eab3d11 100644 --- a/webview-ui/src/i18n/locales/en/settings.json +++ b/webview-ui/src/i18n/locales/en/settings.json @@ -630,8 +630,25 @@ "awsSecretKey": "AWS Secret Key", "awsSessionToken": "AWS Session Token", "awsRegion": "AWS Region", - "awsCrossRegion": "Use cross-region inference", - "awsGlobalInference": "Use Global inference (auto-select optimal AWS Region)", + "awsCrossRegion": "Use geographic cross-region inference", + "awsGlobalInference": "Use global inference (worldwide routing)", + "awsCrossRegionDescription": "Uses a geographic inference profile (for example eu. or us.). Processing stays within the profile’s geography, not necessarily the selected region. Some models, including Claude Sonnet 4.5, require an inference profile. Check the profile’s supported source and destination regions in AWS; a generated prefix does not guarantee availability.", + "awsGlobalInferenceDescription": "Allows processing in commercial AWS regions worldwide. When both options are enabled, global routing takes precedence for supported models. Leave this off if processing must stay within a specific geography.", + "awsRequestModelId": "Request model ID / ARN:", + "awsArnRouting": "The selected ARN controls routing; these checkboxes do not override it. Application profiles inherit the routing of their underlying model/profile. Check its destinations in AWS before use.", + "awsBundledModels": "The model picker below is a bundled, unverified list, not an account/region availability check. Refresh the regional catalogue to select an AWS model or inference profile by ARN. No routing option is enabled automatically.", + "awsCatalogRefresh": "Refresh regional AWS catalogue", + "awsCatalogLoading": "Loading regional AWS catalogue…", + "awsCatalogDescription": "Queries the selected region’s AWS control plane using your current IAM credentials/profile (not a custom runtime endpoint). Requires bedrock:ListFoundationModels and bedrock:ListInferenceProfiles; Bedrock API keys are not supported. Listings do not guarantee invocation permission or tool support. Unknown models use estimated capabilities; verify them before use. Selecting an entry fills the custom ARN without saving settings.", + "awsCatalogError": "Could not load the catalogue. Check IAM credentials/profile, network access, and listing permissions. The bundled list and custom ARN remain available.", + "awsCatalogSelect": "Regional models and inference profiles", + "awsCatalogEmpty": "No streaming text models or active profiles returned", + "awsCatalogKinds": { + "regional": "Foundation model — check inference-profile requirements", + "geographic": "Geographic inference profile", + "global": "Global inference profile — worldwide", + "application": "Application profile — check destinations in AWS" + }, "awsServiceTier": "Service Tier", "awsServiceTierStandard": "Standard", "awsServiceTierStandardDesc": "Balanced performance and cost", From 391a9df279fe1cb58a78514a058f1306f327e810 Mon Sep 17 00:00:00 2001 From: Amp Date: Mon, 21 Sep 2026 18:24:59 +0000 Subject: [PATCH 2/6] fix(bedrock): complete catalogue translations and regression coverage Amp-Thread-ID: https://ampcode.com/threads/T-01a0c52b-8ac5-71d9-a71c-f1c4360c2832 --- .../fetchers/__tests__/bedrock.spec.ts | 58 ++++++++++++ .../providers/__tests__/Bedrock.spec.tsx | 90 ++++++++++++++++++- webview-ui/src/i18n/locales/ca/settings.json | 21 ++++- webview-ui/src/i18n/locales/de/settings.json | 21 ++++- webview-ui/src/i18n/locales/es/settings.json | 21 ++++- webview-ui/src/i18n/locales/fr/settings.json | 21 ++++- webview-ui/src/i18n/locales/hi/settings.json | 21 ++++- webview-ui/src/i18n/locales/id/settings.json | 21 ++++- webview-ui/src/i18n/locales/it/settings.json | 21 ++++- webview-ui/src/i18n/locales/ja/settings.json | 21 ++++- webview-ui/src/i18n/locales/ko/settings.json | 21 ++++- webview-ui/src/i18n/locales/nl/settings.json | 21 ++++- webview-ui/src/i18n/locales/pl/settings.json | 21 ++++- .../src/i18n/locales/pt-BR/settings.json | 21 ++++- webview-ui/src/i18n/locales/ru/settings.json | 21 ++++- webview-ui/src/i18n/locales/tr/settings.json | 21 ++++- webview-ui/src/i18n/locales/vi/settings.json | 21 ++++- .../src/i18n/locales/zh-CN/settings.json | 21 ++++- .../src/i18n/locales/zh-TW/settings.json | 21 ++++- 19 files changed, 469 insertions(+), 36 deletions(-) diff --git a/src/api/providers/fetchers/__tests__/bedrock.spec.ts b/src/api/providers/fetchers/__tests__/bedrock.spec.ts index f2a990a45a..447593b214 100644 --- a/src/api/providers/fetchers/__tests__/bedrock.spec.ts +++ b/src/api/providers/fetchers/__tests__/bedrock.spec.ts @@ -92,3 +92,61 @@ it("does not silently use the default credential chain when API-key authenticati await expect(getBedrockCatalog({ awsRegion: "eu-west-3", awsUseApiKey: true })).rejects.toThrow("IAM credentials") expect(BedrockClient).not.toHaveBeenCalled() }) + +it("rejects a missing region before creating a client", async () => { + await expect(getBedrockCatalog({})).rejects.toThrow("Select an AWS region") + expect(BedrockClient).not.toHaveBeenCalled() +}) + +it("filters legacy and incomplete entries and sorts display names with ID/ARN fallbacks", async () => { + send.mockResolvedValue({ + modelSummaries: [ + { modelArn: "legacy", responseStreamingSupported: true, modelLifecycle: { status: "LEGACY" } }, + { modelName: "Missing ARN", responseStreamingSupported: true }, + { modelArn: "z-arn", responseStreamingSupported: true }, + { modelArn: "foundation", modelId: "b-id", responseStreamingSupported: true }, + ], + }) + pages.mockImplementation(async function* () { + yield { + inferenceProfileSummaries: [ + { status: "ACTIVE", inferenceProfileName: "Missing ARN" }, + { + inferenceProfileArn: "profile", + inferenceProfileId: "global.id", + inferenceProfileName: "a-name", + status: "ACTIVE", + type: "APPLICATION", + }, + { inferenceProfileArn: "c-arn", status: "ACTIVE" }, + ], + } + }) + await expect(getBedrockCatalog({ awsRegion: "eu-west-3" })).resolves.toEqual([ + { arn: "profile", name: "a-name", kind: "application" }, + { arn: "foundation", name: "b-id", kind: "regional" }, + { arn: "c-arn", name: "c-arn", kind: "geographic" }, + { arn: "z-arn", name: "z-arn", kind: "regional" }, + ]) + expect(BedrockClient).toHaveBeenCalledWith(expect.objectContaining({ credentials: undefined })) + expect(destroy).toHaveBeenCalledOnce() +}) + +it("accepts empty AWS responses without inventing models", async () => { + send.mockResolvedValue({}) + pages.mockImplementation(async function* () { + yield {} + }) + await expect(getBedrockCatalog({ awsRegion: "eu-west-3" })).resolves.toEqual([]) + expect(destroy).toHaveBeenCalledOnce() +}) + +it("releases the client if a later profile page fails instead of returning partial availability", async () => { + send.mockResolvedValue({ modelSummaries: [] }) + pages.mockImplementation(async function* () { + yield { inferenceProfileSummaries: [{ inferenceProfileArn: "first", status: "ACTIVE" }] } + throw new Error("Pagination denied") + }) + await expect(getBedrockCatalog({ awsRegion: "eu-west-3" })).rejects.toThrow("Pagination denied") + expect(destroy).toHaveBeenCalledOnce() +}) diff --git a/webview-ui/src/components/settings/providers/__tests__/Bedrock.spec.tsx b/webview-ui/src/components/settings/providers/__tests__/Bedrock.spec.tsx index 5750d0f977..75105d376c 100644 --- a/webview-ui/src/components/settings/providers/__tests__/Bedrock.spec.tsx +++ b/webview-ui/src/components/settings/providers/__tests__/Bedrock.spec.tsx @@ -1,7 +1,10 @@ import React from "react" -import { render, screen, fireEvent } from "@/utils/test-utils" +import { act, render, screen, fireEvent } from "@/utils/test-utils" import { Bedrock } from "../Bedrock" -import { ProviderSettings } from "@roo-code/types" +import { BedrockModelsMessageType, type ProviderSettings, type OrganizationAllowList } from "@roo-code/types" +import { vscode } from "@/utils/vscode" + +vi.mock("@/utils/vscode", () => ({ vscode: { postMessage: vi.fn() } })) // Mock the vscrui Checkbox component vi.mock("vscrui", () => ({ @@ -85,6 +88,89 @@ describe("Bedrock Component", () => { vi.clearAllMocks() }) + it.each([ + ["arn:aws:bedrock:eu-west-3::foundation-model/amazon.nova-pro-v1:0", "amazon.nova-pro-v1:0"], + [ + "arn:aws:bedrock:eu-west-3:123456789012:application-inference-profile/custom", + "arn:aws:bedrock:eu-west-3:123456789012:application-inference-profile/custom", + ], + ])("previews custom ARN routing without applying checkbox prefixes: %s", (awsCustomArn, expected) => { + render( + , + ) + expect(screen.getByTestId("bedrock-request-model").querySelector("code")).toHaveTextContent(expected) + expect(screen.getByText("settings:providers.awsArnRouting")).toBeInTheDocument() + expect(mockSetApiConfigurationField).not.toHaveBeenCalled() + }) + + it.each<[OrganizationAllowList, boolean]>([ + [{ allowAll: true, providers: {} }, true], + [{ allowAll: false, providers: { bedrock: { allowAll: true } } }, true], + [{ allowAll: false, providers: { bedrock: { allowAll: false, models: ["amazon.nova-pro-v1:0"] } } }, false], + [{ allowAll: false, providers: {} }, false], + ])("respects organization catalogue restrictions: %j", (organizationAllowList, visible) => { + render( + , + ) + expect(!!screen.queryByRole("button", { name: "settings:providers.awsCatalogRefresh" })).toBe(visible) + }) + + it("selects a discovered ARN into the edit buffer without saving or enabling routing", () => { + render( + , + ) + fireEvent.click(screen.getByRole("button", { name: "settings:providers.awsCatalogRefresh" })) + const request = vi.mocked(vscode.postMessage).mock.calls[0][0] + const arn = "arn:aws:bedrock:eu-west-3:123456789012:inference-profile/eu.model" + act(() => + window.dispatchEvent( + new MessageEvent("message", { + data: { + type: BedrockModelsMessageType.bedrockModels, + requestId: request.requestId, + bedrockModels: [{ arn, name: "Discovered", kind: "geographic" }], + }, + }), + ), + ) + fireEvent.change(screen.getByLabelText("settings:providers.awsCatalogSelect"), { target: { value: arn } }) + expect(mockSetApiConfigurationField.mock.calls).toEqual([ + ["apiModelId", "custom-arn"], + ["awsCustomArn", arn], + ]) + expect(vscode.postMessage).toHaveBeenCalledTimes(1) + }) + + it.each(["awsGlobalInference", "awsCrossRegion"])("buffers explicit routing opt-in: %s", (label) => { + render( + , + ) + fireEvent.click(screen.getByLabelText(`settings:providers.${label}`)) + expect(mockSetApiConfigurationField).toHaveBeenCalledWith( + label === "awsGlobalInference" ? "awsUseGlobalInference" : "awsUseCrossRegionInference", + true, + ) + expect(vscode.postMessage).not.toHaveBeenCalled() + }) + it.each([ [false, false, "anthropic.claude-sonnet-4-5-20250929-v1:0"], [true, false, "eu.anthropic.claude-sonnet-4-5-20250929-v1:0"], diff --git a/webview-ui/src/i18n/locales/ca/settings.json b/webview-ui/src/i18n/locales/ca/settings.json index 762a1290af..f95d6d22d2 100644 --- a/webview-ui/src/i18n/locales/ca/settings.json +++ b/webview-ui/src/i18n/locales/ca/settings.json @@ -550,8 +550,25 @@ "awsSecretKey": "Clau secreta d'AWS", "awsSessionToken": "Token de sessió d'AWS", "awsRegion": "Regió d'AWS", - "awsCrossRegion": "Utilitzar inferència entre regions", - "awsGlobalInference": "Utilitzar la inferència global (selecció automàtica de la regió òptima d'AWS)", + "awsCrossRegion": "Utilitzar inferència geogràfica entre regions", + "awsGlobalInference": "Utilitzar inferència global (encaminament mundial)", + "awsCrossRegionDescription": "Utilitza un perfil d'inferència geogràfic (per exemple eu. o us.). El processament es manté dins la zona geogràfica del perfil, no necessàriament a la regió seleccionada. Alguns models, com Claude Sonnet 4.5, requereixen un perfil d'inferència. Comprova les regions d'origen i destinació admeses a AWS; un prefix generat no garanteix la disponibilitat.", + "awsGlobalInferenceDescription": "Permet el processament en regions comercials d'AWS de tot el món. Si les dues opcions estan activades, l'encaminament global té prioritat per als models compatibles. Desactiva aquesta opció si el processament ha de romandre en una zona geogràfica concreta.", + "awsRequestModelId": "ID del model / ARN de la sol·licitud:", + "awsArnRouting": "L'ARN seleccionat controla l'encaminament; aquestes caselles no el substitueixen. Els perfils d'aplicació hereten l'encaminament del model/perfil subjacent. Comprova les seves destinacions a AWS abans d'utilitzar-lo.", + "awsBundledModels": "El selector inferior és una llista inclosa sense verificar, no una comprovació de disponibilitat del compte/regió. Actualitza el catàleg regional per seleccionar un model AWS o perfil d'inferència per ARN. Cap opció d'encaminament s'activa automàticament.", + "awsCatalogRefresh": "Actualitzar el catàleg regional d'AWS", + "awsCatalogLoading": "S'està carregant el catàleg regional d'AWS…", + "awsCatalogDescription": "Consulta el pla de control d'AWS de la regió seleccionada amb les credencials/perfil IAM actuals (no un punt d'accés d'execució personalitzat). Requereix bedrock:ListFoundationModels i bedrock:ListInferenceProfiles; no admet claus API de Bedrock. Les entrades no garanteixen permís d'invocació ni compatibilitat amb eines. Les capacitats dels models desconeguts són estimades; verifica-les abans d'utilitzar-los. Seleccionar una entrada omple l'ARN personalitzat sense desar la configuració.", + "awsCatalogError": "No s'ha pogut carregar el catàleg. Comprova les credencials/perfil IAM, l'accés a la xarxa i els permisos de llistat. La llista inclosa i l'ARN personalitzat continuen disponibles.", + "awsCatalogSelect": "Models regionals i perfils d'inferència", + "awsCatalogEmpty": "No s'han retornat models de text en streaming ni perfils actius", + "awsCatalogKinds": { + "regional": "Model fundacional — comprova els requisits de perfil d'inferència", + "geographic": "Perfil d'inferència geogràfic", + "global": "Perfil d'inferència global — mundial", + "application": "Perfil d'aplicació — comprova les destinacions a AWS" + }, "awsServiceTier": "Nivell de servei", "awsServiceTierStandard": "Standard", "awsServiceTierStandardDesc": "Rendiment i cost equilibrats", diff --git a/webview-ui/src/i18n/locales/de/settings.json b/webview-ui/src/i18n/locales/de/settings.json index f56984bc73..6e0c99a679 100644 --- a/webview-ui/src/i18n/locales/de/settings.json +++ b/webview-ui/src/i18n/locales/de/settings.json @@ -550,8 +550,25 @@ "awsSecretKey": "AWS Geheimschlüssel", "awsSessionToken": "AWS Sitzungstoken", "awsRegion": "AWS Region", - "awsCrossRegion": "Regionsübergreifende Inferenz verwenden", - "awsGlobalInference": "Globale Inferenz verwenden (optimale AWS-Region automatisch auswählen)", + "awsCrossRegion": "Geografische regionsübergreifende Inferenz verwenden", + "awsGlobalInference": "Globale Inferenz verwenden (weltweites Routing)", + "awsCrossRegionDescription": "Verwendet ein geografisches Inferenzprofil (z. B. eu. oder us.). Die Verarbeitung bleibt innerhalb dessen geografischen Gebiets, nicht unbedingt in der ausgewählten Region. Einige Modelle, darunter Claude Sonnet 4.5, benötigen ein Inferenzprofil. Prüfe die unterstützten Quell- und Zielregionen in AWS; ein erzeugtes Präfix garantiert keine Verfügbarkeit.", + "awsGlobalInferenceDescription": "Erlaubt die Verarbeitung in kommerziellen AWS-Regionen weltweit. Sind beide Optionen aktiviert, hat globales Routing für unterstützte Modelle Vorrang. Deaktiviere dies, wenn die Verarbeitung auf ein bestimmtes geografisches Gebiet beschränkt bleiben muss.", + "awsRequestModelId": "Modell-ID / ARN der Anfrage:", + "awsArnRouting": "Die ausgewählte ARN bestimmt das Routing; diese Kontrollkästchen überschreiben es nicht. Anwendungsprofile übernehmen das Routing ihres zugrunde liegenden Modells/Profils. Prüfe dessen Zielregionen vor der Verwendung in AWS.", + "awsBundledModels": "Die Modellauswahl unten ist eine mitgelieferte, ungeprüfte Liste, keine Verfügbarkeitsprüfung für Konto/Region. Aktualisiere den regionalen Katalog, um ein AWS-Modell oder Inferenzprofil per ARN auszuwählen. Keine Routingoption wird automatisch aktiviert.", + "awsCatalogRefresh": "Regionalen AWS-Katalog aktualisieren", + "awsCatalogLoading": "Regionaler AWS-Katalog wird geladen…", + "awsCatalogDescription": "Fragt die AWS-Steuerungsebene der ausgewählten Region mit deinen aktuellen IAM-Zugangsdaten/deinem Profil ab (nicht über einen benutzerdefinierten Laufzeitendpunkt). Erfordert bedrock:ListFoundationModels und bedrock:ListInferenceProfiles; Bedrock-API-Schlüssel werden nicht unterstützt. Einträge garantieren weder Aufrufberechtigung noch Werkzeugunterstützung. Unbekannte Modelle verwenden geschätzte Fähigkeiten; prüfe diese vor der Verwendung. Die Auswahl füllt die benutzerdefinierte ARN aus, ohne Einstellungen zu speichern.", + "awsCatalogError": "Der Katalog konnte nicht geladen werden. Prüfe IAM-Zugangsdaten/Profil, Netzwerkzugriff und Auflistungsberechtigungen. Die mitgelieferte Liste und die benutzerdefinierte ARN bleiben verfügbar.", + "awsCatalogSelect": "Regionale Modelle und Inferenzprofile", + "awsCatalogEmpty": "Keine Textmodelle mit Streaming oder aktive Profile zurückgegeben", + "awsCatalogKinds": { + "regional": "Basismodell — Anforderungen an Inferenzprofile prüfen", + "geographic": "Geografisches Inferenzprofil", + "global": "Globales Inferenzprofil — weltweit", + "application": "Anwendungsprofil — Zielregionen in AWS prüfen" + }, "awsServiceTier": "Service-Stufe", "awsServiceTierStandard": "Standard", "awsServiceTierStandardDesc": "Ausgewogene Leistung und Kosten", diff --git a/webview-ui/src/i18n/locales/es/settings.json b/webview-ui/src/i18n/locales/es/settings.json index e730483fa0..22069ec6af 100644 --- a/webview-ui/src/i18n/locales/es/settings.json +++ b/webview-ui/src/i18n/locales/es/settings.json @@ -550,8 +550,25 @@ "awsSecretKey": "Clave secreta de AWS", "awsSessionToken": "Token de sesión de AWS", "awsRegion": "Región de AWS", - "awsCrossRegion": "Usar inferencia entre regiones", - "awsGlobalInference": "Usar inferencia global (selección automática de la región óptima de AWS)", + "awsCrossRegion": "Usar inferencia geográfica entre regiones", + "awsGlobalInference": "Usar inferencia global (enrutamiento mundial)", + "awsCrossRegionDescription": "Utiliza un perfil de inferencia geográfico (por ejemplo, eu. o us.). El procesamiento permanece en la zona geográfica del perfil, no necesariamente en la región seleccionada. Algunos modelos, como Claude Sonnet 4.5, requieren un perfil de inferencia. Comprueba sus regiones de origen y destino admitidas en AWS; un prefijo generado no garantiza la disponibilidad.", + "awsGlobalInferenceDescription": "Permite el procesamiento en regiones comerciales de AWS de todo el mundo. Si ambas opciones están activadas, el enrutamiento global tiene prioridad para los modelos compatibles. Desactiva esta opción si el procesamiento debe permanecer en una zona geográfica específica.", + "awsRequestModelId": "ID del modelo / ARN de la solicitud:", + "awsArnRouting": "El ARN seleccionado controla el enrutamiento; estas casillas no lo anulan. Los perfiles de aplicación heredan el enrutamiento de su modelo/perfil subyacente. Comprueba sus destinos en AWS antes de usarlo.", + "awsBundledModels": "El selector de modelos inferior es una lista incluida sin verificar, no una comprobación de disponibilidad de la cuenta/región. Actualiza el catálogo regional para seleccionar un modelo de AWS o perfil de inferencia por ARN. Ninguna opción de enrutamiento se activa automáticamente.", + "awsCatalogRefresh": "Actualizar catálogo regional de AWS", + "awsCatalogLoading": "Cargando catálogo regional de AWS…", + "awsCatalogDescription": "Consulta el plano de control de AWS de la región seleccionada con tus credenciales/perfil IAM actuales (no un punto de conexión de ejecución personalizado). Requiere bedrock:ListFoundationModels y bedrock:ListInferenceProfiles; no admite claves API de Bedrock. Las entradas no garantizan permisos de invocación ni compatibilidad con herramientas. Las capacidades de modelos desconocidos son estimadas; verifícalas antes de usarlos. Seleccionar una entrada rellena el ARN personalizado sin guardar los ajustes.", + "awsCatalogError": "No se pudo cargar el catálogo. Comprueba las credenciales/perfil IAM, el acceso a la red y los permisos de listado. La lista incluida y el ARN personalizado siguen disponibles.", + "awsCatalogSelect": "Modelos regionales y perfiles de inferencia", + "awsCatalogEmpty": "No se devolvieron modelos de texto en streaming ni perfiles activos", + "awsCatalogKinds": { + "regional": "Modelo fundacional — comprobar requisitos de perfil de inferencia", + "geographic": "Perfil de inferencia geográfico", + "global": "Perfil de inferencia global — mundial", + "application": "Perfil de aplicación — comprobar destinos en AWS" + }, "awsServiceTier": "Nivel de servicio", "awsServiceTierStandard": "Estándar", "awsServiceTierStandardDesc": "Rendimiento y costo equilibrados", diff --git a/webview-ui/src/i18n/locales/fr/settings.json b/webview-ui/src/i18n/locales/fr/settings.json index 78770da21d..72fb9580d2 100644 --- a/webview-ui/src/i18n/locales/fr/settings.json +++ b/webview-ui/src/i18n/locales/fr/settings.json @@ -550,8 +550,25 @@ "awsSecretKey": "Clé secrète AWS", "awsSessionToken": "Jeton de session AWS", "awsRegion": "Région AWS", - "awsCrossRegion": "Utiliser l'inférence inter-régions", - "awsGlobalInference": "Utiliser l'inférence globale (sélection automatique de la région AWS optimale)", + "awsCrossRegion": "Utiliser l'inférence inter-régions géographique", + "awsGlobalInference": "Utiliser l'inférence globale (routage mondial)", + "awsCrossRegionDescription": "Utilise un profil d'inférence géographique (par exemple eu. ou us.). Le traitement reste dans la zone géographique du profil, pas nécessairement dans la région sélectionnée. Certains modèles, dont Claude Sonnet 4.5, nécessitent un profil d'inférence. Vérifiez ses régions source et destination prises en charge dans AWS ; un préfixe généré ne garantit pas la disponibilité.", + "awsGlobalInferenceDescription": "Autorise le traitement dans les régions AWS commerciales du monde entier. Si les deux options sont activées, le routage global est prioritaire pour les modèles compatibles. Désactivez cette option si le traitement doit rester dans une zone géographique précise.", + "awsRequestModelId": "ID du modèle / ARN de la requête :", + "awsArnRouting": "L'ARN sélectionné détermine le routage ; ces cases ne le remplacent pas. Les profils d'application héritent du routage du modèle/profil sous-jacent. Vérifiez ses destinations dans AWS avant utilisation.", + "awsBundledModels": "Le sélecteur ci-dessous est une liste intégrée non vérifiée, pas un contrôle de disponibilité pour le compte/la région. Actualisez le catalogue régional pour sélectionner un modèle AWS ou un profil d'inférence par ARN. Aucune option de routage n'est activée automatiquement.", + "awsCatalogRefresh": "Actualiser le catalogue AWS régional", + "awsCatalogLoading": "Chargement du catalogue AWS régional…", + "awsCatalogDescription": "Interroge le plan de contrôle AWS de la région sélectionnée avec vos identifiants/profil IAM actuels (pas un point de terminaison d'exécution personnalisé). Nécessite bedrock:ListFoundationModels et bedrock:ListInferenceProfiles ; les clés API Bedrock ne sont pas prises en charge. La présence dans la liste ne garantit ni l'autorisation d'appel ni la prise en charge des outils. Les capacités des modèles inconnus sont estimées ; vérifiez-les avant utilisation. Sélectionner une entrée renseigne l'ARN personnalisé sans enregistrer les paramètres.", + "awsCatalogError": "Impossible de charger le catalogue. Vérifiez les identifiants/profil IAM, l'accès réseau et les autorisations de consultation. La liste intégrée et l'ARN personnalisé restent disponibles.", + "awsCatalogSelect": "Modèles régionaux et profils d'inférence", + "awsCatalogEmpty": "Aucun modèle de texte en streaming ni profil actif renvoyé", + "awsCatalogKinds": { + "regional": "Modèle de fondation — vérifier les exigences de profil d'inférence", + "geographic": "Profil d'inférence géographique", + "global": "Profil d'inférence global — mondial", + "application": "Profil d'application — vérifier les destinations dans AWS" + }, "awsServiceTier": "Niveau de service", "awsServiceTierStandard": "Standard", "awsServiceTierStandardDesc": "Performances et coûts équilibrés", diff --git a/webview-ui/src/i18n/locales/hi/settings.json b/webview-ui/src/i18n/locales/hi/settings.json index 413d3515bc..5b25bb20c4 100644 --- a/webview-ui/src/i18n/locales/hi/settings.json +++ b/webview-ui/src/i18n/locales/hi/settings.json @@ -550,8 +550,25 @@ "awsSecretKey": "AWS सीक्रेट कुंजी", "awsSessionToken": "AWS सत्र टोकन", "awsRegion": "AWS क्षेत्र", - "awsCrossRegion": "क्रॉस-क्षेत्र अनुमान का उपयोग करें", - "awsGlobalInference": "वैश्विक अनुमान का उपयोग करें (स्वचालित रूप से श्रेष्ठ AWS क्षेत्र चुनें)", + "awsCrossRegion": "भौगोलिक क्रॉस-क्षेत्र अनुमान का उपयोग करें", + "awsGlobalInference": "वैश्विक अनुमान का उपयोग करें (दुनिया भर में रूटिंग)", + "awsCrossRegionDescription": "भौगोलिक अनुमान प्रोफ़ाइल (जैसे eu. या us.) का उपयोग करता है। प्रोसेसिंग प्रोफ़ाइल के भौगोलिक दायरे में रहती है, ज़रूरी नहीं कि चुने गए क्षेत्र में हो। Claude Sonnet 4.5 सहित कुछ मॉडलों को अनुमान प्रोफ़ाइल की आवश्यकता होती है। AWS में प्रोफ़ाइल के समर्थित स्रोत और गंतव्य क्षेत्रों की जाँच करें; बनाया गया उपसर्ग उपलब्धता की गारंटी नहीं देता।", + "awsGlobalInferenceDescription": "दुनिया भर के वाणिज्यिक AWS क्षेत्रों में प्रोसेसिंग की अनुमति देता है। दोनों विकल्प चालू होने पर समर्थित मॉडलों के लिए वैश्विक रूटिंग को प्राथमिकता मिलती है। यदि प्रोसेसिंग किसी विशेष भौगोलिक दायरे में रहनी चाहिए, तो इसे बंद रखें।", + "awsRequestModelId": "अनुरोध मॉडल ID / ARN:", + "awsArnRouting": "चुना गया ARN रूटिंग नियंत्रित करता है; ये चेकबॉक्स इसे ओवरराइड नहीं करते। एप्लिकेशन प्रोफ़ाइल अपने मूल मॉडल/प्रोफ़ाइल की रूटिंग अपनाती हैं। उपयोग से पहले AWS में उसके गंतव्यों की जाँच करें।", + "awsBundledModels": "नीचे का मॉडल चयनकर्ता एक शामिल, असत्यापित सूची है, खाते/क्षेत्र की उपलब्धता की जाँच नहीं। ARN द्वारा AWS मॉडल या अनुमान प्रोफ़ाइल चुनने के लिए क्षेत्रीय कैटलॉग रीफ़्रेश करें। कोई रूटिंग विकल्प अपने आप चालू नहीं होता।", + "awsCatalogRefresh": "क्षेत्रीय AWS कैटलॉग रीफ़्रेश करें", + "awsCatalogLoading": "क्षेत्रीय AWS कैटलॉग लोड हो रहा है…", + "awsCatalogDescription": "आपके वर्तमान IAM क्रेडेंशियल/प्रोफ़ाइल से चुने गए क्षेत्र के AWS कंट्रोल प्लेन को क्वेरी करता है (कस्टम रनटाइम एंडपॉइंट को नहीं)। bedrock:ListFoundationModels और bedrock:ListInferenceProfiles आवश्यक हैं; Bedrock API कुंजियाँ समर्थित नहीं हैं। सूची में होना कॉल करने की अनुमति या टूल समर्थन की गारंटी नहीं देता। अज्ञात मॉडलों की क्षमताएँ अनुमानित हैं; उपयोग से पहले सत्यापित करें। कोई प्रविष्टि चुनने पर सेटिंग्स सहेजे बिना कस्टम ARN भर जाता है।", + "awsCatalogError": "कैटलॉग लोड नहीं हो सका। IAM क्रेडेंशियल/प्रोफ़ाइल, नेटवर्क पहुँच और सूची देखने की अनुमतियाँ जाँचें। शामिल सूची और कस्टम ARN उपलब्ध रहते हैं।", + "awsCatalogSelect": "क्षेत्रीय मॉडल और अनुमान प्रोफ़ाइल", + "awsCatalogEmpty": "कोई स्ट्रीमिंग टेक्स्ट मॉडल या सक्रिय प्रोफ़ाइल नहीं मिली", + "awsCatalogKinds": { + "regional": "आधार मॉडल — अनुमान प्रोफ़ाइल की आवश्यकताएँ जाँचें", + "geographic": "भौगोलिक अनुमान प्रोफ़ाइल", + "global": "वैश्विक अनुमान प्रोफ़ाइल — दुनिया भर में", + "application": "एप्लिकेशन प्रोफ़ाइल — AWS में गंतव्य जाँचें" + }, "awsServiceTier": "सेवा स्तर", "awsServiceTierStandard": "Standard", "awsServiceTierStandardDesc": "संतुलित प्रदर्शन और लागत", diff --git a/webview-ui/src/i18n/locales/id/settings.json b/webview-ui/src/i18n/locales/id/settings.json index 9b9928da64..f6c93a5438 100644 --- a/webview-ui/src/i18n/locales/id/settings.json +++ b/webview-ui/src/i18n/locales/id/settings.json @@ -550,8 +550,25 @@ "awsSecretKey": "AWS Secret Key", "awsSessionToken": "AWS Session Token", "awsRegion": "AWS Region", - "awsCrossRegion": "Gunakan cross-region inference", - "awsGlobalInference": "Gunakan inferensi Global (pilih Wilayah AWS optimal secara otomatis)", + "awsCrossRegion": "Gunakan inferensi lintas wilayah geografis", + "awsGlobalInference": "Gunakan inferensi global (perutean seluruh dunia)", + "awsCrossRegionDescription": "Menggunakan profil inferensi geografis (misalnya eu. atau us.). Pemrosesan tetap dalam cakupan geografis profil, belum tentu di wilayah yang dipilih. Beberapa model, termasuk Claude Sonnet 4.5, memerlukan profil inferensi. Periksa wilayah sumber dan tujuan yang didukung profil di AWS; awalan yang dihasilkan tidak menjamin ketersediaan.", + "awsGlobalInferenceDescription": "Mengizinkan pemrosesan di wilayah AWS komersial di seluruh dunia. Jika kedua opsi diaktifkan, perutean global diutamakan untuk model yang didukung. Nonaktifkan ini jika pemrosesan harus tetap dalam cakupan geografis tertentu.", + "awsRequestModelId": "ID model / ARN permintaan:", + "awsArnRouting": "ARN yang dipilih mengendalikan perutean; kotak centang ini tidak menimpanya. Profil aplikasi mewarisi perutean model/profil dasarnya. Periksa tujuannya di AWS sebelum digunakan.", + "awsBundledModels": "Pemilih model di bawah adalah daftar bawaan yang belum diverifikasi, bukan pemeriksaan ketersediaan akun/wilayah. Segarkan katalog regional untuk memilih model AWS atau profil inferensi berdasarkan ARN. Tidak ada opsi perutean yang diaktifkan secara otomatis.", + "awsCatalogRefresh": "Segarkan katalog AWS regional", + "awsCatalogLoading": "Memuat katalog AWS regional…", + "awsCatalogDescription": "Mengkueri bidang kontrol AWS wilayah yang dipilih menggunakan kredensial/profil IAM saat ini (bukan endpoint runtime khusus). Memerlukan bedrock:ListFoundationModels dan bedrock:ListInferenceProfiles; kunci API Bedrock tidak didukung. Daftar tidak menjamin izin pemanggilan atau dukungan alat. Kemampuan model yang tidak dikenal merupakan perkiraan; verifikasi sebelum digunakan. Memilih entri mengisi ARN khusus tanpa menyimpan pengaturan.", + "awsCatalogError": "Tidak dapat memuat katalog. Periksa kredensial/profil IAM, akses jaringan, dan izin pencantuman. Daftar bawaan dan ARN khusus tetap tersedia.", + "awsCatalogSelect": "Model regional dan profil inferensi", + "awsCatalogEmpty": "Tidak ada model teks streaming atau profil aktif yang dikembalikan", + "awsCatalogKinds": { + "regional": "Model dasar — periksa persyaratan profil inferensi", + "geographic": "Profil inferensi geografis", + "global": "Profil inferensi global — seluruh dunia", + "application": "Profil aplikasi — periksa tujuan di AWS" + }, "awsServiceTier": "Tingkat Layanan", "awsServiceTierStandard": "Standard", "awsServiceTierStandardDesc": "Performa dan biaya yang seimbang", diff --git a/webview-ui/src/i18n/locales/it/settings.json b/webview-ui/src/i18n/locales/it/settings.json index 8a43ec3d35..051bb91f4f 100644 --- a/webview-ui/src/i18n/locales/it/settings.json +++ b/webview-ui/src/i18n/locales/it/settings.json @@ -550,8 +550,25 @@ "awsSecretKey": "Chiave segreta AWS", "awsSessionToken": "Token di sessione AWS", "awsRegion": "Regione AWS", - "awsCrossRegion": "Usa inferenza cross-regione", - "awsGlobalInference": "Usa l'inferenza globale (selezione automatica della regione AWS ottimale)", + "awsCrossRegion": "Usa inferenza geografica tra regioni", + "awsGlobalInference": "Usa inferenza globale (instradamento mondiale)", + "awsCrossRegionDescription": "Usa un profilo di inferenza geografico (ad esempio eu. o us.). L'elaborazione rimane nell'area geografica del profilo, non necessariamente nella regione selezionata. Alcuni modelli, incluso Claude Sonnet 4.5, richiedono un profilo di inferenza. Verifica le regioni di origine e destinazione supportate in AWS; un prefisso generato non garantisce la disponibilità.", + "awsGlobalInferenceDescription": "Consente l'elaborazione nelle regioni commerciali AWS di tutto il mondo. Se entrambe le opzioni sono attive, l'instradamento globale ha la precedenza per i modelli supportati. Disattiva questa opzione se l'elaborazione deve rimanere in una specifica area geografica.", + "awsRequestModelId": "ID modello / ARN della richiesta:", + "awsArnRouting": "L'ARN selezionato controlla l'instradamento; queste caselle non lo sostituiscono. I profili applicativi ereditano l'instradamento del modello/profilo sottostante. Verifica le destinazioni in AWS prima dell'uso.", + "awsBundledModels": "Il selettore sottostante è un elenco incluso non verificato, non un controllo di disponibilità per account/regione. Aggiorna il catalogo regionale per selezionare un modello AWS o un profilo di inferenza tramite ARN. Nessuna opzione di instradamento viene attivata automaticamente.", + "awsCatalogRefresh": "Aggiorna catalogo regionale AWS", + "awsCatalogLoading": "Caricamento del catalogo regionale AWS…", + "awsCatalogDescription": "Interroga il piano di controllo AWS della regione selezionata con le credenziali/profilo IAM correnti (non un endpoint di esecuzione personalizzato). Richiede bedrock:ListFoundationModels e bedrock:ListInferenceProfiles; le chiavi API Bedrock non sono supportate. Le voci non garantiscono autorizzazioni di invocazione né supporto degli strumenti. Le capacità dei modelli sconosciuti sono stimate; verificale prima dell'uso. Selezionare una voce compila l'ARN personalizzato senza salvare le impostazioni.", + "awsCatalogError": "Impossibile caricare il catalogo. Controlla credenziali/profilo IAM, accesso alla rete e autorizzazioni di elenco. L'elenco incluso e l'ARN personalizzato restano disponibili.", + "awsCatalogSelect": "Modelli regionali e profili di inferenza", + "awsCatalogEmpty": "Nessun modello di testo in streaming o profilo attivo restituito", + "awsCatalogKinds": { + "regional": "Modello di base — verifica i requisiti del profilo di inferenza", + "geographic": "Profilo di inferenza geografico", + "global": "Profilo di inferenza globale — mondiale", + "application": "Profilo applicativo — verifica le destinazioni in AWS" + }, "awsServiceTier": "Livello di servizio", "awsServiceTierStandard": "Standard", "awsServiceTierStandardDesc": "Prestazioni e costo equilibrati", diff --git a/webview-ui/src/i18n/locales/ja/settings.json b/webview-ui/src/i18n/locales/ja/settings.json index b2cfbe977e..56479bfce8 100644 --- a/webview-ui/src/i18n/locales/ja/settings.json +++ b/webview-ui/src/i18n/locales/ja/settings.json @@ -550,8 +550,25 @@ "awsSecretKey": "AWSシークレットキー", "awsSessionToken": "AWSセッショントークン", "awsRegion": "AWSリージョン", - "awsCrossRegion": "クロスリージョン推論を使用", - "awsGlobalInference": "グローバル推論を使用する(最適なAWSリージョンを自動選択)", + "awsCrossRegion": "地理的クロスリージョン推論を使用", + "awsGlobalInference": "グローバル推論を使用(世界規模のルーティング)", + "awsCrossRegionDescription": "地理的推論プロファイル(例:eu.、us.)を使用します。処理はプロファイルの地理的範囲内に留まりますが、選択したリージョン内とは限りません。Claude Sonnet 4.5 など一部のモデルには推論プロファイルが必要です。AWS でプロファイルが対応する送信元と宛先リージョンを確認してください。生成されたプレフィックスは利用可能性を保証しません。", + "awsGlobalInferenceDescription": "世界中の商用 AWS リージョンでの処理を許可します。両方のオプションが有効な場合、対応モデルではグローバルルーティングが優先されます。処理を特定の地理的範囲内に留める必要がある場合は無効にしてください。", + "awsRequestModelId": "リクエストのモデル ID / ARN:", + "awsArnRouting": "選択した ARN がルーティングを制御し、これらのチェックボックスでは上書きされません。アプリケーションプロファイルは基になるモデル/プロファイルのルーティングを継承します。使用前に AWS で宛先を確認してください。", + "awsBundledModels": "以下のモデル選択は同梱の未検証リストであり、アカウント/リージョンの利用可能性を確認するものではありません。リージョン別カタログを更新して、ARN で AWS モデルまたは推論プロファイルを選択してください。ルーティングオプションが自動で有効になることはありません。", + "awsCatalogRefresh": "リージョン別 AWS カタログを更新", + "awsCatalogLoading": "リージョン別 AWS カタログを読み込み中…", + "awsCatalogDescription": "現在の IAM 認証情報/プロファイルで、選択したリージョンの AWS コントロールプレーンに問い合わせます(カスタムランタイムエンドポイントではありません)。bedrock:ListFoundationModels と bedrock:ListInferenceProfiles が必要です。Bedrock API キーは非対応です。掲載は呼び出し権限やツール対応を保証しません。未知のモデルの機能は推定のため、使用前に確認してください。項目を選択すると、設定を保存せずにカスタム ARN が入力されます。", + "awsCatalogError": "カタログを読み込めませんでした。IAM 認証情報/プロファイル、ネットワーク接続、一覧取得権限を確認してください。同梱リストとカスタム ARN は引き続き使用できます。", + "awsCatalogSelect": "リージョン別モデルと推論プロファイル", + "awsCatalogEmpty": "ストリーミング対応のテキストモデルまたはアクティブなプロファイルが返されませんでした", + "awsCatalogKinds": { + "regional": "基盤モデル — 推論プロファイルの要件を確認", + "geographic": "地理的推論プロファイル", + "global": "グローバル推論プロファイル — 世界規模", + "application": "アプリケーションプロファイル — AWS で宛先を確認" + }, "awsServiceTier": "サービスティア", "awsServiceTierStandard": "Standard", "awsServiceTierStandardDesc": "バランスの取れたパフォーマンスとコスト", diff --git a/webview-ui/src/i18n/locales/ko/settings.json b/webview-ui/src/i18n/locales/ko/settings.json index 1ff9addeb4..ed92d14d80 100644 --- a/webview-ui/src/i18n/locales/ko/settings.json +++ b/webview-ui/src/i18n/locales/ko/settings.json @@ -550,8 +550,25 @@ "awsSecretKey": "AWS 시크릿 키", "awsSessionToken": "AWS 세션 토큰", "awsRegion": "AWS 리전", - "awsCrossRegion": "교차 리전 추론 사용", - "awsGlobalInference": "글로벌 추론 사용(최적의 AWS 리전 자동 선택)", + "awsCrossRegion": "지리적 교차 리전 추론 사용", + "awsGlobalInference": "글로벌 추론 사용(전 세계 라우팅)", + "awsCrossRegionDescription": "지리적 추론 프로필(예: eu. 또는 us.)을 사용합니다. 처리는 프로필의 지리적 범위 안에 머무르지만 반드시 선택한 리전에서 이루어지는 것은 아닙니다. Claude Sonnet 4.5 등 일부 모델에는 추론 프로필이 필요합니다. AWS에서 프로필이 지원하는 소스 및 대상 리전을 확인하세요. 생성된 접두사는 가용성을 보장하지 않습니다.", + "awsGlobalInferenceDescription": "전 세계 상용 AWS 리전에서 처리를 허용합니다. 두 옵션이 모두 켜져 있으면 지원되는 모델에 글로벌 라우팅이 우선 적용됩니다. 처리가 특정 지리적 범위 내에 머물러야 한다면 이 옵션을 끄세요.", + "awsRequestModelId": "요청 모델 ID / ARN:", + "awsArnRouting": "선택한 ARN이 라우팅을 제어하며 이 체크박스는 이를 재정의하지 않습니다. 애플리케이션 프로필은 기본 모델/프로필의 라우팅을 상속합니다. 사용 전에 AWS에서 대상을 확인하세요.", + "awsBundledModels": "아래 모델 선택기는 포함된 미검증 목록이며 계정/리전 가용성 확인이 아닙니다. 리전별 카탈로그를 새로고침하여 ARN으로 AWS 모델 또는 추론 프로필을 선택하세요. 라우팅 옵션은 자동으로 켜지지 않습니다.", + "awsCatalogRefresh": "리전별 AWS 카탈로그 새로고침", + "awsCatalogLoading": "리전별 AWS 카탈로그 로딩 중…", + "awsCatalogDescription": "현재 IAM 자격 증명/프로필로 선택한 리전의 AWS 제어 영역을 조회합니다(사용자 지정 런타임 엔드포인트가 아님). bedrock:ListFoundationModels 및 bedrock:ListInferenceProfiles가 필요하며 Bedrock API 키는 지원되지 않습니다. 목록에 있어도 호출 권한이나 도구 지원이 보장되지 않습니다. 알 수 없는 모델의 기능은 추정치이므로 사용 전에 확인하세요. 항목을 선택하면 설정을 저장하지 않고 사용자 지정 ARN을 채웁니다.", + "awsCatalogError": "카탈로그를 불러올 수 없습니다. IAM 자격 증명/프로필, 네트워크 접근 및 목록 조회 권한을 확인하세요. 포함된 목록과 사용자 지정 ARN은 계속 사용할 수 있습니다.", + "awsCatalogSelect": "리전별 모델 및 추론 프로필", + "awsCatalogEmpty": "스트리밍 텍스트 모델이나 활성 프로필이 반환되지 않았습니다", + "awsCatalogKinds": { + "regional": "기반 모델 — 추론 프로필 요구 사항 확인", + "geographic": "지리적 추론 프로필", + "global": "글로벌 추론 프로필 — 전 세계", + "application": "애플리케이션 프로필 — AWS에서 대상 확인" + }, "awsServiceTier": "서비스 계층", "awsServiceTierStandard": "Standard", "awsServiceTierStandardDesc": "균형 잡힌 성능 및 비용", diff --git a/webview-ui/src/i18n/locales/nl/settings.json b/webview-ui/src/i18n/locales/nl/settings.json index 4361d091a1..a44e0d5e0a 100644 --- a/webview-ui/src/i18n/locales/nl/settings.json +++ b/webview-ui/src/i18n/locales/nl/settings.json @@ -550,8 +550,25 @@ "awsSecretKey": "AWS-geheime sleutel", "awsSessionToken": "AWS-sessietoken", "awsRegion": "AWS-regio", - "awsCrossRegion": "Gebruik cross-region inference", - "awsGlobalInference": "Gebruik wereldwijde inferentie (automatische selectie van optimale AWS-regio)", + "awsCrossRegion": "Gebruik geografische inferentie tussen regio's", + "awsGlobalInference": "Gebruik globale inferentie (wereldwijde routering)", + "awsCrossRegionDescription": "Gebruikt een geografisch inferentieprofiel (bijvoorbeeld eu. of us.). Verwerking blijft binnen het geografische gebied van het profiel, niet noodzakelijk in de geselecteerde regio. Sommige modellen, waaronder Claude Sonnet 4.5, vereisen een inferentieprofiel. Controleer de ondersteunde bron- en doelregio's in AWS; een gegenereerd voorvoegsel garandeert geen beschikbaarheid.", + "awsGlobalInferenceDescription": "Staat verwerking toe in commerciële AWS-regio's wereldwijd. Als beide opties zijn ingeschakeld, heeft globale routering voorrang voor ondersteunde modellen. Schakel dit uit als verwerking binnen een specifiek geografisch gebied moet blijven.", + "awsRequestModelId": "Model-ID / ARN van de aanvraag:", + "awsArnRouting": "De geselecteerde ARN bepaalt de routering; deze selectievakjes overschrijven die niet. Applicatieprofielen erven de routering van hun onderliggende model/profiel. Controleer de bestemmingen in AWS vóór gebruik.", + "awsBundledModels": "De modelkiezer hieronder is een meegeleverde, ongecontroleerde lijst, geen beschikbaarheidscontrole voor het account/de regio. Vernieuw de regionale catalogus om een AWS-model of inferentieprofiel via ARN te selecteren. Geen enkele routeringsoptie wordt automatisch ingeschakeld.", + "awsCatalogRefresh": "Regionale AWS-catalogus vernieuwen", + "awsCatalogLoading": "Regionale AWS-catalogus laden…", + "awsCatalogDescription": "Bevraagt het AWS-besturingsvlak van de geselecteerde regio met je huidige IAM-inloggegevens/profiel (niet een aangepast runtime-eindpunt). Vereist bedrock:ListFoundationModels en bedrock:ListInferenceProfiles; Bedrock-API-sleutels worden niet ondersteund. Vermeldingen garanderen geen aanroeprechten of ondersteuning voor tools. Mogelijkheden van onbekende modellen zijn geschat; controleer ze vóór gebruik. Een selectie vult de aangepaste ARN in zonder instellingen op te slaan.", + "awsCatalogError": "Kan de catalogus niet laden. Controleer IAM-inloggegevens/profiel, netwerktoegang en lijstbevoegdheden. De meegeleverde lijst en aangepaste ARN blijven beschikbaar.", + "awsCatalogSelect": "Regionale modellen en inferentieprofielen", + "awsCatalogEmpty": "Geen streamingtekstmodellen of actieve profielen teruggegeven", + "awsCatalogKinds": { + "regional": "Basismodel — controleer vereisten voor inferentieprofielen", + "geographic": "Geografisch inferentieprofiel", + "global": "Globaal inferentieprofiel — wereldwijd", + "application": "Applicatieprofiel — controleer bestemmingen in AWS" + }, "awsServiceTier": "Servicelaag", "awsServiceTierStandard": "Standard", "awsServiceTierStandardDesc": "Gebalanceerde prestaties en kosten", diff --git a/webview-ui/src/i18n/locales/pl/settings.json b/webview-ui/src/i18n/locales/pl/settings.json index 277bcaa470..dbb42b6720 100644 --- a/webview-ui/src/i18n/locales/pl/settings.json +++ b/webview-ui/src/i18n/locales/pl/settings.json @@ -550,8 +550,25 @@ "awsSecretKey": "Klucz tajny AWS", "awsSessionToken": "Token sesji AWS", "awsRegion": "Region AWS", - "awsCrossRegion": "Użyj wnioskowania międzyregionalnego", - "awsGlobalInference": "Użyj globalnej inferencji (automatyczny wybór optymalnego regionu AWS)", + "awsCrossRegion": "Użyj geograficznego wnioskowania międzyregionalnego", + "awsGlobalInference": "Użyj wnioskowania globalnego (routing na całym świecie)", + "awsCrossRegionDescription": "Używa geograficznego profilu wnioskowania (np. eu. lub us.). Przetwarzanie pozostaje w obszarze geograficznym profilu, niekoniecznie w wybranym regionie. Niektóre modele, w tym Claude Sonnet 4.5, wymagają profilu wnioskowania. Sprawdź obsługiwane regiony źródłowe i docelowe w AWS; wygenerowany prefiks nie gwarantuje dostępności.", + "awsGlobalInferenceDescription": "Zezwala na przetwarzanie w komercyjnych regionach AWS na całym świecie. Gdy obie opcje są włączone, routing globalny ma pierwszeństwo dla obsługiwanych modeli. Wyłącz tę opcję, jeśli przetwarzanie musi pozostać w określonym obszarze geograficznym.", + "awsRequestModelId": "ID modelu / ARN żądania:", + "awsArnRouting": "Wybrany ARN steruje routingiem; te pola wyboru go nie zastępują. Profile aplikacji dziedziczą routing modelu/profilu bazowego. Przed użyciem sprawdź jego regiony docelowe w AWS.", + "awsBundledModels": "Poniższy selektor to dołączona, niezweryfikowana lista, a nie kontrola dostępności dla konta/regionu. Odśwież katalog regionalny, aby wybrać model AWS lub profil wnioskowania przez ARN. Żadna opcja routingu nie jest włączana automatycznie.", + "awsCatalogRefresh": "Odśwież regionalny katalog AWS", + "awsCatalogLoading": "Ładowanie regionalnego katalogu AWS…", + "awsCatalogDescription": "Odpytuje płaszczyznę sterowania AWS wybranego regionu przy użyciu bieżących danych uwierzytelniających/profilu IAM (nie niestandardowego punktu końcowego wykonania). Wymaga bedrock:ListFoundationModels i bedrock:ListInferenceProfiles; klucze API Bedrock nie są obsługiwane. Wpisy nie gwarantują uprawnień do wywołań ani obsługi narzędzi. Możliwości nieznanych modeli są szacowane; sprawdź je przed użyciem. Wybranie wpisu wypełnia niestandardowy ARN bez zapisywania ustawień.", + "awsCatalogError": "Nie udało się załadować katalogu. Sprawdź dane uwierzytelniające/profil IAM, dostęp do sieci i uprawnienia do wyświetlania list. Dołączona lista i niestandardowy ARN pozostają dostępne.", + "awsCatalogSelect": "Modele regionalne i profile wnioskowania", + "awsCatalogEmpty": "Nie zwrócono modeli tekstowych ze strumieniowaniem ani aktywnych profili", + "awsCatalogKinds": { + "regional": "Model bazowy — sprawdź wymagania profilu wnioskowania", + "geographic": "Geograficzny profil wnioskowania", + "global": "Globalny profil wnioskowania — cały świat", + "application": "Profil aplikacji — sprawdź regiony docelowe w AWS" + }, "awsServiceTier": "Warstwa usługi", "awsServiceTierStandard": "Standard", "awsServiceTierStandardDesc": "Zrównoważona wydajność i koszt", diff --git a/webview-ui/src/i18n/locales/pt-BR/settings.json b/webview-ui/src/i18n/locales/pt-BR/settings.json index 8ce67bcd48..8c49bb78c2 100644 --- a/webview-ui/src/i18n/locales/pt-BR/settings.json +++ b/webview-ui/src/i18n/locales/pt-BR/settings.json @@ -550,8 +550,25 @@ "awsSecretKey": "Chave Secreta AWS", "awsSessionToken": "Token de Sessão AWS", "awsRegion": "Região AWS", - "awsCrossRegion": "Usar inferência entre regiões", - "awsGlobalInference": "Usar inferência global (selecionar automaticamente a região ideal da AWS)", + "awsCrossRegion": "Usar inferência geográfica entre regiões", + "awsGlobalInference": "Usar inferência global (roteamento mundial)", + "awsCrossRegionDescription": "Usa um perfil de inferência geográfico (por exemplo, eu. ou us.). O processamento permanece na área geográfica do perfil, não necessariamente na região selecionada. Alguns modelos, incluindo Claude Sonnet 4.5, exigem um perfil de inferência. Confira as regiões de origem e destino compatíveis na AWS; um prefixo gerado não garante disponibilidade.", + "awsGlobalInferenceDescription": "Permite processamento em regiões comerciais da AWS no mundo todo. Quando ambas as opções estão ativadas, o roteamento global tem prioridade para modelos compatíveis. Desative esta opção se o processamento precisar permanecer em uma área geográfica específica.", + "awsRequestModelId": "ID do modelo / ARN da solicitação:", + "awsArnRouting": "O ARN selecionado controla o roteamento; estas caixas não o substituem. Perfis de aplicação herdam o roteamento do modelo/perfil subjacente. Confira seus destinos na AWS antes de usar.", + "awsBundledModels": "O seletor abaixo é uma lista incluída não verificada, não uma verificação de disponibilidade da conta/região. Atualize o catálogo regional para selecionar um modelo AWS ou perfil de inferência por ARN. Nenhuma opção de roteamento é ativada automaticamente.", + "awsCatalogRefresh": "Atualizar catálogo regional da AWS", + "awsCatalogLoading": "Carregando catálogo regional da AWS…", + "awsCatalogDescription": "Consulta o plano de controle da AWS da região selecionada com suas credenciais/perfil IAM atuais (não um endpoint de execução personalizado). Requer bedrock:ListFoundationModels e bedrock:ListInferenceProfiles; chaves de API do Bedrock não são compatíveis. As entradas não garantem permissão de invocação nem suporte a ferramentas. As capacidades de modelos desconhecidos são estimadas; verifique-as antes de usar. Selecionar uma entrada preenche o ARN personalizado sem salvar as configurações.", + "awsCatalogError": "Não foi possível carregar o catálogo. Confira credenciais/perfil IAM, acesso à rede e permissões de listagem. A lista incluída e o ARN personalizado continuam disponíveis.", + "awsCatalogSelect": "Modelos regionais e perfis de inferência", + "awsCatalogEmpty": "Nenhum modelo de texto com streaming ou perfil ativo retornado", + "awsCatalogKinds": { + "regional": "Modelo de base — confira os requisitos de perfil de inferência", + "geographic": "Perfil de inferência geográfico", + "global": "Perfil de inferência global — mundial", + "application": "Perfil de aplicação — confira os destinos na AWS" + }, "awsServiceTier": "Nível de serviço", "awsServiceTierStandard": "Padrão", "awsServiceTierStandardDesc": "Desempenho e custo equilibrados", diff --git a/webview-ui/src/i18n/locales/ru/settings.json b/webview-ui/src/i18n/locales/ru/settings.json index 0ac516c190..20a552bfd2 100644 --- a/webview-ui/src/i18n/locales/ru/settings.json +++ b/webview-ui/src/i18n/locales/ru/settings.json @@ -550,8 +550,25 @@ "awsSecretKey": "AWS Secret Key", "awsSessionToken": "AWS Session Token", "awsRegion": "Регион AWS", - "awsCrossRegion": "Использовать кросс-региональный вывод", - "awsGlobalInference": "Использовать глобальный вывод (автоматический выбор оптимального региона AWS)", + "awsCrossRegion": "Использовать географический межрегиональный вывод", + "awsGlobalInference": "Использовать глобальный вывод (маршрутизация по всему миру)", + "awsCrossRegionDescription": "Использует географический профиль вывода (например, eu. или us.). Обработка остаётся в географической области профиля, но не обязательно в выбранном регионе. Некоторые модели, включая Claude Sonnet 4.5, требуют профиль вывода. Проверьте поддерживаемые исходные и целевые регионы профиля в AWS; созданный префикс не гарантирует доступность.", + "awsGlobalInferenceDescription": "Разрешает обработку в коммерческих регионах AWS по всему миру. Если включены обе опции, глобальная маршрутизация имеет приоритет для поддерживаемых моделей. Отключите эту опцию, если обработка должна оставаться в определённой географической области.", + "awsRequestModelId": "ID модели / ARN запроса:", + "awsArnRouting": "Выбранный ARN определяет маршрутизацию; эти флажки её не переопределяют. Профили приложений наследуют маршрутизацию базовой модели/профиля. Перед использованием проверьте целевые регионы в AWS.", + "awsBundledModels": "Список моделей ниже встроенный и непроверенный; он не проверяет доступность для аккаунта/региона. Обновите региональный каталог, чтобы выбрать модель AWS или профиль вывода по ARN. Ни одна опция маршрутизации не включается автоматически.", + "awsCatalogRefresh": "Обновить региональный каталог AWS", + "awsCatalogLoading": "Загрузка регионального каталога AWS…", + "awsCatalogDescription": "Запрашивает плоскость управления AWS выбранного региона с текущими учётными данными/профилем IAM (не пользовательскую конечную точку выполнения). Требуются bedrock:ListFoundationModels и bedrock:ListInferenceProfiles; ключи API Bedrock не поддерживаются. Наличие в списке не гарантирует права вызова или поддержку инструментов. Возможности неизвестных моделей оценочные; проверьте их перед использованием. Выбор записи заполняет пользовательский ARN без сохранения настроек.", + "awsCatalogError": "Не удалось загрузить каталог. Проверьте учётные данные/профиль IAM, доступ к сети и разрешения на получение списков. Встроенный список и пользовательский ARN остаются доступны.", + "awsCatalogSelect": "Региональные модели и профили вывода", + "awsCatalogEmpty": "Потоковые текстовые модели и активные профили не найдены", + "awsCatalogKinds": { + "regional": "Базовая модель — проверьте требования к профилю вывода", + "geographic": "Географический профиль вывода", + "global": "Глобальный профиль вывода — весь мир", + "application": "Профиль приложения — проверьте целевые регионы в AWS" + }, "awsServiceTier": "Уровень обслуживания", "awsServiceTierStandard": "Стандартный", "awsServiceTierStandardDesc": "Сбалансированная производительность и стоимость", diff --git a/webview-ui/src/i18n/locales/tr/settings.json b/webview-ui/src/i18n/locales/tr/settings.json index 5d3a5cb89a..a4ee0b54f9 100644 --- a/webview-ui/src/i18n/locales/tr/settings.json +++ b/webview-ui/src/i18n/locales/tr/settings.json @@ -550,8 +550,25 @@ "awsSecretKey": "AWS Gizli Anahtarı", "awsSessionToken": "AWS Oturum Belirteci", "awsRegion": "AWS Bölgesi", - "awsCrossRegion": "Bölgeler arası çıkarım kullan", - "awsGlobalInference": "Genel çıkarımı kullan (en uygun AWS Bölgesini otomatik seç)", + "awsCrossRegion": "Coğrafi bölgeler arası çıkarım kullan", + "awsGlobalInference": "Küresel çıkarım kullan (dünya çapında yönlendirme)", + "awsCrossRegionDescription": "Coğrafi bir çıkarım profili kullanır (örneğin eu. veya us.). İşleme, seçilen bölgede olmak zorunda değildir ancak profilin coğrafi alanı içinde kalır. Claude Sonnet 4.5 dahil bazı modeller çıkarım profili gerektirir. AWS'de profilin desteklenen kaynak ve hedef bölgelerini kontrol edin; oluşturulan önek kullanılabilirliği garanti etmez.", + "awsGlobalInferenceDescription": "Dünya çapındaki ticari AWS bölgelerinde işlemeye izin verir. Her iki seçenek de etkinse desteklenen modellerde küresel yönlendirme önceliklidir. İşlemenin belirli bir coğrafi alanda kalması gerekiyorsa bunu kapalı tutun.", + "awsRequestModelId": "İstek model kimliği / ARN:", + "awsArnRouting": "Seçilen ARN yönlendirmeyi belirler; bu onay kutuları onu geçersiz kılmaz. Uygulama profilleri temel model/profilin yönlendirmesini devralır. Kullanmadan önce AWS'de hedeflerini kontrol edin.", + "awsBundledModels": "Aşağıdaki model seçici, hesap/bölge kullanılabilirlik kontrolü değil, paketlenmiş ve doğrulanmamış bir listedir. ARN ile bir AWS modeli veya çıkarım profili seçmek için bölgesel kataloğu yenileyin. Hiçbir yönlendirme seçeneği otomatik etkinleştirilmez.", + "awsCatalogRefresh": "Bölgesel AWS kataloğunu yenile", + "awsCatalogLoading": "Bölgesel AWS kataloğu yükleniyor…", + "awsCatalogDescription": "Geçerli IAM kimlik bilgileriniz/profilinizle seçilen bölgenin AWS kontrol düzlemini sorgular (özel çalışma zamanı uç noktasını değil). bedrock:ListFoundationModels ve bedrock:ListInferenceProfiles gerektirir; Bedrock API anahtarları desteklenmez. Listeler çağırma iznini veya araç desteğini garanti etmez. Bilinmeyen modellerin yetenekleri tahminidir; kullanmadan önce doğrulayın. Bir giriş seçmek ayarları kaydetmeden özel ARN'yi doldurur.", + "awsCatalogError": "Katalog yüklenemedi. IAM kimlik bilgilerini/profilini, ağ erişimini ve listeleme izinlerini kontrol edin. Paketlenmiş liste ve özel ARN kullanılabilir durumda kalır.", + "awsCatalogSelect": "Bölgesel modeller ve çıkarım profilleri", + "awsCatalogEmpty": "Akış destekli metin modeli veya etkin profil döndürülmedi", + "awsCatalogKinds": { + "regional": "Temel model — çıkarım profili gereksinimlerini kontrol edin", + "geographic": "Coğrafi çıkarım profili", + "global": "Küresel çıkarım profili — dünya çapında", + "application": "Uygulama profili — AWS'de hedefleri kontrol edin" + }, "awsServiceTier": "Hizmet seviyesi", "awsServiceTierStandard": "Standart", "awsServiceTierStandardDesc": "Dengeli performans ve maliyet", diff --git a/webview-ui/src/i18n/locales/vi/settings.json b/webview-ui/src/i18n/locales/vi/settings.json index adb1be64e3..8c8acbf14c 100644 --- a/webview-ui/src/i18n/locales/vi/settings.json +++ b/webview-ui/src/i18n/locales/vi/settings.json @@ -550,8 +550,25 @@ "awsSecretKey": "Khóa bí mật AWS", "awsSessionToken": "Token phiên AWS", "awsRegion": "Vùng AWS", - "awsCrossRegion": "Sử dụng suy luận liên vùng", - "awsGlobalInference": "Sử dụng suy luận toàn cầu (tự động chọn Khu vực AWS tối ưu)", + "awsCrossRegion": "Sử dụng suy luận liên vùng theo địa lý", + "awsGlobalInference": "Sử dụng suy luận toàn cầu (định tuyến toàn thế giới)", + "awsCrossRegionDescription": "Sử dụng hồ sơ suy luận theo địa lý (ví dụ eu. hoặc us.). Việc xử lý nằm trong phạm vi địa lý của hồ sơ, không nhất thiết ở vùng đã chọn. Một số mô hình, bao gồm Claude Sonnet 4.5, yêu cầu hồ sơ suy luận. Kiểm tra các vùng nguồn và đích được hồ sơ hỗ trợ trong AWS; tiền tố được tạo không đảm bảo tính khả dụng.", + "awsGlobalInferenceDescription": "Cho phép xử lý tại các vùng AWS thương mại trên toàn thế giới. Khi bật cả hai tùy chọn, định tuyến toàn cầu được ưu tiên cho các mô hình được hỗ trợ. Tắt tùy chọn này nếu việc xử lý phải nằm trong một phạm vi địa lý cụ thể.", + "awsRequestModelId": "ID mô hình / ARN của yêu cầu:", + "awsArnRouting": "ARN đã chọn điều khiển định tuyến; các hộp kiểm này không ghi đè định tuyến đó. Hồ sơ ứng dụng kế thừa định tuyến của mô hình/hồ sơ cơ sở. Kiểm tra các đích trong AWS trước khi sử dụng.", + "awsBundledModels": "Bộ chọn mô hình bên dưới là danh sách đi kèm chưa được xác minh, không phải kiểm tra tính khả dụng của tài khoản/vùng. Làm mới danh mục theo vùng để chọn mô hình AWS hoặc hồ sơ suy luận bằng ARN. Không tùy chọn định tuyến nào được bật tự động.", + "awsCatalogRefresh": "Làm mới danh mục AWS theo vùng", + "awsCatalogLoading": "Đang tải danh mục AWS theo vùng…", + "awsCatalogDescription": "Truy vấn mặt phẳng điều khiển AWS của vùng đã chọn bằng thông tin xác thực/hồ sơ IAM hiện tại (không phải điểm cuối thời gian chạy tùy chỉnh). Yêu cầu bedrock:ListFoundationModels và bedrock:ListInferenceProfiles; không hỗ trợ khóa API Bedrock. Danh sách không đảm bảo quyền gọi hoặc hỗ trợ công cụ. Khả năng của mô hình chưa biết là ước tính; hãy xác minh trước khi dùng. Chọn một mục sẽ điền ARN tùy chỉnh mà không lưu cài đặt.", + "awsCatalogError": "Không thể tải danh mục. Kiểm tra thông tin xác thực/hồ sơ IAM, quyền truy cập mạng và quyền liệt kê. Danh sách đi kèm và ARN tùy chỉnh vẫn khả dụng.", + "awsCatalogSelect": "Mô hình theo vùng và hồ sơ suy luận", + "awsCatalogEmpty": "Không có mô hình văn bản phát trực tuyến hoặc hồ sơ đang hoạt động được trả về", + "awsCatalogKinds": { + "regional": "Mô hình nền tảng — kiểm tra yêu cầu về hồ sơ suy luận", + "geographic": "Hồ sơ suy luận theo địa lý", + "global": "Hồ sơ suy luận toàn cầu — toàn thế giới", + "application": "Hồ sơ ứng dụng — kiểm tra các đích trong AWS" + }, "awsServiceTier": "Cấp độ dịch vụ", "awsServiceTierStandard": "Tiêu chuẩn", "awsServiceTierStandardDesc": "Hiệu suất và chi phí cân bằng", diff --git a/webview-ui/src/i18n/locales/zh-CN/settings.json b/webview-ui/src/i18n/locales/zh-CN/settings.json index 916f629efe..2f0ce4affb 100644 --- a/webview-ui/src/i18n/locales/zh-CN/settings.json +++ b/webview-ui/src/i18n/locales/zh-CN/settings.json @@ -550,8 +550,25 @@ "awsSecretKey": "AWS 密钥", "awsSessionToken": "AWS 会话Token", "awsRegion": "AWS 区域", - "awsCrossRegion": "使用跨区域推理", - "awsGlobalInference": "使用全局推理(自动选择最佳 AWS 区域)", + "awsCrossRegion": "使用地理范围内的跨区域推理", + "awsGlobalInference": "使用全局推理(全球路由)", + "awsCrossRegionDescription": "使用地理推理配置文件(例如 eu. 或 us.)。处理会保持在配置文件的地理范围内,但不一定在所选区域内。部分模型(包括 Claude Sonnet 4.5)需要推理配置文件。请在 AWS 中检查配置文件支持的源区域和目标区域;生成的前缀不保证可用性。", + "awsGlobalInferenceDescription": "允许在全球的商业 AWS 区域中处理。当两个选项都启用时,支持的模型优先使用全局路由。如果处理必须保持在特定地理范围内,请关闭此选项。", + "awsRequestModelId": "请求模型 ID / ARN:", + "awsArnRouting": "所选 ARN 控制路由;这些复选框不会覆盖它。应用程序配置文件继承其底层模型/配置文件的路由。使用前请在 AWS 中检查其目标区域。", + "awsBundledModels": "下方的模型选择器是内置的未经验证的列表,并非账户/区域可用性检查。刷新区域目录可通过 ARN 选择 AWS 模型或推理配置文件。不会自动启用任何路由选项。", + "awsCatalogRefresh": "刷新区域 AWS 目录", + "awsCatalogLoading": "正在加载区域 AWS 目录…", + "awsCatalogDescription": "使用当前 IAM 凭证/配置文件查询所选区域的 AWS 控制平面(而非自定义运行时端点)。需要 bedrock:ListFoundationModels 和 bedrock:ListInferenceProfiles;不支持 Bedrock API 密钥。列出条目不保证调用权限或工具支持。未知模型的能力为估计值,请在使用前核实。选择条目会填入自定义 ARN,但不会保存设置。", + "awsCatalogError": "无法加载目录。请检查 IAM 凭证/配置文件、网络访问和列表查询权限。内置列表和自定义 ARN 仍然可用。", + "awsCatalogSelect": "区域模型和推理配置文件", + "awsCatalogEmpty": "未返回流式文本模型或活动配置文件", + "awsCatalogKinds": { + "regional": "基础模型 — 请检查推理配置文件要求", + "geographic": "地理推理配置文件", + "global": "全局推理配置文件 — 全球", + "application": "应用程序配置文件 — 请在 AWS 中检查目标区域" + }, "awsServiceTier": "服务层级", "awsServiceTierStandard": "Standard", "awsServiceTierStandardDesc": "性能和成本均衡", diff --git a/webview-ui/src/i18n/locales/zh-TW/settings.json b/webview-ui/src/i18n/locales/zh-TW/settings.json index d1f9258dcf..d0ef98927f 100644 --- a/webview-ui/src/i18n/locales/zh-TW/settings.json +++ b/webview-ui/src/i18n/locales/zh-TW/settings.json @@ -577,8 +577,25 @@ "awsSecretKey": "AWS 秘密金鑰", "awsSessionToken": "AWS 工作階段權杖", "awsRegion": "AWS 區域", - "awsCrossRegion": "使用跨區域推論", - "awsGlobalInference": "使用全域推論(自動選取最佳 AWS 區域)", + "awsCrossRegion": "使用地理範圍內的跨區域推論", + "awsGlobalInference": "使用全域推論(全球路由)", + "awsCrossRegionDescription": "使用地理推論設定檔(例如 eu. 或 us.)。處理會維持在設定檔的地理範圍內,但不一定在所選區域內。部分模型(包括 Claude Sonnet 4.5)需要推論設定檔。請在 AWS 中檢查設定檔支援的來源區域和目的地區域;產生的前綴不保證可用性。", + "awsGlobalInferenceDescription": "允許在全球的商業 AWS 區域中處理。當兩個選項都啟用時,支援的模型優先使用全域路由。如果處理必須維持在特定地理範圍內,請關閉此選項。", + "awsRequestModelId": "請求模型 ID / ARN:", + "awsArnRouting": "所選 ARN 控制路由;這些核取方塊不會覆寫它。應用程式設定檔繼承其底層模型/設定檔的路由。使用前請在 AWS 中檢查其目的地。", + "awsBundledModels": "下方的模型選擇器是內建的未驗證清單,並非帳戶/區域可用性檢查。重新整理區域目錄可透過 ARN 選擇 AWS 模型或推論設定檔。不會自動啟用任何路由選項。", + "awsCatalogRefresh": "重新整理區域 AWS 目錄", + "awsCatalogLoading": "正在載入區域 AWS 目錄…", + "awsCatalogDescription": "使用目前的 IAM 憑證/設定檔查詢所選區域的 AWS 控制平面(而非自訂執行階段端點)。需要 bedrock:ListFoundationModels 和 bedrock:ListInferenceProfiles;不支援 Bedrock API 金鑰。列出項目不保證呼叫權限或工具支援。未知模型的能力為估計值,請在使用前確認。選擇項目會填入自訂 ARN,但不會儲存設定。", + "awsCatalogError": "無法載入目錄。請檢查 IAM 憑證/設定檔、網路存取和清單查詢權限。內建清單和自訂 ARN 仍然可用。", + "awsCatalogSelect": "區域模型和推論設定檔", + "awsCatalogEmpty": "未傳回串流文字模型或使用中的設定檔", + "awsCatalogKinds": { + "regional": "基礎模型 — 請檢查推論設定檔需求", + "geographic": "地理推論設定檔", + "global": "全域推論設定檔 — 全球", + "application": "應用程式設定檔 — 請在 AWS 中檢查目的地" + }, "awsServiceTier": "服務層級", "awsServiceTierStandard": "Standard", "awsServiceTierStandardDesc": "效能和成本均衡", From e36a6deff656b47ca8fed116697d9304ceaa4ef8 Mon Sep 17 00:00:00 2001 From: Amp Date: Mon, 21 Sep 2026 18:26:44 +0000 Subject: [PATCH 3/6] test(bedrock): reject extra routing prefixes in ARN preview Amp-Thread-ID: https://ampcode.com/threads/T-01a0c52b-8ac5-71d9-a71c-f1c4360c2832 --- .../components/settings/providers/__tests__/Bedrock.spec.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webview-ui/src/components/settings/providers/__tests__/Bedrock.spec.tsx b/webview-ui/src/components/settings/providers/__tests__/Bedrock.spec.tsx index 75105d376c..99bf860b7a 100644 --- a/webview-ui/src/components/settings/providers/__tests__/Bedrock.spec.tsx +++ b/webview-ui/src/components/settings/providers/__tests__/Bedrock.spec.tsx @@ -106,7 +106,7 @@ describe("Bedrock Component", () => { setApiConfigurationField={mockSetApiConfigurationField} />, ) - expect(screen.getByTestId("bedrock-request-model").querySelector("code")).toHaveTextContent(expected) + expect(screen.getByTestId("bedrock-request-model").querySelector("code")?.textContent).toBe(expected) expect(screen.getByText("settings:providers.awsArnRouting")).toBeInTheDocument() expect(mockSetApiConfigurationField).not.toHaveBeenCalled() }) From 5ed3aa0c3d0d31f6ec795181baf615ceb4f0c13d Mon Sep 17 00:00:00 2001 From: PierrunoYT Date: Mon, 28 Sep 2026 18:54:08 +0200 Subject: [PATCH 4/6] fix(bedrock): address review feedback on regional catalogue - Reject the "custom-arn" picker sentinel before any Bedrock request when no ARN is entered, instead of sending it as the model ID. - Show a placeholder request ID and ARN guidance while the custom ARN is still empty. - Log the underlying catalogue discovery error (IAM denial, network, region) to the output channel; the webview message stays sanitized. - Use the shared Select component for the catalogue picker so it matches the surrounding Bedrock settings. - Label ON_DEMAND foundation-model entries as needing no inference profile, which the ListFoundationModels filter already guarantees. Co-Authored-By: Claude Opus 5.5 (1M context) --- src/api/providers/__tests__/bedrock.spec.ts | 11 +++++++ src/api/providers/bedrock.ts | 9 ++++++ ...webviewMessageHandler.routerModels.spec.ts | 15 +++++++++ src/core/webview/webviewMessageHandler.ts | 6 +++- .../components/settings/providers/Bedrock.tsx | 30 ++++++++++------- .../settings/providers/BedrockCatalog.tsx | 32 +++++++++++-------- .../providers/__tests__/Bedrock.spec.tsx | 18 ++++++++++- .../__tests__/BedrockCatalog.spec.tsx | 23 +++++++++++++ webview-ui/src/i18n/locales/ca/settings.json | 2 +- webview-ui/src/i18n/locales/de/settings.json | 2 +- webview-ui/src/i18n/locales/en/settings.json | 2 +- webview-ui/src/i18n/locales/es/settings.json | 2 +- webview-ui/src/i18n/locales/fr/settings.json | 2 +- webview-ui/src/i18n/locales/hi/settings.json | 2 +- webview-ui/src/i18n/locales/id/settings.json | 2 +- webview-ui/src/i18n/locales/it/settings.json | 2 +- webview-ui/src/i18n/locales/ja/settings.json | 2 +- webview-ui/src/i18n/locales/ko/settings.json | 2 +- webview-ui/src/i18n/locales/nl/settings.json | 2 +- webview-ui/src/i18n/locales/pl/settings.json | 2 +- .../src/i18n/locales/pt-BR/settings.json | 2 +- webview-ui/src/i18n/locales/ru/settings.json | 2 +- webview-ui/src/i18n/locales/tr/settings.json | 2 +- webview-ui/src/i18n/locales/vi/settings.json | 2 +- .../src/i18n/locales/zh-CN/settings.json | 2 +- .../src/i18n/locales/zh-TW/settings.json | 2 +- 26 files changed, 135 insertions(+), 45 deletions(-) diff --git a/src/api/providers/__tests__/bedrock.spec.ts b/src/api/providers/__tests__/bedrock.spec.ts index b3502ba5ab..a08ba5f461 100644 --- a/src/api/providers/__tests__/bedrock.spec.ts +++ b/src/api/providers/__tests__/bedrock.spec.ts @@ -122,6 +122,17 @@ describe("AwsBedrockHandler", () => { expect(provider.getModel().info.supportsReasoningBudget).not.toBe(true) }) + it("rejects the custom-arn sentinel before sending a request when no ARN is entered", async () => { + const provider = new AwsBedrockHandler({ apiModelId: "custom-arn", awsRegion: "eu-west-3" }) + const send = vi.fn() + provider["client"].send = send + await expect( + collectStream(provider.createMessage("system", [{ role: "user", content: "hello" }])), + ).rejects.toThrow("Enter a custom ARN") + await expect(provider.completePrompt("hello")).rejects.toThrow("Enter a custom ARN") + expect(send).not.toHaveBeenCalled() + }) + it.each(["max_tokens", "end_turn", "tool_use", "stop_sequence"])( "reports truncation only for %s, after preserving usage", async (stopReason) => { diff --git a/src/api/providers/bedrock.ts b/src/api/providers/bedrock.ts index debc88cca7..9c7d45dd02 100644 --- a/src/api/providers/bedrock.ts +++ b/src/api/providers/bedrock.ts @@ -424,6 +424,7 @@ export class AwsBedrockHandler extends BaseProvider implements SingleCompletionH } }, ): ApiStream { + this.assertCustomArnProvided() const modelConfig = this.getModel() const usePromptCache = Boolean( (this.options.awsUsePromptCache ?? true) && this.supportsAwsPromptCache(modelConfig), @@ -876,6 +877,7 @@ export class AwsBedrockHandler extends BaseProvider implements SingleCompletionH } async completePrompt(prompt: string, options?: CompletePromptOptions): Promise { + this.assertCustomArnProvided() try { const modelConfig = this.getModel() @@ -1162,6 +1164,13 @@ export class AwsBedrockHandler extends BaseProvider implements SingleCompletionH return modelId } + // "custom-arn" is a picker sentinel, not a Bedrock model ID; never send it as ConverseCommand.modelId. + private assertCustomArnProvided(): void { + if (this.options.apiModelId === "custom-arn" && !this.options.awsCustomArn?.trim()) { + throw new Error("Enter a custom ARN in the Amazon Bedrock settings, or select a model from the list.") + } + } + //Prompt Router responses come back in a different sequence and the model used is in the response and must be fetched by name getModelById(modelId: string, modelType?: string): { id: BedrockModelId | string; info: ModelInfo } { // Try to find the model in bedrockModels diff --git a/src/core/webview/__tests__/webviewMessageHandler.routerModels.spec.ts b/src/core/webview/__tests__/webviewMessageHandler.routerModels.spec.ts index d0d1ca485c..c2dc93e83a 100644 --- a/src/core/webview/__tests__/webviewMessageHandler.routerModels.spec.ts +++ b/src/core/webview/__tests__/webviewMessageHandler.routerModels.spec.ts @@ -125,6 +125,21 @@ describe("webviewMessageHandler - requestRouterModels provider filter", () => { }) }) + it("logs the underlying Bedrock discovery failure for diagnosis", async () => { + const error = new Error("User is not authorized to perform: bedrock:ListInferenceProfiles") + error.name = "AccessDeniedException" + getBedrockCatalogMock.mockRejectedValue(error) + await webviewMessageHandler(mockProvider, { + type: BedrockModelsMessageType.requestBedrockModels, + requestId: "denied", + }) + expect(mockProvider.log).toHaveBeenCalledWith( + expect.stringContaining( + "AccessDeniedException: User is not authorized to perform: bedrock:ListInferenceProfiles", + ), + ) + }) + it("returns a correlated, sanitized Bedrock discovery failure", async () => { getBedrockCatalogMock.mockRejectedValue(new Error("secret credential detail")) await webviewMessageHandler(mockProvider, { diff --git a/src/core/webview/webviewMessageHandler.ts b/src/core/webview/webviewMessageHandler.ts index 220abfb294..2f88a91cd4 100644 --- a/src/core/webview/webviewMessageHandler.ts +++ b/src/core/webview/webviewMessageHandler.ts @@ -1116,7 +1116,11 @@ export const webviewMessageHandler = async ( requestId: message.requestId, bedrockModels, }) - } catch { + } catch (error) { + // Keep the underlying cause (IAM denial, network, wrong region) diagnosable in the output channel. + provider.log( + `Bedrock catalogue discovery failed: ${error instanceof Error ? `${error.name}: ${error.message}` : String(error)}`, + ) await provider.postMessageToWebview({ type: BedrockModelsMessageType.bedrockModels, requestId: message.requestId, diff --git a/webview-ui/src/components/settings/providers/Bedrock.tsx b/webview-ui/src/components/settings/providers/Bedrock.tsx index 6ae2b8a427..d0c52b9373 100644 --- a/webview-ui/src/components/settings/providers/Bedrock.tsx +++ b/webview-ui/src/components/settings/providers/Bedrock.tsx @@ -43,16 +43,20 @@ export const Bedrock = ({ organizationAllowList.allowAll || organizationAllowList.providers[providerIdentifiers.bedrock]?.allowAll const customArn = apiConfiguration.awsCustomArn - const requestModelId = customArn - ? customArn.includes(":foundation-model/") - ? getBedrockInferenceModelId(customArn.split(":foundation-model/")[1]) - : customArn - : getBedrockInferenceModelId( - apiConfiguration.apiModelId || bedrockDefaultModelId, - apiConfiguration.awsRegion, - apiConfiguration.awsUseCrossRegionInference, - apiConfiguration.awsUseGlobalInference, - ) + // The "custom-arn" sentinel is not a request model ID; show a placeholder until an ARN is entered. + const awaitingArn = !customArn && apiConfiguration.apiModelId === "custom-arn" + const requestModelId = awaitingArn + ? "—" + : customArn + ? customArn.includes(":foundation-model/") + ? getBedrockInferenceModelId(customArn.split(":foundation-model/")[1]) + : customArn + : getBedrockInferenceModelId( + apiConfiguration.apiModelId || bedrockDefaultModelId, + apiConfiguration.awsRegion, + apiConfiguration.awsUseCrossRegionInference, + apiConfiguration.awsUseGlobalInference, + ) // Check if the selected model supports 1M context (supported Claude 4 models) const supports1MContextBeta = @@ -235,7 +239,11 @@ export const Bedrock = ({ {t("settings:providers.awsRequestModelId")} {requestModelId}

- {t(customArn ? "settings:providers.awsArnRouting" : "settings:providers.awsBundledModels")} + {t( + customArn || awaitingArn + ? "settings:providers.awsArnRouting" + : "settings:providers.awsBundledModels", + )}
{allowCatalog && ( {t("settings:providers.awsCatalogSelect")} - + {/* Empty value keeps the placeholder visible: picking an entry fills the custom ARN field. */} + )} diff --git a/webview-ui/src/components/settings/providers/__tests__/Bedrock.spec.tsx b/webview-ui/src/components/settings/providers/__tests__/Bedrock.spec.tsx index 99bf860b7a..0e04724a71 100644 --- a/webview-ui/src/components/settings/providers/__tests__/Bedrock.spec.tsx +++ b/webview-ui/src/components/settings/providers/__tests__/Bedrock.spec.tsx @@ -111,6 +111,21 @@ describe("Bedrock Component", () => { expect(mockSetApiConfigurationField).not.toHaveBeenCalled() }) + it("shows a placeholder and ARN guidance while the custom ARN is still empty", () => { + render( + , + ) + expect(screen.getByTestId("bedrock-request-model").querySelector("code")?.textContent).toBe("—") + expect(screen.getByText("settings:providers.awsArnRouting")).toBeInTheDocument() + }) + it.each<[OrganizationAllowList, boolean]>([ [{ allowAll: true, providers: {} }, true], [{ allowAll: false, providers: { bedrock: { allowAll: true } } }, true], @@ -148,7 +163,8 @@ describe("Bedrock Component", () => { }), ), ) - fireEvent.change(screen.getByLabelText("settings:providers.awsCatalogSelect"), { target: { value: arn } }) + const catalogSelect = screen.getByRole("option", { name: /Discovered/ }).closest("select")! + fireEvent.change(catalogSelect, { target: { value: arn } }) expect(mockSetApiConfigurationField.mock.calls).toEqual([ ["apiModelId", "custom-arn"], ["awsCustomArn", arn], diff --git a/webview-ui/src/components/settings/providers/__tests__/BedrockCatalog.spec.tsx b/webview-ui/src/components/settings/providers/__tests__/BedrockCatalog.spec.tsx index 786465392e..1beea894e7 100644 --- a/webview-ui/src/components/settings/providers/__tests__/BedrockCatalog.spec.tsx +++ b/webview-ui/src/components/settings/providers/__tests__/BedrockCatalog.spec.tsx @@ -4,6 +4,29 @@ import { vscode } from "@/utils/vscode" import { BedrockCatalog } from "../BedrockCatalog" vi.mock("@/utils/vscode", () => ({ vscode: { postMessage: vi.fn() } })) +// Radix Select needs pointer APIs JSDOM lacks; a native select keeps the value wiring testable. +vi.mock("@src/components/ui", () => ({ + Select: ({ + children, + value, + onValueChange, + }: { + children: React.ReactNode + value: string + onValueChange: (value: string) => void + }) => ( + + ), + SelectContent: ({ children }: { children: React.ReactNode }) => <>{children}, + SelectItem: ({ children, value }: { children: React.ReactNode; value: string }) => ( + + ), + SelectTrigger: () => null, + SelectValue: () => null, +})) beforeEach(() => vi.clearAllMocks()) diff --git a/webview-ui/src/i18n/locales/ca/settings.json b/webview-ui/src/i18n/locales/ca/settings.json index f95d6d22d2..91572f194a 100644 --- a/webview-ui/src/i18n/locales/ca/settings.json +++ b/webview-ui/src/i18n/locales/ca/settings.json @@ -564,7 +564,7 @@ "awsCatalogSelect": "Models regionals i perfils d'inferència", "awsCatalogEmpty": "No s'han retornat models de text en streaming ni perfils actius", "awsCatalogKinds": { - "regional": "Model fundacional — comprova els requisits de perfil d'inferència", + "regional": "Model fundacional — sota demanda en aquesta regió, no cal cap perfil d'inferència", "geographic": "Perfil d'inferència geogràfic", "global": "Perfil d'inferència global — mundial", "application": "Perfil d'aplicació — comprova les destinacions a AWS" diff --git a/webview-ui/src/i18n/locales/de/settings.json b/webview-ui/src/i18n/locales/de/settings.json index 6e0c99a679..17ce9eb25b 100644 --- a/webview-ui/src/i18n/locales/de/settings.json +++ b/webview-ui/src/i18n/locales/de/settings.json @@ -564,7 +564,7 @@ "awsCatalogSelect": "Regionale Modelle und Inferenzprofile", "awsCatalogEmpty": "Keine Textmodelle mit Streaming oder aktive Profile zurückgegeben", "awsCatalogKinds": { - "regional": "Basismodell — Anforderungen an Inferenzprofile prüfen", + "regional": "Basismodell — On-Demand in dieser Region, kein Inferenzprofil erforderlich", "geographic": "Geografisches Inferenzprofil", "global": "Globales Inferenzprofil — weltweit", "application": "Anwendungsprofil — Zielregionen in AWS prüfen" diff --git a/webview-ui/src/i18n/locales/en/settings.json b/webview-ui/src/i18n/locales/en/settings.json index 771eab3d11..20cb5ce347 100644 --- a/webview-ui/src/i18n/locales/en/settings.json +++ b/webview-ui/src/i18n/locales/en/settings.json @@ -644,7 +644,7 @@ "awsCatalogSelect": "Regional models and inference profiles", "awsCatalogEmpty": "No streaming text models or active profiles returned", "awsCatalogKinds": { - "regional": "Foundation model — check inference-profile requirements", + "regional": "Foundation model — on-demand in this region, no inference profile needed", "geographic": "Geographic inference profile", "global": "Global inference profile — worldwide", "application": "Application profile — check destinations in AWS" diff --git a/webview-ui/src/i18n/locales/es/settings.json b/webview-ui/src/i18n/locales/es/settings.json index 22069ec6af..d24449eee2 100644 --- a/webview-ui/src/i18n/locales/es/settings.json +++ b/webview-ui/src/i18n/locales/es/settings.json @@ -564,7 +564,7 @@ "awsCatalogSelect": "Modelos regionales y perfiles de inferencia", "awsCatalogEmpty": "No se devolvieron modelos de texto en streaming ni perfiles activos", "awsCatalogKinds": { - "regional": "Modelo fundacional — comprobar requisitos de perfil de inferencia", + "regional": "Modelo fundacional — bajo demanda en esta región, no requiere perfil de inferencia", "geographic": "Perfil de inferencia geográfico", "global": "Perfil de inferencia global — mundial", "application": "Perfil de aplicación — comprobar destinos en AWS" diff --git a/webview-ui/src/i18n/locales/fr/settings.json b/webview-ui/src/i18n/locales/fr/settings.json index 72fb9580d2..3de4d71f97 100644 --- a/webview-ui/src/i18n/locales/fr/settings.json +++ b/webview-ui/src/i18n/locales/fr/settings.json @@ -564,7 +564,7 @@ "awsCatalogSelect": "Modèles régionaux et profils d'inférence", "awsCatalogEmpty": "Aucun modèle de texte en streaming ni profil actif renvoyé", "awsCatalogKinds": { - "regional": "Modèle de fondation — vérifier les exigences de profil d'inférence", + "regional": "Modèle de fondation — à la demande dans cette région, aucun profil d'inférence requis", "geographic": "Profil d'inférence géographique", "global": "Profil d'inférence global — mondial", "application": "Profil d'application — vérifier les destinations dans AWS" diff --git a/webview-ui/src/i18n/locales/hi/settings.json b/webview-ui/src/i18n/locales/hi/settings.json index 5b25bb20c4..0dc0aead44 100644 --- a/webview-ui/src/i18n/locales/hi/settings.json +++ b/webview-ui/src/i18n/locales/hi/settings.json @@ -564,7 +564,7 @@ "awsCatalogSelect": "क्षेत्रीय मॉडल और अनुमान प्रोफ़ाइल", "awsCatalogEmpty": "कोई स्ट्रीमिंग टेक्स्ट मॉडल या सक्रिय प्रोफ़ाइल नहीं मिली", "awsCatalogKinds": { - "regional": "आधार मॉडल — अनुमान प्रोफ़ाइल की आवश्यकताएँ जाँचें", + "regional": "आधार मॉडल — इस क्षेत्र में ऑन-डिमांड, अनुमान प्रोफ़ाइल की आवश्यकता नहीं", "geographic": "भौगोलिक अनुमान प्रोफ़ाइल", "global": "वैश्विक अनुमान प्रोफ़ाइल — दुनिया भर में", "application": "एप्लिकेशन प्रोफ़ाइल — AWS में गंतव्य जाँचें" diff --git a/webview-ui/src/i18n/locales/id/settings.json b/webview-ui/src/i18n/locales/id/settings.json index f6c93a5438..6ec3c2a93b 100644 --- a/webview-ui/src/i18n/locales/id/settings.json +++ b/webview-ui/src/i18n/locales/id/settings.json @@ -564,7 +564,7 @@ "awsCatalogSelect": "Model regional dan profil inferensi", "awsCatalogEmpty": "Tidak ada model teks streaming atau profil aktif yang dikembalikan", "awsCatalogKinds": { - "regional": "Model dasar — periksa persyaratan profil inferensi", + "regional": "Model dasar — on-demand di wilayah ini, tidak perlu profil inferensi", "geographic": "Profil inferensi geografis", "global": "Profil inferensi global — seluruh dunia", "application": "Profil aplikasi — periksa tujuan di AWS" diff --git a/webview-ui/src/i18n/locales/it/settings.json b/webview-ui/src/i18n/locales/it/settings.json index 051bb91f4f..41d41cae63 100644 --- a/webview-ui/src/i18n/locales/it/settings.json +++ b/webview-ui/src/i18n/locales/it/settings.json @@ -564,7 +564,7 @@ "awsCatalogSelect": "Modelli regionali e profili di inferenza", "awsCatalogEmpty": "Nessun modello di testo in streaming o profilo attivo restituito", "awsCatalogKinds": { - "regional": "Modello di base — verifica i requisiti del profilo di inferenza", + "regional": "Modello di base — on demand in questa regione, nessun profilo di inferenza necessario", "geographic": "Profilo di inferenza geografico", "global": "Profilo di inferenza globale — mondiale", "application": "Profilo applicativo — verifica le destinazioni in AWS" diff --git a/webview-ui/src/i18n/locales/ja/settings.json b/webview-ui/src/i18n/locales/ja/settings.json index 56479bfce8..d6ee6af1c1 100644 --- a/webview-ui/src/i18n/locales/ja/settings.json +++ b/webview-ui/src/i18n/locales/ja/settings.json @@ -564,7 +564,7 @@ "awsCatalogSelect": "リージョン別モデルと推論プロファイル", "awsCatalogEmpty": "ストリーミング対応のテキストモデルまたはアクティブなプロファイルが返されませんでした", "awsCatalogKinds": { - "regional": "基盤モデル — 推論プロファイルの要件を確認", + "regional": "基盤モデル — このリージョンでオンデマンド、推論プロファイル不要", "geographic": "地理的推論プロファイル", "global": "グローバル推論プロファイル — 世界規模", "application": "アプリケーションプロファイル — AWS で宛先を確認" diff --git a/webview-ui/src/i18n/locales/ko/settings.json b/webview-ui/src/i18n/locales/ko/settings.json index ed92d14d80..f5c42bc9b5 100644 --- a/webview-ui/src/i18n/locales/ko/settings.json +++ b/webview-ui/src/i18n/locales/ko/settings.json @@ -564,7 +564,7 @@ "awsCatalogSelect": "리전별 모델 및 추론 프로필", "awsCatalogEmpty": "스트리밍 텍스트 모델이나 활성 프로필이 반환되지 않았습니다", "awsCatalogKinds": { - "regional": "기반 모델 — 추론 프로필 요구 사항 확인", + "regional": "기반 모델 — 이 리전에서 온디맨드, 추론 프로필 불필요", "geographic": "지리적 추론 프로필", "global": "글로벌 추론 프로필 — 전 세계", "application": "애플리케이션 프로필 — AWS에서 대상 확인" diff --git a/webview-ui/src/i18n/locales/nl/settings.json b/webview-ui/src/i18n/locales/nl/settings.json index a44e0d5e0a..f42a92d4aa 100644 --- a/webview-ui/src/i18n/locales/nl/settings.json +++ b/webview-ui/src/i18n/locales/nl/settings.json @@ -564,7 +564,7 @@ "awsCatalogSelect": "Regionale modellen en inferentieprofielen", "awsCatalogEmpty": "Geen streamingtekstmodellen of actieve profielen teruggegeven", "awsCatalogKinds": { - "regional": "Basismodel — controleer vereisten voor inferentieprofielen", + "regional": "Basismodel — on-demand in deze regio, geen inferentieprofiel nodig", "geographic": "Geografisch inferentieprofiel", "global": "Globaal inferentieprofiel — wereldwijd", "application": "Applicatieprofiel — controleer bestemmingen in AWS" diff --git a/webview-ui/src/i18n/locales/pl/settings.json b/webview-ui/src/i18n/locales/pl/settings.json index dbb42b6720..e3a13979af 100644 --- a/webview-ui/src/i18n/locales/pl/settings.json +++ b/webview-ui/src/i18n/locales/pl/settings.json @@ -564,7 +564,7 @@ "awsCatalogSelect": "Modele regionalne i profile wnioskowania", "awsCatalogEmpty": "Nie zwrócono modeli tekstowych ze strumieniowaniem ani aktywnych profili", "awsCatalogKinds": { - "regional": "Model bazowy — sprawdź wymagania profilu wnioskowania", + "regional": "Model bazowy — na żądanie w tym regionie, profil wnioskowania nie jest wymagany", "geographic": "Geograficzny profil wnioskowania", "global": "Globalny profil wnioskowania — cały świat", "application": "Profil aplikacji — sprawdź regiony docelowe w AWS" diff --git a/webview-ui/src/i18n/locales/pt-BR/settings.json b/webview-ui/src/i18n/locales/pt-BR/settings.json index 8c49bb78c2..cb98001193 100644 --- a/webview-ui/src/i18n/locales/pt-BR/settings.json +++ b/webview-ui/src/i18n/locales/pt-BR/settings.json @@ -564,7 +564,7 @@ "awsCatalogSelect": "Modelos regionais e perfis de inferência", "awsCatalogEmpty": "Nenhum modelo de texto com streaming ou perfil ativo retornado", "awsCatalogKinds": { - "regional": "Modelo de base — confira os requisitos de perfil de inferência", + "regional": "Modelo de base — sob demanda nesta região, sem necessidade de perfil de inferência", "geographic": "Perfil de inferência geográfico", "global": "Perfil de inferência global — mundial", "application": "Perfil de aplicação — confira os destinos na AWS" diff --git a/webview-ui/src/i18n/locales/ru/settings.json b/webview-ui/src/i18n/locales/ru/settings.json index 20a552bfd2..11b815f401 100644 --- a/webview-ui/src/i18n/locales/ru/settings.json +++ b/webview-ui/src/i18n/locales/ru/settings.json @@ -564,7 +564,7 @@ "awsCatalogSelect": "Региональные модели и профили вывода", "awsCatalogEmpty": "Потоковые текстовые модели и активные профили не найдены", "awsCatalogKinds": { - "regional": "Базовая модель — проверьте требования к профилю вывода", + "regional": "Базовая модель — по запросу в этом регионе, профиль вывода не требуется", "geographic": "Географический профиль вывода", "global": "Глобальный профиль вывода — весь мир", "application": "Профиль приложения — проверьте целевые регионы в AWS" diff --git a/webview-ui/src/i18n/locales/tr/settings.json b/webview-ui/src/i18n/locales/tr/settings.json index a4ee0b54f9..41f3030e83 100644 --- a/webview-ui/src/i18n/locales/tr/settings.json +++ b/webview-ui/src/i18n/locales/tr/settings.json @@ -564,7 +564,7 @@ "awsCatalogSelect": "Bölgesel modeller ve çıkarım profilleri", "awsCatalogEmpty": "Akış destekli metin modeli veya etkin profil döndürülmedi", "awsCatalogKinds": { - "regional": "Temel model — çıkarım profili gereksinimlerini kontrol edin", + "regional": "Temel model — bu bölgede isteğe bağlı, çıkarım profili gerekmez", "geographic": "Coğrafi çıkarım profili", "global": "Küresel çıkarım profili — dünya çapında", "application": "Uygulama profili — AWS'de hedefleri kontrol edin" diff --git a/webview-ui/src/i18n/locales/vi/settings.json b/webview-ui/src/i18n/locales/vi/settings.json index 8c8acbf14c..30ac98b41a 100644 --- a/webview-ui/src/i18n/locales/vi/settings.json +++ b/webview-ui/src/i18n/locales/vi/settings.json @@ -564,7 +564,7 @@ "awsCatalogSelect": "Mô hình theo vùng và hồ sơ suy luận", "awsCatalogEmpty": "Không có mô hình văn bản phát trực tuyến hoặc hồ sơ đang hoạt động được trả về", "awsCatalogKinds": { - "regional": "Mô hình nền tảng — kiểm tra yêu cầu về hồ sơ suy luận", + "regional": "Mô hình nền tảng — theo yêu cầu trong vùng này, không cần hồ sơ suy luận", "geographic": "Hồ sơ suy luận theo địa lý", "global": "Hồ sơ suy luận toàn cầu — toàn thế giới", "application": "Hồ sơ ứng dụng — kiểm tra các đích trong AWS" diff --git a/webview-ui/src/i18n/locales/zh-CN/settings.json b/webview-ui/src/i18n/locales/zh-CN/settings.json index 2f0ce4affb..52e1cd4b4d 100644 --- a/webview-ui/src/i18n/locales/zh-CN/settings.json +++ b/webview-ui/src/i18n/locales/zh-CN/settings.json @@ -564,7 +564,7 @@ "awsCatalogSelect": "区域模型和推理配置文件", "awsCatalogEmpty": "未返回流式文本模型或活动配置文件", "awsCatalogKinds": { - "regional": "基础模型 — 请检查推理配置文件要求", + "regional": "基础模型 — 在此区域按需可用,无需推理配置文件", "geographic": "地理推理配置文件", "global": "全局推理配置文件 — 全球", "application": "应用程序配置文件 — 请在 AWS 中检查目标区域" diff --git a/webview-ui/src/i18n/locales/zh-TW/settings.json b/webview-ui/src/i18n/locales/zh-TW/settings.json index d0ef98927f..d4731d230c 100644 --- a/webview-ui/src/i18n/locales/zh-TW/settings.json +++ b/webview-ui/src/i18n/locales/zh-TW/settings.json @@ -591,7 +591,7 @@ "awsCatalogSelect": "區域模型和推論設定檔", "awsCatalogEmpty": "未傳回串流文字模型或使用中的設定檔", "awsCatalogKinds": { - "regional": "基礎模型 — 請檢查推論設定檔需求", + "regional": "基礎模型 — 在此區域隨選可用,無需推論設定檔", "geographic": "地理推論設定檔", "global": "全域推論設定檔 — 全球", "application": "應用程式設定檔 — 請在 AWS 中檢查目的地" From 047e5d9ba14b287fc190515cfea448026edb5b3c Mon Sep 17 00:00:00 2001 From: PierrunoYT Date: Mon, 5 Oct 2026 18:00:41 +0200 Subject: [PATCH 5/6] fix(bedrock): isolate catalog credentials and clarify regional availability Amp-Thread-ID: https://ampcode.com/threads/T-01a10cc3-9ccd-740a-917e-e09003b7f29a Co-authored-by: Amp --- .../fetchers/__tests__/bedrock.spec.ts | 24 ++++++++++- src/api/providers/fetchers/bedrock.ts | 2 + .../settings/providers/BedrockCatalog.tsx | 14 +++---- .../providers/__tests__/Bedrock.visual.tsx | 20 +++++++++ .../__tests__/BedrockCatalog.spec.tsx | 42 +++++++++++++++++++ webview-ui/src/i18n/locales/ca/settings.json | 2 +- webview-ui/src/i18n/locales/de/settings.json | 2 +- webview-ui/src/i18n/locales/en/settings.json | 2 +- webview-ui/src/i18n/locales/es/settings.json | 2 +- webview-ui/src/i18n/locales/fr/settings.json | 2 +- webview-ui/src/i18n/locales/hi/settings.json | 2 +- webview-ui/src/i18n/locales/id/settings.json | 2 +- webview-ui/src/i18n/locales/it/settings.json | 2 +- webview-ui/src/i18n/locales/ja/settings.json | 2 +- webview-ui/src/i18n/locales/ko/settings.json | 2 +- webview-ui/src/i18n/locales/nl/settings.json | 2 +- webview-ui/src/i18n/locales/pl/settings.json | 2 +- .../src/i18n/locales/pt-BR/settings.json | 2 +- webview-ui/src/i18n/locales/ru/settings.json | 2 +- webview-ui/src/i18n/locales/tr/settings.json | 2 +- webview-ui/src/i18n/locales/vi/settings.json | 2 +- .../src/i18n/locales/zh-CN/settings.json | 2 +- .../src/i18n/locales/zh-TW/settings.json | 2 +- 23 files changed, 111 insertions(+), 27 deletions(-) diff --git a/src/api/providers/fetchers/__tests__/bedrock.spec.ts b/src/api/providers/fetchers/__tests__/bedrock.spec.ts index 447593b214..9dd9981024 100644 --- a/src/api/providers/fetchers/__tests__/bedrock.spec.ts +++ b/src/api/providers/fetchers/__tests__/bedrock.spec.ts @@ -81,13 +81,35 @@ it("uses the selected region and credentials, and includes every profile page wi it("uses a profile and releases the client on permission failure without fabricating availability", async () => { send.mockRejectedValue(new Error("AccessDenied")) await expect( - getBedrockCatalog({ awsRegion: "us-east-1", awsUseProfile: true, awsProfile: "work" }), + getBedrockCatalog({ + awsRegion: "us-east-1", + awsUseProfile: true, + awsProfile: "work", + awsAccessKey: "retained-key", + awsSecretKey: "retained-secret", + }), ).rejects.toThrow("AccessDenied") expect(fromIni).toHaveBeenCalledWith({ profile: "work", ignoreCache: true }) expect(BedrockClient).toHaveBeenCalledWith(expect.objectContaining({ credentials: "profile-provider" })) expect(destroy).toHaveBeenCalledOnce() }) +it.each([undefined, "", " "])( + "rejects incomplete profile mode (%j) without using retained keys", + async (awsProfile) => { + await expect( + getBedrockCatalog({ + awsRegion: "eu-west-3", + awsUseProfile: true, + awsProfile, + awsAccessKey: "retained-key", + awsSecretKey: "retained-secret", + }), + ).rejects.toThrow("Select an AWS profile") + expect(BedrockClient).not.toHaveBeenCalled() + }, +) + it("does not silently use the default credential chain when API-key authentication is selected", async () => { await expect(getBedrockCatalog({ awsRegion: "eu-west-3", awsUseApiKey: true })).rejects.toThrow("IAM credentials") expect(BedrockClient).not.toHaveBeenCalled() diff --git a/src/api/providers/fetchers/bedrock.ts b/src/api/providers/fetchers/bedrock.ts index 961a887868..1c75da0f3e 100644 --- a/src/api/providers/fetchers/bedrock.ts +++ b/src/api/providers/fetchers/bedrock.ts @@ -11,6 +11,8 @@ export async function getBedrockCatalog(options: ProviderSettings): Promise