From 93c8a5bfe5a2bed384213a291fdb0a9a60fd7bc6 Mon Sep 17 00:00:00 2001 From: PipeYume <1178795412@qq.com> Date: Sat, 29 Aug 2026 23:35:35 +0800 Subject: [PATCH 1/4] update model config --- packages/types/src/providers/deepseek.ts | 16 ++++++++++++++++ src/api/providers/deepseek.ts | 3 ++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/packages/types/src/providers/deepseek.ts b/packages/types/src/providers/deepseek.ts index d9cf7ce755..286855a423 100644 --- a/packages/types/src/providers/deepseek.ts +++ b/packages/types/src/providers/deepseek.ts @@ -40,6 +40,22 @@ export const deepSeekModels = { cacheReadsPrice: 0.044, description: `DeepSeek-V4-Pro-0813 is DeepSeek's strongest V4 model for reasoning, coding, long-context, and agentic workloads. It supports thinking and non-thinking modes, JSON output, tool calls, chat prefix completion (beta), and FIM completion (beta) in non-thinking mode.`, }, + "deepseek-v4-flash-vision-exp": { + displayName: "DeepSeek V4 Flash Vision Exp", + maxTokens: 384_000, + contextWindow: 1_000_000, + supportsImages: true, + supportsPromptCache: true, + supportsReasoningEffort: ["disable", "low", "high", "max"], // Updated 2026-08-13 + preserveReasoning: true, + reasoningEffort: "high", + inputPrice: 0, // the inputs are priced as cache read/write, so `inputPrice` should be 0 + // Static estimates use peak rates; off-peak rates are 50% lower. + outputPrice: 1.32, + cacheWritesPrice: 0.44, + cacheReadsPrice: 0.014, + description: `DeepSeek-V4-Flash-Vision-Exp is DeepSeek's experimental multimodal V4 Flash model with image understanding. It supports thinking and non-thinking modes, JSON output, tool calls, chat prefix completion (beta), and image inputs.`, + }, } as const satisfies Record // https://api-docs.deepseek.com/quick_start/parameter_settings diff --git a/src/api/providers/deepseek.ts b/src/api/providers/deepseek.ts index 64782c9fb4..b3ca67287a 100644 --- a/src/api/providers/deepseek.ts +++ b/src/api/providers/deepseek.ts @@ -28,7 +28,7 @@ type DeepSeekChatCompletionParams = Omit deepSeekV4ThinkingModels.has(modelId) // Only known V4 models and the legacy reasoner alias support DeepSeek's @@ -51,6 +51,7 @@ export const normalizeDeepSeekReasoningEffort = ( switch (modelId) { case "deepseek-v4-flash": case "deepseek-v4-pro": + case "deepseek-v4-flash-vision-exp": switch (reasoningEffort) { case "low": return "low" From 620cc5e42ef60ddc27f766c1bd103ab06f71f496 Mon Sep 17 00:00:00 2001 From: PipeYume <1178795412@qq.com> Date: Sat, 29 Aug 2026 23:36:33 +0800 Subject: [PATCH 2/4] add test unit --- .../src/__tests__/deepseek-v4-pro.test.ts | 9 +++ src/api/providers/__tests__/deepseek.spec.ts | 71 +++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/packages/types/src/__tests__/deepseek-v4-pro.test.ts b/packages/types/src/__tests__/deepseek-v4-pro.test.ts index 4449bfd1f6..78a4befd6b 100644 --- a/packages/types/src/__tests__/deepseek-v4-pro.test.ts +++ b/packages/types/src/__tests__/deepseek-v4-pro.test.ts @@ -35,6 +35,15 @@ describe("DeepSeek V4 Pro 0813 provider catalogs", () => { }) }) + it("marks deepseek-v4-flash-vision-exp as a vision-capable model", () => { + const model = deepSeekModels["deepseek-v4-flash-vision-exp"] + expect(model).toBeDefined() + expect(model.supportsImages).toBe(true) + expect(model.supportsPromptCache).toBe(true) + expect(model.contextWindow).toBeGreaterThanOrEqual(1_000_000) + expect(model.supportsReasoningEffort).toEqual(["disable", "low", "high", "max"]) + }) + // Self-hosted providers retain separate IDs for the preview weights and 0813 checkpoint. it.each([ ["Fireworks AI", fireworksModels["accounts/fireworks/models/deepseek-v4-pro"]], diff --git a/src/api/providers/__tests__/deepseek.spec.ts b/src/api/providers/__tests__/deepseek.spec.ts index dd2c3d4019..49b5ee59b2 100644 --- a/src/api/providers/__tests__/deepseek.spec.ts +++ b/src/api/providers/__tests__/deepseek.spec.ts @@ -249,6 +249,18 @@ describe("DeepSeekHandler", () => { expect((model.info as ModelInfo).reasoningEffort).toBe("high") }) + it("should return vision model info for deepseek-v4-flash-vision-exp", () => { + const handlerWithVision = new DeepSeekHandler({ + ...mockOptions, + apiModelId: "deepseek-v4-flash-vision-exp", + }) + const model = handlerWithVision.getModel() + expect(model.id).toBe("deepseek-v4-flash-vision-exp") + expect(model.info.supportsImages).toBe(true) + expect(model.info.supportsPromptCache).toBe(true) + expect((model.info as ModelInfo).preserveReasoning).toBe(true) + }) + it("should return provided model ID with default model info if model does not exist", () => { const handlerWithInvalidModel = new DeepSeekHandler({ ...mockOptions, @@ -412,6 +424,35 @@ describe("DeepSeekHandler", () => { const reasoningChunks = chunks.filter((chunk) => chunk.type === "reasoning") expect(reasoningChunks).toEqual([{ type: "reasoning", text: "primary thought" }]) }) + + it("enables thinking and forwards image_url for the vision model", async () => { + const visionHandler = new DeepSeekHandler({ + ...mockOptions, + apiModelId: "deepseek-v4-flash-vision-exp", + }) + const withImage: Anthropic.Messages.MessageParam[] = [ + { + role: "user", + content: [ + { type: "text", text: "Describe:" }, + { type: "image", source: { type: "base64", media_type: "image/png", data: "abc" } }, + ], + }, + ] + + await collectStream(visionHandler.createMessage(systemPrompt, withImage)) + + const callArgs = mockCreate.mock.calls[0][0] + expect(callArgs.thinking).toEqual({ type: "enabled" }) + expect(callArgs.messages).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + role: "user", + content: expect.arrayContaining([expect.objectContaining({ type: "image_url" })]), + }), + ]), + ) + }) }) describe("processUsageMetrics", () => { @@ -684,6 +725,36 @@ describe("DeepSeekHandler", () => { rawReasoningEffort: "max", mappedReasoningEffort: "max", }, + { + modelId: "deepseek-v4-flash-vision-exp", + rawReasoningEffort: "disable", + mappedReasoningEffort: undefined, + }, + { + modelId: "deepseek-v4-flash-vision-exp", + rawReasoningEffort: "low", + mappedReasoningEffort: "low", + }, + { + modelId: "deepseek-v4-flash-vision-exp", + rawReasoningEffort: "medium", + mappedReasoningEffort: "high", + }, + { + modelId: "deepseek-v4-flash-vision-exp", + rawReasoningEffort: "high", + mappedReasoningEffort: "high", + }, + { + modelId: "deepseek-v4-flash-vision-exp", + rawReasoningEffort: "xhigh", + mappedReasoningEffort: "high", + }, + { + modelId: "deepseek-v4-flash-vision-exp", + rawReasoningEffort: "max", + mappedReasoningEffort: "max", + }, ] for (const { modelId, rawReasoningEffort, mappedReasoningEffort } of mappings) { From 72623a9dce4ee915c630535bcad91d986a017d9e Mon Sep 17 00:00:00 2001 From: PipeYume <1178795412@qq.com> Date: Sat, 29 Aug 2026 23:53:37 +0800 Subject: [PATCH 3/4] update test --- src/api/providers/__tests__/deepseek.spec.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/api/providers/__tests__/deepseek.spec.ts b/src/api/providers/__tests__/deepseek.spec.ts index 49b5ee59b2..b99cbe4ff5 100644 --- a/src/api/providers/__tests__/deepseek.spec.ts +++ b/src/api/providers/__tests__/deepseek.spec.ts @@ -448,7 +448,14 @@ describe("DeepSeekHandler", () => { expect.arrayContaining([ expect.objectContaining({ role: "user", - content: expect.arrayContaining([expect.objectContaining({ type: "image_url" })]), + content: expect.arrayContaining([ + expect.objectContaining({ + type: "image_url", + image_url: expect.objectContaining({ + url: "data:image/png;base64,abc", + }), + }), + ]), }), ]), ) From 3adcf7c225a209d159610264a59c8c6b1e53f0b1 Mon Sep 17 00:00:00 2001 From: PipeYume <1178795412@qq.com> Date: Sun, 30 Aug 2026 23:22:17 +0800 Subject: [PATCH 4/4] trigger ci re-run