@@ -428,7 +428,8 @@ def supports_audio_inputs(self) -> bool:
428
428
on invoke and streaming responses. Defaults to ``True``.
429
429
430
430
``usage_metadata`` is an optional dict attribute on ``AIMessage``s that track input
431
- and output tokens. `See more. <https://python.langchain.com/api_reference/core/messages/langchain_core.messages.ai.UsageMetadata.html>`__
431
+ and output tokens.
432
+ `See more. <https://python.langchain.com/api_reference/core/messages/langchain_core.messages.ai.UsageMetadata.html>`__
432
433
433
434
Example:
434
435
@@ -525,7 +526,8 @@ def supports_image_tool_message(self) -> bool:
525
526
and stream.
526
527
527
528
``usage_metadata`` is an optional dict attribute on ``AIMessage``s that track input
528
- and output tokens. `See more. <https://python.langchain.com/api_reference/core/messages/langchain_core.messages.ai.UsageMetadata.html>`__
529
+ and output tokens.
530
+ `See more. <https://python.langchain.com/api_reference/core/messages/langchain_core.messages.ai.UsageMetadata.html>`__
529
531
530
532
It includes optional keys ``input_token_details`` and ``output_token_details``
531
533
that can track usage details associated with special types of tokens, such as
@@ -549,7 +551,8 @@ def supports_image_tool_message(self) -> bool:
549
551
def enable_vcr_tests(self) -> bool:
550
552
return True
551
553
552
- 2. Configure VCR to exclude sensitive headers and other information from cassettes.
554
+ 2. Configure VCR to exclude sensitive headers and other information from
555
+ cassettes.
553
556
554
557
.. important::
555
558
VCR will by default record authentication headers and other sensitive
@@ -569,7 +572,9 @@ def enable_vcr_tests(self) -> bool:
569
572
:caption: tests/conftest.py
570
573
571
574
import pytest
572
- from langchain_tests.conftest import _base_vcr_config as _base_vcr_config
575
+ from langchain_tests.conftest import (
576
+ _base_vcr_config as _base_vcr_config,
577
+ )
573
578
574
579
_EXTRA_HEADERS = [
575
580
# Specify additional headers to redact
@@ -603,8 +608,13 @@ def vcr_config(_base_vcr_config: dict) -> dict: # noqa: F811
603
608
:caption: tests/conftest.py
604
609
605
610
import pytest
606
- from langchain_tests.conftest import CustomPersister, CustomSerializer
607
- from langchain_tests.conftest import _base_vcr_config as _base_vcr_config
611
+ from langchain_tests.conftest import (
612
+ CustomPersister,
613
+ CustomSerializer,
614
+ )
615
+ from langchain_tests.conftest import (
616
+ _base_vcr_config as _base_vcr_config,
617
+ )
608
618
from vcr import VCR
609
619
610
620
_EXTRA_HEADERS = [
@@ -648,10 +658,15 @@ def pytest_recording_configure(config: dict, vcr: VCR) -> None:
648
658
649
659
.. code-block:: python
650
660
651
- from langchain_tests.conftest import CustomPersister, CustomSerializer
661
+ from langchain_tests.conftest import (
662
+ CustomPersister,
663
+ CustomSerializer,
664
+ )
652
665
653
666
cassette_path = "/path/to/tests/cassettes/TestClass_test.yaml.gz"
654
- requests, responses = CustomPersister().load_cassette(path, CustomSerializer())
667
+ requests, responses = CustomPersister().load_cassette(
668
+ path, CustomSerializer()
669
+ )
655
670
656
671
3. Run tests to generate VCR cassettes.
657
672
@@ -697,9 +712,9 @@ def test_invoke(self, model: BaseChatModel) -> None:
697
712
.. code-block:: python
698
713
699
714
return ChatResult(
700
- generations=[ChatGeneration(
701
- message=AIMessage(content="Output text")
702
- ) ]
715
+ generations=[
716
+ ChatGeneration( message=AIMessage(content="Output text") )
717
+ ]
703
718
)
704
719
705
720
"""
@@ -730,9 +745,9 @@ async def test_ainvoke(self, model: BaseChatModel) -> None:
730
745
.. code-block:: python
731
746
732
747
return ChatResult(
733
- generations=[ChatGeneration(
734
- message=AIMessage(content="Output text")
735
- ) ]
748
+ generations=[
749
+ ChatGeneration( message=AIMessage(content="Output text") )
750
+ ]
736
751
)
737
752
738
753
"""
@@ -763,9 +778,7 @@ def test_stream(self, model: BaseChatModel) -> None:
763
778
764
779
.. code-block:: python
765
780
766
- yield ChatGenerationChunk(
767
- message=AIMessageChunk(content="chunk text")
768
- )
781
+ yield ChatGenerationChunk(message=AIMessageChunk(content="chunk text"))
769
782
770
783
"""
771
784
num_chunks = 0
@@ -800,9 +813,7 @@ async def test_astream(self, model: BaseChatModel) -> None:
800
813
801
814
.. code-block:: python
802
815
803
- yield ChatGenerationChunk(
804
- message=AIMessageChunk(content="chunk text")
805
- )
816
+ yield ChatGenerationChunk(message=AIMessageChunk(content="chunk text"))
806
817
807
818
"""
808
819
num_chunks = 0
@@ -920,10 +931,11 @@ def test_double_messages_conversation(self, model: BaseChatModel) -> None:
920
931
because this test is the "basic case" without double messages.
921
932
922
933
If that test passes those but not this one, you should verify that:
923
- 1. Your model API can handle double messages, or the integration should merge messages before sending them to the API.
934
+ 1. Your model API can handle double messages, or the integration should
935
+ merge messages before sending them to the API.
924
936
2. The response is a valid :class:`~langchain_core.messages.AIMessage`
925
937
926
- """ # noqa: E501
938
+ """
927
939
messages = [
928
940
SystemMessage ("hello" ),
929
941
SystemMessage ("hello" ),
@@ -1002,25 +1014,27 @@ def supported_usage_metadata_details(self) -> dict:
1002
1014
.. code-block:: python
1003
1015
1004
1016
return ChatResult(
1005
- generations=[ChatGeneration(
1006
- message=AIMessage(
1007
- content="Output text",
1008
- usage_metadata={
1009
- "input_tokens": 350,
1010
- "output_tokens": 240,
1011
- "total_tokens": 590,
1012
- "input_token_details": {
1013
- "audio": 10,
1014
- "cache_creation": 200,
1015
- "cache_read": 100,
1017
+ generations=[
1018
+ ChatGeneration(
1019
+ message=AIMessage(
1020
+ content="Output text",
1021
+ usage_metadata={
1022
+ "input_tokens": 350,
1023
+ "output_tokens": 240,
1024
+ "total_tokens": 590,
1025
+ "input_token_details": {
1026
+ "audio": 10,
1027
+ "cache_creation": 200,
1028
+ "cache_read": 100,
1029
+ },
1030
+ "output_token_details": {
1031
+ "audio": 10,
1032
+ "reasoning": 200,
1033
+ },
1016
1034
},
1017
- "output_token_details": {
1018
- "audio": 10,
1019
- "reasoning": 200,
1020
- }
1021
- }
1035
+ )
1022
1036
)
1023
- ) ]
1037
+ ]
1024
1038
)
1025
1039
1026
1040
Check also that the response includes a ``'model_name'`` key in its
@@ -1173,29 +1187,31 @@ def supported_usage_metadata_details(self) -> dict:
1173
1187
.. code-block:: python
1174
1188
1175
1189
yield ChatResult(
1176
- generations=[ChatGeneration(
1177
- message=AIMessage(
1178
- content="Output text",
1179
- usage_metadata={
1180
- "input_tokens": (
1181
- num_input_tokens if is_first_chunk else 0
1182
- ),
1183
- "output_tokens": 11,
1184
- "total_tokens": (
1185
- 11+num_input_tokens if is_first_chunk else 11
1186
- ),
1187
- "input_token_details": {
1188
- "audio": 10,
1189
- "cache_creation": 200,
1190
- "cache_read": 100,
1190
+ generations=[
1191
+ ChatGeneration(
1192
+ message=AIMessage(
1193
+ content="Output text",
1194
+ usage_metadata={
1195
+ "input_tokens": (
1196
+ num_input_tokens if is_first_chunk else 0
1197
+ ),
1198
+ "output_tokens": 11,
1199
+ "total_tokens": (
1200
+ 11 + num_input_tokens if is_first_chunk else 11
1201
+ ),
1202
+ "input_token_details": {
1203
+ "audio": 10,
1204
+ "cache_creation": 200,
1205
+ "cache_read": 100,
1206
+ },
1207
+ "output_token_details": {
1208
+ "audio": 10,
1209
+ "reasoning": 200,
1210
+ },
1191
1211
},
1192
- "output_token_details": {
1193
- "audio": 10,
1194
- "reasoning": 200,
1195
- }
1196
- }
1212
+ )
1197
1213
)
1198
- ) ]
1214
+ ]
1199
1215
)
1200
1216
1201
1217
Check also that the aggregated response includes a ``'model_name'`` key
@@ -1538,20 +1554,25 @@ def has_tool_calling(self) -> bool:
1538
1554
1539
1555
If this test fails, check that:
1540
1556
1541
- 1. The model can correctly handle message histories that include ``AIMessage`` objects with ``""`` content.
1542
- 2. The ``tool_calls`` attribute on ``AIMessage`` objects is correctly handled and passed to the model in an appropriate format.
1543
- 3. The model can correctly handle ``ToolMessage`` objects with string content and arbitrary string values for ``tool_call_id``.
1557
+ 1. The model can correctly handle message histories that include
1558
+ ``AIMessage`` objects with ``""`` content.
1559
+ 2. The ``tool_calls`` attribute on ``AIMessage`` objects is correctly
1560
+ handled and passed to the model in an appropriate format.
1561
+ 3. The model can correctly handle ``ToolMessage`` objects with string
1562
+ content and arbitrary string values for ``tool_call_id``.
1544
1563
1545
1564
You can ``xfail`` the test if tool calling is implemented but this format
1546
1565
is not supported.
1547
1566
1548
1567
.. code-block:: python
1549
1568
1550
1569
@pytest.mark.xfail(reason=("Not implemented."))
1551
- def test_tool_message_histories_string_content(self, *args: Any) -> None:
1570
+ def test_tool_message_histories_string_content(
1571
+ self, *args: Any
1572
+ ) -> None:
1552
1573
super().test_tool_message_histories_string_content(*args)
1553
1574
1554
- """ # noqa: E501
1575
+ """
1555
1576
if not self .has_tool_calling :
1556
1577
pytest .skip ("Test requires tool calling." )
1557
1578
@@ -1625,9 +1646,12 @@ def has_tool_calling(self) -> bool:
1625
1646
1626
1647
If this test fails, check that:
1627
1648
1628
- 1. The model can correctly handle message histories that include ``AIMessage`` objects with list content.
1629
- 2. The ``tool_calls`` attribute on ``AIMessage`` objects is correctly handled and passed to the model in an appropriate format.
1630
- 3. The model can correctly handle ToolMessage objects with string content and arbitrary string values for ``tool_call_id``.
1649
+ 1. The model can correctly handle message histories that include
1650
+ ``AIMessage`` objects with list content.
1651
+ 2. The ``tool_calls`` attribute on ``AIMessage`` objects is correctly
1652
+ handled and passed to the model in an appropriate format.
1653
+ 3. The model can correctly handle ToolMessage objects with string content
1654
+ and arbitrary string values for ``tool_call_id``.
1631
1655
1632
1656
You can ``xfail`` the test if tool calling is implemented but this format
1633
1657
is not supported.
@@ -1638,7 +1662,7 @@ def has_tool_calling(self) -> bool:
1638
1662
def test_tool_message_histories_list_content(self, *args: Any) -> None:
1639
1663
super().test_tool_message_histories_list_content(*args)
1640
1664
1641
- """ # noqa: E501
1665
+ """
1642
1666
if not self .has_tool_calling :
1643
1667
pytest .skip ("Test requires tool calling." )
1644
1668
@@ -1766,13 +1790,15 @@ def has_tool_calling(self) -> bool:
1766
1790
.. code-block:: python
1767
1791
1768
1792
@pytest.mark.xfail(reason=("Does not support tool_choice."))
1769
- def test_tool_calling_with_no_arguments(self, model: BaseChatModel) -> None:
1793
+ def test_tool_calling_with_no_arguments(
1794
+ self, model: BaseChatModel
1795
+ ) -> None:
1770
1796
super().test_tool_calling_with_no_arguments(model)
1771
1797
1772
1798
Otherwise, in the case that only one tool is bound, ensure that
1773
1799
``tool_choice`` supports the string ``'any'`` to force calling that tool.
1774
1800
1775
- """ # noqa: E501
1801
+ """
1776
1802
if not self .has_tool_calling :
1777
1803
pytest .skip ("Test requires tool calling." )
1778
1804
@@ -2317,7 +2343,6 @@ def test_pdf_inputs(self, model: BaseChatModel) -> None:
2317
2343
.. code-block:: python
2318
2344
2319
2345
class TestMyChatModelIntegration(ChatModelIntegrationTests):
2320
-
2321
2346
@property
2322
2347
def supports_pdf_inputs(self) -> bool:
2323
2348
return False
@@ -2394,7 +2419,6 @@ def test_audio_inputs(self, model: BaseChatModel) -> None:
2394
2419
.. code-block:: python
2395
2420
2396
2421
class TestMyChatModelIntegration(ChatModelIntegrationTests):
2397
-
2398
2422
@property
2399
2423
def supports_audio_inputs(self) -> bool:
2400
2424
return False
@@ -2704,7 +2728,8 @@ def test_anthropic_inputs(self, model: BaseChatModel) -> None:
2704
2728
"content": [
2705
2729
{
2706
2730
"type": "text",
2707
- "text": "green is a great pick! that's my sister's favorite color", # noqa: E501
2731
+ "text": "green is a great pick! "
2732
+ "that's my sister's favorite color",
2708
2733
}
2709
2734
],
2710
2735
"is_error": False,
@@ -2732,14 +2757,17 @@ def supports_anthropic_inputs(self) -> bool:
2732
2757
2733
2758
If this test fails, check that:
2734
2759
2735
- 1. The model can correctly handle message histories that include message objects with list content.
2736
- 2. The ``tool_calls`` attribute on AIMessage objects is correctly handled and passed to the model in an appropriate format.
2737
- 3. ``HumanMessage``s with "tool_result" content blocks are correctly handled.
2760
+ 1. The model can correctly handle message histories that include message
2761
+ objects with list content.
2762
+ 2. The ``tool_calls`` attribute on AIMessage objects is correctly handled
2763
+ and passed to the model in an appropriate format.
2764
+ 3. ``HumanMessage``s with "tool_result" content blocks are correctly
2765
+ handled.
2738
2766
2739
2767
Otherwise, if Anthropic tool call and result formats are not supported,
2740
2768
set the ``supports_anthropic_inputs`` property to False.
2741
2769
2742
- """ # noqa: E501
2770
+ """
2743
2771
if not self .supports_anthropic_inputs :
2744
2772
pytest .skip ("Model does not explicitly support Anthropic inputs." )
2745
2773
@@ -3017,13 +3045,15 @@ def test_unicode_tool_call_integration(
3017
3045
3018
3046
Args:
3019
3047
model: The chat model to test
3020
- tool_choice: Tool choice parameter to pass to ``bind_tools()`` (provider-specific)
3021
- force_tool_call: Whether to force a tool call (use ``tool_choice=True`` if None)
3048
+ tool_choice: Tool choice parameter to pass to ``bind_tools()``
3049
+ (provider-specific)
3050
+ force_tool_call: Whether to force a tool call
3051
+ (use ``tool_choice=True`` if None)
3022
3052
3023
3053
Tests that Unicode characters in tool call arguments are preserved correctly,
3024
3054
not escaped as ``\\uXXXX`` sequences.
3025
3055
3026
- """ # noqa: E501
3056
+ """
3027
3057
if not self .has_tool_calling :
3028
3058
pytest .skip ("Test requires tool calling support." )
3029
3059
0 commit comments