mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-23 15:42:12 +03:00
Merged — locally validated (61/61 focused tests: early-stream-keepalive, chat-body-admission, responses-parse-once-4041, responses-route-early-keepalive-wiring; file-size/changelog gates clean, merges conflict-free against the current release tip). Good catch replacing the synthetic reasoning placeholder with a real response.in_progress bookkeeping event — keeps event-level watchdogs (Codex etc.) happy without any replayable fake reasoning content. Thanks!
154 lines
5.2 KiB
TypeScript
154 lines
5.2 KiB
TypeScript
import test, { after } 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 dataDir = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-responses-parse-once-"));
|
|
process.env.DATA_DIR = dataDir;
|
|
after(() => fs.rmSync(dataDir, { recursive: true, force: true }));
|
|
|
|
// #4041: AI routes must parse each JSON body at most once and thread the parsed value
|
|
// through model resolution and handleChat. /v1/responses now parses after raw-body admission;
|
|
// withInjectionGuard retains the same preParsedBody contract for routes that still wrap it.
|
|
|
|
// ─── Part A: withInjectionGuard threads the parsed body ──────────────────────
|
|
|
|
const { withInjectionGuard } = await import("../../src/middleware/promptInjectionGuard.ts");
|
|
|
|
test("#4041 withInjectionGuard passes the parsed body as 3rd arg to the inner handler", async () => {
|
|
let receivedPreParsed: unknown = undefined;
|
|
|
|
const innerHandler = async (_request: Request, _context: unknown, preParsedBody: unknown) => {
|
|
receivedPreParsed = preParsedBody;
|
|
return new Response("ok");
|
|
};
|
|
|
|
const wrapped = withInjectionGuard(innerHandler, { mode: "warn" });
|
|
const payload = { messages: [{ role: "user", content: "Hello world" }] };
|
|
|
|
const request = new Request("http://localhost/v1/responses", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify(payload),
|
|
});
|
|
|
|
await wrapped(request, {});
|
|
|
|
assert.deepEqual(
|
|
receivedPreParsed,
|
|
payload,
|
|
"withInjectionGuard must thread the body it already parsed into the inner handler as 3rd arg"
|
|
);
|
|
});
|
|
|
|
test("#4041 withInjectionGuard passes null as 3rd arg when body cannot be parsed", async () => {
|
|
let receivedPreParsed: unknown = "sentinel";
|
|
|
|
const innerHandler = async (_request: Request, _context: unknown, preParsedBody: unknown) => {
|
|
receivedPreParsed = preParsedBody;
|
|
return new Response("ok");
|
|
};
|
|
|
|
const wrapped = withInjectionGuard(innerHandler, { mode: "warn" });
|
|
|
|
// A GET request skips the guard entirely — 3rd arg is NOT forwarded (handler gets 2 args)
|
|
// A POST with non-JSON body: body is null, still calls handler with null as 3rd arg
|
|
const request = new Request("http://localhost/v1/responses", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "text/plain" },
|
|
body: "not json",
|
|
});
|
|
|
|
await wrapped(request, {});
|
|
|
|
assert.equal(
|
|
receivedPreParsed,
|
|
null,
|
|
"withInjectionGuard must pass null (not undefined) when body could not be parsed"
|
|
);
|
|
});
|
|
|
|
// ─── Part B: withCodexPreferredModel reuses pre-parsed body ──────────────────
|
|
|
|
test("#4041 withCodexPreferredModel accepts a pre-parsed body and avoids re-cloning the request", async () => {
|
|
const { withCodexPreferredModel } = await import("../../src/app/api/v1/responses/route.ts");
|
|
const body = { model: "openai/gpt-4o", input: "hello" };
|
|
const request = new Request("http://localhost/v1/responses", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify(body),
|
|
});
|
|
let cloneCount = 0;
|
|
const originalClone = request.clone.bind(request);
|
|
Object.defineProperty(request, "clone", {
|
|
value: () => {
|
|
cloneCount += 1;
|
|
return originalClone();
|
|
},
|
|
});
|
|
|
|
const result = await withCodexPreferredModel(request, body);
|
|
|
|
assert.equal(cloneCount, 0);
|
|
assert.equal(result.body, body);
|
|
});
|
|
|
|
// ─── Part C: wrapped routes parse once before invoking their handler ─────────
|
|
|
|
test("#4041 the body is parsed AT MOST ONCE through withInjectionGuard + inner handler", async () => {
|
|
let jsonParseCount = 0;
|
|
|
|
// Build a request where we count every .json() call (including on clones)
|
|
const payload = { model: "gpt-4o", messages: [{ role: "user", content: "hi" }] };
|
|
const bodyStr = JSON.stringify(payload);
|
|
|
|
// We create a real Request but intercept .clone() to return a spy-wrapped clone
|
|
const origRequest = new Request("http://localhost/v1/responses", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: bodyStr,
|
|
});
|
|
|
|
function wrapWithJsonSpy(req: Request): Request {
|
|
const origJson = req.json.bind(req);
|
|
const origClone = req.clone.bind(req);
|
|
Object.defineProperty(req, "json", {
|
|
value: async () => {
|
|
jsonParseCount++;
|
|
return origJson();
|
|
},
|
|
writable: true,
|
|
});
|
|
Object.defineProperty(req, "clone", {
|
|
value: () => {
|
|
const cloned = origClone();
|
|
return wrapWithJsonSpy(cloned);
|
|
},
|
|
writable: true,
|
|
});
|
|
return req;
|
|
}
|
|
|
|
const spyRequest = wrapWithJsonSpy(origRequest);
|
|
|
|
let preParsedBodyReceived: unknown = undefined;
|
|
const innerHandler = async (_req: Request, _ctx: unknown, preParsedBody: unknown) => {
|
|
preParsedBodyReceived = preParsedBody;
|
|
return new Response("ok");
|
|
};
|
|
|
|
const wrapped = withInjectionGuard(innerHandler, { mode: "warn" });
|
|
await wrapped(spyRequest, {});
|
|
|
|
assert.ok(
|
|
jsonParseCount <= 1,
|
|
`Expected at most 1 JSON parse through withInjectionGuard, got ${jsonParseCount}`
|
|
);
|
|
assert.deepEqual(
|
|
preParsedBodyReceived,
|
|
payload,
|
|
"inner handler must receive the pre-parsed body as 3rd arg"
|
|
);
|
|
});
|