Skip to content
This repository was archived by the owner on May 15, 2026. It is now read-only.

Commit 415580b

Browse files
committed
feat: add DeepSeek V4 Pro model support
- Add deepseek-v4-pro to the model registry with appropriate config (164K context, 16K max output, vision support, preserveReasoning) - Update isThinkingModel check to recognize deepseek-v4 models so thinking mode and reasoning_content passback work correctly - Add tests for the new model Fixes #12177
1 parent 96d6e43 commit 415580b

3 files changed

Lines changed: 80 additions & 3 deletions

File tree

packages/types/src/providers/deepseek.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,18 @@ export const deepSeekModels = {
3232
cacheReadsPrice: 0.028, // $0.028 per million tokens (cache hit) - Updated Dec 9, 2025
3333
description: `DeepSeek-V3.2 (Thinking Mode) achieves performance comparable to OpenAI-o1 across math, code, and reasoning tasks. Supports Chain of Thought reasoning with up to 8K output tokens. Supports JSON output, tool calls, and chat prefix completion (beta).`,
3434
},
35+
"deepseek-v4-pro": {
36+
maxTokens: 16_384, // 16K max output
37+
contextWindow: 164_000,
38+
supportsImages: true,
39+
supportsPromptCache: true,
40+
preserveReasoning: true,
41+
inputPrice: 2.19, // $2.19 per million tokens (cache miss)
42+
outputPrice: 8.87, // $8.87 per million tokens
43+
cacheWritesPrice: 2.19, // $2.19 per million tokens (cache miss)
44+
cacheReadsPrice: 0.55, // $0.55 per million tokens (cache hit)
45+
description: `DeepSeek V4 Pro is a frontier reasoning model with advanced capabilities across math, code, and complex reasoning tasks. Features 164K context window, 16K max output, vision support, and enhanced tool calling with interleaved thinking mode.`,
46+
},
3547
} as const satisfies Record<string, ModelInfo>
3648

3749
// https://api-docs.deepseek.com/quick_start/parameter_settings

src/api/providers/__tests__/deepseek.spec.ts

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ vi.mock("openai", () => {
3030
}
3131

3232
// Check if this is a reasoning_content test by looking at model
33-
const isReasonerModel = options.model?.includes("deepseek-reasoner")
33+
const isReasonerModel =
34+
options.model?.includes("deepseek-reasoner") || options.model?.includes("deepseek-v4")
3435
const isToolCallTest = options.tools?.length > 0
3536

3637
// Return async iterator for streaming
@@ -507,5 +508,69 @@ describe("DeepSeekHandler", () => {
507508
expect(toolCallChunks.length).toBeGreaterThan(0)
508509
expect(toolCallChunks[0].name).toBe("get_weather")
509510
})
511+
512+
it("should handle reasoning_content in streaming responses for deepseek-v4-pro", async () => {
513+
const v4Handler = new DeepSeekHandler({
514+
...mockOptions,
515+
apiModelId: "deepseek-v4-pro",
516+
})
517+
518+
const stream = v4Handler.createMessage(systemPrompt, messages)
519+
const chunks: any[] = []
520+
for await (const chunk of stream) {
521+
chunks.push(chunk)
522+
}
523+
524+
// Should have reasoning chunks
525+
const reasoningChunks = chunks.filter((chunk) => chunk.type === "reasoning")
526+
expect(reasoningChunks.length).toBeGreaterThan(0)
527+
expect(reasoningChunks[0].text).toBe("Let me think about this...")
528+
expect(reasoningChunks[1].text).toBe(" I'll analyze step by step.")
529+
})
530+
531+
it("should pass thinking parameter for deepseek-v4-pro model", async () => {
532+
const v4Handler = new DeepSeekHandler({
533+
...mockOptions,
534+
apiModelId: "deepseek-v4-pro",
535+
})
536+
537+
const stream = v4Handler.createMessage(systemPrompt, messages)
538+
for await (const _chunk of stream) {
539+
// Consume the stream
540+
}
541+
542+
// Verify that the thinking parameter was passed to the API
543+
expect(mockCreate).toHaveBeenCalledWith(
544+
expect.objectContaining({
545+
thinking: { type: "enabled" },
546+
}),
547+
{}, // Empty path options for non-Azure URLs
548+
)
549+
})
550+
551+
it("should have preserveReasoning enabled for deepseek-v4-pro", () => {
552+
const v4Handler = new DeepSeekHandler({
553+
...mockOptions,
554+
apiModelId: "deepseek-v4-pro",
555+
})
556+
const model = v4Handler.getModel()
557+
expect((model.info as ModelInfo).preserveReasoning).toBe(true)
558+
})
559+
})
560+
561+
describe("deepseek-v4-pro model info", () => {
562+
it("should return correct model info for deepseek-v4-pro", () => {
563+
const v4Handler = new DeepSeekHandler({
564+
...mockOptions,
565+
apiModelId: "deepseek-v4-pro",
566+
})
567+
const model = v4Handler.getModel()
568+
expect(model.id).toBe("deepseek-v4-pro")
569+
expect(model.info).toBeDefined()
570+
expect(model.info.maxTokens).toBe(16_384)
571+
expect(model.info.contextWindow).toBe(164_000)
572+
expect(model.info.supportsImages).toBe(true)
573+
expect(model.info.supportsPromptCache).toBe(true)
574+
})
510575
})
511576
})

src/api/providers/deepseek.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ export class DeepSeekHandler extends OpenAiHandler {
5555
const modelId = this.options.apiModelId ?? deepSeekDefaultModelId
5656
const { info: modelInfo } = this.getModel()
5757

58-
// Check if this is a thinking-enabled model (deepseek-reasoner)
59-
const isThinkingModel = modelId.includes("deepseek-reasoner")
58+
// Check if this is a thinking-enabled model (deepseek-reasoner or deepseek-v4-pro)
59+
const isThinkingModel = modelId.includes("deepseek-reasoner") || modelId.includes("deepseek-v4")
6060

6161
// Convert messages to R1 format (merges consecutive same-role messages)
6262
// This is required for DeepSeek which does not support successive messages with the same role

0 commit comments

Comments
 (0)