langgraph-api 0.2.30__py3-none-any.whl → 0.2.34__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/__init__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.2.30"
1
+ __version__ = "0.2.34"
langgraph_api/api/runs.py CHANGED
@@ -39,7 +39,10 @@ async def create_run(request: ApiRequest):
39
39
  payload,
40
40
  request.headers,
41
41
  )
42
- return ApiResponse(run)
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(run)
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={"Location": f"/threads/{thread_id}/runs/{run['run_id']}/stream"},
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"/threads/{run['thread_id']}/runs/{run['run_id']}/stream"
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={"Location": f"/threads/{thread_id}/runs/{run['run_id']}/join"},
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={"Location": f"/threads/{run['thread_id']}/runs/{run['run_id']}/join"},
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
 
@@ -7,7 +7,10 @@ import * as path from "node:path";
7
7
  import { type GraphSchema, resolveGraph } from "./src/graph.mts";
8
8
  import { build } from "@langchain/langgraph-ui";
9
9
  import { checkLangGraphSemver } from "@langchain/langgraph-api/semver";
10
- import { getStaticGraphSchema } from "@langchain/langgraph-api/schema";
10
+ import {
11
+ getStaticGraphSchema,
12
+ GraphSpec,
13
+ } from "@langchain/langgraph-api/schema";
11
14
  import { filterValidExportPath } from "./src/utils/files.mts";
12
15
 
13
16
  const __dirname = new URL(".", import.meta.url).pathname;
@@ -17,7 +20,7 @@ async function main() {
17
20
  z.record(z.string()).parse(JSON.parse(process.env.LANGSERVE_GRAPHS)),
18
21
  ).filter(([_, spec]) => filterValidExportPath(spec));
19
22
 
20
- const GRAPH_SCHEMAS: Record<string, Record<string, GraphSchema> | false> = {};
23
+ let GRAPH_SCHEMAS: Record<string, Record<string, GraphSchema> | false> = {};
21
24
 
22
25
  const semver = await checkLangGraphSemver();
