langgraph-api 0.2.32__tar.gz → 0.2.35__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.
Potentially problematic release.
This version of langgraph-api might be problematic. Click here for more details.
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/Makefile +3 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/PKG-INFO +2 -2
- langgraph_api-0.2.35/langgraph_api/__init__.py +1 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/api/meta.py +2 -2
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/api/runs.py +29 -9
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/graph.py +7 -7
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/js/package.json +1 -1
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/js/yarn.lock +4 -4
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/models/run.py +3 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/sse.py +12 -4
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/stream.py +10 -3
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/worker.py +5 -2
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/openapi.json +129 -59
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/pyproject.toml +1 -1
- langgraph_api-0.2.32/langgraph_api/__init__.py +0 -1
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/.gitignore +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/LICENSE +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/README.md +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/benchmark/weather.js +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/constraints.txt +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/forbidden.txt +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/healthcheck.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/api/__init__.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/api/assistants.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/api/mcp.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/api/openapi.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/api/store.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/api/threads.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/api/ui.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/asgi_transport.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/asyncio.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/auth/__init__.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/auth/custom.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/auth/langsmith/__init__.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/auth/langsmith/backend.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/auth/langsmith/client.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/auth/middleware.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/auth/noop.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/auth/studio_user.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/cli.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/command.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/config.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/cron_scheduler.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/errors.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/http.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/js/.gitignore +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/js/.prettierrc +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/js/__init__.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/js/base.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/js/build.mts +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/js/client.http.mts +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/js/client.mts +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/js/errors.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/js/global.d.ts +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/js/remote.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/js/schema.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/js/src/graph.mts +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/js/src/load.hooks.mjs +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/js/src/preload.mjs +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/js/src/utils/files.mts +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/js/src/utils/importMap.mts +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/js/src/utils/pythonSchemas.mts +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/js/src/utils/serde.mts +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/js/sse.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/js/tsconfig.json +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/js/ui.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/logging.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/metadata.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/middleware/__init__.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/middleware/http_logger.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/middleware/private_network.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/middleware/request_id.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/models/__init__.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/patch.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/queue_entrypoint.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/route.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/schema.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/serde.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/server.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/state.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/store.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/thread_ttl.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/tunneling/cloudflare.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/utils.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/validation.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_api/webhook.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_license/__init__.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_license/validation.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/langgraph_runtime/__init__.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/logging.json +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/scripts/create_license.py +0 -0
- {langgraph_api-0.2.32 → langgraph_api-0.2.35}/uv.lock +0 -0
|
@@ -67,6 +67,7 @@ start:
|
|
|
67
67
|
--reload \
|
|
68
68
|
--port 9123 \
|
|
69
69
|
--reload-dir langgraph_api \
|
|
70
|
+
--reload-dir ../runtime_inmem \
|
|
70
71
|
--no-access-log
|
|
71
72
|
|
|
72
73
|
|
|
@@ -89,6 +90,7 @@ start-auth-jwt:
|
|
|
89
90
|
--reload \
|
|
90
91
|
--port 9123 \
|
|
91
92
|
--reload-dir langgraph_api \
|
|
93
|
+
--reload-dir ../runtime_inmem \
|
|
92
94
|
--no-access-log
|
|
93
95
|
|
|
94
96
|
start-auth-fastapi-jwt:
|
|
@@ -106,6 +108,7 @@ start-auth-fastapi-jwt:
|
|
|
106
108
|
--reload \
|
|
107
109
|
--port 9123 \
|
|
108
110
|
--reload-dir langgraph_api \
|
|
111
|
+
--reload-dir ../runtime_inmem \
|
|
109
112
|
--no-access-log
|
|
110
113
|
|
|
111
114
|
VERSION_KIND ?= patch
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: langgraph-api
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.35
|
|
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.2.38
|
|
13
13
|
Requires-Dist: langgraph-checkpoint>=2.0.23
|
|
14
|
-
Requires-Dist: langgraph-runtime-inmem<0.
|
|
14
|
+
Requires-Dist: langgraph-runtime-inmem<0.3,>=0.2.0
|
|
15
15
|
Requires-Dist: langgraph-sdk>=0.1.66
|
|
16
16
|
Requires-Dist: langgraph>=0.3.27
|
|
17
17
|
Requires-Dist: langsmith>=0.1.112
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.2.35"
|
|
@@ -54,10 +54,10 @@ async def meta_metrics(request: ApiRequest):
|
|
|
54
54
|
}
|
|
55
55
|
)
|
|
56
56
|
elif format == "prometheus":
|
|
57
|
-
# LANGSMITH_HOST_PROJECT_ID and
|
|
57
|
+
# LANGSMITH_HOST_PROJECT_ID and LANGSMITH_HOST_REVISION_ID are injected
|
|
58
58
|
# into the deployed image by host-backend.
|
|
59
59
|
project_id = os.getenv("LANGSMITH_HOST_PROJECT_ID")
|
|
60
|
-
revision_id = os.getenv("
|
|
60
|
+
revision_id = os.getenv("LANGSMITH_HOST_REVISION_ID")
|
|
61
61
|
|
|
62
62
|
metrics = [
|
|
63
63
|
"# HELP lg_api_workers_max The maximum number of workers available.",
|
|
@@ -39,7 +39,10 @@ async def create_run(request: ApiRequest):
|
|
|
39
39
|
payload,
|
|
40
40
|
request.headers,
|
|
41
41
|
)
|
|
42
|
-
return ApiResponse(
|
|
42
|
+
return ApiResponse(
|
|
43
|
+
run,
|
|
44
|
+
headers={"Content-Location": f"/threads/{thread_id}/runs/{run['run_id']}"},
|
|
45
|
+
)
|
|
43
46
|
|
|
44
47
|
|
|
45
48
|
@retry_db
|
|
@@ -53,7 +56,10 @@ async def create_stateless_run(request: ApiRequest):
|
|
|
53
56
|
payload,
|
|
54
57
|
request.headers,
|
|
55
58
|
)
|
|
56
|
-
return ApiResponse(
|
|
59
|
+
return ApiResponse(
|
|
60
|
+
run,
|
|
61
|
+
headers={"Content-Location": f"/runs/{run['run_id']}"},
|
|
62
|
+
)
|
|
57
63
|
|
|
58
64
|
|
|
59
65
|
async def create_stateless_run_batch(request: ApiRequest):
|
|
@@ -107,8 +113,12 @@ async def stream_run(
|
|
|
107
113
|
thread_id=thread_id,
|
|
108
114
|
cancel_on_disconnect=on_disconnect == "cancel",
|
|
109
115
|
stream_mode=await sub,
|
|
116
|
+
last_event_id=None,
|
|
110
117
|
),
|
|
111
|
-
headers={
|
|
118
|
+
headers={
|
|
119
|
+
"Location": f"/threads/{thread_id}/runs/{run['run_id']}/stream",
|
|
120
|
+
"Content-Location": f"/threads/{thread_id}/runs/{run['run_id']}",
|
|
121
|
+
},
|
|
112
122
|
)
|
|
113
123
|
|
|
114
124
|
|
|
@@ -143,9 +153,11 @@ async def stream_run_stateless(
|
|
|
143
153
|
ignore_404=True,
|
|
144
154
|
cancel_on_disconnect=on_disconnect == "cancel",
|
|
145
155
|
stream_mode=await sub,
|
|
156
|
+
last_event_id=None,
|
|
146
157
|
),
|
|
147
158
|
headers={
|
|
148
|
-
"Location": f"/
|
|
159
|
+
"Location": f"/runs/{run['run_id']}/stream",
|
|
160
|
+
"Content-Location": f"/runs/{run['run_id']}",
|
|
149
161
|
},
|
|
150
162
|
)
|
|
151
163
|
|
|
@@ -182,7 +194,7 @@ async def wait_run(request: ApiRequest):
|
|
|
182
194
|
run["run_id"], thread_id=run["thread_id"], stream_mode=await sub
|
|
183
195
|
)
|
|
184
196
|
) as stream:
|
|
185
|
-
async for mode, chunk in stream:
|
|
197
|
+
async for mode, chunk, _ in stream:
|
|
186
198
|
if mode == b"values":
|
|
187
199
|
vchunk = chunk
|
|
188
200
|
elif mode == b"error":
|
|
@@ -216,7 +228,10 @@ async def wait_run(request: ApiRequest):
|
|
|
216
228
|
return StreamingResponse(
|
|
217
229
|
body(),
|
|
218
230
|
media_type="application/json",
|
|
219
|
-
headers={
|
|
231
|
+
headers={
|
|
232
|
+
"Location": f"/threads/{thread_id}/runs/{run['run_id']}/join",
|
|
233
|
+
"Content-Location": f"/threads/{thread_id}/runs/{run['run_id']}",
|
|
234
|
+
},
|
|
220
235
|
)
|
|
221
236
|
|
|
222
237
|
|
|
@@ -251,7 +266,7 @@ async def wait_run_stateless(request: ApiRequest):
|
|
|
251
266
|
run["run_id"], thread_id=run["thread_id"], stream_mode=await sub
|
|
252
267
|
)
|
|
253
268
|
) as stream:
|
|
254
|
-
async for mode, chunk in stream:
|
|
269
|
+
async for mode, chunk, _ in stream:
|
|
255
270
|
if mode == b"values":
|
|
256
271
|
vchunk = chunk
|
|
257
272
|
elif mode == b"error":
|
|
@@ -280,7 +295,10 @@ async def wait_run_stateless(request: ApiRequest):
|
|
|
280
295
|
return StreamingResponse(
|
|
281
296
|
body(),
|
|
282
297
|
media_type="application/json",
|
|
283
|
-
headers={
|
|
298
|
+
headers={
|
|
299
|
+
"Location": f"/threads/{run['thread_id']}/runs/{run['run_id']}/join",
|
|
300
|
+
"Content-Location": f"/threads/{run['thread_id']}/runs/{run['run_id']}",
|
|
301
|
+
},
|
|
284
302
|
)
|
|
285
303
|
|
|
286
304
|
|
|
@@ -358,13 +376,15 @@ async def join_run_stream(request: ApiRequest):
|
|
|
358
376
|
validate_uuid(thread_id, "Invalid thread ID: must be a UUID")
|
|
359
377
|
validate_uuid(run_id, "Invalid run ID: must be a UUID")
|
|
360
378
|
stream_mode = request.query_params.get("stream_mode") or None
|
|
379
|
+
last_event_id = request.headers.get("last-event-id") or None
|
|
361
380
|
return EventSourceResponse(
|
|
362
381
|
Runs.Stream.join(
|
|
363
382
|
run_id,
|
|
364
383
|
thread_id=thread_id,
|
|
365
384
|
cancel_on_disconnect=cancel_on_disconnect,
|
|
366
385
|
stream_mode=stream_mode,
|
|
367
|
-
|
|
386
|
+
last_event_id=last_event_id,
|
|
387
|
+
),
|
|
368
388
|
)
|
|
369
389
|
|
|
370
390
|
|
|
@@ -18,7 +18,7 @@ import structlog
|
|
|
18
18
|
from langchain_core.runnables.config import run_in_executor, var_child_runnable_config
|
|
19
19
|
from langgraph.checkpoint.base import BaseCheckpointSaver
|
|
20
20
|
from langgraph.constants import CONFIG_KEY_CHECKPOINTER, CONFIG_KEY_STORE
|
|
21
|
-
from langgraph.graph import
|
|
21
|
+
from langgraph.graph import StateGraph
|
|
22
22
|
from langgraph.pregel import Pregel
|
|
23
23
|
from langgraph.store.base import BaseStore
|
|
24
24
|
from langgraph.utils.config import ensure_config
|
|
@@ -34,8 +34,8 @@ if TYPE_CHECKING:
|
|
|
34
34
|
|
|
35
35
|
logger = structlog.stdlib.get_logger(__name__)
|
|
36
36
|
|
|
37
|
-
GraphFactoryFromConfig = Callable[[Config], Pregel |
|
|
38
|
-
GraphFactory = Callable[[], Pregel |
|
|
37
|
+
GraphFactoryFromConfig = Callable[[Config], Pregel | StateGraph]
|
|
38
|
+
GraphFactory = Callable[[], Pregel | StateGraph]
|
|
39
39
|
GraphValue = Pregel | GraphFactory
|
|
40
40
|
|
|
41
41
|
|
|
@@ -130,7 +130,7 @@ async def get_graph(
|
|
|
130
130
|
value = value(config) if FACTORY_ACCEPTS_CONFIG[graph_id] else value()
|
|
131
131
|
try:
|
|
132
132
|
async with _generate_graph(value) as graph_obj:
|
|
133
|
-
if isinstance(graph_obj,
|
|
133
|
+
if isinstance(graph_obj, StateGraph):
|
|
134
134
|
graph_obj = graph_obj.compile()
|
|
135
135
|
if not isinstance(graph_obj, Pregel | BaseRemotePregel):
|
|
136
136
|
raise HTTPException(
|
|
@@ -442,7 +442,7 @@ def _graph_from_spec(spec: GraphSpec) -> GraphValue:
|
|
|
442
442
|
likely = [
|
|
443
443
|
k
|
|
444
444
|
for k in available
|
|
445
|
-
if isinstance(module.__dict__[k],
|
|
445
|
+
if isinstance(module.__dict__[k], StateGraph | Pregel)
|
|
446
446
|
]
|
|
447
447
|
if likely:
|
|
448
448
|
prefix = spec.module or spec.path
|
|
@@ -471,7 +471,7 @@ def _graph_from_spec(spec: GraphSpec) -> GraphValue:
|
|
|
471
471
|
raise ValueError(
|
|
472
472
|
f"Graph factory function '{spec.variable}' in module '{spec.path}' must take exactly one argument, a RunnableConfig"
|
|
473
473
|
)
|
|
474
|
-
elif isinstance(graph,
|
|
474
|
+
elif isinstance(graph, StateGraph):
|
|
475
475
|
graph = graph.compile()
|
|
476
476
|
elif isinstance(graph, Pregel):
|
|
477
477
|
# We don't want to fail real deployments, but this will help folks catch unnecessary custom components
|
|
@@ -513,7 +513,7 @@ def _graph_from_spec(spec: GraphSpec) -> GraphValue:
|
|
|
513
513
|
break
|
|
514
514
|
else:
|
|
515
515
|
for _, member in inspect.getmembers(module):
|
|
516
|
-
if isinstance(member,
|
|
516
|
+
if isinstance(member, StateGraph):
|
|
517
517
|
graph = member.compile()
|
|
518
518
|
break
|
|
519
519
|
else:
|
|
@@ -236,10 +236,10 @@
|
|
|
236
236
|
dependencies:
|
|
237
237
|
uuid "^10.0.0"
|
|
238
238
|
|
|
239
|
-
"@langchain/langgraph-sdk@^0.0.
|
|
240
|
-
version "0.0.
|
|
241
|
-
resolved "https://registry.yarnpkg.com/@langchain/langgraph-sdk/-/langgraph-sdk-0.0.
|
|
242
|
-
integrity sha512-
|
|
239
|
+
"@langchain/langgraph-sdk@^0.0.77":
|
|
240
|
+
version "0.0.77"
|
|
241
|
+
resolved "https://registry.yarnpkg.com/@langchain/langgraph-sdk/-/langgraph-sdk-0.0.77.tgz#adcd978843e61bbf09b9625d519dda16d27cec09"
|
|
242
|
+
integrity sha512-DMCONENhhaMS+Buw8s2UkKjAa9I6cT1aVJEDOmTO2lpon4Dqz/jiYUVJK7pTlNVSNvSx0E8aOmtT7NgGBcWflg==
|
|
243
243
|
dependencies:
|
|
244
244
|
"@types/json-schema" "^7.0.15"
|
|
245
245
|
p-queue "^6.6.2"
|
|
@@ -77,6 +77,8 @@ class RunCreateDict(TypedDict):
|
|
|
77
77
|
"""
|
|
78
78
|
stream_subgraphs: bool | None
|
|
79
79
|
"""Stream output from subgraphs. By default, streams only the top graph."""
|
|
80
|
+
stream_resumable: bool | None
|
|
81
|
+
"""Whether to persist the stream chunks in order to resume the stream later."""
|
|
80
82
|
feedback_keys: list[str] | None
|
|
81
83
|
"""Pass one or more feedback_keys if you want to request short-lived signed URLs
|
|
82
84
|
for submitting feedback to LangSmith with this key for this run."""
|
|
@@ -305,6 +307,7 @@ async def create_valid_run(
|
|
|
305
307
|
"feedback_keys": payload.get("feedback_keys"),
|
|
306
308
|
"temporary": temporary,
|
|
307
309
|
"subgraphs": payload.get("stream_subgraphs", False),
|
|
310
|
+
"resumable": payload.get("stream_resumable", False),
|
|
308
311
|
"checkpoint_during": payload.get("checkpoint_during", True),
|
|
309
312
|
},
|
|
310
313
|
metadata=payload.get("metadata"),
|
|
@@ -18,7 +18,9 @@ logger = structlog.stdlib.get_logger(__name__)
|
|
|
18
18
|
class EventSourceResponse(sse_starlette.EventSourceResponse):
|
|
19
19
|
def __init__(
|
|
20
20
|
self,
|
|
21
|
-
content: AsyncIterator[
|
|
21
|
+
content: AsyncIterator[
|
|
22
|
+
bytes | tuple[bytes, Any | bytes] | tuple[bytes, Any | bytes, bytes | None]
|
|
23
|
+
],
|
|
22
24
|
status_code: int = 200,
|
|
23
25
|
headers: Mapping[str, str] | None = None,
|
|
24
26
|
) -> None:
|
|
@@ -101,11 +103,12 @@ async def sse_heartbeat(send: Send) -> None:
|
|
|
101
103
|
SEP = b"\r\n"
|
|
102
104
|
EVENT = b"event: "
|
|
103
105
|
DATA = b"data: "
|
|
106
|
+
ID = b"id: "
|
|
104
107
|
BYTES_LIKE = (bytes, bytearray, memoryview)
|
|
105
108
|
|
|
106
109
|
|
|
107
|
-
def json_to_sse(event: bytes, data: Any | bytes) -> bytes:
|
|
108
|
-
|
|
110
|
+
def json_to_sse(event: bytes, data: Any | bytes, id: bytes | None = None) -> bytes:
|
|
111
|
+
result = b"".join(
|
|
109
112
|
(
|
|
110
113
|
EVENT,
|
|
111
114
|
event,
|
|
@@ -113,6 +116,11 @@ def json_to_sse(event: bytes, data: Any | bytes) -> bytes:
|
|
|
113
116
|
DATA,
|
|
114
117
|
data if isinstance(data, BYTES_LIKE) else json_dumpb(data),
|
|
115
118
|
SEP,
|
|
116
|
-
SEP,
|
|
117
119
|
)
|
|
118
120
|
)
|
|
121
|
+
|
|
122
|
+
if id is not None:
|
|
123
|
+
result += b"".join((ID, id, SEP))
|
|
124
|
+
|
|
125
|
+
result += SEP
|
|
126
|
+
return result
|
|
@@ -87,6 +87,7 @@ async def astream_state(
|
|
|
87
87
|
# extract args from run
|
|
88
88
|
kwargs = run["kwargs"].copy()
|
|
89
89
|
kwargs.pop("webhook", None)
|
|
90
|
+
kwargs.pop("resumable", False)
|
|
90
91
|
subgraphs = kwargs.get("subgraphs", False)
|
|
91
92
|
temporary = kwargs.pop("temporary", False)
|
|
92
93
|
config = kwargs.pop("config")
|
|
@@ -278,19 +279,25 @@ async def astream_state(
|
|
|
278
279
|
yield "feedback", feedback_urls
|
|
279
280
|
|
|
280
281
|
|
|
281
|
-
async def consume(stream: AnyStream, run_id: str) -> None:
|
|
282
|
+
async def consume(stream: AnyStream, run_id: str, resumable: bool = False) -> None:
|
|
282
283
|
async with aclosing(stream):
|
|
283
284
|
try:
|
|
284
285
|
async for mode, payload in stream:
|
|
285
286
|
await Runs.Stream.publish(
|
|
286
|
-
run_id,
|
|
287
|
+
run_id,
|
|
288
|
+
mode,
|
|
289
|
+
await run_in_executor(None, json_dumpb, payload),
|
|
290
|
+
resumable=resumable,
|
|
287
291
|
)
|
|
288
292
|
except Exception as e:
|
|
289
293
|
g = e
|
|
290
294
|
if isinstance(e, ExceptionGroup):
|
|
291
295
|
e = e.exceptions[0]
|
|
292
296
|
await Runs.Stream.publish(
|
|
293
|
-
run_id,
|
|
297
|
+
run_id,
|
|
298
|
+
"error",
|
|
299
|
+
await run_in_executor(None, json_dumpb, e),
|
|
300
|
+
resumable=resumable,
|
|
294
301
|
)
|
|
295
302
|
raise e from g
|
|
296
303
|
|
|
@@ -83,8 +83,8 @@ async def worker(
|
|
|
83
83
|
Runs.enter(run_id, main_loop) as done,
|
|
84
84
|
):
|
|
85
85
|
temporary = run["kwargs"].get("temporary", False)
|
|
86
|
+
resumable = run["kwargs"].get("resumable", False)
|
|
86
87
|
run_created_at = run["created_at"].isoformat()
|
|
87
|
-
run["kwargs"]
|
|
88
88
|
lg_logging.set_logging_context(
|
|
89
89
|
{
|
|
90
90
|
"run_id": str(run_id),
|
|
@@ -145,7 +145,10 @@ async def worker(
|
|
|
145
145
|
on_checkpoint=on_checkpoint,
|
|
146
146
|
on_task_result=on_task_result,
|
|
147
147
|
)
|
|
148
|
-
await asyncio.wait_for(
|
|
148
|
+
await asyncio.wait_for(
|
|
149
|
+
consume(stream, run_id, resumable),
|
|
150
|
+
BG_JOB_TIMEOUT_SECS,
|
|
151
|
+
)
|
|
149
152
|
run_ended_at = datetime.now(UTC).isoformat()
|
|
150
153
|
await logger.ainfo(
|
|
151
154
|
"Background run succeeded",
|
|
@@ -886,73 +886,73 @@
|
|
|
886
886
|
}
|
|
887
887
|
}
|
|
888
888
|
},
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
},
|
|
908
|
-
{
|
|
909
|
-
"description": "The ID of the checkpoint.",
|
|
910
|
-
"required": true,
|
|
911
|
-
"schema": {
|
|
912
|
-
"type": "string",
|
|
913
|
-
"format": "uuid",
|
|
914
|
-
"title": "Checkpoint Id",
|
|
915
|
-
"description": "The ID of the checkpoint."
|
|
889
|
+
"/threads/{thread_id}/state/{checkpoint_id}": {
|
|
890
|
+
"get": {
|
|
891
|
+
"tags": ["Threads"],
|
|
892
|
+
"summary": "Get Thread State At Checkpoint",
|
|
893
|
+
"description": "Get state for a thread at a specific checkpoint.",
|
|
894
|
+
"operationId": "get_thread_state_at_checkpoint_threads__thread_id__state__checkpoint_id__get",
|
|
895
|
+
"parameters": [
|
|
896
|
+
{
|
|
897
|
+
"description": "The ID of the thread.",
|
|
898
|
+
"required": true,
|
|
899
|
+
"schema": {
|
|
900
|
+
"type": "string",
|
|
901
|
+
"format": "uuid",
|
|
902
|
+
"title": "Thread Id",
|
|
903
|
+
"description": "The ID of the thread."
|
|
904
|
+
},
|
|
905
|
+
"name": "thread_id",
|
|
906
|
+
"in": "path"
|
|
916
907
|
},
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
"
|
|
908
|
+
{
|
|
909
|
+
"description": "The ID of the checkpoint.",
|
|
910
|
+
"required": true,
|
|
911
|
+
"schema": {
|
|
912
|
+
"type": "string",
|
|
913
|
+
"format": "uuid",
|
|
914
|
+
"title": "Checkpoint Id",
|
|
915
|
+
"description": "The ID of the checkpoint."
|
|
916
|
+
},
|
|
917
|
+
"name": "checkpoint_id",
|
|
918
|
+
"in": "path"
|
|
927
919
|
},
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
"
|
|
937
|
-
|
|
938
|
-
|
|
920
|
+
{
|
|
921
|
+
"description": "Whether to include subgraphs in the response.",
|
|
922
|
+
"required": false,
|
|
923
|
+
"schema": {
|
|
924
|
+
"type": "boolean",
|
|
925
|
+
"title": "Subgraphs",
|
|
926
|
+
"description": "Whether to include subgraphs in the response."
|
|
927
|
+
},
|
|
928
|
+
"name": "subgraphs",
|
|
929
|
+
"in": "query"
|
|
930
|
+
}
|
|
931
|
+
],
|
|
932
|
+
"responses": {
|
|
933
|
+
"200": {
|
|
934
|
+
"description": "Success",
|
|
935
|
+
"content": {
|
|
936
|
+
"application/json": {
|
|
937
|
+
"schema": {
|
|
938
|
+
"$ref": "#/components/schemas/ThreadState"
|
|
939
|
+
}
|
|
939
940
|
}
|
|
940
941
|
}
|
|
941
|
-
}
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
942
|
+
},
|
|
943
|
+
"422": {
|
|
944
|
+
"description": "Validation Error",
|
|
945
|
+
"content": {
|
|
946
|
+
"application/json": {
|
|
947
|
+
"schema": {
|
|
948
|
+
"$ref": "#/components/schemas/ErrorResponse"
|
|
949
|
+
}
|
|
949
950
|
}
|
|
950
951
|
}
|
|
951
952
|
}
|
|
952
953
|
}
|
|
953
954
|
}
|
|
954
|
-
}
|
|
955
|
-
},
|
|
955
|
+
},
|
|
956
956
|
"/threads/{thread_id}/state/checkpoint": {
|
|
957
957
|
"post": {
|
|
958
958
|
"tags": ["Threads"],
|
|
@@ -1483,6 +1483,14 @@
|
|
|
1483
1483
|
"$ref": "#/components/schemas/Run"
|
|
1484
1484
|
}
|
|
1485
1485
|
}
|
|
1486
|
+
},
|
|
1487
|
+
"headers": {
|
|
1488
|
+
"Content-Location": {
|
|
1489
|
+
"description": "The URL of the run that was created. Can be used to later join the stream.",
|
|
1490
|
+
"schema": {
|
|
1491
|
+
"type": "string"
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1486
1494
|
}
|
|
1487
1495
|
},
|
|
1488
1496
|
"404": {
|
|
@@ -1622,6 +1630,14 @@
|
|
|
1622
1630
|
"description": "The server will send a stream of events in SSE format.\n\n**Example event**:\n\nid: 1\n\nevent: message\n\ndata: {}"
|
|
1623
1631
|
}
|
|
1624
1632
|
}
|
|
1633
|
+
},
|
|
1634
|
+
"headers": {
|
|
1635
|
+
"Content-Location": {
|
|
1636
|
+
"description": "The URL of the run that was created. Can be used to later join the stream.",
|
|
1637
|
+
"schema": {
|
|
1638
|
+
"type": "string"
|
|
1639
|
+
}
|
|
1640
|
+
}
|
|
1625
1641
|
}
|
|
1626
1642
|
},
|
|
1627
1643
|
"404": {
|
|
@@ -1694,6 +1710,14 @@
|
|
|
1694
1710
|
"application/json": {
|
|
1695
1711
|
"schema": {}
|
|
1696
1712
|
}
|
|
1713
|
+
},
|
|
1714
|
+
"headers": {
|
|
1715
|
+
"Content-Location": {
|
|
1716
|
+
"description": "The URL of the run that was created. Can be used to later join the stream.",
|
|
1717
|
+
"schema": {
|
|
1718
|
+
"type": "string"
|
|
1719
|
+
}
|
|
1720
|
+
}
|
|
1697
1721
|
}
|
|
1698
1722
|
},
|
|
1699
1723
|
"404": {
|
|
@@ -1936,7 +1960,7 @@
|
|
|
1936
1960
|
"get": {
|
|
1937
1961
|
"tags": ["Thread Runs"],
|
|
1938
1962
|
"summary": "Join Run Stream",
|
|
1939
|
-
"description": "Join a run stream. This endpoint streams output in real-time from a run similar to the /threads/__THREAD_ID__/runs/stream endpoint.
|
|
1963
|
+
"description": "Join a run stream. This endpoint streams output in real-time from a run similar to the /threads/__THREAD_ID__/runs/stream endpoint. If the run has been created with `stream_resumable=true`, the stream can be resumed from the last seen event ID.",
|
|
1940
1964
|
"operationId": "stream_run_http_threads__thread_id__runs__run_id__join_get",
|
|
1941
1965
|
"parameters": [
|
|
1942
1966
|
{
|
|
@@ -1962,6 +1986,16 @@
|
|
|
1962
1986
|
},
|
|
1963
1987
|
"name": "run_id",
|
|
1964
1988
|
"in": "path"
|
|
1989
|
+
},
|
|
1990
|
+
{
|
|
1991
|
+
"required": false,
|
|
1992
|
+
"schema": {
|
|
1993
|
+
"type": "string",
|
|
1994
|
+
"title": "Last Event ID",
|
|
1995
|
+
"description": "The ID of the last event received. Set to -1 if you want to stream all events. Requires `stream_resumable=true` to be set when creating the run."
|
|
1996
|
+
},
|
|
1997
|
+
"name": "Last-Event-ID",
|
|
1998
|
+
"in": "header"
|
|
1965
1999
|
}
|
|
1966
2000
|
],
|
|
1967
2001
|
"responses": {
|
|
@@ -2204,6 +2238,14 @@
|
|
|
2204
2238
|
"description": "The server will send a stream of events in SSE format.\n\n**Example event**:\n\nid: 1\n\nevent: message\n\ndata: {}"
|
|
2205
2239
|
}
|
|
2206
2240
|
}
|
|
2241
|
+
},
|
|
2242
|
+
"headers": {
|
|
2243
|
+
"Content-Location": {
|
|
2244
|
+
"description": "The URL of the run that was created. Can be used to later join the stream.",
|
|
2245
|
+
"schema": {
|
|
2246
|
+
"type": "string"
|
|
2247
|
+
}
|
|
2248
|
+
}
|
|
2207
2249
|
}
|
|
2208
2250
|
},
|
|
2209
2251
|
"404": {
|
|
@@ -2319,6 +2361,14 @@
|
|
|
2319
2361
|
"application/json": {
|
|
2320
2362
|
"schema": {}
|
|
2321
2363
|
}
|
|
2364
|
+
},
|
|
2365
|
+
"headers": {
|
|
2366
|
+
"Content-Location": {
|
|
2367
|
+
"description": "The URL of the run that was created. Can be used to later join the stream.",
|
|
2368
|
+
"schema": {
|
|
2369
|
+
"type": "string"
|
|
2370
|
+
}
|
|
2371
|
+
}
|
|
2322
2372
|
}
|
|
2323
2373
|
},
|
|
2324
2374
|
"404": {
|
|
@@ -2377,6 +2427,14 @@
|
|
|
2377
2427
|
"application/json": {
|
|
2378
2428
|
"schema": {}
|
|
2379
2429
|
}
|
|
2430
|
+
},
|
|
2431
|
+
"headers": {
|
|
2432
|
+
"Content-Location": {
|
|
2433
|
+
"description": "The URL of the run that was created. Can be used to later join the stream.",
|
|
2434
|
+
"schema": {
|
|
2435
|
+
"type": "string"
|
|
2436
|
+
}
|
|
2437
|
+
}
|
|
2380
2438
|
}
|
|
2381
2439
|
},
|
|
2382
2440
|
"404": {
|
|
@@ -3569,6 +3627,12 @@
|
|
|
3569
3627
|
"description": "Whether to stream output from subgraphs.",
|
|
3570
3628
|
"default": false
|
|
3571
3629
|
},
|
|
3630
|
+
"stream_resumable": {
|
|
3631
|
+
"type": "boolean",
|
|
3632
|
+
"title": "Stream Resumable",
|
|
3633
|
+
"description": "Whether to persist the stream chunks in order to resume the stream later.",
|
|
3634
|
+
"default": false
|
|
3635
|
+
},
|
|
3572
3636
|
"on_disconnect": {
|
|
3573
3637
|
"type": "string",
|
|
3574
3638
|
"enum": ["cancel", "continue"],
|
|
@@ -3791,6 +3855,12 @@
|
|
|
3791
3855
|
"description": "Whether to stream output from subgraphs.",
|
|
3792
3856
|
"default": false
|
|
3793
3857
|
},
|
|
3858
|
+
"stream_resumable": {
|
|
3859
|
+
"type": "boolean",
|
|
3860
|
+
"title": "Stream Resumable",
|
|
3861
|
+
"description": "Whether to persist the stream chunks in order to resume the stream later.",
|
|
3862
|
+
"default": false
|
|
3863
|
+
},
|
|
3794
3864
|
"on_completion": {
|
|
3795
3865
|
"type": "string",
|
|
3796
3866
|
"enum": ["delete", "keep"],
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.2.32"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|