fix: translate input_image↔image_url with detail preservation

This commit is contained in:
AveryanAlex
2026-03-29 00:11:25 +03:00
parent a536a2b822
commit 58d6938065
2 changed files with 100 additions and 2 deletions

View File

@@ -112,6 +112,16 @@ export function openaiResponsesToOpenAIRequest(
if (contentItem.type === "output_text") {
return { type: "text", text: toString(contentItem.text) };
}
if (contentItem.type === "input_image") {
const imgResult: JsonRecord = {
type: "image_url",
image_url: { url: toString(contentItem.image_url) },
};
if (contentItem.detail !== undefined) {
(imgResult.image_url as JsonRecord).detail = contentItem.detail;
}
return imgResult;
}
return contentValue;
})
: item.content;
@@ -288,11 +298,15 @@ export function openaiToOpenAIResponsesRequest(
return { type: "input_text", text: toString(contentItem.text) };
}
if (contentItem.type === "image_url") {
const imgUrl = contentItem.image_url as string | { url?: string };
return {
const imgUrl = contentItem.image_url as string | { url?: string; detail?: string };
const imgResult: JsonRecord = {
type: "input_image",
image_url: typeof imgUrl === "string" ? imgUrl : imgUrl?.url || "",
};
if (typeof imgUrl === "object" && imgUrl?.detail !== undefined) {
imgResult.detail = imgUrl.detail;
}
return imgResult;
}
return contentValue;
})

View File

@@ -4,6 +4,9 @@ import assert from "node:assert/strict";
const { convertResponsesApiFormat } = await import(
"../../open-sse/translator/helpers/responsesApiHelper.ts"
);
const { openaiResponsesToOpenAIRequest, openaiToOpenAIResponsesRequest } = await import(
"../../open-sse/translator/request/openai-responses.ts"
);
test("convertResponsesApiFormat filters orphaned function_call_output items", () => {
const body = {
@@ -33,3 +36,84 @@ test("convertResponsesApiFormat skips function_call items with empty names", ()
const assistantMsgs = result.messages.filter((m) => m.role === "assistant");
assert.equal(assistantMsgs.length, 0);
});
test("Responses→Chat: input_image converted to image_url with detail", () => {
const body = {
model: "gpt-4",
input: [
{
type: "message",
role: "user",
content: [
{ type: "input_text", text: "What is this?" },
{ type: "input_image", image_url: "https://example.com/img.png", detail: "high" },
],
},
],
};
const result = openaiResponsesToOpenAIRequest(null, body, null, null);
const userMsg = result.messages.find((m) => m.role === "user");
const imgPart = userMsg.content.find((c) => c.type === "image_url");
assert.ok(imgPart, "should have image_url content part");
assert.equal(imgPart.image_url.url, "https://example.com/img.png");
assert.equal(imgPart.image_url.detail, "high");
});
test("Responses→Chat: input_image without detail omits detail field", () => {
const body = {
model: "gpt-4",
input: [
{
type: "message",
role: "user",
content: [{ type: "input_image", image_url: "https://example.com/img.png" }],
},
],
};
const result = openaiResponsesToOpenAIRequest(null, body, null, null);
const userMsg = result.messages.find((m) => m.role === "user");
const imgPart = userMsg.content.find((c) => c.type === "image_url");
assert.ok(imgPart);
assert.equal(imgPart.image_url.url, "https://example.com/img.png");
assert.equal(imgPart.image_url.detail, undefined);
});
test("Chat→Responses: image_url detail preserved as input_image", () => {
const body = {
model: "gpt-4",
messages: [
{
role: "user",
content: [
{ type: "text", text: "Describe" },
{ type: "image_url", image_url: { url: "https://example.com/img.png", detail: "low" } },
],
},
],
};
const result = openaiToOpenAIResponsesRequest("gpt-4", body, true, null);
const userItem = result.input.find((i) => i.type === "message" && i.role === "user");
const imgPart = userItem.content.find((c) => c.type === "input_image");
assert.ok(imgPart, "should have input_image content part");
assert.equal(imgPart.image_url, "https://example.com/img.png");
assert.equal(imgPart.detail, "low");
});
test("Chat→Responses: image_url without detail omits detail", () => {
const body = {
model: "gpt-4",
messages: [
{
role: "user",
content: [
{ type: "image_url", image_url: { url: "https://example.com/img.png" } },
],
},
],
};
const result = openaiToOpenAIResponsesRequest("gpt-4", body, true, null);
const userItem = result.input.find((i) => i.type === "message" && i.role === "user");
const imgPart = userItem.content.find((c) => c.type === "input_image");
assert.ok(imgPart);
assert.equal(imgPart.detail, undefined);
});