From 589bc1989050f01e5067ad15b24c904ec59da211 Mon Sep 17 00:00:00 2001 From: Ahmed Tammaa Date: Mon, 21 Apr 2025 16:44:39 +0200 Subject: [PATCH] anthropic[patch]: make description optional on AnthropicTool (#30935) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR Summary This change adds a fallback in ChatAnthropic.with_structured_output() to handle Pydantic models that don’t include a docstring. Without it, calling: ```py from pydantic import BaseModel from langchain_anthropic import ChatAnthropic class SampleModel(BaseModel): sample_field: str llm = ChatAnthropic( model="claude-3-7-sonnet-latest" ).with_structured_output(SampleModel.model_json_schema()) llm.invoke("test") ``` will raise a ``` KeyError: 'description' ``` because Pydantic omits the description field when no docstring is present. This issue doesn’t occur when using ChatOpenAI or if you add a docstring to the model: ```py from pydantic import BaseModel from langchain_openai import ChatOpenAI class SampleModel(BaseModel): """Schema for sample_field output.""" sample_field: str llm = ChatOpenAI( model="gpt-4o-mini" ).with_structured_output(SampleModel.model_json_schema()) llm.invoke("test") ``` --------- Co-authored-by: Chester Curme --- .../anthropic/langchain_anthropic/chat_models.py | 5 +++-- .../anthropic/tests/unit_tests/test_chat_models.py | 9 +++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/libs/partners/anthropic/langchain_anthropic/chat_models.py b/libs/partners/anthropic/langchain_anthropic/chat_models.py index 5ca29c20bce..f872fe32c18 100644 --- a/libs/partners/anthropic/langchain_anthropic/chat_models.py +++ b/libs/partners/anthropic/langchain_anthropic/chat_models.py @@ -82,8 +82,8 @@ class AnthropicTool(TypedDict): """Anthropic tool definition.""" name: str - description: str input_schema: dict[str, Any] + description: NotRequired[str] cache_control: NotRequired[dict[str, str]] @@ -1675,9 +1675,10 @@ def convert_to_anthropic_tool( oai_formatted = convert_to_openai_tool(tool)["function"] anthropic_formatted = AnthropicTool( name=oai_formatted["name"], - description=oai_formatted["description"], input_schema=oai_formatted["parameters"], ) + if "description" in oai_formatted: + anthropic_formatted["description"] = oai_formatted["description"] return anthropic_formatted diff --git a/libs/partners/anthropic/tests/unit_tests/test_chat_models.py b/libs/partners/anthropic/tests/unit_tests/test_chat_models.py index f9225296096..008b2be1cb6 100644 --- a/libs/partners/anthropic/tests/unit_tests/test_chat_models.py +++ b/libs/partners/anthropic/tests/unit_tests/test_chat_models.py @@ -931,3 +931,12 @@ def test_anthropic_bind_tools_tool_choice() -> None: assert cast(RunnableBinding, chat_model_with_tools).kwargs["tool_choice"] == { "type": "any" } + + +def test_optional_description() -> None: + llm = ChatAnthropic(model="claude-3-5-haiku-latest") + + class SampleModel(BaseModel): + sample_field: str + + _ = llm.with_structured_output(SampleModel.model_json_schema())