23
26
  const invalidPackages = semver.filter(
@@ -42,28 +45,42 @@ async function main() {
42
45
 
43
46
  let failed = false;
44
47
  try {
45
- await Promise.all(
46
- specs.map(async ([graphId, rawSpec]) => {
47
- console.info(`[${graphId}]: Checking for source file existence`);
48
- const { resolved, ...spec } = await resolveGraph(rawSpec, {
49
- onlyFilePresence: true,
50
- });
51
-
52
- try {
53
- console.info(`[${graphId}]: Extracting schema`);
54
- GRAPH_SCHEMAS[graphId] = await getStaticGraphSchema(spec, {
55
- timeoutMs: 120_000,
48
+ const resolveSpecs = Object.fromEntries<GraphSpec>(
49
+ await Promise.all(
50
+ specs.map(async ([graphId, rawSpec]) => {
51
+ console.info(`[${graphId}]: Checking for source file existence`);
52
+ const { resolved, ...spec } = await resolveGraph(rawSpec, {
53
+ onlyFilePresence: true,
56
54
  });
57
- } catch (error) {
58
- console.error(`[${graphId}]: Error extracting schema: ${error}`);
59
- GRAPH_SCHEMAS[graphId] = false;
60
- }
61
- }),
55
+
56
+ return [graphId, spec] as [string, GraphSpec];
57
+ }),
58
+ ),
62
59
  );
63
60
 
61
+ try {
62
+ console.info("Extracting schemas");
63
+ GRAPH_SCHEMAS = await getStaticGraphSchema(resolveSpecs, {
64
+ timeoutMs: 120_000,
65
+ });
66
+ } catch (error) {
67
+ console.error(`Error extracting schema: ${error}`);
68
+ }
69
+
64
70
  await fs.writeFile(
65
71
  path.resolve(__dirname, "client.schemas.json"),
66
- JSON.stringify(GRAPH_SCHEMAS),
72
+ JSON.stringify(
73
+ Object.fromEntries(
74
+ specs.map(([graphId]) => {
75
+ const valid = GRAPH_SCHEMAS[graphId];
76
+ if (valid == null || Object.values(valid).every((x) => x == null)) {
77
+ return [graphId, false];
78
+ }
79
+
80
+ return [graphId, valid];
81
+ }),
82
+ ),
83
+ ),
67
84
  { encoding: "utf-8" },
68
85
  );
69
86
  } catch (error) {
@@ -24,8 +24,8 @@
24
24
  "undici": "^6.21.1",
25
25
  "uuid": "^10.0.0",
26
26
  "winston": "^3.17.0",
27
- "@langchain/langgraph-api": "~0.0.32",
28
- "@langchain/langgraph-ui": "~0.0.32",
27
+ "@langchain/langgraph-api": "~0.0.37",
28
+ "@langchain/langgraph-ui": "~0.0.37",
29
29
  "zod": "^3.23.8"
30
30
  },
31
31
  "resolutions": {
@@ -33,7 +33,7 @@
33
33
  },
34
34
  "devDependencies": {
35
35
  "jose": "^6.0.10",
36
- "@langchain/langgraph-sdk": "^0.0.73",
36
+ "@langchain/langgraph-sdk": "^0.0.77",
37
37
  "@types/react": "^19.0.8",
38
38
  "@types/react-dom": "^19.0.3",
39
39
  "@types/node": "^22.2.0",
@@ -203,15 +203,15 @@
203
203
  zod "^3.22.4"
204
204
  zod-to-json-schema "^3.22.3"
205
205
 
206
- "@langchain/langgraph-api@~0.0.32":
207
- version "0.0.32"
208
- resolved "https://registry.yarnpkg.com/@langchain/langgraph-api/-/langgraph-api-0.0.32.tgz#65f41373318055b330fa64e7d4ccd7c994f7dc8d"
209
- integrity sha512-wYflud8iCGjwh3/GtzrTeWlwcc91kXBa49Goc2iaHcJRjMnTbl+loE3eklegDPnQGx1VKUCiB9qW/HutxuqXGA==
206
+ "@langchain/langgraph-api@~0.0.37":
207
+ version "0.0.37"
208
+ resolved "https://registry.yarnpkg.com/@langchain/langgraph-api/-/langgraph-api-0.0.37.tgz#52b3a62ac56dc56e239b76953ccc5b42a5aa1396"
209
+ integrity sha512-0mMmjA0KSYx/oKm6a+KSjWj7hneWsGlTDuwIaEnpauFLo5FCx3bZ8yQSPNFprvgHgJkxYWLjnVuXS+y/V1kLqg==
210
210
  dependencies:
211
211
  "@babel/code-frame" "^7.26.2"
212
212
  "@hono/node-server" "^1.12.0"
213
213
  "@hono/zod-validator" "^0.2.2"
214
- "@langchain/langgraph-ui" "0.0.32"
214
+ "@langchain/langgraph-ui" "0.0.37"
215
215
  "@types/json-schema" "^7.0.15"
216
216
  "@typescript/vfs" "^1.6.0"
217
217
  dedent "^1.5.3"
@@ -236,10 +236,10 @@
236
236
  dependencies:
237
237
  uuid "^10.0.0"
238
238
 
239
- "@langchain/langgraph-sdk@^0.0.73":
240
- version "0.0.73"
241
- resolved "https://registry.yarnpkg.com/@langchain/langgraph-sdk/-/langgraph-sdk-0.0.73.tgz#6f5cb44fb306461182df55be4cf1d263c5ce3e16"
242
- integrity sha512-V3E7Bd1KNcTpnEglZqKpnQtth62WHf+Dxq5V+0CqMxbzPHnW9I4eynCO4c1/HSY/rHgEtvgj7fMvCAb6I5R+lQ==
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"
@@ -256,10 +256,10 @@
256
256
  p-retry "4"
257
257
  uuid "^9.0.0"
258
258
 
259
- "@langchain/langgraph-ui@0.0.32", "@langchain/langgraph-ui@~0.0.32":
260
- version "0.0.32"
261
- resolved "https://registry.yarnpkg.com/@langchain/langgraph-ui/-/langgraph-ui-0.0.32.tgz#7e0cab750ba1e65f47d7b1d2adf955a36e50664e"
262
- integrity sha512-65QZpouvw4P+hCpklYebNiwR88M84h7awjNB6FaKWHvCZa6NcSzlruFa/PnvU1o/kRK5NNpXNPyDUQLhT3tmTA==
259
+ "@langchain/langgraph-ui@0.0.37", "@langchain/langgraph-ui@~0.0.37":
260
+ version "0.0.37"
261
+ resolved "https://registry.yarnpkg.com/@langchain/langgraph-ui/-/langgraph-ui-0.0.37.tgz#02bfdcc6ef1f518d3810afe298d6862d82100c58"
262
+ integrity sha512-eHsm+bjxXYzHsWa3WjlYiHd7a5PMaLgH1U0B5Ox+p43QnCE+mUCm82dWvvvXQ+FO/RktPk8kjbswwK/y/0Zk5A==
263
263
  dependencies:
264
264
  "@commander-js/extra-typings" "^13.0.0"
265
265
  commander "^13.0.0"
langgraph_api/metadata.py CHANGED
@@ -1,6 +1,5 @@
1
1
  import asyncio
2
2
  import os
3
- from collections import defaultdict
4
3
  from datetime import UTC, datetime
5
4
 
6
5
  import langgraph.version
@@ -37,8 +36,8 @@ PLAN = "enterprise" if plus_features_enabled() else "developer"
37
36
  USER_API_URL = os.getenv("LANGGRAPH_API_URL", None)
38
37
 
39
38
  LOGS: list[dict] = []
40
- RUN_COUNTER = defaultdict(int)
41
- NODE_COUNTER = defaultdict(int)
39
+ RUN_COUNTER = 0
40
+ NODE_COUNTER = 0
42
41
  FROM_TIMESTAMP = datetime.now(UTC).isoformat()
43
42
 
44
43
  if (
@@ -50,12 +49,14 @@ else:
50
49
  METADATA_ENDPOINT = "https://api.smith.langchain.com/v1/metadata/submit"
51
50
 
52
51
 
53
- def incr_runs(*, graph_id: str | None = None, incr: int = 1) -> None:
54
- RUN_COUNTER[graph_id] += incr
52
+ def incr_runs(*, incr: int = 1) -> None:
53
+ global RUN_COUNTER
54
+ RUN_COUNTER += incr
55
55
 
56
56
 
57
- def incr_nodes(*_, graph_id: str | None = None, incr: int = 1) -> None:
58
- NODE_COUNTER[graph_id] += incr
57
+ def incr_nodes(_, *, incr: int = 1) -> None:
58
+ global NODE_COUNTER
59
+ NODE_COUNTER += incr
59
60
 
60
61
 
61
62
  def append_log(log: dict) -> None:
@@ -88,23 +89,13 @@ async def metadata_loop() -> None:
88
89
  # we don't need a lock as long as there's no awaits in this block
89
90
  from_timestamp = FROM_TIMESTAMP
90
91
  to_timestamp = datetime.now(UTC).isoformat()
91
- nodes = NODE_COUNTER.copy()
92
- runs = RUN_COUNTER.copy()
92
+ nodes = NODE_COUNTER
93
+ runs = RUN_COUNTER
93
94
  logs = LOGS.copy()
94
95
  LOGS.clear()
95
- RUN_COUNTER.clear()
96
- NODE_COUNTER.clear()
96
+ RUN_COUNTER = 0
97
+ NODE_COUNTER = 0
97
98
  FROM_TIMESTAMP = to_timestamp
98
- graph_measures = {
99
- f"langgraph.platform.graph_runs.{graph_id}": runs.get(graph_id, 0)
100
- for graph_id in runs
101
- }
102
- graph_measures.update(
103
- {
104
- f"langgraph.platform.graph_nodes.{graph_id}": nodes.get(graph_id, 0)
105
- for graph_id in nodes
106
- }
107
- )
108
99
 
109
100
  payload = {
110
101
  "license_key": LANGGRAPH_CLOUD_LICENSE_KEY,
@@ -129,9 +120,8 @@ async def metadata_loop() -> None:
129
120
  "user_app.uses_store_ttl": str(USES_STORE_TTL),
130
121
  },
131
122
  "measures": {
132
- "langgraph.platform.runs": sum(runs.values()),
133
- "langgraph.platform.nodes": sum(nodes.values()),
134
- **graph_measures,
123
+ "langgraph.platform.runs": runs,
124
+ "langgraph.platform.nodes": nodes,
135
125
  },
136
126
  "logs": logs,
137
127
  }
@@ -144,10 +134,8 @@ async def metadata_loop() -> None:
144
134
  )
145
135
  except Exception as e:
146
136
  # retry on next iteration
147
- for graph_id, incr in runs.items():
148
- incr_runs(graph_id=graph_id, incr=incr)
149
- for graph_id, incr in nodes.items():
150
- incr_nodes(graph_id=graph_id, incr=incr)
137
+ incr_runs(incr=runs)
138
+ incr_nodes("", incr=nodes)
151
139
  FROM_TIMESTAMP = from_timestamp
152
140
  await logger.ainfo("Metadata submission skipped.", error=str(e))
153
141
  await asyncio.sleep(INTERVAL)
@@ -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"),
langgraph_api/sse.py CHANGED
@@ -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[bytes | tuple[bytes, Any | bytes]],
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
- return b"".join(
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
langgraph_api/stream.py CHANGED
@@ -1,6 +1,6 @@
1
- import functools
2
1
  from collections.abc import AsyncIterator, Callable
3
2
  from contextlib import AsyncExitStack, aclosing
3
+ from functools import lru_cache
4
4
  from typing import Any, cast
5
5
 
6
6
  import langgraph.version
@@ -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")
@@ -119,9 +120,7 @@ async def astream_state(
119
120
  # attach node counter
120
121
  is_remote_pregel = isinstance(graph, BaseRemotePregel)
121
122
  if not is_remote_pregel:
122
- config["configurable"]["__pregel_node_finished"] = functools.partial(
123
- incr_nodes, graph_id=_get_graph_id(run)
124
- )
123
+ config["configurable"]["__pregel_node_finished"] = incr_nodes
125
124
 
126
125
  # attach run_id to config
127
126
  # for attempts beyond the first, use a fresh, unique run_id
@@ -265,10 +264,10 @@ async def astream_state(
265
264
  yield mode, chunk
266
265
  # --- end shared logic with astream_events ---
267
266
  if is_remote_pregel:
268
- # increment the remote runs
267
+ # increament the remote runs
269
268
  try:
270
269
  nodes_executed = await graph.fetch_nodes_executed()
271
- incr_nodes(graph_id=graph.graph_id, incr=nodes_executed)
270
+ incr_nodes(None, incr=nodes_executed)
272
271
  except Exception as e:
273
272
  logger.warning(f"Failed to fetch nodes executed for {graph.graph_id}: {e}")
274
273
 
@@ -280,19 +279,25 @@ async def astream_state(
280
279
  yield "feedback", feedback_urls
281
280
 
282
281
 
283
- async def consume(stream: AnyStream, run_id: str) -> None:
282
+ async def consume(stream: AnyStream, run_id: str, resumable: bool = False) -> None:
284
283
  async with aclosing(stream):
285
284
  try:
286
285
  async for mode, payload in stream:
287
286
  await Runs.Stream.publish(
288
- run_id, mode, await run_in_executor(None, json_dumpb, payload)
287
+ run_id,
288
+ mode,
289
+ await run_in_executor(None, json_dumpb, payload),
290
+ resumable=resumable,
289
291
  )
290
292
  except Exception as e:
291
293
  g = e
292
294
  if isinstance(e, ExceptionGroup):
293
295
  e = e.exceptions[0]
294
296
  await Runs.Stream.publish(
295
- run_id, "error", await run_in_executor(None, json_dumpb, e)
297
+ run_id,
298
+ "error",
299
+ await run_in_executor(None, json_dumpb, e),
300
+ resumable=resumable,
296
301
  )
297
302
  raise e from g
298
303
 
@@ -303,7 +308,7 @@ def get_feedback_urls(run_id: str, feedback_keys: list[str]) -> dict[str, str]:
303
308
  return {key: token.url for key, token in zip(feedback_keys, tokens, strict=False)}
304
309
 
305
310
 
306
- @functools.lru_cache(maxsize=1)
311
+ @lru_cache(maxsize=1)
307
312
  def get_langsmith_client() -> langsmith.Client:
308
313
  return langsmith.Client()
309
314
 
@@ -317,11 +322,3 @@ EXPECTED_ERRORS = (
317
322
  ValidationError,
318
323
  ValidationErrorLegacy,
319
324
  )
320
-
321
-
322
- def _get_graph_id(run: Run) -> str | None:
323
- try:
324
- return run["kwargs"]["config"]["configurable"]["graph_id"]
325
- except Exception:
326
- logger.info(f"Failed to get graph_id from run {run['run_id']}")
327
- return "Unknown"
langgraph_api/worker.py CHANGED
@@ -69,7 +69,7 @@ async def worker(
69
69
  ) -> WorkerResult:
70
70
  run_id = run["run_id"]
71
71
  if attempt == 1:
72
- incr_runs(graph_id=_get_graph_id(run))
72
+ incr_runs()
73
73
  checkpoint: CheckpointPayload | None = None
74
74
  exception: Exception | None = None
75
75
  status: str | None = None
@@ -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(consume(stream, run_id), BG_JOB_TIMEOUT_SECS)
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",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: langgraph-api
3
- Version: 0.2.30
3
+ Version: 0.2.34
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.2,>=0.1.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
@@ -1,4 +1,4 @@
1
- langgraph_api/__init__.py,sha256=R75QzgJ-X9Ixa6UnK5Wm3Jn0Wd9dnVdrtup0aqecq6U,23
1
+ langgraph_api/__init__.py,sha256=5TnwcrtiZS4c6J_QH9Z6CeZN1Ljn_ZOqbNVg9Dw2Xsk,23
2
2
  langgraph_api/asgi_transport.py,sha256=eqifhHxNnxvI7jJqrY1_8RjL4Fp9NdN4prEub2FWBt8,5091
3
3
  langgraph_api/asyncio.py,sha256=nelZwKL7iOjM5GHj1rVjiPE7igUIKLNKtc-3urxmlfo,9250
4
4
  langgraph_api/cli.py,sha256=9Ou3tGDDY_VVLt5DFle8UviJdpI4ZigC5hElYvq2-To,14519
@@ -9,28 +9,28 @@ langgraph_api/errors.py,sha256=Bu_i5drgNTyJcLiyrwVE_6-XrSU50BHf9TDpttki9wQ,1690
9
9
  langgraph_api/graph.py,sha256=uc4YFMwzC8husHC0lySPm7KUaYh1L5Y9sZREE-FIekE,23205
10
10
  langgraph_api/http.py,sha256=gYbxxjY8aLnsXeJymcJ7G7Nj_yToOGpPYQqmZ1_ggfA,5240
11
11
  langgraph_api/logging.py,sha256=3GSbvmXi8yWxWxJ558RE81xUEdklrPHJ4PpkxAb-35w,4428
12
- langgraph_api/metadata.py,sha256=YZ2O9BpMSgDyPUc4hcw5ab6e6VMZETpoc-ml2RWgpIU,5140
12
+ langgraph_api/metadata.py,sha256=ptaxwmzdx2bUBSc1KRhqgF-Xnm-Zh2gqwSiHpl8LD9c,4482
13
13
  langgraph_api/patch.py,sha256=Dgs0PXHytekX4SUL6KsjjN0hHcOtGLvv1GRGbh6PswU,1408
14
14
  langgraph_api/queue_entrypoint.py,sha256=_41ZveMDdn9bapjA7Ik9FG3r4hyIwXESUM5F1PdlieE,2309
15
15
  langgraph_api/route.py,sha256=uN311KjIugyNHG3rmVw_ms61QO1W1l16jJx03rf0R_s,4630
16
16
  langgraph_api/schema.py,sha256=2711t4PIBk5dky4gmMndrTRC9CVvAgH47C9FKDxhkBo,5444
17
17
  langgraph_api/serde.py,sha256=8fQXg7T7RVUqj_jgOoSOJrWVpQDW0qJKjAjSsEhPHo4,4803
18
18
  langgraph_api/server.py,sha256=Z_VL-kIphybTRDWBIqHMfRhgCmAFyTRqAGlgnHQF0Zg,6973
19
- langgraph_api/sse.py,sha256=3jG_FZj8FI9r7xGWTqaAyDkmqf6P1NOu0EzGrcSOGYc,4033
19
+ langgraph_api/sse.py,sha256=F7swfjKBDrlUmXZ_dWuDVHtp-3o1Cpjq1lwp0bJD-nw,4223
20
20
  langgraph_api/state.py,sha256=8jx4IoTCOjTJuwzuXJKKFwo1VseHjNnw_CCq4x1SW14,2284
21
21
  langgraph_api/store.py,sha256=UWVpopgVjAYM2U9Ra6ZY_BmwPPlq6wfqOw7zdWnQjBU,4598
22
- langgraph_api/stream.py,sha256=UAc_bOlXadE4nK2Bf0iNyzQkMgRegDszk5AMoLR3NGI,12781
22
+ langgraph_api/stream.py,sha256=T1tkUZFr5KlgqvE-QHEh-m80mWAgp2MUT9gFD7HLen0,12670
23
23
  langgraph_api/thread_ttl.py,sha256=-Ox8NFHqUH3wGNdEKMIfAXUubY5WGifIgCaJ7npqLgw,1762
24
24
  langgraph_api/utils.py,sha256=92mSti9GfGdMRRWyESKQW5yV-75Z9icGHnIrBYvdypU,3619
25
25
  langgraph_api/validation.py,sha256=zMuKmwUEBjBgFMwAaeLZmatwGVijKv2sOYtYg7gfRtc,4950
26
26
  langgraph_api/webhook.py,sha256=1ncwO0rIZcj-Df9sxSnFEzd1gP1bfS4okeZQS8NSRoE,1382
27
- langgraph_api/worker.py,sha256=X1btoYoAhCGLgC8zi34zeF512ZjzXzozOyeb4eLzElY,12418
27
+ langgraph_api/worker.py,sha256=yngRvZAKePFAGD0Xb3wtUYfEIcZS1D_ewA2tZJxmXys,12485
28
28
  langgraph_api/api/__init__.py,sha256=YVzpbn5IQotvuuLG9fhS9QMrxXfP4s4EpEMG0n4q3Nw,5625
29
29
  langgraph_api/api/assistants.py,sha256=x_V1rnSGFYjNZFJkZKFN9yNFOqXhqkOSqMDSv3I8VeE,15880
30
30
  langgraph_api/api/mcp.py,sha256=RvRYgANqRzNQzSmgjNkq4RlKTtoEJYil04ot9lsmEtE,14352
31
31
  langgraph_api/api/meta.py,sha256=sTgkhE-DaFWpERG6F7KelZfDsmJAiVc4j5dg50tDkSo,2950
32
32
  langgraph_api/api/openapi.py,sha256=362m6Ny8wOwZ6HrDK9JAVUzPkyLYWKeV1E71hPOaA0U,11278
33
- langgraph_api/api/runs.py,sha256=ys8X3g2EGbuF_OF1htM4jcLu4Mqztd8v7ttosmIbdsw,17972
33
+ langgraph_api/api/runs.py,sha256=CGPNYM8jjwQybVsaKC5ubhABQUpytHAxX5wWA4QJ9Tk,18669
34
34
  langgraph_api/api/store.py,sha256=TSeMiuMfrifmEnEbL0aObC2DPeseLlmZvAMaMzPgG3Y,5535
35
35
  langgraph_api/api/threads.py,sha256=ogMKmEoiycuaV3fa5kpupDohJ7fwUOfVczt6-WSK4FE,9322
36
36
  langgraph_api/api/ui.py,sha256=2nlipYV2nUGR4T9pceaAbgN1lS3-T2zPBh7Nv3j9eZQ,2479
@@ -46,18 +46,18 @@ langgraph_api/js/.gitignore,sha256=l5yI6G_V6F1600I1IjiUKn87f4uYIrBAYU1MOyBBhg4,5
46
46
  langgraph_api/js/.prettierrc,sha256=0es3ovvyNIqIw81rPQsdt1zCQcOdBqyR_DMbFE4Ifms,19
47
47
  langgraph_api/js/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
48
48
  langgraph_api/js/base.py,sha256=gjY6K8avI03OrI-Hy6a311fQ_EG5r_x8hUYlc7uqxdE,534
49
- langgraph_api/js/build.mts,sha256=05bkP9mpxf1JVuJ3at0y56p13QBkHgf7Q6eG6pOZsIg,2784
49
+ langgraph_api/js/build.mts,sha256=bRQo11cglDFXlLN7Y48CQPTSMLenp7MqIWuP1DkSIo0,3139
50
50
  langgraph_api/js/client.http.mts,sha256=AGA-p8J85IcNh2oXZjDxHQ4PnQdJmt-LPcpZp6j0Cws,4687
51
51
  langgraph_api/js/client.mts,sha256=N9CTH7mbXGSD-gpv-XyruYsHI-rgrObL8cQoAp5s3_U,30986
52
52
  langgraph_api/js/errors.py,sha256=Cm1TKWlUCwZReDC5AQ6SgNIVGD27Qov2xcgHyf8-GXo,361
53
53
  langgraph_api/js/global.d.ts,sha256=j4GhgtQSZ5_cHzjSPcHgMJ8tfBThxrH-pUOrrJGteOU,196
54
- langgraph_api/js/package.json,sha256=craKzuSIEnt-WQpKZDaACwdm75lPqpRQde6l9LfS-eI,1289
54
+ langgraph_api/js/package.json,sha256=o7cl0lFy4PkM0ghvhoG5OZ8b3tVo3NXuGhoVCg1cJpo,1289
55
55
  langgraph_api/js/remote.py,sha256=utq7tjSFUf0zPLDFgC9lnsGKrtX3EVEX6IcNCc9Q1yM,35934
56
56
  langgraph_api/js/schema.py,sha256=7idnv7URlYUdSNMBXQcw7E4SxaPxCq_Oxwnlml8q5ik,408
57
57
  langgraph_api/js/sse.py,sha256=lsfp4nyJyA1COmlKG9e2gJnTttf_HGCB5wyH8OZBER8,4105
58
58
  langgraph_api/js/tsconfig.json,sha256=imCYqVnqFpaBoZPx8k1nO4slHIWBFsSlmCYhO73cpBs,341
59
59
  langgraph_api/js/ui.py,sha256=XNT8iBcyT8XmbIqSQUWd-j_00HsaWB2vRTVabwFBkik,2439
60
- langgraph_api/js/yarn.lock,sha256=qtnJQjwX8OUQVzsh51N1imtjYGg5RCI9xkg5n5VZMKI,84019
60
+ langgraph_api/js/yarn.lock,sha256=eBrRB9ryern6NBwfZ2LAtsKw7-DjbKIDjDnv58jtByc,84019
61
61
  langgraph_api/js/src/graph.mts,sha256=9zTQNdtanI_CFnOwNRoamoCVHHQHGbNlbm91aRxDeOc,2675
62
62
  langgraph_api/js/src/load.hooks.mjs,sha256=xNVHq75W0Lk6MUKl1pQYrx-wtQ8_neiUyI6SO-k0ecM,2235
63
63
  langgraph_api/js/src/preload.mjs,sha256=ORV7xwMuZcXWL6jQxNAcCYp8GZVYIvVJbUhmle8jbno,759
@@ -70,16 +70,16 @@ langgraph_api/middleware/http_logger.py,sha256=aj4mdisRobFePkD3Iy6-w_Mujwx4TQRaE
70
70
  langgraph_api/middleware/private_network.py,sha256=eYgdyU8AzU2XJu362i1L8aSFoQRiV7_aLBPw7_EgeqI,2111
71
71
  langgraph_api/middleware/request_id.py,sha256=jBaL-zRLIYuGkYBz1poSH35ld_GDRuiMR5CyIpzKJt8,1025
72
72
  langgraph_api/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
73
- langgraph_api/models/run.py,sha256=kVdxF239sVmdvXUZNBL-GV0-euZO-Ca2Jz8qseNycKM,13362
73
+ langgraph_api/models/run.py,sha256=vmNTqM1owx1LF7AIzW7Uo1VFFhGC2x4o6mvz5ax1zOk,13545
74
74
  langgraph_api/tunneling/cloudflare.py,sha256=iKb6tj-VWPlDchHFjuQyep2Dpb-w2NGfJKt-WJG9LH0,3650
75
75
  langgraph_license/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
76
76
  langgraph_license/validation.py,sha256=ZKraAVJArAABKqrmHN-EN18ncoNUmRm500Yt1Sc7tUA,537
77
77
  langgraph_runtime/__init__.py,sha256=O4GgSmu33c-Pr8Xzxj_brcK5vkm70iNTcyxEjICFZxA,1075
78
78
  LICENSE,sha256=ZPwVR73Biwm3sK6vR54djCrhaRiM4cAD2zvOQZV8Xis,3859
79
79
  logging.json,sha256=3RNjSADZmDq38eHePMm1CbP6qZ71AmpBtLwCmKU9Zgo,379
80
- openapi.json,sha256=ZMY9UXZJYiFK59z8QmDxVZ7LV6KonQbHzG-D5h-ZTYE,135412
81
- langgraph_api-0.2.30.dist-info/METADATA,sha256=O5OFqZfihKkP1eKHlbey1pBYaXl7QbVVZM8buR4uBzg,3892
82
- langgraph_api-0.2.30.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
83
- langgraph_api-0.2.30.dist-info/entry_points.txt,sha256=hGedv8n7cgi41PypMfinwS_HfCwA7xJIfS0jAp8htV8,78
84
- langgraph_api-0.2.30.dist-info/licenses/LICENSE,sha256=ZPwVR73Biwm3sK6vR54djCrhaRiM4cAD2zvOQZV8Xis,3859
85
- langgraph_api-0.2.30.dist-info/RECORD,,
80
+ openapi.json,sha256=_4GFDqbq1X9vD4_FxwahuVODJMOHx-U76gkY4rdy3DA,138189
81
+ langgraph_api-0.2.34.dist-info/METADATA,sha256=losRmo3ncbBzvQBaZo2v_5-EA6B01bCLnBOBQAsPVno,3892
82
+ langgraph_api-0.2.34.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
83
+ langgraph_api-0.2.34.dist-info/entry_points.txt,sha256=hGedv8n7cgi41PypMfinwS_HfCwA7xJIfS0jAp8htV8,78
84
+ langgraph_api-0.2.34.dist-info/licenses/LICENSE,sha256=ZPwVR73Biwm3sK6vR54djCrhaRiM4cAD2zvOQZV8Xis,3859
85
+ langgraph_api-0.2.34.dist-info/RECORD,,
openapi.json CHANGED
@@ -886,73 +886,73 @@
886
886
  }
887
887
  }
888
888
  },
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"
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
- "name": "checkpoint_id",
918
- "in": "path"
919
- },
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."
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
- "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"
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
- "422": {
944
- "description": "Validation Error",
945
- "content": {
946
- "application/json": {
947
- "schema": {
948
- "$ref": "#/components/schemas/ErrorResponse"
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. Only output produced after this endpoint is called will be streamed.",
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"],