summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAiden Cline <[email protected]>2026-04-27 10:17:38 -0500
committerGitHub <[email protected]>2026-04-27 10:17:38 -0500
commit738b3065dc2bf643daa40507061a928299f67d30 (patch)
tree709c814128535f5cfdab0694b9c75aed9e53e722
parent26cc537cb12e5211fe9d6eee3c9ef97b4b0f317d (diff)
downloadopencode-738b3065dc2bf643daa40507061a928299f67d30.tar.gz
opencode-738b3065dc2bf643daa40507061a928299f67d30.zip
tweak: make interleaved reasoning_content default to true for openai compat deepseek setups (#24630)
-rw-r--r--packages/opencode/src/provider/provider.ts23
-rw-r--r--packages/opencode/test/provider/provider.test.ts61
2 files changed, 76 insertions, 8 deletions
diff --git a/packages/opencode/src/provider/provider.ts b/packages/opencode/src/provider/provider.ts
index 9aa1b6304..04d53a685 100644
--- a/packages/opencode/src/provider/provider.ts
+++ b/packages/opencode/src/provider/provider.ts
@@ -1135,6 +1135,13 @@ const layer: Layer.Layer<
for (const [modelID, model] of Object.entries(provider.models ?? {})) {
const existingModel = parsed.models[model.id ?? modelID]
+ const apiID = model.id ?? existingModel?.api.id ?? modelID
+ const apiNpm =
+ model.provider?.npm ??
+ provider.npm ??
+ existingModel?.api.npm ??
+ modelsDev[providerID]?.npm ??
+ "@ai-sdk/openai-compatible"
const name = iife(() => {
if (model.name) return model.name
if (model.id && model.id !== modelID) return modelID
@@ -1143,13 +1150,8 @@ const layer: Layer.Layer<
const parsedModel: Model = {
id: ModelID.make(modelID),
api: {
- id: model.id ?? existingModel?.api.id ?? modelID,
- npm:
- model.provider?.npm ??
- provider.npm ??
- existingModel?.api.npm ??
- modelsDev[providerID]?.npm ??
- "@ai-sdk/openai-compatible",
+ id: apiID,
+ npm: apiNpm,
url: model.provider?.api ?? provider?.api ?? existingModel?.api.url ?? modelsDev[providerID]?.api ?? "",
},
status: model.status ?? existingModel?.status ?? "active",
@@ -1177,7 +1179,12 @@ const layer: Layer.Layer<
model.modalities?.output?.includes("video") ?? existingModel?.capabilities.output.video ?? false,
pdf: model.modalities?.output?.includes("pdf") ?? existingModel?.capabilities.output.pdf ?? false,
},
- interleaved: model.interleaved ?? existingModel?.capabilities.interleaved ?? false,
+ interleaved:
+ model.interleaved ??
+ existingModel?.capabilities.interleaved ??
+ (!existingModel && apiNpm === "@ai-sdk/openai-compatible" && apiID.includes("deepseek")
+ ? { field: "reasoning_content" }
+ : false),
},
cost: {
input: model?.cost?.input ?? existingModel?.cost?.input ?? 0,
diff --git a/packages/opencode/test/provider/provider.test.ts b/packages/opencode/test/provider/provider.test.ts
index da98496c3..1480b2314 100644
--- a/packages/opencode/test/provider/provider.test.ts
+++ b/packages/opencode/test/provider/provider.test.ts
@@ -312,6 +312,67 @@ test("custom provider with npm package", async () => {
})
})
+test("custom DeepSeek openai-compatible model defaults interleaved reasoning field", async () => {
+ await using tmp = await tmpdir({
+ init: async (dir) => {
+ await Bun.write(
+ path.join(dir, "opencode.json"),
+ JSON.stringify({
+ $schema: "https://opencode.ai/config.json",
+ provider: {
+ "custom-provider": {
+ name: "Custom Provider",
+ npm: "@ai-sdk/openai-compatible",
+ api: "https://api.custom.com/v1",
+ models: {
+ "deepseek-r1": {
+ name: "DeepSeek R1",
+ },
+ "deepseek-details": {
+ name: "DeepSeek Details",
+ interleaved: { field: "reasoning_details" },
+ },
+ "custom-model": {
+ name: "Custom Model",
+ },
+ },
+ options: {
+ apiKey: "custom-key",
+ },
+ },
+ "custom-anthropic-provider": {
+ name: "Custom Anthropic Provider",
+ npm: "@ai-sdk/anthropic",
+ api: "https://api.custom.com/v1",
+ models: {
+ "deepseek-r1": {
+ name: "DeepSeek R1",
+ },
+ },
+ options: {
+ apiKey: "custom-key",
+ },
+ },
+ },
+ }),
+ )
+ },
+ })
+ await Instance.provide({
+ directory: tmp.path,
+ fn: async () => {
+ const providers = await list()
+ const provider = providers[ProviderID.make("custom-provider")]
+ expect(provider.models["deepseek-r1"].capabilities.interleaved).toEqual({ field: "reasoning_content" })
+ expect(provider.models["deepseek-details"].capabilities.interleaved).toEqual({ field: "reasoning_details" })
+ expect(provider.models["custom-model"].capabilities.interleaved).toBe(false)
+ expect(
+ providers[ProviderID.make("custom-anthropic-provider")].models["deepseek-r1"].capabilities.interleaved,
+ ).toBe(false)
+ },
+ })
+})
+
test("env variable takes precedence, config merges options", async () => {
await using tmp = await tmpdir({
init: async (dir) => {