Skip to content

Commit a1ab489

Browse files
fix(provider): widen interleaved reasoning fields (#39556)
Co-authored-by: Aiden Cline <rekram1-node@users.noreply.github.com>
1 parent 8c38d26 commit a1ab489

6 files changed

Lines changed: 63 additions & 16 deletions

File tree

packages/core/src/models-dev.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ import { httpClient } from "./effect/app-node-platform"
1515
export const CatalogModelStatus = Schema.Literals(["alpha", "beta", "deprecated"])
1616
export type CatalogModelStatus = typeof CatalogModelStatus.Type
1717

18+
const InterleavedField = Schema.Union([
19+
Schema.Literals(["reasoning", "reasoning_content", "reasoning_text"]),
20+
Schema.String,
21+
])
22+
1823
const USER_AGENT = `opencode/${InstallationChannel}/${InstallationVersion}/${Flag.OPENCODE_CLIENT}`
1924

2025
const CostTier = Schema.Struct({
@@ -71,9 +76,10 @@ export const Model = Schema.Struct({
7176
reasoning_options: Schema.optional(Schema.Array(ReasoningOption)),
7277
interleaved: Schema.optional(
7378
Schema.Union([
74-
Schema.Literal(true),
79+
Schema.Boolean,
80+
InterleavedField,
7581
Schema.Struct({
76-
field: Schema.Literals(["reasoning", "reasoning_content", "reasoning_details"]),
82+
field: InterleavedField,
7783
}),
7884
]),
7985
),

packages/core/src/v1/config/provider.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ import { PositiveInt } from "../../schema"
55

66
export const ModelStatus = Schema.Literals(["alpha", "beta", "deprecated", "active"])
77

8+
const InterleavedField = Schema.Union([
9+
Schema.Literals(["reasoning", "reasoning_content", "reasoning_text"]),
10+
Schema.String,
11+
])
12+
813
export const Model = Schema.Struct({
914
id: Schema.optional(Schema.String),
1015
name: Schema.optional(Schema.String),
@@ -16,9 +21,10 @@ export const Model = Schema.Struct({
1621
tool_call: Schema.optional(Schema.Boolean),
1722
interleaved: Schema.optional(
1823
Schema.Union([
19-
Schema.Literal(true),
24+
Schema.Boolean,
25+
InterleavedField,
2026
Schema.Struct({
21-
field: Schema.Literals(["reasoning", "reasoning_content", "reasoning_details"]),
27+
field: InterleavedField,
2228
}),
2329
]),
2430
),

packages/opencode/src/provider/provider.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -976,10 +976,15 @@ const ProviderModalities = Schema.Struct({
976976
pdf: Schema.Boolean,
977977
})
978978

979+
const ProviderInterleavedField = Schema.Union([
980+
Schema.Literals(["reasoning", "reasoning_content", "reasoning_text"]),
981+
Schema.String,
982+
])
983+
979984
const ProviderInterleaved = Schema.Union([
980985
Schema.Boolean,
981986
Schema.Struct({
982-
field: Schema.Literals(["reasoning", "reasoning_content", "reasoning_details"]),
987+
field: ProviderInterleavedField,
983988
}),
984989
])
985990

@@ -1243,7 +1248,7 @@ function fromModelsDevModel(provider: ModelsDev.Provider, model: ModelsDev.Model
12431248
video: model.modalities?.output?.includes("video") ?? false,
12441249
pdf: model.modalities?.output?.includes("pdf") ?? false,
12451250
},
1246-
interleaved: model.interleaved ?? false,
1251+
interleaved: typeof model.interleaved === "string" ? { field: model.interleaved } : (model.interleaved ?? false),
12471252
},
12481253
release_date: model.release_date ?? "",
12491254
variants: {},
@@ -1475,7 +1480,7 @@ const layer = Layer.effect(
14751480
pdf: model.modalities?.output?.includes("pdf") ?? existingModel?.capabilities.output.pdf ?? false,
14761481
},
14771482
interleaved:
1478-
model.interleaved ??
1483+
(typeof model.interleaved === "string" ? { field: model.interleaved } : model.interleaved) ??
14791484
existingModel?.capabilities.interleaved ??
14801485
(!existingModel && apiNpm === "@ai-sdk/openai-compatible" && apiID.includes("deepseek")
14811486
? { field: "reasoning_content" }

packages/opencode/test/provider/provider.test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,8 @@ it.instance(
252252
const provider = providers[ProviderV2.ID.make("custom-provider")]
253253
expect(provider.models["deepseek-r1"].capabilities.interleaved).toEqual({ field: "reasoning_content" })
254254
expect(provider.models["deepseek-details"].capabilities.interleaved).toEqual({ field: "reasoning_details" })
255+
expect(provider.models["deepseek-text"].capabilities.interleaved).toEqual({ field: "reasoning_text" })
256+
expect(provider.models["custom-reasoning"].capabilities.interleaved).toEqual({ field: "vendor_reasoning" })
255257
expect(provider.models["custom-model"].capabilities.interleaved).toBe(false)
256258
expect(
257259
providers[ProviderV2.ID.make("custom-anthropic-provider")].models["deepseek-r1"].capabilities.interleaved,
@@ -267,6 +269,8 @@ it.instance(
267269
models: {
268270
"deepseek-r1": { name: "DeepSeek R1" },
269271
"deepseek-details": { name: "DeepSeek Details", interleaved: { field: "reasoning_details" } },
272+
"deepseek-text": { name: "DeepSeek Text", interleaved: "reasoning_text" },
273+
"custom-reasoning": { name: "Custom Reasoning", interleaved: { field: "vendor_reasoning" } },
270274
"custom-model": { name: "Custom Model" },
271275
},
272276
options: { apiKey: "custom-key" },
@@ -1462,6 +1466,7 @@ test("models.dev normalization fills required response fields", () => {
14621466
id: "gpt-5.4",
14631467
name: "GPT-5.4",
14641468
family: "gpt",
1469+
interleaved: "reasoning_text",
14651470
cost: { input: 2.5, output: 15 },
14661471
limit: { context: 1_050_000, input: 922_000, output: 128_000 },
14671472
},
@@ -1474,6 +1479,7 @@ test("models.dev normalization fills required response fields", () => {
14741479
expect(model.capabilities.reasoning).toBe(false)
14751480
expect(model.capabilities.attachment).toBe(false)
14761481
expect(model.capabilities.toolcall).toBe(true)
1482+
expect(model.capabilities.interleaved).toEqual({ field: "reasoning_text" })
14771483
expect(model.release_date).toBe("")
14781484
})
14791485

packages/sdk/js/src/v2/gen/types.gen.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1768,9 +1768,13 @@ export type ProviderConfig = {
17681768
temperature?: boolean
17691769
tool_call?: boolean
17701770
interleaved?:
1771-
| true
1771+
| boolean
1772+
| "reasoning"
1773+
| "reasoning_content"
1774+
| "reasoning_text"
1775+
| string
17721776
| {
1773-
field: "reasoning" | "reasoning_content" | "reasoning_details"
1777+
field: "reasoning" | "reasoning_content" | "reasoning_text" | string
17741778
}
17751779
cost?: {
17761780
input: number
@@ -2057,7 +2061,7 @@ export type Model = {
20572061
interleaved:
20582062
| boolean
20592063
| {
2060-
field: "reasoning" | "reasoning_content" | "reasoning_details"
2064+
field: "reasoning" | "reasoning_content" | "reasoning_text" | string
20612065
}
20622066
}
20632067
cost: {

packages/sdk/openapi.json

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20820,15 +20820,28 @@
2082020820
"interleaved": {
2082120821
"anyOf": [
2082220822
{
20823-
"type": "boolean",
20824-
"enum": [true]
20823+
"type": "boolean"
20824+
},
20825+
{
20826+
"type": "string",
20827+
"enum": ["reasoning", "reasoning_content", "reasoning_text"]
20828+
},
20829+
{
20830+
"type": "string"
2082520831
},
2082620832
{
2082720833
"type": "object",
2082820834
"properties": {
2082920835
"field": {
20830-
"type": "string",
20831-
"enum": ["reasoning", "reasoning_content", "reasoning_details"]
20836+
"anyOf": [
20837+
{
20838+
"type": "string",
20839+
"enum": ["reasoning", "reasoning_content", "reasoning_text"]
20840+
},
20841+
{
20842+
"type": "string"
20843+
}
20844+
]
2083220845
}
2083320846
},
2083420847
"required": ["field"],
@@ -21641,8 +21654,15 @@
2164121654
"type": "object",
2164221655
"properties": {
2164321656
"field": {
21644-
"type": "string",
21645-
"enum": ["reasoning", "reasoning_content", "reasoning_details"]
21657+
"anyOf": [
21658+
{
21659+
"type": "string",
21660+
"enum": ["reasoning", "reasoning_content", "reasoning_text"]
21661+
},
21662+
{
21663+
"type": "string"
21664+
}
21665+
]
2164621666
}
2164721667
},
2164821668
"required": ["field"],

0 commit comments

Comments
 (0)