[PR #5719] fix(provider): harden Claude tool-call adjacency normalization #11548

Closed
opened 2026-02-16 18:16:24 -05:00 by yindo · 0 comments
Owner

Original Pull Request: https://github.com/anomalyco/opencode/pull/5719

State: closed
Merged: No


Summary

Fixes Anthropic API 400 errors caused by incorrect message adjacency when using tool calls. Anthropic requires that tool calls in an assistant message be the last content blocks (terminal tool calls). This PR implements a "Terminal Suffix" strategy to strictly enforce this.

Key Changes

  • Terminal Suffix Normalization: Ensures assistant messages always end with a contiguous block of tool calls. Any text following a tool call is moved to a new subsequent assistant message.
  • Safe ID Sanitization: Hardens sanitizeToolParts to avoid ID collisions using a Map + base64url fallback, ensuring uniqueness even when sanitization modifies IDs.
  • Synthetic Attachment Handling: Moves synthetic "attachment" user messages (generated by tools) to follow tool results, maintaining correct conversation flow.
  • Type Safety: Strengthened type guards (isToolCallPart) to reject malformed arrays and require valid tool names.
  • Cleanup: Removed unsafe casts and duplicate metadata emission.

Verification

  • Unit Tests:
    • packages/opencode/test/provider/transform.test.ts: Added coverage for split/duplicate/partial results, ID collision avoidance, and idempotence.
    • packages/opencode/test/provider/anthropic-regression.test.ts: Added regression test matching the specific failure shape (tool call followed by text).
  • Manual Verification: Verified against local E2E harness with Anthropic models (Claude 3.5 Sonnet) ensuring no 400 errors on complex tool usage patterns.
**Original Pull Request:** https://github.com/anomalyco/opencode/pull/5719 **State:** closed **Merged:** No --- ## Summary Fixes Anthropic API 400 errors caused by incorrect message adjacency when using tool calls. Anthropic requires that tool calls in an assistant message be the *last* content blocks (terminal tool calls). This PR implements a "Terminal Suffix" strategy to strictly enforce this. ## Key Changes - **Terminal Suffix Normalization**: Ensures assistant messages always end with a contiguous block of tool calls. Any text following a tool call is moved to a *new* subsequent assistant message. - **Safe ID Sanitization**: Hardens `sanitizeToolParts` to avoid ID collisions using a `Map` + base64url fallback, ensuring uniqueness even when sanitization modifies IDs. - **Synthetic Attachment Handling**: Moves synthetic "attachment" user messages (generated by tools) to follow tool results, maintaining correct conversation flow. - **Type Safety**: Strengthened type guards (`isToolCallPart`) to reject malformed arrays and require valid tool names. - **Cleanup**: Removed unsafe casts and duplicate metadata emission. ## Verification - **Unit Tests**: - `packages/opencode/test/provider/transform.test.ts`: Added coverage for split/duplicate/partial results, ID collision avoidance, and idempotence. - `packages/opencode/test/provider/anthropic-regression.test.ts`: Added regression test matching the specific failure shape (tool call followed by text). - **Manual Verification**: Verified against local E2E harness with Anthropic models (Claude 3.5 Sonnet) ensuring no 400 errors on complex tool usage patterns.
yindo added the pull-request label 2026-02-16 18:16:24 -05:00
yindo closed this issue 2026-02-16 18:16:24 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: anomalyco/opencode#11548