mirror of
https://github.com/Gitlawb/openclaude.git
synced 2026-08-24 02:34:15 -05:00
fix(thinking): disable thinking for unsupported Ollama models (#1376)
* fix(thinking): disable thinking for unsupported Ollama models Fixes #1371 - Adds central `shouldUseThinkingForModel` gate that checks the actual route and model descriptor. - Disables thinking parameters for the Ollama route when the model is unknown or unsupported. - Updates API requests to evaluate the actual retry model against the capability gate instead of the initial request model. - Adds targeted tests for Ollama logic and shim payloads. * test(thinking): cover Ollama thinking gate
This commit is contained in:
@@ -181,7 +181,7 @@ import { calculateUSDCost } from 'src/utils/modelCost.js'
|
||||
import { endQueryProfile, queryCheckpoint } from 'src/utils/queryProfiler.js'
|
||||
import {
|
||||
modelSupportsAdaptiveThinking,
|
||||
modelSupportsThinking,
|
||||
shouldUseThinkingForModel,
|
||||
type ThinkingConfig,
|
||||
} from 'src/utils/thinking.js'
|
||||
import {
|
||||
@@ -1604,18 +1604,16 @@ async function* queryModel(
|
||||
options.maxOutputTokensOverride ||
|
||||
getMaxOutputTokensForModel(options.model)
|
||||
|
||||
const hasThinking =
|
||||
thinkingConfig.type !== 'disabled' &&
|
||||
!isEnvTruthy(process.env.CLAUDE_CODE_DISABLE_THINKING)
|
||||
const hasThinking = shouldUseThinkingForModel(retryContext.model, thinkingConfig)
|
||||
let thinking: BetaMessageStreamParams['thinking'] | undefined = undefined
|
||||
|
||||
// IMPORTANT: Do not change the adaptive-vs-budget thinking selection below
|
||||
// without notifying the model launch DRI and research. This is a sensitive
|
||||
// setting that can greatly affect model quality and bashing.
|
||||
if (hasThinking && modelSupportsThinking(options.model)) {
|
||||
if (hasThinking) {
|
||||
if (
|
||||
!isEnvTruthy(process.env.CLAUDE_CODE_DISABLE_ADAPTIVE_THINKING) &&
|
||||
modelSupportsAdaptiveThinking(options.model)
|
||||
modelSupportsAdaptiveThinking(retryContext.model)
|
||||
) {
|
||||
// For models that support adaptive thinking, always use adaptive
|
||||
// thinking without a budget.
|
||||
@@ -1625,7 +1623,7 @@ async function* queryModel(
|
||||
} else {
|
||||
// For models that do not support adaptive thinking, use the default
|
||||
// thinking budget unless explicitly specified.
|
||||
let thinkingBudget = getMaxThinkingTokensForModel(options.model)
|
||||
let thinkingBudget = getMaxThinkingTokensForModel(retryContext.model)
|
||||
if (
|
||||
thinkingConfig.type === 'enabled' &&
|
||||
thinkingConfig.budgetTokens !== undefined
|
||||
|
||||
@@ -25,6 +25,7 @@ const ENV_KEYS = [
|
||||
'ANTHROPIC_DEFAULT_SONNET_MODEL_SUPPORTED_CAPABILITIES',
|
||||
'ANTHROPIC_DEFAULT_HAIKU_MODEL',
|
||||
'ANTHROPIC_DEFAULT_HAIKU_MODEL_SUPPORTED_CAPABILITIES',
|
||||
'CLAUDE_CODE_DISABLE_THINKING',
|
||||
'USER_TYPE',
|
||||
]
|
||||
|
||||
@@ -57,9 +58,13 @@ afterEach(() => {
|
||||
|
||||
async function importFreshThinkingModule() {
|
||||
mock.restore()
|
||||
mock.module('./model/providers.js', () => ({
|
||||
getAPIProvider: () => 'openai',
|
||||
}))
|
||||
const originalProviders = await import('./model/providers.js')
|
||||
mock.module('./model/providers.js', () => {
|
||||
return {
|
||||
...originalProviders,
|
||||
getAPIProvider: () => 'openai',
|
||||
}
|
||||
})
|
||||
const nonce = `${Date.now()}-${Math.random()}`
|
||||
return import(`./thinking.js?ts=${nonce}`)
|
||||
}
|
||||
@@ -109,3 +114,16 @@ describe('modelSupportsThinking — Z.AI GLM', () => {
|
||||
expect(modelSupportsThinking('GLM-5.1')).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('shouldUseThinkingForModel — Ollama', () => {
|
||||
test('does not use thinking for Ollama models when app-level thinking is enabled', async () => {
|
||||
process.env.CLAUDE_CODE_USE_OPENAI = '1'
|
||||
process.env.OPENAI_BASE_URL = 'http://localhost:11434/v1'
|
||||
const { shouldUseThinkingForModel } = await importFreshThinkingModule()
|
||||
const enabledThinking = { type: 'enabled' as const, budgetTokens: 1024 }
|
||||
|
||||
expect(shouldUseThinkingForModel('llama3.1:8b', enabledThinking)).toBe(false)
|
||||
// Covers catalog-missing local names that would otherwise match Claude 4 heuristics.
|
||||
expect(shouldUseThinkingForModel('claude-sonnet-4-local', enabledThinking)).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -12,6 +12,7 @@ import { resolveAntModel } from './model/antModels.js'
|
||||
import { get3PModelCapabilityOverride } from './model/modelSupportOverrides.js'
|
||||
import { getAPIProvider } from './model/providers.js'
|
||||
import { getSettingsWithErrors } from './settings/settings.js'
|
||||
import { isEnvTruthy } from './envUtils.js'
|
||||
|
||||
export type ThinkingConfig =
|
||||
| { type: 'adaptive' }
|
||||
@@ -143,6 +144,10 @@ export function modelSupportsThinking(model: string): boolean {
|
||||
if (descriptorSupportsThinking !== undefined) {
|
||||
return descriptorSupportsThinking
|
||||
}
|
||||
const routeId = resolveActiveRouteIdFromEnv(process.env)
|
||||
if (routeId === 'ollama') {
|
||||
return false
|
||||
}
|
||||
}
|
||||
// 3P (Bedrock/Vertex): only Opus 4+ and Sonnet 4+
|
||||
return canonical.includes('sonnet-4') || canonical.includes('opus-4')
|
||||
@@ -199,3 +204,14 @@ export function shouldEnableThinkingByDefault(): boolean {
|
||||
// Enable thinking by default unless explicitly disabled.
|
||||
return true
|
||||
}
|
||||
|
||||
export function shouldUseThinkingForModel(
|
||||
model: string,
|
||||
thinkingConfig: ThinkingConfig,
|
||||
): boolean {
|
||||
return (
|
||||
thinkingConfig.type !== 'disabled' &&
|
||||
!isEnvTruthy(process.env.CLAUDE_CODE_DISABLE_THINKING) &&
|
||||
modelSupportsThinking(model)
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user