refactor(agents): centralize model fallback resolution

This commit is contained in:
Peter Steinberger
2026-02-25 04:32:25 +00:00
parent dd6ad0da8c
commit 9beec48e9c
7 changed files with 205 additions and 61 deletions

View File

@@ -63,7 +63,8 @@ function shouldRethrowAbort(err: unknown): boolean {
function createModelCandidateCollector(allowlist: Set<string> | null | undefined): {
candidates: ModelCandidate[];
addCandidate: (candidate: ModelCandidate, enforceAllowlist: boolean) => void;
addExplicitCandidate: (candidate: ModelCandidate) => void;
addAllowlistedCandidate: (candidate: ModelCandidate) => void;
} {
const seen = new Set<string>();
const candidates: ModelCandidate[] = [];
@@ -83,7 +84,14 @@ function createModelCandidateCollector(allowlist: Set<string> | null | undefined
candidates.push(candidate);
};
return { candidates, addCandidate };
const addExplicitCandidate = (candidate: ModelCandidate) => {
addCandidate(candidate, false);
};
const addAllowlistedCandidate = (candidate: ModelCandidate) => {
addCandidate(candidate, true);
};
return { candidates, addExplicitCandidate, addAllowlistedCandidate };
}
type ModelFallbackErrorHandler = (attempt: {
@@ -138,9 +146,10 @@ function resolveImageFallbackCandidates(params: {
cfg: params.cfg,
defaultProvider: params.defaultProvider,
});
const { candidates, addCandidate } = createModelCandidateCollector(allowlist);
const { candidates, addExplicitCandidate, addAllowlistedCandidate } =
createModelCandidateCollector(allowlist);
const addRaw = (raw: string, enforceAllowlist: boolean) => {
const addRaw = (raw: string, opts?: { allowlist?: boolean }) => {
const resolved = resolveModelRefFromString({
raw: String(raw ?? ""),
defaultProvider: params.defaultProvider,
@@ -149,15 +158,19 @@ function resolveImageFallbackCandidates(params: {
if (!resolved) {
return;
}
addCandidate(resolved.ref, enforceAllowlist);
if (opts?.allowlist) {
addAllowlistedCandidate(resolved.ref);
return;
}
addExplicitCandidate(resolved.ref);
};
if (params.modelOverride?.trim()) {
addRaw(params.modelOverride, false);
addRaw(params.modelOverride);
} else {
const primary = resolveAgentModelPrimaryValue(params.cfg?.agents?.defaults?.imageModel);
if (primary?.trim()) {
addRaw(primary, false);
addRaw(primary);
}
}
@@ -166,7 +179,7 @@ function resolveImageFallbackCandidates(params: {
for (const raw of imageFallbacks) {
// Explicitly configured image fallbacks should remain reachable even when a
// model allowlist is present.
addRaw(raw, false);
addRaw(raw);
}
return candidates;
@@ -200,9 +213,9 @@ function resolveFallbackCandidates(params: {
cfg: params.cfg,
defaultProvider,
});
const { candidates, addCandidate } = createModelCandidateCollector(allowlist);
const { candidates, addExplicitCandidate } = createModelCandidateCollector(allowlist);
addCandidate(normalizedPrimary, false);
addExplicitCandidate(normalizedPrimary);
const modelFallbacks = (() => {
if (params.fallbacksOverride !== undefined) {
@@ -239,11 +252,11 @@ function resolveFallbackCandidates(params: {
}
// Fallbacks are explicit user intent; do not silently filter them by the
// model allowlist.
addCandidate(resolved.ref, false);
addExplicitCandidate(resolved.ref);
}
if (params.fallbacksOverride === undefined && primary?.provider && primary.model) {
addCandidate({ provider: primary.provider, model: primary.model }, false);
addExplicitCandidate({ provider: primary.provider, model: primary.model });
}
return candidates;