Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions src/api/providers/__tests__/base-openai-compatible-provider.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,106 @@ describe("BaseOpenAiCompatibleProvider", () => {
})
})

describe("reasoning_content field", () => {
it("should filter out whitespace-only reasoning_content", async () => {
mockCreate.mockImplementationOnce(() => {
return {
[Symbol.asyncIterator]: () => ({
next: vi
.fn()
.mockResolvedValueOnce({
done: false,
value: { choices: [{ delta: { reasoning_content: "\n" } }] },
})
.mockResolvedValueOnce({
done: false,
value: { choices: [{ delta: { reasoning_content: " " } }] },
})
.mockResolvedValueOnce({
done: false,
value: { choices: [{ delta: { reasoning_content: "\t\n " } }] },
})
.mockResolvedValueOnce({
done: false,
value: { choices: [{ delta: { content: "Regular content" } }] },
})
.mockResolvedValueOnce({ done: true }),
}),
}
})

const stream = handler.createMessage("system prompt", [])
const chunks = []
for await (const chunk of stream) {
chunks.push(chunk)
}

// Should only have the regular content, not the whitespace-only reasoning
expect(chunks).toEqual([{ type: "text", text: "Regular content" }])
})

it("should yield non-empty reasoning_content", async () => {
mockCreate.mockImplementationOnce(() => {
return {
[Symbol.asyncIterator]: () => ({
next: vi
.fn()
.mockResolvedValueOnce({
done: false,
value: { choices: [{ delta: { reasoning_content: "Thinking step 1" } }] },
})
.mockResolvedValueOnce({
done: false,
value: { choices: [{ delta: { reasoning_content: "\n" } }] },
})
.mockResolvedValueOnce({
done: false,
value: { choices: [{ delta: { reasoning_content: "Thinking step 2" } }] },
})
.mockResolvedValueOnce({ done: true }),
}),
}
})

const stream = handler.createMessage("system prompt", [])
const chunks = []
for await (const chunk of stream) {
chunks.push(chunk)
}

// Should only yield the non-empty reasoning content
expect(chunks).toEqual([
{ type: "reasoning", text: "Thinking step 1" },
{ type: "reasoning", text: "Thinking step 2" },
])
})

it("should handle reasoning_content with leading/trailing whitespace", async () => {
mockCreate.mockImplementationOnce(() => {
return {
[Symbol.asyncIterator]: () => ({
next: vi
.fn()
.mockResolvedValueOnce({
done: false,
value: { choices: [{ delta: { reasoning_content: " content with spaces " } }] },
})
.mockResolvedValueOnce({ done: true }),
}),
}
})

const stream = handler.createMessage("system prompt", [])
const chunks = []
for await (const chunk of stream) {
chunks.push(chunk)
}

// Should yield reasoning with spaces (only pure whitespace is filtered)
expect(chunks).toEqual([{ type: "reasoning", text: " content with spaces " }])
})
})

describe("Basic functionality", () => {
it("should create stream with correct parameters", async () => {
mockCreate.mockImplementationOnce(() => {
Expand Down
7 changes: 5 additions & 2 deletions src/api/providers/base-openai-compatible-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,11 @@ export abstract class BaseOpenAiCompatibleProvider<ModelName extends string>
}
}

if (delta && "reasoning_content" in delta && delta.reasoning_content) {
yield { type: "reasoning", text: (delta.reasoning_content as string | undefined) || "" }
if (delta && "reasoning_content" in delta) {
const reasoning_content = (delta.reasoning_content as string | undefined) || ""
if (reasoning_content?.trim()) {
yield { type: "reasoning", text: reasoning_content }
}
}
Comment on lines +127 to 132
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change correctly filters out whitespace-only reasoning content. However, there's no test coverage for this new behavior. Consider adding a test case with reasoning_content: "\n" to verify the filtering works and prevent regression.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@roomote add the test please

Copy link

@roomote roomote bot Nov 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See this task on Roo Code Cloud

Added test coverage for whitespace-only reasoning_content filtering. All local checks passed.

View commit | Revert commit


if (chunk.usage) {
Expand Down