fix: stringify Anthropic typeless blocks as JSON
This commit is contained in:
@@ -4,6 +4,7 @@ from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import hashlib
|
||||
import json
|
||||
import re
|
||||
import secrets
|
||||
import string
|
||||
@@ -280,7 +281,10 @@ class AnthropicProvider(LLMProvider):
|
||||
# Anthropic requires every content block to declare a "type".
|
||||
# A tool that returned a bare dict lands here; coerce it to
|
||||
# a text block instead of emitting one that the API rejects.
|
||||
blocks.append({"type": "text", "text": str(item)})
|
||||
blocks.append({
|
||||
"type": "text",
|
||||
"text": AnthropicProvider._stringify_typeless_block(item),
|
||||
})
|
||||
else:
|
||||
blocks.append(item)
|
||||
else:
|
||||
@@ -324,11 +328,18 @@ class AnthropicProvider(LLMProvider):
|
||||
# A tool that returned a bare dict (or a list of dicts) lands
|
||||
# here; coerce it to a text block instead of emitting a block
|
||||
# the API rejects with "content.0.type: Field required".
|
||||
result.append({"type": "text", "text": str(item)})
|
||||
result.append({
|
||||
"type": "text",
|
||||
"text": AnthropicProvider._stringify_typeless_block(item),
|
||||
})
|
||||
continue
|
||||
result.append(item)
|
||||
return result or "(empty)"
|
||||
|
||||
@staticmethod
|
||||
def _stringify_typeless_block(block: dict[str, Any]) -> str:
|
||||
return json.dumps(block, ensure_ascii=False, sort_keys=True, default=str)
|
||||
|
||||
@staticmethod
|
||||
def _convert_image_block(block: dict[str, Any]) -> dict[str, Any] | None:
|
||||
"""Convert OpenAI image_url block to Anthropic image block."""
|
||||
|
||||
@@ -70,7 +70,7 @@ def test_convert_user_content_coerces_typeless_dict():
|
||||
{"foo": "bar"},
|
||||
{"type": "text", "text": "ok"},
|
||||
])
|
||||
assert result[0] == {"type": "text", "text": str({"foo": "bar"})}
|
||||
assert result[0] == {"type": "text", "text": '{"foo": "bar"}'}
|
||||
assert result[1] == {"type": "text", "text": "ok"}
|
||||
|
||||
|
||||
@@ -81,7 +81,16 @@ def test_convert_user_content_coerces_mixed_typeless():
|
||||
{"key": "val"},
|
||||
])
|
||||
assert result[0] == {"type": "text", "text": "42"}
|
||||
assert result[1] == {"type": "text", "text": str({"key": "val"})}
|
||||
assert result[1] == {"type": "text", "text": '{"key": "val"}'}
|
||||
|
||||
|
||||
def test_assistant_blocks_coerce_typeless_dict_to_json_text():
|
||||
blocks = AnthropicProvider._assistant_blocks({
|
||||
"role": "assistant",
|
||||
"content": [{"answer": "ok", "count": 2}],
|
||||
})
|
||||
|
||||
assert blocks == [{"type": "text", "text": '{"answer": "ok", "count": 2}'}]
|
||||
|
||||
|
||||
def test_convert_assistant_message_repairs_history_tool_arguments():
|
||||
|
||||
Reference in New Issue
Block a user