langchain 1.0.2__tar.gz → 1.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. {langchain-1.0.2 → langchain-1.1.0}/.gitignore +5 -0
  2. {langchain-1.0.2 → langchain-1.1.0}/Makefile +12 -2
  3. {langchain-1.0.2 → langchain-1.1.0}/PKG-INFO +6 -4
  4. {langchain-1.0.2 → langchain-1.1.0}/README.md +1 -1
  5. {langchain-1.0.2 → langchain-1.1.0}/langchain/__init__.py +1 -1
  6. langchain-1.1.0/langchain/agents/__init__.py +9 -0
  7. {langchain-1.0.2 → langchain-1.1.0}/langchain/agents/factory.py +171 -67
  8. {langchain-1.0.2 → langchain-1.1.0}/langchain/agents/middleware/__init__.py +5 -7
  9. {langchain-1.0.2 → langchain-1.1.0}/langchain/agents/middleware/_execution.py +21 -20
  10. langchain-1.1.0/langchain/agents/middleware/_retry.py +123 -0
  11. {langchain-1.0.2 → langchain-1.1.0}/langchain/agents/middleware/context_editing.py +24 -22
  12. {langchain-1.0.2 → langchain-1.1.0}/langchain/agents/middleware/file_search.py +18 -13
  13. {langchain-1.0.2 → langchain-1.1.0}/langchain/agents/middleware/human_in_the_loop.py +52 -48
  14. {langchain-1.0.2 → langchain-1.1.0}/langchain/agents/middleware/model_call_limit.py +58 -14
  15. {langchain-1.0.2 → langchain-1.1.0}/langchain/agents/middleware/model_fallback.py +5 -7
  16. langchain-1.1.0/langchain/agents/middleware/model_retry.py +300 -0
  17. {langchain-1.0.2 → langchain-1.1.0}/langchain/agents/middleware/pii.py +72 -25
  18. {langchain-1.0.2 → langchain-1.1.0}/langchain/agents/middleware/shell_tool.py +96 -91
  19. langchain-1.1.0/langchain/agents/middleware/summarization.py +478 -0
  20. {langchain-1.0.2 → langchain-1.1.0}/langchain/agents/middleware/todo.py +30 -24
  21. langchain-1.1.0/langchain/agents/middleware/tool_call_limit.py +487 -0
  22. {langchain-1.0.2 → langchain-1.1.0}/langchain/agents/middleware/tool_emulator.py +45 -36
  23. {langchain-1.0.2 → langchain-1.1.0}/langchain/agents/middleware/tool_retry.py +170 -158
  24. {langchain-1.0.2 → langchain-1.1.0}/langchain/agents/middleware/tool_selection.py +34 -24
  25. {langchain-1.0.2 → langchain-1.1.0}/langchain/agents/middleware/types.py +651 -375
  26. {langchain-1.0.2 → langchain-1.1.0}/langchain/agents/structured_output.py +8 -2
  27. langchain-1.1.0/langchain/chat_models/__init__.py +7 -0
  28. {langchain-1.0.2 → langchain-1.1.0}/langchain/chat_models/base.py +83 -53
  29. {langchain-1.0.2 → langchain-1.1.0}/langchain/embeddings/__init__.py +1 -6
  30. {langchain-1.0.2 → langchain-1.1.0}/langchain/embeddings/base.py +22 -16
  31. {langchain-1.0.2 → langchain-1.1.0}/langchain/messages/__init__.py +7 -6
  32. {langchain-1.0.2 → langchain-1.1.0}/langchain/tools/__init__.py +1 -7
  33. langchain-1.1.0/langchain/tools/tool_node.py +20 -0
  34. {langchain-1.0.2 → langchain-1.1.0}/pyproject.toml +10 -9
  35. langchain-1.1.0/tests/cassettes/test_inference_to_native_output[False].yaml.gz +0 -0
  36. langchain-1.1.0/tests/cassettes/test_inference_to_native_output[True].yaml.gz +0 -0
  37. langchain-1.1.0/tests/cassettes/test_inference_to_tool_output[False].yaml.gz +0 -0
  38. langchain-1.1.0/tests/cassettes/test_inference_to_tool_output[True].yaml.gz +0 -0
  39. {langchain-1.0.2 → langchain-1.1.0}/tests/integration_tests/agents/middleware/test_shell_tool_integration.py +1 -1
  40. {langchain-1.0.2 → langchain-1.1.0}/tests/integration_tests/chat_models/test_base.py +1 -1
  41. langchain-1.1.0/tests/unit_tests/agents/__snapshots__/test_middleware_framework.ambr +212 -0
  42. langchain-1.1.0/tests/unit_tests/agents/middleware/__snapshots__/test_middleware_decorators.ambr +95 -0
  43. langchain-1.1.0/tests/unit_tests/agents/middleware/__snapshots__/test_middleware_diagram.ambr +289 -0
  44. langchain-1.1.0/tests/unit_tests/agents/middleware/__snapshots__/test_middleware_framework.ambr +212 -0
  45. langchain-1.1.0/tests/unit_tests/agents/middleware/core/__snapshots__/test_decorators.ambr +95 -0
  46. langchain-1.1.0/tests/unit_tests/agents/middleware/core/__snapshots__/test_diagram.ambr +289 -0
  47. langchain-1.1.0/tests/unit_tests/agents/middleware/core/__snapshots__/test_framework.ambr +212 -0
  48. langchain-1.0.2/tests/unit_tests/agents/test_handler_composition.py → langchain-1.1.0/tests/unit_tests/agents/middleware/core/test_composition.py +1 -3
  49. langchain-1.0.2/tests/unit_tests/agents/test_middleware_decorators.py → langchain-1.1.0/tests/unit_tests/agents/middleware/core/test_decorators.py +3 -5
  50. langchain-1.1.0/tests/unit_tests/agents/middleware/core/test_diagram.py +193 -0
  51. langchain-1.1.0/tests/unit_tests/agents/middleware/core/test_framework.py +1051 -0
  52. langchain-1.0.2/tests/unit_tests/agents/middleware/test_override_methods.py → langchain-1.1.0/tests/unit_tests/agents/middleware/core/test_overrides.py +1 -1
  53. langchain-1.0.2/tests/unit_tests/agents/test_sync_async_tool_wrapper_composition.py → langchain-1.1.0/tests/unit_tests/agents/middleware/core/test_sync_async_wrappers.py +2 -2
  54. langchain-1.0.2/tests/unit_tests/agents/test_middleware_tools.py → langchain-1.1.0/tests/unit_tests/agents/middleware/core/test_tools.py +14 -12
  55. langchain-1.0.2/tests/unit_tests/agents/middleware/test_wrap_model_call_middleware.py → langchain-1.1.0/tests/unit_tests/agents/middleware/core/test_wrap_model_call.py +550 -74
  56. langchain-1.0.2/tests/unit_tests/agents/middleware/test_wrap_tool_call_decorator.py → langchain-1.1.0/tests/unit_tests/agents/middleware/core/test_wrap_tool_call.py +2 -2
  57. langchain-1.0.2/tests/unit_tests/agents/test_context_editing_middleware.py → langchain-1.1.0/tests/unit_tests/agents/middleware/implementations/test_context_editing.py +76 -28
  58. {langchain-1.0.2/tests/unit_tests/agents/middleware → langchain-1.1.0/tests/unit_tests/agents/middleware/implementations}/test_file_search.py +105 -0
  59. langchain-1.1.0/tests/unit_tests/agents/middleware/implementations/test_human_in_the_loop.py +737 -0
  60. langchain-1.1.0/tests/unit_tests/agents/middleware/implementations/test_model_call_limit.py +224 -0
  61. langchain-1.0.2/tests/unit_tests/agents/test_model_fallback_middleware.py → langchain-1.1.0/tests/unit_tests/agents/middleware/implementations/test_model_fallback.py +145 -9
  62. langchain-1.1.0/tests/unit_tests/agents/middleware/implementations/test_model_retry.py +689 -0
  63. langchain-1.0.2/tests/unit_tests/agents/test_pii_middleware.py → langchain-1.1.0/tests/unit_tests/agents/middleware/implementations/test_pii.py +1 -1
  64. langchain-1.1.0/tests/unit_tests/agents/middleware/implementations/test_shell_tool.py +556 -0
  65. langchain-1.1.0/tests/unit_tests/agents/middleware/implementations/test_structured_output_retry.py +369 -0
  66. langchain-1.1.0/tests/unit_tests/agents/middleware/implementations/test_summarization.py +894 -0
  67. langchain-1.1.0/tests/unit_tests/agents/middleware/implementations/test_todo.py +516 -0
  68. langchain-1.1.0/tests/unit_tests/agents/middleware/implementations/test_tool_call_limit.py +789 -0
  69. {langchain-1.0.2/tests/unit_tests/agents/middleware → langchain-1.1.0/tests/unit_tests/agents/middleware/implementations}/test_tool_emulator.py +1 -1
  70. {langchain-1.0.2/tests/unit_tests/agents/middleware → langchain-1.1.0/tests/unit_tests/agents/middleware/implementations}/test_tool_retry.py +143 -32
  71. langchain-1.0.2/tests/unit_tests/agents/middleware/test_llm_tool_selection.py → langchain-1.1.0/tests/unit_tests/agents/middleware/implementations/test_tool_selection.py +17 -8
  72. {langchain-1.0.2 → langchain-1.1.0}/tests/unit_tests/agents/model.py +2 -3
  73. langchain-1.1.0/tests/unit_tests/agents/test_create_agent_tool_validation.py +370 -0
  74. {langchain-1.0.2 → langchain-1.1.0}/tests/unit_tests/agents/test_injected_runtime_create_agent.py +244 -1
  75. {langchain-1.0.2 → langchain-1.1.0}/tests/unit_tests/agents/test_response_format.py +53 -3
  76. langchain-1.1.0/tests/unit_tests/agents/test_response_format_integration.py +142 -0
  77. langchain-1.1.0/tests/unit_tests/agents/test_system_message.py +1013 -0
  78. {langchain-1.0.2 → langchain-1.1.0}/tests/unit_tests/chat_models/test_chat_models.py +4 -4
  79. {langchain-1.0.2 → langchain-1.1.0}/tests/unit_tests/conftest.py +44 -0
  80. langchain-1.1.0/tests/unit_tests/embeddings/__init__.py +0 -0
  81. langchain-1.1.0/tests/unit_tests/tools/__init__.py +0 -0
  82. langchain-1.1.0/uv.lock +5408 -0
  83. langchain-1.0.2/langchain/agents/__init__.py +0 -15
  84. langchain-1.0.2/langchain/agents/middleware/summarization.py +0 -249
  85. langchain-1.0.2/langchain/agents/middleware/tool_call_limit.py +0 -333
  86. langchain-1.0.2/langchain/chat_models/__init__.py +0 -13
  87. langchain-1.0.2/langchain/tools/tool_node.py +0 -1786
  88. langchain-1.0.2/tests/integration_tests/agents/test_response_format.py +0 -79
  89. langchain-1.0.2/tests/unit_tests/agents/middleware/test_before_after_agent.py +0 -286
  90. langchain-1.0.2/tests/unit_tests/agents/middleware/test_shell_tool.py +0 -175
  91. langchain-1.0.2/tests/unit_tests/agents/middleware/test_wrap_model_call_decorator.py +0 -355
  92. langchain-1.0.2/tests/unit_tests/agents/test_middleware_agent.py +0 -2600
  93. langchain-1.0.2/tests/unit_tests/agents/test_on_tool_call_middleware.py +0 -828
  94. langchain-1.0.2/tests/unit_tests/agents/test_todo_middleware.py +0 -172
  95. langchain-1.0.2/tests/unit_tests/agents/test_tool_call_limit.py +0 -454
  96. langchain-1.0.2/tests/unit_tests/agents/test_tool_node.py +0 -1716
  97. langchain-1.0.2/tests/unit_tests/agents/test_tool_node_interceptor_unregistered.py +0 -571
  98. langchain-1.0.2/tests/unit_tests/agents/test_tool_node_validation_error_filtering.py +0 -678
  99. langchain-1.0.2/tests/unit_tests/tools/test_on_tool_call.py +0 -1287
  100. langchain-1.0.2/uv.lock +0 -4781
  101. {langchain-1.0.2 → langchain-1.1.0}/LICENSE +0 -0
  102. {langchain-1.0.2 → langchain-1.1.0}/extended_testing_deps.txt +0 -0
  103. {langchain-1.0.2 → langchain-1.1.0}/langchain/agents/middleware/_redaction.py +0 -0
  104. {langchain-1.0.2 → langchain-1.1.0}/langchain/py.typed +0 -0
  105. {langchain-1.0.2 → langchain-1.1.0}/langchain/rate_limiters/__init__.py +0 -0
  106. {langchain-1.0.2 → langchain-1.1.0}/scripts/check_imports.py +0 -0
  107. {langchain-1.0.2 → langchain-1.1.0}/tests/__init__.py +0 -0
  108. {langchain-1.0.2 → langchain-1.1.0}/tests/integration_tests/__init__.py +0 -0
  109. {langchain-1.0.2 → langchain-1.1.0}/tests/integration_tests/agents/__init__.py +0 -0
  110. {langchain-1.0.2 → langchain-1.1.0}/tests/integration_tests/agents/middleware/__init__.py +0 -0
  111. {langchain-1.0.2 → langchain-1.1.0}/tests/integration_tests/cache/__init__.py +0 -0
  112. {langchain-1.0.2 → langchain-1.1.0}/tests/integration_tests/cache/fake_embeddings.py +0 -0
  113. {langchain-1.0.2 → langchain-1.1.0}/tests/integration_tests/chat_models/__init__.py +0 -0
  114. {langchain-1.0.2 → langchain-1.1.0}/tests/integration_tests/conftest.py +0 -0
  115. {langchain-1.0.2 → langchain-1.1.0}/tests/integration_tests/embeddings/__init__.py +0 -0
  116. {langchain-1.0.2 → langchain-1.1.0}/tests/integration_tests/embeddings/test_base.py +0 -0
  117. {langchain-1.0.2 → langchain-1.1.0}/tests/integration_tests/test_compile.py +0 -0
  118. {langchain-1.0.2 → langchain-1.1.0}/tests/unit_tests/__init__.py +0 -0
  119. {langchain-1.0.2 → langchain-1.1.0}/tests/unit_tests/agents/__init__.py +0 -0
  120. {langchain-1.0.2 → langchain-1.1.0}/tests/unit_tests/agents/__snapshots__/test_middleware_agent.ambr +0 -0
  121. {langchain-1.0.2 → langchain-1.1.0}/tests/unit_tests/agents/__snapshots__/test_middleware_decorators.ambr +0 -0
  122. {langchain-1.0.2 → langchain-1.1.0}/tests/unit_tests/agents/__snapshots__/test_return_direct_graph.ambr +0 -0
  123. {langchain-1.0.2 → langchain-1.1.0}/tests/unit_tests/agents/any_str.py +0 -0
  124. {langchain-1.0.2 → langchain-1.1.0}/tests/unit_tests/agents/compose-postgres.yml +0 -0
  125. {langchain-1.0.2 → langchain-1.1.0}/tests/unit_tests/agents/compose-redis.yml +0 -0
  126. {langchain-1.0.2 → langchain-1.1.0}/tests/unit_tests/agents/conftest.py +0 -0
  127. {langchain-1.0.2 → langchain-1.1.0}/tests/unit_tests/agents/conftest_checkpointer.py +0 -0
  128. {langchain-1.0.2 → langchain-1.1.0}/tests/unit_tests/agents/conftest_store.py +0 -0
  129. {langchain-1.0.2 → langchain-1.1.0}/tests/unit_tests/agents/memory_assert.py +0 -0
  130. {langchain-1.0.2 → langchain-1.1.0}/tests/unit_tests/agents/messages.py +0 -0
  131. {langchain-1.0.2 → langchain-1.1.0}/tests/unit_tests/agents/middleware/__init__.py +0 -0
  132. {langchain-1.0.2/tests/unit_tests/chat_models → langchain-1.1.0/tests/unit_tests/agents/middleware/core}/__init__.py +0 -0
  133. {langchain-1.0.2/tests/unit_tests/embeddings → langchain-1.1.0/tests/unit_tests/agents/middleware/implementations}/__init__.py +0 -0
  134. {langchain-1.0.2/tests/unit_tests/agents/middleware → langchain-1.1.0/tests/unit_tests/agents/middleware/implementations}/test_shell_execution_policies.py +0 -0
  135. {langchain-1.0.2 → langchain-1.1.0}/tests/unit_tests/agents/specifications/responses.json +0 -0
  136. {langchain-1.0.2 → langchain-1.1.0}/tests/unit_tests/agents/specifications/return_direct.json +0 -0
  137. {langchain-1.0.2 → langchain-1.1.0}/tests/unit_tests/agents/test_react_agent.py +0 -0
  138. {langchain-1.0.2 → langchain-1.1.0}/tests/unit_tests/agents/test_responses.py +0 -0
  139. {langchain-1.0.2 → langchain-1.1.0}/tests/unit_tests/agents/test_responses_spec.py +0 -0
  140. {langchain-1.0.2 → langchain-1.1.0}/tests/unit_tests/agents/test_return_direct_graph.py +0 -0
  141. {langchain-1.0.2 → langchain-1.1.0}/tests/unit_tests/agents/test_return_direct_spec.py +0 -0
  142. {langchain-1.0.2 → langchain-1.1.0}/tests/unit_tests/agents/test_state_schema.py +0 -0
  143. {langchain-1.0.2 → langchain-1.1.0}/tests/unit_tests/agents/utils.py +0 -0
  144. {langchain-1.0.2/tests/unit_tests/tools → langchain-1.1.0/tests/unit_tests/chat_models}/__init__.py +0 -0
  145. {langchain-1.0.2 → langchain-1.1.0}/tests/unit_tests/embeddings/test_base.py +0 -0
  146. {langchain-1.0.2 → langchain-1.1.0}/tests/unit_tests/embeddings/test_imports.py +0 -0
  147. {langchain-1.0.2 → langchain-1.1.0}/tests/unit_tests/stubs.py +0 -0
  148. {langchain-1.0.2 → langchain-1.1.0}/tests/unit_tests/test_dependencies.py +0 -0
  149. {langchain-1.0.2 → langchain-1.1.0}/tests/unit_tests/test_imports.py +0 -0
  150. {langchain-1.0.2 → langchain-1.1.0}/tests/unit_tests/test_pytest_config.py +0 -0
  151. {langchain-1.0.2 → langchain-1.1.0}/tests/unit_tests/tools/test_imports.py +0 -0
