mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-07 08:26:51 +00:00
fix: apply R1 format conversion to Mistral 2512 models
Extends the message format conversion logic to include Mistral 2512 models (mistralai/*-2512) which require strict role alternation between user and assistant messages, similar to DeepSeek R1 models. This fixes the API error: "After the optional system message, conversation roles must alternate user and assistant roles except for tool calls and results." - Updated openrouter.ts to detect Mistral 2512 models via regex pattern - Added test coverage for both mistral-large-2512 and devstral-2512 - Reuses existing convertToR1Format function for consistent handling Fixes #10045
This commit is contained in:
parent
f97b5155ac
commit
a81ad325bd
2 changed files with 91 additions and 1 deletions
|
|
@ -489,6 +489,90 @@ describe("OpenRouterHandler", () => {
|
|||
expect(endChunks).toHaveLength(1)
|
||||
expect(endChunks[0].id).toBe("call_openrouter_test")
|
||||
})
|
||||
|
||||
it("uses R1 format for Mistral 2512 models", async () => {
|
||||
const handler = new OpenRouterHandler({
|
||||
openRouterApiKey: "test-key",
|
||||
openRouterModelId: "mistralai/mistral-large-2512",
|
||||
})
|
||||
|
||||
const mockStream = {
|
||||
async *[Symbol.asyncIterator]() {
|
||||
yield {
|
||||
id: "test-id",
|
||||
choices: [{ delta: { content: "test response" } }],
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
const mockCreate = vitest.fn().mockResolvedValue(mockStream)
|
||||
;(OpenAI as any).prototype.chat = {
|
||||
completions: { create: mockCreate },
|
||||
} as any
|
||||
|
||||
const systemPrompt = "test system prompt"
|
||||
const messages: Anthropic.Messages.MessageParam[] = [
|
||||
{ role: "user", content: "message 1" },
|
||||
{ role: "user", content: "message 2" },
|
||||
]
|
||||
|
||||
await handler.createMessage(systemPrompt, messages).next()
|
||||
|
||||
// Verify that convertToR1Format was used by checking messages structure
|
||||
// Consecutive user messages should be merged into a single user message
|
||||
expect(mockCreate).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
messages: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
role: "user",
|
||||
// The system prompt and two user messages should be merged
|
||||
content: expect.stringContaining("test system prompt"),
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
undefined,
|
||||
)
|
||||
|
||||
// Verify that messages were merged (should have fewer messages than original)
|
||||
const callArgs = mockCreate.mock.calls[0][0]
|
||||
// Original would have 3 messages (system converted to user + 2 user messages)
|
||||
// After R1 format conversion, consecutive user messages should be merged into 1
|
||||
expect(callArgs.messages).toHaveLength(1)
|
||||
})
|
||||
|
||||
it("uses R1 format for Mistral devstral-2512 model", async () => {
|
||||
const handler = new OpenRouterHandler({
|
||||
openRouterApiKey: "test-key",
|
||||
openRouterModelId: "mistralai/devstral-2512",
|
||||
})
|
||||
|
||||
const mockStream = {
|
||||
async *[Symbol.asyncIterator]() {
|
||||
yield {
|
||||
id: "test-id",
|
||||
choices: [{ delta: { content: "test response" } }],
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
const mockCreate = vitest.fn().mockResolvedValue(mockStream)
|
||||
;(OpenAI as any).prototype.chat = {
|
||||
completions: { create: mockCreate },
|
||||
} as any
|
||||
|
||||
const systemPrompt = "test system prompt"
|
||||
const messages: Anthropic.Messages.MessageParam[] = [
|
||||
{ role: "user", content: "message 1" },
|
||||
{ role: "user", content: "message 2" },
|
||||
]
|
||||
|
||||
await handler.createMessage(systemPrompt, messages).next()
|
||||
|
||||
// Verify R1 format conversion was applied
|
||||
const callArgs = mockCreate.mock.calls[0][0]
|
||||
expect(callArgs.messages).toHaveLength(1)
|
||||
expect(callArgs.messages[0].role).toBe("user")
|
||||
})
|
||||
})
|
||||
|
||||
describe("completePrompt", () => {
|
||||
|
|
|
|||
|
|
@ -140,7 +140,13 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH
|
|||
]
|
||||
|
||||
// DeepSeek highly recommends using user instead of system role.
|
||||
if (modelId.startsWith("deepseek/deepseek-r1") || modelId === "perplexity/sonar-reasoning") {
|
||||
// Mistral 2512 models also require strict role alternation.
|
||||
const requiresR1Format =
|
||||
modelId.startsWith("deepseek/deepseek-r1") ||
|
||||
modelId === "perplexity/sonar-reasoning" ||
|
||||
/mistralai\/.*-2512/.test(modelId)
|
||||
|
||||
if (requiresR1Format) {
|
||||
openAiMessages = convertToR1Format([{ role: "user", content: systemPrompt }, ...messages])
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue