diff --git a/src/agents/model-selection.ts b/src/agents/model-selection.ts index 5be15fa15a8..385558c43b8 100644 --- a/src/agents/model-selection.ts +++ b/src/agents/model-selection.ts @@ -1,4 +1,3 @@ -import { resolveThinkingDefaultForModel } from "../auto-reply/thinking.shared.js"; import { resolveAgentModelFallbackValues, resolveAgentModelPrimaryValue, @@ -8,7 +7,6 @@ import type { OpenClawConfig } from "../config/types.openclaw.js"; import { createSubsystemLogger } from "../logging/subsystem.js"; import { normalizeLowercaseStringOrEmpty, - normalizeOptionalLowercaseString, normalizeOptionalString, } from "../shared/string-coerce.js"; import { sanitizeForLog, stripAnsi } from "../terminal/ansi.js"; @@ -21,6 +19,7 @@ import { resolveConfiguredProviderFallback } from "./configured-provider-fallbac import { DEFAULT_MODEL, DEFAULT_PROVIDER } from "./defaults.js"; import type { ModelCatalogEntry } from "./model-catalog.types.js"; import { splitTrailingAuthProfile } from "./model-ref-profile.js"; +export { resolveThinkingDefault } from "./model-thinking-default.js"; import { type ModelRef, findNormalizedProviderKey, @@ -761,65 +760,6 @@ export function resolveAllowedModelRef(params: { return { ref: resolved.ref, key: status.key }; } -export function resolveThinkingDefault(params: { - cfg: OpenClawConfig; - provider: string; - model: string; - catalog?: ModelCatalogEntry[]; -}): ThinkLevel { - const normalizedProvider = normalizeProviderId(params.provider); - const normalizedModel = normalizeLowercaseStringOrEmpty(params.model).replace(/\./g, "-"); - const catalogCandidate = params.catalog?.find( - (entry) => entry.provider === params.provider && entry.id === params.model, - ); - const configuredModels = params.cfg.agents?.defaults?.models; - const canonicalKey = modelKey(params.provider, params.model); - const legacyKey = legacyModelKey(params.provider, params.model); - const normalizedCanonicalKey = normalizeLowercaseStringOrEmpty(canonicalKey); - const normalizedLegacyKey = normalizeOptionalLowercaseString(legacyKey); - const primarySelection = normalizeModelSelection(params.cfg.agents?.defaults?.model); - const normalizedPrimarySelection = normalizeOptionalLowercaseString(primarySelection); - const explicitModelConfigured = - (configuredModels ? canonicalKey in configuredModels : false) || - Boolean(legacyKey && configuredModels && legacyKey in configuredModels) || - normalizedPrimarySelection === normalizedCanonicalKey || - Boolean(normalizedLegacyKey && normalizedPrimarySelection === normalizedLegacyKey) || - normalizedPrimarySelection === normalizeLowercaseStringOrEmpty(params.model); - const perModelThinking = - configuredModels?.[canonicalKey]?.params?.thinking ?? - (legacyKey ? configuredModels?.[legacyKey]?.params?.thinking : undefined); - if ( - perModelThinking === "off" || - perModelThinking === "minimal" || - perModelThinking === "low" || - perModelThinking === "medium" || - perModelThinking === "high" || - perModelThinking === "xhigh" || - perModelThinking === "adaptive" - ) { - return perModelThinking; - } - const configured = params.cfg.agents?.defaults?.thinkingDefault; - if (configured) { - return configured; - } - if ( - normalizedProvider === "anthropic" && - explicitModelConfigured && - typeof catalogCandidate?.name === "string" && - /4\.6\b/.test(catalogCandidate.name) && - (normalizedModel.startsWith("claude-opus-4-6") || - normalizedModel.startsWith("claude-sonnet-4-6")) - ) { - return "adaptive"; - } - return resolveThinkingDefaultForModel({ - provider: params.provider, - model: params.model, - catalog: params.catalog, - }); -} - /** Default reasoning level when session/directive do not set it: "on" if model supports reasoning, else "off". */ export function resolveReasoningDefault(params: { provider: string; diff --git a/src/agents/model-thinking-default.ts b/src/agents/model-thinking-default.ts new file mode 100644 index 00000000000..5479152253d --- /dev/null +++ b/src/agents/model-thinking-default.ts @@ -0,0 +1,70 @@ +import { resolveThinkingDefaultForModel } from "../auto-reply/thinking.shared.js"; +import type { OpenClawConfig } from "../config/types.openclaw.js"; +import { + normalizeLowercaseStringOrEmpty, + normalizeOptionalLowercaseString, +} from "../shared/string-coerce.js"; +import type { ModelCatalogEntry } from "./model-catalog.types.js"; +import { legacyModelKey, modelKey, normalizeProviderId } from "./model-selection-normalize.js"; +import { normalizeModelSelection } from "./model-selection-resolve.js"; + +type ThinkLevel = "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "adaptive"; + +export function resolveThinkingDefault(params: { + cfg: OpenClawConfig; + provider: string; + model: string; + catalog?: ModelCatalogEntry[]; +}): ThinkLevel { + const normalizedProvider = normalizeProviderId(params.provider); + const normalizedModel = normalizeLowercaseStringOrEmpty(params.model).replace(/\./g, "-"); + const catalogCandidate = params.catalog?.find( + (entry) => entry.provider === params.provider && entry.id === params.model, + ); + const configuredModels = params.cfg.agents?.defaults?.models; + const canonicalKey = modelKey(params.provider, params.model); + const legacyKey = legacyModelKey(params.provider, params.model); + const normalizedCanonicalKey = normalizeLowercaseStringOrEmpty(canonicalKey); + const normalizedLegacyKey = normalizeOptionalLowercaseString(legacyKey); + const primarySelection = normalizeModelSelection(params.cfg.agents?.defaults?.model); + const normalizedPrimarySelection = normalizeOptionalLowercaseString(primarySelection); + const explicitModelConfigured = + (configuredModels ? canonicalKey in configuredModels : false) || + Boolean(legacyKey && configuredModels && legacyKey in configuredModels) || + normalizedPrimarySelection === normalizedCanonicalKey || + Boolean(normalizedLegacyKey && normalizedPrimarySelection === normalizedLegacyKey) || + normalizedPrimarySelection === normalizeLowercaseStringOrEmpty(params.model); + const perModelThinking = + configuredModels?.[canonicalKey]?.params?.thinking ?? + (legacyKey ? configuredModels?.[legacyKey]?.params?.thinking : undefined); + if ( + perModelThinking === "off" || + perModelThinking === "minimal" || + perModelThinking === "low" || + perModelThinking === "medium" || + perModelThinking === "high" || + perModelThinking === "xhigh" || + perModelThinking === "adaptive" + ) { + return perModelThinking; + } + const configured = params.cfg.agents?.defaults?.thinkingDefault; + if (configured) { + return configured; + } + if ( + normalizedProvider === "anthropic" && + explicitModelConfigured && + typeof catalogCandidate?.name === "string" && + /4\.6\b/.test(catalogCandidate.name) && + (normalizedModel.startsWith("claude-opus-4-6") || + normalizedModel.startsWith("claude-sonnet-4-6")) + ) { + return "adaptive"; + } + return resolveThinkingDefaultForModel({ + provider: params.provider, + model: params.model, + catalog: params.catalog, + }); +} diff --git a/src/cron/isolated-agent/run.runtime.ts b/src/cron/isolated-agent/run.runtime.ts index c873a114224..fff003c988c 100644 --- a/src/cron/isolated-agent/run.runtime.ts +++ b/src/cron/isolated-agent/run.runtime.ts @@ -7,7 +7,8 @@ export { } from "../../agents/agent-scope.js"; export { resolveCronStyleNow } from "../../agents/current-time.js"; export { DEFAULT_CONTEXT_TOKENS } from "../../agents/defaults.js"; -export { isCliProvider, resolveThinkingDefault } from "../../agents/model-selection.js"; +export { isCliProvider } from "../../agents/model-selection-cli.js"; +export { resolveThinkingDefault } from "../../agents/model-thinking-default.js"; export { resolveAgentTimeoutMs } from "../../agents/timeout.js"; export { deriveSessionTotalTokens, hasNonzeroUsage } from "../../agents/usage.js"; export { DEFAULT_IDENTITY_FILENAME, ensureAgentWorkspace } from "../../agents/workspace.js";