From a8ec92748c19faa2fac82c59c756aa61f2396045 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Thu, 26 Mar 2026 16:54:04 +0900 Subject: [PATCH] fix(model-resolution): honor user config overrides on cold cache MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When provider-models cache is cold (first run / cache miss), resolveModelForDelegateTask returns {skipped: true}. Previously this caused the subagent resolver to: 1. Ignore the user's explicit model override (e.g. explore.model) 2. Fall through to the hardcoded fallback chain which may contain model IDs that don't exist in the provider catalog Now: - subagent-resolver: if resolution is skipped but user explicitly configured a model, use it directly - subagent-resolver: don't assign hardcoded fallback chain on skip - category-resolver: same — don't leak hardcoded chain on skip - general-agents: if user model fails resolution, use it as-is instead of falling back to hardcoded chain first entry Closes #2820 --- src/agents/builtin-agents/general-agents.ts | 8 ++++++-- src/tools/delegate-task/category-resolver.ts | 3 ++- src/tools/delegate-task/subagent-resolver.ts | 20 ++++++++++++++++++-- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/agents/builtin-agents/general-agents.ts b/src/agents/builtin-agents/general-agents.ts index f5fd1d920..7d9d52979 100644 --- a/src/agents/builtin-agents/general-agents.ts +++ b/src/agents/builtin-agents/general-agents.ts @@ -78,12 +78,16 @@ export function collectPendingBuiltinAgents(input: { }) if (!resolution) { if (override?.model) { - log("[agent-registration] User-configured model could not be resolved, falling back", { + // User explicitly configured a model but resolution failed (e.g., cold cache). + // Honor the user's choice directly instead of falling back to hardcoded chain. + log("[agent-registration] User-configured model not resolved, using as-is", { agent: agentName, configuredModel: override.model, }) + resolution = { model: override.model, provenance: "override" as const } + } else { + resolution = getFirstFallbackModel(requirement) } - resolution = getFirstFallbackModel(requirement) } if (!resolution) continue const { model, variant: resolvedVariant } = resolution diff --git a/src/tools/delegate-task/category-resolver.ts b/src/tools/delegate-task/category-resolver.ts index 648fa933c..8406652f1 100644 --- a/src/tools/delegate-task/category-resolver.ts +++ b/src/tools/delegate-task/category-resolver.ts @@ -239,6 +239,7 @@ Available categories: ${categoryNames.join(", ")}`, modelInfo, actualModel, isUnstableAgent, - fallbackChain: configuredFallbackChain ?? requirement?.fallbackChain, + // Don't use hardcoded fallback chain when resolution was skipped (cold cache) + fallbackChain: configuredFallbackChain ?? (isModelResolutionSkipped ? undefined : requirement?.fallbackChain), } } diff --git a/src/tools/delegate-task/subagent-resolver.ts b/src/tools/delegate-task/subagent-resolver.ts index fe80af663..df6fe7378 100644 --- a/src/tools/delegate-task/subagent-resolver.ts +++ b/src/tools/delegate-task/subagent-resolver.ts @@ -125,12 +125,26 @@ Create the work plan directly - that's your job as the planning agent.`, systemDefaultModel: undefined, }) - if (resolution && !('skipped' in resolution)) { + const resolutionSkipped = resolution && 'skipped' in resolution + + if (resolution && !resolutionSkipped) { const normalized = normalizeModelFormat(resolution.model) if (normalized) { const variantToUse = agentOverride?.variant ?? resolution.variant categoryModel = variantToUse ? { ...normalized, variant: variantToUse } : normalized } + } else if (resolutionSkipped && agentOverride?.model) { + // Cold cache: resolution was skipped but user explicitly configured a model. + // Honor the user override directly — don't fall through to hardcoded fallback chain. + const normalized = normalizeModelFormat(agentOverride.model) + if (normalized) { + const variantToUse = agentOverride?.variant + categoryModel = variantToUse ? { ...normalized, variant: variantToUse } : normalized + log("[delegate-task] Cold cache: using explicit user override for subagent", { + agent: agentToUse, + model: agentOverride.model, + }) + } } const defaultProviderID = categoryModel?.providerID @@ -140,7 +154,9 @@ Create the work plan directly - that's your job as the planning agent.`, normalizedAgentFallbackModels, defaultProviderID, ) - fallbackChain = configuredFallbackChain ?? agentRequirement?.fallbackChain + // Don't assign hardcoded fallback chain when resolution was skipped (cold cache) + // — the chain may contain model IDs that don't exist in the provider yet. + fallbackChain = configuredFallbackChain ?? (resolutionSkipped ? undefined : agentRequirement?.fallbackChain) // Only promote fallback-only settings when resolution actually selected a fallback model. const resolvedFallbackEntry = (resolution && !('skipped' in resolution)) ? resolution.fallbackEntry : undefined