Skip to content

fix(bedrock): remove remove_custom_field_from_tools — Bedrock now supports custom.defer_loading natively#26143

Open
Anai-Guo wants to merge 4 commits intoBerriAI:mainfrom
Anai-Guo:fix-bedrock-remove-custom-field
Open

fix(bedrock): remove remove_custom_field_from_tools — Bedrock now supports custom.defer_loading natively#26143
Anai-Guo wants to merge 4 commits intoBerriAI:mainfrom
Anai-Guo:fix-bedrock-remove-custom-field

Conversation

@Anai-Guo
Copy link
Copy Markdown

Summary

Removes remove_custom_field_from_tools() and all its call sites.

This function was added in #22861 (fixing #22847) to strip the custom: {defer_loading: true} field from tool definitions before forwarding to Bedrock, because Bedrock was rejecting it with "Extra inputs are not permitted".

Bedrock has since been updated and now accepts custom.defer_loading natively. When using Claude Code directly against Bedrock (without LiteLLM), Tool Search works correctly. But routing through LiteLLM → Bedrock caused the field to be stripped, defeating the feature and loading every tool definition into context — adding ~20k+ extra input tokens per request for a typical MCP setup.

Changes

  • litellm/llms/bedrock/common_utils.py: Remove remove_custom_field_from_tools() function
  • litellm/llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py: Remove import + call
  • litellm/llms/bedrock/chat/invoke_transformations/anthropic_claude3_transformation.py: Remove import + call
  • tests/…/test_anthropic_claude3_transformation.py: Remove test_remove_custom_field_from_tools test

Note: normalize_json_schema_custom_types_to_object() and normalize_tool_input_schema_types_for_bedrock_invoke() are intentionally kept — they handle type: "custom" in JSON schemas, which is a separate issue that Bedrock still does not accept.

Test plan

  • Verify existing Bedrock invoke tests pass
  • Manually test with Claude Code + LiteLLM → Bedrock: confirm defer_loading is preserved in tool definitions
  • Confirm token usage drops to match direct Bedrock path

Fixes #26113

🤖 Generated with Claude Code

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Apr 20, 2026

Greptile Summary

This PR removes the remove_custom_field_from_tools() workaround from the Bedrock invoke transformation pipeline, now that Bedrock natively accepts the custom: {defer_loading: true} field that Claude Code sends with tool definitions. The change is well-scoped: both the chat and messages Bedrock invoke paths are updated, the function and its tests are cleanly deleted, and the unrelated normalize_tool_input_schema_types_for_bedrock_invoke (which handles a different Bedrock limitation) is correctly left in place.

Confidence Score: 5/5

Safe to merge — the change is a clean removal of a workaround that is no longer needed, with no logic altered beyond stripping the stripping.

All findings are P2 (missing passthrough test for the new behavior). The core change is minimal, well-explained, and consistent across both Bedrock invoke paths. The deleted test was appropriate to delete since the function it covered is gone.

The test file is the only file worth a second look — consider adding a test verifying custom.defer_loading survives the transformation pipeline.

Important Files Changed

Filename Overview
litellm/llms/bedrock/common_utils.py Removes the remove_custom_field_from_tools() function entirely; normalize_tool_input_schema_types_for_bedrock_invoke is correctly retained for the separate type: "custom" schema issue.
litellm/llms/bedrock/chat/invoke_transformations/anthropic_claude3_transformation.py Removes import and call of remove_custom_field_from_tools; the remaining normalize_tool_input_schema_types_for_bedrock_invoke call is unaffected.
litellm/llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py Removes import and call of remove_custom_field_from_tools; adjacent transformation steps (normalize_tool_input_schema_types_for_bedrock_invoke, ensure_bedrock_anthropic_messages_tool_names) are correctly preserved.
tests/test_litellm/llms/bedrock/messages/invoke_transformations/test_anthropic_claude3_transformation.py Removes the test_remove_custom_field_from_tools test (appropriate since the function is gone), but no new test is added to verify custom.defer_loading is preserved through the transformation pipeline.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["Incoming request\n(tools with custom: {defer_loading: true})"] --> B[AmazonAnthropicClaudeMessagesConfig\n.transform_request]
    A --> C[AmazonAnthropicClaudeConfig\n.transform_request]
    B --> D["~~remove_custom_field_from_tools()~~\n(REMOVED)"]
    C --> E["~~remove_custom_field_from_tools()~~\n(REMOVED)"]
    D --> F[normalize_tool_input_schema_types_for_bedrock_invoke\ntype:custom → object in input_schema]
    E --> F
    F --> G[Bedrock Invoke API\nnow accepts custom field natively]
Loading

Reviews (1): Last reviewed commit: "test(bedrock): remove test_remove_custom..." | Re-trigger Greptile

assert request4["tools"] is None


def test_normalize_tool_input_schema_types_for_bedrock_invoke():
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.

P2 Missing test for preserved custom field passthrough

The deleted test verified that custom fields were stripped; now that the stripping is removed, there is no corresponding test verifying that custom: {defer_loading: true} is actually preserved (not dropped) in the final Bedrock request body. A regression here (e.g., a future developer re-adding the strip or an upstream transform clearing it) would go undetected. Consider adding a test asserting the custom field survives the full transformation pipeline alongside test_normalize_tool_input_schema_types_for_bedrock_invoke.

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.

1 participant