Add support for Amazon Bedrock provider (#1185)

- follows existing patterns for AI SDK to provide Bedrock integration
- Uses Bedrock's API token feature for authentication which provides a
standard experience
- bedrock provided models match the Anthropic provided models (for now)


**Disclaimer**: The contributing docs are extremely sparse. I don't
actually know how to build this and get this running in Electron


## Testing

- AWS Bedrock provider is available for selection
<img width="994" height="496" alt="image"
src="https://github.com/user-attachments/assets/3cb21fed-9826-40e5-8019-b2b5df5e873b"
/>

- The provider settings also show the right models and offer the right
env variable to use
<img width="949" height="862" alt="image"
src="https://github.com/user-attachments/assets/8c23d5c8-d84d-4bf7-856a-8dc8d9d6c4b4"
/>


    
<!-- This is an auto-generated description by cubic. -->
---

## Summary by cubic
Adds AWS Bedrock as a provider so users can run Claude models via
Bedrock with API token authentication. The settings now list Bedrock
with supported models and a new env var.

- New Features
- New provider: bedrock using @ai-sdk/amazon-bedrock, wired into model
client and schemas.
- Models: Claude 4 Sonnet, Claude 3.7 Sonnet, Claude 3.5 Sonnet (Bedrock
model IDs).
- Settings: shows AWS Bedrock with correct models and env var
AWS_BEARER_TOKEN_BEDROCK.
  - Default region: us-east-1.

- Migration
  - Set AWS_BEARER_TOKEN_BEDROCK with your Bedrock API token.
  - Select AWS Bedrock in settings and pick a model.

<!-- End of auto-generated description by cubic. -->

Co-authored-by: Samrat Jha <samratj@amazon.com>
Co-authored-by: Will Chen <willchen90@gmail.com>
This commit is contained in:
Samrat Jha
2025-09-09 01:52:12 -04:00
committed by GitHub
parent 4db6d63b72
commit 938595aab2
5 changed files with 252 additions and 4 deletions

205
package-lock.json generated
View File

@@ -6,9 +6,10 @@
"packages": { "packages": {
"": { "": {
"name": "dyad", "name": "dyad",
"version": "0.20.0-beta.1", "version": "0.20.0-beta.1",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@ai-sdk/amazon-bedrock": "^3.0.15",
"@ai-sdk/anthropic": "^2.0.4", "@ai-sdk/anthropic": "^2.0.4",
"@ai-sdk/azure": "^2.0.17", "@ai-sdk/azure": "^2.0.17",
"@ai-sdk/google": "^2.0.6", "@ai-sdk/google": "^2.0.6",
@@ -129,10 +130,47 @@
"node": ">=20" "node": ">=20"
} }
}, },
"node_modules/@ai-sdk/amazon-bedrock": {
"version": "3.0.15",
"resolved": "https://registry.npmjs.org/@ai-sdk/amazon-bedrock/-/amazon-bedrock-3.0.15.tgz",
"integrity": "sha512-gRzjgyeaavYO4Vq4/yILZxinGrXTN1AGaEYAvFQ7fn1CP4kAreLEVDTh2du85WTQHxFck7f3OGKRWXNqQZ7OCA==",
"license": "Apache-2.0",
"dependencies": {
"@ai-sdk/anthropic": "2.0.11",
"@ai-sdk/provider": "2.0.0",
"@ai-sdk/provider-utils": "3.0.7",
"@smithy/eventstream-codec": "^4.0.1",
"@smithy/util-utf8": "^4.0.0",
"aws4fetch": "^1.0.20"
},
"engines": {
"node": ">=18"
},
"peerDependencies": {
"zod": "^3.25.76 || ^4"
}
},
"node_modules/@ai-sdk/amazon-bedrock/node_modules/@ai-sdk/provider-utils": {
"version": "3.0.7",
"resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-3.0.7.tgz",
"integrity": "sha512-o3BS5/t8KnBL3ubP8k3w77AByOypLm+pkIL/DCw0qKkhDbvhCy+L3hRTGPikpdb8WHcylAeKsjgwOxhj4cqTUA==",
"license": "Apache-2.0",
"dependencies": {
"@ai-sdk/provider": "2.0.0",
"@standard-schema/spec": "^1.0.0",
"eventsource-parser": "^3.0.5"
},
"engines": {
"node": ">=18"
},
"peerDependencies": {
"zod": "^3.25.76 || ^4"
}
},
"node_modules/@ai-sdk/anthropic": { "node_modules/@ai-sdk/anthropic": {
"version": "2.0.9", "version": "2.0.11",
"resolved": "https://registry.npmjs.org/@ai-sdk/anthropic/-/anthropic-2.0.9.tgz", "resolved": "https://registry.npmjs.org/@ai-sdk/anthropic/-/anthropic-2.0.11.tgz",
"integrity": "sha512-1kQgL2A3PeqfEcHHmqy4NxRc8rbgLS71bHBuvDFfDz3VAAyndkilPMCLNDSP2mJVGAej2EMWJ1sShRAxzn70jA==", "integrity": "sha512-NCHWE/BnHm9CBw2M17kPwe4bKEUBtntzY26uvoZmWZfCvu2muYBR03pN2pdYmRRZlhpKk1kAOwPOzs9OW8ZC9Q=="
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@ai-sdk/provider": "2.0.0", "@ai-sdk/provider": "2.0.0",
@@ -373,6 +411,82 @@
"node": ">=6.0.0" "node": ">=6.0.0"
} }
}, },
"node_modules/@aws-crypto/crc32": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-5.2.0.tgz",
"integrity": "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==",
"license": "Apache-2.0",
"dependencies": {
"@aws-crypto/util": "^5.2.0",
"@aws-sdk/types": "^3.222.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/@aws-crypto/util": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz",
"integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/types": "^3.222.0",
"@smithy/util-utf8": "^2.0.0",
"tslib": "^2.6.2"
}
},
"node_modules/@aws-crypto/util/node_modules/@smithy/is-array-buffer": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz",
"integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==",
"license": "Apache-2.0",
"dependencies": {
"tslib": "^2.6.2"
},
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/@aws-crypto/util/node_modules/@smithy/util-buffer-from": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz",
"integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==",
"license": "Apache-2.0",
"dependencies": {
"@smithy/is-array-buffer": "^2.2.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/@aws-crypto/util/node_modules/@smithy/util-utf8": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz",
"integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==",
"license": "Apache-2.0",
"dependencies": {
"@smithy/util-buffer-from": "^2.2.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/@aws-sdk/types": {
"version": "3.862.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.862.0.tgz",
"integrity": "sha512-Bei+RL0cDxxV+lW2UezLbCYYNeJm6Nzee0TpW0FfyTRBhH9C1XQh4+x+IClriXvgBnRquTMMYsmJfvx8iyLKrg==",
"license": "Apache-2.0",
"dependencies": {
"@smithy/types": "^4.3.2",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@babel/code-frame": { "node_modules/@babel/code-frame": {
"version": "7.27.1", "version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
@@ -6100,6 +6214,83 @@
"url": "https://github.com/sindresorhus/is?sponsor=1" "url": "https://github.com/sindresorhus/is?sponsor=1"
} }
}, },
"node_modules/@smithy/eventstream-codec": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-4.0.5.tgz",
"integrity": "sha512-miEUN+nz2UTNoRYRhRqVTJCx7jMeILdAurStT2XoS+mhokkmz1xAPp95DFW9Gxt4iF2VBqpeF9HbTQ3kY1viOA==",
"license": "Apache-2.0",
"dependencies": {
"@aws-crypto/crc32": "5.2.0",
"@smithy/types": "^4.3.2",
"@smithy/util-hex-encoding": "^4.0.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@smithy/is-array-buffer": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.0.0.tgz",
"integrity": "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==",
"license": "Apache-2.0",
"dependencies": {
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@smithy/types": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.2.tgz",
"integrity": "sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw==",
"license": "Apache-2.0",
"dependencies": {
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@smithy/util-buffer-from": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.0.0.tgz",
"integrity": "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug==",
"license": "Apache-2.0",
"dependencies": {
"@smithy/is-array-buffer": "^4.0.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@smithy/util-hex-encoding": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.0.0.tgz",
"integrity": "sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw==",
"license": "Apache-2.0",
"dependencies": {
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@smithy/util-utf8": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.0.0.tgz",
"integrity": "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==",
"license": "Apache-2.0",
"dependencies": {
"@smithy/util-buffer-from": "^4.0.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@standard-schema/spec": { "node_modules/@standard-schema/spec": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz",
@@ -7875,6 +8066,12 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/aws4fetch": {
"version": "1.0.20",
"resolved": "https://registry.npmjs.org/aws4fetch/-/aws4fetch-1.0.20.tgz",
"integrity": "sha512-/djoAN709iY65ETD6LKCtyyEI04XIBP5xVvfmNxsEP0uJB5tyaGBztSryRr4HqMStr9R06PisQE7m9zDTXKu6g==",
"license": "MIT"
},
"node_modules/axios": { "node_modules/axios": {
"version": "1.11.0", "version": "1.11.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.11.0.tgz", "resolved": "https://registry.npmjs.org/axios/-/axios-1.11.0.tgz",

View File

@@ -85,6 +85,7 @@
"vitest": "^3.1.1" "vitest": "^3.1.1"
}, },
"dependencies": { "dependencies": {
"@ai-sdk/amazon-bedrock": "^3.0.15",
"@ai-sdk/anthropic": "^2.0.4", "@ai-sdk/anthropic": "^2.0.4",
"@ai-sdk/azure": "^2.0.17", "@ai-sdk/azure": "^2.0.17",
"@ai-sdk/google": "^2.0.6", "@ai-sdk/google": "^2.0.6",

View File

@@ -253,6 +253,32 @@ export const MODEL_OPTIONS: Record<string, ModelOption[]> = {
temperature: 0, temperature: 0,
}, },
], ],
bedrock: [
{
name: "us.anthropic.claude-sonnet-4-20250514-v1:0",
displayName: "Claude 4 Sonnet",
description: "Excellent coder",
maxOutputTokens: 16_000,
contextWindow: 200_000,
temperature: 0,
},
{
name: "us.anthropic.claude-3-7-sonnet-20250219-v1:0",
displayName: "Claude 3.7 Sonnet",
description: "Excellent coder",
maxOutputTokens: 16_000,
contextWindow: 200_000,
temperature: 0,
},
{
name: "us.anthropic.claude-3-5-sonnet-20241022-v2:0",
displayName: "Claude 3.5 Sonnet",
description: "Good coder, excellent at following instructions",
maxOutputTokens: 8_000,
contextWindow: 200_000,
temperature: 0,
},
],
}; };
export const PROVIDER_TO_ENV_VAR: Record<string, string> = { export const PROVIDER_TO_ENV_VAR: Record<string, string> = {
@@ -261,6 +287,7 @@ export const PROVIDER_TO_ENV_VAR: Record<string, string> = {
google: "GEMINI_API_KEY", google: "GEMINI_API_KEY",
openrouter: "OPENROUTER_API_KEY", openrouter: "OPENROUTER_API_KEY",
azure: "AZURE_API_KEY", azure: "AZURE_API_KEY",
bedrock: "AWS_BEARER_TOKEN_BEDROCK",
}; };
export const CLOUD_PROVIDERS: Record< export const CLOUD_PROVIDERS: Record<
@@ -317,6 +344,12 @@ export const CLOUD_PROVIDERS: Record<
gatewayPrefix: "", gatewayPrefix: "",
secondary: true, secondary: true,
}, },
bedrock: {
displayName: "AWS Bedrock",
hasFreeTier: false,
websiteUrl: "https://console.aws.amazon.com/bedrock/",
gatewayPrefix: "bedrock/",
},
}; };
const LOCAL_PROVIDERS: Record< const LOCAL_PROVIDERS: Record<

