langgraph 1.2.4__tar.gz → 1.2.6__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 (165) hide show
  1. {langgraph-1.2.4 → langgraph-1.2.6}/Makefile +2 -5
  2. langgraph-1.2.6/PKG-INFO +78 -0
  3. langgraph-1.2.6/README.md +46 -0
  4. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/_internal/_config.py +69 -13
  5. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/_internal/_constants.py +9 -0
  6. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/pregel/main.py +46 -2
  7. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/stream/run_stream.py +62 -7
  8. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/types.py +1 -1
  9. {langgraph-1.2.4 → langgraph-1.2.6}/pyproject.toml +21 -12
  10. langgraph-1.2.6/tests/test_delta_channel_update_state.py +294 -0
  11. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_large_cases.py +7 -0
  12. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_large_cases_async.py +7 -0
  13. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_pregel.py +2 -0
  14. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_pregel_async.py +111 -272
  15. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_pregel_stream_events_v3.py +158 -0
  16. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_stream_events_v3.py +1 -1
  17. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_subgraph_persistence.py +46 -0
  18. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_subgraph_persistence_async.py +47 -0
  19. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_utils.py +243 -0
  20. {langgraph-1.2.4 → langgraph-1.2.6}/uv.lock +407 -535
  21. langgraph-1.2.4/PKG-INFO +0 -133
  22. langgraph-1.2.4/README.md +0 -101
  23. {langgraph-1.2.4 → langgraph-1.2.6}/.gitignore +0 -0
  24. {langgraph-1.2.4 → langgraph-1.2.6}/LICENSE +0 -0
  25. {langgraph-1.2.4 → langgraph-1.2.6}/bench/__init__.py +0 -0
  26. {langgraph-1.2.4 → langgraph-1.2.6}/bench/__main__.py +0 -0
  27. {langgraph-1.2.4 → langgraph-1.2.6}/bench/fanout_to_subgraph.py +0 -0
  28. {langgraph-1.2.4 → langgraph-1.2.6}/bench/pydantic_state.py +0 -0
  29. {langgraph-1.2.4 → langgraph-1.2.6}/bench/react_agent.py +0 -0
  30. {langgraph-1.2.4 → langgraph-1.2.6}/bench/sequential.py +0 -0
  31. {langgraph-1.2.4 → langgraph-1.2.6}/bench/serde_allowlist.py +0 -0
  32. {langgraph-1.2.4 → langgraph-1.2.6}/bench/wide_dict.py +0 -0
  33. {langgraph-1.2.4 → langgraph-1.2.6}/bench/wide_state.py +0 -0
  34. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/_internal/__init__.py +0 -0
  35. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/_internal/_cache.py +0 -0
  36. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/_internal/_fields.py +0 -0
  37. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/_internal/_future.py +0 -0
  38. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/_internal/_pydantic.py +0 -0
  39. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/_internal/_queue.py +0 -0
  40. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/_internal/_replay.py +0 -0
  41. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/_internal/_retry.py +0 -0
  42. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/_internal/_runnable.py +0 -0
  43. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/_internal/_scratchpad.py +0 -0
  44. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/_internal/_serde.py +0 -0
  45. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/_internal/_timeout.py +0 -0
  46. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/_internal/_typing.py +0 -0
  47. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/callbacks.py +0 -0
  48. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/channels/__init__.py +0 -0
  49. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/channels/any_value.py +0 -0
  50. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/channels/base.py +0 -0
  51. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/channels/binop.py +0 -0
  52. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/channels/delta.py +0 -0
  53. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/channels/ephemeral_value.py +0 -0
  54. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/channels/last_value.py +0 -0
  55. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/channels/named_barrier_value.py +0 -0
  56. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/channels/topic.py +0 -0
  57. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/channels/untracked_value.py +0 -0
  58. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/config.py +0 -0
  59. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/constants.py +0 -0
  60. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/errors.py +0 -0
  61. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/func/__init__.py +0 -0
  62. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/graph/__init__.py +0 -0
  63. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/graph/_branch.py +0 -0
  64. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/graph/_node.py +0 -0
  65. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/graph/message.py +0 -0
  66. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/graph/state.py +0 -0
  67. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/graph/ui.py +0 -0
  68. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/managed/__init__.py +0 -0
  69. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/managed/base.py +0 -0
  70. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/managed/is_last_step.py +0 -0
  71. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/pregel/__init__.py +0 -0
  72. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/pregel/_algo.py +0 -0
  73. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/pregel/_call.py +0 -0
  74. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/pregel/_checkpoint.py +0 -0
  75. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/pregel/_config.py +0 -0
  76. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/pregel/_draw.py +0 -0
  77. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/pregel/_executor.py +0 -0
  78. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/pregel/_io.py +0 -0
  79. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/pregel/_log.py +0 -0
  80. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/pregel/_loop.py +0 -0
  81. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/pregel/_messages.py +0 -0
  82. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/pregel/_read.py +0 -0
  83. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/pregel/_remote_run_stream.py +0 -0
  84. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/pregel/_retry.py +0 -0
  85. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/pregel/_runner.py +0 -0
  86. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/pregel/_tools.py +0 -0
  87. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/pregel/_utils.py +0 -0
  88. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/pregel/_validate.py +0 -0
  89. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/pregel/_write.py +0 -0
  90. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/pregel/debug.py +0 -0
  91. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/pregel/protocol.py +0 -0
  92. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/pregel/remote.py +0 -0
  93. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/pregel/types.py +0 -0
  94. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/py.typed +0 -0
  95. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/runtime.py +0 -0
  96. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/stream/__init__.py +0 -0
  97. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/stream/_convert.py +0 -0
  98. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/stream/_mux.py +0 -0
  99. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/stream/_types.py +0 -0
  100. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/stream/stream_channel.py +0 -0
  101. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/stream/transformers.py +0 -0
  102. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/typing.py +0 -0
  103. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/utils/__init__.py +0 -0
  104. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/utils/config.py +0 -0
  105. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/utils/runnable.py +0 -0
  106. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/version.py +0 -0
  107. {langgraph-1.2.4 → langgraph-1.2.6}/langgraph/warnings.py +0 -0
  108. {langgraph-1.2.4 → langgraph-1.2.6}/tests/__init__.py +0 -0
  109. {langgraph-1.2.4 → langgraph-1.2.6}/tests/__snapshots__/test_large_cases.ambr +0 -0
  110. {langgraph-1.2.4 → langgraph-1.2.6}/tests/__snapshots__/test_pregel.ambr +0 -0
  111. {langgraph-1.2.4 → langgraph-1.2.6}/tests/__snapshots__/test_pregel_async.ambr +0 -0
  112. {langgraph-1.2.4 → langgraph-1.2.6}/tests/agents.py +0 -0
  113. {langgraph-1.2.4 → langgraph-1.2.6}/tests/any_int.py +0 -0
  114. {langgraph-1.2.4 → langgraph-1.2.6}/tests/any_str.py +0 -0
  115. {langgraph-1.2.4 → langgraph-1.2.6}/tests/compose-postgres.yml +0 -0
  116. {langgraph-1.2.4 → langgraph-1.2.6}/tests/compose-redis.yml +0 -0
  117. {langgraph-1.2.4 → langgraph-1.2.6}/tests/conftest.py +0 -0
  118. {langgraph-1.2.4 → langgraph-1.2.6}/tests/conftest_checkpointer.py +0 -0
  119. {langgraph-1.2.4 → langgraph-1.2.6}/tests/conftest_store.py +0 -0
  120. {langgraph-1.2.4 → langgraph-1.2.6}/tests/example_app/example_graph.py +0 -0
  121. {langgraph-1.2.4 → langgraph-1.2.6}/tests/example_app/langgraph.json +0 -0
  122. {langgraph-1.2.4 → langgraph-1.2.6}/tests/example_app/requirements.txt +0 -0
  123. {langgraph-1.2.4 → langgraph-1.2.6}/tests/fake_chat.py +0 -0
  124. {langgraph-1.2.4 → langgraph-1.2.6}/tests/fake_tracer.py +0 -0
  125. {langgraph-1.2.4 → langgraph-1.2.6}/tests/memory_assert.py +0 -0
  126. {langgraph-1.2.4 → langgraph-1.2.6}/tests/messages.py +0 -0
  127. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_algo.py +0 -0
  128. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_channels.py +0 -0
  129. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_checkpoint_migration.py +0 -0
  130. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_config_async.py +0 -0
  131. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_delta_channel_benchmark.py +0 -0
  132. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_delta_channel_exit_mode.py +0 -0
  133. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_delta_channel_id_stability.py +0 -0
  134. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_delta_channel_migration.py +0 -0
  135. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_delta_channel_supersteps_bound.py +0 -0
  136. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_deprecation.py +0 -0
  137. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_graph_callbacks.py +0 -0
  138. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_interleave_arrival_order.py +0 -0
  139. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_interrupt_migration.py +0 -0
  140. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_interruption.py +0 -0
  141. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_managed_values.py +0 -0
  142. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_messages_state.py +0 -0
  143. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_parent_command.py +0 -0
  144. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_parent_command_async.py +0 -0
  145. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_pregel_debug.py +0 -0
  146. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_pydantic.py +0 -0
  147. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_remote_graph.py +0 -0
  148. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_remote_graph_v3.py +0 -0
  149. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_retry.py +0 -0
  150. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_runnable.py +0 -0
  151. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_runtime.py +0 -0
  152. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_serde_allowlist.py +0 -0
  153. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_state.py +0 -0
  154. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_stream_before_builtins.py +0 -0
  155. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_stream_data_transformers.py +0 -0
  156. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_stream_events_v3_e2e.py +0 -0
  157. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_stream_events_v3_kwarg_forwarding.py +0 -0
  158. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_stream_lifecycle_transformer.py +0 -0
  159. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_stream_messages_transformer.py +0 -0
  160. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_stream_subgraph_transformer.py +0 -0
  161. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_time_travel.py +0 -0
  162. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_time_travel_async.py +0 -0
  163. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_tool_stream_handler.py +0 -0
  164. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_tracing_interops.py +0 -0
  165. {langgraph-1.2.4 → langgraph-1.2.6}/tests/test_type_checking.py +0 -0
