fix(model-resolution): honor user config overrides on cold cache

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
This commit is contained in:
YeonGyu-Kim
2026-03-26 16:54:04 +09:00
parent dd85d1451a
commit a8ec92748c
3 changed files with 26 additions and 5 deletions

View File

@@ -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

View File

@@ -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),
}
}

View File

@@ -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