@@ -1,6 +1,8 @@
1
1
  .vs/
2
2
  .claude/
3
3
  .idea/
4
+ #Emacs backup
5
+ *~
4
6
  # Byte-compiled / optimized / DLL files
5
7
  __pycache__/
6
8
  *.py[cod]
@@ -161,3 +163,6 @@ node_modules
161
163
 
162
164
  prof
163
165
  virtualenv/
166
+ scratch/
167
+
168
+ .langgraph_api/
@@ -1,4 +1,4 @@
1
- .PHONY: all start_services stop_services coverage test test_fast extended_tests test_watch test_watch_extended integration_tests check_imports lint format lint_diff format_diff lint_package lint_tests help
1
+ .PHONY: all start_services stop_services coverage coverage_agents test test_fast extended_tests test_watch test_watch_extended integration_tests check_imports lint format lint_diff format_diff lint_package lint_tests help
2
2
 
3
3
  # Default target executed when no arguments are given to make.
4
4
  all: help
@@ -27,8 +27,17 @@ coverage:
27
27
  --cov-report term-missing:skip-covered \
28
28
  $(TEST_FILE)
29
29
 
30
+ # Run middleware and agent tests with coverage report.
31
+ coverage_agents:
32
+ uv run --group test pytest \
33
+ tests/unit_tests/agents/middleware/ \
34
+ tests/unit_tests/agents/test_*.py \
35
+ --cov=langchain.agents \
36
+ --cov-report=term-missing \
37
+ --cov-report=html:htmlcov \
38
+
30
39
  test:
