mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-05 08:10:14 +00:00
fix: add support for additional DeepSeek models in OpenRouter
- Add deepseek-chat prefix detection for V3 chat models (deepseek-chat-v3.1, deepseek-chat-v3-0324, etc.) - Add deepseek-prover prefix detection for prover/reasoning models (deepseek-prover-v2) - Prover models now correctly use R1 format like other reasoning models - Chat models use standard format with native tool support - Added comprehensive tests for new model patterns
This commit is contained in:
parent
7ce8ff1b9f
commit
5e934f0a9c
3 changed files with 146 additions and 13 deletions
|
|
@ -339,8 +339,8 @@ describe("OpenRouterHandler", () => {
|
|||
})
|
||||
})
|
||||
|
||||
describe("DeepSeek V3 Model Handling", () => {
|
||||
// Note: OpenRouter only has deepseek/deepseek-v3.2, not deepseek/deepseek-v3
|
||||
describe("DeepSeek Model Handling", () => {
|
||||
// Test DeepSeek V3.2 model (uses standard format)
|
||||
it("should NOT use R1 format for DeepSeek V3.2 models", async () => {
|
||||
const deepseek32Handler = new OpenRouterHandler({
|
||||
...mockOptions,
|
||||
|
|
@ -422,5 +422,131 @@ describe("OpenRouterHandler", () => {
|
|||
undefined,
|
||||
)
|
||||
})
|
||||
|
||||
// Test DeepSeek Chat V3.1 model (uses standard format, NOT R1)
|
||||
it("should NOT use R1 format for DeepSeek Chat V3.1 models", async () => {
|
||||
const deepseekChatHandler = new OpenRouterHandler({
|
||||
...mockOptions,
|
||||
openRouterModelId: "deepseek/deepseek-chat-v3.1",
|
||||
})
|
||||
|
||||
const mockStream = {
|
||||
[Symbol.asyncIterator]: async function* () {
|
||||
yield {
|
||||
choices: [{ delta: { content: "test" }, finish_reason: null }],
|
||||
usage: null,
|
||||
}
|
||||
yield {
|
||||
choices: [{ delta: {}, finish_reason: "stop" }],
|
||||
usage: { prompt_tokens: 10, completion_tokens: 5 },
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
const mockCreate = vitest.fn().mockResolvedValue(mockStream)
|
||||
;(OpenAI as any).prototype.chat = {
|
||||
completions: { create: mockCreate },
|
||||
} as any
|
||||
|
||||
const generator = deepseekChatHandler.createMessage("system prompt", [])
|
||||
const chunks = []
|
||||
for await (const chunk of generator) {
|
||||
chunks.push(chunk)
|
||||
}
|
||||
|
||||
// Verify that the messages were NOT converted to R1 format (system role preserved)
|
||||
expect(mockCreate).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
messages: expect.arrayContaining([
|
||||
expect.objectContaining({ role: "system", content: expect.anything() }),
|
||||
]),
|
||||
}),
|
||||
undefined,
|
||||
)
|
||||
})
|
||||
|
||||
// Test DeepSeek R1-0528 variant (uses R1 format)
|
||||
it("should use R1 format for DeepSeek R1-0528 models", async () => {
|
||||
const deepseekR1Handler = new OpenRouterHandler({
|
||||
...mockOptions,
|
||||
openRouterModelId: "deepseek/deepseek-r1-0528",
|
||||
})
|
||||
|
||||
const mockStream = {
|
||||
[Symbol.asyncIterator]: async function* () {
|
||||
yield {
|
||||
choices: [{ delta: { content: "test" }, finish_reason: null }],
|
||||
usage: null,
|
||||
}
|
||||
yield {
|
||||
choices: [{ delta: {}, finish_reason: "stop" }],
|
||||
usage: { prompt_tokens: 10, completion_tokens: 5 },
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
const mockCreate = vitest.fn().mockResolvedValue(mockStream)
|
||||
;(OpenAI as any).prototype.chat = {
|
||||
completions: { create: mockCreate },
|
||||
} as any
|
||||
|
||||
const generator = deepseekR1Handler.createMessage("system prompt", [])
|
||||
const chunks = []
|
||||
for await (const chunk of generator) {
|
||||
chunks.push(chunk)
|
||||
}
|
||||
|
||||
// Verify that the messages WERE converted to R1 format (user role instead of system)
|
||||
expect(mockCreate).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
messages: expect.arrayContaining([
|
||||
expect.objectContaining({ role: "user", content: expect.anything() }),
|
||||
]),
|
||||
}),
|
||||
undefined,
|
||||
)
|
||||
})
|
||||
|
||||
// Test DeepSeek Prover V2 model (uses R1 format as it's a reasoning model)
|
||||
it("should use R1 format for DeepSeek Prover V2 models", async () => {
|
||||
const deepseekProverHandler = new OpenRouterHandler({
|
||||
...mockOptions,
|
||||
openRouterModelId: "deepseek/deepseek-prover-v2",
|
||||
})
|
||||
|
||||
const mockStream = {
|
||||
[Symbol.asyncIterator]: async function* () {
|
||||
yield {
|
||||
choices: [{ delta: { content: "test" }, finish_reason: null }],
|
||||
usage: null,
|
||||
}
|
||||
yield {
|
||||
choices: [{ delta: {}, finish_reason: "stop" }],
|
||||
usage: { prompt_tokens: 10, completion_tokens: 5 },
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
const mockCreate = vitest.fn().mockResolvedValue(mockStream)
|
||||
;(OpenAI as any).prototype.chat = {
|
||||
completions: { create: mockCreate },
|
||||
} as any
|
||||
|
||||
const generator = deepseekProverHandler.createMessage("system prompt", [])
|
||||
const chunks = []
|
||||
for await (const chunk of generator) {
|
||||
chunks.push(chunk)
|
||||
}
|
||||
|
||||
// Verify that the messages WERE converted to R1 format (user role instead of system)
|
||||
expect(mockCreate).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
messages: expect.arrayContaining([
|
||||
expect.objectContaining({ role: "user", content: expect.anything() }),
|
||||
]),
|
||||
}),
|
||||
undefined,
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -266,12 +266,12 @@ export const parseOpenRouterModel = ({
|
|||
modelInfo.maxTokens = 32768
|
||||
}
|
||||
|
||||
// Configure DeepSeek V3 models properly
|
||||
// Configure DeepSeek V3/Chat models properly
|
||||
// These models support standard tool calling but NOT R1 format
|
||||
// OpenRouter uses deepseek/deepseek-v3 and deepseek/deepseek-v3.2 naming
|
||||
// OpenRouter uses deepseek/deepseek-v3, deepseek/deepseek-v3.2, deepseek/deepseek-chat-v3.1, etc.
|
||||
if (
|
||||
id.startsWith("deepseek/deepseek-v3") || // Matches deepseek/deepseek-v3, deepseek/deepseek-v3.2, etc.
|
||||
id === "deepseek/deepseek-chat"
|
||||
id.startsWith("deepseek/deepseek-v3") || // Matches deepseek/deepseek-v3, deepseek/deepseek-v3.2, deepseek/deepseek-v3.1-terminus, etc.
|
||||
id.startsWith("deepseek/deepseek-chat") // Matches deepseek/deepseek-chat, deepseek/deepseek-chat-v3.1, deepseek/deepseek-chat-v3-0324, etc.
|
||||
) {
|
||||
// Ensure these models are marked as supporting native tools
|
||||
// but NOT reasoning format (they're not R1 models)
|
||||
|
|
|
|||
|
|
@ -135,9 +135,13 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH
|
|||
...convertToOpenAiMessages(messages),
|
||||
]
|
||||
|
||||
// DeepSeek R1 models require user instead of system role.
|
||||
// Note: DeepSeek V3 models (deepseek-v3, deepseek-v3.2, etc.) do NOT use R1 format
|
||||
if (modelId.startsWith("deepseek/deepseek-r1") || modelId === "perplexity/sonar-reasoning") {
|
||||
// DeepSeek R1 and Prover models require user instead of system role.
|
||||
// Note: DeepSeek V3/Chat models (deepseek-v3, deepseek-v3.2, deepseek-chat-v3.1, etc.) do NOT use R1 format
|
||||
if (
|
||||
modelId.startsWith("deepseek/deepseek-r1") ||
|
||||
modelId.startsWith("deepseek/deepseek-prover") ||
|
||||
modelId === "perplexity/sonar-reasoning"
|
||||
) {
|
||||
openAiMessages = convertToR1Format([{ role: "user", content: systemPrompt }, ...messages])
|
||||
}
|
||||
|
||||
|
|
@ -389,12 +393,15 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH
|
|||
info = this.endpoints[this.options.openRouterSpecificProvider]
|
||||
}
|
||||
|
||||
// Only DeepSeek R1 models use special temperature and topP settings
|
||||
// DeepSeek V3 models (v3, v3.2, etc.) use standard settings
|
||||
const isDeepSeekR1 = id.startsWith("deepseek/deepseek-r1") || id === "perplexity/sonar-reasoning"
|
||||
// Only DeepSeek R1 and Prover models use special temperature and topP settings
|
||||
// DeepSeek V3/Chat models (v3, v3.2, chat-v3.1, etc.) use standard settings
|
||||
const isDeepSeekR1 =
|
||||
id.startsWith("deepseek/deepseek-r1") ||
|
||||
id.startsWith("deepseek/deepseek-prover") ||
|
||||
id === "perplexity/sonar-reasoning"
|
||||
const isDeepSeekV3 =
|
||||
id.startsWith("deepseek/deepseek-v3") || // Matches deepseek/deepseek-v3, deepseek/deepseek-v3.2, etc.
|
||||
id === "deepseek/deepseek-chat"
|
||||
id.startsWith("deepseek/deepseek-chat") // Matches deepseek/deepseek-chat, deepseek/deepseek-chat-v3.1, etc.
|
||||
|
||||
const params = getModelParams({
|
||||
format: "openrouter",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue