fix(anthropic): send number and boolean tool results as JSON instead of an empty string

Snowflake sent json.dumps of a non-string tool result before it moved onto the shared transform, which then sent an empty string for a number or boolean, so Claude lost the answer. Mapping results were already serialized; numbers and booleans now take the same path, and None stays empty as it was on Anthropic
This commit is contained in:
mateo-berri 2026-10-30 23:05:26 -07:00
parent d0bb701c34
commit 735ace429b
2 changed files with 5 additions and 6 deletions

View file

@ -1935,7 +1935,7 @@ def convert_to_anthropic_tool_result(
) = ""
if isinstance(message["content"], str):
anthropic_content = message["content"]
elif isinstance(message["content"], Mapping):
elif isinstance(message["content"], (Mapping, int, float)):
anthropic_content = json.dumps(message["content"])
elif isinstance(message["content"], list):
content_list: Final = message["content"]

View file

@ -3191,17 +3191,16 @@ def test_convert_to_anthropic_tool_result_image_with_cache_control():
assert result["content"][1]["cache_control"]["type"] == "ephemeral"
def test_convert_to_anthropic_tool_result_serializes_mapping_content():
@pytest.mark.parametrize("tool_output", [{"result_key": "result_value"}, 42, 0, 3.5, True, False])
def test_convert_to_anthropic_tool_result_serializes_non_string_content(tool_output):
from litellm.litellm_core_utils.prompt_templates.factory import (
convert_to_anthropic_tool_result,
)
result = convert_to_anthropic_tool_result(
{"role": "tool", "tool_call_id": "call_dict", "content": {"result_key": "result_value"}}
)
result = convert_to_anthropic_tool_result({"role": "tool", "tool_call_id": "call_value", "content": tool_output})
assert result["type"] == "tool_result"
assert json.loads(result["content"]) == {"result_key": "result_value"}
assert json.loads(result["content"]) == tool_output
def test_convert_to_anthropic_tool_result_image_without_cache_control():