fix(agent): consider the full fallback pool within the request deadline

This commit is contained in:
134 2026-10-21 10:00:23 +08:00
parent bd27401b6c
commit e3a8f0e0a1
2 changed files with 6 additions and 5 deletions

View File

@ -67,11 +67,9 @@ export function createAgentModelFailover(entries: AgentModelEntry[], circuit: Ag
const totalSignal = signal ? AbortSignal.any([signal, deadline]) : deadline;
const ordered = [...entries].sort((a, b) => Number(b.model.id === preferred) - Number(a.model.id === preferred));
let last: unknown;
let attempts = 0;
for (const entry of ordered) {
totalSignal.throwIfAborted();
if (await circuit.isPaused(entry)) continue;
if (attempts++ >= 4) break;
const attemptSignal = AbortSignal.any([totalSignal, AbortSignal.timeout(AGENT_MODEL_ATTEMPT_MS)]);
try {
const result = await execute(entry, attemptSignal);

View File

@ -54,11 +54,14 @@ test("invalid input, content policy and cancellation neither quarantine nor retr
assert.equal(s.faults.size, 0);
});
test("multiple failed backups are skipped; no model is tried twice and attempts are bounded", async () => {
test("every eligible backup is considered once; a fixed small retry count cannot strand a healthy later model", async () => {
const s = store(); const calls: string[] = [];
await assert.rejects(createAgentModelFailover(["a", "b", "c", "d", "e"].map(id => entry(id)), s.circuit)(async e => { calls.push(e.model.id); throw Object.assign(new Error("busy"), { status: 503 }); }));
assert.deepEqual(calls, ["a", "b", "c", "d"]);
assert.equal(s.faults.size, 4);
assert.deepEqual(calls, ["a", "b", "c", "d", "e"]);
assert.equal(s.faults.size, 5);
calls.length = 0;
const result = await createAgentModelFailover(["a", "b", "c", "d", "e", "healthy"].map(id => entry(id)), s.circuit)(async e => { calls.push(e.model.id); return "ok"; });
assert.equal(result, "ok"); assert.deepEqual(calls, ["healthy"]);
});
test("late success cannot clear a fault recorded by another in-flight request", async () => {