mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
fix: strip thinking blocks from qwen-code completePrompt responses
qwen3-coder models include <think>...</think> blocks in their responses. The completePrompt() method (used for prompt enhancement) was returning these blocks as-is, causing the enhanced prompt to either be empty (triggering "Failed to enhance prompt" toast) or contain raw thinking markup. This strips <think> blocks from the response content before returning, consistent with how createMessage() already handles them for streaming. Closes #12102
This commit is contained in:
parent
7adbfec2a4
commit
16ea03114b
2 changed files with 150 additions and 1 deletions
146
src/api/providers/__tests__/qwen-code-complete-prompt.spec.ts
Normal file
146
src/api/providers/__tests__/qwen-code-complete-prompt.spec.ts
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
// npx vitest run api/providers/__tests__/qwen-code-complete-prompt.spec.ts
|
||||
|
||||
// Mock filesystem - must come before other imports
|
||||
vi.mock("node:fs", () => ({
|
||||
promises: {
|
||||
readFile: vi.fn(),
|
||||
writeFile: vi.fn(),
|
||||
},
|
||||
}))
|
||||
|
||||
const mockCreate = vi.fn()
|
||||
vi.mock("openai", () => {
|
||||
return {
|
||||
__esModule: true,
|
||||
default: vi.fn().mockImplementation(() => ({
|
||||
apiKey: "test-key",
|
||||
baseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1",
|
||||
chat: {
|
||||
completions: {
|
||||
create: mockCreate,
|
||||
},
|
||||
},
|
||||
})),
|
||||
}
|
||||
})
|
||||
|
||||
import { promises as fs } from "node:fs"
|
||||
import { QwenCodeHandler } from "../qwen-code"
|
||||
import type { ApiHandlerOptions } from "../../../shared/api"
|
||||
|
||||
describe("QwenCodeHandler completePrompt", () => {
|
||||
let handler: QwenCodeHandler
|
||||
let mockOptions: ApiHandlerOptions & { qwenCodeOauthPath?: string }
|
||||
|
||||
const validCredentials = {
|
||||
access_token: "test-access-token",
|
||||
refresh_token: "test-refresh-token",
|
||||
token_type: "Bearer",
|
||||
expiry_date: Date.now() + 3600000,
|
||||
resource_url: "https://dashscope.aliyuncs.com/compatible-mode/v1",
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
|
||||
mockOptions = {
|
||||
apiModelId: "qwen3-coder-plus",
|
||||
qwenCodeOauthPath: "/tmp/test-creds.json",
|
||||
}
|
||||
|
||||
handler = new QwenCodeHandler(mockOptions)
|
||||
;(fs.readFile as ReturnType<typeof vi.fn>).mockResolvedValue(JSON.stringify(validCredentials))
|
||||
})
|
||||
|
||||
it("should return plain text content as-is", async () => {
|
||||
mockCreate.mockResolvedValueOnce({
|
||||
choices: [
|
||||
{
|
||||
message: {
|
||||
content: "Here is your enhanced prompt with more details.",
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
const result = await handler.completePrompt("Enhance this prompt")
|
||||
expect(result).toBe("Here is your enhanced prompt with more details.")
|
||||
})
|
||||
|
||||
it("should strip <think> blocks from response content", async () => {
|
||||
mockCreate.mockResolvedValueOnce({
|
||||
choices: [
|
||||
{
|
||||
message: {
|
||||
content:
|
||||
"<think>Let me analyze this prompt and think about how to enhance it...</think>Here is your enhanced prompt with more details.",
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
const result = await handler.completePrompt("Enhance this prompt")
|
||||
expect(result).toBe("Here is your enhanced prompt with more details.")
|
||||
})
|
||||
|
||||
it("should strip multiple <think> blocks from response content", async () => {
|
||||
mockCreate.mockResolvedValueOnce({
|
||||
choices: [
|
||||
{
|
||||
message: {
|
||||
content: "<think>First thought...</think>Part one. <think>Second thought...</think>Part two.",
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
const result = await handler.completePrompt("Enhance this prompt")
|
||||
expect(result).toBe("Part one. Part two.")
|
||||
})
|
||||
|
||||
it("should handle multiline <think> blocks", async () => {
|
||||
mockCreate.mockResolvedValueOnce({
|
||||
choices: [
|
||||
{
|
||||
message: {
|
||||
content:
|
||||
"<think>\nLet me think about this.\nI need to consider multiple things.\n</think>\nThe enhanced prompt.",
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
const result = await handler.completePrompt("Enhance this prompt")
|
||||
expect(result).toBe("The enhanced prompt.")
|
||||
})
|
||||
|
||||
it("should return empty string when content is only a think block", async () => {
|
||||
mockCreate.mockResolvedValueOnce({
|
||||
choices: [
|
||||
{
|
||||
message: {
|
||||
content: "<think>Only thinking, no actual content.</think>",
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
const result = await handler.completePrompt("Enhance this prompt")
|
||||
expect(result).toBe("")
|
||||
})
|
||||
|
||||
it("should return empty string when message content is null", async () => {
|
||||
mockCreate.mockResolvedValueOnce({
|
||||
choices: [
|
||||
{
|
||||
message: {
|
||||
content: null,
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
const result = await handler.completePrompt("Enhance this prompt")
|
||||
expect(result).toBe("")
|
||||
})
|
||||
})
|
||||
|
|
@ -340,6 +340,9 @@ export class QwenCodeHandler extends BaseProvider implements SingleCompletionHan
|
|||
|
||||
const response = await this.callApiWithRetry(() => client.chat.completions.create(requestOptions))
|
||||
|
||||
return response.choices[0]?.message.content || ""
|
||||
const content = response.choices[0]?.message.content || ""
|
||||
|
||||
// Strip <think>...</think> blocks that qwen3-coder thinking models include
|
||||
return content.replace(/<think>[\s\S]*?<\/think>/g, "").trim()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue