You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
ZCode sends assistant text as the Responses message shorthand — {"role":"assistant","content":[...]} with no type. isAssistantTurnItem recognized only a typed message, so the shorthand closed the assistant turn:
before: [user] [assistant text] | [function_call] [output]
turn split; the bare-tool-call placeholder lands after the text
after: [user] [assistant text] [function_call] [output]
one turn; the placeholder lands at the head, before the text
DeepSeek's strict plaintext replay contract then rejects every continuation of that session with The reasoning_text in the thinking mode must be passed back to the API. Switching models away and back does not help, because the client keeps rebuilding the same history shape.
The fix normalizes the item type the same way the Responses parser already does (type ?? (role present ? "message" : undefined)), so a shorthand with role: "assistant" belongs to the surrounding assistant turn. The placeholder then precedes the whole turn — the shape the typed-message case already produces and DeepSeek accepts.
Scope: isAssistantTurnItem is used only by backfillBareToolCallTurnReasoning, which runs only for providers that declare both preserveResponsesReasoningContent and requiresAdjacentResponsesToolResults. Other providers keep byte-identical behavior.
Verification
Added two cases to the existing regression file for this contract (tests/providers/deepseek-bare-tool-call-replay.test.ts): the turn-grouping helper, and the DeepSeek passthrough wire ending up as message, reasoning, undefined (shorthand), function_call, function_call_output.
bun test ./tests/providers/deepseek-bare-tool-call-replay.test.ts
# 8 pass, 0 fail
bun test ./tests/test-layout.test.ts
# 2 pass, 0 fail
bun test ./tests/ci-workflows/file-size-ratchet.test.ts
# 9 pass, 0 fail
bun run typecheck
# No type errors in 2,259 files
Before/after on the wire: replaying a captured failing ZCode request body against a live proxy returned HTTP 400 with the message above; the same body returns HTTP 200 after this change, including with stream: true.
Full-suite exception: bun run test was not run locally. This is a two-file change — one helper in a Responses adapter and its own regression file — and the focused test above exercises the changed behavior. The two gates that can reject a test-case addition (test layout, file-size ratchet) were run explicitly. Remaining coverage is left to the sharded PR CI.
Checklist
Scope stays focused and avoids unrelated cleanup.
Docs or release notes were updated when needed. (No user-facing option or documented behavior changed.)
Security-sensitive changes were reviewed for secrets, auth, and unsafe defaults. (No auth, credential, workflow, or dependency surface touched.)
Review readiness checklist
This PR stays in draft until every box below is ticked. Tick all four boxes once the requirements are met:
Required local validation passed; commands, results, and any full-suite exception are documented.
I pushed my PR to a recent dev commit (at most 10 behind; a maintainer may still ask for the exact tip before merge).
I resolved all correct Codex and CodeRabbit findings.
My PR is ready for review.
Summary by CodeRabbit
Bug Fixes
Improved compatibility with Responses messages that omit an explicit type. Assistant messages are now correctly recognized during tool-call replay, and their original format is preserved when sent to DeepSeek.
Added regression coverage for reasoning backfill when a shorthand assistant message appears before a tool call.
…l turn
ZCode sends assistant text as the Responses message shorthand
({role, content} with no type). isAssistantTurnItem only recognized a typed
message, so the shorthand closed the assistant turn and
backfillBareToolCallTurnReasoning inserted its placeholder after the text
instead of at the head of the turn. DeepSeek's thinking mode rejects that
ordering with "The reasoning_text in the thinking mode must be passed back to
the API", and every continuation of the session fails the same way.
Normalize the item type the way the Responses parser already does, so a
shorthand with role=assistant belongs to the surrounding assistant turn. The
placeholder then precedes the whole turn, matching the typed-message shape
that already passes.
Reviewing files that changed from the base of the PR and between ca443ca and 16149ea.
You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.
Use the checkbox below for a quick retry:
Trigger review
No actionable comments were generated in the recent review.
Walkthrough
isAssistantTurnItem now accepts message objects that have a role but no type. Regression tests cover reasoning backfill and DeepSeek wire output for this shorthand message shape.
isAssistantTurnItem now accepts objects with a role and no type. Tests check that placeholder reasoning appears before the shorthand assistant message and tool call, and that the shorthand message's type remains undefined in the wire output.
Untyped assistant messages remain grouped with their tool calls. No material merge risk was identified.
Pre-merge checks: 5
Check name
Status
Explanation
Description Check
Check skipped - CodeRabbit’s high-level summary is enabled.
Title check
The title names the main change: untyped assistant messages (shorthand {role, content} items) are now kept inside their tool-call turn. The raw summary says isAssistantTurnItem now recognizes role-bea…
Docstring Coverage
Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentat…
Linked Issues check
Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check
Check skipped because no linked issues were found for this pull request.
Full details: Title check
Explanation
The title names the main change: untyped assistant messages (shorthand {role, content} items) are now kept inside their tool-call turn. The raw summary says isAssistantTurnItem now recognizes role-bearing items without a type as messages, and the PR objectives describe the same fix for backfillBareToolCallTurnReasoning placement. The title is specific and matches the changeset, so it passes.
Full details: Docstring Coverage
Explanation
Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 1 functions across 2 files.
Finishing Touches
Generate unit tests (beta)
Create a new PR
Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
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.
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.
Maintainer integration into dev (account lidge-jun) at head 16149ea76bb25d5707e03a71f74399e8967c2171. The PR is moved out of draft by a maintainer for this integration (the checklist gate re-drafted it after a maintainer dev-merge push).
fix(responses): keep untyped assistant messages inside their tool-call turn.
The branch merges current dev (dev-merge only); later dev commits share no source file with it. Exact-head required CI passed: ci, enforce-target, hygiene, test 1/4–4/4.
Independent review (gpt-6.1-terra, high) on the code merged onto dev: focused tests plus layout and file-size guards 82 pass / 0 fail; narrowly scoped, no auth/credential/logging change.
No unresolved threads or changes-requested reviews.
The reason will be displayed to describe this comment to others. Learn more.
Update the mapped replay contract alongside the adapter change
This changes assistant-turn membership and DeepSeek wire ordering, but the commit updates none of the mapped structure documentation. The scoped src/AGENTS.md explicitly requires that “every doc listed for an area is updated in the same change that changes the area.” Update structure/transports/native-reasoning-retention.md to record that untyped assistant messages remain inside the tool-call turn and that the reasoning placeholder precedes their text, and review the other mapped adapter documents. Otherwise this compatibility-sensitive history shape remains documented only in implementation comments and tests rather than the required architectural contract.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
bugSomething isn't workingci:fullRun the four full Ubuntu test shards on this pull request
2 participants
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
ZCode sends assistant text as the Responses message shorthand —
{"role":"assistant","content":[...]}with notype.isAssistantTurnItemrecognized only a typedmessage, so the shorthand closed the assistant turn:DeepSeek's strict plaintext replay contract then rejects every continuation of that session with
The reasoning_text in the thinking mode must be passed back to the API. Switching models away and back does not help, because the client keeps rebuilding the same history shape.The fix normalizes the item type the same way the Responses parser already does (
type ?? (role present ? "message" : undefined)), so a shorthand withrole: "assistant"belongs to the surrounding assistant turn. The placeholder then precedes the whole turn — the shape the typed-message case already produces and DeepSeek accepts.Scope:
isAssistantTurnItemis used only bybackfillBareToolCallTurnReasoning, which runs only for providers that declare bothpreserveResponsesReasoningContentandrequiresAdjacentResponsesToolResults. Other providers keep byte-identical behavior.Verification
Added two cases to the existing regression file for this contract (
tests/providers/deepseek-bare-tool-call-replay.test.ts): the turn-grouping helper, and the DeepSeek passthrough wire ending up asmessage, reasoning, undefined (shorthand), function_call, function_call_output.Before/after on the wire: replaying a captured failing ZCode request body against a live proxy returned HTTP 400 with the message above; the same body returns HTTP 200 after this change, including with
stream: true.Full-suite exception:
bun run testwas not run locally. This is a two-file change — one helper in a Responses adapter and its own regression file — and the focused test above exercises the changed behavior. The two gates that can reject a test-case addition (test layout, file-size ratchet) were run explicitly. Remaining coverage is left to the sharded PR CI.Checklist
Review readiness checklist
This PR stays in draft until every box below is ticked. Tick all four boxes once the requirements are met:
Required local validation passed; commands, results, and any full-suite exception are documented.
I pushed my PR to a recent dev commit (at most 10 behind; a maintainer may still ask for the exact tip before merge).
I resolved all correct Codex and CodeRabbit findings.
My PR is ready for review.
Summary by CodeRabbit