Description
Two related, verified bugs affecting every Claude Opus/Sonnet 4.6+ model
(and every 5.x family — Fable 5, Mythos 5, Sonnet 5, etc.) on the
Anthropic wire:
Bug 1: assistant-turn "prefill" 400s with no mitigation
When Gemini-format history ends on a model turn with no follow-up
(e.g. context trimming drops the next user turn, or a subagent
transcript is replayed mid-turn), the Anthropic converter forwards a
request whose last message has role: 'assistant'. Anthropic rejects
this outright on every 4.6+ model:
This model does not support assistant message prefill. The
conversation must end with a user message.
Per Anthropic's own migration documentation, this is a model-generation
behavior change (introduced at 4.6, applies through every subsequent
family), not a backend-specific quirk — confirmed live below across
both the affected and unaffected model boundary.
Bug 2: thinking.display silently defaults to omitted on newer models
Anthropic's adaptive-thinking display field controls whether thinking
content is returned as readable text (summarized) or redacted
(omitted, with only a continuity signature). The default value
changed between model generations: Sonnet 4.6 defaults to
summarized, but Opus 4.7+ and every 5.x family (including Sonnet 5)
silently default to omitted. qwen-code never sets display
explicitly, so any caller surfacing reasoning to users sees thinking
blocks stream back with empty text on newer models — no error, just
a long pause before output with nothing shown, where the same code
worked fine on Sonnet 4.6 or Opus 4.6.
Reproduction
Bug 1 — verified live against claude-sonnet-5, claude-opus-4.6,
claude-opus-4.7, claude-opus-4.8, and claude-sonnet-4.6 via the
Anthropic Messages API (all 400 identically):
curl -s -X POST https://api.anthropic.com/v1/messages \
-H content-type:application/json \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-d '{
"model":"claude-sonnet-5",
"max_tokens":16,
"messages":[
{"role":"user","content":"hi"},
{"role":"assistant","content":"Sure, here is"}
]
}'
{"type":"error","error":{"type":"invalid_request_error","message":"This model does not support assistant message prefill. The conversation must end with a user message."}}
The same request against claude-haiku-4.5 (a genuinely pre-4.6-generation
model — confirmed not a proxy alias to a 4.6+ model) succeeds normally,
confirming this is a real model-generation cutoff, not a universal
Anthropic restriction:
{"content":[{"type":"text","text":"\"Hi!\"\n\nIs there anything else..."}],...}
Bug 2 — verified live against claude-sonnet-5 with a task that
warrants visible reasoning: without display set, thinking blocks
return with empty thinking text; with display: 'summarized' set
explicitly, the same request returns full, non-empty reasoning text
(confirmed by direct comparison of both request variants against the
live API).
Expected Behavior
- A conversation that would end on an assistant message should be
made safe for 4.6+ models before it reaches the wire — either by
dropping a genuinely empty trailing assistant message, or (when it
carries real content) appending a synthetic user turn so nothing
the model already said is discarded.
thinking.display should be set explicitly to 'summarized' when
emitting the adaptive thinking shape, so reasoning text is visible
regardless of which model generation's silent default applies.
Suggested Fix
- Add a
stripTrailingAssistantPrefill converter option, gated on the
existing modelSupportsAdaptiveThinking() check (the same 4.6+
cutoff already used for the adaptive-thinking shape) — this reuses
existing, already-correct version-detection infrastructure rather
than introducing a new one.
- Set
display: 'summarized' unconditionally on the { type: 'adaptive' } thinking shape returned by buildThinkingConfig(). This is a
no-op on models whose default is already summarized and required
on models whose default silently changed to omitted.
Both are minimal, additive changes localized to
anthropicContentGenerator/converter.ts and
anthropicContentGenerator/anthropicContentGenerator.ts, following the
same options-object pattern already used for the file's other
converter passes (dropUnsignedAssistantThinking,
injectThinkingOnToolUseTurns, etc.).
Happy to open a PR for this — will link it here once ready.
Description
Two related, verified bugs affecting every Claude Opus/Sonnet 4.6+ model
(and every 5.x family — Fable 5, Mythos 5, Sonnet 5, etc.) on the
Anthropic wire:
Bug 1: assistant-turn "prefill" 400s with no mitigation
When Gemini-format history ends on a model turn with no follow-up
(e.g. context trimming drops the next user turn, or a subagent
transcript is replayed mid-turn), the Anthropic converter forwards a
request whose last message has
role: 'assistant'. Anthropic rejectsthis outright on every 4.6+ model:
Per Anthropic's own migration documentation, this is a model-generation
behavior change (introduced at 4.6, applies through every subsequent
family), not a backend-specific quirk — confirmed live below across
both the affected and unaffected model boundary.
Bug 2:
thinking.displaysilently defaults toomittedon newer modelsAnthropic's adaptive-thinking
displayfield controls whether thinkingcontent is returned as readable text (
summarized) or redacted(
omitted, with only a continuity signature). The default valuechanged between model generations: Sonnet 4.6 defaults to
summarized, but Opus 4.7+ and every 5.x family (including Sonnet 5)silently default to
omitted.qwen-codenever setsdisplayexplicitly, so any caller surfacing reasoning to users sees thinking
blocks stream back with empty text on newer models — no error, just
a long pause before output with nothing shown, where the same code
worked fine on Sonnet 4.6 or Opus 4.6.
Reproduction
Bug 1 — verified live against
claude-sonnet-5,claude-opus-4.6,claude-opus-4.7,claude-opus-4.8, andclaude-sonnet-4.6via theAnthropic Messages API (all 400 identically):
{"type":"error","error":{"type":"invalid_request_error","message":"This model does not support assistant message prefill. The conversation must end with a user message."}}The same request against
claude-haiku-4.5(a genuinely pre-4.6-generationmodel — confirmed not a proxy alias to a 4.6+ model) succeeds normally,
confirming this is a real model-generation cutoff, not a universal
Anthropic restriction:
{"content":[{"type":"text","text":"\"Hi!\"\n\nIs there anything else..."}],...}Bug 2 — verified live against
claude-sonnet-5with a task thatwarrants visible reasoning: without
displayset,thinkingblocksreturn with empty
thinkingtext; withdisplay: 'summarized'setexplicitly, the same request returns full, non-empty reasoning text
(confirmed by direct comparison of both request variants against the
live API).
Expected Behavior
made safe for 4.6+ models before it reaches the wire — either by
dropping a genuinely empty trailing assistant message, or (when it
carries real content) appending a synthetic user turn so nothing
the model already said is discarded.
thinking.displayshould be set explicitly to'summarized'whenemitting the adaptive thinking shape, so reasoning text is visible
regardless of which model generation's silent default applies.
Suggested Fix
stripTrailingAssistantPrefillconverter option, gated on theexisting
modelSupportsAdaptiveThinking()check (the same 4.6+cutoff already used for the adaptive-thinking shape) — this reuses
existing, already-correct version-detection infrastructure rather
than introducing a new one.
display: 'summarized'unconditionally on the{ type: 'adaptive' }thinking shape returned bybuildThinkingConfig(). This is ano-op on models whose default is already
summarizedand requiredon models whose default silently changed to
omitted.Both are minimal, additive changes localized to
anthropicContentGenerator/converter.tsandanthropicContentGenerator/anthropicContentGenerator.ts, following thesame options-object pattern already used for the file's other
converter passes (
dropUnsignedAssistantThinking,injectThinkingOnToolUseTurns, etc.).Happy to open a PR for this — will link it here once ready.