From 5ae20dfe93f7d7935cf11c76996e5a097236b8b8 Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Thu, 23 Jul 2026 15:43:44 -0500 Subject: [PATCH 1/2] fix(provider): preserve Alibaba DeepSeek effort --- packages/opencode/src/provider/provider.ts | 20 ++++--- packages/opencode/src/provider/transform.ts | 4 +- .../opencode/test/provider/transform.test.ts | 12 ++++ packages/opencode/test/session/llm.test.ts | 60 +++++++++++++++++++ 4 files changed, 88 insertions(+), 8 deletions(-) diff --git a/packages/opencode/src/provider/provider.ts b/packages/opencode/src/provider/provider.ts index a0ab5eb347..0bfc81cb39 100644 --- a/packages/opencode/src/provider/provider.ts +++ b/packages/opencode/src/provider/provider.ts @@ -1686,7 +1686,13 @@ const layer = Layer.effect( delete options.fetch } - if (model.api.npm.includes("@ai-sdk/openai-compatible") && options["includeUsage"] !== false) { + // Alibaba's SDK does not expose DeepSeek V4's native reasoning_effort field. + const npm = + model.api.npm === "@ai-sdk/alibaba" && ["deepseek-v4-pro", "deepseek-v4-flash"].includes(model.api.id) + ? "@ai-sdk/openai-compatible" + : model.api.npm + + if (npm.includes("@ai-sdk/openai-compatible") && options["includeUsage"] !== false) { options["includeUsage"] = true } @@ -1722,7 +1728,7 @@ const layer = Layer.effect( const key = Hash.fast( JSON.stringify({ providerID: model.providerID, - npm: model.api.npm, + npm, options, }), ) @@ -1762,7 +1768,7 @@ const layer = Layer.effect( return wrapSSE(res, chunkTimeout, chunkAbortCtl) } - const bundledLoader = BUNDLED_PROVIDERS[model.api.npm] + const bundledLoader = BUNDLED_PROVIDERS[npm] if (bundledLoader) { const factory = await bundledLoader() const loaded = factory({ @@ -1774,11 +1780,11 @@ const layer = Layer.effect( } const installedPath = await (async () => { - if (model.api.npm.startsWith("file://")) { - return model.api.npm + if (npm.startsWith("file://")) { + return npm } - const item = await Npm.add(model.api.npm) - if (!item.entrypoint) throw new Error(`Package ${model.api.npm} has no import entrypoint`) + const item = await Npm.add(npm) + if (!item.entrypoint) throw new Error(`Package ${npm} has no import entrypoint`) return item.entrypoint })() diff --git a/packages/opencode/src/provider/transform.ts b/packages/opencode/src/provider/transform.ts index 81759160bf..7820615e74 100644 --- a/packages/opencode/src/provider/transform.ts +++ b/packages/opencode/src/provider/transform.ts @@ -1744,9 +1744,11 @@ function reasoningEffort(model: Provider.Model, effort: string) { case "@ai-sdk/cohere": case "@ai-sdk/perplexity": case "@ai-sdk/vercel": - case "@ai-sdk/alibaba": case "gitlab-ai-provider": return + case "@ai-sdk/alibaba": + if (["deepseek-v4-pro", "deepseek-v4-flash"].includes(model.api.id)) return { reasoningEffort: effort } + return } } diff --git a/packages/opencode/test/provider/transform.test.ts b/packages/opencode/test/provider/transform.test.ts index ef2b275035..b8273346d3 100644 --- a/packages/opencode/test/provider/transform.test.ts +++ b/packages/opencode/test/provider/transform.test.ts @@ -3289,6 +3289,18 @@ describe("ProviderTransform.reasoningVariants", () => { ).toEqual({ max: { effort: "max" } }) }) + test.each(["deepseek-v4-pro", "deepseek-v4-flash"])("preserves Alibaba %s reasoning effort", (id) => { + expect( + ProviderTransform.reasoningVariants( + model([{ type: "effort", values: ["high", "max"] }]), + target("@ai-sdk/alibaba", id), + ), + ).toEqual({ + high: { reasoningEffort: "high" }, + max: { reasoningEffort: "max" }, + }) + }) + test("maps Kimi effort metadata to adaptive thinking", () => { expect( ProviderTransform.reasoningVariants( diff --git a/packages/opencode/test/session/llm.test.ts b/packages/opencode/test/session/llm.test.ts index 3bfc722e2b..5de27ffe8c 100644 --- a/packages/opencode/test/session/llm.test.ts +++ b/packages/opencode/test/session/llm.test.ts @@ -832,6 +832,66 @@ describe("session.llm.stream", () => { }, ) + it.instance( + "preserves DeepSeek V4 effort and caching with the Alibaba SDK", + () => + Effect.gen(function* () { + const request = waitRequest( + "/chat/completions", + new Response(createChatStream("Hello"), { + status: 200, + headers: { "Content-Type": "text/event-stream" }, + }), + ) + const source = yield* Provider.use.getModel(ProviderV2.ID.make("alibaba"), ModelV2.ID.make("qwen-plus")) + const resolved = { + ...source, + id: ModelV2.ID.make("deepseek-v4-pro"), + api: { ...source.api, id: "deepseek-v4-pro", npm: "@ai-sdk/alibaba" }, + variants: { high: { reasoningEffort: "high" } }, + } + const sessionID = SessionID.make("session-test-alibaba-deepseek-effort") + const agent = { + name: "test", + mode: "primary", + options: {}, + permission: [{ permission: "*", pattern: "*", action: "allow" }], + } satisfies Agent.Info + const user = { + id: MessageID.make("msg_user-alibaba-deepseek-effort"), + sessionID, + role: "user", + time: { created: Date.now() }, + agent: agent.name, + model: { providerID: resolved.providerID, modelID: resolved.id, variant: "high" }, + } satisfies SessionV1.User + + yield* drain({ + user, + sessionID, + model: resolved, + agent, + system: ["You are a helpful assistant."], + messages: [{ role: "user", content: "Hello" }], + tools: {}, + }) + + const capture = yield* Effect.promise(() => request) + expect(capture.body.reasoning_effort).toBe("high") + expect(JSON.stringify(capture.body.messages)).toContain('"cache_control":{"type":"ephemeral"}') + }), + { + config: () => ({ + enabled_providers: ["alibaba"], + provider: { + alibaba: { + options: { apiKey: "test-key", baseURL: `${state.server!.url.origin}/v1` }, + }, + }, + }), + }, + ) + const cerebrasFixture = { providerID: "cerebras", modelID: "gpt-oss-120b" } it.instance( "replays Cerebras assistant reasoning using the provider-supported field", From 88797739b92c155917b893fafeb03e6b30991588 Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Thu, 23 Jul 2026 15:51:26 -0500 Subject: [PATCH 2/2] Revert "fix(provider): preserve Alibaba DeepSeek effort" This reverts commit 5ae20dfe93f7d7935cf11c76996e5a097236b8b8. --- packages/opencode/src/provider/provider.ts | 20 +++---- packages/opencode/src/provider/transform.ts | 4 +- .../opencode/test/provider/transform.test.ts | 12 ---- packages/opencode/test/session/llm.test.ts | 60 ------------------- 4 files changed, 8 insertions(+), 88 deletions(-) diff --git a/packages/opencode/src/provider/provider.ts b/packages/opencode/src/provider/provider.ts index 0bfc81cb39..a0ab5eb347 100644 --- a/packages/opencode/src/provider/provider.ts +++ b/packages/opencode/src/provider/provider.ts @@ -1686,13 +1686,7 @@ const layer = Layer.effect( delete options.fetch } - // Alibaba's SDK does not expose DeepSeek V4's native reasoning_effort field. - const npm = - model.api.npm === "@ai-sdk/alibaba" && ["deepseek-v4-pro", "deepseek-v4-flash"].includes(model.api.id) - ? "@ai-sdk/openai-compatible" - : model.api.npm - - if (npm.includes("@ai-sdk/openai-compatible") && options["includeUsage"] !== false) { + if (model.api.npm.includes("@ai-sdk/openai-compatible") && options["includeUsage"] !== false) { options["includeUsage"] = true } @@ -1728,7 +1722,7 @@ const layer = Layer.effect( const key = Hash.fast( JSON.stringify({ providerID: model.providerID, - npm, + npm: model.api.npm, options, }), ) @@ -1768,7 +1762,7 @@ const layer = Layer.effect( return wrapSSE(res, chunkTimeout, chunkAbortCtl) } - const bundledLoader = BUNDLED_PROVIDERS[npm] + const bundledLoader = BUNDLED_PROVIDERS[model.api.npm] if (bundledLoader) { const factory = await bundledLoader() const loaded = factory({ @@ -1780,11 +1774,11 @@ const layer = Layer.effect( } const installedPath = await (async () => { - if (npm.startsWith("file://")) { - return npm + if (model.api.npm.startsWith("file://")) { + return model.api.npm } - const item = await Npm.add(npm) - if (!item.entrypoint) throw new Error(`Package ${npm} has no import entrypoint`) + const item = await Npm.add(model.api.npm) + if (!item.entrypoint) throw new Error(`Package ${model.api.npm} has no import entrypoint`) return item.entrypoint })() diff --git a/packages/opencode/src/provider/transform.ts b/packages/opencode/src/provider/transform.ts index 7820615e74..81759160bf 100644 --- a/packages/opencode/src/provider/transform.ts +++ b/packages/opencode/src/provider/transform.ts @@ -1744,10 +1744,8 @@ function reasoningEffort(model: Provider.Model, effort: string) { case "@ai-sdk/cohere": case "@ai-sdk/perplexity": case "@ai-sdk/vercel": - case "gitlab-ai-provider": - return case "@ai-sdk/alibaba": - if (["deepseek-v4-pro", "deepseek-v4-flash"].includes(model.api.id)) return { reasoningEffort: effort } + case "gitlab-ai-provider": return } } diff --git a/packages/opencode/test/provider/transform.test.ts b/packages/opencode/test/provider/transform.test.ts index b8273346d3..ef2b275035 100644 --- a/packages/opencode/test/provider/transform.test.ts +++ b/packages/opencode/test/provider/transform.test.ts @@ -3289,18 +3289,6 @@ describe("ProviderTransform.reasoningVariants", () => { ).toEqual({ max: { effort: "max" } }) }) - test.each(["deepseek-v4-pro", "deepseek-v4-flash"])("preserves Alibaba %s reasoning effort", (id) => { - expect( - ProviderTransform.reasoningVariants( - model([{ type: "effort", values: ["high", "max"] }]), - target("@ai-sdk/alibaba", id), - ), - ).toEqual({ - high: { reasoningEffort: "high" }, - max: { reasoningEffort: "max" }, - }) - }) - test("maps Kimi effort metadata to adaptive thinking", () => { expect( ProviderTransform.reasoningVariants( diff --git a/packages/opencode/test/session/llm.test.ts b/packages/opencode/test/session/llm.test.ts index 5de27ffe8c..3bfc722e2b 100644 --- a/packages/opencode/test/session/llm.test.ts +++ b/packages/opencode/test/session/llm.test.ts @@ -832,66 +832,6 @@ describe("session.llm.stream", () => { }, ) - it.instance( - "preserves DeepSeek V4 effort and caching with the Alibaba SDK", - () => - Effect.gen(function* () { - const request = waitRequest( - "/chat/completions", - new Response(createChatStream("Hello"), { - status: 200, - headers: { "Content-Type": "text/event-stream" }, - }), - ) - const source = yield* Provider.use.getModel(ProviderV2.ID.make("alibaba"), ModelV2.ID.make("qwen-plus")) - const resolved = { - ...source, - id: ModelV2.ID.make("deepseek-v4-pro"), - api: { ...source.api, id: "deepseek-v4-pro", npm: "@ai-sdk/alibaba" }, - variants: { high: { reasoningEffort: "high" } }, - } - const sessionID = SessionID.make("session-test-alibaba-deepseek-effort") - const agent = { - name: "test", - mode: "primary", - options: {}, - permission: [{ permission: "*", pattern: "*", action: "allow" }], - } satisfies Agent.Info - const user = { - id: MessageID.make("msg_user-alibaba-deepseek-effort"), - sessionID, - role: "user", - time: { created: Date.now() }, - agent: agent.name, - model: { providerID: resolved.providerID, modelID: resolved.id, variant: "high" }, - } satisfies SessionV1.User - - yield* drain({ - user, - sessionID, - model: resolved, - agent, - system: ["You are a helpful assistant."], - messages: [{ role: "user", content: "Hello" }], - tools: {}, - }) - - const capture = yield* Effect.promise(() => request) - expect(capture.body.reasoning_effort).toBe("high") - expect(JSON.stringify(capture.body.messages)).toContain('"cache_control":{"type":"ephemeral"}') - }), - { - config: () => ({ - enabled_providers: ["alibaba"], - provider: { - alibaba: { - options: { apiKey: "test-key", baseURL: `${state.server!.url.origin}/v1` }, - }, - }, - }), - }, - ) - const cerebrasFixture = { providerID: "cerebras", modelID: "gpt-oss-120b" } it.instance( "replays Cerebras assistant reasoning using the provider-supported field",