fix(codex): normalize additional_tools passthrough items (#9219)

Validated in local merge-train (devbox-vm-06-dev002) @ combined-tip (FAST gates — only pre-existing audit.test.ts flake).
This commit is contained in:
Diego Rodrigues de Sa e Souza
2026-08-05 22:40:26 -03:00
committed by GitHub
parent 5cf9a33d85
commit 348e1b1921
4 changed files with 60 additions and 1 deletions

View File

@@ -0,0 +1 @@
- **fix(codex):** normalize additional_tools passthrough items. (thanks @SalyyS1)

View File

@@ -77,8 +77,17 @@ function normalizeCodexResponsesInputItem(itemValue: unknown): unknown {
const role = typeof item.role === "string" ? item.role : "user";
const type = typeof item.type === "string" ? item.type : "";
if (type === "additional_tools") {
delete item.content;
return item;
}
if (!type && item.content === undefined && typeof item.text === "string") {
return { type: "message", role, content: [{ type: textPartTypeForRole(role), text: item.text }] };
return {
type: "message",
role,
content: [{ type: textPartTypeForRole(role), text: item.text }],
};
}
if (!type && role) item.type = "message";

View File

@@ -39,6 +39,32 @@ test("codex native responses passthrough strips client-only params (#3317)", asy
assert.ok(Array.isArray(result.input), "input array preserved");
});
test("codex native responses passthrough normalizes additional_tools items", async () => {
const executor = new CodexExecutor();
const messageContent = [{ type: "input_text", text: "run the terminal tool" }];
const tools = [{ type: "function", name: "terminal", parameters: { type: "object" } }];
const body = {
_nativeCodexPassthrough: true,
model: "gpt-5.5",
input: [
{
type: "additional_tools",
role: "developer",
content: [{ type: "input_text", text: "unsupported wrapper content" }],
tools,
},
{ type: "message", role: "user", content: messageContent },
],
};
const result = (await executor.transformRequest("gpt-5.5", body, true, {} as never)) as {
input: Array<Record<string, unknown>>;
};
assert.deepEqual(result.input[0], { type: "additional_tools", role: "developer", tools });
assert.deepEqual(result.input[1], { type: "message", role: "user", content: messageContent });
});
test.after(() => {
try {
core.resetDbInstance?.();

View File

@@ -126,6 +126,29 @@ test("Codex Responses input: null input normalizes to an empty list (not [null])
assert.deepEqual(body.input, []);
});
test("Codex Responses input: additional_tools drops unsupported content", () => {
const body: Record<string, unknown> = {
input: [
{
type: "additional_tools",
role: "developer",
content: [{ type: "input_text", text: "unsupported wrapper content" }],
tools: [{ type: "function", name: "terminal", parameters: { type: "object" } }],
},
],
};
normalizeCodexResponsesInput(body);
assert.deepEqual(body.input, [
{
type: "additional_tools",
role: "developer",
tools: [{ type: "function", name: "terminal", parameters: { type: "object" } }],
},
]);
});
test("Codex Responses input: assistant history normalized to output_text (OpenAI/Codex rejects input_text on assistant turns)", () => {
const body: Record<string, unknown> = {
input: [