Bypass semantic cache in combo live tests

This commit is contained in:
R.D.
2026-03-29 14:21:39 -04:00
parent af338d447b
commit 40862f26e6
4 changed files with 109 additions and 1 deletions

View File

@@ -1,3 +1,4 @@
import { randomUUID } from "node:crypto";
import { NextResponse } from "next/server";
import { buildComboTestRequestBody, extractComboTestResponseText } from "@/lib/combos/testHealth";
import { getComboByName } from "@/lib/localDb";
@@ -67,6 +68,10 @@ export async function POST(request) {
// Internal dashboard tests still use the normal /v1 pipeline but
// bypass REQUIRE_API_KEY so admins can test with local session auth.
"X-Internal-Test": "combo-health-check",
// Force a fresh execution path so combo tests cannot be satisfied by
// OmniRoute's semantic cache or other request reuse layers.
"X-OmniRoute-No-Cache": "true",
"X-Request-Id": `combo-test-${randomUUID()}`,
},
body: JSON.stringify(testBody),
signal: controller.signal,

View File

@@ -29,6 +29,25 @@ function toNumber(value: unknown, fallback = 0): number {
return fallback;
}
function getHeaderValue(
headers: { get?: (name: string) => string | null } | Record<string, unknown> | null | undefined,
name: string
): string | null {
if (!headers) return null;
if (typeof headers.get === "function") {
return headers.get(name);
}
const needle = name.toLowerCase();
for (const [key, value] of Object.entries(headers)) {
if (key.toLowerCase() !== needle) continue;
return typeof value === "string" ? value : null;
}
return null;
}
// ─── Singleton ─────────────────
let memoryCache: LRUCache | null = null;
@@ -309,7 +328,9 @@ export function getCacheStats() {
* Only non-streaming, deterministic (temperature=0) requests.
*/
export function isCacheable(body, headers) {
if (headers?.get?.("x-omniroute-no-cache") === "true") return false;
if ((getHeaderValue(headers, "x-omniroute-no-cache") || "").toLowerCase() === "true") {
return false;
}
if (body.stream !== false) return false;
if ((body.temperature ?? 0) !== 0) return false;
return true;

View File

@@ -10,6 +10,11 @@ process.env.DATA_DIR = TEST_DATA_DIR;
const core = await import("../../src/lib/db/core.ts");
const providersDb = await import("../../src/lib/db/providers.ts");
const chatRoute = await import("../../src/app/api/v1/chat/completions/route.ts");
const {
generateSignature,
invalidateBySignature,
setCachedResponse,
} = await import("../../src/lib/semanticCache.ts");
const {
clearModelUnavailability,
resetAllAvailability,
@@ -43,6 +48,17 @@ async function seedSuppressedConnection() {
});
}
async function seedHealthyConnection() {
return providersDb.createProviderConnection({
provider: "openai",
authType: "apikey",
name: "openai-cache-test",
apiKey: "sk-cache-test",
isActive: true,
testStatus: "active",
});
}
function makeRequest(extraHeaders = {}) {
return new Request("http://localhost/v1/chat/completions", {
method: "POST",
@@ -126,3 +142,67 @@ test("combo live test bypasses local cooldown and breaker state to perform a rea
const updated = await providersDb.getProviderConnectionById(created.id);
assert.equal(updated.testStatus, "active");
});
test("combo live test bypasses semantic cache and forces a fresh upstream request", async () => {
await seedHealthyConnection();
const signature = generateSignature(
"gpt-4o-mini",
[{ role: "user", content: "Reply with OK only." }],
0,
1
);
setCachedResponse(signature, "gpt-4o-mini", {
id: "chatcmpl-cached",
choices: [
{
message: {
role: "assistant",
content: "CACHED",
},
},
],
});
const fetchCalls = [];
globalThis.fetch = async (url, init = {}) => {
fetchCalls.push({ url: String(url), init });
return Response.json({
id: "chatcmpl-live",
choices: [
{
message: {
role: "assistant",
content: "LIVE",
},
},
],
});
};
try {
const cachedResponse = await chatRoute.POST(makeRequest());
const cachedBody = await cachedResponse.json();
assert.equal(cachedResponse.status, 200);
assert.equal(fetchCalls.length, 0);
assert.equal(cachedBody.choices[0].message.content, "CACHED");
const liveResponse = await chatRoute.POST(
makeRequest({
"X-Internal-Test": "combo-health-check",
"X-OmniRoute-No-Cache": "true",
"X-Request-Id": "combo-test-cache-bypass",
})
);
const liveBody = await liveResponse.json();
assert.equal(liveResponse.status, 200);
assert.equal(fetchCalls.length, 1);
assert.match(fetchCalls[0].url, /\/chat\/completions$/);
assert.equal(liveBody.choices[0].message.content, "LIVE");
} finally {
invalidateBySignature(signature);
}
});

View File

@@ -82,6 +82,8 @@ test("combo test route marks a model healthy only when it returns assistant text
assert.equal(fetchCalls.length, 1);
assert.equal(fetchCalls[0].url, "http://localhost/v1/chat/completions");
assert.equal(fetchCalls[0].init.headers["X-Internal-Test"], "combo-health-check");
assert.equal(fetchCalls[0].init.headers["X-OmniRoute-No-Cache"], "true");
assert.match(fetchCalls[0].init.headers["X-Request-Id"], /^combo-test-/);
assert.equal(forwardedBody.model, "openrouter/openai/gpt-5.4");
assert.equal(forwardedBody.messages[0].content, "Reply with OK only.");
assert.equal(body.resolvedBy, "openrouter/openai/gpt-5.4");