diff --git a/packages/opencode/src/provider/provider.ts b/packages/opencode/src/provider/provider.ts index bcb115edf41..83c34cfed1a 100644 --- a/packages/opencode/src/provider/provider.ts +++ b/packages/opencode/src/provider/provider.ts @@ -1024,9 +1024,20 @@ export namespace Provider { }) } + // Special case: Azure Cognitive Services with Anthropic models uses @ai-sdk/anthropic + const isAzureClaude = model.providerID === "azure-cognitive-services" && model.api.id.includes("claude") + if (isAzureClaude) { + const resourceName = Env.get("AZURE_COGNITIVE_SERVICES_RESOURCE_NAME") + if (resourceName) options["baseURL"] = `https://${resourceName}.services.ai.azure.com/anthropic/v1/` + } + // Special case: google-vertex-anthropic uses a subpath import const bundledKey = - model.providerID === "google-vertex-anthropic" ? "@ai-sdk/google-vertex/anthropic" : model.api.npm + model.providerID === "google-vertex-anthropic" + ? "@ai-sdk/google-vertex/anthropic" + : isAzureClaude + ? "@ai-sdk/anthropic" + : model.api.npm const bundledFn = BUNDLED_PROVIDERS[bundledKey] if (bundledFn) { log.info("using bundled provider", { providerID: model.providerID, pkg: bundledKey }) @@ -1092,10 +1103,13 @@ export namespace Provider { const provider = s.providers[model.providerID] const sdk = await getSDK(model) + // Skip custom model loader for Azure Cognitive Services with Claude models + // since they use @ai-sdk/anthropic which uses sdk.languageModel() + const isAzureClaude = model.providerID === "azure-cognitive-services" && model.api.id.includes("claude") + const loader = isAzureClaude ? undefined : s.modelLoaders[model.providerID] + try { - const language = s.modelLoaders[model.providerID] - ? await s.modelLoaders[model.providerID](sdk, model.api.id, provider.options) - : sdk.languageModel(model.api.id) + const language = loader ? await loader(sdk, model.api.id, provider.options) : sdk.languageModel(model.api.id) s.models.set(key, language) return language } catch (e) { diff --git a/packages/opencode/src/provider/transform.ts b/packages/opencode/src/provider/transform.ts index b803bd66ce1..285a9a6e613 100644 --- a/packages/opencode/src/provider/transform.ts +++ b/packages/opencode/src/provider/transform.ts @@ -45,7 +45,8 @@ export namespace ProviderTransform { ): ModelMessage[] { // Anthropic rejects messages with empty content - filter out empty string messages // and remove empty text/reasoning parts from array content - if (model.api.npm === "@ai-sdk/anthropic") { + const isAzureClaude = model.providerID === "azure-cognitive-services" && model.api.id.includes("claude") + if (model.api.npm === "@ai-sdk/anthropic" || isAzureClaude) { msgs = msgs .map((msg) => { if (typeof msg.content === "string") { @@ -325,6 +326,15 @@ export namespace ProviderTransform { const id = model.id.toLowerCase() if (id.includes("deepseek") || id.includes("minimax") || id.includes("glm") || id.includes("mistral")) return {} + // Azure Cognitive Services with Claude models uses Anthropic thinking config + const isAzureClaude = model.providerID === "azure-cognitive-services" && model.api.id.includes("claude") + if (isAzureClaude) { + return { + high: { thinking: { type: "enabled", budgetTokens: 16000 } }, + max: { thinking: { type: "enabled", budgetTokens: 31999 } }, + } + } + // see: https://docs.x.ai/docs/guides/reasoning#control-how-hard-the-model-thinks if (id.includes("grok") && id.includes("grok-3-mini")) { if (model.api.npm === "@openrouter/ai-sdk-provider") { @@ -610,6 +620,12 @@ export namespace ProviderTransform { } export function providerOptions(model: Provider.Model, options: { [x: string]: any }) { + // Azure Cognitive Services with Claude models uses Anthropic provider options + const isAzureClaude = model.providerID === "azure-cognitive-services" && model.api.id.includes("claude") + if (isAzureClaude) { + return { anthropic: options } + } + const key = sdkKey(model.api.npm) ?? model.providerID return { [key]: options } } diff --git a/packages/opencode/src/session/llm.ts b/packages/opencode/src/session/llm.ts index 1029b45ea0d..02e7e394f91 100644 --- a/packages/opencode/src/session/llm.ts +++ b/packages/opencode/src/session/llm.ts @@ -131,14 +131,13 @@ export namespace LLM { }, ) + // Azure Cognitive Services with Claude models uses Anthropic SDK + const isAzureClaude = input.model.providerID === "azure-cognitive-services" && input.model.api.id.includes("claude") + const npm = isAzureClaude ? "@ai-sdk/anthropic" : input.model.api.npm + const maxOutputTokens = isCodex ? undefined - : ProviderTransform.maxOutputTokens( - input.model.api.npm, - params.options, - input.model.limit.output, - OUTPUT_TOKEN_MAX, - ) + : ProviderTransform.maxOutputTokens(npm, params.options, input.model.limit.output, OUTPUT_TOKEN_MAX) const tools = await resolveTools(input)