Skip to content

Commit d62a260

Browse files
jrroomote
andauthored
Add support for bedrock api keys (#6132)
Co-authored-by: Roo Code <[email protected]>
1 parent b140634 commit d62a260

29 files changed

+862
-584
lines changed

packages/types/src/global-settings.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ export const SECRET_STATE_KEYS = [
164164
"glamaApiKey",
165165
"openRouterApiKey",
166166
"awsAccessKey",
167+
"awsApiKey",
167168
"awsSecretKey",
168169
"awsSessionToken",
169170
"openAiApiKey",

packages/types/src/provider-settings.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ const bedrockSchema = apiModelIdProviderModelSchema.extend({
114114
awsUsePromptCache: z.boolean().optional(),
115115
awsProfile: z.string().optional(),
116116
awsUseProfile: z.boolean().optional(),
117+
awsApiKey: z.string().optional(),
118+
awsUseApiKey: z.boolean().optional(),
117119
awsCustomArn: z.string().optional(),
118120
awsModelContextWindow: z.number().optional(),
119121
awsBedrockEndpointEnabled: z.boolean().optional(),

packages/types/src/providers/bedrock.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ export const BEDROCK_MAX_TOKENS = 4096
360360

361361
export const BEDROCK_DEFAULT_CONTEXT = 128_000
362362

363-
// AWS Bedrock Inference Profile mapping based on official documentation
363+
// Amazon Bedrock Inference Profile mapping based on official documentation
364364
// https://docs.aws.amazon.com/bedrock/latest/userguide/inference-profiles-support.html
365365
// This mapping is pre-ordered by pattern length (descending) to ensure more specific patterns match first
366366
export const AWS_INFERENCE_PROFILE_MAPPING: Array<[string, string]> = [
@@ -378,7 +378,7 @@ export const AWS_INFERENCE_PROFILE_MAPPING: Array<[string, string]> = [
378378
["sa-", "sa."],
379379
]
380380

381-
// AWS Bedrock supported regions for the regions dropdown
381+
// Amazon Bedrock supported regions for the regions dropdown
382382
// Based on official AWS documentation
383383
export const BEDROCK_REGIONS = [
384384
{ value: "us-east-1", label: "us-east-1" },

pnpm-lock.yaml

Lines changed: 602 additions & 553 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/api/providers/__tests__/bedrock-inference-profiles.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ vitest.mock("@aws-sdk/client-bedrock-runtime", () => {
1616
}
1717
})
1818

19-
describe("AWS Bedrock Inference Profiles", () => {
19+
describe("Amazon Bedrock Inference Profiles", () => {
2020
// Helper function to create a handler with specific options
2121
const createHandler = (options: Partial<ApiHandlerOptions> = {}) => {
2222
const defaultOptions: ApiHandlerOptions = {

src/api/providers/__tests__/bedrock-reasoning.spec.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,5 +278,51 @@ describe("AwsBedrockHandler - Extended Thinking", () => {
278278
expect(reasoningChunks[0].text).toBe("Let me think...")
279279
expect(reasoningChunks[1].text).toBe(" about this problem.")
280280
})
281+
282+
it("should support API key authentication", async () => {
283+
handler = new AwsBedrockHandler({
284+
apiProvider: "bedrock",
285+
apiModelId: "anthropic.claude-3-5-sonnet-20241022-v2:0",
286+
awsRegion: "us-east-1",
287+
awsUseApiKey: true,
288+
awsApiKey: "test-api-key-token",
289+
})
290+
291+
mockSend.mockResolvedValue({
292+
stream: (async function* () {
293+
yield { messageStart: { role: "assistant" } }
294+
yield {
295+
contentBlockStart: {
296+
start: { text: "Hello from API key auth" },
297+
contentBlockIndex: 0,
298+
},
299+
}
300+
yield { metadata: { usage: { inputTokens: 100, outputTokens: 50 } } }
301+
})(),
302+
})
303+
304+
const messages = [{ role: "user" as const, content: "Test message" }]
305+
const stream = handler.createMessage("System prompt", messages)
306+
307+
const chunks = []
308+
for await (const chunk of stream) {
309+
chunks.push(chunk)
310+
}
311+
312+
// Verify the client was created with API key token
313+
expect(BedrockRuntimeClient).toHaveBeenCalledWith(
314+
expect.objectContaining({
315+
region: "us-east-1",
316+
token: { token: "test-api-key-token" },
317+
authSchemePreference: ["httpBearerAuth"],
318+
}),
319+
)
320+
321+
// Verify the stream worked correctly
322+
expect(mockSend).toHaveBeenCalledTimes(1)
323+
const textChunks = chunks.filter((c) => c.type === "text")
324+
expect(textChunks).toHaveLength(1)
325+
expect(textChunks[0].text).toBe("Hello from API key auth")
326+
})
281327
})
282328
})

src/api/providers/__tests__/bedrock-vpc-endpoint.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import { BedrockRuntimeClient } from "@aws-sdk/client-bedrock-runtime"
2929
// Get access to the mocked functions
3030
const mockBedrockRuntimeClient = vi.mocked(BedrockRuntimeClient)
3131

32-
describe("AWS Bedrock VPC Endpoint Functionality", () => {
32+
describe("Amazon Bedrock VPC Endpoint Functionality", () => {
3333
beforeEach(() => {
3434
// Clear all mocks before each test
3535
vi.clearAllMocks()

src/api/providers/bedrock.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,11 @@ export class AwsBedrockHandler extends BaseProvider implements SingleCompletionH
222222
this.options.awsBedrockEndpointEnabled && { endpoint: this.options.awsBedrockEndpoint }),
223223
}
224224

225-
if (this.options.awsUseProfile && this.options.awsProfile) {
225+
if (this.options.awsUseApiKey && this.options.awsApiKey) {
226+
// Use API key/token-based authentication if enabled and API key is set
227+
clientConfig.token = { token: this.options.awsApiKey }
228+
clientConfig.authSchemePreference = ["httpBearerAuth"] // Otherwise there's no end of credential problems.
229+
} else if (this.options.awsUseProfile && this.options.awsProfile) {
226230
// Use profile-based credentials if enabled and profile is set
227231
clientConfig.credentials = fromIni({
228232
profile: this.options.awsProfile,
@@ -1078,7 +1082,7 @@ Please verify:
10781082
"throttl",
10791083
"rate",
10801084
"limit",
1081-
"bedrock is unable to process your request", // AWS Bedrock specific throttling message
1085+
"bedrock is unable to process your request", // Amazon Bedrock specific throttling message
10821086
"please wait",
10831087
"quota exceeded",
10841088
"service unavailable",
@@ -1124,7 +1128,7 @@ Suggestions:
11241128
Please try:
11251129
1. Contact AWS support to request a quota increase
11261130
2. Reduce request frequency temporarily
1127-
3. Check your AWS Bedrock quotas in the AWS console
1131+
3. Check your Amazon Bedrock quotas in the AWS console
11281132
4. Consider using a different model or region with available capacity
11291133
11301134
`,
@@ -1139,15 +1143,15 @@ Please try:
11391143
11401144
Please try:
11411145
1. Wait a few minutes and retry
1142-
2. Check the model status in AWS Bedrock console
1146+
2. Check the model status in Amazon Bedrock console
11431147
3. Verify the model is properly provisioned
11441148
11451149
`,
11461150
logLevel: "error",
11471151
},
11481152
INTERNAL_SERVER_ERROR: {
11491153
patterns: ["internal server error", "internal error", "server error", "service error"],
1150-
messageTemplate: `AWS Bedrock internal server error. This is a temporary service issue.
1154+
messageTemplate: `Amazon Bedrock internal server error. This is a temporary service issue.
11511155
11521156
Please try:
11531157
1. Retry the request after a brief delay
@@ -1184,7 +1188,7 @@ Please try:
11841188
],
11851189
messageTemplate: `Parameter validation error: {errorMessage}
11861190
1187-
This error indicates that the request parameters don't match AWS Bedrock's expected format.
1191+
This error indicates that the request parameters don't match Amazon Bedrock's expected format.
11881192
11891193
Common causes:
11901194
1. Extended thinking parameter format is incorrect
@@ -1193,7 +1197,7 @@ Common causes:
11931197
11941198
Please check:
11951199
- Model supports the requested features (extended thinking, etc.)
1196-
- Parameter format matches AWS Bedrock specification
1200+
- Parameter format matches Amazon Bedrock specification
11971201
- Model ID is correct for the requested features`,
11981202
logLevel: "error",
11991203
},
@@ -1218,7 +1222,7 @@ Please check:
12181222
return "THROTTLING"
12191223
}
12201224

1221-
// Check for AWS Bedrock specific throttling exception names
1225+
// Check for Amazon Bedrock specific throttling exception names
12221226
if ((error as any).name === "ThrottlingException" || (error as any).__type === "ThrottlingException") {
12231227
return "THROTTLING"
12241228
}

src/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -413,8 +413,8 @@
413413
"@anthropic-ai/bedrock-sdk": "^0.10.2",
414414
"@anthropic-ai/sdk": "^0.37.0",
415415
"@anthropic-ai/vertex-sdk": "^0.7.0",
416-
"@aws-sdk/client-bedrock-runtime": "^3.779.0",
417-
"@aws-sdk/credential-providers": "^3.806.0",
416+
"@aws-sdk/client-bedrock-runtime": "^3.848.0",
417+
"@aws-sdk/credential-providers": "^3.848.0",
418418
"@google/genai": "^1.0.0",
419419
"@lmstudio/sdk": "^1.1.1",
420420
"@mistralai/mistralai": "^1.3.6",

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

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useCallback, useState, useEffect } from "react"
22
import { Checkbox } from "vscrui"
3-
import { VSCodeTextField, VSCodeRadio, VSCodeRadioGroup } from "@vscode/webview-ui-toolkit/react"
3+
import { VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
44

55
import { type ProviderSettings, type ModelInfo, BEDROCK_REGIONS } from "@roo-code/types"
66

@@ -37,19 +37,51 @@ export const Bedrock = ({ apiConfiguration, setApiConfigurationField, selectedMo
3737

3838
return (
3939
<>
40-
<VSCodeRadioGroup
41-
value={apiConfiguration?.awsUseProfile ? "profile" : "credentials"}
42-
onChange={handleInputChange(
43-
"awsUseProfile",
44-
(e) => (e.target as HTMLInputElement).value === "profile",
45-
)}>
46-
<VSCodeRadio value="credentials">{t("settings:providers.awsCredentials")}</VSCodeRadio>
47-
<VSCodeRadio value="profile">{t("settings:providers.awsProfile")}</VSCodeRadio>
48-
</VSCodeRadioGroup>
40+
<div>
41+
<label className="block font-medium mb-1">Authentication Method</label>
42+
<Select
43+
value={
44+
apiConfiguration?.awsUseApiKey
45+
? "apikey"
46+
: apiConfiguration?.awsUseProfile
47+
? "profile"
48+
: "credentials"
49+
}
50+
onValueChange={(value) => {
51+
if (value === "apikey") {
52+
setApiConfigurationField("awsUseApiKey", true)
53+
setApiConfigurationField("awsUseProfile", false)
54+
} else if (value === "profile") {
55+
setApiConfigurationField("awsUseApiKey", false)
56+
setApiConfigurationField("awsUseProfile", true)
57+
} else {
58+
setApiConfigurationField("awsUseApiKey", false)
59+
setApiConfigurationField("awsUseProfile", false)
60+
}
61+
}}>
62+
<SelectTrigger className="w-full">
63+
<SelectValue placeholder={t("settings:common.select")} />
64+
</SelectTrigger>
65+
<SelectContent>
66+
<SelectItem value="credentials">{t("settings:providers.awsCredentials")}</SelectItem>
67+
<SelectItem value="profile">{t("settings:providers.awsProfile")}</SelectItem>
68+
<SelectItem value="apikey">{t("settings:providers.awsApiKey")}</SelectItem>
69+
</SelectContent>
70+
</Select>
71+
</div>
4972
<div className="text-sm text-vscode-descriptionForeground -mt-3">
5073
{t("settings:providers.apiKeyStorageNotice")}
5174
</div>
52-
{apiConfiguration?.awsUseProfile ? (
75+
{apiConfiguration?.awsUseApiKey ? (
76+
<VSCodeTextField
77+
value={apiConfiguration?.awsApiKey || ""}
78+
type="password"
79+
onInput={handleInputChange("awsApiKey")}
80+
placeholder={t("settings:placeholders.apiKey")}
81+
className="w-full">
82+
<label className="block font-medium mb-1">{t("settings:providers.awsApiKey")}</label>
83+
</VSCodeTextField>
84+
) : apiConfiguration?.awsUseProfile ? (
5385
<VSCodeTextField
5486
value={apiConfiguration?.awsProfile || ""}
5587
onInput={handleInputChange("awsProfile")}

0 commit comments

Comments
 (0)