Skip to content
This repository was archived by the owner on May 15, 2026. It is now read-only.

Commit 43b2425

Browse files
committed
fix: reasoning_effort parameter silently dropped for OpenAI-compatible providers
Root cause: BaseOpenAiCompatibleProvider and OpenAICompatibleHandler never called getModelParams() and never read options.reasoningEffort, causing reasoning_effort to be silently dropped from all API requests regardless of user settings. Changes: - BaseOpenAiCompatibleProvider.getModel() now calls getModelParams() (same pattern as OpenAiHandler and DeepSeekHandler) - Added openAiCustomModelInfo fallback for custom/unknown models - createStream() and completePrompt() now spread reasoning from getModel() - OpenAICompatibleHandler now passes reasoning_effort via AI SDK's providerOptions.openaiCompatible.reasoningEffort Affected providers: Baseten, Fireworks, SambaNova, ZAi, Moonshot
1 parent e921f9d commit 43b2425

2 files changed

Lines changed: 51 additions & 8 deletions

File tree

src/api/providers/base-openai-compatible-provider.ts

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { type ApiHandlerOptions, getModelMaxOutputTokens } from "../../shared/ap
77
import { TagMatcher } from "../../utils/tag-matcher"
88
import { ApiStream, ApiStreamUsageChunk } from "../transform/stream"
99
import { convertToOpenAiMessages } from "../transform/openai-format"
10+
import { getModelParams } from "../transform/model-params"
1011

1112
import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from "../index"
1213
import { DEFAULT_HEADERS } from "./constants"
@@ -73,7 +74,7 @@ export abstract class BaseOpenAiCompatibleProvider<ModelName extends string>
7374
metadata?: ApiHandlerCreateMessageMetadata,
7475
requestOptions?: OpenAI.RequestOptions,
7576
) {
76-
const { id: model, info } = this.getModel()
77+
const { id: model, info, reasoning } = this.getModel()
7778

7879
// Centralized cap: clamp to 20% of the context window (unless provider-specific exceptions apply)
7980
const max_tokens =
@@ -98,8 +99,14 @@ export abstract class BaseOpenAiCompatibleProvider<ModelName extends string>
9899
parallel_tool_calls: metadata?.parallelToolCalls ?? true,
99100
}
100101

101-
// Add thinking parameter if reasoning is enabled and model supports it
102-
if (this.options.enableReasoningEffort && info.supportsReasoningBinary) {
102+
// Add reasoning_effort from centralized model params (handled by getModelParams)
103+
if (reasoning) {
104+
Object.assign(params, reasoning)
105+
}
106+
107+
// Fallback: Add binary thinking parameter when reasoning_effort not used but
108+
// reasoning is still enabled and model supports simple on/off thinking
109+
if (!reasoning && this.options.enableReasoningEffort && info.supportsReasoningBinary) {
103110
;(params as any).thinking = { type: "enabled" }
104111
}
105112

@@ -220,15 +227,20 @@ export abstract class BaseOpenAiCompatibleProvider<ModelName extends string>
220227
}
221228

222229
async completePrompt(prompt: string): Promise<string> {
223-
const { id: modelId, info: modelInfo } = this.getModel()
230+
const { id: modelId, info: modelInfo, reasoning } = this.getModel()
224231

225232
const params: OpenAI.Chat.Completions.ChatCompletionCreateParams = {
226233
model: modelId,
227234
messages: [{ role: "user", content: prompt }],
228235
}
229236

230-
// Add thinking parameter if reasoning is enabled and model supports it
231-
if (this.options.enableReasoningEffort && modelInfo.supportsReasoningBinary) {
237+
// Add reasoning_effort from centralized model params
238+
if (reasoning) {
239+
Object.assign(params, reasoning)
240+
}
241+
242+
// Fallback: Add binary thinking parameter when reasoning_effort not used
243+
if (!reasoning && this.options.enableReasoningEffort && modelInfo.supportsReasoningBinary) {
232244
;(params as any).thinking = { type: "enabled" }
233245
}
234246

@@ -250,11 +262,23 @@ export abstract class BaseOpenAiCompatibleProvider<ModelName extends string>
250262
}
251263

252264
override getModel() {
253-
const id =
265+
const providerId =
254266
this.options.apiModelId && this.options.apiModelId in this.providerModels
255267
? (this.options.apiModelId as ModelName)
256268
: this.defaultProviderModelId
257269

258-
return { id, info: this.providerModels[id] }
270+
// Allow user to override model info via openAiCustomModelInfo (like OpenAiHandler),
271+
// enabling support for custom/unknown models with reasoning effort capability
272+
const info: ModelInfo = this.options.openAiCustomModelInfo ?? this.providerModels[providerId]
273+
274+
const params = getModelParams({
275+
format: "openai",
276+
modelId: providerId,
277+
model: info,
278+
settings: this.options,
279+
defaultTemperature: this.defaultTemperature,
280+
})
281+
282+
return { id: providerId as string, info, ...params }
259283
}
260284
}

src/api/providers/openai-compatible.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,12 @@ export abstract class OpenAICompatibleHandler extends BaseProvider implements Si
165165
const openAiTools = this.convertToolsForOpenAI(metadata?.tools)
166166
const aiSdkTools = convertToolsForAiSdk(openAiTools) as ToolSet | undefined
167167

168+
// Build provider options for reasoning_effort (supported by @ai-sdk/openai-compatible)
169+
const modelReasoning = (model as any).reasoning as { reasoning_effort?: string } | undefined
170+
const openaiCompatibleOptions = modelReasoning?.reasoning_effort
171+
? { reasoningEffort: modelReasoning.reasoning_effort }
172+
: undefined
173+
168174
// Build the request options
169175
const requestOptions: Parameters<typeof streamText>[0] = {
170176
model: languageModel,
@@ -174,6 +180,9 @@ export abstract class OpenAICompatibleHandler extends BaseProvider implements Si
174180
maxOutputTokens: this.getMaxOutputTokens(),
175181
tools: aiSdkTools,
176182
toolChoice: this.mapToolChoice(metadata?.tool_choice),
183+
...(openaiCompatibleOptions
184+
? { providerOptions: { openaiCompatible: openaiCompatibleOptions } as any }
185+
: {}),
177186
}
178187

179188
// Use streamText for streaming responses
@@ -199,12 +208,22 @@ export abstract class OpenAICompatibleHandler extends BaseProvider implements Si
199208
*/
200209
async completePrompt(prompt: string): Promise<string> {
201210
const languageModel = this.getLanguageModel()
211+
const model = this.getModel()
212+
213+
// Build provider options for reasoning_effort
214+
const modelReasoning = (model as any).reasoning as { reasoning_effort?: string } | undefined
215+
const openaiCompatibleOptions = modelReasoning?.reasoning_effort
216+
? { reasoningEffort: modelReasoning.reasoning_effort }
217+
: undefined
202218

203219
const { text } = await generateText({
204220
model: languageModel,
205221
prompt,
206222
maxOutputTokens: this.getMaxOutputTokens(),
207223
temperature: this.config.temperature ?? 0,
224+
...(openaiCompatibleOptions
225+
? { providerOptions: { openaiCompatible: openaiCompatibleOptions } as any }
226+
: {}),
208227
})
209228

210229
return text

0 commit comments

Comments
 (0)