From 013bdcc8ce9732a26b9688a2d481be585076bcdd Mon Sep 17 00:00:00 2001 From: ikeda-tomoya-swx Date: Tue, 6 Jan 2026 11:23:15 +0900 Subject: [PATCH 1/2] fix(provider): support cross-region inference profile prefixes in model lookup for Amazon Bedrock --- packages/opencode/src/provider/provider.ts | 30 +++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/packages/opencode/src/provider/provider.ts b/packages/opencode/src/provider/provider.ts index cd0a80c2c48..c8d79b91b71 100644 --- a/packages/opencode/src/provider/provider.ts +++ b/packages/opencode/src/provider/provider.ts @@ -977,12 +977,36 @@ export namespace Provider { throw new ModelNotFoundError({ providerID, modelID, suggestions }) } - const info = provider.models[modelID] + // For amazon-bedrock, strip cross-region inference profile prefixes before lookup + let lookupModelID = modelID + if (providerID === "amazon-bedrock") { + const crossRegionPrefixes = ["us.", "eu.", "apac.", "global.", "jp.", "au."] + for (const prefix of crossRegionPrefixes) { + if (modelID.startsWith(prefix)) { + lookupModelID = modelID.slice(prefix.length) + break + } + } + } + + const info = provider.models[lookupModelID] if (!info) { const availableModels = Object.keys(provider.models) - const matches = fuzzysort.go(modelID, availableModels, { limit: 3, threshold: -10000 }) + const matches = fuzzysort.go(lookupModelID, availableModels, { limit: 3, threshold: -10000 }) const suggestions = matches.map((m) => m.target) - throw new ModelNotFoundError({ providerID, modelID, suggestions }) + throw new ModelNotFoundError({ providerID, modelID: lookupModelID, suggestions }) + } + + // If a cross-region prefix was used, return model info with the original prefixed modelID + if (lookupModelID !== modelID) { + return { + ...info, + id: modelID, + api: { + ...info.api, + id: modelID, + }, + } } return info } From b28dd2cefe55eb12a9da8a90afb2a5f6248fe235 Mon Sep 17 00:00:00 2001 From: ikeda-tomoya-swx Date: Tue, 6 Jan 2026 11:44:40 +0900 Subject: [PATCH 2/2] =?UTF-8?q?fix(provider):=20=E6=9D=B1=E4=BA=AC?= =?UTF-8?q?=E3=83=AA=E3=83=BC=E3=82=B8=E3=83=A7=E3=83=B3(ap-northeast-1)?= =?UTF-8?q?=E3=81=ABjp.=E3=83=97=E3=83=AC=E3=83=95=E3=82=A3=E3=83=83?= =?UTF-8?q?=E3=82=AF=E3=82=B9=E3=82=92=E8=87=AA=E5=8B=95=E4=BB=98=E4=B8=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/opencode/src/provider/provider.ts | 41 ++++++++-------------- 1 file changed, 14 insertions(+), 27 deletions(-) diff --git a/packages/opencode/src/provider/provider.ts b/packages/opencode/src/provider/provider.ts index c8d79b91b71..9f14b5464c9 100644 --- a/packages/opencode/src/provider/provider.ts +++ b/packages/opencode/src/provider/provider.ts @@ -266,13 +266,24 @@ export namespace Provider { } case "ap": { const isAustraliaRegion = ["ap-southeast-2", "ap-southeast-4"].includes(region) + const isTokyoRegion = region === "ap-northeast-1" if ( isAustraliaRegion && ["anthropic.claude-sonnet-4-5", "anthropic.claude-haiku"].some((m) => modelID.includes(m)) ) { regionPrefix = "au" modelID = `${regionPrefix}.${modelID}` + } else if (isTokyoRegion) { + // Tokyo region uses jp. prefix for cross-region inference + const modelRequiresPrefix = ["claude", "nova-lite", "nova-micro", "nova-pro"].some((m) => + modelID.includes(m), + ) + if (modelRequiresPrefix) { + regionPrefix = "jp" + modelID = `${regionPrefix}.${modelID}` + } } else { + // Other APAC regions use apac. prefix const modelRequiresPrefix = ["claude", "nova-lite", "nova-micro", "nova-pro"].some((m) => modelID.includes(m), ) @@ -977,36 +988,12 @@ export namespace Provider { throw new ModelNotFoundError({ providerID, modelID, suggestions }) } - // For amazon-bedrock, strip cross-region inference profile prefixes before lookup - let lookupModelID = modelID - if (providerID === "amazon-bedrock") { - const crossRegionPrefixes = ["us.", "eu.", "apac.", "global.", "jp.", "au."] - for (const prefix of crossRegionPrefixes) { - if (modelID.startsWith(prefix)) { - lookupModelID = modelID.slice(prefix.length) - break - } - } - } - - const info = provider.models[lookupModelID] + const info = provider.models[modelID] if (!info) { const availableModels = Object.keys(provider.models) - const matches = fuzzysort.go(lookupModelID, availableModels, { limit: 3, threshold: -10000 }) + const matches = fuzzysort.go(modelID, availableModels, { limit: 3, threshold: -10000 }) const suggestions = matches.map((m) => m.target) - throw new ModelNotFoundError({ providerID, modelID: lookupModelID, suggestions }) - } - - // If a cross-region prefix was used, return model info with the original prefixed modelID - if (lookupModelID !== modelID) { - return { - ...info, - id: modelID, - api: { - ...info.api, - id: modelID, - }, - } + throw new ModelNotFoundError({ providerID, modelID, suggestions }) } return info }