langgraph-sdk 0.4.2__tar.gz → 0.4.3__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 (144) hide show
  1. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/.gitignore +5 -0
  2. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/MIGRATION.md +3 -1
  3. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/Makefile +0 -1
  4. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/PKG-INFO +38 -15
  5. langgraph_sdk-0.4.3/README.md +98 -0
  6. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/integration/Dockerfile +13 -0
  7. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/integration/docker-compose.yml +10 -3
  8. langgraph_sdk-0.4.3/integration/graph/factory_graph.py +70 -0
  9. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/integration/langgraph.json +2 -1
  10. langgraph_sdk-0.4.3/langgraph_sdk/__init__.py +15 -0
  11. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/_async/cron.py +12 -4
  12. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/_sync/cron.py +12 -4
  13. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/auth/__init__.py +2 -3
  14. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/encryption/__init__.py +12 -5
  15. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/encryption/types.py +30 -4
  16. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/schema.py +1 -1
  17. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/pyproject.toml +8 -5
  18. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/integration/conftest.py +6 -4
  19. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/integration/test_assistants.py +5 -4
  20. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/integration/test_cancel.py +5 -4
  21. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/integration/test_crons.py +5 -4
  22. langgraph_sdk-0.4.3/tests/integration/test_factory_graph.py +66 -0
  23. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/integration/test_runs.py +5 -4
  24. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/integration/test_store.py +5 -4
  25. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/integration/test_websocket.py +5 -4
  26. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/streaming/test_controller.py +9 -15
  27. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/streaming/test_decoders.py +2 -1
  28. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/streaming/test_extensions_projection.py +1 -2
  29. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/streaming/test_lifecycle_watcher.py +2 -2
  30. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/streaming/test_scoped_handles.py +4 -10
  31. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/streaming/test_shared_stream.py +3 -11
  32. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/streaming/test_sync_extensions_projection.py +1 -2
  33. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/streaming/test_sync_projections.py +3 -7
  34. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/streaming/test_sync_scoped_handles.py +2 -2
  35. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/streaming/test_sync_thread_stream.py +22 -87
  36. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/streaming/test_sync_transport_ws.py +2 -3
  37. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/streaming/test_thread_stream.py +7 -66
  38. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/streaming/test_tool_calls_projection.py +3 -5
  39. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/streaming/test_transport_http.py +10 -42
  40. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/streaming/test_transport_ws.py +2 -4
  41. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/test_client_stream.py +5 -5
  42. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/test_crons_client.py +49 -0
  43. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/test_encryption.py +32 -0
  44. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/test_langsmith_tracing.py +2 -5
  45. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/test_path_encoding.py +2 -1
  46. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/test_serde.py +1 -1
  47. langgraph_sdk-0.4.3/uv.lock +1547 -0
  48. langgraph_sdk-0.4.2/README.md +0 -75
  49. langgraph_sdk-0.4.2/langgraph_sdk/__init__.py +0 -8
  50. langgraph_sdk-0.4.2/uv.lock +0 -1662
  51. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/CHANGELOG.md +0 -0
  52. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/LICENSE +0 -0
  53. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/integration/graph/__init__.py +0 -0
  54. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/integration/graph/deep_agent.py +0 -0
  55. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/integration/graph/streaming_graph.py +0 -0
  56. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/integration/graph/tools_agent.py +0 -0
  57. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/integration/scripts/_common.py +0 -0
  58. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/integration/scripts/test_cancel.py +0 -0
  59. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/integration/scripts/test_concurrent.py +0 -0
  60. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/integration/scripts/test_extensions.py +0 -0
  61. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/integration/scripts/test_helpers.py +0 -0
  62. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/integration/scripts/test_lifecycle.py +0 -0
  63. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/integration/scripts/test_messages.py +0 -0
  64. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/integration/scripts/test_reconnect.py +0 -0
  65. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/integration/scripts/test_subgraphs.py +0 -0
  66. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/integration/scripts/test_tools.py +0 -0
  67. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/integration/scripts/test_update_state.py +0 -0
  68. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/integration/scripts/test_values.py +0 -0
  69. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/integration/scripts/test_websocket.py +0 -0
  70. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/_async/__init__.py +0 -0
  71. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/_async/assistants.py +0 -0
  72. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/_async/client.py +0 -0
  73. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/_async/http.py +0 -0
  74. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/_async/runs.py +0 -0
  75. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/_async/store.py +0 -0
  76. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/_async/stream.py +0 -0
  77. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/_async/threads.py +0 -0
  78. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/_shared/__init__.py +0 -0
  79. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/_shared/types.py +0 -0
  80. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/_shared/utilities.py +0 -0
  81. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/_sync/__init__.py +0 -0
  82. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/_sync/assistants.py +0 -0
  83. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/_sync/client.py +0 -0
  84. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/_sync/http.py +0 -0
  85. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/_sync/runs.py +0 -0
  86. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/_sync/store.py +0 -0
  87. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/_sync/stream.py +0 -0
  88. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/_sync/threads.py +0 -0
  89. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/auth/exceptions.py +0 -0
  90. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/auth/types.py +0 -0
  91. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/cache.py +0 -0
  92. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/client.py +0 -0
  93. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/errors.py +0 -0
  94. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/py.typed +0 -0
  95. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/runtime.py +0 -0
  96. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/sse.py +0 -0
  97. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/stream/__init__.py +0 -0
  98. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/stream/controller.py +0 -0
  99. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/stream/decoders.py +0 -0
  100. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/stream/multi_cursor_buffer.py +0 -0
  101. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/stream/subscription.py +0 -0
  102. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/stream/sync_controller.py +0 -0
  103. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/stream/transport/__init__.py +0 -0
  104. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/stream/transport/base.py +0 -0
  105. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/stream/transport/http.py +0 -0
  106. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/stream/transport/sync_http.py +0 -0
  107. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/stream/transport/sync_ws.py +0 -0
  108. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/langgraph_sdk/stream/transport/ws.py +0 -0
  109. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/fixtures/response.txt +0 -0
  110. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/integration/__init__.py +0 -0
  111. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/integration/test_concurrent.py +0 -0
  112. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/integration/test_extensions.py +0 -0
  113. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/integration/test_helpers.py +0 -0
  114. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/integration/test_lifecycle.py +0 -0
  115. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/integration/test_messages.py +0 -0
  116. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/integration/test_reconnect.py +0 -0
  117. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/integration/test_remote_graph_v3.py +0 -0
  118. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/integration/test_subgraphs.py +0 -0
  119. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/integration/test_threads_crud.py +0 -0
  120. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/integration/test_tools.py +0 -0
  121. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/integration/test_update_state.py +0 -0
  122. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/integration/test_values.py +0 -0
  123. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/streaming/__init__.py +0 -0
  124. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/streaming/_events.py +0 -0
  125. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/streaming/_fake_server.py +0 -0
  126. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/streaming/_sync_fake_server.py +0 -0
  127. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/streaming/assert_transport_replays.py +0 -0
  128. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/streaming/test_messages_projection.py +0 -0
  129. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/streaming/test_multi_cursor_buffer.py +0 -0
  130. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/streaming/test_output.py +0 -0
  131. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/streaming/test_replay_conformance.py +0 -0
  132. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/streaming/test_subscription.py +0 -0
  133. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/streaming/test_sync_shared_stream.py +0 -0
  134. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/streaming/test_sync_transport_http.py +0 -0
  135. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/streaming/test_transport_path_encoding.py +0 -0
  136. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/streaming/test_values_projection.py +0 -0
  137. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/test_api_parity.py +0 -0
  138. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/test_assistants_client.py +0 -0
  139. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/test_cache.py +0 -0
  140. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/test_client_exports.py +0 -0
  141. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/test_errors.py +0 -0
  142. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/test_serde_schema.py +0 -0
  143. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/test_skip_auto_load_api_key.py +0 -0
  144. {langgraph_sdk-0.4.2 → langgraph_sdk-0.4.3}/tests/test_threads_client.py +0 -0
