diff --git a/libs/partners/anthropic/langchain_anthropic/chat_models.py b/libs/partners/anthropic/langchain_anthropic/chat_models.py index a7decc4c3e..e5deebd6b7 100644 --- a/libs/partners/anthropic/langchain_anthropic/chat_models.py +++ b/libs/partners/anthropic/langchain_anthropic/chat_models.py @@ -191,6 +191,18 @@ def _format_messages(messages: List[BaseMessage]) -> Tuple[Optional[str], List[D elif item["type"] == "tool_use": item.pop("text", None) content.append(item) + elif item["type"] == "text": + text = item.get("text", "") + # Only add non-empty strings for now as empty ones are not + # accepted. + # https://github.com/anthropics/anthropic-sdk-python/issues/461 + if text.strip(): + content.append( + { + "type": "text", + "text": text, + } + ) else: content.append(item) else: diff --git a/libs/partners/anthropic/tests/integration_tests/test_chat_models.py b/libs/partners/anthropic/tests/integration_tests/test_chat_models.py index 7737a1df99..94f773975e 100644 --- a/libs/partners/anthropic/tests/integration_tests/test_chat_models.py +++ b/libs/partners/anthropic/tests/integration_tests/test_chat_models.py @@ -9,9 +9,12 @@ from langchain_core.messages import ( AIMessageChunk, BaseMessage, HumanMessage, + SystemMessage, + ToolMessage, ) from langchain_core.outputs import ChatGeneration, LLMResult from langchain_core.prompts import ChatPromptTemplate +from langchain_core.tools import tool from langchain_anthropic import ChatAnthropic, ChatAnthropicMessages from tests.unit_tests._utils import FakeCallbackHandler @@ -264,6 +267,50 @@ def test_tool_use() -> None: assert "location" in json.loads(tool_call_chunk["args"]) +def test_anthropic_with_empty_text_block() -> None: + """Anthropic SDK can return an empty text block.""" + + @tool + def type_letter(letter: str) -> str: + """Type the given letter.""" + return "OK" + + model = ChatAnthropic(model="claude-3-opus-20240229", temperature=0).bind_tools( + [type_letter] + ) + + messages = [ + SystemMessage( + content="Repeat the given string using the provided tools. Do not write " + "anything else or provide any explanations. For example, " + "if the string is 'abc', you must print the " + "letters 'a', 'b', and 'c' one at a time and in that order. " + ), + HumanMessage(content="dog"), + AIMessage( + content=[ + {"text": "", "type": "text"}, + { + "id": "toolu_01V6d6W32QGGSmQm4BT98EKk", + "input": {"letter": "d"}, + "name": "type_letter", + "type": "tool_use", + }, + ], + tool_calls=[ + { + "name": "type_letter", + "args": {"letter": "d"}, + "id": "toolu_01V6d6W32QGGSmQm4BT98EKk", + }, + ], + ), + ToolMessage(content="OK", tool_call_id="toolu_01V6d6W32QGGSmQm4BT98EKk"), + ] + + model.invoke(messages) + + def test_with_structured_output() -> None: llm = ChatAnthropic( model="claude-3-opus-20240229",