From 4bbae4818f8adf6fdb734f38758f15ff227c3974 Mon Sep 17 00:00:00 2001 From: Nizzy Date: Sat, 17 Jan 2026 07:54:42 +0700 Subject: [PATCH] fix(app): support anthropic models on azure cognitive services --- packages/opencode/src/provider/provider.ts | 22 +++++++++++++++++---- packages/opencode/src/provider/transform.ts | 18 ++++++++++++++++- packages/opencode/src/session/llm.ts | 11 +++++------ 3 files changed, 40 insertions(+), 11 deletions(-) diff --git a/packages/opencode/src/provider/provider.ts b/packages/opencode/src/provider/provider.ts index 9e2dd0ba0b5..e815e34b28f 100644 --- a/packages/opencode/src/provider/provider.ts +++ b/packages/opencode/src/provider/provider.ts @@ -1006,9 +1006,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 }) @@ -1074,10 +1085,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 023b00dd304..0b73ac07a1c 100644 --- a/packages/opencode/src/provider/transform.ts +++ b/packages/opencode/src/provider/transform.ts @@ -46,7 +46,8 @@ export namespace ProviderTransform { // 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") { @@ -304,6 +305,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 } }, + } + } + switch (model.api.npm) { case "@openrouter/ai-sdk-provider": if (!model.id.includes("gpt") && !model.id.includes("gemini-3") && !model.id.includes("grok-4")) return {} @@ -574,6 +584,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" as string]: options } + } + switch (model.api.npm) { case "@ai-sdk/github-copilot": case "@ai-sdk/openai": 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)