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
25 changes: 20 additions & 5 deletions open-sse/translator/request/openai-responses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,28 @@ export function openaiResponsesToOpenAIRequest(
}
}

if (root.background) {
throw unsupportedFeature(
"Unsupported Responses API feature: background mode is not supported by omniroute"
const result: JsonRecord = { ...root };

// background: true requests a deferred Responses API run (the upstream
// returns 202 with response_id and the client polls GET /responses/<id>).
// OmniRoute is a forward proxy that streams responses synchronously —
// implementing the queue/poll contract would require persistence and a
// separate retrieval surface. Degrade: log a marker when true was
// actually requested (operators can observe clients that should be
// reconfigured) and strip the flag. Clients that set background=true
// opportunistically (Capy Captain Pro, Codex agents) work unchanged.
// Clients that strictly require the async contract still observe a
// completed response on the first poll and can adapt.
if (result.background === true) {
const providerStr = toString(credentialRecord.provider);
const modelStr = toString(model);
console.warn(
`BACKGROUND_DEGRADE provider=${providerStr || "unknown"} model=${modelStr || "unknown"}`
);
}

const result: JsonRecord = { ...root };
if (result.background !== undefined) {
delete result.background;
}
Comment on lines +99 to +101

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The implementation is missing the warning log (BACKGROUND_DEGRADE) mentioned in the PR description. This log is important for operators to identify clients that are requesting background mode and being degraded to synchronous execution.

Additionally, the current logic strips the background field even when it is false, which contradicts the "passthrough" behavior described in the PR summary for that case. While stripping it is generally safer for the downstream Chat API, the logging should be conditional on background: true.

Suggested change
if (result.background !== undefined) {
delete result.background;
}
if (result.background === true) {
console.warn(`BACKGROUND_DEGRADE provider=${credentialRecord.provider} model=${model}`);
}
if (result.background !== undefined) {
delete result.background;
}

const messages: JsonRecord[] = [];
result.messages = messages;

Expand Down
85 changes: 71 additions & 14 deletions tests/unit/translator-openai-responses-req.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ test("Responses -> Chat filters orphan tool outputs and supports role-based mess
});
});

test("Responses -> Chat rejects unsupported built-in tools and background mode", () => {
test("Responses -> Chat rejects unsupported built-in tools", () => {
assert.throws(
() =>
openaiResponsesToOpenAIRequest(
Expand All @@ -124,20 +124,77 @@ test("Responses -> Chat rejects unsupported built-in tools and background mode",
),
(error: any) => error.statusCode === 400 && error.errorType === "unsupported_feature"
);
});

assert.throws(
() =>
openaiResponsesToOpenAIRequest(
"gpt-4o",
{
input: [],
background: true,
},
false,
null
),
(error: any) => error.statusCode === 400 && error.errorType === "unsupported_feature"
);
test("Responses -> Chat strips background flag and degrades to synchronous execution", () => {
// Previously this threw 400 unsupported_feature. OmniRoute is a forward proxy
// and cannot host the deferred run + poll contract, so background=true is
// silently dropped and the request runs synchronously. Clients that set the
// flag opportunistically (Capy Captain Pro, Codex agents) work unchanged.
const warnLog: string[] = [];
const originalWarn = console.warn;
console.warn = (msg: unknown) => warnLog.push(String(msg));
try {
const result = openaiResponsesToOpenAIRequest(
"gpt-5.5",
{
input: [{ role: "user", content: [{ type: "input_text", text: "hi" }] }],
background: true,
},
true,
{ provider: "codex" }
);
const r = result as Record<string, unknown>;
assert.equal(r.background, undefined, "background flag must be stripped from output");
assert.ok(Array.isArray(r.messages), "translation must complete and produce messages");
assert.equal((r.messages as unknown[]).length, 1, "user message must be preserved");
assert.ok(
warnLog.some((m) => m.startsWith("BACKGROUND_DEGRADE provider=codex model=gpt-5.5")),
"BACKGROUND_DEGRADE warning log must be emitted when background=true"
);
} finally {
console.warn = originalWarn;
}
});

test("Responses -> Chat passes through when background flag is unset or false (no degrade log)", () => {
// Verifies the inverse of the degradation case: when background is absent or
// explicitly false, no warning should be emitted and the request body should
// not carry a residual background field. Guards against accidental log spam
// and confirms the degradation logic is conditional on background === true.
const warnLog: string[] = [];
const originalWarn = console.warn;
console.warn = (msg: unknown) => warnLog.push(String(msg));
try {
// Case 1: background unset
const r1 = openaiResponsesToOpenAIRequest(
"gpt-5.5",
{ input: [{ role: "user", content: [{ type: "input_text", text: "hi" }] }] },
true,
{ provider: "codex" }
) as Record<string, unknown>;
assert.equal(r1.background, undefined, "background must be absent on output (unset case)");

// Case 2: background explicitly false
const r2 = openaiResponsesToOpenAIRequest(
"gpt-5.5",
{
input: [{ role: "user", content: [{ type: "input_text", text: "hi" }] }],
background: false,
},
true,
{ provider: "codex" }
) as Record<string, unknown>;
assert.equal(r2.background, undefined, "background must be stripped on output (false case)");

assert.equal(
warnLog.filter((m) => m.startsWith("BACKGROUND_DEGRADE")).length,
0,
"BACKGROUND_DEGRADE must NOT be emitted for unset or false values"
);
} finally {
console.warn = originalWarn;
}
});
Comment on lines +129 to 198

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The PR description mentions two new unit cases, but only the background: true case was added in this patch. Please include a test case for background: false (or unset) to verify that it is handled correctly and does not trigger the degradation warning logic.


test("Chat -> Responses converts messages, tool calls, tool outputs, tools and pass-through params", () => {
Expand Down