Browse Source

fix(opencode): honor Bedrock Mantle config (#31001)

Aiden Cline 3 months ago
parent
commit
ca9bf7abf9

+ 13 - 2
packages/opencode/src/provider/provider.ts

@@ -295,6 +295,7 @@ function custom(dep: CustomDep): Record<string, CustomLoader> {
       const profile = configProfile ?? envProfile
 
       const awsAccessKeyId = env["AWS_ACCESS_KEY_ID"]
+      const configApiKey = providerConfig?.options?.apiKey
 
       // TODO: Using process.env directly because Env.set only updates a process.env shallow copy,
       // until the scope of the Env API is clarified (test only or runtime?)
@@ -314,7 +315,14 @@ function custom(dep: CustomDep): Record<string, CustomLoader> {
         process.env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI || process.env.AWS_CONTAINER_CREDENTIALS_FULL_URI,
       )
 
-      if (!profile && !awsAccessKeyId && !awsBearerToken && !awsWebIdentityTokenFile && !containerCreds)
+      if (
+        !profile &&
+        !awsAccessKeyId &&
+        !awsBearerToken &&
+        !configApiKey &&
+        !awsWebIdentityTokenFile &&
+        !containerCreds
+      )
         return { autoload: false }
 
       const { fromNodeProviderChain } = yield* Effect.promise(() => import("@aws-sdk/credential-providers"))
@@ -325,7 +333,7 @@ function custom(dep: CustomDep): Record<string, CustomLoader> {
 
       // Only use credential chain if no bearer token exists
       // Bearer token takes precedence over credential chain (profiles, access keys, IAM roles, web identity tokens)
-      if (!awsBearerToken) {
+      if (!awsBearerToken && !configApiKey) {
         // Build credential provider options (only pass profile if specified)
         const credentialProviderOptions = profile ? { profile } : {}
 
@@ -341,6 +349,9 @@ function custom(dep: CustomDep): Record<string, CustomLoader> {
       return {
         autoload: true,
         options: providerOptions,
+        vars(options: Record<string, any>) {
+          return { AWS_REGION: options.region ?? defaultRegion }
+        },
         async getModel(sdk: any, modelID: string, options?: Record<string, any>, model?: Model) {
           if (model?.api.npm === "@ai-sdk/amazon-bedrock/mantle") return selectBedrockMantleLanguageModel(sdk, modelID)
 

+ 14 - 8
packages/opencode/test/provider/amazon-bedrock.test.ts

@@ -43,11 +43,6 @@ const mantleModelConfig = {
   },
 }
 
-const mantleOpenAIModelConfig = {
-  ...mantleModelConfig,
-  provider: { npm: "@ai-sdk/amazon-bedrock/mantle", api: "https://bedrock-mantle.us-east-2.api.aws/openai/v1" },
-}
-
 const withAuthJson = (contents: string) =>
   Effect.acquireRelease(
     Effect.promise(async () => {
@@ -113,7 +108,10 @@ it.instance(
   "Bedrock Mantle: GPT-5.5 uses Responses API and OpenAI base path",
   () =>
     Effect.gen(function* () {
-      yield* set("AWS_BEARER_TOKEN_BEDROCK", "test-bearer-token")
+      yield* set("AWS_REGION", "")
+      yield* set("AWS_PROFILE", "")
+      yield* set("AWS_ACCESS_KEY_ID", "")
+      yield* set("AWS_BEARER_TOKEN_BEDROCK", "")
       const model = yield* Provider.use.getModel(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("openai.gpt-5.5"))
       const language = yield* Provider.use.getLanguage(model)
       expect((language as { provider: string }).provider).toBe("bedrock-mantle.responses")
@@ -129,8 +127,16 @@ it.instance(
     config: {
       provider: {
         "amazon-bedrock": {
-          options: { region: "us-east-2" },
-          models: { "openai.gpt-5.5": mantleOpenAIModelConfig },
+          options: { region: "us-east-2", apiKey: "test-bearer-token" },
+          models: {
+            "openai.gpt-5.5": {
+              ...mantleModelConfig,
+              provider: {
+                npm: "@ai-sdk/amazon-bedrock/mantle",
+                api: "https://bedrock-mantle.${AWS_REGION}.api.aws/openai/v1",
+              },
+            },
+          },
         },
       },
     },