From 938595aab2b182388ba5d6c7c3a6f0febc8d5fca Mon Sep 17 00:00:00 2001
From: Samrat Jha <43038847+samratjha96@users.noreply.github.com>
Date: Tue, 9 Sep 2025 01:52:12 -0400
Subject: [PATCH] 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
- The provider settings also show the right models and offer the right
env variable to use
---
## 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.
Co-authored-by: Samrat Jha
Co-authored-by: Will Chen
---
package-lock.json | 205 ++++++++++++++++++++++-
package.json | 1 +
src/ipc/shared/language_model_helpers.ts | 33 ++++
src/ipc/utils/get_model_client.ts | 16 ++
src/lib/schemas.ts | 1 +
5 files changed, 252 insertions(+), 4 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index c6fa805..bd437e4 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -6,9 +6,10 @@
"packages": {
"": {
"name": "dyad",
- "version": "0.20.0-beta.1",
+ "version": "0.20.0-beta.1",
"license": "MIT",
"dependencies": {
+ "@ai-sdk/amazon-bedrock": "^3.0.15",
"@ai-sdk/anthropic": "^2.0.4",
"@ai-sdk/azure": "^2.0.17",
"@ai-sdk/google": "^2.0.6",
@@ -129,10 +130,47 @@
"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": {
- "version": "2.0.9",
- "resolved": "https://registry.npmjs.org/@ai-sdk/anthropic/-/anthropic-2.0.9.tgz",
- "integrity": "sha512-1kQgL2A3PeqfEcHHmqy4NxRc8rbgLS71bHBuvDFfDz3VAAyndkilPMCLNDSP2mJVGAej2EMWJ1sShRAxzn70jA==",
+ "version": "2.0.11",
+ "resolved": "https://registry.npmjs.org/@ai-sdk/anthropic/-/anthropic-2.0.11.tgz",
+ "integrity": "sha512-NCHWE/BnHm9CBw2M17kPwe4bKEUBtntzY26uvoZmWZfCvu2muYBR03pN2pdYmRRZlhpKk1kAOwPOzs9OW8ZC9Q=="
"license": "Apache-2.0",
"dependencies": {
"@ai-sdk/provider": "2.0.0",
@@ -373,6 +411,82 @@
"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": {
"version": "7.27.1",
"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"
}
},
+ "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": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz",
@@ -7875,6 +8066,12 @@
"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": {
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.11.0.tgz",
diff --git a/package.json b/package.json
index 998ce18..2391be9 100644
--- a/package.json
+++ b/package.json
@@ -85,6 +85,7 @@
"vitest": "^3.1.1"
},
"dependencies": {
+ "@ai-sdk/amazon-bedrock": "^3.0.15",
"@ai-sdk/anthropic": "^2.0.4",
"@ai-sdk/azure": "^2.0.17",
"@ai-sdk/google": "^2.0.6",
diff --git a/src/ipc/shared/language_model_helpers.ts b/src/ipc/shared/language_model_helpers.ts
index 625ebf0..9714fda 100644
--- a/src/ipc/shared/language_model_helpers.ts
+++ b/src/ipc/shared/language_model_helpers.ts
@@ -253,6 +253,32 @@ export const MODEL_OPTIONS: Record = {
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 = {
@@ -261,6 +287,7 @@ export const PROVIDER_TO_ENV_VAR: Record = {
google: "GEMINI_API_KEY",
openrouter: "OPENROUTER_API_KEY",
azure: "AZURE_API_KEY",
+ bedrock: "AWS_BEARER_TOKEN_BEDROCK",
};
export const CLOUD_PROVIDERS: Record<
@@ -317,6 +344,12 @@ export const CLOUD_PROVIDERS: Record<
gatewayPrefix: "",
secondary: true,
},
+ bedrock: {
+ displayName: "AWS Bedrock",
+ hasFreeTier: false,
+ websiteUrl: "https://console.aws.amazon.com/bedrock/",
+ gatewayPrefix: "bedrock/",
+ },
};
const LOCAL_PROVIDERS: Record<
diff --git a/src/ipc/utils/get_model_client.ts b/src/ipc/utils/get_model_client.ts
index 5e8c5e7..f3c7355 100644
--- a/src/ipc/utils/get_model_client.ts
+++ b/src/ipc/utils/get_model_client.ts
@@ -5,6 +5,7 @@ import { createVertex as createGoogleVertex } from "@ai-sdk/google-vertex";
import { azure } from "@ai-sdk/azure";
import { createOpenRouter } from "@openrouter/ai-sdk-provider";
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
+import { createAmazonBedrock } from "@ai-sdk/amazon-bedrock";
import type {
LargeLanguageModel,
UserSettings,
@@ -342,6 +343,21 @@ function getRegularModelClient(
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: {
// Handle custom providers
if (providerConfig.type === "custom") {
diff --git a/src/lib/schemas.ts b/src/lib/schemas.ts
index 9dca45c..09fbeef 100644
--- a/src/lib/schemas.ts
+++ b/src/lib/schemas.ts
@@ -36,6 +36,7 @@ const providers = [
"ollama",
"lmstudio",
"azure",
+ "bedrock",
] as const;
export const cloudProviders = providers.filter(