Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 249
DeepSeek V4 Support#6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
b7ec13570385d8ec48dd2c358bd7a2d19da91c9798e214faa221dfc9File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -6,9 +6,39 @@ import type { ModelInfo } from "../model.js" | ||
| // continuation within the same turn. See: https://api-docs.deepseek.com/guides/thinking_mode | ||
| export type DeepSeekModelId = keyof typeof deepSeekModels | ||
| export const deepSeekDefaultModelId: DeepSeekModelId = "deepseek-chat" | ||
| export const deepSeekDefaultModelId: DeepSeekModelId = "deepseek-v4-flash" | ||
| export const deepSeekModels = { | ||
| "deepseek-v4-flash": { | ||
| maxTokens: 384_000, | ||
| contextWindow: 1_000_000, | ||
| supportsImages: false, | ||
| supportsPromptCache: true, | ||
| supportsReasoningEffort: ["disable", "low", "medium", "high", "xhigh"], | ||
| preserveReasoning: true, | ||
| reasoningEffort: "high", | ||
| inputPrice: 0.14, // $0.14 per million tokens (cache miss) - Updated Apr 29, 2026 | ||
| outputPrice: 0.28, // $0.28 per million tokens - Updated Apr 29, 2026 | ||
| cacheWritesPrice: 0.14, // $0.14 per million tokens (cache miss) - Updated Apr 29, 2026 | ||
| cacheReadsPrice: 0.0028, // $0.0028 per million tokens (cache hit) - Updated Apr 29, 2026 | ||
| description: `DeepSeek-V4-Flash is DeepSeek's fast, cost-efficient V4 model. 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-pro": { | ||
| maxTokens: 384_000, | ||
| contextWindow: 1_000_000, | ||
| supportsImages: false, | ||
| supportsPromptCache: true, | ||
| supportsReasoningEffort: ["disable", "low", "medium", "high", "xhigh"], | ||
| preserveReasoning: true, | ||
| reasoningEffort: "high", | ||
| // TODO(deepseek): Re-check V4 Pro discounted prices after DeepSeek's 2026-05-31 discount end date. | ||
doctarock marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| inputPrice: 0.435, // $0.435 per million tokens (cache miss, discounted) - Updated Apr 29, 2026 | ||
| outputPrice: 0.87, // $0.87 per million tokens (discounted) - Updated Apr 29, 2026 | ||
| cacheWritesPrice: 0.435, // $0.435 per million tokens (cache miss, discounted) - Updated Apr 29, 2026 | ||
| cacheReadsPrice: 0.003625, // $0.003625 per million tokens (cache hit, discounted) - Updated Apr 29, 2026 | ||
| description: `DeepSeek-V4-Pro 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.`, | ||
| }, | ||
| // TODO(deepseek): Remove this compatibility alias after DeepSeek's 2026-07-24 retirement date. | ||
| "deepseek-chat": { | ||
| maxTokens: 8192, // 8K max output | ||
| contextWindow: 128_000, | ||
| @@ -18,8 +48,9 @@ export const deepSeekModels = { | ||
| outputPrice: 0.42, // $0.42 per million tokens - Updated Dec 9, 2025 | ||
| cacheWritesPrice: 0.28, // $0.28 per million tokens (cache miss) - Updated Dec 9, 2025 | ||
| cacheReadsPrice: 0.028, // $0.028 per million tokens (cache hit) - Updated Dec 9, 2025 | ||
| description: `DeepSeek-V3.2 (Non-thinking Mode) achieves a significant breakthrough in inference speed over previous models. It tops the leaderboard among open-source models and rivals the most advanced closed-source models globally. Supports JSON output, tool calls, chat prefix completion (beta), and FIM completion (beta).`, | ||
| description: `Legacy compatibility alias for the non-thinking mode of deepseek-v4-flash. DeepSeek plans to deprecate this model name on 2026-07-24.`, | ||
| }, | ||
| // TODO(deepseek): Remove this compatibility alias after DeepSeek's 2026-07-24 retirement date. | ||
| "deepseek-reasoner": { | ||
| maxTokens: 8192, // 8K max output | ||
| contextWindow: 128_000, | ||
| @@ -30,7 +61,7 @@ export const deepSeekModels = { | ||
| outputPrice: 0.42, // $0.42 per million tokens - Updated Dec 9, 2025 | ||
| cacheWritesPrice: 0.28, // $0.28 per million tokens (cache miss) - Updated Dec 9, 2025 | ||
| cacheReadsPrice: 0.028, // $0.028 per million tokens (cache hit) - Updated Dec 9, 2025 | ||
| 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).`, | ||
| description: `Legacy compatibility alias for the thinking mode of deepseek-v4-flash. DeepSeek plans to deprecate this model name on 2026-07-24.`, | ||
| }, | ||
| } as const satisfies Record<string, ModelInfo> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -6,6 +6,7 @@ import { | ||
| deepSeekDefaultModelId, | ||
| DEEP_SEEK_DEFAULT_TEMPERATURE, | ||
| OPENAI_AZURE_AI_INFERENCE_PATH, | ||
| type ModelInfo, | ||
| } from "@roo-code/types" | ||
| import type { ApiHandlerOptions } from "../../shared/api" | ||
| @@ -18,8 +19,45 @@ import { OpenAiHandler } from "./openai" | ||
| import type { ApiHandlerCreateMessageMetadata } from "../index" | ||
| // Custom interface for DeepSeek params to support thinking mode | ||
| type DeepSeekChatCompletionParams = OpenAI.Chat.ChatCompletionCreateParamsStreaming & { | ||
| type DeepSeekChatCompletionParams = Omit<OpenAI.Chat.ChatCompletionCreateParamsStreaming, "reasoning_effort"> & { | ||
| thinking?: { type: "enabled" | "disabled" } | ||
| reasoning_effort?: "high" | "max" | ||
| } | ||
| const deepSeekV4ThinkingModels = new Set(["deepseek-v4-flash", "deepseek-v4-pro"]) | ||
| const supportsDeepSeekThinkingToggle = (modelId: string) => deepSeekV4ThinkingModels.has(modelId) | ||
| // Only known V4 models and the legacy reasoner alias support DeepSeek's | ||
| // thinking fields. Custom model IDs still fall back to default metadata, but | ||
| // should not receive V4-only request parameters. | ||
| const isDeepSeekThinkingEnabled = (modelId: string, options: ApiHandlerOptions) => { | ||
| if (options.enableReasoningEffort === false || options.reasoningEffort === "disable") { | ||
| return false | ||
| } | ||
| return modelId === "deepseek-reasoner" || supportsDeepSeekThinkingToggle(modelId) | ||
| } | ||
| const normalizeDeepSeekReasoningEffort = (reasoningEffort?: string): "high" | "max" | undefined => { | ||
| if (!reasoningEffort || reasoningEffort === "disable") { | ||
| return undefined | ||
| } | ||
| // DeepSeek currently maps low/medium to high and xhigh to max in thinking mode. | ||
| return reasoningEffort === "xhigh" ? "max" : "high" | ||
| } | ||
| // Use the computed maxTokens from getModelParams rather than raw model metadata. | ||
| // V4 advertises a 384K maximum output, but the project convention caps most | ||
| // models to 20% of context unless the user explicitly overrides modelMaxTokens. | ||
| const addDeepSeekMaxTokensIfNeeded = ( | ||
| requestOptions: DeepSeekChatCompletionParams, | ||
| options: ApiHandlerOptions, | ||
| computedMaxTokens?: number, | ||
| ) => { | ||
| if (options.includeMaxTokens === true) { | ||
| requestOptions.max_completion_tokens = options.modelMaxTokens || computedMaxTokens | ||
| } | ||
| } | ||
| export class DeepSeekHandler extends OpenAiHandler { | ||
| @@ -53,14 +91,19 @@ export class DeepSeekHandler extends OpenAiHandler { | ||
| metadata?: ApiHandlerCreateMessageMetadata, | ||
| ): ApiStream { | ||
| const modelId = this.options.apiModelId ?? deepSeekDefaultModelId | ||
| const { info: modelInfo } = this.getModel() | ||
| const { info: modelInfo, temperature, reasoningEffort, maxTokens } = this.getModel() | ||
| // Check if this is a thinking-enabled model (deepseek-reasoner) | ||
| const isThinkingModel = modelId.includes("deepseek-reasoner") | ||
| const isThinkingModel = isDeepSeekThinkingEnabled(modelId, this.options) | ||
| const thinking = supportsDeepSeekThinkingToggle(modelId) | ||
| ? ({ type: isThinkingModel ? "enabled" : "disabled" } as const) | ||
| : isThinkingModel | ||
| ? ({ type: "enabled" } as const) | ||
| : undefined | ||
| const deepSeekReasoningEffort = isThinkingModel ? normalizeDeepSeekReasoningEffort(reasoningEffort) : undefined | ||
| // Convert messages to R1 format (merges consecutive same-role messages) | ||
| // This is required for DeepSeek which does not support successive messages with the same role | ||
| // For thinking models (deepseek-reasoner), enable mergeToolResultText to preserve reasoning_content | ||
| // For thinking models, enable mergeToolResultText to preserve reasoning_content | ||
| // during tool call sequences. Without this, environment_details text after tool_results would | ||
| // create user messages that cause DeepSeek to drop all previous reasoning_content. | ||
| // See: https://api-docs.deepseek.com/guides/thinking_mode | ||
| @@ -70,27 +113,26 @@ export class DeepSeekHandler extends OpenAiHandler { | ||
| const requestOptions: DeepSeekChatCompletionParams = { | ||
| model: modelId, | ||
| temperature: this.options.modelTemperature ?? DEEP_SEEK_DEFAULT_TEMPERATURE, | ||
| ...(!isThinkingModel && { temperature: temperature ?? DEEP_SEEK_DEFAULT_TEMPERATURE }), | ||
| messages: convertedMessages, | ||
| stream: true as const, | ||
| stream_options: { include_usage: true }, | ||
| // Enable thinking mode for deepseek-reasoner or when tools are used with thinking model | ||
| ...(isThinkingModel && { thinking: { type: "enabled" } }), | ||
| ...(thinking && { thinking }), | ||
| ...(deepSeekReasoningEffort && { reasoning_effort: deepSeekReasoningEffort }), | ||
| tools: this.convertToolsForOpenAI(metadata?.tools), | ||
| tool_choice: metadata?.tool_choice, | ||
| parallel_tool_calls: metadata?.parallelToolCalls ?? true, | ||
| } | ||
| // Add max_tokens if needed | ||
| this.addMaxTokensIfNeeded(requestOptions, modelInfo) | ||
| addDeepSeekMaxTokensIfNeeded(requestOptions, this.options, maxTokens) | ||
| // Check if base URL is Azure AI Inference (for DeepSeek via Azure) | ||
| const isAzureAiInference = this._isAzureAiInference(this.options.deepSeekBaseUrl) | ||
| let stream | ||
| try { | ||
| stream = await this.client.chat.completions.create( | ||
| requestOptions, | ||
| requestOptions as OpenAI.Chat.Completions.ChatCompletionCreateParamsStreaming, | ||
edelauna marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| isAzureAiInference ? { path: OPENAI_AZURE_AI_INFERENCE_PATH } : {}, | ||
| ) | ||
| } catch (error) { | ||
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.