31
- make start_services && LANGGRAPH_TEST_FAST=0 uv run --group test pytest -n auto --disable-socket --allow-unix-socket $(TEST_FILE) --cov-report term-missing:skip-covered; \
40
+ make start_services && LANGGRAPH_TEST_FAST=0 uv run --no-sync --active --group test pytest -n auto --disable-socket --allow-unix-socket $(TEST_FILE) --cov-report term-missing:skip-covered --snapshot-update; \
32
41
  EXIT_CODE=$$?; \
33
42
  make stop_services; \
34
43
  exit $$EXIT_CODE
@@ -93,6 +102,7 @@ help:
93
102
  @echo 'lint - run linters'
94
103
  @echo '-- TESTS --'
95
104
  @echo 'coverage - run unit tests and generate coverage report'
105
+ @echo 'coverage_agents - run middleware and agent tests with coverage report'
96
106
  @echo 'test - run unit tests with all services'
97
107
  @echo 'test_fast - run unit tests with in-memory services only'
98
108
  @echo 'tests - run unit tests (alias for "make test")'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: langchain
3
- Version: 1.0.2
3
+ Version: 1.1.0
4
4
  Summary: Building applications with LLMs through composability
5
5
  Project-URL: Homepage, https://docs.langchain.com/
6
6
  Project-URL: Documentation, https://reference.langchain.com/python/langchain/langchain/
