fix(headroom): skip unsafe responses tool history (#2132)

Guard openai-responses compression: skip Headroom when body.input
contains non-message items (function_call, function_call_output,
reasoning) to preserve the Responses contract instead of collapsing
them into chat messages.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Sutarto Jordan Chrisfivo
2026-06-29 15:58:38 +07:00
committed by decolua
parent 749c2e3f9c
commit 373850ee36
2 changed files with 69 additions and 0 deletions

View File

@@ -73,6 +73,14 @@ function maskEndpoint(endpoint) {
}
}
function hasUnsafeResponsesInputForCompression(body) {
if (!Array.isArray(body?.input)) return false;
return body.input.some((item) => {
if (!item || typeof item !== "object" || Array.isArray(item)) return false;
return typeof item.type === "string" && item.type !== "message";
});
}
// POST messages to Headroom /v1/compress; returns compressed messages + stats or null.
async function callCompress(url, messages, model, timeoutMs, compressUserMessages, diagnostics) {
const endpoint = buildCompressEndpoint(url);
@@ -143,6 +151,10 @@ export async function compressWithHeadroom(body, { enabled, url, model, format,
// messages. Translate input -> OpenAI -> compress -> translate back to input so
// body.input keeps the Responses contract (the proxy only understands OpenAI). (#1998)
if (format === "openai-responses") {
if (hasUnsafeResponsesInputForCompression(body)) {
setDiagnostic(diagnostics, "skipped: openai-responses tool/reasoning input is not safe to compress");
return null;
}
const oai = openaiResponsesToOpenAIRequest(model, body, false);
if (!Array.isArray(oai?.messages)) return null;
const data = await callCompress(url, oai.messages, model, timeoutMs, compressUserMessages, diagnostics || {});