@@ -111,22 +111,19 @@ test_watch_all:
111
111
 
112
112
  # Define a variable for Python and notebook files.
113
113
  PYTHON_FILES=.
114
- MYPY_CACHE=.mypy_cache
115
114
  lint format: PYTHON_FILES=.
116
115
  lint_diff format_diff: PYTHON_FILES=$(shell git diff --name-only --relative --diff-filter=d main . | grep -E r'\.py$$|\.ipynb$$')
117
116
  lint_package: PYTHON_FILES=langgraph
118
117
  lint_tests: PYTHON_FILES=tests
119
- lint_tests: MYPY_CACHE=.mypy_cache_test
120
118
 
121
119
  lint lint_diff lint_package lint_tests:
122
120
  uv run ruff check .
123
121
  [ "$(PYTHON_FILES)" = "" ] || uv run ruff format $(PYTHON_FILES) --diff
124
122
  [ "$(PYTHON_FILES)" = "" ] || uv run ruff check --select I $(PYTHON_FILES)
125
- [ "$(PYTHON_FILES)" = "" ] || mkdir -p $(MYPY_CACHE)
126
- [ "$(PYTHON_FILES)" = "" ] || uv run mypy langgraph --cache-dir $(MYPY_CACHE)
123
+ [ "$(PYTHON_FILES)" = "" ] || uv run ty check langgraph
127
124
 
