Files
OmniRoute/tests/unit/omniroute-decision-header.test.ts
Bob.Hou c75e293a47 fix(api): thread X-OmniRoute-Fallback-Attempts through combo chat (#12339) (#13038)
Right call not to reuse the combo loop's `fallbackCount`: it only increments after a leg fails or is skipped, so the second target would still report 0 at dispatch. Stamping the ordered index (or round-robin offset) at the gate is the only place the number is actually known. This PR also carries the batch's file-size rebaseline, since it merges first and the ceiling has to cover every intermediate state.

---

Validated in one consolidated worktree cut from `release/v3.8.51`, boarded with the other 19 PRs of this batch. Two in-batch conflicts, both additive and resolved by keeping each side: the `ENVIRONMENT.md` table (#13035 + #13011) and the `chatHelpers.ts` import block (#12975 on the tip + #13017).

- `typecheck:core` clean; `check:dashboard-typecheck` OK (206 pre-existing, within baseline); `check:changelog-integrity` OK; `check:docs-counts` migrations ✓
- complexity 2816 / baseline 3218 and cognitive-complexity 1271 / baseline 1437 — both under baseline
- 531 of 532 focused assertions green across the batch's 46 test files
- `check-file-size` rebaselined for the batch's real growth (annotation `_rebaseline_2026_09_11_mergebatch_v3851_houminxi`, landed on #13038), attributed per PR

The single red is **not this batch**: `tests/unit/combo/quota-weighted-strategy.test.ts` → "A/B isolation: 7 hard-empty + 2 at 0.5% + 1 at 40%, floor=1" asserts an order between two connections of identical weight and flakes on the pure tip too — 2 failures in 4 runs at `origin/release/v3.8.51` with nothing from this batch applied.

⚠️ base-red inherited: #12732 — `Docs Gates`, `Merge integrity`, `No new ESLint warnings`, `Unit Tests fast-path` and `Fast Quality Gates` reproduce on the pure tip (provider count 356 vs the 358 the modules define, SKILL.md drift, and `open-sse/utils/stream.ts` at 3115 > frozen 3098, untouched here).

Thanks @HouMinXi — the live evidence on these (X500 logs, `storage.sqlite` state, real `/v1/models` probes, the 36-minute outage write-up) is what let a 20-PR batch be reviewed as a unit.
2026-09-11 19:27:33 -03:00

131 lines
4.3 KiB
TypeScript

import test from "node:test";
import assert from "node:assert/strict";
import { OMNIROUTE_RESPONSE_HEADERS } from "../../src/shared/constants/headers.ts";
import {
buildOmniRouteDecisionHeaderValue,
buildOmniRouteResponseMetaHeaders,
} from "../../src/domain/omnirouteResponseMeta.ts";
import { assembleStreamingResponseHeaders } from "../../open-sse/handlers/chatCore/streamingResponseHeaders.ts";
import { buildNonStreamingResponseHeaders } from "../../open-sse/handlers/chatCore/nonStreamingResponseHeaders.ts";
test("headers constant exposes the decision key", () => {
assert.equal(OMNIROUTE_RESPONSE_HEADERS.decision, "X-OmniRoute-Decision");
});
test("buildOmniRouteResponseMetaHeaders emits X-OmniRoute-Decision for a combo strategy", () => {
const headers = buildOmniRouteResponseMetaHeaders({
strategy: "priority",
provider: "openai",
model: "gpt-4o",
latencyMs: 42,
});
assert.equal(
headers["X-OmniRoute-Decision"],
"strategy=priority; provider=openai; latency_ms=42"
);
});
test("strategy: single (non-combo request) still emits the header", () => {
const headers = buildOmniRouteResponseMetaHeaders({
strategy: "single",
provider: "anthropic",
latencyMs: 10,
});
assert.equal(
headers["X-OmniRoute-Decision"],
"strategy=single; provider=anthropic; latency_ms=10"
);
});
test("omitted strategy AND provider -> header absent entirely", () => {
const headers = buildOmniRouteResponseMetaHeaders({ model: "gpt-4o" });
assert.equal("X-OmniRoute-Decision" in headers, false);
});
test("control characters in strategy are stripped, no header-injection / leak surface", () => {
const value = buildOmniRouteDecisionHeaderValue({
strategy: "prio\r\nrity",
provider: "openai",
latencyMs: 5,
});
assert.ok(value !== null);
assert.equal(/[\r\n]/.test(value as string), false);
assert.equal((value as string).includes("Error:"), false);
assert.equal((value as string).includes(" at /"), false);
});
test("assembleStreamingResponseHeaders includes X-OmniRoute-Decision with strategy=fusion", () => {
const providerHeaders = new Headers();
const headers = assembleStreamingResponseHeaders({
providerHeaders,
provider: "openai",
model: "gpt-4o",
pendingRequestId: "req-1",
comboStrategy: "fusion",
});
assert.equal(headers["X-OmniRoute-Decision"], "strategy=fusion; provider=openai; latency_ms=0");
});
test("buildNonStreamingResponseHeaders falls back to strategy=single when comboStrategy is null", () => {
const headers = buildNonStreamingResponseHeaders({
provider: "openai",
model: "gpt-4o",
startTime: Date.now(),
responseUsage: null,
estimatedCost: 0,
requestId: "req-2",
comboStrategy: null,
});
assert.match(
headers["X-OmniRoute-Decision"],
/^strategy=single; provider=openai; latency_ms=\d+$/
);
});
test("assembleStreamingResponseHeaders emits X-OmniRoute-Fallback-Attempts when count > 0", () => {
const headers = assembleStreamingResponseHeaders({
providerHeaders: new Headers(),
provider: "openai",
model: "gpt-4o",
pendingRequestId: "req-3",
comboStrategy: "priority",
fallbackAttempts: 2,
});
assert.equal(headers["X-OmniRoute-Fallback-Attempts"], "2");
});
test("buildNonStreamingResponseHeaders emits X-OmniRoute-Fallback-Attempts when count > 0", () => {
const headers = buildNonStreamingResponseHeaders({
provider: "openai",
model: "gpt-4o",
startTime: Date.now(),
responseUsage: null,
estimatedCost: 0,
requestId: "req-4",
comboStrategy: "priority",
fallbackAttempts: 1,
});
assert.equal(headers["X-OmniRoute-Fallback-Attempts"], "1");
});
test("builders omit X-OmniRoute-Fallback-Attempts when count is 0", () => {
const streaming = assembleStreamingResponseHeaders({
providerHeaders: new Headers(),
provider: "openai",
model: "gpt-4o",
pendingRequestId: "req-5",
fallbackAttempts: 0,
});
const nonStreaming = buildNonStreamingResponseHeaders({
provider: "openai",
model: "gpt-4o",
startTime: Date.now(),
responseUsage: null,
estimatedCost: 0,
requestId: "req-6",
fallbackAttempts: 0,
});
assert.equal(streaming["X-OmniRoute-Fallback-Attempts"], undefined);
assert.equal(nonStreaming["X-OmniRoute-Fallback-Attempts"], undefined);
});