mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-13 18:32:12 +03:00
stripStore() now forces store=false for stateless OpenAI-compatible Responses-API targets unless the connection explicitly opts in via providerSpecificData.openaiStoreEnabled, instead of only handling the openai/agentrouter cases — a client-supplied store value previously passed through untouched to backends that don't actually persist responses server-side. Closes #11826. Thanks!
This commit is contained in:
@@ -265,7 +265,7 @@ export function orderHeaders(
|
||||
* Apply a CLI fingerprint to headers and body.
|
||||
* Returns { headers, bodyString } with the correct ordering.
|
||||
*/
|
||||
function stripInternalBodyFields(body: unknown): unknown {
|
||||
export function stripInternalBodyFields(body: unknown): unknown {
|
||||
if (!body || typeof body !== "object" || Array.isArray(body)) return body;
|
||||
|
||||
const record = body as Record<string, unknown>;
|
||||
|
||||
@@ -30,7 +30,7 @@ import {
|
||||
addParamToBlocklist,
|
||||
isAutoLearnGloballyEnabled,
|
||||
} from "@/lib/db/paramFilters";
|
||||
import { applyFingerprint, isCliCompatEnabled } from "../config/cliFingerprints.ts";
|
||||
import { applyFingerprint, isCliCompatEnabled, stripInternalBodyFields } from "../config/cliFingerprints.ts";
|
||||
import { supportsClaudeMaxEffort, supportsXHighEffort } from "../config/providerModels.ts";
|
||||
import { getThinkingBudgetConfig, ThinkingMode } from "../services/thinkingBudget.ts";
|
||||
import {
|
||||
@@ -582,6 +582,8 @@ export class BaseExecutor {
|
||||
if (cloned[key] === "") delete cloned[key];
|
||||
}
|
||||
|
||||
stripInternalBodyFields(cloned);
|
||||
|
||||
return cloned;
|
||||
}
|
||||
|
||||
@@ -1393,6 +1395,7 @@ export class BaseExecutor {
|
||||
);
|
||||
}
|
||||
|
||||
stripInternalBodyFields(transformedBody);
|
||||
let bodyString = JSON.stringify(transformedBody);
|
||||
|
||||
const shouldFingerprint =
|
||||
|
||||
@@ -2808,7 +2808,12 @@ export async function handleChatCore({
|
||||
log?.debug?.("PARAMS", `Renamed max_completion_tokens to max_tokens for ${model}`);
|
||||
}
|
||||
|
||||
stripStore(translatedBody, provider, targetFormat);
|
||||
stripStore(
|
||||
translatedBody,
|
||||
provider,
|
||||
targetFormat,
|
||||
credentials?.providerSpecificData as Record<string, unknown> | null | undefined
|
||||
);
|
||||
|
||||
// Chat clients may send stream_options.include_usage, but OpenAI Responses
|
||||
// upstreams (including Azure AI Foundry /responses) reject stream_options.
|
||||
|
||||
@@ -26,8 +26,21 @@ export function usesClaudeBridge(
|
||||
export function stripStore(
|
||||
body: Record<string, unknown>,
|
||||
provider: string,
|
||||
targetFormat: string
|
||||
targetFormat: string,
|
||||
providerSpecificData?: unknown
|
||||
): void {
|
||||
if (provider.startsWith("openai-compatible-") && targetFormat === FORMATS.OPENAI_RESPONSES) {
|
||||
const psd =
|
||||
providerSpecificData && typeof providerSpecificData === "object"
|
||||
? (providerSpecificData as Record<string, unknown>)
|
||||
: undefined;
|
||||
if (psd?.openaiStoreEnabled === true) {
|
||||
return;
|
||||
}
|
||||
body.store = false;
|
||||
return;
|
||||
}
|
||||
|
||||
const supportsStore =
|
||||
provider === "openai" ||
|
||||
(provider === "agentrouter" && targetFormat === FORMATS.OPENAI_RESPONSES);
|
||||
|
||||
120
tests/unit/strip-store-responses.test.ts
Normal file
120
tests/unit/strip-store-responses.test.ts
Normal file
@@ -0,0 +1,120 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { createServer } from "node:http";
|
||||
import test from "node:test";
|
||||
|
||||
import { DefaultExecutor } from "../../open-sse/executors/default.ts";
|
||||
import { stripStore } from "../../open-sse/handlers/chatCore/agentRouterProtocol.ts";
|
||||
import { FORMATS } from "../../open-sse/translator/formats.ts";
|
||||
|
||||
const COMPATIBLE_PROVIDER = "openai-compatible-responses-test";
|
||||
|
||||
test("stripStore forces store=false for stateless OpenAI-compatible Responses requests", () => {
|
||||
for (const initialStore of [undefined, false, true]) {
|
||||
const body: Record<string, unknown> = {};
|
||||
if (initialStore !== undefined) body.store = initialStore;
|
||||
|
||||
stripStore(body, COMPATIBLE_PROVIDER, FORMATS.OPENAI_RESPONSES, {});
|
||||
|
||||
assert.equal(body.store, false);
|
||||
}
|
||||
});
|
||||
|
||||
test("stripStore preserves client store values for opted-in OpenAI-compatible Responses requests", () => {
|
||||
for (const initialStore of [false, true]) {
|
||||
const body: Record<string, unknown> = { store: initialStore };
|
||||
|
||||
stripStore(body, COMPATIBLE_PROVIDER, FORMATS.OPENAI_RESPONSES, {
|
||||
openaiStoreEnabled: true,
|
||||
});
|
||||
|
||||
assert.equal(body.store, initialStore);
|
||||
}
|
||||
|
||||
const omitted: Record<string, unknown> = {};
|
||||
stripStore(omitted, COMPATIBLE_PROVIDER, FORMATS.OPENAI_RESPONSES, {
|
||||
openaiStoreEnabled: true,
|
||||
});
|
||||
assert.equal("store" in omitted, false);
|
||||
});
|
||||
|
||||
test("stripStore keeps existing OpenAI and AgentRouter behavior", () => {
|
||||
const cases = [
|
||||
{ provider: "openai", targetFormat: FORMATS.OPENAI, expected: true },
|
||||
{ provider: "openai", targetFormat: FORMATS.OPENAI_RESPONSES, expected: true },
|
||||
{ provider: "agentrouter", targetFormat: FORMATS.OPENAI_RESPONSES, expected: true },
|
||||
{ provider: "agentrouter", targetFormat: FORMATS.OPENAI, expected: false },
|
||||
];
|
||||
|
||||
for (const { provider, targetFormat, expected } of cases) {
|
||||
const body: Record<string, unknown> = { store: true };
|
||||
stripStore(body, provider, targetFormat, {});
|
||||
assert.equal("store" in body, expected, `${provider}/${targetFormat}`);
|
||||
}
|
||||
});
|
||||
|
||||
test("stripStore removes store outside OpenAI-compatible Responses targets", () => {
|
||||
const cases = [
|
||||
{ provider: COMPATIBLE_PROVIDER, targetFormat: FORMATS.OPENAI },
|
||||
{ provider: "anthropic", targetFormat: FORMATS.CLAUDE },
|
||||
];
|
||||
|
||||
for (const { provider, targetFormat } of cases) {
|
||||
const body: Record<string, unknown> = { store: false };
|
||||
stripStore(body, provider, targetFormat, { openaiStoreEnabled: true });
|
||||
assert.equal("store" in body, false, `${provider}/${targetFormat}`);
|
||||
}
|
||||
});
|
||||
|
||||
test("DefaultExecutor never serializes native passthrough markers upstream", async () => {
|
||||
let capturedBody: Record<string, unknown> | null = null;
|
||||
const server = createServer((request, response) => {
|
||||
let rawBody = "";
|
||||
request.setEncoding("utf8");
|
||||
request.on("data", (chunk) => {
|
||||
rawBody += chunk;
|
||||
});
|
||||
request.on("end", () => {
|
||||
capturedBody = JSON.parse(rawBody);
|
||||
response.writeHead(200, { "Content-Type": "application/json" });
|
||||
response.end(JSON.stringify({ id: "resp_test", object: "response", output: [] }));
|
||||
});
|
||||
});
|
||||
await new Promise<void>((resolve) => server.listen(0, "127.0.0.1", resolve));
|
||||
const address = server.address();
|
||||
assert.ok(address && typeof address !== "string");
|
||||
|
||||
try {
|
||||
const executor = new DefaultExecutor(COMPATIBLE_PROVIDER);
|
||||
await executor.execute({
|
||||
model: "gpt-5.6-test",
|
||||
body: {
|
||||
model: "gpt-5.6-test",
|
||||
input: "hi",
|
||||
store: false,
|
||||
_nativeOpenAICompatibleResponsesPassthrough: true,
|
||||
_nativeCodexPassthrough: true,
|
||||
_nativeXaiResponsesPassthrough: true,
|
||||
_omnirouteResponsesStore: false,
|
||||
},
|
||||
stream: false,
|
||||
credentials: {
|
||||
apiKey: "test-key",
|
||||
providerSpecificData: {
|
||||
apiType: "responses",
|
||||
baseUrl: `http://127.0.0.1:${address.port}/v1`,
|
||||
},
|
||||
},
|
||||
});
|
||||
} finally {
|
||||
await new Promise<void>((resolve, reject) =>
|
||||
server.close((error) => (error ? reject(error) : resolve()))
|
||||
);
|
||||
}
|
||||
|
||||
assert.ok(capturedBody);
|
||||
assert.equal(capturedBody.store, false);
|
||||
assert.equal(capturedBody._nativeOpenAICompatibleResponsesPassthrough, undefined);
|
||||
assert.equal(capturedBody._nativeCodexPassthrough, undefined);
|
||||
assert.equal(capturedBody._nativeXaiResponsesPassthrough, undefined);
|
||||
assert.equal(capturedBody._omnirouteResponsesStore, undefined);
|
||||
});
|
||||
Reference in New Issue
Block a user