Merge pull request #954 from roshanasingh4/fix/946-openai-completions-trim

Fix model fallback crash on undefined provider/model (#946)
This commit is contained in:
Peter Steinberger
2026-01-15 16:59:19 +00:00
committed by GitHub
3 changed files with 36 additions and 6 deletions

View File

@@ -2,7 +2,7 @@
## 2026.1.15 (unreleased) ## 2026.1.15 (unreleased)
- TBD - Fix: guard model fallback against undefined provider/model values. (#954) — thanks @roshanasingh4.
## 2026.1.14-1 ## 2026.1.14-1

View File

@@ -213,6 +213,34 @@ describe("runWithModelFallback", () => {
expect(calls).toEqual([{ provider: "anthropic", model: "claude-opus-4-5" }]); expect(calls).toEqual([{ provider: "anthropic", model: "claude-opus-4-5" }]);
}); });
it("defaults provider/model when missing (regression #946)", async () => {
const cfg = makeCfg({
agents: {
defaults: {
model: {
primary: "openai/gpt-4.1-mini",
fallbacks: [],
},
},
},
});
const calls: Array<{ provider: string; model: string }> = [];
const result = await runWithModelFallback({
cfg,
provider: undefined as unknown as string,
model: undefined as unknown as string,
run: async (provider, model) => {
calls.push({ provider, model });
return "ok";
},
});
expect(result.result).toBe("ok");
expect(calls).toEqual([{ provider: "openai", model: "gpt-4.1-mini" }]);
});
it("falls back on missing API key errors", async () => { it("falls back on missing API key errors", async () => {
const cfg = makeCfg(); const cfg = makeCfg();
const run = vi const run = vi

View File

@@ -119,8 +119,6 @@ function resolveFallbackCandidates(params: {
/** Optional explicit fallbacks list; when provided (even empty), replaces agents.defaults.model.fallbacks. */ /** Optional explicit fallbacks list; when provided (even empty), replaces agents.defaults.model.fallbacks. */
fallbacksOverride?: string[]; fallbacksOverride?: string[];
}): ModelCandidate[] { }): ModelCandidate[] {
const provider = params.provider.trim() || DEFAULT_PROVIDER;
const model = params.model.trim() || DEFAULT_MODEL;
const primary = params.cfg const primary = params.cfg
? resolveConfiguredModelRef({ ? resolveConfiguredModelRef({
cfg: params.cfg, cfg: params.cfg,
@@ -128,11 +126,15 @@ function resolveFallbackCandidates(params: {
defaultModel: DEFAULT_MODEL, defaultModel: DEFAULT_MODEL,
}) })
: null; : null;
const defaultProvider = primary?.provider ?? DEFAULT_PROVIDER;
const defaultModel = primary?.model ?? DEFAULT_MODEL;
const provider = String(params.provider ?? "").trim() || defaultProvider;
const model = String(params.model ?? "").trim() || defaultModel;
const aliasIndex = buildModelAliasIndex({ const aliasIndex = buildModelAliasIndex({
cfg: params.cfg ?? {}, cfg: params.cfg ?? {},
defaultProvider: DEFAULT_PROVIDER, defaultProvider,
}); });
const allowlist = buildAllowedModelKeys(params.cfg, DEFAULT_PROVIDER); const allowlist = buildAllowedModelKeys(params.cfg, defaultProvider);
const seen = new Set<string>(); const seen = new Set<string>();
const candidates: ModelCandidate[] = []; const candidates: ModelCandidate[] = [];
@@ -160,7 +162,7 @@ function resolveFallbackCandidates(params: {
for (const raw of modelFallbacks) { for (const raw of modelFallbacks) {
const resolved = resolveModelRefFromString({ const resolved = resolveModelRefFromString({
raw: String(raw ?? ""), raw: String(raw ?? ""),
defaultProvider: DEFAULT_PROVIDER, defaultProvider,
aliasIndex, aliasIndex,
}); });
if (!resolved) continue; if (!resolved) continue;