View File

@@ -5,6 +5,7 @@ import { createVertex as createGoogleVertex } from "@ai-sdk/google-vertex";
import { azure } from "@ai-sdk/azure"; import { azure } from "@ai-sdk/azure";
import { createOpenRouter } from "@openrouter/ai-sdk-provider"; import { createOpenRouter } from "@openrouter/ai-sdk-provider";
import { createOpenAICompatible } from "@ai-sdk/openai-compatible"; import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
import { createAmazonBedrock } from "@ai-sdk/amazon-bedrock";
import type { import type {
LargeLanguageModel, LargeLanguageModel,
UserSettings, UserSettings,
@@ -342,6 +343,21 @@ function getRegularModelClient(
backupModelClients: [], backupModelClients: [],
}; };
} }
case "bedrock": {
// AWS Bedrock supports API key authentication using AWS_BEARER_TOKEN_BEDROCK
// See: https://sdk.vercel.ai/providers/ai-sdk-providers/amazon-bedrock#api-key-authentication
const provider = createAmazonBedrock({
apiKey: apiKey,
region: getEnvVar("AWS_REGION") || "us-east-1",
});
return {
modelClient: {
model: provider(model.name),
builtinProviderId: providerId,
},
backupModelClients: [],
};
}
default: { default: {
// Handle custom providers // Handle custom providers
if (providerConfig.type === "custom") { if (providerConfig.type === "custom") {

View File

@@ -36,6 +36,7 @@ const providers = [
"ollama", "ollama",
"lmstudio", "lmstudio",
"azure", "azure",
"bedrock",
] as const; ] as const;
export const cloudProviders = providers.filter( export const cloudProviders = providers.filter(