Skip to content

Commit a425859

Browse files
authored
fix(chatcmpl): preserve text content when adding Anthropic thinking blocks to tool calls (#1784)
1 parent d91e39c commit a425859

File tree

2 files changed

+26
-6
lines changed

2 files changed

+26
-6
lines changed

src/agents/models/chatcmpl_converter.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,20 @@ def ensure_assistant_message() -> ChatCompletionAssistantMessageParam:
480480
# If we have pending thinking blocks, use them as the content
481481
# This is required for Anthropic API tool calls with interleaved thinking
482482
if pending_thinking_blocks:
483-
asst["content"] = pending_thinking_blocks # type: ignore
483+
# If there is a text content, save it to append after thinking blocks
484+
# content type is Union[str, Iterable[ContentArrayOfContentPart], None]
485+
if "content" in asst and isinstance(asst["content"], str):
486+
text_content = ChatCompletionContentPartTextParam(
487+
text=asst["content"], type="text"
488+
)
489+
asst["content"] = [text_content]
490+
491+
if "content" not in asst or asst["content"] is None:
492+
asst["content"] = []
493+
494+
# Thinking blocks MUST come before any other content
495+
# We ignore type errors because pending_thinking_blocks is not openai standard
496+
asst["content"] = pending_thinking_blocks + asst["content"] # type: ignore
484497
pending_thinking_blocks = None # Clear after using
485498

486499
tool_calls = list(asst.get("tool_calls", []))

tests/test_anthropic_thinking_blocks.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -217,20 +217,27 @@ def test_anthropic_thinking_blocks_with_tool_calls():
217217
"Signature should be preserved in thinking block"
218218
)
219219

220-
first_content = content[1]
221-
assert first_content.get("type") == "thinking", (
220+
second_content = content[1]
221+
assert second_content.get("type") == "thinking", (
222222
f"Second content must be 'thinking' type for Anthropic compatibility, "
223-
f"but got '{first_content.get('type')}'"
223+
f"but got '{second_content.get('type')}'"
224224
)
225225
expected_thinking = "We should use the city Tokyo as the city."
226-
assert first_content.get("thinking") == expected_thinking, (
226+
assert second_content.get("thinking") == expected_thinking, (
227227
"Thinking content should be preserved"
228228
)
229229
# Signature should also be preserved
230-
assert first_content.get("signature") == "TestSignature456", (
230+
assert second_content.get("signature") == "TestSignature456", (
231231
"Signature should be preserved in thinking block"
232232
)
233233

234+
last_content = content[2]
235+
assert last_content.get("type") == "text", (
236+
f"First content must be 'text' type but got '{last_content.get('type')}'"
237+
)
238+
expected_text = "I'll check the weather for you."
239+
assert last_content.get("text") == expected_text, "Content text should be preserved"
240+
234241
# Verify tool calls are preserved
235242
tool_calls = assistant_msg.get("tool_calls", [])
236243
assert len(cast(list[Any], tool_calls)) == 1, "Tool calls should be preserved"

0 commit comments

Comments
 (0)