fix(bedrock): forward clear_thinking context_management edits on Converse while thinking is on

The Converse request path kept only compact_20260112 edits, so a
clear_thinking_20251015 edit sent through context_management was dropped
without a trace. Bedrock accepts that edit with the context-management-2025-06-27
beta as long as thinking is enabled or adaptive in the same request. Keep the
edit and add the beta in that case, and keep dropping it when thinking is off,
which is what Bedrock rejects.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Gouranga Satapathy 2026-10-31 14:52:34 +05:30
parent da71a03f6e
commit 1e601d1aa1
3 changed files with 93 additions and 12 deletions

View file

@ -3,6 +3,7 @@
from typing import Final
CLEAR_TOOL_USES_EDIT_TYPE: Final = "clear_tool_uses_20250919"
CLEAR_THINKING_EDIT_TYPE: Final = "clear_thinking_20251015"
DEFAULT_INPUT_TOKENS_TRIGGER: Final = 100_000
DEFAULT_KEEP_TOOL_USES: Final = 3

View file

@ -1977,8 +1977,9 @@ class AmazonConverseConfig(BaseConfig):
additional_request_params: dict,
anthropic_beta_list: list,
) -> None:
"""Keep only compact_20260112 edits for Bedrock; add beta header or drop field."""
"""Keep compact edits, and clear_thinking edits while thinking is on. Add their betas or drop the field."""
from litellm.llms.anthropic.messages.context_management.constants import (
CLEAR_THINKING_EDIT_TYPE,
COMPACT_EDIT_TYPE,
)
from litellm.types.llms.anthropic import ANTHROPIC_BETA_HEADER_VALUES
@ -1992,17 +1993,25 @@ class AmazonConverseConfig(BaseConfig):
additional_request_params.pop("context_management", None)
return
compact_edits: Final = [e for e in edits if isinstance(e, dict) and e.get("type") == COMPACT_EDIT_TYPE]
if compact_edits:
compact_beta: Final = ANTHROPIC_BETA_HEADER_VALUES.COMPACT_2026_01_12.value
if compact_beta not in anthropic_beta_list:
anthropic_beta_list.append(compact_beta)
additional_request_params["context_management"] = {
**cm,
"edits": compact_edits,
}
else:
thinking: Final = additional_request_params.get("thinking")
thinking_is_on: Final = isinstance(thinking, dict) and thinking.get("type") in ("enabled", "adaptive")
beta_by_edit_type: Final = {
COMPACT_EDIT_TYPE: ANTHROPIC_BETA_HEADER_VALUES.COMPACT_2026_01_12.value,
**(
{CLEAR_THINKING_EDIT_TYPE: ANTHROPIC_BETA_HEADER_VALUES.CONTEXT_MANAGEMENT_2025_06_27.value}
if thinking_is_on
else {}
),
}
kept_edits: Final = [e for e in edits if isinstance(e, dict) and e.get("type") in beta_by_edit_type]
if not kept_edits:
additional_request_params.pop("context_management", None)
return
for beta in dict.fromkeys(beta_by_edit_type[e["type"]] for e in kept_edits):
if beta not in anthropic_beta_list:
anthropic_beta_list.append(beta)
additional_request_params["context_management"] = {**cm, "edits": kept_edits}
def _transform_request_helper(
self,

View file

@ -1,4 +1,6 @@
"""Bedrock Converse context_management forwarding (compact_20260112 only)."""
"""Bedrock Converse context_management forwarding (compact_20260112, and clear_thinking_20251015 while thinking is on)."""
import pytest
from litellm.llms.bedrock.chat.converse_transformation import AmazonConverseConfig
@ -112,3 +114,72 @@ def test_filter_does_not_duplicate_beta_header():
additional, betas
)
assert betas.count("compact-2026-01-12") == 1
CLEAR_THINKING_EDIT = {
"type": "clear_thinking_20251015",
"keep": {"type": "thinking_turns", "value": 1},
}
@pytest.mark.parametrize(
"thinking", [{"type": "enabled", "budget_tokens": 2048}, {"type": "adaptive"}]
)
def test_filter_keeps_clear_thinking_edit_and_adds_beta_when_thinking_is_on(thinking):
additional = {
"thinking": thinking,
"context_management": {"edits": [CLEAR_THINKING_EDIT]},
}
betas: list = []
AmazonConverseConfig._filter_context_management_for_bedrock_converse(
additional, betas
)
assert additional["context_management"] == {"edits": [CLEAR_THINKING_EDIT]}
assert betas == ["context-management-2025-06-27"]
@pytest.mark.parametrize("thinking", [None, {"type": "disabled"}])
def test_filter_drops_clear_thinking_edit_when_thinking_is_off(thinking):
additional = {"context_management": {"edits": [CLEAR_THINKING_EDIT]}}
if thinking is not None:
additional["thinking"] = thinking
betas: list = []
AmazonConverseConfig._filter_context_management_for_bedrock_converse(
additional, betas
)
assert "context_management" not in additional
assert betas == []
def test_filter_keeps_compact_and_clear_thinking_together_with_both_betas():
additional = {
"thinking": {"type": "adaptive"},
"context_management": {
"edits": [
CLEAR_THINKING_EDIT,
{"type": "compact_20260112"},
{"type": "clear_tool_uses_20250919"},
]
},
}
betas: list = []
AmazonConverseConfig._filter_context_management_for_bedrock_converse(
additional, betas
)
assert additional["context_management"]["edits"] == [
CLEAR_THINKING_EDIT,
{"type": "compact_20260112"},
]
assert sorted(betas) == ["compact-2026-01-12", "context-management-2025-06-27"]
def test_filter_does_not_duplicate_context_management_beta():
additional = {
"thinking": {"type": "adaptive"},
"context_management": {"edits": [CLEAR_THINKING_EDIT]},
}
betas: list = ["context-management-2025-06-27"]
AmazonConverseConfig._filter_context_management_for_bedrock_converse(
additional, betas
)
assert betas == ["context-management-2025-06-27"]