When the model streams `tool_use ... text ... tool_use` interleaved blocks
within one turn (e.g. parallel TaskCreate calls plus a mid-stream
explanation), the previous merge logic preserved the literal stream order
and persisted it to history. On the next request, Bedrock's stricter
history validator inspects the trailing run of `tool_use` blocks: text
between tool_uses makes the earlier tool_uses no longer count as
"trailing", so they are reported as missing tool_result and the API 400s
even though all tool_results were actually returned. See
CLIENT_TOOL_USE_BUG_REPORT.md from the worldRouter proxy team for the
captured request body and Bedrock error.
This fix:
- Adds `reorderAssistantToolUseBlocks` that moves non-tool_use blocks out
of the tool_use cluster (preserving tool_use id order, thinking/
redacted_thinking positions, and dropping no blocks). No-op when zero
or one tool_use, or when tool_uses are already contiguous.
- Applies it in `mergeAssistantMessages` so live stream-merge produces
clean history.
- Applies it as a pass in `normalizeMessagesForAPI` so sessions resumed
from disk that were persisted before this fix also get cleaned up.
- Adds 9 bun:test cases covering the no-op, hoist, head/tail
preservation, idempotence, and merge cases (including the exact
pattern from the upstream bug report).