From 998445ea20fdb9534eb26a6613869ad759b64853 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Tue, 16 Jun 2026 21:42:59 +0800 Subject: [PATCH] fix(qwen): place DashScope image prompts in user content (#93649) Co-authored-by: openclaw-clownfish[bot] <280122609+openclaw-clownfish[bot]@users.noreply.github.com> --- src/media-understanding/image.test.ts | 53 +++++++++++++++++++++++++++ src/media-understanding/image.ts | 1 + 2 files changed, 54 insertions(+) diff --git a/src/media-understanding/image.test.ts b/src/media-understanding/image.test.ts index 4dad4c3b9918..61ba109414a2 100644 --- a/src/media-understanding/image.test.ts +++ b/src/media-understanding/image.test.ts @@ -884,6 +884,59 @@ describe("describeImageWithModel", () => { ]); }); + it("places DashScope image prompts in user content before images", async () => { + discoverModelsMock.mockReturnValue({ + find: vi.fn(() => ({ + api: "openai-completions", + provider: "qwen", + id: "qwen-vl-max-latest", + input: ["text", "image"], + baseUrl: "https://dashscope.aliyuncs.com/compatible-mode/v1", + })), + }); + completeMock.mockResolvedValue({ + role: "assistant", + api: "openai-completions", + provider: "qwen", + model: "qwen-vl-max-latest", + stopReason: "stop", + timestamp: Date.now(), + content: [{ type: "text", text: "dashscope ok" }], + }); + + const result = await describeImageWithModel({ + cfg: {}, + agentDir: "/tmp/openclaw-agent", + provider: "qwen", + model: "qwen-vl-max-latest", + buffer: Buffer.from("png-bytes"), + fileName: "image.png", + mime: "image/png", + prompt: "Describe the image.", + timeoutMs: 1000, + }); + + expect(result).toEqual({ + text: "dashscope ok", + model: "qwen-vl-max-latest", + }); + const firstCall = requireFirstMockCall(completeMock, "DashScope image completion"); + const [, context] = firstCall; + expect(context.systemPrompt).toBeUndefined(); + const userMessage = context.messages[0]; + if (!userMessage) { + throw new Error("expected DashScope image completion user message"); + } + expect(userMessage.content).toEqual([ + { type: "text", text: "Describe the image." }, + { + type: "image", + data: Buffer.from("png-bytes").toString("base64"), + mimeType: "image/png", + }, + ]); + }); + it.each([ { name: "direct OpenAI Responses baseUrl", diff --git a/src/media-understanding/image.ts b/src/media-understanding/image.ts index 881eb94dec50..1249cf576a0a 100644 --- a/src/media-understanding/image.ts +++ b/src/media-understanding/image.ts @@ -298,6 +298,7 @@ function shouldPlaceImagePromptInUserContent(model: Model): boolean { }); return ( capabilities.endpointClass === "openrouter" || + capabilities.endpointClass === "modelstudio-native" || (model.provider.toLowerCase() === "openrouter" && capabilities.endpointClass === "default") ); }