Skip to content

fix(anthropic): sanitize tool_use ids on native /v1/messages path - #31094

Merged
mateo-berri merged 3 commits into
litellm_internal_stagingfrom
litellm_sanitize-anthropic-tool-use-ids
Jun 24, 2026
Merged

mateo-berri merged 3 commits into
litellm_internal_stagingfrom
litellm_sanitize-anthropic-tool-use-ids

Conversation

@Sameerlite

@Sameerlite Sameerlite commented Jun 23, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Sanitize tool_use / tool_result ids on the native Anthropic /v1/messages path so replayed cross-provider history (e.g. kimi → Anthropic) no longer 400s on ids like functions.Bash:0
  • Normalize ids when converting OpenAI tool_calls to Anthropic tool_use blocks in the pass-through adapter

Fixes LIT-3881

Test plan

  • pytest tests/test_litellm/llms/anthropic/test_anthropic_common_utils.py -k "sanitize_tool_use or normalize_anthropic_tool_use"
  • pytest tests/test_litellm/llms/anthropic/experimental_pass_through/adapters/test_anthropic_experimental_pass_through_adapters_transformation.py::test_translate_openai_content_to_anthropic_sanitizes_colon_dot_tool_call_ids
  • pytest tests/test_litellm/llms/anthropic/experimental_pass_through/messages/test_anthropic_experimental_pass_through_messages_handler.py::test_anthropic_messages_sanitizes_tool_use_ids_before_dispatch

Cross-provider replay (e.g. kimi -> Anthropic) can carry tool ids like
functions.Bash:0 that violate Anthropic's ^[a-zA-Z0-9_-]+$ pattern and 400.

Co-authored-by: Cursor <cursoragent@cursor.com>
@codecov

codecov Bot commented Jun 23, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.36842% with 1 line in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
litellm/llms/anthropic/common_utils.py 97.14% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@greptile-apps

greptile-apps Bot commented Jun 23, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds ID sanitization for tool_use/tool_result blocks on the native Anthropic /v1/messages path, fixing 400 errors caused by replayed cross-provider conversation history containing IDs (e.g. functions.Bash:0) that contain characters invalid under Anthropic's ^[a-zA-Z0-9_-]+$ constraint.

  • Introduces normalize_anthropic_tool_use_id in common_utils.py, which strips Gemini thought-signature suffixes and replaces any remaining invalid characters with underscores; the adapter's streaming and non-streaming tool-id normalization is refactored to reuse this shared helper.
  • Adds sanitize_tool_use_ids_in_anthropic_messages and calls it in both anthropic_messages (async) and anthropic_messages_handler (sync); a _litellm_messages_presanitized flag prevents redundant double-scanning on the async → sync dispatch path.
  • Four targeted tests cover unit normalization, full-message sanitization, adapter transformation, and end-to-end handler dispatch, all mock-only.

Confidence Score: 5/5

Safe to merge — the sanitization is idempotent, copy-on-write, and guarded against double-application.

The change is narrowly scoped to ID normalization on an existing path, all new functions are idempotent (valid IDs pass through unchanged), the double-sanitization shortcut via _litellm_messages_presanitized is correct, and the four added tests are all mock-only with no network calls. The only theoretical concern (two distinct raw IDs colliding after normalization) is highly unlikely with real cross-provider history and would not cause silent data loss — Anthropic would return an error rather than misroute results.

No files require special attention.

Important Files Changed

Filename Overview
litellm/llms/anthropic/common_utils.py Adds normalize_anthropic_tool_use_id, _sanitize_tool_use_id_content_block, and sanitize_tool_use_ids_in_anthropic_messages — all idempotent and copy-on-write; clean implementation.
litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py Refactors both the non-streaming and streaming tool-use ID paths to use the shared normalize_anthropic_tool_use_id helper; thought_sig is still correctly extracted for provider_specific_fields.signature.
litellm/llms/anthropic/experimental_pass_through/messages/handler.py Adds sanitize_tool_use_ids_in_anthropic_messages call in both anthropic_messages and anthropic_messages_handler; the _litellm_messages_presanitized flag correctly prevents double-sanitization on the async path.
tests/test_litellm/llms/anthropic/test_anthropic_common_utils.py Adds unit tests for sanitize_tool_use_ids_in_anthropic_messages and normalize_anthropic_tool_use_id; verifies both tool_use.id and tool_result.tool_use_id normalization and non-mutation of original messages.
tests/test_litellm/llms/anthropic/experimental_pass_through/adapters/test_anthropic_experimental_pass_through_adapters_transformation.py Adds test for colon/dot ID sanitization in the OpenAI→Anthropic adapter transformation; all mock-only, no network calls.
tests/test_litellm/llms/anthropic/experimental_pass_through/messages/test_anthropic_experimental_pass_through_messages_handler.py Adds async test verifying that anthropic_messages sanitizes tool IDs before dispatch and does not mutate the caller's original message list.

Reviews (3): Last reviewed commit: "Merge remote-tracking branch 'origin/lit..." | Re-trigger Greptile

@Sameerlite

Copy link
Copy Markdown
Contributor Author

@greptileai

@Sameerlite

Copy link
Copy Markdown
Contributor Author

@greptileai

@mateo-berri
mateo-berri self-requested a review June 24, 2026 14:57

@mateo-berri mateo-berri left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM; thanks!

@mateo-berri
mateo-berri merged commit 8bca05d into litellm_internal_staging Jun 24, 2026
123 checks passed
@mateo-berri
mateo-berri deleted the litellm_sanitize-anthropic-tool-use-ids branch June 24, 2026 14:57
@ishaan-berri ishaan-berri mentioned this pull request Jun 25, 2026
9 of 13 tasks
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.

2 participants