langgraph-api 0.3.4__py3-none-any.whl → 0.4.1__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.
- langgraph_api/__init__.py +1 -1
- langgraph_api/api/runs.py +13 -8
- langgraph_api/api/threads.py +24 -0
- langgraph_api/js/isolate-0x130008000-46649-46649-v8.log +4430 -0
- langgraph_api/js/isolate-0x138008000-44681-44681-v8.log +4430 -0
- langgraph_api/js/package-lock.json +3308 -0
- langgraph_api/models/run.py +5 -4
- langgraph_api/stream.py +6 -2
- langgraph_api/utils/__init__.py +19 -0
- langgraph_api/worker.py +4 -2
- {langgraph_api-0.3.4.dist-info → langgraph_api-0.4.1.dist-info}/METADATA +2 -2
- {langgraph_api-0.3.4.dist-info → langgraph_api-0.4.1.dist-info}/RECORD +16 -13
- openapi.json +67 -0
- {langgraph_api-0.3.4.dist-info → langgraph_api-0.4.1.dist-info}/WHEEL +0 -0
- {langgraph_api-0.3.4.dist-info → langgraph_api-0.4.1.dist-info}/entry_points.txt +0 -0
- {langgraph_api-0.3.4.dist-info → langgraph_api-0.4.1.dist-info}/licenses/LICENSE +0 -0
langgraph_api/models/run.py
CHANGED
|
@@ -249,6 +249,7 @@ async def create_valid_run(
|
|
|
249
249
|
barrier: asyncio.Barrier | None = None,
|
|
250
250
|
run_id: UUID | None = None,
|
|
251
251
|
request_start_time: float | None = None,
|
|
252
|
+
temporary: bool = False,
|
|
252
253
|
) -> Run:
|
|
253
254
|
request_id = headers.get("x-request-id") # Will be null in the crons scheduler.
|
|
254
255
|
(
|
|
@@ -262,7 +263,7 @@ async def create_valid_run(
|
|
|
262
263
|
run_id=run_id,
|
|
263
264
|
)
|
|
264
265
|
if (
|
|
265
|
-
thread_id_ is None
|
|
266
|
+
(thread_id_ is None or temporary)
|
|
266
267
|
and (command := payload.get("command"))
|
|
267
268
|
and command.get("resume")
|
|
268
269
|
):
|
|
@@ -270,9 +271,9 @@ async def create_valid_run(
|
|
|
270
271
|
status_code=400,
|
|
271
272
|
detail="You must provide a thread_id when resuming.",
|
|
272
273
|
)
|
|
273
|
-
temporary = (
|
|
274
|
-
|
|
275
|
-
)
|
|
274
|
+
temporary = (temporary or thread_id_ is None) and payload.get(
|
|
275
|
+
"on_completion", "delete"
|
|
276
|
+
) == "delete"
|
|
276
277
|
stream_resumable = payload.get("stream_resumable", False)
|
|
277
278
|
stream_mode, multitask_strategy, prevent_insert_if_inflight = assign_defaults(
|
|
278
279
|
payload
|
langgraph_api/stream.py
CHANGED
|
@@ -2,7 +2,7 @@ import uuid
|
|
|
2
2
|
from collections.abc import AsyncIterator, Callable
|
|
3
3
|
from contextlib import AsyncExitStack, aclosing, asynccontextmanager
|
|
4
4
|
from functools import lru_cache
|
|
5
|
-
from typing import Any,
|
|
5
|
+
from typing import Any, cast
|
|
6
6
|
|
|
7
7
|
import langgraph.version
|
|
8
8
|
import langsmith
|
|
@@ -423,7 +423,9 @@ async def consume(
|
|
|
423
423
|
stream: AnyStream,
|
|
424
424
|
run_id: str | uuid.UUID,
|
|
425
425
|
resumable: bool = False,
|
|
426
|
-
stream_modes: set[StreamMode
|
|
426
|
+
stream_modes: set[StreamMode] | None = None,
|
|
427
|
+
*,
|
|
428
|
+
thread_id: str | uuid.UUID | None = None,
|
|
427
429
|
) -> None:
|
|
428
430
|
stream_modes = stream_modes or set()
|
|
429
431
|
if "messages-tuple" in stream_modes:
|
|
@@ -437,6 +439,7 @@ async def consume(
|
|
|
437
439
|
run_id,
|
|
438
440
|
mode,
|
|
439
441
|
await run_in_executor(None, json_dumpb, payload),
|
|
442
|
+
thread_id=thread_id,
|
|
440
443
|
resumable=resumable and mode.split("|")[0] in stream_modes,
|
|
441
444
|
)
|
|
442
445
|
except Exception as e:
|
|
@@ -446,6 +449,7 @@ async def consume(
|
|
|
446
449
|
run_id,
|
|
447
450
|
"error",
|
|
448
451
|
await run_in_executor(None, json_dumpb, e),
|
|
452
|
+
thread_id=thread_id,
|
|
449
453
|
)
|
|
450
454
|
raise e
|
|
451
455
|
|
langgraph_api/utils/__init__.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import contextvars
|
|
2
|
+
import re
|
|
2
3
|
import uuid
|
|
3
4
|
from collections.abc import AsyncIterator
|
|
4
5
|
from contextlib import asynccontextmanager
|
|
@@ -22,6 +23,7 @@ Row: TypeAlias = dict[str, Any]
|
|
|
22
23
|
AuthContext = contextvars.ContextVar[Auth.types.BaseAuthContext | None](
|
|
23
24
|
"AuthContext", default=None
|
|
24
25
|
)
|
|
26
|
+
STREAM_ID_PATTERN = re.compile(r"^\d+(-(\d+|\*))?$")
|
|
25
27
|
|
|
26
28
|
|
|
27
29
|
@asynccontextmanager
|
|
@@ -101,6 +103,23 @@ def validate_uuid(uuid_str: str, invalid_uuid_detail: str | None) -> uuid.UUID:
|
|
|
101
103
|
raise HTTPException(status_code=422, detail=invalid_uuid_detail) from None
|
|
102
104
|
|
|
103
105
|
|
|
106
|
+
def validate_stream_id(stream_id: str | None, invalid_stream_id_detail: str | None):
|
|
107
|
+
"""
|
|
108
|
+
Validate Redis stream ID format.
|
|
109
|
+
Valid formats:
|
|
110
|
+
- timestamp-sequence (e.g., "1724342400000-0")
|
|
111
|
+
- timestamp-* (e.g., "1724342400000-*")
|
|
112
|
+
- timestamp only (e.g., "1724342400000")
|
|
113
|
+
- "-" (special case, represents the beginning of the stream, use if you want to replay all events)
|
|
114
|
+
"""
|
|
115
|
+
if not stream_id or stream_id == "-":
|
|
116
|
+
return stream_id
|
|
117
|
+
|
|
118
|
+
if STREAM_ID_PATTERN.match(stream_id):
|
|
119
|
+
return stream_id
|
|
120
|
+
raise HTTPException(status_code=422, detail=invalid_stream_id_detail)
|
|
121
|
+
|
|
122
|
+
|
|
104
123
|
def next_cron_date(schedule: str, base_time: datetime) -> datetime:
|
|
105
124
|
import croniter # type: ignore[unresolved-import]
|
|
106
125
|
|
langgraph_api/worker.py
CHANGED
|
@@ -139,7 +139,9 @@ async def worker(
|
|
|
139
139
|
stream_modes: set[StreamMode],
|
|
140
140
|
):
|
|
141
141
|
try:
|
|
142
|
-
await consume(
|
|
142
|
+
await consume(
|
|
143
|
+
stream, run_id, resumable, stream_modes, thread_id=run["thread_id"]
|
|
144
|
+
)
|
|
143
145
|
except Exception as e:
|
|
144
146
|
if not isinstance(e, UserRollback | UserInterrupt):
|
|
145
147
|
logger.exception(
|
|
@@ -151,7 +153,7 @@ async def worker(
|
|
|
151
153
|
raise UserTimeout(e) from e
|
|
152
154
|
raise
|
|
153
155
|
|
|
154
|
-
async with Runs.enter(run_id, main_loop) as done:
|
|
156
|
+
async with Runs.enter(run_id, run["thread_id"], main_loop) as done:
|
|
155
157
|
# attempt the run
|
|
156
158
|
try:
|
|
157
159
|
if attempt > BG_JOB_MAX_RETRIES:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: langgraph-api
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.1
|
|
4
4
|
Author-email: Nuno Campos <nuno@langchain.dev>, Will Fu-Hinthorn <will@langchain.dev>
|
|
5
5
|
License: Elastic-2.0
|
|
6
6
|
License-File: LICENSE
|
|
@@ -11,7 +11,7 @@ Requires-Dist: httpx>=0.25.0
|
|
|
11
11
|
Requires-Dist: jsonschema-rs<0.30,>=0.20.0
|
|
12
12
|
Requires-Dist: langchain-core>=0.3.64
|
|
13
13
|
Requires-Dist: langgraph-checkpoint>=2.0.23
|
|
14
|
-
Requires-Dist: langgraph-runtime-inmem<0.
|
|
14
|
+
Requires-Dist: langgraph-runtime-inmem<0.10.0,>=0.9.0
|
|
15
15
|
Requires-Dist: langgraph-sdk>=0.2.0
|
|
16
16
|
Requires-Dist: langgraph>=0.4.0
|
|
17
17
|
Requires-Dist: langsmith>=0.3.45
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
langgraph_api/__init__.py,sha256=
|
|
1
|
+
langgraph_api/__init__.py,sha256=pMtTmSUht-XtbR_7Doz6bsQqopJJd8rZ8I8zy2HwwoA,22
|
|
2
2
|
langgraph_api/asgi_transport.py,sha256=XtiLOu4WWsd-xizagBLzT5xUkxc9ZG9YqwvETBPjBFE,5161
|
|
3
3
|
langgraph_api/asyncio.py,sha256=mZ7G32JjrGxrlH4OMy7AKlBQo5bZt4Sm2rlrBcU-Vj8,9483
|
|
4
4
|
langgraph_api/cli.py,sha256=-ruIeKi1imvS6GriOfRDZY-waV4SbWiJ0BEFAciPVYI,16330
|
|
@@ -22,21 +22,21 @@ langgraph_api/server.py,sha256=uCAqPgCLJ6ckslLs0i_dacSR8mzuR0Y6PkkJYk0O3bE,7196
|
|
|
22
22
|
langgraph_api/sse.py,sha256=SLdtZmTdh5D8fbWrQjuY9HYLd2dg8Rmi6ZMmFMVc2iE,4204
|
|
23
23
|
langgraph_api/state.py,sha256=5RTOShiFVnkx-o6t99_x63CGwXw_8Eb-dSTpYirP8ro,4683
|
|
24
24
|
langgraph_api/store.py,sha256=NIoNZojs6NbtG3VLBPQEFNttvp7XPkHAfjbQ3gY7aLY,4701
|
|
25
|
-
langgraph_api/stream.py,sha256=
|
|
25
|
+
langgraph_api/stream.py,sha256=IpGW9vpknI_wWteEmZfQKqCYqbaJAzOpq0FgdFJP60s,18528
|
|
26
26
|
langgraph_api/thread_ttl.py,sha256=7H3gFlWcUiODPoaEzcwB0LR61uvcuyjD0ew_4BztB7k,1902
|
|
27
27
|
langgraph_api/traceblock.py,sha256=Qq5CUdefnMDaRDnyvBSWGBClEj-f3oO7NbH6fedxOSE,630
|
|
28
28
|
langgraph_api/utils.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
29
29
|
langgraph_api/validation.py,sha256=86jftgOsMa7tkeshBw6imYe7zyUXPoVuf5Voh6dFiR8,5285
|
|
30
30
|
langgraph_api/webhook.py,sha256=SvSM1rdnNtiH4q3JQYmAqJUk2Sable5xAcwOLuRhtlo,1723
|
|
31
|
-
langgraph_api/worker.py,sha256=
|
|
31
|
+
langgraph_api/worker.py,sha256=M9WQdxEzVGDZqdjz3LHEHhM1g6isPcf3k1V4PEkcSY8,15343
|
|
32
32
|
langgraph_api/api/__init__.py,sha256=WHy6oNLWtH1K7AxmmsU9RD-Vm6WP-Ov16xS8Ey9YCmQ,6090
|
|
33
33
|
langgraph_api/api/assistants.py,sha256=5gVvU58Y1-EftBhCHGbEaOi_7cqGMKWhOt_GVfBC0Gg,16836
|
|
34
34
|
langgraph_api/api/mcp.py,sha256=qe10ZRMN3f-Hli-9TI8nbQyWvMeBb72YB1PZVbyqBQw,14418
|
|
35
35
|
langgraph_api/api/meta.py,sha256=dFD9ZgykbKARLdVSaJD9vO3CShvEyBmGpkjE8tqii0c,4448
|
|
36
36
|
langgraph_api/api/openapi.py,sha256=If-z1ckXt-Yu5bwQytK1LWyX_T7G46UtLfixgEP8hwc,11959
|
|
37
|
-
langgraph_api/api/runs.py,sha256=
|
|
37
|
+
langgraph_api/api/runs.py,sha256=1RlD4WA8auCNugFjJSgaM9WPnwEHeWsJLEuKpwSRqcU,22089
|
|
38
38
|
langgraph_api/api/store.py,sha256=xGcPFx4v-VxlK6HRU9uCjzCQ0v66cvc3o_PB5_g7n0Q,5550
|
|
39
|
-
langgraph_api/api/threads.py,sha256=
|
|
39
|
+
langgraph_api/api/threads.py,sha256=xjeA6eUp4r19YYvqkfe8c3b_u4yIg6jvjq-EmlGu1kI,11150
|
|
40
40
|
langgraph_api/api/ui.py,sha256=_genglTUy5BMHlL0lkQypX524yFv6Z5fraIvnrxp7yE,2639
|
|
41
41
|
langgraph_api/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
42
42
|
langgraph_api/auth/custom.py,sha256=psETw_GpLWClBbd_ESVPRLUz9GLQ0_XNsuUDSVbtZy0,22522
|
|
@@ -55,6 +55,9 @@ langgraph_api/js/client.http.mts,sha256=cvn8JV9go4pUMWkcug8FfSYWsp1wTaT8SgJaskqE
|
|
|
55
55
|
langgraph_api/js/client.mts,sha256=gDvYiW7Qfl4re2YhZ5oNqtuvffnW_Sf7DK5aUbKB3vw,32330
|
|
56
56
|
langgraph_api/js/errors.py,sha256=Cm1TKWlUCwZReDC5AQ6SgNIVGD27Qov2xcgHyf8-GXo,361
|
|
57
57
|
langgraph_api/js/global.d.ts,sha256=j4GhgtQSZ5_cHzjSPcHgMJ8tfBThxrH-pUOrrJGteOU,196
|
|
58
|
+
langgraph_api/js/isolate-0x130008000-46649-46649-v8.log,sha256=s6h4v7ZtOBK9tKJ0zzPojnob7MBV2j-nyLVPGbgotdg,2641826
|
|
59
|
+
langgraph_api/js/isolate-0x138008000-44681-44681-v8.log,sha256=knAbmQTmz2umDoqMXKuThsmgc4Q6b1HBwZ2ZFUcFu40,2644591
|
|
60
|
+
langgraph_api/js/package-lock.json,sha256=bGM4LYdWJxAb5JE6Tap1-WA_IqRE_CzBjxZTCcMt1_U,117589
|
|
58
61
|
langgraph_api/js/package.json,sha256=syy2fEcmTxGQVfz4P9MUTgoTxHr1MUcA1rDXemAig2U,1335
|
|
59
62
|
langgraph_api/js/remote.py,sha256=aeszJ0HGbcL9oExyeWYHb0xLV75U3KgVSxjm3ZK_a48,38403
|
|
60
63
|
langgraph_api/js/schema.py,sha256=M4fLtr50O1jck8H1hm_0W4cZOGYGdkrB7riLyCes4oY,438
|
|
@@ -75,9 +78,9 @@ langgraph_api/middleware/http_logger.py,sha256=2LABfhzTAUtqT8nf1ACy8cYXteatkwraB
|
|
|
75
78
|
langgraph_api/middleware/private_network.py,sha256=eYgdyU8AzU2XJu362i1L8aSFoQRiV7_aLBPw7_EgeqI,2111
|
|
76
79
|
langgraph_api/middleware/request_id.py,sha256=SDj3Yi3WvTbFQ2ewrPQBjAV8sYReOJGeIiuoHeZpR9g,1242
|
|
77
80
|
langgraph_api/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
78
|
-
langgraph_api/models/run.py,sha256=
|
|
81
|
+
langgraph_api/models/run.py,sha256=jPGWcW9fd1KFoXZTSXMMvc0IiXDXk3yoZ5kjdqxZ1mg,15536
|
|
79
82
|
langgraph_api/tunneling/cloudflare.py,sha256=iKb6tj-VWPlDchHFjuQyep2Dpb-w2NGfJKt-WJG9LH0,3650
|
|
80
|
-
langgraph_api/utils/__init__.py,sha256=
|
|
83
|
+
langgraph_api/utils/__init__.py,sha256=yCMq7pOMlmeNmi2Fh8U7KLiljBdOMcF0L2SfpobnKKE,5703
|
|
81
84
|
langgraph_api/utils/cache.py,sha256=SrtIWYibbrNeZzLXLUGBFhJPkMVNQnVxR5giiYGHEfI,1810
|
|
82
85
|
langgraph_api/utils/config.py,sha256=Tbp4tKDSLKXQJ44EKr885wAQupY-9VWNJ6rgUU2oLOY,4162
|
|
83
86
|
langgraph_api/utils/future.py,sha256=lXsRQPhJwY7JUbFFZrK-94JjgsToLu-EWU896hvbUxE,7289
|
|
@@ -96,9 +99,9 @@ langgraph_runtime/retry.py,sha256=V0duD01fO7GUQ_btQkp1aoXcEOFhXooGVP6q4yMfuyY,11
|
|
|
96
99
|
langgraph_runtime/store.py,sha256=7mowndlsIroGHv3NpTSOZDJR0lCuaYMBoTnTrewjslw,114
|
|
97
100
|
LICENSE,sha256=ZPwVR73Biwm3sK6vR54djCrhaRiM4cAD2zvOQZV8Xis,3859
|
|
98
101
|
logging.json,sha256=3RNjSADZmDq38eHePMm1CbP6qZ71AmpBtLwCmKU9Zgo,379
|
|
99
|
-
openapi.json,sha256=
|
|
100
|
-
langgraph_api-0.
|
|
101
|
-
langgraph_api-0.
|
|
102
|
-
langgraph_api-0.
|
|
103
|
-
langgraph_api-0.
|
|
104
|
-
langgraph_api-0.
|
|
102
|
+
openapi.json,sha256=kT_Xi6PAI64jLUalbdh0TtIRy1PfqQBxSu-rbyo_ZyA,162474
|
|
103
|
+
langgraph_api-0.4.1.dist-info/METADATA,sha256=v2nNOyHqw8ReH5uNs_tQQeMgnMk969MloE1rsY9P_ow,3891
|
|
104
|
+
langgraph_api-0.4.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
105
|
+
langgraph_api-0.4.1.dist-info/entry_points.txt,sha256=hGedv8n7cgi41PypMfinwS_HfCwA7xJIfS0jAp8htV8,78
|
|
106
|
+
langgraph_api-0.4.1.dist-info/licenses/LICENSE,sha256=ZPwVR73Biwm3sK6vR54djCrhaRiM4cAD2zvOQZV8Xis,3859
|
|
107
|
+
langgraph_api-0.4.1.dist-info/RECORD,,
|
openapi.json
CHANGED
|
@@ -1520,6 +1520,73 @@
|
|
|
1520
1520
|
}
|
|
1521
1521
|
}
|
|
1522
1522
|
},
|
|
1523
|
+
"/threads/{thread_id}/stream": {
|
|
1524
|
+
"get": {
|
|
1525
|
+
"tags": [
|
|
1526
|
+
"Threads"
|
|
1527
|
+
],
|
|
1528
|
+
"summary": "Join Thread Stream",
|
|
1529
|
+
"description": "This endpoint streams output in real-time from a thread. The stream will include the output of each run executed sequentially on the thread and will remain open indefinitely. It is the responsibility of the calling client to close the connection.",
|
|
1530
|
+
"operationId": "join_thread_stream_threads__thread_id__stream_get",
|
|
1531
|
+
"parameters": [
|
|
1532
|
+
{
|
|
1533
|
+
"description": "The ID of the thread.",
|
|
1534
|
+
"required": true,
|
|
1535
|
+
"schema": {
|
|
1536
|
+
"type": "string",
|
|
1537
|
+
"format": "uuid",
|
|
1538
|
+
"title": "Thread Id",
|
|
1539
|
+
"description": "The ID of the thread."
|
|
1540
|
+
},
|
|
1541
|
+
"name": "thread_id",
|
|
1542
|
+
"in": "path"
|
|
1543
|
+
},
|
|
1544
|
+
{
|
|
1545
|
+
"required": false,
|
|
1546
|
+
"schema": {
|
|
1547
|
+
"type": "string",
|
|
1548
|
+
"title": "Last Event ID",
|
|
1549
|
+
"description": "The ID of the last event received. Used to resume streaming from a specific point. Pass '-' to resume from the beginning."
|
|
1550
|
+
},
|
|
1551
|
+
"name": "Last-Event-ID",
|
|
1552
|
+
"in": "header"
|
|
1553
|
+
}
|
|
1554
|
+
],
|
|
1555
|
+
"responses": {
|
|
1556
|
+
"200": {
|
|
1557
|
+
"description": "Success",
|
|
1558
|
+
"content": {
|
|
1559
|
+
"text/event-stream": {
|
|
1560
|
+
"schema": {
|
|
1561
|
+
"type": "string",
|
|
1562
|
+
"description": "The server will send a stream of events in SSE format.\n\n**Example event**:\n\nid: 1\n\nevent: message\n\ndata: {}"
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
},
|
|
1567
|
+
"404": {
|
|
1568
|
+
"description": "Not Found",
|
|
1569
|
+
"content": {
|
|
1570
|
+
"application/json": {
|
|
1571
|
+
"schema": {
|
|
1572
|
+
"$ref": "#/components/schemas/ErrorResponse"
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1575
|
+
}
|
|
1576
|
+
},
|
|
1577
|
+
"422": {
|
|
1578
|
+
"description": "Validation Error",
|
|
1579
|
+
"content": {
|
|
1580
|
+
"application/json": {
|
|
1581
|
+
"schema": {
|
|
1582
|
+
"$ref": "#/components/schemas/ErrorResponse"
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
},
|
|
1523
1590
|
"/threads/{thread_id}/runs": {
|
|
1524
1591
|
"get": {
|
|
1525
1592
|
"tags": [
|
|
File without changes
|
|
File without changes
|
|
File without changes
|