test(anthropic): add think-tag regression coverage

This commit is contained in:
Gennaro Malafronte 2026-04-23 00:29:01 +02:00
parent 7bf38c6312
commit af42ce7209
3 changed files with 122 additions and 0 deletions

View file

@ -511,6 +511,41 @@ def test_multiple_web_search_tool_results():
assert web_search_results[1]["tool_use_id"] == "srvtoolu_search2"
def test_extract_response_content_strips_leaked_think_tags_from_text_blocks():
config = AnthropicConfig()
completion_response = {
"content": [
{
"type": "text",
"text": "I need to call the tool first.\n</think>\n\ntool-loop-ok",
},
{
"type": "tool_use",
"id": "toolu_01XYZ789",
"name": "echo_status",
"input": {"status": "ok"},
},
]
}
(
text,
citations,
thinking_blocks,
reasoning_content,
tool_calls,
web_search_results,
tool_results,
compaction_blocks,
) = config.extract_response_content(completion_response)
assert text == "tool-loop-ok"
assert tool_calls is not None
assert len(tool_calls) == 1
assert tool_calls[0]["function"]["name"] == "echo_status"
def test_add_code_execution_tool():
config = AnthropicConfig()

View file

@ -472,6 +472,45 @@ def test_translate_openai_response_to_anthropic_text_and_tool_calls():
assert anthropic_response.get("stop_reason") == "tool_use"
def test_translate_openai_response_to_anthropic_strips_leaked_think_tags():
openai_response = ModelResponse(
id="resp_text_tool_sanitized",
model="gpt-4o-mini",
choices=[
Choices(
finish_reason="tool_calls",
message=Message(
role="assistant",
content="I need to call the tool first.\n</think>\n\ntool-loop-ok",
tool_calls=[
ChatCompletionAssistantToolCall(
id="call_tool_combo",
type="function",
function=Function(
name="echo_status", arguments='{"status": "ok"}'
),
)
],
),
)
],
usage=Usage(prompt_tokens=5, completion_tokens=2),
)
adapter = LiteLLMAnthropicMessagesAdapter()
anthropic_response = adapter.translate_openai_response_to_anthropic(
response=openai_response
)
anthropic_content = anthropic_response.get("content")
assert anthropic_content is not None
assert len(anthropic_content) == 2
assert anthropic_content[0]["type"] == "text"
assert anthropic_content[0]["text"] == "tool-loop-ok"
assert anthropic_content[1]["type"] == "tool_use"
assert anthropic_content[1]["name"] == "echo_status"
def test_translate_streaming_openai_chunk_to_anthropic_with_partial_json():
"""Test that partial tool arguments are correctly handled as input_json_delta."""
choices = [

View file

@ -499,3 +499,51 @@ class TestThinkingSummaryPreservation:
assert result == {
"reasoning_effort": {"effort": "medium", "summary": "concise"}
}
def test_anthropic_messages_handler_strips_leaked_think_tags_from_completion_path():
from litellm.llms.anthropic.experimental_pass_through.messages.handler import (
anthropic_messages_handler,
)
from litellm.types.llms.anthropic_messages.anthropic_response import (
AnthropicMessagesResponse,
)
leaked_response = AnthropicMessagesResponse(
id="msg_test",
type="message",
role="assistant",
content=[
{
"type": "text",
"text": "I need to call the tool first.\n</think>\n\ntool-loop-ok",
},
{
"type": "tool_use",
"id": "toolu_01XYZ789",
"name": "echo_status",
"input": {"status": "ok"},
},
],
model="custom-provider/test-model",
stop_reason="tool_use",
usage={"input_tokens": 10, "output_tokens": 20},
)
with patch(
"litellm.llms.anthropic.experimental_pass_through.messages.handler.LiteLLMMessagesToCompletionTransformationHandler.anthropic_messages_handler",
return_value=leaked_response,
) as mock_completion_handler:
result = anthropic_messages_handler(
max_tokens=100,
messages=[{"role": "user", "content": "Hello"}],
model="my-custom-model",
custom_llm_provider="my-custom-llm",
api_key="test-api-key",
)
mock_completion_handler.assert_called_once()
assert result["content"][0]["type"] == "text"
assert result["content"][0]["text"] == "tool-loop-ok"
assert result["content"][1]["type"] == "tool_use"
assert result["content"][1]["name"] == "echo_status"