Compare commits

...
4 changed files with 43 additions and 8 deletions

No files matched your search

@@ -37,7 +37,11 @@ export const defaultChain = (options: DefaultChainOptions): Effect.Effect<Creden
Effect.tryPromise({
try: async () => {
const { fromNodeProviderChain } = await import("@aws-sdk/credential-providers")
const identity = await fromNodeProviderChain(options.profile === undefined ? {} : { profile: options.profile })()
const identity = await fromNodeProviderChain({
...(options.profile === undefined ? {} : { profile: options.profile }),
clientConfig: { region: options.region },
ignoreCache: true,
})()
return {
region: options.region,
accessKeyId: identity.accessKeyId,
@@ -1,4 +1,5 @@
import { Effect } from "effect"
import { Effect, Schedule } from "effect"
import { BedrockAuth } from "@opencode/ai/protocols/utils/bedrock-auth"
import { define } from "@opencode/plugin/effect/plugin"
import { Provider } from "../../provider.js"
@@ -19,6 +20,8 @@ const isBedrock = (item: { readonly package: string }) =>
export const AmazonBedrockPlugin = define({
id: "opencode.provider.amazon.bedrock",
effect: Effect.fn(function* (ctx) {
const providers = yield* Provider.Service
const discovered = { available: false }
yield* ctx.integration.transform((editor) => {
// models.dev advertises AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and
// AWS_REGION alongside the bearer token. Only the bearer token is a key;
@@ -36,7 +39,7 @@ export const AmazonBedrockPlugin = define({
const chain = typeof settings.profile === "string" || CHAIN_ENV.some((name) => process.env[name])
// SigV4 authenticates through the AWS default chain rather than a key
// credential, so ambient AWS configuration is what makes Bedrock usable.
if (chain && provider.activation === "auto") provider.activation = "enabled"
if ((chain || discovered.available) && provider.activation === "auto") provider.activation = "enabled"
// Same default the native package uses, made explicit here so catalog
// `${AWS_REGION}` URLs resolve without any region configured.
const region = process.env.AWS_REGION ?? process.env.AWS_DEFAULT_REGION ?? "us-east-1"
@@ -53,5 +56,23 @@ export const AmazonBedrockPlugin = define({
})
}
})
// Resolve the same AWS chain used by requests, including default profiles and
// EC2 roles with no AWS_* variables. Keep I/O out of the synchronous catalog fold.
const refresh = Effect.fn("AmazonBedrockPlugin.refresh")(function* () {
if (!(yield* providers.all()).some((provider) => isBedrock(provider) && provider.activation !== "disabled"))
return
const available = yield* BedrockAuth.defaultChain({
region: process.env.AWS_REGION ?? process.env.AWS_DEFAULT_REGION ?? "us-east-1",
}).pipe(
Effect.as(true),
Effect.timeout("5 seconds"),
Effect.orElseSucceed(() => false),
)
if (available === discovered.available) return
discovered.available = available
yield* ctx.provider.reload()
})
// Recheck so logging in after startup is picked up without restarting OpenCode.
yield* refresh().pipe(Effect.repeat(Schedule.spaced("1 minute")), Effect.forkScoped({ startImmediately: true }))
}),
})
@@ -31,7 +31,7 @@ function withEnv<A, E, R>(vars: Record<string, string | undefined>, fx: () => Ef
})
return previous
}),
fx,
() => fx().pipe(Effect.scoped),
(previous) =>
Effect.sync(() => {
Object.entries(previous).forEach(([key, value]) => {
@@ -50,6 +50,9 @@ const noAmbientAWS = {
AWS_CONTAINER_CREDENTIALS_FULL_URI: undefined,
AWS_REGION: undefined,
AWS_DEFAULT_REGION: undefined,
AWS_CONFIG_FILE: "/nonexistent/opencode-bedrock-test/config",
AWS_SHARED_CREDENTIALS_FILE: "/nonexistent/opencode-bedrock-test/credentials",
AWS_EC2_METADATA_DISABLED: "true",
}
const seedBedrock = Effect.fn(function* (settings?: Provider.Settings) {
@@ -121,7 +124,13 @@ describe("AmazonBedrockPlugin", () => {
),
)
for (const name of Object.keys(noAmbientAWS).filter((name) => !name.includes("REGION"))) {
for (const name of [
"AWS_PROFILE",
"AWS_ACCESS_KEY_ID",
"AWS_WEB_IDENTITY_TOKEN_FILE",
"AWS_CONTAINER_CREDENTIALS_RELATIVE_URI",
"AWS_CONTAINER_CREDENTIALS_FULL_URI",
]) {
it.effect(`enables the provider when ${name} is set`, () =>
withEnv({ ...noAmbientAWS, [name]: "value" }, () =>
Effect.gen(function* () {
+4 -3
View File
@@ -362,8 +362,9 @@ az login --tenant TENANT_ID
## Bedrock
Amazon Bedrock uses the AWS default credential chain. A named AWS profile is the simplest durable setup; OpenCode also
recognizes access-key environments, web identity, and container credentials.
Amazon Bedrock uses the AWS default credential chain and automatically discovers default profiles, `aws login`
sessions, credential helpers, and EC2 instance roles. No OpenCode login is required; discovery rechecks every minute.
To use a named SSO profile:
```bash
aws configure sso --profile work
@@ -371,7 +372,7 @@ aws sso login --profile work
```
Select the profile and region in provider settings. A configured `profile`, `AWS_PROFILE`, `AWS_ACCESS_KEY_ID`, web
identity token file, or container credential URI activates the provider; a region alone does not.
identity token file, or container credential URI still activates the provider immediately; a region alone does not.
```jsonc title="opencode.jsonc"
{