@@ -77,6 +77,10 @@ __pypackages__/
77
77
  # Environments
78
78
  .env
79
79
  .envrc
80
+ *.crt
81
+ *.key
82
+ *.pem
83
+ credentials.json
80
84
  .venv
81
85
  .venvs
82
86
  env/
@@ -98,6 +102,7 @@ dmypy.json
98
102
 
99
103
  .vercel
100
104
  .turbo
105
+ node_modules/
101
106
  .editorconfig
102
107
  .scratch
103
108
  .worktrees/
@@ -87,7 +87,9 @@ async with client.threads.stream(assistant_id="agent") as thread:
87
87
 
88
88
  ```python
89
89
  async with client.threads.stream(assistant_id="agent") as thread:
90
- await thread.run.start(input={"messages": [{"role": "user", "content": "book a flight"}]})
90
+ await thread.run.start(
91
+ input={"messages": [{"role": "user", "content": "book a flight"}]}
92
+ )
91
93
 
92
94
  # Wait for the run to pause at an interrupt node.
93
95
  # thread.interrupted becomes True when input.requested arrives.
@@ -9,7 +9,6 @@ test:
9
9
 
10
10
  # Define a variable for Python and notebook files.
11
11
  PYTHON_FILES=.
12
- MYPY_CACHE=.mypy_cache
13
12
  lint format: PYTHON_FILES=.
14
13
  lint_diff format_diff: PYTHON_FILES=$(shell git diff --name-only --relative --diff-filter=d main . | grep -E '\.py$$|\.ipynb$$')
15
14
 
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: langgraph-sdk
3
- Version: 0.4.2
3
+ Version: 0.4.3
4
4
  Summary: SDK for interacting with LangGraph API
5
5
  Project-URL: Source, https://github.com/langchain-ai/langgraph/tree/main/libs/sdk-py
6
6
  Project-URL: Twitter, https://x.com/langchain_oss
@@ -13,23 +13,36 @@ Requires-Dist: httpx>=0.25.2
13
13
  Requires-Dist: langchain-core<2,>=1.4.0
14
14
  Requires-Dist: langchain-protocol>=0.0.15
15
15
  Requires-Dist: orjson>=3.11.5
16
- Requires-Dist: websockets<16,>=14
16
+ Requires-Dist: websockets<17,>=14
17
17
  Description-Content-Type: text/markdown
18
18
 
19
19
  # LangGraph Python SDK
20
20
 
21
- This repository contains the Python SDK for interacting with the LangSmith Deployment REST API.
21
+ [![PyPI - Version](https://img.shields.io/pypi/v/langgraph-sdk?label=%20)](https://pypi.org/project/langgraph-sdk/#history)
22
+ [![PyPI - License](https://img.shields.io/pypi/l/langgraph-sdk)](https://opensource.org/licenses/MIT)
23
+ [![PyPI - Downloads](https://img.shields.io/pepy/dt/langgraph-sdk)](https://pypistats.org/packages/langgraph-sdk)
24
+ [![Twitter](https://img.shields.io/twitter/url/https/twitter.com/langchain_oss.svg?style=social&label=Follow%20%40LangChain)](https://x.com/langchain_oss)
22
25
 
23
- ## Quick Start
26
+ To help you ship LangGraph apps to production faster, check out [LangSmith](https://www.langchain.com/langsmith).
27
+ [LangSmith](https://www.langchain.com/langsmith) is a unified developer platform for building, testing, and monitoring LLM applications.
24
28
 
25
- To get started with the Python SDK, [install the package](https://pypi.org/project/langgraph-sdk/)
29
+ ## Quick Install
26
30
 
27
31
  ```bash
