Skip to content

fix(anthropic): preserve provider content blocks on assistant replay (refs #298)#392

Merged
pushpak1300 merged 5 commits into
laravel:0.xfrom
CodeWrap:fix/anthropic-preserve-content-blocks
May 4, 2026
Merged

fix(anthropic): preserve provider content blocks on assistant replay (refs #298)#392
pushpak1300 merged 5 commits into
laravel:0.xfrom
CodeWrap:fix/anthropic-preserve-content-blocks

Conversation

@CodeWrap

@CodeWrap CodeWrap commented Apr 13, 2026

Copy link
Copy Markdown
Contributor

Hit this integrating advisor — every multi-turn advisor conversation 400s because the advisor_tool_result block drops on replay.

MapsMessages::mapAssistantMessage() rebuilds assistant content from text + tool_calls only. On replay that drops Anthropic provider blocks like server_tool_use, server_tool_result, thinking, and redacted_thinking. In multi-turn conversations that used server tools, the next request can fail with 400 invalid_request_error because the assistant history no longer matches what Anthropic expects. This is the in-memory replay side of #298.

This change adds a contentBlocks property to AssistantMessage and uses it verbatim in mapAssistantMessage() when present, instead of rebuilding from text + tool_calls. The non-streaming parser now passes the raw ordered content array into AssistantMessage. If contentBlocks is empty, the existing path is unchanged, so current behavior and older cached/unserialized messages still fall back to the old rebuild logic.

Scope is limited to in-memory AssistantMessage replay. DatabaseConversationStore still rehydrates assistant messages from text + tool_calls, so persisted conversations are unchanged here; that needs schema work and is already tracked in #380. Streaming is also unchanged: same-request replay already uses the raw response content directly and does not go through mapAssistantMessage().

Tests cover the verbatim mapping path, parser population of contentBlocks, round-tripping a parsed assistant message back through mapMessages(), and the fallback behavior when contentBlocks is absent. Anthropic tests are green. Related: #380 for persistence, #301 for adjacent reasoning-data loss, and #349 for the TextOrchestrator refactor this avoids touching.

@pushpak1300

Copy link
Copy Markdown
Member

can you fix the merge conflict ?

@CodeWrap CodeWrap force-pushed the fix/anthropic-preserve-content-blocks branch from ae98298 to 736a434 Compare April 14, 2026 15:30
@CodeWrap

Copy link
Copy Markdown
Contributor Author

done

Anthropic's Messages API expects the original ordered content-block
array on multi-turn replay. `mapAssistantMessage()` rebuilt assistant
content from text + tool_use only, dropping `server_tool_use`,
`server_tool_result`, `thinking`, and `redacted_thinking` blocks — so
conversations using advisor, web_search, web_fetch, code_execution, or
extended thinking broke when assistant history was replayed through the
mapper.

Carry the raw ordered blocks on AssistantMessage via a new
`contentBlocks` property. The Anthropic non-streaming parser now
populates it, and `mapAssistantMessage` replays it verbatim (running
through `ensureToolInputIsObject` so empty `input` survives as `{}`).
When `contentBlocks` is empty, the existing text + tool_calls rebuild
is unchanged — backward-compat preserved.

Scope: in-memory AssistantMessage replay only. Persistence-backed
conversations via `DatabaseConversationStore` need a matching schema +
rehydration change, tracked separately in laravel#380. Streaming replay
already uses raw response content directly and is unaffected.

References laravel#298.
Reframe the docblock to make intent explicit: contentBlocks is a
replay carrier for provider-native blocks (populated by the SDK's own
parser), not a general-purpose user-authored schema. Preempts review
concerns about public API surface.
@CodeWrap CodeWrap force-pushed the fix/anthropic-preserve-content-blocks branch from 736a434 to 2bb0da3 Compare April 29, 2026 13:48
@pushpak1300 pushpak1300 linked an issue May 4, 2026 that may be closed by this pull request
@pushpak1300 pushpak1300 merged commit 5c27595 into laravel:0.x May 4, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Results of provider tool calls are forgotten by agents

2 participants