diff --git a/libs/core/langchain_core/messages/content_blocks.py b/libs/core/langchain_core/messages/content_blocks.py index ed45c77bb6e..1c80bacbd7a 100644 --- a/libs/core/langchain_core/messages/content_blocks.py +++ b/libs/core/langchain_core/messages/content_blocks.py @@ -70,7 +70,7 @@ The module defines several types of content blocks, including: - ``TextContentBlock``: Standard text. - ``ImageContentBlock``, ``Audio...``, ``Video...``, ``PlainText...``, ``File...``: For multimodal data. -- ``ToolCallContentBlock``, ``ToolOutputContentBlock``: For function calling. +- ``ToolCallContentBlock``: For function calling. - ``ReasoningContentBlock``: To capture a model's thought process. - ``Citation``: For annotations that link generated text to a source document. diff --git a/libs/standard-tests/langchain_tests/integration_tests/chat_models.py b/libs/standard-tests/langchain_tests/integration_tests/chat_models.py index 4a2b0a78235..a6d03f72805 100644 --- a/libs/standard-tests/langchain_tests/integration_tests/chat_models.py +++ b/libs/standard-tests/langchain_tests/integration_tests/chat_models.py @@ -135,6 +135,7 @@ def unicode_customer(customer_name: str, description: str) -> str: Returns: A confirmation message about the customer creation. + """ return f"Created customer: {customer_name} - {description}" @@ -680,13 +681,13 @@ class ChatModelIntegrationTests(ChatModelTests): return {} def test_invoke(self, model: BaseChatModel) -> None: - """Test to verify that `model.invoke(simple_message)` works. + """Test to verify that ``model.invoke(simple_message)`` works. This should pass for all integrations. .. dropdown:: Troubleshooting - If this test fails, you should make sure your _generate method + If this test fails, you should make sure your ``_generate`` method does not raise any exceptions, and that it returns a valid :class:`~langchain_core.outputs.chat_result.ChatResult` like so: @@ -706,7 +707,7 @@ class ChatModelIntegrationTests(ChatModelTests): assert len(result.content) > 0 async def test_ainvoke(self, model: BaseChatModel) -> None: - """Test to verify that `await model.ainvoke(simple_message)` works. + """Test to verify that ``await model.ainvoke(simple_message)`` works. This should pass for all integrations. Passing this test does not indicate a "natively async" implementation, but rather that the model can be used @@ -716,7 +717,7 @@ class ChatModelIntegrationTests(ChatModelTests): First, debug :meth:`~langchain_tests.integration_tests.chat_models.ChatModelIntegrationTests.test_invoke`. - because `ainvoke` has a default implementation that calls `invoke` in an + because ``ainvoke`` has a default implementation that calls ``invoke`` in an async context. If that test passes but not this one, you should make sure your _agenerate @@ -739,7 +740,7 @@ class ChatModelIntegrationTests(ChatModelTests): assert len(result.content) > 0 def test_stream(self, model: BaseChatModel) -> None: - """Test to verify that `model.stream(simple_message)` works. + """Test to verify that ``model.stream(simple_message)`` works. This should pass for all integrations. Passing this test does not indicate a "streaming" implementation, but rather that the model can be used in a @@ -772,7 +773,7 @@ class ChatModelIntegrationTests(ChatModelTests): assert num_chunks > 0 async def test_astream(self, model: BaseChatModel) -> None: - """Test to verify that `await model.astream(simple_message)` works. + """Test to verify that ``await model.astream(simple_message)`` works. This should pass for all integrations. Passing this test does not indicate a "natively async" or "streaming" implementation, but rather that the model can @@ -809,7 +810,7 @@ class ChatModelIntegrationTests(ChatModelTests): assert num_chunks > 0 def test_batch(self, model: BaseChatModel) -> None: - """Test to verify that `model.batch([messages])` works. + """Test to verify that ``model.batch([messages])`` works. This should pass for all integrations. Tests the model's ability to process multiple prompts in a single batch. @@ -836,7 +837,7 @@ class ChatModelIntegrationTests(ChatModelTests): assert len(result.content) > 0 async def test_abatch(self, model: BaseChatModel) -> None: - """Test to verify that `await model.abatch([messages])` works. + """Test to verify that ``await model.abatch([messages])`` works. This should pass for all integrations. Tests the model's ability to process multiple prompts in a single batch asynchronously. @@ -853,6 +854,7 @@ class ChatModelIntegrationTests(ChatModelTests): If those tests pass but not this one, you should make sure your `abatch` method does not raise any exceptions, and that it returns a list of valid :class:`~langchain_core.messages.AIMessage` objects. + """ batch_results = await model.abatch(["Hello", "Hey"]) assert batch_results is not None @@ -881,6 +883,7 @@ class ChatModelIntegrationTests(ChatModelTests): 1. Your model correctly processes the message history 2. The model maintains appropriate context from previous messages 3. The response is a valid :class:`~langchain_core.messages.AIMessage` + """ messages = [ HumanMessage("hello"), @@ -914,6 +917,7 @@ class ChatModelIntegrationTests(ChatModelTests): 1. Your model API can handle double messages, or the integration should merge messages before sending them to the API. 2. The response is a valid :class:`~langchain_core.messages.AIMessage` + """ messages = [ SystemMessage("hello"), @@ -938,7 +942,7 @@ class ChatModelIntegrationTests(ChatModelTests): .. versionchanged:: 0.3.17 - Additionally check for the presence of `model_name` in the response + Additionally check for the presence of ``model_name`` in the response metadata, which is needed for usage tracking in callback handlers. .. dropdown:: Configuration @@ -987,7 +991,7 @@ class ChatModelIntegrationTests(ChatModelTests): If this test fails, first verify that your model returns :class:`~langchain_core.messages.ai.UsageMetadata` dicts - attached to the returned AIMessage object in `_generate`: + attached to the returned AIMessage object in ``_generate``: .. code-block:: python @@ -1105,7 +1109,7 @@ class ChatModelIntegrationTests(ChatModelTests): .. versionchanged:: 0.3.17 - Additionally check for the presence of `model_name` in the response + Additionally check for the presence of ``model_name`` in the response metadata, which is needed for usage tracking in callback handlers. .. dropdown:: Configuration @@ -1152,16 +1156,16 @@ class ChatModelIntegrationTests(ChatModelTests): If this test fails, first verify that your model yields :class:`~langchain_core.messages.ai.UsageMetadata` dicts - attached to the returned AIMessage object in `_stream` + attached to the returned AIMessage object in ``_stream`` that sum up to the total usage metadata. - Note that `input_tokens` should only be included on one of the chunks - (typically the first or the last chunk), and the rest should have 0 or None - to avoid counting input tokens multiple times. + Note that ``input_tokens`` should only be included on one of the chunks + (typically the first or the last chunk), and the rest should have ``0`` or + ``None`` to avoid counting input tokens multiple times. - `output_tokens` typically count the number of tokens in each chunk, not the - sum. This test will pass as long as the sum of `output_tokens` across all - chunks is not 0. + ``output_tokens`` typically count the number of tokens in each chunk, not + the sum. This test will pass as long as the sum of ``output_tokens`` across + all chunks is not ``0``. .. code-block:: python @@ -1261,7 +1265,7 @@ class ChatModelIntegrationTests(ChatModelTests): """Test that model does not fail when invoked with the ``stop`` parameter, which is a standard parameter for stopping generation at a certain token. - More on standard parameters here: https://python.langchain.com/docs/concepts/chat_models/#standard-parameters + `More on standard parameters `__ This should pass for all integrations. @@ -1569,7 +1573,7 @@ class ChatModelIntegrationTests(ChatModelTests): """Test that message histories are compatible with list tool contents (e.g. Anthropic format). - These message histories will include AIMessage objects with "tool use" and + These message histories will include ``AIMessage`` objects with "tool use" and content blocks, e.g., .. code-block:: python @@ -1603,8 +1607,8 @@ class ChatModelIntegrationTests(ChatModelTests): If this test fails, check that: - 1. The model can correctly handle message histories that include AIMessage objects with list content. - 2. The ``tool_calls`` attribute on AIMessage objects is correctly handled and passed to the model in an appropriate format. + 1. The model can correctly handle message histories that include ``AIMessage`` objects with list content. + 2. The ``tool_calls`` attribute on ``AIMessage`` objects is correctly handled and passed to the model in an appropriate format. 3. The model can correctly handle ToolMessage objects with string content and arbitrary string values for ``tool_call_id``. You can ``xfail`` the test if tool calling is implemented but this format @@ -2052,9 +2056,9 @@ class ChatModelIntegrationTests(ChatModelTests): @pytest.mark.skipif(PYDANTIC_MAJOR_VERSION != 2, reason="Test requires pydantic 2.") def test_structured_output_pydantic_2_v1(self, model: BaseChatModel) -> None: """Test to verify we can generate structured output using - pydantic.v1.BaseModel. + ``pydantic.v1.BaseModel``. - pydantic.v1.BaseModel is available in the pydantic 2 package. + ``pydantic.v1.BaseModel`` is available in the pydantic 2 package. This test is optional and should be skipped if the model does not support structured output (see Configuration below). @@ -2686,7 +2690,7 @@ class ChatModelIntegrationTests(ChatModelTests): 1. The model can correctly handle message histories that include message objects with list content. 2. The ``tool_calls`` attribute on AIMessage objects is correctly handled and passed to the model in an appropriate format. - 3. HumanMessages with "tool_result" content blocks are correctly handled. + 3. ``HumanMessage``s with "tool_result" content blocks are correctly handled. Otherwise, if Anthropic tool call and result formats are not supported, set the ``supports_anthropic_inputs`` property to False. @@ -2792,7 +2796,7 @@ class ChatModelIntegrationTests(ChatModelTests): assert isinstance(response, AIMessage) def test_message_with_name(self, model: BaseChatModel) -> None: - """Test that HumanMessage with values for the ``name`` field can be handled. + """Test that ``HumanMessage`` with values for the ``name`` field can be handled. These messages may take the form: @@ -2953,11 +2957,12 @@ class ChatModelIntegrationTests(ChatModelTests): Args: model: The chat model to test tool_choice: Tool choice parameter to pass to bind_tools (provider-specific) - force_tool_call: Whether to force a tool call (use tool_choice=True if None) + force_tool_call: Whether to force a tool call (use ``tool_choice=True`` if None) Tests that Unicode characters in tool call arguments are preserved correctly, - not escaped as \\uXXXX sequences. - """ + not escaped as ``\\uXXXX`` sequences. + + """ # noqa: E501 if not self.has_tool_calling: pytest.skip("Test requires tool calling support.") diff --git a/libs/standard-tests/langchain_tests/unit_tests/chat_models.py b/libs/standard-tests/langchain_tests/unit_tests/chat_models.py index 0e1c3f9b3a3..a42201f2bce 100644 --- a/libs/standard-tests/langchain_tests/unit_tests/chat_models.py +++ b/libs/standard-tests/langchain_tests/unit_tests/chat_models.py @@ -26,6 +26,7 @@ def generate_schema_pydantic_v1_from_2() -> Any: """Use to generate a schema from v1 namespace in pydantic 2. :private: + """ if PYDANTIC_MAJOR_VERSION != 2: msg = "This function is only compatible with Pydantic v2." @@ -44,6 +45,7 @@ def generate_schema_pydantic() -> Any: """Works with either pydantic 1 or 2. :private: + """ class PersonA(BaseModel): @@ -65,6 +67,7 @@ class ChatModelTests(BaseStandardTests): """Base class for chat model tests. :private: + """ @property @@ -148,16 +151,12 @@ class ChatModelTests(BaseStandardTests): @property def supports_image_inputs(self) -> bool: - """(bool) whether the chat model supports image inputs, defaults to - ``False``. - """ + """(bool) whether the chat model supports image inputs, defaults to ``False``.""" # noqa: E501 return False @property def supports_image_urls(self) -> bool: - """(bool) whether the chat model supports image inputs from URLs, defaults to - ``False``. - """ + """(bool) whether the chat model supports image inputs from URLs, defaults to ``False``.""" # noqa: E501 return False @property @@ -167,23 +166,21 @@ class ChatModelTests(BaseStandardTests): @property def supports_audio_inputs(self) -> bool: - """(bool) whether the chat model supports audio inputs, defaults to - ``False``. - """ + """(bool) whether the chat model supports audio inputs, defaults to ``False``.""" # noqa: E501 return False @property def supports_video_inputs(self) -> bool: """(bool) whether the chat model supports video inputs, defaults to ``False``. + No current tests are written for this feature. + """ return False @property def returns_usage_metadata(self) -> bool: - """(bool) whether the chat model returns usage metadata on invoke and streaming - responses. - """ + """(bool) whether the chat model returns usage metadata on invoke and streaming responses.""" # noqa: E501 return True @property @@ -193,9 +190,7 @@ class ChatModelTests(BaseStandardTests): @property def supports_image_tool_message(self) -> bool: - """(bool) whether the chat model supports ``ToolMessage``s that include image - content. - """ + """(bool) whether the chat model supports ``ToolMessage``s that include image content.""" # noqa: E501 return False @property @@ -205,6 +200,7 @@ class ChatModelTests(BaseStandardTests): .. important:: See ``enable_vcr_tests`` dropdown :class:`above ` for more information. + """ return False @@ -806,6 +802,7 @@ class ChatModelUnitTests(ChatModelTests): def init_from_env_params(self) -> tuple[dict, dict, dict]: """(tuple) environment variables, additional initialization args, and expected instance attributes for testing initialization from environment variables. + """ return {}, {}, {} @@ -818,6 +815,7 @@ class ChatModelUnitTests(ChatModelTests): 1. ``chat_model_params`` is specified and the model can be initialized from those params; 2. The model accommodates `standard parameters `__ + """ # noqa: E501 model = self.chat_model_class( **{ @@ -837,6 +835,7 @@ class ChatModelUnitTests(ChatModelTests): If this test fails, ensure that ``init_from_env_params`` is specified correctly and that model parameters are properly set from environment variables during initialization. + """ env_params, model_params, expected_attrs = self.init_from_env_params if not env_params: @@ -861,6 +860,7 @@ class ChatModelUnitTests(ChatModelTests): If this test fails, ensure that the model can be initialized with a boolean ``streaming`` parameter. + """ model = self.chat_model_class( **{ @@ -887,6 +887,7 @@ class ChatModelUnitTests(ChatModelTests): a utility function that will accommodate most formats: https://python.langchain.com/api_reference/core/utils/langchain_core.utils.function_calling.convert_to_openai_tool.html See example implementation of ``bind_tools`` here: https://python.langchain.com/api_reference/_modules/langchain_openai/chat_models/base.html#BaseChatOpenAI.bind_tools + """ if not self.has_tool_calling: return @@ -927,6 +928,7 @@ class ChatModelUnitTests(ChatModelTests): a utility function that will accommodate most formats: https://python.langchain.com/api_reference/core/utils/langchain_core.utils.function_calling.convert_to_openai_tool.html See example implementation of ``with_structured_output`` here: https://python.langchain.com/api_reference/_modules/langchain_openai/chat_models/base.html#BaseChatOpenAI.with_structured_output + """ if not self.has_structured_output: return @@ -949,6 +951,7 @@ class ChatModelUnitTests(ChatModelTests): Check also that the model class is named according to convention (e.g., ``ChatProviderName``). + """ class ExpectedParams(BaseModelV1): @@ -986,6 +989,7 @@ class ChatModelUnitTests(ChatModelTests): If this test fails, check that the ``init_from_env_params`` property is correctly set on the test class. + """ if not self.chat_model_class.is_lc_serializable(): pytest.skip("Model is not serializable.") @@ -1005,6 +1009,7 @@ class ChatModelUnitTests(ChatModelTests): def test_init_time(self, benchmark: BenchmarkFixture) -> None: """Test initialization time of the chat model. If this test fails, check that we are not introducing undue overhead in the model's initialization. + """ def _init_in_loop() -> None: diff --git a/libs/standard-tests/tests/unit_tests/test_custom_chat_model_v1.py b/libs/standard-tests/tests/unit_tests/test_custom_chat_model_v1.py index 091253865b0..171b52681aa 100644 --- a/libs/standard-tests/tests/unit_tests/test_custom_chat_model_v1.py +++ b/libs/standard-tests/tests/unit_tests/test_custom_chat_model_v1.py @@ -102,8 +102,8 @@ class TestChatParrotLinkV1Unit(ChatModelV1UnitTests): return False @property - def supports_enhanced_tool_calls(self) -> bool: - """``ChatParrotLinkV1`` does not support enhanced tool calls.""" + def supports_tool_calls(self) -> bool: + """``ChatParrotLinkV1`` does not support tool calls.""" return False @property