Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions packages/core/src/plugin/provider/azure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,17 @@ import { Effect } from "effect"
import { define } from "../internal"
import { ProviderV2 } from "../../provider"

function selectLanguage(sdk: any, modelID: string, useChat: boolean) {
function selectLanguage(
sdk: any,
model: { id: string; name: string; family?: string; api: { id: string } },
useChat: boolean,
) {
const modelID = model.api.id
if (
sdk.deepseek &&
[modelID, model.id, model.name, model.family].some((value) => value?.toLowerCase().includes("deepseek"))
)
return sdk.deepseek(modelID)
if (useChat && sdk.chat) return sdk.chat(modelID)
if (sdk.responses) return sdk.responses(modelID)
if (sdk.messages) return sdk.messages(modelID)
Expand Down Expand Up @@ -49,7 +59,7 @@ export const AzurePlugin = define({
yield* ctx.aisdk.language(
Effect.fn(function* (evt) {
if (evt.model.providerID !== ProviderV2.ID.azure) return
evt.language = selectLanguage(evt.sdk, evt.model.api.id, Boolean(evt.options.useCompletionUrls))
evt.language = selectLanguage(evt.sdk, evt.model, Boolean(evt.options.useCompletionUrls))
}),
)
}),
Expand All @@ -75,7 +85,7 @@ export const AzureCognitiveServicesPlugin = define({
yield* ctx.aisdk.language(
Effect.fn(function* (evt) {
if (evt.model.providerID !== ProviderV2.ID.make("azure-cognitive-services")) return
evt.language = selectLanguage(evt.sdk, evt.model.api.id, Boolean(evt.options.useCompletionUrls))
evt.language = selectLanguage(evt.sdk, evt.model, Boolean(evt.options.useCompletionUrls))
}),
)
}),
Expand Down
18 changes: 18 additions & 0 deletions packages/core/test/plugin/provider-azure.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ function fakeSelectorSdk(calls: string[]) {
return { modelId: id, provider: method, specificationVersion: "v3" } as unknown as LanguageModelV3
}
return {
deepseek: make("deepseek"),
responses: make("responses"),
messages: make("messages"),
chat: make("chat"),
Expand Down Expand Up @@ -197,6 +198,23 @@ describe("AzurePlugin", () => {
}),
)

it.effect("selects DeepSeek for named deployments", () =>
Effect.gen(function* () {
const aisdk = yield* AISDK.Service
const calls: string[] = []
yield* addPlugin()
yield* aisdk.runLanguage({
model: ModelV2.Info.make({
...ModelV2.Info.empty(ProviderV2.ID.azure, ModelV2.ID.make("deepseek-v4-pro")),
api: { id: ModelV2.ID.make("production-deployment"), type: "aisdk", package: "test-provider" },
}),
sdk: fakeSelectorSdk(calls),
options: { useCompletionUrls: true },
})
expect(calls).toEqual(["deepseek:production-deployment"])
}),
)

it.effect("selects chat from per-call useCompletionUrls", () =>
Effect.gen(function* () {
const plugin = yield* PluginV2.Service
Expand Down
15 changes: 10 additions & 5 deletions packages/opencode/src/provider/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,12 @@ type CustomDep = {
get: (key: string) => Effect.Effect<string | undefined>
}

function selectAzureLanguageModel(sdk: any, modelID: string, useChat: boolean) {
function selectAzureLanguageModel(sdk: any, modelID: string, useChat: boolean, model?: Model) {
if (
sdk.deepseek &&
[modelID, model?.id, model?.name, model?.family].some((value) => value?.toLowerCase().includes("deepseek"))
)
return sdk.deepseek(modelID)
if (useChat && sdk.chat) return sdk.chat(modelID)
if (sdk.responses) return sdk.responses(modelID)
if (sdk.messages) return sdk.messages(modelID)
Expand Down Expand Up @@ -261,8 +266,8 @@ function custom(dep: CustomDep): Record<string, CustomLoader> {

return {
autoload: false,
async getModel(sdk: any, modelID: string, options?: Record<string, any>) {
return selectAzureLanguageModel(sdk, modelID, Boolean(options?.["useCompletionUrls"]))
async getModel(sdk: any, modelID: string, options?: Record<string, any>, model?: Model) {
return selectAzureLanguageModel(sdk, modelID, Boolean(options?.["useCompletionUrls"]), model)
},
options: {
resourceName: resource,
Expand All @@ -281,8 +286,8 @@ function custom(dep: CustomDep): Record<string, CustomLoader> {
const resourceName = yield* dep.get("AZURE_COGNITIVE_SERVICES_RESOURCE_NAME")
return {
autoload: false,
async getModel(sdk: any, modelID: string, options?: Record<string, any>) {
return selectAzureLanguageModel(sdk, modelID, Boolean(options?.["useCompletionUrls"]))
async getModel(sdk: any, modelID: string, options?: Record<string, any>, model?: Model) {
return selectAzureLanguageModel(sdk, modelID, Boolean(options?.["useCompletionUrls"]), model)
},
options: {
baseURL: resourceName
Expand Down
29 changes: 29 additions & 0 deletions packages/opencode/test/provider/provider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -809,6 +809,35 @@ it.instance("getSmallModel skips inferred models for Azure Cognitive Services",
}),
)

it.instance(
"Azure uses the DeepSeek adapter for DeepSeek models",
Effect.gen(function* () {
yield* set("AZURE_API_KEY", "test-key")
const provider = yield* Provider.Service
const deepseek = yield* provider.getModel(ProviderV2.ID.azure, ModelV2.ID.make("deepseek-v4-pro"))
const chat = yield* provider.getModel(ProviderV2.ID.azure, ModelV2.ID.make("gpt-4o"))
const deepseekLanguage = yield* provider.getLanguage(deepseek)
const chatLanguage = yield* provider.getLanguage(chat)
expect((deepseekLanguage as { provider: string }).provider).toBe("azure.deepseek")
expect((deepseekLanguage as { modelId: string }).modelId).toBe("production-deployment")
expect((chatLanguage as { provider: string }).provider).toBe("azure.chat")
}),
{
config: {
provider: {
azure: {
npm: "@ai-sdk/azure",
options: { apiKey: "test-key", baseURL: "https://test.openai.azure.com/openai" },
models: {
"deepseek-v4-pro": { id: "production-deployment", options: { useCompletionUrls: true } },
"gpt-4o": { options: { useCompletionUrls: true } },
},
},
},
},
},
)

it.instance(
"getSmallModel respects config small_model override",
Effect.gen(function* () {
Expand Down
Loading