From aa2ad995a5a7368f5567c1c267e586b95d8de67f Mon Sep 17 00:00:00 2001 From: Luis Pater Date: Fri, 19 Jun 2026 05:56:25 +0800 Subject: [PATCH] feat(translator): preserve `input_image` details in OpenAI response conversion - Updated handling in `ConvertOpenAIResponsesRequestToOpenAIChatCompletions` to retain `input_image` detail fields such as `image_url` and `detail`. - Added `TestConvertOpenAIResponsesRequestToOpenAIChatCompletions_PreservesInputImageDetail` to verify preservation of image details during transformation. Closes: #3385 --- .../openai_openai-responses_request.go | 3 ++ .../openai_openai-responses_request_test.go | 28 +++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/internal/translator/openai/openai/responses/openai_openai-responses_request.go b/internal/translator/openai/openai/responses/openai_openai-responses_request.go index 76b28acf..bc7027cd 100644 --- a/internal/translator/openai/openai/responses/openai_openai-responses_request.go +++ b/internal/translator/openai/openai/responses/openai_openai-responses_request.go @@ -154,6 +154,9 @@ func ConvertOpenAIResponsesRequestToOpenAIChatCompletions(modelName string, inpu imageURL := contentItem.Get("image_url").String() contentPart := []byte(`{"type":"image_url","image_url":{"url":""}}`) contentPart, _ = sjson.SetBytes(contentPart, "image_url.url", imageURL) + if detail := contentItem.Get("detail"); detail.Exists() { + contentPart, _ = sjson.SetBytes(contentPart, "image_url.detail", detail.String()) + } message, _ = sjson.SetRawBytes(message, "content.-1", contentPart) } return true diff --git a/internal/translator/openai/openai/responses/openai_openai-responses_request_test.go b/internal/translator/openai/openai/responses/openai_openai-responses_request_test.go index 56bc5686..2a0f3dcd 100644 --- a/internal/translator/openai/openai/responses/openai_openai-responses_request_test.go +++ b/internal/translator/openai/openai/responses/openai_openai-responses_request_test.go @@ -198,3 +198,31 @@ func TestConvertOpenAIResponsesRequestToOpenAIChatCompletions_PreservesStructure t.Fatalf("tool_choice.function.name = %q, want run_command; output=%s", got, out) } } + +func TestConvertOpenAIResponsesRequestToOpenAIChatCompletions_PreservesInputImageDetail(t *testing.T) { + raw := []byte(`{ + "input": [ + { + "role": "user", + "content": [ + { + "type": "input_image", + "image_url": "https://example.com/image.png", + "detail": "high" + } + ] + } + ] + }`) + t.Logf("input json:\n%s", prettyJSONForTest(raw)) + + out := ConvertOpenAIResponsesRequestToOpenAIChatCompletions("gpt-5.4", raw, false) + t.Logf("output json:\n%s", prettyJSONForTest(out)) + + if got := gjson.GetBytes(out, "messages.0.content.0.image_url.url").String(); got != "https://example.com/image.png" { + t.Fatalf("messages.0.content.0.image_url.url = %q, want https://example.com/image.png; output=%s", got, out) + } + if got := gjson.GetBytes(out, "messages.0.content.0.image_url.detail").String(); got != "high" { + t.Fatalf("messages.0.content.0.image_url.detail = %q, want high; output=%s", got, out) + } +} -- 2.51.2