28
- pip install -U langgraph-sdk
32
+ uv add langgraph-sdk
29
33
  ```
30
34
 
31
- You will need a running LangGraph API server. If you're running a server locally using `langgraph-cli`, SDK will automatically point at `http://localhost:8123`, otherwise
32
- you would need to specify the server URL when creating a client.
35
+ ## 🤔 What is this?
36
+
37
+ This library provides the Python SDK for interacting with the LangGraph API. Use it to connect to a running LangGraph API server, manage assistants and threads, and stream runs from Python applications.
38
+
39
+ You will need a running LangGraph API server. If you're running a server locally using `langgraph-cli`, the SDK will automatically point at `http://localhost:8123`; otherwise, specify the server URL when creating a client.
40
+
41
+ ## 📖 Documentation
42
+
43
+ For full documentation, see the [API reference](https://reference.langchain.com/python/langgraph-sdk/). For conceptual guides and tutorials, see the [LangGraph Docs](https://docs.langchain.com/oss/python/langgraph/overview).
44
+
45
+ ## Quick Start
33
46
 
34
47
  ```python
35
48
  from langgraph_sdk import get_client
@@ -48,7 +61,9 @@ thread = await client.threads.create()
48
61
 
49
62
  # Start a streaming run
50
63
  input = {"messages": [{"role": "human", "content": "what's the weather in la"}]}
51
- async for chunk in client.runs.stream(thread['thread_id'], agent['assistant_id'], input=input):
64
+ async for chunk in client.runs.stream(
65
+ thread["thread_id"], agent["assistant_id"], input=input
66
+ ):
52
67
  print(chunk)
53
68
  ```
54
69
 
@@ -61,9 +76,7 @@ async for chunk in client.runs.stream(thread['thread_id'], agent['assistant_id']
61
76
 
62
77
  ## Thread-Centric Streaming (v3)
63
78
 
64
- `client.threads.stream()` returns a context manager that owns the SSE session for one
65
- thread. Typed projections — values snapshots, message streams, tool calls, custom
66
- events — all share the same underlying connection.
79
+ `client.threads.stream()` returns a context manager that owns the SSE session for one thread. Typed projections — values snapshots, message streams, tool calls, custom events — all share the same underlying connection.
67
80
 
68
81
  ```python
69
82
  from langgraph_sdk import get_client
@@ -87,7 +100,17 @@ async with client.threads.stream(
87
100
  messages, tool_calls = await asyncio.gather(get_messages(), get_tool_calls())
88
101
 
89
102
  for stream in messages:
90
- print(await stream.text) # accumulated text
103
+ print(await stream.text) # accumulated text
91
104
 
92
- final = await thread.output # terminal state values
105
+ final = await thread.output # terminal state values
93
106
  ```
107
+
108
+ ## 📕 Releases & Versioning
109
+
110
+ See our [Releases](https://docs.langchain.com/oss/python/release-policy) and [Versioning](https://docs.langchain.com/oss/python/versioning) policies.
111
+
112
+ ## 💁 Contributing
113
+
114
+ 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.
115
+
116
+ For detailed information on how to contribute, see the [Contributing Guide](https://docs.langchain.com/oss/python/contributing/overview).
@@ -0,0 +1,98 @@
1
+ # LangGraph Python SDK
2
+
3
+ [![PyPI - Version](https://img.shields.io/pypi/v/langgraph-sdk?label=%20)](https://pypi.org/project/langgraph-sdk/#history)
4
+ [![PyPI - License](https://img.shields.io/pypi/l/langgraph-sdk)](https://opensource.org/licenses/MIT)
5
+ [![PyPI - Downloads](https://img.shields.io/pepy/dt/langgraph-sdk)](https://pypistats.org/packages/langgraph-sdk)
6
+ [![Twitter](https://img.shields.io/twitter/url/https/twitter.com/langchain_oss.svg?style=social&label=Follow%20%40LangChain)](https://x.com/langchain_oss)
7
+
8
+ To help you ship LangGraph apps to production faster, check out [LangSmith](https://www.langchain.com/langsmith).
9
+ [LangSmith](https://www.langchain.com/langsmith) is a unified developer platform for building, testing, and monitoring LLM applications.
10
+
11
+ ## Quick Install
12
+
13
+ ```bash
14
+ uv add langgraph-sdk
15
+ ```
16
+
17
+ ## 🤔 What is this?
18
+
19
+ This library provides the Python SDK for interacting with the LangGraph API. Use it to connect to a running LangGraph API server, manage assistants and threads, and stream runs from Python applications.
20
+
21
+ You will need a running LangGraph API server. If you're running a server locally using `langgraph-cli`, the SDK will automatically point at `http://localhost:8123`; otherwise, specify the server URL when creating a client.
22
+
23
+ ## 📖 Documentation
24
+
25
+ For full documentation, see the [API reference](https://reference.langchain.com/python/langgraph-sdk/). For conceptual guides and tutorials, see the [LangGraph Docs](https://docs.langchain.com/oss/python/langgraph/overview).
26
+
27
+ ## Quick Start
28
+
29
+ ```python
30
+ from langgraph_sdk import get_client
31
+
32
+ # If you're using a remote server, initialize the client with `get_client(url=REMOTE_URL)`
33
+ client = get_client()
34
+
35
+ # List all assistants
36
+ assistants = await client.assistants.search()
37
+
38
+ # We auto-create an assistant for each graph you register in config.
39
+ agent = assistants[0]
40
+
41
+ # Start a new thread
42
+ thread = await client.threads.create()
43
+
44
+ # Start a streaming run
45
+ input = {"messages": [{"role": "human", "content": "what's the weather in la"}]}
46
+ async for chunk in client.runs.stream(
47
+ thread["thread_id"], agent["assistant_id"], input=input
48
+ ):
49
+ print(chunk)
50
+ ```
51
+
52
+ ## Known Limitations
53
+
54
+ - **WebSocket transport** requires `websockets>=14` and is only available on the async client (`AsyncThreadStream`). The sync client (`SyncThreadStream`) uses SSE exclusively.
55
+ - **`thread.extensions[name]`** opens a new subscription each time the same name is accessed. Assign the projection to a variable and reuse it within a single session rather than re-indexing across multiple iterations.
56
+ - **Sync streaming** drives the lifecycle watcher in a background thread. Long-lived sync sessions will hold that thread open until the context manager exits.
57
+ - **Reconnect attempts** are limited to 5 by default for both the shared SSE fan-out and the lifecycle watcher. Persistent network partitions will surface as `RuntimeError` on in-flight projections.
58
+
59
+ ## Thread-Centric Streaming (v3)
60
+
61
+ `client.threads.stream()` returns a context manager that owns the SSE session for one thread. Typed projections — values snapshots, message streams, tool calls, custom events — all share the same underlying connection.
62
+
63
+ ```python
64
+ from langgraph_sdk import get_client
65
+ import asyncio
66
+
67
+ client = get_client()
68
+
69
+ async with client.threads.stream(
70
+ thread_id="my-thread",
71
+ assistant_id="agent",
72
+ ) as thread:
73
+ await thread.run.start(input={"messages": [{"role": "user", "content": "hi"}]})
74
+
75
+ # Start all consumers concurrently so they share one SSE connection.
76
+ async def get_messages():
77
+ return [s async for s in thread.messages]
78
+
79
+ async def get_tool_calls():
80
+ return [c async for c in thread.tool_calls]
81
+
82
+ messages, tool_calls = await asyncio.gather(get_messages(), get_tool_calls())
83
+
84
+ for stream in messages:
85
+ print(await stream.text) # accumulated text
86
+
87
+ final = await thread.output # terminal state values
88
+ ```
89
+
90
+ ## 📕 Releases & Versioning
91
+
92
+ See our [Releases](https://docs.langchain.com/oss/python/release-policy) and [Versioning](https://docs.langchain.com/oss/python/versioning) policies.
93
+
94
+ ## 💁 Contributing
95
+
96
+ 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.
97
+
98
+ For detailed information on how to contribute, see the [Contributing Guide](https://docs.langchain.com/oss/python/contributing/overview).
@@ -22,6 +22,19 @@ RUN pip install --no-cache-dir \
22
22
  "langchain>=1.3.0" \
23
23
  "deepagents>=0.6.2"
24
24
 
25
+ # Swap the published langgraph *core* for this monorepo's local copy, so the
26
+ # server executes the langgraph under test rather than the latest release.
27
+ # We keep the rest of the base image (langgraph-api, runtime, Go core server)
28
+ # on `latest` — that still surfaces upstream regressions — but the core the
29
+ # server runs is now the PR's, which is what lets this suite catch core
30
+ # regressions (e.g. ensure_config / runtime changes) before they're published.
31
+ # `--no-deps` keeps the base image's already-compatible
32
+ # checkpoint/prebuilt/sdk; we only replace core. The local source comes from
33
+ # the `langgraph_src` additional build context (see docker-compose.yml).
34
+ COPY --from=langgraph_src pyproject.toml README.md LICENSE /opt/langgraph-src/
35
+ COPY --from=langgraph_src langgraph /opt/langgraph-src/langgraph/
36
+ RUN pip install --no-cache-dir --force-reinstall --no-deps /opt/langgraph-src
37
+
25
38
  # Project graphs + registration config.
26
39
  COPY graph/ /app/graph/
27
40
  COPY langgraph.json /app/langgraph.json
@@ -36,11 +36,18 @@ services:
36
36
  api:
37
37
  # Thin layer on top of langchain/langgraph-api:latest-py3.12 —
38
38
  # see ./Dockerfile. The base image bundles langgraph-api +
39
- # langgraph_runtime_postgres + langgraph_license + the Go core-server,
40
- # so we only add graph deps (deepagents) and the graph files on top.
39
+ # langgraph_runtime_postgres + langgraph_license + the Go core-server;
40
+ # on top we add graph deps (deepagents), the graph files, and this
41
+ # monorepo's local langgraph *core* (so the server runs the code under
42
+ # test, not the released langgraph).
41
43
  build:
42
44
  context: .
43
45
  dockerfile: Dockerfile
46
+ additional_contexts:
47
+ # The monorepo's local langgraph core (libs/langgraph), installed over
48
+ # the base image so the server runs the langgraph under test. See the
49
+ # Dockerfile for why.
50
+ langgraph_src: ../../langgraph
44
51
  image: langgraph-v3-integration-api:local
45
52
  depends_on:
46
53
  postgres:
@@ -70,7 +77,7 @@ services:
70
77
  # Tell langgraph-api which graphs to register. The langgraph CLI sets
71
78
  # this from langgraph.json; we're bypassing the CLI (running uvicorn
72
79
  # directly) so we set it manually.
73
- LANGSERVE_GRAPHS: '{"agent":"/app/graph/streaming_graph.py:graph","tools_agent":"/app/graph/tools_agent.py:graph","deep_agent":"/app/graph/deep_agent.py:graph"}'
80
+ LANGSERVE_GRAPHS: '{"agent":"/app/graph/streaming_graph.py:graph","tools_agent":"/app/graph/tools_agent.py:graph","deep_agent":"/app/graph/deep_agent.py:graph","factory_agent":"/app/graph/factory_graph.py:make_graph"}'
74
81
 
75
82
  # The published langgraph-api image is the `licensed` variant and
76
83
  # requires a real LANGSMITH_API_KEY (or LANGGRAPH_CLOUD_LICENSE_KEY)
@@ -0,0 +1,70 @@
1
+ """Integration fixture: a graph *factory* (not a pre-compiled graph).
2
+
3
+ Registered as `factory_agent`. The other integration graphs are all
4
+ pre-compiled objects, so this is the only fixture that drives the server's
5
+ graph-factory code path on a run. That path is where langgraph-api seeds a
6
+ `ServerRuntime` into the run config; executing a run against this graph is the
7
+ end-to-end regression guard for the langgraph 1.2.3 `ensure_config`
8
+ configurable-merge surfacing a leaked `__pregel_runtime`
9
+ (`AttributeError: '_ExecutionRuntime' object has no attribute 'control'`).
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ from typing import TYPE_CHECKING
15
+
16
+ from langgraph.graph.state import END, CompiledStateGraph, StateGraph
17
+ from langgraph.store.base import BaseStore
18
+ from typing_extensions import TypedDict
19
+
20
+ if TYPE_CHECKING:
21
+ from langgraph.types import RunnableConfig
22
+
23
+ from langgraph_sdk.runtime import ServerRuntime
24
+
25
+
26
+ class State(TypedDict, total=False):
27
+ text: str
28
+ access_context: str
29
+ is_for_execution: bool
30
+
31
+
32
+ async def make_graph(
33
+ config: RunnableConfig, runtime: ServerRuntime
34
+ ) -> CompiledStateGraph:
35
+ """2-arg factory (config + runtime) returning a compiled echo graph.
36
+
37
+ Validates that the server injected a real `ServerRuntime`, then builds a
38
+ one-node graph whose output echoes the input and reports the runtime's
39
+ access context (so the test can confirm the factory ran under execution).
40
+ """
41
+ from langgraph_sdk.runtime import (
42
+ _ExecutionRuntime,
43
+ _ReadRuntime,
44
+ )
45
+
46
+ # `if/raise` rather than `assert` so the contract holds under `python -O`.
47
+ if not isinstance(runtime, (_ExecutionRuntime, _ReadRuntime)):
48
+ raise TypeError(
49
+ f"factory must receive a ServerRuntime, got {type(runtime).__name__}"
50
+ )
51
+ if not isinstance(runtime.store, BaseStore):
52
+ raise TypeError(
53
+ f"runtime.store must be a BaseStore, got {type(runtime.store).__name__}"
54
+ )
55
+
56
+ access_context = runtime.access_context
57
+ is_for_execution = runtime.execution_runtime is not None
58
+
59
+ def echo(state: State) -> State:
60
+ return {
61
+ "text": (state.get("text") or "") + " echoed",
62
+ "access_context": access_context,
63
+ "is_for_execution": is_for_execution,
64
+ }
65
+
66
+ workflow = StateGraph(State)
67
+ workflow.add_node("echo", echo)
68
+ workflow.set_entry_point("echo")
69
+ workflow.add_edge("echo", END)
70
+ return workflow.compile()
@@ -4,7 +4,8 @@
4
4
  "graphs": {
5
5
  "agent": "./graph/streaming_graph.py:graph",
6
6
  "tools_agent": "./graph/tools_agent.py:graph",
7
- "deep_agent": "./graph/deep_agent.py:graph"
7
+ "deep_agent": "./graph/deep_agent.py:graph",
8
+ "factory_agent": "./graph/factory_graph.py:make_graph"
8
9
  },
9
10
  "env": {}
10
11
  }
@@ -0,0 +1,15 @@
1
+ from langgraph_sdk.auth import Auth
2
+ from langgraph_sdk.client import get_client, get_sync_client
3
+ from langgraph_sdk.encryption import Encryption
4
+ from langgraph_sdk.encryption.types import DecryptResult, EncryptionContext
5
+
6
+ __version__ = "0.4.3"
7
+
8
+ __all__ = [
9
+ "Auth",
10
+ "DecryptResult",
11
+ "Encryption",
12
+ "EncryptionContext",
13
+ "get_client",
14
+ "get_sync_client",
15
+ ]
@@ -8,7 +8,11 @@ from datetime import datetime, tzinfo
8
8
  from typing import Any
9
9
 
10
10
  from langgraph_sdk._async.http import HttpClient
11
- from langgraph_sdk._shared.utilities import _quote_path_param, _resolve_timezone
11
+ from langgraph_sdk._shared.utilities import (
12
+ NOT_PROVIDED,
13
+ _quote_path_param,
14
+ _resolve_timezone,
15
+ )
12
16
  from langgraph_sdk.schema import (
13
17
  All,
14
18
  Config,
@@ -324,7 +328,7 @@ class CronClient:
324
328
  cron_id: str,
325
329
  *,
326
330
  schedule: str | None = None,
327
- end_time: datetime | None = None,
331
+ end_time: datetime | None = NOT_PROVIDED,
328
332
  input: Input | None = None,
329
333
  metadata: Mapping[str, Any] | None = None,
330
334
  config: Config | None = None,
@@ -348,7 +352,8 @@ class CronClient:
348
352
  cron_id: The cron ID to update.
349
353
  schedule: The cron schedule to execute this job on.
350
354
  Schedules are interpreted in UTC unless a timezone is specified.
351
- end_time: The end date to stop running the cron.
355
+ end_time: The end date to stop running the cron. Pass ``None`` to
356
+ clear a previously set end time; omit to leave it unchanged.
352
357
  input: The input to the graph.
353
358
  metadata: Metadata to assign to the cron job runs.
354
359
  config: The configuration for the assistant.
@@ -386,7 +391,6 @@ class CronClient:
386
391
  """
387
392
  payload = {
388
393
  "schedule": schedule,
389
- "end_time": end_time.isoformat() if end_time else None,
390
394
  "input": input,
391
395
  "metadata": metadata,
392
396
  "config": config,
@@ -403,6 +407,10 @@ class CronClient:
403
407
  "durability": durability,
404
408
  }
405
409
  payload = {k: v for k, v in payload.items() if v is not None}
410
+ # An explicit end_time=None clears the end time; NOT_PROVIDED leaves it
411
+ # unchanged. Inject after the None-strip so the explicit null survives.
412
+ if end_time is not NOT_PROVIDED:
413
+ payload["end_time"] = end_time.isoformat() if end_time is not None else None
406
414
  return await self.http.patch(
407
415
  f"/runs/crons/{_quote_path_param(cron_id)}",
408
416
  json=payload,
@@ -7,7 +7,11 @@ from collections.abc import Mapping, Sequence
7
7
  from datetime import datetime, tzinfo
8
8
  from typing import Any
9
9
 
10
- from langgraph_sdk._shared.utilities import _quote_path_param, _resolve_timezone
10
+ from langgraph_sdk._shared.utilities import (
11
+ NOT_PROVIDED,
12
+ _quote_path_param,
13
+ _resolve_timezone,
14
+ )
11
15
  from langgraph_sdk._sync.http import SyncHttpClient
12
16
  from langgraph_sdk.schema import (
13
17
  All,
@@ -313,7 +317,7 @@ class SyncCronClient:
313
317
  cron_id: str,
314
318
  *,
315
319
  schedule: str | None = None,
316
- end_time: datetime | None = None,
320
+ end_time: datetime | None = NOT_PROVIDED,
317
321
  input: Input | None = None,
318
322
  metadata: Mapping[str, Any] | None = None,
319
323
  config: Config | None = None,
@@ -337,7 +341,8 @@ class SyncCronClient:
337
341
  cron_id: The cron ID to update.
338
342
  schedule: The cron schedule to execute this job on.
339
343
  Schedules are interpreted in UTC unless a timezone is specified.
340
- end_time: The end date to stop running the cron.
344
+ end_time: The end date to stop running the cron. Pass ``None`` to
345
+ clear a previously set end time; omit to leave it unchanged.
341
346
  input: The input to the graph.
342
347
  metadata: Metadata to assign to the cron job runs.
343
348
  config: The configuration for the assistant.
@@ -375,7 +380,6 @@ class SyncCronClient:
375
380
  """
376
381
  payload = {
377
382
  "schedule": schedule,
378
- "end_time": end_time.isoformat() if end_time else None,
379
383
  "input": input,
380
384
  "metadata": metadata,
381
385
  "config": config,
@@ -392,6 +396,10 @@ class SyncCronClient:
392
396
  "durability": durability,
393
397
  }
394
398
  payload = {k: v for k, v in payload.items() if v is not None}
399
+ # An explicit end_time=None clears the end time; NOT_PROVIDED leaves it
400
+ # unchanged. Inject after the None-strip so the explicit null survives.
401
+ if end_time is not NOT_PROVIDED:
402
+ payload["end_time"] = end_time.isoformat() if end_time is not None else None
395
403
  return self.http.patch(
396
404
  f"/runs/crons/{_quote_path_param(cron_id)}",
397
405
  json=payload,
@@ -867,9 +867,8 @@ def _validate_handler(fn: Callable[..., typing.Any]) -> None:
867
867
  def is_studio_user(
868
868
  user: types.MinimalUser | types.BaseUser | types.MinimalUserDict,
869
869
  ) -> bool:
870
- return (
871
- isinstance(user, types.StudioUser)
872
- or (isinstance(user, dict) and user.get("kind") == "StudioUser") # ty: ignore[invalid-argument-type]
870
+ return isinstance(user, types.StudioUser) or (
871
+ isinstance(user, dict) and user.get("kind") == "StudioUser"
873
872
  )
874
873
 
875
874
 
@@ -18,6 +18,9 @@ import warnings
18
18
 
19
19
  from langgraph_sdk.encryption import types
20
20
 
21
+ _BlobDecryptorT = typing.TypeVar("_BlobDecryptorT", bound=types.BlobDecryptor)
22
+ _JsonDecryptorT = typing.TypeVar("_JsonDecryptorT", bound=types.JsonDecryptor)
23
+
21
24
 
22
25
  class LangGraphBetaWarning(UserWarning):
23
26
  """Warning for beta features in LangGraph SDK."""
@@ -141,7 +144,7 @@ class _DecryptDecorators:
141
144
  def __init__(self, parent: Encryption):
142
145
  self._parent = parent
143
146
 
144
- def blob(self, fn: types.BlobDecryptor) -> types.BlobDecryptor:
147
+ def blob(self, fn: _BlobDecryptorT) -> _BlobDecryptorT:
145
148
  """Register a blob decryption handler.
146
149
 
147
150
  The handler will be called to decrypt opaque data like checkpoint blobs.
@@ -149,7 +152,9 @@ class _DecryptDecorators:
149
152
  Example:
150
153
  ```python
151
154
  @encryption.decrypt.blob
152
- async def decrypt_blob(ctx: EncryptionContext, blob: bytes) -> bytes:
155
+ async def decrypt_blob(
156
+ ctx: EncryptionContext, blob: bytes
157
+ ) -> bytes | DecryptResult[bytes]:
153
158
  # Decrypt the blob using your encryption service
154
159
  return decrypted_blob
155
160
  ```
@@ -170,13 +175,15 @@ class _DecryptDecorators:
170
175
  self._parent._blob_decryptor = fn
171
176
  return fn
172
177
 
173
- def json(self, fn: types.JsonDecryptor) -> types.JsonDecryptor:
178
+ def json(self, fn: _JsonDecryptorT) -> _JsonDecryptorT:
174
179
  """Register the JSON decryption handler.
175
180
 
176
181
  Example:
177
182
  ```python
178
183
  @encryption.decrypt.json
179
- async def decrypt_json(ctx: EncryptionContext, data: dict) -> dict:
184
+ async def decrypt_json(
185
+ ctx: EncryptionContext, data: dict
186
+ ) -> dict | DecryptResult[dict]:
180
187
  # Decrypt the data
181
188
  return decrypt_data(data)
182
189
  ```
@@ -369,7 +376,7 @@ class Encryption:
369
376
  """Reference to encryption type definitions.
370
377
 
371
378
  Provides access to all type definitions used in the encryption system,
372
- including EncryptionContext, BlobEncryptor, BlobDecryptor,
379
+ including EncryptionContext, DecryptResult, BlobEncryptor, BlobDecryptor,
373
380
  JsonEncryptor, and JsonDecryptor.
374
381
  """
375
382
 
@@ -9,10 +9,30 @@ from __future__ import annotations
9
9
 
10
10
  import typing
11
11
  from collections.abc import Awaitable, Callable
12
+ from dataclasses import dataclass
12
13
 
13
14
  Json = dict[str, typing.Any]
14
15
  """JSON-serializable dictionary type for structured data encryption."""
15
16
 
17
+ T = typing.TypeVar("T")
18
+
19
+
20
+ @dataclass(frozen=True, slots=True)
21
+ class DecryptResult(typing.Generic[T]):
22
+ """Decrypted data and optional replacement ciphertext.
23
+
24
+ Return this from a decrypt handler when encrypted data should be replaced,
25
+ such as after rotating its encryption key. Returning plaintext directly
26
+ remains supported when no replacement is needed.
27
+
28
+ Attributes:
29
+ plaintext: Decrypted data returned to the caller
30
+ replacement: New encrypted data to persist in place of the input
31
+ """
32
+
33
+ plaintext: T
34
+ replacement: T | None = None
35
+
16
36
 
17
37
  class EncryptionContext:
18
38
  """Context passed to encryption/decryption handlers.
@@ -57,7 +77,9 @@ Returns:
57
77
  Awaitable that resolves to encrypted bytes
58
78
  """
59
79
 
60
- BlobDecryptor = Callable[[EncryptionContext, bytes], Awaitable[bytes]]
80
+ BlobDecryptor = Callable[
81
+ [EncryptionContext, bytes], Awaitable[bytes | DecryptResult[bytes]]
82
+ ]
61
83
  """Handler for decrypting opaque blob data like checkpoints.
62
84
 
63
85
  Note: Must be an async function. Decryption typically involves I/O operations
@@ -68,7 +90,8 @@ Args:
68
90
  blob: The encrypted bytes to decrypt
69
91
 
70
92
  Returns:
71
- Awaitable that resolves to decrypted bytes
93
+ Awaitable that resolves to decrypted bytes, or a DecryptResult containing
94
+ decrypted bytes and replacement ciphertext
72
95
  """
73
96
 
74
97
  JsonEncryptor = Callable[[EncryptionContext, Json], Awaitable[Json]]
@@ -101,7 +124,9 @@ Returns:
101
124
  Awaitable that resolves to encrypted JSON dictionary
102
125
  """
103
126
 
104
- JsonDecryptor = Callable[[EncryptionContext, Json], Awaitable[Json]]
127
+ JsonDecryptor = Callable[
128
+ [EncryptionContext, Json], Awaitable[Json | DecryptResult[Json]]
129
+ ]
105
130
  """Handler for decrypting structured JSON data.
106
131
 
107
132
  Note: Must be an async function. Decryption typically involves I/O operations
@@ -115,7 +140,8 @@ Args:
115
140
  data: The encrypted JSON dictionary
116
141
 
117
142
  Returns:
118
- Awaitable that resolves to decrypted JSON dictionary
143
+ Awaitable that resolves to a decrypted JSON dictionary, or a DecryptResult
144
+ containing decrypted JSON and replacement ciphertext
119
145
  """
120
146
 
121
147
  if typing.TYPE_CHECKING:
@@ -963,7 +963,7 @@ class _BaseModelLike(Protocol):
963
963
  ) -> dict[str, Any]: ...
964
964
 
965
965
 
966
- _JSONLike: TypeAlias = None | str | int | float | bool
966
+ _JSONLike: TypeAlias = str | int | float | bool | None
967
967
  _JSONMap: TypeAlias = Mapping[
968
968
  str, Union[_JSONLike, list[_JSONLike], "_JSONMap", list["_JSONMap"]]
969
969
  ]