langgraph-api 0.0.38__py3-none-any.whl → 0.0.39__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.39.dist-info}/METADATA +4 -2
- {langgraph_api-0.0.38.dist-info → langgraph_api-0.0.39.dist-info}/RECORD +27 -29
- {langgraph_api-0.0.38.dist-info → langgraph_api-0.0.39.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/LICENSE +0 -93
- logging.json +0 -22
- openapi.json +0 -4596
- /LICENSE → /langgraph_api-0.0.39.dist-info/LICENSE +0 -0
- {langgraph_api-0.0.38.dist-info → langgraph_api-0.0.39.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.39
|
|
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,5 @@
|
|
|
1
|
-
LICENSE,sha256=ZPwVR73Biwm3sK6vR54djCrhaRiM4cAD2zvOQZV8Xis,3859
|
|
2
1
|
langgraph_api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
-
langgraph_api/api/__init__.py,sha256=
|
|
2
|
+
langgraph_api/api/__init__.py,sha256=qNcg8QJydef0gM-vYJlxITMRZw-9r1vw8zqm2raqqYE,5493
|
|
4
3
|
langgraph_api/api/assistants.py,sha256=nU6tnbgdr_6Utlq0A9nw2a6xxpUM_DNuCFI42_Kcs_o,14233
|
|
5
4
|
langgraph_api/api/mcp.py,sha256=KbR19dtFCpJEiKYj3IfepAuJij8YZVELuVp7JY_yu_o,13754
|
|
6
5
|
langgraph_api/api/meta.py,sha256=ifJ_Ki0Qf2DYbmY6OKlqKhLGxbt55gm0lEqH1A0cJbw,2790
|
|
@@ -18,23 +17,23 @@ langgraph_api/auth/langsmith/client.py,sha256=eKchvAom7hdkUXauD8vHNceBDDUijrFgdT
|
|
|
18
17
|
langgraph_api/auth/middleware.py,sha256=jU8aDSIZHdzCGdifejRF7ndHkSjBtqIHcBwFIuUdHEA,1875
|
|
19
18
|
langgraph_api/auth/noop.py,sha256=Bk6Nf3p8D_iMVy_OyfPlyiJp_aEwzL-sHrbxoXpCbac,586
|
|
20
19
|
langgraph_api/auth/studio_user.py,sha256=FzFQRROKDlA9JjtBuwyZvk6Mbwno5M9RVYjDO6FU3F8,186
|
|
21
|
-
langgraph_api/cli.py,sha256=
|
|
20
|
+
langgraph_api/cli.py,sha256=X76TYnErQPjRkZhK-n6gthCUmtItkwqVrRPvwZswF5Y,12335
|
|
22
21
|
langgraph_api/command.py,sha256=3O9v3i0OPa96ARyJ_oJbLXkfO8rPgDhLCswgO9koTFA,768
|
|
23
|
-
langgraph_api/config.py,sha256=
|
|
22
|
+
langgraph_api/config.py,sha256=y-dmkmd929WDosIO0nUmcQicZN2XozJrVHzeBGtLhUg,9418
|
|
24
23
|
langgraph_api/cron_scheduler.py,sha256=9yzbbGxzNgJdIg4ZT7yu2oTwT_wRuPxD1c2sbbd52xs,2630
|
|
25
24
|
langgraph_api/errors.py,sha256=Bu_i5drgNTyJcLiyrwVE_6-XrSU50BHf9TDpttki9wQ,1690
|
|
26
|
-
langgraph_api/graph.py,sha256=
|
|
25
|
+
langgraph_api/graph.py,sha256=jpMMMgn8uHqDc3gPu02tF7B8af0TV153t2F_kodcBvI,18799
|
|
27
26
|
langgraph_api/http.py,sha256=gYbxxjY8aLnsXeJymcJ7G7Nj_yToOGpPYQqmZ1_ggfA,5240
|
|
28
27
|
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=
|
|
28
|
+
langgraph_api/js/base.py,sha256=xkBp5bwRrbpMFaAMViEU-qIlnsJuu3X_G8sa1pqNZK0,227
|
|
29
|
+
langgraph_api/js/build.mts,sha256=PZGeFTOhmRIBxkbFaaUOpTacqg1Z7kUkZWTU2l9a7FY,3077
|
|
30
|
+
langgraph_api/js/client.mts,sha256=n6ecWwJBP2wp1jCaam55GxffH-YesVrV-7ZTml-k4Oc,26137
|
|
32
31
|
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=
|
|
32
|
+
langgraph_api/js/global.d.ts,sha256=yDusqAyzVYhxfwqqcERUzucu2Pw9ma3-ug4DFyUvQfs,167
|
|
33
|
+
langgraph_api/js/package.json,sha256=uA_2KV86yMJmqfQd9Xe4w2PPjH6DmttBpSxi1PlSq3U,1224
|
|
34
|
+
langgraph_api/js/remote.py,sha256=jtzzkCBZ6eUE8g1JCn1lguaKF1RkpUmKbdblI6-NWgQ,24607
|
|
36
35
|
langgraph_api/js/schema.py,sha256=7idnv7URlYUdSNMBXQcw7E4SxaPxCq_Oxwnlml8q5ik,408
|
|
37
|
-
langgraph_api/js/src/graph.mts,sha256=
|
|
36
|
+
langgraph_api/js/src/graph.mts,sha256=otgztTNzNJpeF2IOrpNuuwbSbpAy4eFE5dHtUd7eQwU,3742
|
|
38
37
|
langgraph_api/js/src/hooks.mjs,sha256=XtktgmIHlls_DsknAuwib-z7TqCm0haRoTXvnkgzMuo,601
|
|
39
38
|
langgraph_api/js/src/parser/parser.mts,sha256=c7WLEtMMwtVzir9O8VpJFVHKuLjtI86rde-In2lvaM0,13217
|
|
40
39
|
langgraph_api/js/src/parser/parser.worker.mjs,sha256=2K6D0GlUmkk7LE39I8mryB8VZVE3-N9Cblji-ArPhFo,386
|
|
@@ -44,22 +43,23 @@ langgraph_api/js/src/utils/importMap.mts,sha256=pX4TGOyUpuuWF82kXcxcv3-8mgusRezO
|
|
|
44
43
|
langgraph_api/js/src/utils/pythonSchemas.mts,sha256=98IW7Z_VP7L_CHNRMb3_MsiV3BgLE2JsWQY_PQcRR3o,685
|
|
45
44
|
langgraph_api/js/src/utils/serde.mts,sha256=OuyyO9btvwWd55rU_H4x91dFEJiaPxL-lL9O6Zgo908,742
|
|
46
45
|
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=
|
|
46
|
+
langgraph_api/js/tests/api.test.mts,sha256=GlCTOTuSGc2m2vdsw6PSZrDPgfcvJi0A5v4A9xGaZi4,60004
|
|
47
|
+
langgraph_api/js/tests/compose-postgres.yml,sha256=pV1dW6aCgTTJ1WHSDeCqlVgFE9PbyWW5WbwrsiJcgoA,1772
|
|
49
48
|
langgraph_api/js/tests/graphs/.gitignore,sha256=26J8MarZNXh7snXD5eTpV3CPFTht5Znv8dtHYCLNfkw,12
|
|
50
49
|
langgraph_api/js/tests/graphs/agent.css,sha256=QgcOC0W7IBsrg4pSqqpull-WTgtULZfx_lF_5ZxLdag,23
|
|
51
50
|
langgraph_api/js/tests/graphs/agent.mts,sha256=E9WMv0alMv0njUEECqEsqoRk9NXJUgXW7SyQJ3GOZ8k,5396
|
|
52
51
|
langgraph_api/js/tests/graphs/agent.ui.tsx,sha256=JDFJdpdIS6rglkXTaROSb1Is0j1kt5wN9ML8W4cuht8,175
|
|
53
52
|
langgraph_api/js/tests/graphs/delay.mts,sha256=CFneKxqI4bGGK0lYjSbe80QirowPQlsRSuhDUKfydhk,703
|
|
53
|
+
langgraph_api/js/tests/graphs/dynamic.mts,sha256=Wf_-keF7lkEfp_iyI45nlFGCeU8ARLQ8axc0LXh7TyE,659
|
|
54
54
|
langgraph_api/js/tests/graphs/error.mts,sha256=l4tk89449dj1BnEF_0ZcfPt0Ikk1gl8L1RaSnRfr3xo,487
|
|
55
|
-
langgraph_api/js/tests/graphs/langgraph.json,sha256=
|
|
55
|
+
langgraph_api/js/tests/graphs/langgraph.json,sha256=iZL7XpAy3-QnCUHCRSj__Fxp3A-JPuYBJ_XQIxeyQfU,227
|
|
56
56
|
langgraph_api/js/tests/graphs/nested.mts,sha256=4G7jSOSaFVQAza-_ARbK-Iai1biLlF2DIPDZXf7PLIY,1245
|
|
57
57
|
langgraph_api/js/tests/graphs/package.json,sha256=Kv2kdlTNeWl00vYQAhngorQ6rLab4SMc7g1AgZslrHQ,118
|
|
58
58
|
langgraph_api/js/tests/graphs/weather.mts,sha256=A7mLK3xW8h5B-ZyJNAyX2M2fJJwzPJzXs4DYesJwreQ,1655
|
|
59
59
|
langgraph_api/js/tests/graphs/yarn.lock,sha256=i2AAIgXA3XBLM8-oU45wgUefCSG-Tne4ghWHmUCUKVk,10407
|
|
60
60
|
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=
|
|
61
|
+
langgraph_api/js/tests/utils.mts,sha256=q1V9gvT63v95onlfK9W4iv3n9ZJO3h-0RD9TdDYuRyY,439
|
|
62
|
+
langgraph_api/js/yarn.lock,sha256=JtMDtRVX9kr9lK0rbWRQsGHYbkQSmzNa4NwTunBv58U,82773
|
|
63
63
|
langgraph_api/lifespan.py,sha256=0F4Xn6IC4wUfvBWbm6KCJ-jiF0S7iWDOHJYJZ-A3o3s,2739
|
|
64
64
|
langgraph_api/logging.py,sha256=JJIzbNIgLCN6ClQ3tA-Mm5ffuBGvpRDSZsEvnIlsuu4,3693
|
|
65
65
|
langgraph_api/metadata.py,sha256=5Mu3MUtUc-iIocU3X2SZDoGIqnUmTdT3517MhP94npI,3495
|
|
@@ -81,23 +81,21 @@ langgraph_api/thread_ttl.py,sha256=ubkWMymTR7p9nGWd60-WKEOQ20ZgIkWB6WGstQUmRS4,1
|
|
|
81
81
|
langgraph_api/utils.py,sha256=92mSti9GfGdMRRWyESKQW5yV-75Z9icGHnIrBYvdypU,3619
|
|
82
82
|
langgraph_api/validation.py,sha256=Qo3EkSRXzIRe3GRuqRWbElTcUXRMXMyA1w0VbMvdwME,4934
|
|
83
83
|
langgraph_api/webhook.py,sha256=1ncwO0rIZcj-Df9sxSnFEzd1gP1bfS4okeZQS8NSRoE,1382
|
|
84
|
-
langgraph_api/worker.py,sha256=
|
|
84
|
+
langgraph_api/worker.py,sha256=CLmohk3B03OTsKHq_ZPhujMHFSuc694qeEL4VNSxHvg,12679
|
|
85
85
|
langgraph_license/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
86
86
|
langgraph_license/middleware.py,sha256=_ODIYzQkymr6W9_Fp9wtf1kAQspnpsmr53xuzyF2GA0,612
|
|
87
87
|
langgraph_license/validation.py,sha256=Uu_G8UGO_WTlLsBEY0gTVWjRR4czYGfw5YAD3HLZoj0,203
|
|
88
88
|
langgraph_storage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
89
89
|
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=
|
|
90
|
+
langgraph_storage/database.py,sha256=ys2glLtQaspfIY-_EgqEOT3b7a5WqBwuE_9I5VAh6FM,5821
|
|
91
|
+
langgraph_storage/inmem_stream.py,sha256=LjJSAxsh_E0ywqEMzdWJk8Hy_Jn9oQByzycss-fANng,3264
|
|
92
|
+
langgraph_storage/ops.py,sha256=6NxeirfuDAKghHc328zejnbTsijg6U80Rlt5rXTC2dc,75392
|
|
93
|
+
langgraph_storage/queue.py,sha256=wyBcY1V_8zah0Z2e5hpovs_dsIPPPfUJQCly2rxFWvo,7039
|
|
94
94
|
langgraph_storage/retry.py,sha256=XmldOP4e_H5s264CagJRVnQMDFcEJR_dldVR1Hm5XvM,763
|
|
95
95
|
langgraph_storage/store.py,sha256=JB9jZ87GE19MVN9wgl3-esgR2eIkeipws9q6qsPWkgc,3399
|
|
96
96
|
langgraph_storage/ttl_dict.py,sha256=FlpEY8EANeXWKo_G5nmIotPquABZGyIJyk6HD9u6vqY,1533
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
langgraph_api-0.0.
|
|
100
|
-
langgraph_api-0.0.
|
|
101
|
-
langgraph_api-0.0.
|
|
102
|
-
langgraph_api-0.0.38.dist-info/entry_points.txt,sha256=3EYLgj89DfzqJHHYGxPH4A_fEtClvlRbWRUHaXO7hj4,77
|
|
103
|
-
langgraph_api-0.0.38.dist-info/RECORD,,
|
|
97
|
+
langgraph_api-0.0.39.dist-info/LICENSE,sha256=ZPwVR73Biwm3sK6vR54djCrhaRiM4cAD2zvOQZV8Xis,3859
|
|
98
|
+
langgraph_api-0.0.39.dist-info/METADATA,sha256=ufXqimdc10omEJG86RkMEqL9ZhwNpnPHxTxRj5T6bi0,4167
|
|
99
|
+
langgraph_api-0.0.39.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
|
|
100
|
+
langgraph_api-0.0.39.dist-info/entry_points.txt,sha256=3EYLgj89DfzqJHHYGxPH4A_fEtClvlRbWRUHaXO7hj4,77
|
|
101
|
+
langgraph_api-0.0.39.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
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
Elastic License 2.0
|
|
2
|
-
|
|
3
|
-
URL: https://www.elastic.co/licensing/elastic-license
|
|
4
|
-
|
|
5
|
-
## Acceptance
|
|
6
|
-
|
|
7
|
-
By using the software, you agree to all of the terms and conditions below.
|
|
8
|
-
|
|
9
|
-
## Copyright License
|
|
10
|
-
|
|
11
|
-
The licensor grants you a non-exclusive, royalty-free, worldwide,
|
|
12
|
-
non-sublicensable, non-transferable license to use, copy, distribute, make
|
|
13
|
-
available, and prepare derivative works of the software, in each case subject to
|
|
14
|
-
the limitations and conditions below.
|
|
15
|
-
|
|
16
|
-
## Limitations
|
|
17
|
-
|
|
18
|
-
You may not provide the software to third parties as a hosted or managed
|
|
19
|
-
service, where the service provides users with access to any substantial set of
|
|
20
|
-
the features or functionality of the software.
|
|
21
|
-
|
|
22
|
-
You may not move, change, disable, or circumvent the license key functionality
|
|
23
|
-
in the software, and you may not remove or obscure any functionality in the
|
|
24
|
-
software that is protected by the license key.
|
|
25
|
-
|
|
26
|
-
You may not alter, remove, or obscure any licensing, copyright, or other notices
|
|
27
|
-
of the licensor in the software. Any use of the licensor’s trademarks is subject
|
|
28
|
-
to applicable law.
|
|
29
|
-
|
|
30
|
-
## Patents
|
|
31
|
-
|
|
32
|
-
The licensor grants you a license, under any patent claims the licensor can
|
|
33
|
-
license, or becomes able to license, to make, have made, use, sell, offer for
|
|
34
|
-
sale, import and have imported the software, in each case subject to the
|
|
35
|
-
limitations and conditions in this license. This license does not cover any
|
|
36
|
-
patent claims that you cause to be infringed by modifications or additions to
|
|
37
|
-
the software. If you or your company make any written claim that the software
|
|
38
|
-
infringes or contributes to infringement of any patent, your patent license for
|
|
39
|
-
the software granted under these terms ends immediately. If your company makes
|
|
40
|
-
such a claim, your patent license ends immediately for work on behalf of your
|
|
41
|
-
company.
|
|
42
|
-
|
|
43
|
-
## Notices
|
|
44
|
-
|
|
45
|
-
You must ensure that anyone who gets a copy of any part of the software from you
|
|
46
|
-
also gets a copy of these terms.
|
|
47
|
-
|
|
48
|
-
If you modify the software, you must include in any modified copies of the
|
|
49
|
-
software prominent notices stating that you have modified the software.
|
|
50
|
-
|
|
51
|
-
## No Other Rights
|
|
52
|
-
|
|
53
|
-
These terms do not imply any licenses other than those expressly granted in
|
|
54
|
-
these terms.
|
|
55
|
-
|
|
56
|
-
## Termination
|
|
57
|
-
|
|
58
|
-
If you use the software in violation of these terms, such use is not licensed,
|
|
59
|
-
and your licenses will automatically terminate. If the licensor provides you
|
|
60
|
-
with a notice of your violation, and you cease all violation of this license no
|
|
61
|
-
later than 30 days after you receive that notice, your licenses will be
|
|
62
|
-
reinstated retroactively. However, if you violate these terms after such
|
|
63
|
-
reinstatement, any additional violation of these terms will cause your licenses
|
|
64
|
-
to terminate automatically and permanently.
|
|
65
|
-
|
|
66
|
-
## No Liability
|
|
67
|
-
|
|
68
|
-
*As far as the law allows, the software comes as is, without any warranty or
|
|
69
|
-
condition, and the licensor will not be liable to you for any damages arising
|
|
70
|
-
out of these terms or the use or nature of the software, under any kind of
|
|
71
|
-
legal claim.*
|
|
72
|
-
|
|
73
|
-
## Definitions
|
|
74
|
-
|
|
75
|
-
The **licensor** is the entity offering these terms, and the **software** is the
|
|
76
|
-
software the licensor makes available under these terms, including any portion
|
|
77
|
-
of it.
|
|
78
|
-
|
|
79
|
-
**you** refers to the individual or entity agreeing to these terms.
|
|
80
|
-
|
|
81
|
-
**your company** is any legal entity, sole proprietorship, or other kind of
|
|
82
|
-
organization that you work for, plus all organizations that have control over,
|
|
83
|
-
are under the control of, or are under common control with that
|
|
84
|
-
organization. **control** means ownership of substantially all the assets of an
|
|
85
|
-
entity, or the power to direct its management and policies by vote, contract, or
|
|
86
|
-
otherwise. Control can be direct or indirect.
|
|
87
|
-
|
|
88
|
-
**your licenses** are all the licenses granted to you for the software under
|
|
89
|
-
these terms.
|
|
90
|
-
|
|
91
|
-
**use** means anything you do with the software requiring one of your licenses.
|
|
92
|
-
|
|
93
|
-
**trademark** means trademarks, service marks, and similar rights.
|
logging.json
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 1,
|
|
3
|
-
"incremental": false,
|
|
4
|
-
"disable_existing_loggers": false,
|
|
5
|
-
"formatters": {
|
|
6
|
-
"simple": {
|
|
7
|
-
"class": "langgraph_api.logging.Formatter"
|
|
8
|
-
}
|
|
9
|
-
},
|
|
10
|
-
"handlers": {
|
|
11
|
-
"console": {
|
|
12
|
-
"class": "logging.StreamHandler",
|
|
13
|
-
"formatter": "simple",
|
|
14
|
-
"stream": "ext://sys.stdout"
|
|
15
|
-
}
|
|
16
|
-
},
|
|
17
|
-
"root": {
|
|
18
|
-
"handlers": [
|
|
19
|
-
"console"
|
|
20
|
-
]
|
|
21
|
-
}
|
|
22
|
-
}
|