Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions config/quality/file-size-baseline.json
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@
"src/shared/validation/schemas.ts": 2523,
"_rebaseline_2026_06_28_5275_correlation_id_extract": "Extraction of the safe CorrelationId subset of #5275 (hartmark) — request correlation id stored in call_logs (migration 109) and returned via the X-Correlation-Id response header, WITHOUT the combo/resilience or build/lazy-loading changes (those stay in #5275). Own growth: callLogs.ts 975->985 (correlation_id column on CallLogSummaryRow + read/map), usageHistory.ts 983->988 (correlationId metadata normalize), chat.ts 1575->1632 (withCorrelationId response wiring + combo-failure log carrying correlationId), chatHelpers.ts new 811 (withCorrelationId helper + reqId threading; was 791<cap pre-feature). Cohesive request/logging chokepoint wiring; structural shrink of chat.ts tracked in #3501.",
"src/sse/handlers/chat.ts": 1763,
"src/sse/handlers/chatHelpers.ts": 866,
"src/sse/handlers/chatHelpers.ts": 876,
"src/sse/services/auth.ts": 2448,
"open-sse/executors/default.ts": 877,
"open-sse/translator/request/openai-responses.ts": 902,
Expand Down Expand Up @@ -385,5 +385,6 @@
"_rebaseline_2026_07_07_6523_chirag_cooldown_body": "PR #6523 (@chirag127, #6460) own growth: chatHelpers.ts 860->866 (+6 = retryAfterAt/credentialsCoolingCount fields on modelCooldownResponse) and auth.ts 2447->2448 (+1 = connectionsCount threaded through no-credentials fallback). Owner-approved rebaseline (file-size cap for contributor PR). Frozen (cannot grow further); release captain's rebaseline-at-release supersedes.",
"_rebaseline_2026_07_07_6526_chirag_modal_1080p": "PR #6526 (@chirag127, #6265): AddApiKeyModal.tsx ->961 (1080p sizing). Owner-approved. Frozen.",
"_rebaseline_2026_07_07_6515_chirag": "PR #6515 (@chirag127) own growth: src/sse/handlers/chat.ts ->1763. Owner-approved rebaseline. Frozen.",
"_rebaseline_2026_07_07_6534_chirag": "PR #6534 (@chirag127) own growth: open-sse/services/compression/strategySelector.ts ->1025. Owner-approved rebaseline. Frozen."
"_rebaseline_2026_07_07_6534_chirag": "PR #6534 (@chirag127) own growth: open-sse/services/compression/strategySelector.ts ->1025. Owner-approved rebaseline. Frozen.",
"_rebaseline_2026_07_07_6546_chirag": "PR #6546 (@chirag127) own growth: src/sse/handlers/chatHelpers.ts ->876. Owner-approved rebaseline. Frozen."
}
12 changes: 11 additions & 1 deletion src/sse/handlers/chatHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,10 +204,20 @@ export async function resolveModelOrError(

try {
const virtualCombo = await createBuiltinAutoCombo(modelStr, suffix);
const poolSize = virtualCombo.candidatePool?.length || 0;
log.info(
"AUTO",
`"auto" provider → built-in virtual combo "${modelStr}" (${virtualCombo.candidatePool?.length || 0} candidates)`
`"auto" provider → built-in virtual combo "${modelStr}" (${poolSize} candidates)`
);
// #6458: fail fast instead of leaking a silent 15s upstream timeout when
// the category/tier filter (e.g. auto/coding:pro, auto/reasoning) matches
// zero connected candidates. An empty virtual combo has no targets to
// dispatch to, so downstream combo routing stalls on an empty set.
if (poolSize === 0) {
const msg = `No connected providers match '${modelStr}'. Connect a provider whose models satisfy this category/tier, or use a different auto combo.`;
log.warn("AUTO", msg, { model: modelStr });
return { error: errorResponse(HTTP_STATUS.SERVICE_UNAVAILABLE, msg) };
}
return { combo: virtualCombo, provider: "auto", model: suffix };
} catch (err) {
log.warn("CHAT", `Failed to create built-in auto combo "${modelStr}"`, { err });
Expand Down
31 changes: 31 additions & 0 deletions tests/unit/auto-empty-pool-fastfail-6458.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* #6458 — an `auto/*` category/tier combo that matches ZERO connected
* candidates must fail fast with a clear 503, instead of building an empty
* virtual combo whose downstream routing stalls on a silent ~15s upstream
* timeout. Regression guard (Rule #18).
*/
import test from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";

const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-auto-empty-pool-"));
process.env.DATA_DIR = TEST_DATA_DIR;

const core = await import("../../src/lib/db/core.ts");
const { resolveModelOrError } = await import("../../src/sse/handlers/chatHelpers.ts");

test.beforeEach(() => core.resetDbInstance());
test.after(() => {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});

test("#6458 empty auto-combo pool returns a 503 instead of an empty combo", async () => {
// No provider connections seeded → any auto category resolves to an empty pool.
const result = await resolveModelOrError("auto/coding:pro", { messages: [{ role: "user", content: "hi" }] });
assert.ok(result.error, "expected an error result, not a combo");
assert.equal(result.error.status, 503, "empty auto pool must fail fast with 503");
assert.equal(result.combo, undefined, "must not return a combo for an empty pool");
});
Loading