@@ -12,13 +12,15 @@ Project-URL: Reddit, https://www.reddit.com/r/LangChain/
12
12
  License: MIT
13
13
  License-File: LICENSE
14
14
  Requires-Python: <4.0.0,>=3.10.0
15
- Requires-Dist: langchain-core<2.0.0,>=1.0.0
16
- Requires-Dist: langgraph<1.1.0,>=1.0.0
15
+ Requires-Dist: langchain-core<2.0.0,>=1.1.0
16
+ Requires-Dist: langgraph<1.1.0,>=1.0.2
17
17
  Requires-Dist: pydantic<3.0.0,>=2.7.4
18
18
  Provides-Extra: anthropic
19
19
  Requires-Dist: langchain-anthropic; extra == 'anthropic'
20
20
  Provides-Extra: aws
21
21
  Requires-Dist: langchain-aws; extra == 'aws'
22
+ Provides-Extra: azure-ai
23
+ Requires-Dist: langchain-azure-ai; extra == 'azure-ai'
22
24
  Provides-Extra: community
23
25
  Requires-Dist: langchain-community; extra == 'community'
24
26
  Provides-Extra: deepseek
@@ -75,7 +77,7 @@ LangChain [agents](https://docs.langchain.com/oss/python/langchain/agents) are b
75
77
 
76
78
  ## 📖 Documentation
77
79
 
78
- For full documentation, see the [API reference](https://reference.langchain.com/python/langchain_classic).
80
+ For full documentation, see the [API reference](https://reference.langchain.com/python/langchain/langchain/). For conceptual guides, tutorials, and examples on using LangChain, see the [LangChain Docs](https://docs.langchain.com/oss/python/langchain/overview).
79
81
 
80
82
  ## 📕 Releases & Versioning
81
83
 
@@ -26,7 +26,7 @@ LangChain [agents](https://docs.langchain.com/oss/python/langchain/agents) are b
26
26
 
27
27
  ## 📖 Documentation
28
28
 
29
- For full documentation, see the [API reference](https://reference.langchain.com/python/langchain_classic).
29
+ For full documentation, see the [API reference](https://reference.langchain.com/python/langchain/langchain/). For conceptual guides, tutorials, and examples on using LangChain, see the [LangChain Docs](https://docs.langchain.com/oss/python/langchain/overview).
30
30
 
31
31
  ## 📕 Releases & Versioning
32
32
 
@@ -1,3 +1,3 @@
1
1
  """Main entrypoint into LangChain."""
2
2
 
3
- __version__ = "1.0.1"
3
+ __version__ = "1.1.0"
@@ -0,0 +1,9 @@
1
+ """Entrypoint to building [Agents](https://docs.langchain.com/oss/python/langchain/agents) with LangChain.""" # noqa: E501
2
+
3
+ from langchain.agents.factory import create_agent
4
+ from langchain.agents.middleware.types import AgentState
5
+
6
+ __all__ = [
7
+ "AgentState",
8
+ "create_agent",
9
+ ]
@@ -3,7 +3,15 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import itertools
6
- from typing import TYPE_CHECKING, Annotated, Any, cast, get_args, get_origin, get_type_hints
6
+ from typing import (
7
+ TYPE_CHECKING,
8
+ Annotated,
9
+ Any,
10
+ cast,
11
+ get_args,
12
+ get_origin,
13
+ get_type_hints,
14
+ )
7
15
 
8
16
  from langchain_core.language_models.chat_models import BaseChatModel
9
17
  from langchain_core.messages import AIMessage, AnyMessage, SystemMessage, ToolMessage
@@ -11,10 +19,11 @@ from langchain_core.tools import BaseTool
11
19
  from langgraph._internal._runnable import RunnableCallable
12
20
  from langgraph.constants import END, START
13
21
  from langgraph.graph.state import StateGraph
22
+ from langgraph.prebuilt.tool_node import ToolCallWithContext, ToolNode
14
23
  from langgraph.runtime import Runtime # noqa: TC002
15
24
  from langgraph.types import Command, Send
16
25
  from langgraph.typing import ContextT # noqa: TC002
17
- from typing_extensions import NotRequired, Required, TypedDict, TypeVar
26
+ from typing_extensions import NotRequired, Required, TypedDict
18
27
 
19
28
  from langchain.agents.middleware.types import (
20
29
  AgentMiddleware,
@@ -23,6 +32,8 @@ from langchain.agents.middleware.types import (
23
32
  ModelRequest,
24
33
  ModelResponse,
25
34
  OmitFromSchema,
35
+ ResponseT,
36
+ StateT_co,
26
37
  _InputAgentState,
27
38
  _OutputAgentState,
28
39
  )
@@ -33,11 +44,11 @@ from langchain.agents.structured_output import (
33
44
  ProviderStrategy,
34
45
  ProviderStrategyBinding,
35
46
  ResponseFormat,
47
+ StructuredOutputError,
36
48
  StructuredOutputValidationError,
37
49
  ToolStrategy,
38
50
  )
39
51
  from langchain.chat_models import init_chat_model
40
- from langchain.tools.tool_node import ToolCallWithContext, _ToolNode
41
52
 
42
53
  if TYPE_CHECKING:
43
54
  from collections.abc import Awaitable, Callable, Sequence
@@ -48,11 +59,21 @@ if TYPE_CHECKING:
48
59
  from langgraph.store.base import BaseStore
49
60
  from langgraph.types import Checkpointer
50
61
 
51
- from langchain.tools.tool_node import ToolCallRequest, ToolCallWrapper
62
+ from langchain.agents.middleware.types import ToolCallRequest, ToolCallWrapper
52
63
 
53
64
  STRUCTURED_OUTPUT_ERROR_TEMPLATE = "Error: {error}\n Please fix your mistakes."
54
65
 
55
- ResponseT = TypeVar("ResponseT")
66
+ FALLBACK_MODELS_WITH_STRUCTURED_OUTPUT = [
67
+ # if model profile data are not available, these models are assumed to support
68
+ # structured output
69
+ "grok",
70
+ "gpt-5",
71
+ "gpt-4.1",
72
+ "gpt-4o",
73
+ "gpt-oss",
74
+ "o3-pro",
75
+ "o3-mini",
76
+ ]
56
77
 
57
78
 
58
79
  def _normalize_to_model_response(result: ModelResponse | AIMessage) -> ModelResponse:
@@ -340,11 +361,13 @@ def _get_can_jump_to(middleware: AgentMiddleware[Any, Any], hook_name: str) -> l
340
361
  return []
341
362
 
342
363
 
343
- def _supports_provider_strategy(model: str | BaseChatModel) -> bool:
364
+ def _supports_provider_strategy(model: str | BaseChatModel, tools: list | None = None) -> bool:
344
365
  """Check if a model supports provider-specific structured output.
345
366
 
346
367
  Args:
347
368
  model: Model name string or `BaseChatModel` instance.
369
+ tools: Optional list of tools provided to the agent. Needed because some models
370
+ don't support structured output together with tool calling.
348
371
 
349
372
  Returns:
350
373
  `True` if the model supports provider-specific structured output, `False` otherwise.
@@ -353,11 +376,23 @@ def _supports_provider_strategy(model: str | BaseChatModel) -> bool:
353
376
  if isinstance(model, str):
354
377
  model_name = model
355
378
  elif isinstance(model, BaseChatModel):
356
- model_name = getattr(model, "model_name", None)
379
+ model_name = (
380
+ getattr(model, "model_name", None)
381
+ or getattr(model, "model", None)
382
+ or getattr(model, "model_id", "")
383
+ )
384
+ model_profile = model.profile
385
+ if (
386
+ model_profile is not None
387
+ and model_profile.get("structured_output")
388
+ # We make an exception for Gemini models, which currently do not support
389
+ # simultaneous tool use with structured output
390
+ and not (tools and isinstance(model_name, str) and "gemini" in model_name.lower())
391
+ ):
392
+ return True
357
393
 
358
394
  return (
359
- "grok" in model_name.lower()
360
- or any(part in model_name for part in ["gpt-5", "gpt-4.1", "gpt-oss", "o3-pro", "o3-mini"])
395
+ any(part in model_name.lower() for part in FALLBACK_MODELS_WITH_STRUCTURED_OUTPUT)
361
396
  if model_name
362
397
  else False
363
398
  )
@@ -507,8 +542,8 @@ def create_agent( # noqa: PLR0915
507
542
  model: str | BaseChatModel,
508
543
  tools: Sequence[BaseTool | Callable | dict[str, Any]] | None = None,
509
544
  *,
510
- system_prompt: str | None = None,
511
- middleware: Sequence[AgentMiddleware[AgentState[ResponseT], ContextT]] = (),
545
+ system_prompt: str | SystemMessage | None = None,
546
+ middleware: Sequence[AgentMiddleware[StateT_co, ContextT]] = (),
512
547
  response_format: ResponseFormat[ResponseT] | type[ResponseT] | None = None,
513
548
  state_schema: type[AgentState[ResponseT]] | None = None,
514
549
  context_schema: type[ContextT] | None = None,
@@ -528,45 +563,88 @@ def create_agent( # noqa: PLR0915
528
563
  visit the [Agents](https://docs.langchain.com/oss/python/langchain/agents) docs.
529
564
 
530
565
  Args:
531
- model: The language model for the agent. Can be a string identifier
532
- (e.g., `"openai:gpt-4"`) or a chat model instance (e.g., `ChatOpenAI()`).
566
+ model: The language model for the agent.
567
+
568
+ Can be a string identifier (e.g., `"openai:gpt-4"`) or a direct chat model
569
+ instance (e.g., [`ChatOpenAI`][langchain_openai.ChatOpenAI] or other another
570
+ [LangChain chat model](https://docs.langchain.com/oss/python/integrations/chat)).
571
+
533
572
  For a full list of supported model strings, see
534
573
  [`init_chat_model`][langchain.chat_models.init_chat_model(model_provider)].
535
- tools: A list of tools, `dicts`, or `Callable`. If `None` or an empty list,
536
- the agent will consist of a model node without a tool calling loop.
537
- system_prompt: An optional system prompt for the LLM. Prompts are converted to a
538
- `SystemMessage` and added to the beginning of the message list.
574
+
575
+ !!! tip ""
576
+
577
+ See the [Models](https://docs.langchain.com/oss/python/langchain/models)
578
+ docs for more information.
579
+ tools: A list of tools, `dict`, or `Callable`.
580
+
581
+ If `None` or an empty list, the agent will consist of a model node without a
582
+ tool calling loop.
583
+
584
+
585
+ !!! tip ""
586
+
587
+ See the [Tools](https://docs.langchain.com/oss/python/langchain/tools)
588
+ docs for more information.
589
+ system_prompt: An optional system prompt for the LLM.
590
+
591
+ Can be a `str` (which will be converted to a `SystemMessage`) or a
592
+ `SystemMessage` instance directly. The system message is added to the
593
+ beginning of the message list when calling the model.
539
594
  middleware: A sequence of middleware instances to apply to the agent.
595
+
540
596
  Middleware can intercept and modify agent behavior at various stages.
597
+
598
+ !!! tip ""
599
+
600
+ See the [Middleware](https://docs.langchain.com/oss/python/langchain/middleware)
601
+ docs for more information.
541
602
  response_format: An optional configuration for structured responses.
603
+
542
604
  Can be a `ToolStrategy`, `ProviderStrategy`, or a Pydantic model class.
605
+
543
606
  If provided, the agent will handle structured output during the
544
- conversation flow. Raw schemas will be wrapped in an appropriate strategy
545
- based on model capabilities.
607
+ conversation flow.
608
+
609
+ Raw schemas will be wrapped in an appropriate strategy based on model
610
+ capabilities.
611
+
612
+ !!! tip ""
613
+
614
+ See the [Structured output](https://docs.langchain.com/oss/python/langchain/structured-output)
615
+ docs for more information.
546
616
  state_schema: An optional `TypedDict` schema that extends `AgentState`.
617
+
547
618
  When provided, this schema is used instead of `AgentState` as the base
548
619
  schema for merging with middleware state schemas. This allows users to
549
620
  add custom state fields without needing to create custom middleware.
550
- Generally, it's recommended to use state_schema extensions via middleware
621
+
622
+ Generally, it's recommended to use `state_schema` extensions via middleware
551
623
  to keep relevant extensions scoped to corresponding hooks / tools.
552
- The schema must be a subclass of `AgentState[ResponseT]`.
553
624
  context_schema: An optional schema for runtime context.
554
- checkpointer: An optional checkpoint saver object. This is used for persisting
555
- the state of the graph (e.g., as chat memory) for a single thread
556
- (e.g., a single conversation).
557
- store: An optional store object. This is used for persisting data
558
- across multiple threads (e.g., multiple conversations / users).
625
+ checkpointer: An optional checkpoint saver object.
626
+
627
+ Used for persisting the state of the graph (e.g., as chat memory) for a
628
+ single thread (e.g., a single conversation).
629
+ store: An optional store object.
630
+
631
+ Used for persisting data across multiple threads (e.g., multiple
632
+ conversations / users).
559
633
  interrupt_before: An optional list of node names to interrupt before.
634
+
560
635
  Useful if you want to add a user confirmation or other interrupt
561
636
  before taking an action.
562
637
  interrupt_after: An optional list of node names to interrupt after.
638
+
563
639
  Useful if you want to return directly or run additional processing
564
640
  on an output.
565
- debug: Whether to enable verbose logging for graph execution. When enabled,
566
- prints detailed information about each node execution, state updates,
567
- and transitions during agent runtime. Useful for debugging middleware
568
- behavior and understanding agent execution flow.
641
+ debug: Whether to enable verbose logging for graph execution.
642
+
643
+ When enabled, prints detailed information about each node execution, state
644
+ updates, and transitions during agent runtime. Useful for debugging
645
+ middleware behavior and understanding agent execution flow.
569
646
  name: An optional name for the `CompiledStateGraph`.
647
+
570
648
  This name will be automatically used when adding the agent graph to
571
649
  another graph as a subgraph node - particularly useful for building
572
650
  multi-agent systems.
@@ -576,11 +654,12 @@ def create_agent( # noqa: PLR0915
576
654
  A compiled `StateGraph` that can be used for chat interactions.
577
655
 
578
656
  The agent node calls the language model with the messages list (after applying
579
- the system prompt). If the resulting `AIMessage` contains `tool_calls`, the graph
580
- will then call the tools. The tools node executes the tools and adds the responses
581
- to the messages list as `ToolMessage` objects. The agent node then calls the
582
- language model again. The process repeats until no more `tool_calls` are
583
- present in the response. The agent then returns the full list of messages.
657
+ the system prompt). If the resulting [`AIMessage`][langchain.messages.AIMessage]
658
+ contains `tool_calls`, the graph will then call the tools. The tools node executes
659
+ the tools and adds the responses to the messages list as
660
+ [`ToolMessage`][langchain.messages.ToolMessage] objects. The agent node then calls
661
+ the language model again. The process repeats until no more `tool_calls` are present
662
+ in the response. The agent then returns the full list of messages.
584
663
 
585
664
  Example:
586
665
  ```python
@@ -593,7 +672,7 @@ def create_agent( # noqa: PLR0915
593
672
 
594
673
 
595
674
  graph = create_agent(
596
- model="anthropic:claude-sonnet-4-5",
675
+ model="anthropic:claude-sonnet-4-5-20250929",
597
676
  tools=[check_weather],
598
677
  system_prompt="You are a helpful assistant",
599
678
  )
@@ -606,6 +685,14 @@ def create_agent( # noqa: PLR0915
606
685
  if isinstance(model, str):
607
686
  model = init_chat_model(model)
608
687
 
688
+ # Convert system_prompt to SystemMessage if needed
689
+ system_message: SystemMessage | None = None
690
+ if system_prompt is not None:
691
+ if isinstance(system_prompt, SystemMessage):
692
+ system_message = system_prompt
693
+ else:
694
+ system_message = SystemMessage(content=system_prompt)
695
+
609
696
  # Handle tools being None or empty
610
697
  if tools is None:
611
698
  tools = []
@@ -675,7 +762,7 @@ def create_agent( # noqa: PLR0915
675
762
  awrap_tool_call_wrapper = _chain_async_tool_call_wrappers(async_wrappers)
676
763
 
677
764
  # Setup tools
678
- tool_node: _ToolNode | None = None
765
+ tool_node: ToolNode | None = None
679
766
  # Extract built-in provider tools (dict format) and regular tools (BaseTool/callables)
680
767
  built_in_tools = [t for t in tools if isinstance(t, dict)]
681
768
  regular_tools = [t for t in tools if not isinstance(t, dict)]
@@ -685,7 +772,7 @@ def create_agent( # noqa: PLR0915
685
772
 
686
773
  # Only create ToolNode if we have client-side tools
687
774
  tool_node = (
688
- _ToolNode(
775
+ ToolNode(
689
776
  tools=available_tools,
690
777
  wrap_tool_call=wrap_tool_call_wrapper,
691
778
  awrap_tool_call=awrap_tool_call_wrapper,
@@ -762,7 +849,7 @@ def create_agent( # noqa: PLR0915
762
849
  async_handlers = [m.awrap_model_call for m in middleware_w_awrap_model_call]
763
850
  awrap_model_call_handler = _chain_async_model_call_handlers(async_handlers)
764
851
 
765
- state_schemas = {m.state_schema for m in middleware}
852
+ state_schemas: set[type] = {m.state_schema for m in middleware}
766
853
  # Use provided state_schema if available, otherwise use base AgentState
767
854
  base_state = state_schema if state_schema is not None else AgentState
768
855
  state_schemas.add(base_state)
@@ -797,8 +884,16 @@ def create_agent( # noqa: PLR0915
797
884
  provider_strategy_binding = ProviderStrategyBinding.from_schema_spec(
798
885
  effective_response_format.schema_spec
799
886
  )
800
- structured_response = provider_strategy_binding.parse(output)
801
- return {"messages": [output], "structured_response": structured_response}
887
+ try:
888
+ structured_response = provider_strategy_binding.parse(output)
889
+ except Exception as exc: # noqa: BLE001
890
+ schema_name = getattr(
891
+ effective_response_format.schema_spec.schema, "__name__", "response_format"
892
+ )
893
+ validation_error = StructuredOutputValidationError(schema_name, exc, output)
894
+ raise validation_error
895
+ else:
896
+ return {"messages": [output], "structured_response": structured_response}
802
897
  return {"messages": [output]}
803
898
 
804
899
  # Handle structured output with tool strategy
@@ -812,11 +907,11 @@ def create_agent( # noqa: PLR0915
812
907
  ]
813
908
 
814
909
  if structured_tool_calls:
815
- exception: Exception | None = None
910
+ exception: StructuredOutputError | None = None
816
911
  if len(structured_tool_calls) > 1:
817
912
  # Handle multiple structured outputs error
818
913
  tool_names = [tc["name"] for tc in structured_tool_calls]
819
- exception = MultipleStructuredOutputsError(tool_names)
914
+ exception = MultipleStructuredOutputsError(tool_names, output)
820
915
  should_retry, error_message = _handle_structured_output_error(
821
916
  exception, effective_response_format
822
917
  )
@@ -858,7 +953,7 @@ def create_agent( # noqa: PLR0915
858
953
  "structured_response": structured_response,
859
954
  }
860
955
  except Exception as exc: # noqa: BLE001
861
- exception = StructuredOutputValidationError(tool_call["name"], exc)
956
+ exception = StructuredOutputValidationError(tool_call["name"], exc, output)
862
957
  should_retry, error_message = _handle_structured_output_error(
863
958
  exception, effective_response_format
864
959
  )
@@ -927,7 +1022,7 @@ def create_agent( # noqa: PLR0915
927
1022
  effective_response_format: ResponseFormat | None
928
1023
  if isinstance(request.response_format, AutoStrategy):
929
1024
  # User provided raw schema via AutoStrategy - auto-detect best strategy based on model
930
- if _supports_provider_strategy(request.model):
1025
+ if _supports_provider_strategy(request.model, tools=request.tools):
931
1026
  # Model supports provider strategy - use it
932
1027
  effective_response_format = ProviderStrategy(schema=request.response_format.schema)
933
1028
  else:
@@ -948,7 +1043,7 @@ def create_agent( # noqa: PLR0915
948
1043
 
949
1044
  # Bind model based on effective response format
950
1045
  if isinstance(effective_response_format, ProviderStrategy):
951
- # Use provider-specific structured output
1046
+ # (Backward compatibility) Use OpenAI format structured output
952
1047
  kwargs = effective_response_format.to_model_kwargs()
953
1048
  return (
954
1049
  request.model.bind_tools(
@@ -1001,8 +1096,8 @@ def create_agent( # noqa: PLR0915
1001
1096
  # Get the bound model (with auto-detection if needed)
1002
1097
  model_, effective_response_format = _get_bound_model(request)
1003
1098
  messages = request.messages
1004
- if request.system_prompt:
1005
- messages = [SystemMessage(request.system_prompt), *messages]
1099
+ if request.system_message:
1100
+ messages = [request.system_message, *messages]
1006
1101
 
1007
1102
  output = model_.invoke(messages)
1008
1103
 
@@ -1021,7 +1116,7 @@ def create_agent( # noqa: PLR0915
1021
1116
  request = ModelRequest(
1022
1117
  model=model,
1023
1118
  tools=default_tools,
1024
- system_prompt=system_prompt,
1119
+ system_message=system_message,
1025
1120
  response_format=initial_response_format,
1026
1121
  messages=state["messages"],
1027
1122
  tool_choice=None,
@@ -1054,8 +1149,8 @@ def create_agent( # noqa: PLR0915
1054
1149
  # Get the bound model (with auto-detection if needed)
1055
1150
  model_, effective_response_format = _get_bound_model(request)
1056
1151
  messages = request.messages
1057
- if request.system_prompt:
1058
- messages = [SystemMessage(request.system_prompt), *messages]
1152
+ if request.system_message:
1153
+ messages = [request.system_message, *messages]
1059
1154
 
1060
1155
  output = await model_.ainvoke(messages)
1061
1156
 
@@ -1074,7 +1169,7 @@ def create_agent( # noqa: PLR0915
1074
1169
  request = ModelRequest(
1075
1170
  model=model,
1076
1171
  tools=default_tools,
1077
- system_prompt=system_prompt,
1172
+ system_message=system_message,
1078
1173
  response_format=initial_response_format,
1079
1174
  messages=state["messages"],
1080
1175
  tool_choice=None,
@@ -1229,11 +1324,14 @@ def create_agent( # noqa: PLR0915
1229
1324
 
1230
1325
  graph.add_conditional_edges(
1231
1326
  "tools",
1232
- _make_tools_to_model_edge(
1233
- tool_node=tool_node,
1234
- model_destination=loop_entry_node,
1235
- structured_output_tools=structured_output_tools,
1236
- end_destination=exit_node,
1327
+ RunnableCallable(
1328
+ _make_tools_to_model_edge(
1329
+ tool_node=tool_node,
1330
+ model_destination=loop_entry_node,
1331
+ structured_output_tools=structured_output_tools,
1332
+ end_destination=exit_node,
1333
+ ),
1334
+ trace=False,
1237
1335
  ),
1238
1336
  tools_to_model_destinations,
1239
1337
  )
@@ -1250,19 +1348,25 @@ def create_agent( # noqa: PLR0915
1250
1348
 
1251
1349
  graph.add_conditional_edges(
1252
1350
  loop_exit_node,
1253
- _make_model_to_tools_edge(
1254
- model_destination=loop_entry_node,
1255
- structured_output_tools=structured_output_tools,
1256
- end_destination=exit_node,
1351
+ RunnableCallable(
1352
+ _make_model_to_tools_edge(
1353
+ model_destination=loop_entry_node,
1354
+ structured_output_tools=structured_output_tools,
1355
+ end_destination=exit_node,
1356
+ ),
1357
+ trace=False,
1257
1358
  ),
1258
1359
  model_to_tools_destinations,
1259
1360
  )
1260
1361
  elif len(structured_output_tools) > 0:
1261
1362
  graph.add_conditional_edges(
1262
1363
  loop_exit_node,
1263
- _make_model_to_model_edge(
1264
- model_destination=loop_entry_node,
1265
- end_destination=exit_node,
1364
+ RunnableCallable(
1365
+ _make_model_to_model_edge(
1366
+ model_destination=loop_entry_node,
1367
+ end_destination=exit_node,
1368
+ ),
1369
+ trace=False,
1266
1370
  ),
1267
1371
  [loop_entry_node, exit_node],
1268
1372
  )
@@ -1372,7 +1476,7 @@ def create_agent( # noqa: PLR0915
1372
1476
  debug=debug,
1373
1477
  name=name,
1374
1478
  cache=cache,
1375
- )
1479
+ ).with_config({"recursion_limit": 10_000})
1376
1480
 
1377
1481
 
1378
1482
  def _resolve_jump(
@@ -1491,7 +1595,7 @@ def _make_model_to_model_edge(
1491
1595
 
1492
1596
  def _make_tools_to_model_edge(
1493
1597
  *,
1494
- tool_node: _ToolNode,
1598
+ tool_node: ToolNode,
1495
1599
  model_destination: str,
1496
1600
  structured_output_tools: dict[str, OutputToolBinding],
1497
1601
  end_destination: str,
@@ -1563,7 +1667,7 @@ def _add_middleware_edge(
1563
1667
  if "model" in can_jump_to and name != model_destination:
1564
1668
  destinations.append(model_destination)
1565
1669
 
1566
- graph.add_conditional_edges(name, jump_edge, destinations)
1670
+ graph.add_conditional_edges(name, RunnableCallable(jump_edge, trace=False), destinations)
1567
1671
 
1568
1672
  else:
1569
1673
  graph.add_edge(name, default_destination)
@@ -1,21 +1,17 @@
1
- """Entrypoint to using [Middleware](https://docs.langchain.com/oss/python/langchain/middleware) plugins with [Agents](https://docs.langchain.com/oss/python/langchain/agents).
2
-
3
- !!! warning "Reference docs"
4
- This page contains **reference documentation** for Middleware. See
5
- [the docs](https://docs.langchain.com/oss/python/langchain/middleware) for conceptual
6
- guides, tutorials, and examples on using Middleware.
7
- """ # noqa: E501
1
+ """Entrypoint to using [middleware](https://docs.langchain.com/oss/python/langchain/middleware) plugins with [Agents](https://docs.langchain.com/oss/python/langchain/agents).""" # noqa: E501
8
2
 
9
3
  from .context_editing import (
10
4
  ClearToolUsesEdit,
11
5
  ContextEditingMiddleware,
12
6
  )
7
+ from .file_search import FilesystemFileSearchMiddleware
13
8
  from .human_in_the_loop import (
14
9
  HumanInTheLoopMiddleware,
15
10
  InterruptOnConfig,
16
11
  )
17
12
  from .model_call_limit import ModelCallLimitMiddleware
18
13
  from .model_fallback import ModelFallbackMiddleware
14
+ from .model_retry import ModelRetryMiddleware
19
15
  from .pii import PIIDetectionError, PIIMiddleware
20
16
  from .shell_tool import (
21
17
  CodexSandboxExecutionPolicy,
@@ -52,6 +48,7 @@ __all__ = [
52
48
  "CodexSandboxExecutionPolicy",
53
49
  "ContextEditingMiddleware",
54
50
  "DockerExecutionPolicy",
51
+ "FilesystemFileSearchMiddleware",
55
52
  "HostExecutionPolicy",
56
53
  "HumanInTheLoopMiddleware",
57
54
  "InterruptOnConfig",
@@ -61,6 +58,7 @@ __all__ = [
61
58
  "ModelFallbackMiddleware",
62
59
  "ModelRequest",
63
60
  "ModelResponse",
61
+ "ModelRetryMiddleware",
64
62
  "PIIDetectionError",
65
63
  "PIIMiddleware",
66
64
  "RedactionRule",