mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-26 09:52:11 +03:00
fix(translator): set status:completed on Responses input items to satisfy strict upstream validators (#8083) (#8507)
Co-authored-by: ikelvingo <im.kelvinwong@gmail.com>
This commit is contained in:
committed by
GitHub
parent
7a8f9156da
commit
e0aef4deb9
1
changelog.d/fixes/8083-responses-input-items-status.md
Normal file
1
changelog.d/fixes/8083-responses-input-items-status.md
Normal file
@@ -0,0 +1 @@
|
||||
- fix(translator): set `status: "completed"` on translated OpenAI Responses `input` items so strict Responses-compatible upstreams stop rejecting them with 400 MissingParameter input.status (#8083)
|
||||
@@ -120,6 +120,7 @@ export function openaiToOpenAIResponsesRequest(
|
||||
type: "message",
|
||||
role: "developer",
|
||||
content: buildResponsesTextParts(msg.content),
|
||||
status: "completed",
|
||||
});
|
||||
continue;
|
||||
}
|
||||
@@ -185,6 +186,7 @@ export function openaiToOpenAIResponsesRequest(
|
||||
type: "message",
|
||||
role: "user",
|
||||
content,
|
||||
status: "completed",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -223,6 +225,7 @@ export function openaiToOpenAIResponsesRequest(
|
||||
type: "message",
|
||||
role: "assistant",
|
||||
content: outputContent,
|
||||
status: "completed",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -241,6 +244,7 @@ export function openaiToOpenAIResponsesRequest(
|
||||
call_id: clampCallId(toString(toolCall.id).trim() || generateToolCallId()),
|
||||
name: fnName,
|
||||
arguments: toString(fn.arguments, "{}"),
|
||||
status: "completed",
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -255,6 +259,7 @@ export function openaiToOpenAIResponsesRequest(
|
||||
call_id: clampCallId(`call_${fnName}`),
|
||||
name: fnName,
|
||||
arguments: toString(fc.arguments, "{}"),
|
||||
status: "completed",
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -276,6 +281,7 @@ export function openaiToOpenAIResponsesRequest(
|
||||
return c;
|
||||
})
|
||||
: String(msg.content ?? ""),
|
||||
status: "completed",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -285,6 +291,7 @@ export function openaiToOpenAIResponsesRequest(
|
||||
type: "function_call_output",
|
||||
call_id: clampCallId(`call_${toString(msg.name)}`),
|
||||
output: typeof msg.content === "string" ? msg.content : String(msg.content ?? ""),
|
||||
status: "completed",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
55
tests/unit/responses-input-item-status-8083.test.ts
Normal file
55
tests/unit/responses-input-item-status-8083.test.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
// Kept in its own file rather than growing the frozen
|
||||
// tests/unit/translator-openai-responses-req.test.ts (file-size ratchet).
|
||||
const { openaiToOpenAIResponsesRequest } = await import(
|
||||
"../../open-sse/translator/request/openai-responses.ts"
|
||||
);
|
||||
|
||||
// --- Issue #8083: strict Responses-compatible upstreams reject items whose
|
||||
// `type` is set without an accompanying `status`, returning
|
||||
// 400 MissingParameter input.status. `status` is optional per OpenAI's own
|
||||
// schema, so setting it to "completed" on translated history items (which by
|
||||
// construction always represent an already-completed prior turn) is a safe
|
||||
// superset fix that also satisfies stricter third-party validators.
|
||||
test("Chat -> Responses sets status:completed on every input item (#8083)", () => {
|
||||
const result = openaiToOpenAIResponsesRequest(
|
||||
"gpt-4o",
|
||||
{
|
||||
messages: [
|
||||
{ role: "system", content: "Rules" },
|
||||
// Mid-conversation developer turn -> developer-role message item.
|
||||
{ role: "developer", content: "Follow up instruction" },
|
||||
{ role: "user", content: "Hello" },
|
||||
{
|
||||
role: "assistant",
|
||||
content: "Done",
|
||||
tool_calls: [
|
||||
{ id: "call_1", type: "function", function: { name: "read_file", arguments: "{}" } },
|
||||
],
|
||||
},
|
||||
{ role: "tool", tool_call_id: "call_1", content: "ok" },
|
||||
// Deprecated function_call / function role pair.
|
||||
{
|
||||
role: "assistant",
|
||||
function_call: { name: "legacy_fn", arguments: "{}" },
|
||||
},
|
||||
{ role: "function", name: "legacy_fn", content: "legacy ok" },
|
||||
],
|
||||
},
|
||||
false,
|
||||
null
|
||||
) as Record<string, unknown>;
|
||||
|
||||
const input = result.input as Array<Record<string, unknown>>;
|
||||
assert.ok(input.length > 0, "input array must not be empty");
|
||||
for (const item of input) {
|
||||
assert.equal(
|
||||
item.status,
|
||||
"completed",
|
||||
`input item of type "${item.type}" is missing status:"completed" — strict Responses-compatible ` +
|
||||
`upstreams reject this with 400 MissingParameter input.status (#8083)`
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -360,22 +360,26 @@ test("Chat -> Responses converts messages, tool calls, tool outputs, tools and p
|
||||
{ type: "input_image", image_url: "https://example.com/cat.png", detail: "high" },
|
||||
{ type: "input_file", file_data: "abc", filename: "doc.txt" },
|
||||
],
|
||||
status: "completed",
|
||||
},
|
||||
{
|
||||
type: "message",
|
||||
role: "assistant",
|
||||
content: [{ type: "output_text", text: "Done" }],
|
||||
status: "completed",
|
||||
},
|
||||
{
|
||||
type: "function_call",
|
||||
call_id: "call_1",
|
||||
name: "read_file",
|
||||
arguments: '{"path":"/tmp/a"}',
|
||||
status: "completed",
|
||||
},
|
||||
{
|
||||
type: "function_call_output",
|
||||
call_id: "call_1",
|
||||
output: [{ type: "input_text", text: "ok" }],
|
||||
status: "completed",
|
||||
},
|
||||
]);
|
||||
assert.deepEqual((result as any).tools, [
|
||||
@@ -520,6 +524,7 @@ test("Chat -> Responses converts assistant image_url history parts to output_tex
|
||||
{ type: "output_text", text: "I inspected the screenshot." },
|
||||
{ type: "output_text", text: "[Image: https://example.com/scope.png]" },
|
||||
],
|
||||
status: "completed",
|
||||
},
|
||||
]);
|
||||
assert.equal(JSON.stringify(result).includes('"image_url"'), false);
|
||||
|
||||
Reference in New Issue
Block a user