128
125
  type:
129
- mkdir -p $(MYPY_CACHE) && uv run mypy langgraph --cache-dir $(MYPY_CACHE)
126
+ uv run ty check langgraph
130
127
 
131
128
  format format_diff:
132
129
  uv run ruff format $(PYTHON_FILES)
@@ -0,0 +1,78 @@
1
+ Metadata-Version: 2.4
2
+ Name: langgraph
3
+ Version: 1.2.6
4
+ Summary: Building stateful, multi-actor applications with LLMs
5
+ Project-URL: Homepage, https://docs.langchain.com/oss/python/langgraph/overview
6
+ Project-URL: Documentation, https://reference.langchain.com/python/langgraph/
7
+ Project-URL: Source, https://github.com/langchain-ai/langgraph/tree/main/libs/langgraph
8
+ Project-URL: Changelog, https://github.com/langchain-ai/langgraph/releases
9
+ Project-URL: Twitter, https://x.com/langchain_oss
10
+ Project-URL: Slack, https://www.langchain.com/join-community
11
+ Project-URL: Reddit, https://www.reddit.com/r/LangChain/
12
+ License-Expression: MIT
13
+ License-File: LICENSE
14
+ Classifier: Development Status :: 5 - Production/Stable
15
+ Classifier: Programming Language :: Python
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Programming Language :: Python :: Implementation :: CPython
23
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
24
+ Requires-Python: >=3.10
25
+ Requires-Dist: langchain-core<2,>=1.4.7
26
+ Requires-Dist: langgraph-checkpoint<5.0.0,>=4.1.0
27
+ Requires-Dist: langgraph-prebuilt<1.2.0,>=1.1.0
28
+ Requires-Dist: langgraph-sdk<0.5.0,>=0.4.2
29
+ Requires-Dist: pydantic>=2.7.4
30
+ Requires-Dist: xxhash>=3.5.0
31
+ Description-Content-Type: text/markdown
32
+
33
+ # 🦜🕸️ LangGraph
34
+
35
+ [![PyPI - Version](https://img.shields.io/pypi/v/langgraph?label=%20)](https://pypi.org/project/langgraph/#history)
36
+ [![PyPI - License](https://img.shields.io/pypi/l/langgraph)](https://opensource.org/licenses/MIT)
37
+ [![PyPI - Downloads](https://img.shields.io/pepy/dt/langgraph)](https://pypistats.org/packages/langgraph)
38
+ [![Open Issues](https://img.shields.io/github/issues-raw/langchain-ai/langgraph)](https://github.com/langchain-ai/langgraph/issues)
39
+ [![Twitter](https://img.shields.io/twitter/url/https/twitter.com/langchain_oss.svg?style=social&label=Follow%20%40LangChain)](https://x.com/langchain_oss)
40
+
41
+ Looking for the JS/TS version? Check out [LangGraph.js](https://github.com/langchain-ai/langgraphjs).
42
+
43
+ To help you ship LangGraph apps to production faster, check out [LangSmith](https://www.langchain.com/langsmith).
44
+ [LangSmith](https://www.langchain.com/langsmith) is a unified developer platform for building, testing, and monitoring LLM applications.
45
+
46
+ ## Quick Install
47
+
48
+ ```bash
49
+ uv add langgraph
50
+ ```
51
+
52
+ ## 🤔 What is this?
53
+
54
+ LangGraph is a low-level orchestration framework for building, managing, and deploying long-running, stateful agents. LangGraph provides the infrastructure for durable execution, streaming, human-in-the-loop, persistence, memory, and more.
55
+
56
+ We recommend you use LangGraph when you have advanced needs that require a combination of deterministic and agentic workflows, heavy customization, and carefully controlled latency. Use [LangChain](https://docs.langchain.com/oss/python/langchain/overview) when you want to quickly build agents and applications powered by LLMs using pre-built agent architectures and model integrations.
57
+
58
+ LangChain [agents](https://docs.langchain.com/oss/python/langchain/agents) are built on top of LangGraph in order to provide durable execution, streaming, human-in-the-loop, persistence, and more. (You do not need to know LangGraph for basic LangChain agent usage.)
59
+
60
+ Trusted by companies shaping the future of agents – including Klarna, Replit, Elastic, and more – LangGraph is used to ship AI applications at scale.
61
+
62
+ ## 📖 Documentation
63
+
64
+ For full documentation, see the [API reference](https://reference.langchain.com/python/langgraph/). For conceptual guides, tutorials, and examples on using LangGraph, see the [LangGraph Docs](https://docs.langchain.com/oss/python/langgraph/overview). Get started with the [LangGraph Quickstart](https://docs.langchain.com/oss/python/langgraph/quickstart).
65
+
66
+ ## 📕 Releases & Versioning
67
+
68
+ See our [Releases](https://docs.langchain.com/oss/python/release-policy) and [Versioning](https://docs.langchain.com/oss/python/versioning) policies.
69
+
70
+ ## 💁 Contributing
71
+
72
+ As an open-source project in a rapidly developing field, we are extremely open to contributions, whether it be in the form of a new feature, improved infrastructure, or better documentation.
73
+
74
+ For detailed information on how to contribute, see the [Contributing Guide](https://docs.langchain.com/oss/python/contributing/overview).
75
+
76
+ ## Acknowledgements
77
+
78
+ LangGraph is inspired by [Pregel](https://research.google/pubs/pub37252/) and [Apache Beam](https://beam.apache.org/). The public interface draws inspiration from [NetworkX](https://networkx.org/documentation/latest/). LangGraph is built by LangChain Inc, the creators of LangChain, but can be used without LangChain.
@@ -0,0 +1,46 @@
1
+ # 🦜🕸️ LangGraph
2
+
3
+ [![PyPI - Version](https://img.shields.io/pypi/v/langgraph?label=%20)](https://pypi.org/project/langgraph/#history)
4
+ [![PyPI - License](https://img.shields.io/pypi/l/langgraph)](https://opensource.org/licenses/MIT)
5
+ [![PyPI - Downloads](https://img.shields.io/pepy/dt/langgraph)](https://pypistats.org/packages/langgraph)
6
+ [![Open Issues](https://img.shields.io/github/issues-raw/langchain-ai/langgraph)](https://github.com/langchain-ai/langgraph/issues)
7
+ [![Twitter](https://img.shields.io/twitter/url/https/twitter.com/langchain_oss.svg?style=social&label=Follow%20%40LangChain)](https://x.com/langchain_oss)
8
+
9
+ Looking for the JS/TS version? Check out [LangGraph.js](https://github.com/langchain-ai/langgraphjs).
10
+
11
+ To help you ship LangGraph apps to production faster, check out [LangSmith](https://www.langchain.com/langsmith).
12
+ [LangSmith](https://www.langchain.com/langsmith) is a unified developer platform for building, testing, and monitoring LLM applications.
13
+
14
+ ## Quick Install
15
+
16
+ ```bash
17
+ uv add langgraph
18
+ ```
19
+
20
+ ## 🤔 What is this?
21
+
22
+ LangGraph is a low-level orchestration framework for building, managing, and deploying long-running, stateful agents. LangGraph provides the infrastructure for durable execution, streaming, human-in-the-loop, persistence, memory, and more.
23
+
24
+ We recommend you use LangGraph when you have advanced needs that require a combination of deterministic and agentic workflows, heavy customization, and carefully controlled latency. Use [LangChain](https://docs.langchain.com/oss/python/langchain/overview) when you want to quickly build agents and applications powered by LLMs using pre-built agent architectures and model integrations.
25
+
26
+ LangChain [agents](https://docs.langchain.com/oss/python/langchain/agents) are built on top of LangGraph in order to provide durable execution, streaming, human-in-the-loop, persistence, and more. (You do not need to know LangGraph for basic LangChain agent usage.)
27
+
28
+ Trusted by companies shaping the future of agents – including Klarna, Replit, Elastic, and more – LangGraph is used to ship AI applications at scale.
29
+
30
+ ## 📖 Documentation
31
+
32
+ For full documentation, see the [API reference](https://reference.langchain.com/python/langgraph/). For conceptual guides, tutorials, and examples on using LangGraph, see the [LangGraph Docs](https://docs.langchain.com/oss/python/langgraph/overview). Get started with the [LangGraph Quickstart](https://docs.langchain.com/oss/python/langgraph/quickstart).
33
+
34
+ ## 📕 Releases & Versioning
35
+
36
+ See our [Releases](https://docs.langchain.com/oss/python/release-policy) and [Versioning](https://docs.langchain.com/oss/python/versioning) policies.
37
+
38
+ ## 💁 Contributing
39
+
40
+ As an open-source project in a rapidly developing field, we are extremely open to contributions, whether it be in the form of a new feature, improved infrastructure, or better documentation.
41
+
42
+ For detailed information on how to contribute, see the [Contributing Guide](https://docs.langchain.com/oss/python/contributing/overview).
43
+
44
+ ## Acknowledgements
45
+
46
+ LangGraph is inspired by [Pregel](https://research.google/pubs/pub37252/) and [Apache Beam](https://beam.apache.org/). The public interface draws inspiration from [NetworkX](https://networkx.org/documentation/latest/). LangGraph is built by LangChain Inc, the creators of LangChain, but can be used without LangChain.
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from collections import ChainMap
4
- from collections.abc import Sequence
4
+ from collections.abc import Mapping, Sequence
5
5
  from os import getenv
6
6
  from typing import Any, cast
7
7
 
@@ -20,6 +20,7 @@ from langchain_core.runnables.config import (
20
20
  from langgraph.checkpoint.base import CheckpointMetadata
21
21
 
22
22
  from langgraph._internal._constants import (
23
+ _CHECKPOINT_COORDINATE_KEYS,
23
24
  CONF,
24
25
  CONFIG_KEY_CHECKPOINT_ID,
25
26
  CONFIG_KEY_CHECKPOINT_MAP,
@@ -79,6 +80,42 @@ def patch_checkpoint_map(
79
80
  return config
80
81
 
81
82
 
83
+ def _copy_mapping_value(value: Any) -> Any:
84
+ return dict(value) if isinstance(value, Mapping) else value
85
+
86
+
87
+ def _merge_metadata(
88
+ base: Mapping[str, Any] | None, new: Mapping[str, Any] | None
89
+ ) -> dict[str, Any]:
90
+ """Merge metadata without mutating inputs.
91
+
92
+ Top-level keys merge with newer values winning. `lc_versions` is the only
93
+ mapping-valued key that merges one level deeper, so independent LangChain
94
+ packages can contribute package versions without changing generic metadata
95
+ semantics. Mapping values are copied one level, so deeper nested objects
96
+ remain shared. `None` inputs are treated as empty metadata.
97
+
98
+ Mirrors `langchain_core.runnables.config._merge_metadata_dicts` so configs
99
+ that pass through LangGraph's merge keep the same `lc_versions` semantics;
100
+ keep the two in sync. Unlike lc-core, this copies mapping values one level
101
+ (intentionally more defensive — do not "simplify" back to a shared ref).
102
+ """
103
+ merged = {key: _copy_mapping_value(value) for key, value in (base or {}).items()}
104
+ for key, value in (new or {}).items():
105
+ if (
106
+ key == "lc_versions"
107
+ and isinstance(merged.get(key), Mapping)
108
+ and isinstance(value, Mapping)
109
+ ):
110
+ merged[key] = {
111
+ **cast(Mapping[str, Any], merged[key]),
112
+ **value,
113
+ }
114
+ else:
115
+ merged[key] = _copy_mapping_value(value)
116
+ return merged
117
+
118
+
82
119
  def _merge_callbacks(base: Callbacks, new: Callbacks) -> Callbacks:
83
120
  """Merge two callbacks values (None / list / BaseCallbackManager).
84
121
 
@@ -126,10 +163,10 @@ def merge_configs(*configs: RunnableConfig | None) -> RunnableConfig:
126
163
  if not value:
127
164
  continue
128
165
  if key == "metadata":
129
- if base_value := base.get(key):
130
- base[key] = {**base_value, **value} # type: ignore
131
- else:
132
- base[key] = value # type: ignore[literal-required]
166
+ base[key] = _merge_metadata(
167
+ cast(Mapping[str, Any] | None, base.get(key)),
168
+ cast(Mapping[str, Any], value),
169
+ )
133
170
  elif key == "tags":
134
171
  if base_value := base.get(key):
135
172
  base[key] = [*base_value, *value] # type: ignore
@@ -306,6 +343,28 @@ def ensure_config(*configs: RunnableConfig | None) -> RunnableConfig:
306
343
  if _is_not_empty(v)
307
344
  },
308
345
  )
346
+ # An explicit config that supplies its own checkpoint coordinate (a
347
+ # thread_id, or any checkpoint_ns/checkpoint_id/checkpoint_map) is addressing
348
+ # its own checkpoint lineage, so drop the inherited ambient configurable
349
+ # rather than merging over it: a child graph invoked inside a parent node
350
+ # would otherwise write its checkpoints under the parent's namespace and
351
+ # never find them again. An explicit thread_id resets even when it equals the
352
+ # ambient one, since a child reusing the parent's thread id still addresses
353
+ # its own root namespace, not the parent task's. Configs that only refine
354
+ # other keys keep the ambient and shallow-merge over it below.
355
+ if empty.get(CONF):
356
+ for config in configs:
357
+ if config is None:
358
+ continue
359
+ explicit_configurable = config.get(CONF)
360
+ if not explicit_configurable:
361
+ continue
362
+ if any(
363
+ _is_not_empty(explicit_configurable.get(k))
364
+ for k in _CHECKPOINT_COORDINATE_KEYS
365
+ ):
366
+ empty[CONF] = {}
367
+ break
309
368
  for config in configs:
310
369
  if config is None:
311
370
  continue
@@ -327,14 +386,11 @@ def ensure_config(*configs: RunnableConfig | None) -> RunnableConfig:
327
386
  empty.get("callbacks"), cast(Callbacks, v)
328
387
  )
329
388
  elif k == "metadata":
330
- # Shallow-merge metadata dicts across configs so values
331
- # bound via with_config(...) (e.g. user_id) are preserved
332
- # when later configs supply other metadata keys.
333
- existing = empty.get("metadata")
334
- empty["metadata"] = (
335
- {**cast(dict, existing), **cast(dict, v)}
336
- if existing
337
- else cast(dict, v).copy()
389
+ # Matches merge_configs: top-level metadata keys merge, and
390
+ # only `lc_versions` merges one level deeper.
391
+ empty["metadata"] = _merge_metadata(
392
+ cast(Mapping[str, Any] | None, empty.get("metadata")),
393
+ cast(Mapping[str, Any], v),
338
394
  )
339
395
  elif k == "tags":
340
396
  # Concatenate tags across configs so values bound via
@@ -95,6 +95,15 @@ NULL_TASK_ID = sys.intern("00000000-0000-0000-0000-000000000000")
95
95
  OVERWRITE = sys.intern("__overwrite__")
96
96
  # dict key for the overwrite value, used as `{'__overwrite__': value}`
97
97
 
98
+ # Checkpoint coordinate keys: when any of these appear in an explicit
99
+ # configurable, the caller is addressing its own checkpoint lineage.
100
+ _CHECKPOINT_COORDINATE_KEYS = (
101
+ CONFIG_KEY_THREAD_ID,
102
+ CONFIG_KEY_CHECKPOINT_NS,
103
+ CONFIG_KEY_CHECKPOINT_ID,
104
+ CONFIG_KEY_CHECKPOINT_MAP,
105
+ )
106
+
98
107
  # redefined to avoid circular import with langgraph.constants
99
108
  _TAG_HIDDEN = sys.intern("langsmith:hidden")
100
109
 
@@ -108,6 +108,7 @@ from langgraph.callbacks import (
108
108
  get_sync_graph_callback_manager_for_config,
109
109
  )
110
110
  from langgraph.channels.base import BaseChannel
111
+ from langgraph.channels.delta import DeltaChannel
111
112
  from langgraph.channels.topic import Topic
112
113
  from langgraph.config import get_config
113
114
  from langgraph.constants import END
@@ -1996,11 +1997,33 @@ class Pregel(
1996
1997
  ),
1997
1998
  )
1998
1999
  # save task writes
2000
+ has_delta_writes = any(
2001
+ isinstance(channels.get(c), DeltaChannel)
2002
+ for task in run_tasks
2003
+ for c, _ in task.writes
2004
+ )
2005
+ should_put_writes = saved is not None or has_delta_writes
2006
+
2007
+ if saved is None and has_delta_writes:
2008
+ # If there is no previous checkpoint, we need to create a stub checkpoint
2009
+ # so the first delta writes has a parent to anchor under.
2010
+ # This is the model of DeltaChannel.
2011
+ stub = empty_checkpoint()
2012
+ checkpoint_config = checkpointer.put(
2013
+ patch_configurable(
2014
+ checkpoint_config, {CONFIG_KEY_CHECKPOINT_ID: None}
2015
+ ),
2016
+ stub,
2017
+ {"source": "update", "step": -1, "parents": {}},
2018
+ {},
2019
+ )
2020
+
1999
2021
  for task_id, task in zip(run_task_ids, run_tasks):
2000
2022
  # channel writes are saved to current checkpoint
2001
2023
  channel_writes = [w for w in task.writes if w[0] != PUSH]
2002
- if saved and channel_writes:
2024
+ if should_put_writes and channel_writes:
2003
2025
  checkpointer.put_writes(checkpoint_config, channel_writes, task_id)
2026
+
2004
2027
  # apply to checkpoint and save
2005
2028
  apply_writes(
2006
2029
  checkpoint,
@@ -2441,10 +2464,31 @@ class Pregel(
2441
2464
  ),
2442
2465
  )
2443
2466
  # save task writes
2467
+ has_delta_writes = any(
2468
+ isinstance(channels.get(c), DeltaChannel)
2469
+ for task in run_tasks
2470
+ for c, _ in task.writes
2471
+ )
2472
+ should_put_writes = saved is not None or has_delta_writes
2473
+
2474
+ if saved is None and has_delta_writes:
2475
+ # If there is no previous checkpoint, we need to create a stub checkpoint
2476
+ # so the first delta writes has a parent to anchor under.
2477
+ # This is the model of DeltaChannel.
2478
+ stub = empty_checkpoint()
2479
+ checkpoint_config = await checkpointer.aput(
2480
+ patch_configurable(
2481
+ checkpoint_config, {CONFIG_KEY_CHECKPOINT_ID: None}
2482
+ ),
2483
+ stub,
2484
+ {"source": "update", "step": -1, "parents": {}},
2485
+ {},
2486
+ )
2487
+
2444
2488
  for task_id, task in zip(run_task_ids, run_tasks):
2445
2489
  # channel writes are saved to current checkpoint
2446
2490
  channel_writes = [w for w in task.writes if w[0] != PUSH]
2447
- if saved and channel_writes:
2491
+ if should_put_writes and channel_writes:
2448
2492
  await checkpointer.aput_writes(
2449
2493
  checkpoint_config, channel_writes, task_id
2450
2494
  )
@@ -132,13 +132,23 @@ class GraphRunStream:
132
132
  def abort(self) -> None:
133
133
  """Stop the run early.
134
134
 
135
- Closes the mux and marks the stream exhausted. The graph
136
- iterator is dropped; any in-flight nodes see the closure on
137
- their next yield point. Idempotent.
135
+ Closes the underlying graph iterator (propagating `GeneratorExit`
136
+ so in-flight nodes and subgraphs are cancelled), closes the mux,
137
+ and marks the stream exhausted. Idempotent.
138
138
  """
139
139
  if self._exhausted:
140
140
  return
141
141
  self._exhausted = True
142
+ graph_iter = self._graph_iter
143
+ self._graph_iter = None
144
+ if (
145
+ graph_iter is not None
146
+ and (close := getattr(graph_iter, "close", None)) is not None
147
+ ):
148
+ try:
149
+ close()
150
+ except Exception:
151
+ pass
142
152
  try:
143
153
  self._mux.close()
144
154
  except Exception:
@@ -348,6 +358,8 @@ class AsyncGraphRunStream:
348
358
  self._scope_list: list[str] = list(mux.scope)
349
359
  self._pump_cond = asyncio.Condition()
350
360
  self._pumping = False
361
+ self._anext_task: asyncio.Future[Any] | None = None
362
+ self._aborting = False
351
363
  for key in mux.native_keys:
352
364
  setattr(self, key, mux.extensions[key])
353
365
  if wire_pump:
@@ -407,7 +419,25 @@ class AsyncGraphRunStream:
407
419
 
408
420
  try:
409
421
  try:
410
- part = await self._graph_aiter.__anext__()
422
+ # Run the pull as a child task so `abort()` can cancel it
423
+ # mid-flight. Cancelling propagates `CancelledError` into the
424
+ # graph generator frame -> Pregel loop -> nested subgraph
425
+ # nodes, which a bare `aclose()` cannot do while the generator
426
+ # is running ("asynchronous generator is already running").
427
+ self._anext_task = asyncio.ensure_future(self._graph_aiter.__anext__())
428
+ try:
429
+ part = await self._anext_task
430
+ except asyncio.CancelledError:
431
+ if self._aborting:
432
+ # Abort-initiated cancel: stop gracefully.
433
+ self._exhausted = True
434
+ return False
435
+ # Genuine external cancel of this task: also stop the
436
+ # in-flight pull, then propagate.
437
+ self._anext_task.cancel()
438
+ raise
439
+ finally:
440
+ self._anext_task = None
411
441
  event = convert_to_protocol_event(part)
412
442
  self._observe_event(event)
413
443
  await self._mux.apush(event)
@@ -428,15 +458,40 @@ class AsyncGraphRunStream:
428
458
  async def abort(self) -> None:
429
459
  """Stop the run early.
430
460
 
431
- Marks the stream exhausted, wakes any pump-waiters, and closes
432
- the mux. Any `apush` blocked on backpressure wakes and returns
433
- without appending. Idempotent.
461
+ Marks the stream exhausted and wakes any pump-waiters. Cancels an
462
+ in-flight pull if one is running, then closes the underlying graph
463
+ iterator, so running nodes and nested subgraphs are cancelled
464
+ whether or not a pump is mid-pull. Closes the mux; any `apush`
465
+ blocked on backpressure wakes and returns without appending.
466
+ Idempotent.
434
467
  """
435
468
  async with self._pump_cond:
436
469
  if self._exhausted:
437
470
  return
438
471
  self._exhausted = True
472
+ self._aborting = True
473
+ graph_aiter = self._graph_aiter
474
+ self._graph_aiter = None
475
+ anext_task = self._anext_task
439
476
  self._pump_cond.notify_all()
477
+ # If a pump is mid-pull, cancel it so the cancellation propagates
478
+ # into running nodes and nested subgraphs. Once it settles the
479
+ # generator is no longer running, so the `aclose()` below is a safe
480
+ # final cleanup (and handles the no-in-flight-pull case directly).
481
+ if anext_task is not None and not anext_task.done():
482
+ anext_task.cancel()
483
+ try:
484
+ await anext_task
485
+ except (asyncio.CancelledError, Exception):
486
+ pass
487
+ if (
488
+ graph_aiter is not None
489
+ and (aclose := getattr(graph_aiter, "aclose", None)) is not None
490
+ ):
491
+ try:
492
+ await aclose()
493
+ except Exception:
494
+ pass
440
495
  try:
441
496
  await self._mux.aclose()
442
497
  except Exception:
@@ -32,7 +32,7 @@ from langgraph.warnings import LangGraphDeprecatedSinceV10, LangGraphDeprecatedS
32
32
 
33
33
  # Local TypeVars for generic stream TypedDicts.
34
34
  # We use separate TypeVars here (rather than importing from langgraph.typing)
35
- # because the typing module TypeVars have defaults that cause mypy issues
35
+ # because the typing module TypeVars have defaults that cause type checker issues
36
36
  # when used in standalone type aliases.
37
37
  StateT = TypeVar("StateT")
38
38
  OutputT = TypeVar("OutputT")
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "langgraph"
7
- version = "1.2.4"
7
+ version = "1.2.6"
8
8
  description = "Building stateful, multi-actor applications with LLMs"
9
9
  authors = []
10
10
  requires-python = ">=3.10"
@@ -24,7 +24,7 @@ classifiers = [
24
24
  'Programming Language :: Python :: 3.13',
25
25
  ]
26
26
  dependencies = [
27
- "langchain-core>=1.4.0,<2",
27
+ "langchain-core>=1.4.7,<2",
28
28
  "langgraph-checkpoint>=4.1.0,<5.0.0",
29
29
  "langgraph-sdk>=0.4.2,<0.5.0",
30
30
  "langgraph-prebuilt>=1.1.0,<1.2.0",
@@ -69,8 +69,8 @@ test = [
69
69
  "redis",
70
70
  ]
71
71
  lint = [
72
- "mypy",
73
72
  "ruff",
73
+ "ty",
74
74
  "types-requests",
75
75
  ]
76
76
  dev = [
@@ -99,15 +99,24 @@ target-version = "py310"
99
99
  [tool.ruff.lint.flake8-tidy-imports.banned-api]
100
100
  "typing.TypedDict".msg = "Use typing_extensions.TypedDict instead."
101
101
 
102
- [tool.mypy]
103
- # https://mypy.readthedocs.io/en/stable/config_file.html
104
- disallow_untyped_defs = "True"
105
- explicit_package_bases = "True"
106
- warn_no_return = "False"
107
- warn_unused_ignores = "True"
108
- warn_redundant_casts = "True"
109
- allow_redefinition = "True"
110
- disable_error_code = "typeddict-item, return-value, override, has-type"
102
+ [tool.ty.rules]
103
+ call-non-callable = "ignore"
104
+ deprecated = "ignore"
105
+ invalid-argument-type = "ignore"
106
+ invalid-assignment = "ignore"
107
+ invalid-key = "ignore"
108
+ invalid-method-override = "ignore"
109
+ invalid-paramspec = "ignore"
110
+ invalid-return-type = "ignore"
111
+ invalid-type-form = "ignore"
112
+ invalid-yield = "ignore"
113
+ missing-typed-dict-key = "ignore"
114
+ no-matching-overload = "ignore"
115
+ not-iterable = "ignore"
116
+ unused-type-ignore-comment = "ignore"
117
+ unresolved-attribute = "ignore"
118
+ unsupported-base = "ignore"
119
+ unsupported-operator = "ignore"
111
120
 
112
121
  [tool.coverage.run]
113
122
  omit = ["tests/*"]