langgraph-api 0.0.38__py3-none-any.whl → 0.0.40__py3-none-any.whl
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.
Potentially problematic release.
This version of langgraph-api might be problematic. Click here for more details.
- langgraph_api/api/__init__.py +2 -2
- langgraph_api/cli.py +3 -0
- langgraph_api/config.py +2 -0
- langgraph_api/graph.py +38 -12
- langgraph_api/js/base.py +5 -2
- langgraph_api/js/build.mts +10 -3
- langgraph_api/js/client.mts +75 -20
- langgraph_api/js/global.d.ts +1 -0
- langgraph_api/js/package.json +2 -2
- langgraph_api/js/remote.py +50 -10
- langgraph_api/js/src/graph.mts +26 -9
- langgraph_api/js/tests/api.test.mts +164 -93
- langgraph_api/js/tests/compose-postgres.yml +1 -1
- langgraph_api/js/tests/graphs/dynamic.mts +24 -0
- langgraph_api/js/tests/graphs/langgraph.json +1 -0
- langgraph_api/js/tests/utils.mts +5 -5
- langgraph_api/js/yarn.lock +8 -8
- langgraph_api/worker.py +52 -1
- {langgraph_api-0.0.38.dist-info → langgraph_api-0.0.40.dist-info}/METADATA +4 -2
- {langgraph_api-0.0.38.dist-info → langgraph_api-0.0.40.dist-info}/RECORD +27 -26
- {langgraph_api-0.0.38.dist-info → langgraph_api-0.0.40.dist-info}/WHEEL +1 -1
- langgraph_storage/database.py +7 -7
- langgraph_storage/inmem_stream.py +1 -0
- langgraph_storage/ops.py +5 -3
- langgraph_storage/queue.py +44 -0
- {langgraph_api-0.0.38.dist-info → langgraph_api-0.0.40.dist-info}/LICENSE +0 -0
- {langgraph_api-0.0.38.dist-info → langgraph_api-0.0.40.dist-info}/entry_points.txt +0 -0
|
@@ -34,7 +34,7 @@ services:
|
|
|
34
34
|
ADD . /deps/graphs
|
|
35
35
|
WORKDIR /deps/graphs
|
|
36
36
|
RUN yarn install --frozen-lockfile
|
|
37
|
-
ENV LANGSERVE_GRAPHS='{"agent":"./agent.mts:graph", "nested": "./nested.mts:graph", "weather": "./weather.mts:graph", "error": "./error.mts:graph", "delay": "./delay.mts:graph"}'
|
|
37
|
+
ENV LANGSERVE_GRAPHS='{"agent":"./agent.mts:graph", "nested": "./nested.mts:graph", "weather": "./weather.mts:graph", "error": "./error.mts:graph", "delay": "./delay.mts:graph", "dynamic": "./dynamic.mts:graph"}'
|
|
38
38
|
ENV LANGGRAPH_CONFIG='{"agent": {"configurable": {"model_name": "openai"}}}'
|
|
39
39
|
RUN tsx /api/langgraph_api/js/build.mts
|
|
40
40
|
depends_on:
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { StateGraph, Annotation } from "@langchain/langgraph";
|
|
2
|
+
|
|
3
|
+
export const graph = async (config: {
|
|
4
|
+
configurable?: { nodeName: string };
|
|
5
|
+
}) => {
|
|
6
|
+
const node = config.configurable?.nodeName ?? "default";
|
|
7
|
+
|
|
8
|
+
const state = Annotation.Root({
|
|
9
|
+
node: Annotation<string>,
|
|
10
|
+
messages: Annotation<string[]>({
|
|
11
|
+
default: () => [],
|
|
12
|
+
reducer: (a: string[], b: string[] | string) => {
|
|
13
|
+
if (Array.isArray(b)) return [...a, ...b];
|
|
14
|
+
return [...a, b];
|
|
15
|
+
},
|
|
16
|
+
}),
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
return new StateGraph(state)
|
|
20
|
+
.addNode(node, () => ({ node, messages: [node] }))
|
|
21
|
+
.addEdge("__start__", node)
|
|
22
|
+
.addEdge(node, "__end__")
|
|
23
|
+
.compile();
|
|
24
|
+
};
|
langgraph_api/js/tests/utils.mts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
export async function gatherIterator<T>(
|
|
2
|
-
i: AsyncIterable<T> | Promise<AsyncIterable<T
|
|
2
|
+
i: AsyncIterable<T> | Promise<AsyncIterable<T>>
|
|
3
3
|
): Promise<Array<T>> {
|
|
4
4
|
const out: T[] = [];
|
|
5
5
|
for await (const item of await i) out.push(item);
|
|
6
6
|
return out;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
export function findLast<T>(
|
|
9
|
+
export function findLast<T, S extends T>(
|
|
10
10
|
lst: Array<T>,
|
|
11
|
-
predicate: (item: T) =>
|
|
12
|
-
):
|
|
11
|
+
predicate: (item: T) => item is S
|
|
12
|
+
): S | undefined {
|
|
13
13
|
for (let i = lst.length - 1; i >= 0; i--) {
|
|
14
|
-
if (predicate(lst[i])) return lst[i];
|
|
14
|
+
if (predicate(lst[i])) return lst[i] as S;
|
|
15
15
|
}
|
|
16
16
|
return undefined;
|
|
17
17
|
}
|
langgraph_api/js/yarn.lock
CHANGED
|
@@ -198,10 +198,10 @@
|
|
|
198
198
|
zod "^3.22.4"
|
|
199
199
|
zod-to-json-schema "^3.22.3"
|
|
200
200
|
|
|
201
|
-
"@langchain/langgraph-api@~0.0.
|
|
202
|
-
version "0.0.
|
|
203
|
-
resolved "https://registry.yarnpkg.com/@langchain/langgraph-api/-/langgraph-api-0.0.
|
|
204
|
-
integrity sha512
|
|
201
|
+
"@langchain/langgraph-api@~0.0.19":
|
|
202
|
+
version "0.0.19"
|
|
203
|
+
resolved "https://registry.yarnpkg.com/@langchain/langgraph-api/-/langgraph-api-0.0.19.tgz#e4b8054a1f4e7943bc53787fb6335470b55f4b1d"
|
|
204
|
+
integrity sha512-vsWnVUMVdr3i0ooI3Pcq4tbRKyRiDFGtUyyusCs2zZ/AHNIOV1ieHVTYubhZ04F+jNEwe0SwSMqtM0/Vg+cbTw==
|
|
205
205
|
dependencies:
|
|
206
206
|
"@babel/code-frame" "^7.26.2"
|
|
207
207
|
"@hono/node-server" "^1.12.0"
|
|
@@ -238,10 +238,10 @@
|
|
|
238
238
|
dependencies:
|
|
239
239
|
uuid "^10.0.0"
|
|
240
240
|
|
|
241
|
-
"@langchain/langgraph-sdk@^0.0.
|
|
242
|
-
version "0.0.
|
|
243
|
-
resolved "https://registry.yarnpkg.com/@langchain/langgraph-sdk/-/langgraph-sdk-0.0.
|
|
244
|
-
integrity sha512-
|
|
241
|
+
"@langchain/langgraph-sdk@^0.0.60":
|
|
242
|
+
version "0.0.60"
|
|
243
|
+
resolved "https://registry.yarnpkg.com/@langchain/langgraph-sdk/-/langgraph-sdk-0.0.60.tgz#eee259632f362298b23712ccf393903daf8affc9"
|
|
244
|
+
integrity sha512-7ndeAdw1afVY72HpKEGw7AyuDlD7U3e4jxaJflxA+PXaFPiE0d/hQYvlPT84YmvqNzJN605hv7YcrOju2573bQ==
|
|
245
245
|
dependencies:
|
|
246
246
|
"@types/json-schema" "^7.0.15"
|
|
247
247
|
p-queue "^6.6.2"
|
langgraph_api/worker.py
CHANGED
|
@@ -10,6 +10,7 @@ from starlette.exceptions import HTTPException
|
|
|
10
10
|
|
|
11
11
|
from langgraph_api.auth.custom import SimpleUser, normalize_user
|
|
12
12
|
from langgraph_api.config import (
|
|
13
|
+
BG_JOB_ISOLATED_LOOPS,
|
|
13
14
|
BG_JOB_MAX_RETRIES,
|
|
14
15
|
BG_JOB_TIMEOUT_SECS,
|
|
15
16
|
)
|
|
@@ -34,6 +35,11 @@ try:
|
|
|
34
35
|
except ImportError:
|
|
35
36
|
InFailedSqlTransaction = ()
|
|
36
37
|
|
|
38
|
+
try:
|
|
39
|
+
from blockbuster import BlockingError
|
|
40
|
+
except ImportError:
|
|
41
|
+
BlockingError = ()
|
|
42
|
+
|
|
37
43
|
logger = structlog.stdlib.get_logger(__name__)
|
|
38
44
|
|
|
39
45
|
|
|
@@ -110,7 +116,22 @@ async def worker(
|
|
|
110
116
|
|
|
111
117
|
try:
|
|
112
118
|
if attempt > BG_JOB_MAX_RETRIES:
|
|
113
|
-
|
|
119
|
+
await logger.aerror("Run exceeded max attempts", run_id=run["run_id"])
|
|
120
|
+
|
|
121
|
+
error_message = (
|
|
122
|
+
f"Run {run['run_id']} exceeded max attempts ({BG_JOB_MAX_RETRIES}).\n\n"
|
|
123
|
+
"This may happen if your code blocks the event loop with synchronous I/O bound calls (network requests, database queries, etc.).\n\n"
|
|
124
|
+
"If that is the case, your issues may be resolved by converting synchronous operations to async (e.g., use aiohttp instead of requests).\n\n"
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
if not BG_JOB_ISOLATED_LOOPS:
|
|
128
|
+
error_message += (
|
|
129
|
+
"Also consider setting BG_JOB_ISOLATED_LOOPS=true in your environment. This will isolate I/O-bound operations to avoid"
|
|
130
|
+
" blocking the main API server.\n\n"
|
|
131
|
+
"See: https://langchain-ai.github.io/langgraph/cloud/reference/env_var/#bg_job_isolated_loops\n\n"
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
raise RuntimeError(error_message)
|
|
114
135
|
if temporary:
|
|
115
136
|
stream = astream_state(
|
|
116
137
|
AsyncExitStack(), conn, cast(Run, run), attempt, done
|
|
@@ -150,6 +171,7 @@ async def worker(
|
|
|
150
171
|
run_started_at=run_started_at.isoformat(),
|
|
151
172
|
run_ended_at=run_ended_at,
|
|
152
173
|
run_exec_ms=ms(datetime.now(UTC), run_started_at),
|
|
174
|
+
graph_id=_get_graph_id(run),
|
|
153
175
|
)
|
|
154
176
|
await Runs.set_status(conn, run_id, "timeout")
|
|
155
177
|
except UserRollback as e:
|
|
@@ -166,6 +188,7 @@ async def worker(
|
|
|
166
188
|
run_started_at=run_started_at.isoformat(),
|
|
167
189
|
run_ended_at=run_ended_at,
|
|
168
190
|
run_exec_ms=ms(datetime.now(UTC), run_started_at),
|
|
191
|
+
graph_id=_get_graph_id(run),
|
|
169
192
|
)
|
|
170
193
|
|
|
171
194
|
except InFailedSqlTransaction as e:
|
|
@@ -203,6 +226,7 @@ async def worker(
|
|
|
203
226
|
run_started_at=run_started_at.isoformat(),
|
|
204
227
|
run_ended_at=run_ended_at,
|
|
205
228
|
run_exec_ms=ms(datetime.now(UTC), run_started_at),
|
|
229
|
+
graph_id=_get_graph_id(run),
|
|
206
230
|
)
|
|
207
231
|
await Runs.set_status(conn, run_id, "interrupted")
|
|
208
232
|
except RETRIABLE_EXCEPTIONS as e:
|
|
@@ -218,10 +242,28 @@ async def worker(
|
|
|
218
242
|
run_started_at=run_started_at.isoformat(),
|
|
219
243
|
run_ended_at=run_ended_at,
|
|
220
244
|
run_exec_ms=ms(datetime.now(UTC), run_started_at),
|
|
245
|
+
graph_id=_get_graph_id(run),
|
|
221
246
|
)
|
|
222
247
|
await Runs.set_status(conn, run_id, "pending")
|
|
223
248
|
raise
|
|
224
249
|
except Exception as exc:
|
|
250
|
+
if isinstance(exc, BlockingError):
|
|
251
|
+
# Only occurs in the dev server
|
|
252
|
+
exc.add_note(
|
|
253
|
+
"Heads up! LangGraph identified a synchronous blocking call in your code. "
|
|
254
|
+
"When running in an ASGI web server, blocking calls can degrade performance for everyone since they tie up the event loop.\n\n"
|
|
255
|
+
"Here are your options to fix this:\n\n"
|
|
256
|
+
"1. Best approach: Convert any blocking code to use async/await patterns\n"
|
|
257
|
+
" For example, use 'await aiohttp.get()' instead of 'requests.get()'\n\n"
|
|
258
|
+
"2. Quick fix: Move blocking operations to a separate thread\n"
|
|
259
|
+
" Example: 'await asyncio.to_thread(your_blocking_function)'\n\n"
|
|
260
|
+
"3. Override (if you can't change the code):\n"
|
|
261
|
+
" - For development: Run 'langgraph dev --allow-blocking'\n"
|
|
262
|
+
" - For deployment: Set 'BG_JOB_ISOLATED_LOOPS=true' environment variable\n\n"
|
|
263
|
+
"These blocking operations can prevent health checks and slow down other runs in your deployment. "
|
|
264
|
+
"Following these recommendations will help keep your LangGraph application running smoothly!"
|
|
265
|
+
)
|
|
266
|
+
|
|
225
267
|
exception = exc
|
|
226
268
|
status = "error"
|
|
227
269
|
run_ended_at = datetime.now(UTC).isoformat()
|
|
@@ -234,6 +276,7 @@ async def worker(
|
|
|
234
276
|
run_started_at=run_started_at.isoformat(),
|
|
235
277
|
run_ended_at=run_ended_at,
|
|
236
278
|
run_exec_ms=ms(datetime.now(UTC), run_started_at),
|
|
279
|
+
graph_id=_get_graph_id(run),
|
|
237
280
|
)
|
|
238
281
|
await Runs.set_status(conn, run_id, "error")
|
|
239
282
|
set_auth_ctx(None, None)
|
|
@@ -266,3 +309,11 @@ async def worker(
|
|
|
266
309
|
|
|
267
310
|
def ms(after: datetime, before: datetime) -> int:
|
|
268
311
|
return int((after - before).total_seconds() * 1000)
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
def _get_graph_id(run: Run) -> str | None:
|
|
315
|
+
try:
|
|
316
|
+
return run["kwargs"]["config"]["configurable"]["graph_id"]
|
|
317
|
+
except Exception:
|
|
318
|
+
logger.info(f"Failed to get graph_id from run {run['run_id']}")
|
|
319
|
+
return "Unknown"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
2
|
Name: langgraph-api
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.40
|
|
4
4
|
Summary:
|
|
5
5
|
License: Elastic-2.0
|
|
6
6
|
Author: Nuno Campos
|
|
@@ -10,6 +10,8 @@ Classifier: License :: Other/Proprietary License
|
|
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
|
11
11
|
Classifier: Programming Language :: Python :: 3.11
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Requires-Dist: blockbuster (>=1.5.24,<2.0.0)
|
|
13
15
|
Requires-Dist: cloudpickle (>=3.0.0,<4.0.0)
|
|
14
16
|
Requires-Dist: cryptography (>=43.0.3,<44.0.0)
|
|
15
17
|
Requires-Dist: httpx (>=0.25.0)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
LICENSE,sha256=ZPwVR73Biwm3sK6vR54djCrhaRiM4cAD2zvOQZV8Xis,3859
|
|
2
2
|
langgraph_api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
-
langgraph_api/api/__init__.py,sha256=
|
|
3
|
+
langgraph_api/api/__init__.py,sha256=qNcg8QJydef0gM-vYJlxITMRZw-9r1vw8zqm2raqqYE,5493
|
|
4
4
|
langgraph_api/api/assistants.py,sha256=nU6tnbgdr_6Utlq0A9nw2a6xxpUM_DNuCFI42_Kcs_o,14233
|
|
5
5
|
langgraph_api/api/mcp.py,sha256=KbR19dtFCpJEiKYj3IfepAuJij8YZVELuVp7JY_yu_o,13754
|
|
6
6
|
langgraph_api/api/meta.py,sha256=ifJ_Ki0Qf2DYbmY6OKlqKhLGxbt55gm0lEqH1A0cJbw,2790
|
|
@@ -18,23 +18,23 @@ langgraph_api/auth/langsmith/client.py,sha256=eKchvAom7hdkUXauD8vHNceBDDUijrFgdT
|
|
|
18
18
|
langgraph_api/auth/middleware.py,sha256=jU8aDSIZHdzCGdifejRF7ndHkSjBtqIHcBwFIuUdHEA,1875
|
|
19
19
|
langgraph_api/auth/noop.py,sha256=Bk6Nf3p8D_iMVy_OyfPlyiJp_aEwzL-sHrbxoXpCbac,586
|
|
20
20
|
langgraph_api/auth/studio_user.py,sha256=FzFQRROKDlA9JjtBuwyZvk6Mbwno5M9RVYjDO6FU3F8,186
|
|
21
|
-
langgraph_api/cli.py,sha256=
|
|
21
|
+
langgraph_api/cli.py,sha256=X76TYnErQPjRkZhK-n6gthCUmtItkwqVrRPvwZswF5Y,12335
|
|
22
22
|
langgraph_api/command.py,sha256=3O9v3i0OPa96ARyJ_oJbLXkfO8rPgDhLCswgO9koTFA,768
|
|
23
|
-
langgraph_api/config.py,sha256=
|
|
23
|
+
langgraph_api/config.py,sha256=y-dmkmd929WDosIO0nUmcQicZN2XozJrVHzeBGtLhUg,9418
|
|
24
24
|
langgraph_api/cron_scheduler.py,sha256=9yzbbGxzNgJdIg4ZT7yu2oTwT_wRuPxD1c2sbbd52xs,2630
|
|
25
25
|
langgraph_api/errors.py,sha256=Bu_i5drgNTyJcLiyrwVE_6-XrSU50BHf9TDpttki9wQ,1690
|
|
26
|
-
langgraph_api/graph.py,sha256=
|
|
26
|
+
langgraph_api/graph.py,sha256=jpMMMgn8uHqDc3gPu02tF7B8af0TV153t2F_kodcBvI,18799
|
|
27
27
|
langgraph_api/http.py,sha256=gYbxxjY8aLnsXeJymcJ7G7Nj_yToOGpPYQqmZ1_ggfA,5240
|
|
28
28
|
langgraph_api/js/.gitignore,sha256=l5yI6G_V6F1600I1IjiUKn87f4uYIrBAYU1MOyBBhg4,59
|
|
29
|
-
langgraph_api/js/base.py,sha256=
|
|
30
|
-
langgraph_api/js/build.mts,sha256=
|
|
31
|
-
langgraph_api/js/client.mts,sha256=
|
|
29
|
+
langgraph_api/js/base.py,sha256=xkBp5bwRrbpMFaAMViEU-qIlnsJuu3X_G8sa1pqNZK0,227
|
|
30
|
+
langgraph_api/js/build.mts,sha256=PZGeFTOhmRIBxkbFaaUOpTacqg1Z7kUkZWTU2l9a7FY,3077
|
|
31
|
+
langgraph_api/js/client.mts,sha256=n6ecWwJBP2wp1jCaam55GxffH-YesVrV-7ZTml-k4Oc,26137
|
|
32
32
|
langgraph_api/js/errors.py,sha256=Cm1TKWlUCwZReDC5AQ6SgNIVGD27Qov2xcgHyf8-GXo,361
|
|
33
|
-
langgraph_api/js/global.d.ts,sha256=
|
|
34
|
-
langgraph_api/js/package.json,sha256=
|
|
35
|
-
langgraph_api/js/remote.py,sha256=
|
|
33
|
+
langgraph_api/js/global.d.ts,sha256=yDusqAyzVYhxfwqqcERUzucu2Pw9ma3-ug4DFyUvQfs,167
|
|
34
|
+
langgraph_api/js/package.json,sha256=uA_2KV86yMJmqfQd9Xe4w2PPjH6DmttBpSxi1PlSq3U,1224
|
|
35
|
+
langgraph_api/js/remote.py,sha256=jtzzkCBZ6eUE8g1JCn1lguaKF1RkpUmKbdblI6-NWgQ,24607
|
|
36
36
|
langgraph_api/js/schema.py,sha256=7idnv7URlYUdSNMBXQcw7E4SxaPxCq_Oxwnlml8q5ik,408
|
|
37
|
-
langgraph_api/js/src/graph.mts,sha256=
|
|
37
|
+
langgraph_api/js/src/graph.mts,sha256=otgztTNzNJpeF2IOrpNuuwbSbpAy4eFE5dHtUd7eQwU,3742
|
|
38
38
|
langgraph_api/js/src/hooks.mjs,sha256=XtktgmIHlls_DsknAuwib-z7TqCm0haRoTXvnkgzMuo,601
|
|
39
39
|
langgraph_api/js/src/parser/parser.mts,sha256=c7WLEtMMwtVzir9O8VpJFVHKuLjtI86rde-In2lvaM0,13217
|
|
40
40
|
langgraph_api/js/src/parser/parser.worker.mjs,sha256=2K6D0GlUmkk7LE39I8mryB8VZVE3-N9Cblji-ArPhFo,386
|
|
@@ -44,22 +44,23 @@ langgraph_api/js/src/utils/importMap.mts,sha256=pX4TGOyUpuuWF82kXcxcv3-8mgusRezO
|
|
|
44
44
|
langgraph_api/js/src/utils/pythonSchemas.mts,sha256=98IW7Z_VP7L_CHNRMb3_MsiV3BgLE2JsWQY_PQcRR3o,685
|
|
45
45
|
langgraph_api/js/src/utils/serde.mts,sha256=OuyyO9btvwWd55rU_H4x91dFEJiaPxL-lL9O6Zgo908,742
|
|
46
46
|
langgraph_api/js/sse.py,sha256=lsfp4nyJyA1COmlKG9e2gJnTttf_HGCB5wyH8OZBER8,4105
|
|
47
|
-
langgraph_api/js/tests/api.test.mts,sha256=
|
|
48
|
-
langgraph_api/js/tests/compose-postgres.yml,sha256=
|
|
47
|
+
langgraph_api/js/tests/api.test.mts,sha256=GlCTOTuSGc2m2vdsw6PSZrDPgfcvJi0A5v4A9xGaZi4,60004
|
|
48
|
+
langgraph_api/js/tests/compose-postgres.yml,sha256=pV1dW6aCgTTJ1WHSDeCqlVgFE9PbyWW5WbwrsiJcgoA,1772
|
|
49
49
|
langgraph_api/js/tests/graphs/.gitignore,sha256=26J8MarZNXh7snXD5eTpV3CPFTht5Znv8dtHYCLNfkw,12
|
|
50
50
|
langgraph_api/js/tests/graphs/agent.css,sha256=QgcOC0W7IBsrg4pSqqpull-WTgtULZfx_lF_5ZxLdag,23
|
|
51
51
|
langgraph_api/js/tests/graphs/agent.mts,sha256=E9WMv0alMv0njUEECqEsqoRk9NXJUgXW7SyQJ3GOZ8k,5396
|
|
52
52
|
langgraph_api/js/tests/graphs/agent.ui.tsx,sha256=JDFJdpdIS6rglkXTaROSb1Is0j1kt5wN9ML8W4cuht8,175
|
|
53
53
|
langgraph_api/js/tests/graphs/delay.mts,sha256=CFneKxqI4bGGK0lYjSbe80QirowPQlsRSuhDUKfydhk,703
|
|
54
|
+
langgraph_api/js/tests/graphs/dynamic.mts,sha256=Wf_-keF7lkEfp_iyI45nlFGCeU8ARLQ8axc0LXh7TyE,659
|
|
54
55
|
langgraph_api/js/tests/graphs/error.mts,sha256=l4tk89449dj1BnEF_0ZcfPt0Ikk1gl8L1RaSnRfr3xo,487
|
|
55
|
-
langgraph_api/js/tests/graphs/langgraph.json,sha256=
|
|
56
|
+
langgraph_api/js/tests/graphs/langgraph.json,sha256=iZL7XpAy3-QnCUHCRSj__Fxp3A-JPuYBJ_XQIxeyQfU,227
|
|
56
57
|
langgraph_api/js/tests/graphs/nested.mts,sha256=4G7jSOSaFVQAza-_ARbK-Iai1biLlF2DIPDZXf7PLIY,1245
|
|
57
58
|
langgraph_api/js/tests/graphs/package.json,sha256=Kv2kdlTNeWl00vYQAhngorQ6rLab4SMc7g1AgZslrHQ,118
|
|
58
59
|
langgraph_api/js/tests/graphs/weather.mts,sha256=A7mLK3xW8h5B-ZyJNAyX2M2fJJwzPJzXs4DYesJwreQ,1655
|
|
59
60
|
langgraph_api/js/tests/graphs/yarn.lock,sha256=i2AAIgXA3XBLM8-oU45wgUefCSG-Tne4ghWHmUCUKVk,10407
|
|
60
61
|
langgraph_api/js/tests/parser.test.mts,sha256=dEC8KTqKygeb1u39ZvpPqCT4HtfPD947nLmITt2buxA,27883
|
|
61
|
-
langgraph_api/js/tests/utils.mts,sha256=
|
|
62
|
-
langgraph_api/js/yarn.lock,sha256=
|
|
62
|
+
langgraph_api/js/tests/utils.mts,sha256=q1V9gvT63v95onlfK9W4iv3n9ZJO3h-0RD9TdDYuRyY,439
|
|
63
|
+
langgraph_api/js/yarn.lock,sha256=JtMDtRVX9kr9lK0rbWRQsGHYbkQSmzNa4NwTunBv58U,82773
|
|
63
64
|
langgraph_api/lifespan.py,sha256=0F4Xn6IC4wUfvBWbm6KCJ-jiF0S7iWDOHJYJZ-A3o3s,2739
|
|
64
65
|
langgraph_api/logging.py,sha256=JJIzbNIgLCN6ClQ3tA-Mm5ffuBGvpRDSZsEvnIlsuu4,3693
|
|
65
66
|
langgraph_api/metadata.py,sha256=5Mu3MUtUc-iIocU3X2SZDoGIqnUmTdT3517MhP94npI,3495
|
|
@@ -81,23 +82,23 @@ langgraph_api/thread_ttl.py,sha256=ubkWMymTR7p9nGWd60-WKEOQ20ZgIkWB6WGstQUmRS4,1
|
|
|
81
82
|
langgraph_api/utils.py,sha256=92mSti9GfGdMRRWyESKQW5yV-75Z9icGHnIrBYvdypU,3619
|
|
82
83
|
langgraph_api/validation.py,sha256=Qo3EkSRXzIRe3GRuqRWbElTcUXRMXMyA1w0VbMvdwME,4934
|
|
83
84
|
langgraph_api/webhook.py,sha256=1ncwO0rIZcj-Df9sxSnFEzd1gP1bfS4okeZQS8NSRoE,1382
|
|
84
|
-
langgraph_api/worker.py,sha256=
|
|
85
|
+
langgraph_api/worker.py,sha256=CLmohk3B03OTsKHq_ZPhujMHFSuc694qeEL4VNSxHvg,12679
|
|
85
86
|
langgraph_license/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
86
87
|
langgraph_license/middleware.py,sha256=_ODIYzQkymr6W9_Fp9wtf1kAQspnpsmr53xuzyF2GA0,612
|
|
87
88
|
langgraph_license/validation.py,sha256=Uu_G8UGO_WTlLsBEY0gTVWjRR4czYGfw5YAD3HLZoj0,203
|
|
88
89
|
langgraph_storage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
89
90
|
langgraph_storage/checkpoint.py,sha256=Qq0y6vdh27qdF3h5nOLT5CcX9Rj2bcFqkVOMeCaGoK4,4036
|
|
90
|
-
langgraph_storage/database.py,sha256=
|
|
91
|
-
langgraph_storage/inmem_stream.py,sha256=
|
|
92
|
-
langgraph_storage/ops.py,sha256=
|
|
93
|
-
langgraph_storage/queue.py,sha256=
|
|
91
|
+
langgraph_storage/database.py,sha256=ys2glLtQaspfIY-_EgqEOT3b7a5WqBwuE_9I5VAh6FM,5821
|
|
92
|
+
langgraph_storage/inmem_stream.py,sha256=LjJSAxsh_E0ywqEMzdWJk8Hy_Jn9oQByzycss-fANng,3264
|
|
93
|
+
langgraph_storage/ops.py,sha256=6NxeirfuDAKghHc328zejnbTsijg6U80Rlt5rXTC2dc,75392
|
|
94
|
+
langgraph_storage/queue.py,sha256=wyBcY1V_8zah0Z2e5hpovs_dsIPPPfUJQCly2rxFWvo,7039
|
|
94
95
|
langgraph_storage/retry.py,sha256=XmldOP4e_H5s264CagJRVnQMDFcEJR_dldVR1Hm5XvM,763
|
|
95
96
|
langgraph_storage/store.py,sha256=JB9jZ87GE19MVN9wgl3-esgR2eIkeipws9q6qsPWkgc,3399
|
|
96
97
|
langgraph_storage/ttl_dict.py,sha256=FlpEY8EANeXWKo_G5nmIotPquABZGyIJyk6HD9u6vqY,1533
|
|
97
98
|
logging.json,sha256=3RNjSADZmDq38eHePMm1CbP6qZ71AmpBtLwCmKU9Zgo,379
|
|
98
99
|
openapi.json,sha256=-25y3NRQ88e_944UXo76Goa34HJhC7pj6I9tjYUwvuE,131492
|
|
99
|
-
langgraph_api-0.0.
|
|
100
|
-
langgraph_api-0.0.
|
|
101
|
-
langgraph_api-0.0.
|
|
102
|
-
langgraph_api-0.0.
|
|
103
|
-
langgraph_api-0.0.
|
|
100
|
+
langgraph_api-0.0.40.dist-info/LICENSE,sha256=ZPwVR73Biwm3sK6vR54djCrhaRiM4cAD2zvOQZV8Xis,3859
|
|
101
|
+
langgraph_api-0.0.40.dist-info/METADATA,sha256=CsN_X-9ths2igUx9E7DdiRHbrqRUFgBa7TnlqHDjTC0,4167
|
|
102
|
+
langgraph_api-0.0.40.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
|
|
103
|
+
langgraph_api-0.0.40.dist-info/entry_points.txt,sha256=3EYLgj89DfzqJHHYGxPH4A_fEtClvlRbWRUHaXO7hj4,77
|
|
104
|
+
langgraph_api-0.0.40.dist-info/RECORD,,
|
langgraph_storage/database.py
CHANGED
|
@@ -161,12 +161,12 @@ async def start_pool() -> None:
|
|
|
161
161
|
"\n - Pulled updates that modified class definitions in a way that's incompatible with the cache"
|
|
162
162
|
"\n\nRemoving invalid cache data stored at path: .langgraph_api"
|
|
163
163
|
)
|
|
164
|
-
os.remove
|
|
165
|
-
os.remove
|
|
164
|
+
await asyncio.to_thread(os.remove, OPS_FILENAME)
|
|
165
|
+
await asyncio.to_thread(os.remove, RETRY_COUNTER_FILENAME)
|
|
166
166
|
except Exception as e:
|
|
167
167
|
logger.error("Failed to load cached data: %s", str(e))
|
|
168
|
-
os.remove
|
|
169
|
-
os.remove
|
|
168
|
+
await asyncio.to_thread(os.remove, OPS_FILENAME)
|
|
169
|
+
await asyncio.to_thread(os.remove, RETRY_COUNTER_FILENAME)
|
|
170
170
|
for k in ["runs", "threads", "assistants", "assistant_versions"]:
|
|
171
171
|
if not GLOBAL_STORE.get(k):
|
|
172
172
|
GLOBAL_STORE[k] = []
|
|
@@ -177,12 +177,12 @@ async def start_pool() -> None:
|
|
|
177
177
|
|
|
178
178
|
|
|
179
179
|
async def stop_pool() -> None:
|
|
180
|
-
GLOBAL_STORE.close
|
|
181
|
-
GLOBAL_RETRY_COUNTER.close
|
|
180
|
+
await asyncio.to_thread(GLOBAL_STORE.close)
|
|
181
|
+
await asyncio.to_thread(GLOBAL_RETRY_COUNTER.close)
|
|
182
182
|
from langgraph_storage.checkpoint import Checkpointer
|
|
183
183
|
from langgraph_storage.store import STORE
|
|
184
184
|
|
|
185
|
-
STORE.close
|
|
185
|
+
await asyncio.to_thread(STORE.close)
|
|
186
186
|
|
|
187
187
|
async with Checkpointer():
|
|
188
188
|
pass
|
|
@@ -92,6 +92,7 @@ async def stop_stream() -> None:
|
|
|
92
92
|
# Send 'done' message to all active queues before clearing
|
|
93
93
|
for run_id in list(stream_manager.queues.keys()):
|
|
94
94
|
control_message = Message(topic=f"run:{run_id}:control".encode(), data=b"done")
|
|
95
|
+
|
|
95
96
|
for queue in stream_manager.queues[run_id]:
|
|
96
97
|
try:
|
|
97
98
|
await queue.put(control_message)
|
langgraph_storage/ops.py
CHANGED
|
@@ -985,7 +985,9 @@ class Threads(Authenticated):
|
|
|
985
985
|
ctx: Auth.types.BaseAuthContext | None = None,
|
|
986
986
|
) -> StateSnapshot:
|
|
987
987
|
"""Get state for a thread."""
|
|
988
|
-
checkpointer =
|
|
988
|
+
checkpointer = await asyncio.to_thread(
|
|
989
|
+
Checkpointer, conn, unpack_hook=_msgpack_ext_hook_to_json
|
|
990
|
+
)
|
|
989
991
|
thread_id = _ensure_uuid(config["configurable"]["thread_id"])
|
|
990
992
|
# Auth will be applied here so no need to use filters downstream
|
|
991
993
|
thread_iter = await Threads.get(conn, thread_id, ctx=ctx)
|
|
@@ -1206,8 +1208,8 @@ class Threads(Authenticated):
|
|
|
1206
1208
|
async with get_graph(
|
|
1207
1209
|
graph_id,
|
|
1208
1210
|
thread_config,
|
|
1209
|
-
checkpointer=
|
|
1210
|
-
conn, unpack_hook=_msgpack_ext_hook_to_json
|
|
1211
|
+
checkpointer=await asyncio.to_thread(
|
|
1212
|
+
Checkpointer, conn, unpack_hook=_msgpack_ext_hook_to_json
|
|
1211
1213
|
),
|
|
1212
1214
|
) as graph:
|
|
1213
1215
|
# Convert before parameter if it's a string
|
langgraph_storage/queue.py
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
+
import os
|
|
2
3
|
|
|
3
4
|
import structlog
|
|
5
|
+
from blockbuster import BlockBuster
|
|
6
|
+
from langsmith import env as ls_env
|
|
4
7
|
|
|
5
8
|
from langgraph_api.config import (
|
|
6
9
|
BG_JOB_HEARTBEAT,
|
|
@@ -27,6 +30,20 @@ async def queue():
|
|
|
27
30
|
last_sweep_secs: int | None = None
|
|
28
31
|
semaphore = asyncio.Semaphore(concurrency)
|
|
29
32
|
WEBHOOKS: set[asyncio.Task] = set()
|
|
33
|
+
enable_blocking = os.getenv("LANGGRAPH_ALLOW_BLOCKING", "false").lower() == "true"
|
|
34
|
+
|
|
35
|
+
# raise exceptions when a blocking call is detected inside an async function
|
|
36
|
+
if enable_blocking:
|
|
37
|
+
bb = None
|
|
38
|
+
await logger.awarning(
|
|
39
|
+
"Heads up: You've set --allow-blocking, which allows synchronous blocking I/O operations."
|
|
40
|
+
" Be aware that blocking code in one run may tie up the shared event loop"
|
|
41
|
+
" and slow down ALL other server operations. For best performance, either convert blocking"
|
|
42
|
+
" code to async patterns or set BG_JOB_ISOLATED_LOOPS=true in production"
|
|
43
|
+
" to isolate each run in its own event loop."
|
|
44
|
+
)
|
|
45
|
+
else:
|
|
46
|
+
bb = _enable_blockbuster()
|
|
30
47
|
|
|
31
48
|
def cleanup(task: asyncio.Task):
|
|
32
49
|
WORKERS.remove(task)
|
|
@@ -120,6 +137,8 @@ async def queue():
|
|
|
120
137
|
semaphore.release()
|
|
121
138
|
await exit.aclose()
|
|
122
139
|
finally:
|
|
140
|
+
if bb:
|
|
141
|
+
bb.deactivate()
|
|
123
142
|
logger.info("Shutting down background workers")
|
|
124
143
|
for task in WORKERS:
|
|
125
144
|
task.cancel()
|
|
@@ -129,3 +148,28 @@ async def queue():
|
|
|
129
148
|
asyncio.gather(*WORKERS, *WEBHOOKS, return_exceptions=True),
|
|
130
149
|
SHUTDOWN_GRACE_PERIOD_SECS,
|
|
131
150
|
)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def _enable_blockbuster() -> BlockBuster:
|
|
154
|
+
ls_env.get_runtime_environment() # this gets cached
|
|
155
|
+
bb = BlockBuster(excluded_modules=["logging"])
|
|
156
|
+
bb.activate()
|
|
157
|
+
# Note, we've cached this call in langsmith==0.3.21 so it shouldn't raise anyway
|
|
158
|
+
# but we don't want to raise teh minbound just for that.
|
|
159
|
+
for func in ["os.stat", "io.TextIOWrapper.read"]:
|
|
160
|
+
bb.functions[func].can_block_in("langsmith/client.py", "_default_retry_config")
|
|
161
|
+
# Only triggers in python 3.11 for getting subgraphs
|
|
162
|
+
# Will be unnecessary once we cache the assistant schemas
|
|
163
|
+
bb.functions[func].can_block_in(
|
|
164
|
+
"langgraph/pregel/utils.py", "get_function_nonlocals"
|
|
165
|
+
)
|
|
166
|
+
for module, func in [
|
|
167
|
+
("uvicorn/lifespan/on.py", "startup"),
|
|
168
|
+
("uvicorn/lifespan/on.py", "shutdown"),
|
|
169
|
+
("ansitowin32.py", "write_plain_text"),
|
|
170
|
+
("logging/__init__.py", "flush"),
|
|
171
|
+
("logging/__init__.py", "emit"),
|
|
172
|
+
]:
|
|
173
|
+
bb.functions["io.TextIOWrapper.write"].can_block_in(module, func)
|
|
174
|
+
bb.functions["io.BufferedWriter.write"].can_block_in(module, func)
|
|
175
|
+
return bb
|
|
File without changes
|
|
File without changes
|