Skip to content

Commit 5fa1094

Browse files
authored
fix(anthropic,standard-tests): carry over updates to v0.3 (#33393)
Cherry pick of #33390 and #33391.
1 parent dd4de69 commit 5fa1094

File tree

4 files changed

+95
-2
lines changed

4 files changed

+95
-2
lines changed

libs/partners/anthropic/langchain_anthropic/chat_models.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,10 @@ def _format_messages(
489489
_lc_tool_calls_to_anthropic_tool_use_blocks(missing_tool_calls),
490490
)
491491

492+
if not content and role == "assistant" and _i < len(merged_messages) - 1:
493+
# anthropic.BadRequestError: Error code: 400: all messages must have
494+
# non-empty content except for the optional final assistant message
495+
continue
492496
formatted_messages.append({"role": role, "content": content})
493497
return system, formatted_messages
494498

libs/partners/anthropic/tests/integration_tests/test_chat_models.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,53 @@ def test_system_invoke() -> None:
271271
assert isinstance(result.content, str)
272272

273273

274+
def test_handle_empty_aimessage() -> None:
275+
# Anthropic can generate empty AIMessages, which are not valid unless in the last
276+
# message in a sequence.
277+
llm = ChatAnthropic(model=MODEL_NAME)
278+
messages = [
279+
HumanMessage("Hello"),
280+
AIMessage([]),
281+
HumanMessage("My name is Bob."),
282+
]
283+
_ = llm.invoke(messages)
284+
285+
# Test tool call sequence
286+
llm_with_tools = llm.bind_tools(
287+
[
288+
{
289+
"name": "get_weather",
290+
"description": "Get weather report for a city",
291+
"input_schema": {
292+
"type": "object",
293+
"properties": {"location": {"type": "string"}},
294+
},
295+
},
296+
],
297+
)
298+
_ = llm_with_tools.invoke(
299+
[
300+
HumanMessage("What's the weather in Boston?"),
301+
AIMessage(
302+
content=[],
303+
tool_calls=[
304+
{
305+
"name": "get_weather",
306+
"args": {"location": "Boston"},
307+
"id": "toolu_01V6d6W32QGGSmQm4BT98EKk",
308+
"type": "tool_call",
309+
},
310+
],
311+
),
312+
ToolMessage(
313+
content="It's sunny.", tool_call_id="toolu_01V6d6W32QGGSmQm4BT98EKk"
314+
),
315+
AIMessage([]),
316+
HumanMessage("Thanks!"),
317+
]
318+
)
319+
320+
274321
def test_anthropic_call() -> None:
275322
"""Test valid call to anthropic."""
276323
chat = ChatAnthropic(model=MODEL_NAME) # type: ignore[call-arg]

libs/partners/anthropic/tests/unit_tests/test_chat_models.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,38 @@ def test__format_messages_with_tool_calls() -> None:
594594
actual = _format_messages(messages)
595595
assert expected == actual
596596

597+
# Check handling of empty AIMessage
598+
empty_contents: list[str | list[str | dict]] = ["", []]
599+
for empty_content in empty_contents:
600+
## Permit message in final position
601+
_, anthropic_messages = _format_messages([human, AIMessage(empty_content)])
602+
expected_messages = [
603+
{"role": "user", "content": "foo"},
604+
{"role": "assistant", "content": empty_content},
605+
]
606+
assert expected_messages == anthropic_messages
607+
608+
## Remove message otherwise
609+
_, anthropic_messages = _format_messages(
610+
[human, AIMessage(empty_content), human]
611+
)
612+
expected_messages = [
613+
{"role": "user", "content": "foo"},
614+
{"role": "user", "content": "foo"},
615+
]
616+
assert expected_messages == anthropic_messages
617+
618+
actual = _format_messages(
619+
[system, human, ai, tool, AIMessage(empty_content), human]
620+
)
621+
assert actual[0] == "fuzz"
622+
assert [message["role"] for message in actual[1]] == [
623+
"user",
624+
"assistant",
625+
"user",
626+
"user",
627+
]
628+
597629

598630
def test__format_tool_use_block() -> None:
599631
# Test we correctly format tool_use blocks when there is no corresponding tool_call.

libs/standard-tests/langchain_tests/integration_tests/chat_models.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2979,8 +2979,18 @@ def supports_anthropic_inputs(self) -> bool:
29792979
[
29802980
{
29812981
"type": "thinking",
2982-
"thinking": "I'm thinking...",
2983-
"signature": "abc123",
2982+
"thinking": (
2983+
"This is a simple greeting. I should respond warmly and "
2984+
"professionally, and perhaps ask how I can help the person "
2985+
"today."
2986+
),
2987+
"signature": (
2988+
"ErUBCkYICBgCIkDCTQUXPc3O7nHXd302Zercaz8WrrpddpOqHITxBih5ze"
2989+
"FPoJkwKBvkvZ8ID1aAfJftji6+ZI5gBYDo7XmNBIkzEgzVDHKopedAn/sc"
2990+
"G80aDFDXVZrDOWgla7lEBiIwLq5kfFjQjvF/CyuL8J5V7dRwsJN5gQIXaM"
2991+
"B6xXTs6T+2Zp0VdiyiMb/hcdrHt+7aKh0z2E1UnjiOCoTlofNFHzOnKk0q"
2992+
"PIoPmfGgpPgGNRgC"
2993+
),
29842994
},
29852995
{
29862996
"type": "text",

0 commit comments

Comments
 (0)