Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughAdds reasoning_content support to convertToOpenAiMessages, including extraction from reasoning content blocks and preservation on outgoing assistant messages before tool_calls. Updates unit tests, DeepSeek fixtures, and e2e capture logic to verify the field round-trips into subsequent requests. Changesreasoning_content round-trip
Sequence Diagram(s)sequenceDiagram
participant AssistantMessage
participant convertToOpenAiMessages
participant OutgoingRequest
AssistantMessage->>convertToOpenAiMessages: top-level reasoning_content or reasoning block
convertToOpenAiMessages->>convertToOpenAiMessages: extract fallback reasoning text
convertToOpenAiMessages->>OutgoingRequest: set reasoning_content before tool_calls
OutgoingRequest->>OutgoingRequest: carry reasoning_content to next API call
Estimated code review effort🎯 2 (Simple) | ⏱️ ~15 minutes Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/api/transform/openai-format.ts (1)
462-481: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winMultiple reasoning blocks in one turn will silently drop earlier reasoning text.
extractedReasoningis overwritten on every matching"reasoning"block rather than accumulated, so only the last block's text survives. Since the PR explicitly targets DeepSeek/Z.ai interleaved thinking (reasoning interspersed with tool calls in the same turn), a turn with more than one reasoning segment will lose all but the final one when round-tripped back to the API.♻️ Proposed fix: accumulate instead of overwrite
- let extractedReasoning: string | undefined + const extractedReasoningParts: string[] = [] const { nonToolMessages, toolMessages } = anthropicMessage.content.reduce<{ nonToolMessages: (Anthropic.TextBlockParam | Anthropic.ImageBlockParam)[] toolMessages: Anthropic.ToolUseBlockParam[] }>( (acc, part) => { if (part.type === "tool_use") { acc.toolMessages.push(part) } else if (part.type === "text" || part.type === "image") { acc.nonToolMessages.push(part) } else if ((part as any).type === "reasoning" && (part as any).text) { - // Extract reasoning stored as a content block (DeepSeek / Z.ai interleaved thinking). - // Must be passed back as top-level reasoning_content so providers like DeepSeek - // don't reject the request with "reasoning_content must be passed back to the API". - extractedReasoning = (part as any).text + extractedReasoningParts.push((part as any).text) } // assistant cannot send tool_result messages return acc }, { nonToolMessages: [], toolMessages: [] }, ) + const extractedReasoning = extractedReasoningParts.length > 0 ? extractedReasoningParts.join("\n") : undefined🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/api/transform/openai-format.ts` around lines 462 - 481, In openai-format.ts, the reasoning extraction in the anthropicMessage.content reduce currently overwrites extractedReasoning on each "reasoning" block, so earlier segments are lost. Update the reducer logic in the nonToolMessages/toolMessages extraction path to accumulate all reasoning text blocks (preserving order) instead of replacing the previous value, and ensure the final reasoning_content passed back for DeepSeek/Z.ai interleaved thinking includes every reasoning block found in the turn.
🧹 Nitpick comments (1)
apps/vscode-e2e/src/suite/providers/deepseek-v4.test.ts (1)
382-395: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winSolid regression assertion for the round-trip fix.
Existence check on
secondRequestbefore asserting onhasReasoningContentInHistoryavoids a brittle false-positive/undefined failure. Consider also assertinghasReasoningContentInHistoryisfalseon the corresponding reasoning-off probe's second request, to guard against the flag becoming a tautology (e.g., always true due to a capture bug).🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/vscode-e2e/src/suite/providers/deepseek-v4.test.ts` around lines 382 - 395, The regression check in deepseek-v4.test.ts should not only verify that the reasoning-enabled flow preserves reasoning_content on the second request via secondRequest.hasReasoningContentInHistory, but also guard against a capture bug by asserting the equivalent second request in the reasoning-off probe keeps that flag false. Use the existing probe/request objects in the DeepSeek test suite to add the negative assertion alongside the current positive one so the flag is validated in both modes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@src/api/transform/openai-format.ts`:
- Around line 462-481: In openai-format.ts, the reasoning extraction in the
anthropicMessage.content reduce currently overwrites extractedReasoning on each
"reasoning" block, so earlier segments are lost. Update the reducer logic in the
nonToolMessages/toolMessages extraction path to accumulate all reasoning text
blocks (preserving order) instead of replacing the previous value, and ensure
the final reasoning_content passed back for DeepSeek/Z.ai interleaved thinking
includes every reasoning block found in the turn.
---
Nitpick comments:
In `@apps/vscode-e2e/src/suite/providers/deepseek-v4.test.ts`:
- Around line 382-395: The regression check in deepseek-v4.test.ts should not
only verify that the reasoning-enabled flow preserves reasoning_content on the
second request via secondRequest.hasReasoningContentInHistory, but also guard
against a capture bug by asserting the equivalent second request in the
reasoning-off probe keeps that flag false. Use the existing probe/request
objects in the DeepSeek test suite to add the negative assertion alongside the
current positive one so the flag is validated in both modes.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 9edf7d50-fd91-4a2f-9e82-45ae5020c01e
📒 Files selected for processing (5)
apps/vscode-e2e/fixtures/deepseek-v4.jsonapps/vscode-e2e/src/suite/providers/deepseek-v4.test.tssrc/api/providers/__tests__/openai.spec.tssrc/api/transform/__tests__/openai-format.spec.tssrc/api/transform/openai-format.ts
taltas
left a comment
There was a problem hiding this comment.
Clean PR, except one question with the typing.
| } | ||
| } | ||
| } else if (anthropicMessage.role === "assistant") { | ||
| const messageWithDetails = anthropicMessage as any |
There was a problem hiding this comment.
I am not a big fan of this any here... maybe we should better define the type here? It's not really a blocker, but something to consider.
Related GitHub Issue
Closes: #201
Description
When DeepSeek thinking mode is active, the API requires
reasoning_contentto be passed back on every assistant message in conversation history. Without it, the API returns HTTP 400:The reasoning_content in the thinking mode must be passed back to the API.Root cause — two bugs, one symptom:
convertToOpenAiMessages(used by the generic OpenAI-compatible provider path) silently droppedreasoningcontent blocks and never setreasoning_contenton outgoing messages. This is the primary fix.aimock fixture format — the e2e fixtures had
reasoning+toolCallsbut nocontent, so aimock classified them asToolCallResponse(which ignoresreasoning) instead ofContentWithToolCallsResponse. Fixed by adding"content": "".What changed:
src/api/transform/openai-format.ts—convertToOpenAiMessagesnow extractsreasoning_contentfrom both the top-level field (already round-tripped) and{ type: "reasoning" }content blocks (stored by Task.ts during streaming), and sets it on the outgoing assistant message.src/api/transform/__tests__/openai-format.spec.ts— 5 new unit tests covering the round-trip: string-content path, array-content path, array-content with tool calls (the exact failure case), preference ordering, and absent-reasoning no-op.src/api/providers/__tests__/openai.spec.ts— provider-level integration test:OpenAiHandler.createMessagewithpreserveReasoning: trueand an assistant message containing areasoningblock + tool call; assertsreasoning_contentappears in the body sent to the OpenAI client. This directly exercises the fixedOpenAiHandler → convertToOpenAiMessagespath.apps/vscode-e2e/fixtures/deepseek-v4.json— added"content": ""to reasoning-on fixtures so aimock routes them throughbuildContentWithToolCallsChunksand streamsreasoning_contentin SSE deltas.apps/vscode-e2e/src/suite/providers/deepseek-v4.test.ts— e2e regression guard for the native DeepSeek provider path: assertshasReasoningContentInHistoryon the second request (after the tool call), provingreasoning_contentfrom turn 1 survives into turn 2's history.Coverage note: The native
DeepSeekHandler → convertToR1Formatpath was already correct before this PR. The e2e test guards that path. The fix toconvertToOpenAiMessagesis guarded by unit tests + the new provider-level integration test inopenai.spec.ts.Test Procedure
Unit tests:
All 408 test files pass (6,584 tests).
E2e tests (mock):
All 4 DeepSeek V4 provider tests pass, including the
reasoning-onprobes that asserthasReasoningContentInHistoryon the second request.Live API validation (performed during development):
content: ""+reasoning_content: "..."+tool_calls: [...]on turn 1 tool-call responses.reasoning_contentround-tripped returns HTTP 200.Pre-Submission Checklist
Summary by CodeRabbit
New Features
reasoning_contentin OpenAI-compatible message formatting (including DeepSeek/Z.ai thinking mode and tool+reasoning scenarios).Bug Fixes
Tests / Chores
reasoningfield.