From ac1758c0e6b8e7368be133e87e8e27a5f60dec04 Mon Sep 17 00:00:00 2001 From: Emrick Date: Wed, 9 Sep 2026 00:20:22 +0800 Subject: [PATCH] fix: preserve Bedrock DeepSeek model ids (#34441) Co-authored-by: yeqisong --- .../src/plugin/provider/amazon-bedrock.ts | 4 +- .../plugin/provider-amazon-bedrock.test.ts | 7 +++ packages/opencode/src/provider/provider.ts | 6 ++- .../test/provider/amazon-bedrock.test.ts | 43 +++++++++++++++++++ 4 files changed, 58 insertions(+), 2 deletions(-) diff --git a/packages/core/src/plugin/provider/amazon-bedrock.ts b/packages/core/src/plugin/provider/amazon-bedrock.ts index 0995cf1c17..1fb625c936 100644 --- a/packages/core/src/plugin/provider/amazon-bedrock.ts +++ b/packages/core/src/plugin/provider/amazon-bedrock.ts @@ -13,13 +13,15 @@ type MantleSDK = { // specific model/region combinations. Keep the mapping narrow and avoid // double-prefixing model IDs that models.dev already marks as global/us/eu/etc. function resolveModelID(modelID: string, region: string | undefined) { + if (modelID.startsWith("arn:")) return modelID + const crossRegionPrefixes = ["global.", "us.", "eu.", "jp.", "apac.", "au."] if (crossRegionPrefixes.some((prefix) => modelID.startsWith(prefix))) return modelID const resolvedRegion = region ?? "us-east-1" const regionPrefix = resolvedRegion.split("-")[0] if (regionPrefix === "us") { - const requiresPrefix = ["nova-micro", "nova-lite", "nova-pro", "nova-premier", "nova-2", "claude", "deepseek"].some( + const requiresPrefix = ["nova-micro", "nova-lite", "nova-pro", "nova-premier", "nova-2", "claude", "deepseek.r1"].some( (item) => modelID.includes(item), ) if (requiresPrefix && !resolvedRegion.startsWith("us-gov")) return `${regionPrefix}.${modelID}` diff --git a/packages/core/test/plugin/provider-amazon-bedrock.test.ts b/packages/core/test/plugin/provider-amazon-bedrock.test.ts index 5d24879e49..9ddcd127dc 100644 --- a/packages/core/test/plugin/provider-amazon-bedrock.test.ts +++ b/packages/core/test/plugin/provider-amazon-bedrock.test.ts @@ -528,6 +528,13 @@ describe("AmazonBedrockPlugin", () => { { region: "us-east-1", modelID: "amazon.nova-2-lite-v1:0", expected: "us.amazon.nova-2-lite-v1:0" }, { region: "us-east-1", modelID: "anthropic.claude-sonnet-4-5", expected: "us.anthropic.claude-sonnet-4-5" }, { region: "us-east-1", modelID: "deepseek.r1-v1:0", expected: "us.deepseek.r1-v1:0" }, + { region: "us-east-1", modelID: "us.deepseek.r1-v1:0", expected: "us.deepseek.r1-v1:0" }, + { region: "us-east-1", modelID: "deepseek.v3.2", expected: "deepseek.v3.2" }, + { + region: "us-east-1", + modelID: "arn:aws:bedrock:us-east-1::foundation-model/deepseek.v3.2", + expected: "arn:aws:bedrock:us-east-1::foundation-model/deepseek.v3.2", + }, { region: "us-gov-west-1", modelID: "anthropic.claude-sonnet-4-5", expected: "anthropic.claude-sonnet-4-5" }, { region: "us-east-1", modelID: "cohere.command-r-plus-v1:0", expected: "cohere.command-r-plus-v1:0" }, { region: "eu-west-1", modelID: "anthropic.claude-sonnet-4-5", expected: "eu.anthropic.claude-sonnet-4-5" }, diff --git a/packages/opencode/src/provider/provider.ts b/packages/opencode/src/provider/provider.ts index 72d5a7a593..867ef2ca2f 100644 --- a/packages/opencode/src/provider/provider.ts +++ b/packages/opencode/src/provider/provider.ts @@ -376,6 +376,10 @@ function custom(dep: CustomDep): Record { // Skip region prefixing if model already has a cross-region inference profile prefix // Models from models.dev may already include prefixes like us., eu., global., etc. + if (modelID.startsWith("arn:")) { + return sdk.languageModel(modelID) + } + const crossRegionPrefixes = ["global.", "us.", "eu.", "jp.", "apac.", "au."] if (crossRegionPrefixes.some((prefix) => modelID.startsWith(prefix))) { return sdk.languageModel(modelID) @@ -398,7 +402,7 @@ function custom(dep: CustomDep): Record { "nova-premier", "nova-2", "claude", - "deepseek", + "deepseek.r1", ].some((m) => modelID.includes(m)) const isGovCloud = region.startsWith("us-gov") if (modelRequiresPrefix && !isGovCloud) { diff --git a/packages/opencode/test/provider/amazon-bedrock.test.ts b/packages/opencode/test/provider/amazon-bedrock.test.ts index 6e677631c4..e4654ddb3d 100644 --- a/packages/opencode/test/provider/amazon-bedrock.test.ts +++ b/packages/opencode/test/provider/amazon-bedrock.test.ts @@ -229,6 +229,49 @@ it.instance( { config: { provider: { "amazon-bedrock": { options: { region: "us-east-1" } } } } }, ) +it.instance( + "Bedrock: preserves explicit DeepSeek model identifiers", + () => + Effect.gen(function* () { + yield* set("AWS_BEARER_TOKEN_BEDROCK", "test-bearer-token") + const provider = yield* Provider.Service + const deepseek = yield* provider.getLanguage( + yield* provider.getModel(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("deepseek.v3.2")), + ) + const r1 = yield* provider.getLanguage( + yield* provider.getModel(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("deepseek.r1-v1:0")), + ) + const profile = yield* provider.getLanguage( + yield* provider.getModel(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("us.deepseek.r1-v1:0")), + ) + const arn = yield* provider.getLanguage( + yield* provider.getModel(ProviderV2.ID.amazonBedrock, ModelV2.ID.make("deepseek-v3-2-arn")), + ) + expect((deepseek as { modelId: string }).modelId).toBe("deepseek.v3.2") + expect((r1 as { modelId: string }).modelId).toBe("us.deepseek.r1-v1:0") + expect((profile as { modelId: string }).modelId).toBe("us.deepseek.r1-v1:0") + expect((arn as { modelId: string }).modelId).toBe("arn:aws:bedrock:us-east-1::foundation-model/deepseek.v3.2") + }), + { + config: { + provider: { + "amazon-bedrock": { + options: { region: "us-east-1" }, + models: { + "deepseek.v3.2": { name: "DeepSeek V3.2" }, + "deepseek.r1-v1:0": { name: "DeepSeek R1" }, + "us.deepseek.r1-v1:0": { name: "DeepSeek R1 US" }, + "deepseek-v3-2-arn": { + id: "arn:aws:bedrock:us-east-1::foundation-model/deepseek.v3.2", + name: "DeepSeek V3.2 ARN", + }, + }, + }, + }, + }, + }, +) + // Cross-region inference profile prefix handling. // Models from models.dev may come with prefixes already (e.g. us., eu., global.). // These should NOT be double-prefixed when passed to the SDK.