fix(provider): widen interleaved reasoning fields (#39556)

Co-authored-by: Aiden Cline <rekram1-node@users.noreply.github.com>
This commit is contained in:
opencode-agent[bot]
2026-07-30 11:10:34 -05:00
committed by GitHub
parent ecfff673a9
commit ecc58c5fc2
6 changed files with 63 additions and 16 deletions
+8 -2
View File
@@ -15,6 +15,11 @@ import { httpClient } from "./effect/app-node-platform"
export const CatalogModelStatus = Schema.Literals(["alpha", "beta", "deprecated"]) export const CatalogModelStatus = Schema.Literals(["alpha", "beta", "deprecated"])
export type CatalogModelStatus = typeof CatalogModelStatus.Type export type CatalogModelStatus = typeof CatalogModelStatus.Type
const InterleavedField = Schema.Union([
Schema.Literals(["reasoning", "reasoning_content", "reasoning_text"]),
Schema.String,
])
const USER_AGENT = `opencode/${InstallationChannel}/${InstallationVersion}/${Flag.OPENCODE_CLIENT}` const USER_AGENT = `opencode/${InstallationChannel}/${InstallationVersion}/${Flag.OPENCODE_CLIENT}`
const CostTier = Schema.Struct({ const CostTier = Schema.Struct({
@@ -71,9 +76,10 @@ export const Model = Schema.Struct({
reasoning_options: Schema.optional(Schema.Array(ReasoningOption)), reasoning_options: Schema.optional(Schema.Array(ReasoningOption)),
interleaved: Schema.optional( interleaved: Schema.optional(
Schema.Union([ Schema.Union([
Schema.Literal(true), Schema.Boolean,
InterleavedField,
Schema.Struct({ Schema.Struct({
field: Schema.Literals(["reasoning", "reasoning_content", "reasoning_details"]), field: InterleavedField,
}), }),
]), ]),
), ),
+8 -2
View File
@@ -5,6 +5,11 @@ import { PositiveInt } from "../../schema"
export const ModelStatus = Schema.Literals(["alpha", "beta", "deprecated", "active"]) export const ModelStatus = Schema.Literals(["alpha", "beta", "deprecated", "active"])
const InterleavedField = Schema.Union([
Schema.Literals(["reasoning", "reasoning_content", "reasoning_text"]),
Schema.String,
])
export const Model = Schema.Struct({ export const Model = Schema.Struct({
id: Schema.optional(Schema.String), id: Schema.optional(Schema.String),
name: Schema.optional(Schema.String), name: Schema.optional(Schema.String),
@@ -16,9 +21,10 @@ export const Model = Schema.Struct({
tool_call: Schema.optional(Schema.Boolean), tool_call: Schema.optional(Schema.Boolean),
interleaved: Schema.optional( interleaved: Schema.optional(
Schema.Union([ Schema.Union([
Schema.Literal(true), Schema.Boolean,
InterleavedField,
Schema.Struct({ Schema.Struct({
field: Schema.Literals(["reasoning", "reasoning_content", "reasoning_details"]), field: InterleavedField,
}), }),
]), ]),
), ),
+8 -3
View File
@@ -976,10 +976,15 @@ const ProviderModalities = Schema.Struct({
pdf: Schema.Boolean, pdf: Schema.Boolean,
}) })
const ProviderInterleavedField = Schema.Union([
Schema.Literals(["reasoning", "reasoning_content", "reasoning_text"]),
Schema.String,
])
const ProviderInterleaved = Schema.Union([ const ProviderInterleaved = Schema.Union([
Schema.Boolean, Schema.Boolean,
Schema.Struct({ Schema.Struct({
field: Schema.Literals(["reasoning", "reasoning_content", "reasoning_details"]), field: ProviderInterleavedField,
}), }),
]) ])
@@ -1243,7 +1248,7 @@ function fromModelsDevModel(provider: ModelsDev.Provider, model: ModelsDev.Model
video: model.modalities?.output?.includes("video") ?? false, video: model.modalities?.output?.includes("video") ?? false,
pdf: model.modalities?.output?.includes("pdf") ?? false, pdf: model.modalities?.output?.includes("pdf") ?? false,
}, },
interleaved: model.interleaved ?? false, interleaved: typeof model.interleaved === "string" ? { field: model.interleaved } : (model.interleaved ?? false),
}, },
release_date: model.release_date ?? "", release_date: model.release_date ?? "",
variants: {}, variants: {},
@@ -1475,7 +1480,7 @@ const layer = Layer.effect(
pdf: model.modalities?.output?.includes("pdf") ?? existingModel?.capabilities.output.pdf ?? false, pdf: model.modalities?.output?.includes("pdf") ?? existingModel?.capabilities.output.pdf ?? false,
}, },
interleaved: interleaved:
model.interleaved ?? (typeof model.interleaved === "string" ? { field: model.interleaved } : model.interleaved) ??
existingModel?.capabilities.interleaved ?? existingModel?.capabilities.interleaved ??
(!existingModel && apiNpm === "@ai-sdk/openai-compatible" && apiID.includes("deepseek") (!existingModel && apiNpm === "@ai-sdk/openai-compatible" && apiID.includes("deepseek")
? { field: "reasoning_content" } ? { field: "reasoning_content" }
@@ -252,6 +252,8 @@ it.instance(
const provider = providers[ProviderV2.ID.make("custom-provider")] const provider = providers[ProviderV2.ID.make("custom-provider")]
expect(provider.models["deepseek-r1"].capabilities.interleaved).toEqual({ field: "reasoning_content" }) 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["deepseek-details"].capabilities.interleaved).toEqual({ field: "reasoning_details" })
expect(provider.models["deepseek-text"].capabilities.interleaved).toEqual({ field: "reasoning_text" })
expect(provider.models["custom-reasoning"].capabilities.interleaved).toEqual({ field: "vendor_reasoning" })
expect(provider.models["custom-model"].capabilities.interleaved).toBe(false) expect(provider.models["custom-model"].capabilities.interleaved).toBe(false)
expect( expect(
providers[ProviderV2.ID.make("custom-anthropic-provider")].models["deepseek-r1"].capabilities.interleaved, providers[ProviderV2.ID.make("custom-anthropic-provider")].models["deepseek-r1"].capabilities.interleaved,
@@ -267,6 +269,8 @@ it.instance(
models: { models: {
"deepseek-r1": { name: "DeepSeek R1" }, "deepseek-r1": { name: "DeepSeek R1" },
"deepseek-details": { name: "DeepSeek Details", interleaved: { field: "reasoning_details" } }, "deepseek-details": { name: "DeepSeek Details", interleaved: { field: "reasoning_details" } },
"deepseek-text": { name: "DeepSeek Text", interleaved: "reasoning_text" },
"custom-reasoning": { name: "Custom Reasoning", interleaved: { field: "vendor_reasoning" } },
"custom-model": { name: "Custom Model" }, "custom-model": { name: "Custom Model" },
}, },
options: { apiKey: "custom-key" }, options: { apiKey: "custom-key" },
@@ -1462,6 +1466,7 @@ test("models.dev normalization fills required response fields", () => {
id: "gpt-5.4", id: "gpt-5.4",
name: "GPT-5.4", name: "GPT-5.4",
family: "gpt", family: "gpt",
interleaved: "reasoning_text",
cost: { input: 2.5, output: 15 }, cost: { input: 2.5, output: 15 },
limit: { context: 1_050_000, input: 922_000, output: 128_000 }, limit: { context: 1_050_000, input: 922_000, output: 128_000 },
}, },
@@ -1474,6 +1479,7 @@ test("models.dev normalization fills required response fields", () => {
expect(model.capabilities.reasoning).toBe(false) expect(model.capabilities.reasoning).toBe(false)
expect(model.capabilities.attachment).toBe(false) expect(model.capabilities.attachment).toBe(false)
expect(model.capabilities.toolcall).toBe(true) expect(model.capabilities.toolcall).toBe(true)
expect(model.capabilities.interleaved).toEqual({ field: "reasoning_text" })
expect(model.release_date).toBe("") expect(model.release_date).toBe("")
}) })
+7 -3
View File
@@ -1768,9 +1768,13 @@ export type ProviderConfig = {
temperature?: boolean temperature?: boolean
tool_call?: boolean tool_call?: boolean
interleaved?: interleaved?:
| true | boolean
| "reasoning"
| "reasoning_content"
| "reasoning_text"
| string
| { | {
field: "reasoning" | "reasoning_content" | "reasoning_details" field: "reasoning" | "reasoning_content" | "reasoning_text" | string
} }
cost?: { cost?: {
input: number input: number
@@ -2057,7 +2061,7 @@ export type Model = {
interleaved: interleaved:
| boolean | boolean
| { | {
field: "reasoning" | "reasoning_content" | "reasoning_details" field: "reasoning" | "reasoning_content" | "reasoning_text" | string
} }
} }
cost: { cost: {
+26 -6
View File
@@ -20820,15 +20820,28 @@
"interleaved": { "interleaved": {
"anyOf": [ "anyOf": [
{ {
"type": "boolean", "type": "boolean"
"enum": [true] },
{
"type": "string",
"enum": ["reasoning", "reasoning_content", "reasoning_text"]
},
{
"type": "string"
}, },
{ {
"type": "object", "type": "object",
"properties": { "properties": {
"field": { "field": {
"type": "string", "anyOf": [
"enum": ["reasoning", "reasoning_content", "reasoning_details"] {
"type": "string",
"enum": ["reasoning", "reasoning_content", "reasoning_text"]
},
{
"type": "string"
}
]
} }
}, },
"required": ["field"], "required": ["field"],
@@ -21641,8 +21654,15 @@
"type": "object", "type": "object",
"properties": { "properties": {
"field": { "field": {
"type": "string", "anyOf": [
"enum": ["reasoning", "reasoning_content", "reasoning_details"] {
"type": "string",
"enum": ["reasoning", "reasoning_content", "reasoning_text"]
},
{
"type": "string"
}
]
} }
}, },
"required": ["field"], "required": ["field"],