langgraph-api 0.2.68__py3-none-any.whl → 0.2.70__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.68"
1
+ __version__ = "0.2.70"
langgraph_api/api/runs.py CHANGED
@@ -548,14 +548,19 @@ async def search_crons(request: ApiRequest):
548
548
  validate_uuid(thread_id, "Invalid thread ID: must be a UUID")
549
549
 
550
550
  async with connect() as conn:
551
- crons_iter = await Crons.search(
551
+ crons_iter, total = await Crons.search(
552
552
  conn,
553
553
  assistant_id=assistant_id,
554
554
  thread_id=thread_id,
555
555
  limit=int(payload.get("limit", 10)),
556
556
  offset=int(payload.get("offset", 0)),
557
+ sort_by=payload.get("sort_by"),
558
+ sort_order=payload.get("sort_order"),
557
559
  )
558
- return ApiResponse([cron async for cron in crons_iter])
560
+ return ApiResponse(
561
+ [cron async for cron in crons_iter],
562
+ headers={"X-Pagination-Total": str(total)},
563
+ )
559
564
 
560
565
 
561
566
  runs_routes = [
langgraph_api/errors.py CHANGED
@@ -50,3 +50,9 @@ class UserInterrupt(Exception):
50
50
  class UserRollback(UserInterrupt):
51
51
  def __init__(self):
52
52
  super().__init__("User requested rollback of the run")
53
+
54
+
55
+ class UserTimeout(Exception):
56
+ def __init__(self, timeout_error: TimeoutError):
57
+ super().__init__(timeout_error)
58
+ self.timeout_error = timeout_error
langgraph_api/schema.py CHANGED
@@ -170,6 +170,8 @@ class Cron(TypedDict):
170
170
 
171
171
  cron_id: UUID
172
172
  """The ID of the cron."""
173
+ assistant_id: UUID
174
+ """The ID of the assistant."""
173
175
  thread_id: UUID | None
174
176
  """The ID of the thread."""
175
177
  end_time: datetime | None
@@ -180,8 +182,14 @@ class Cron(TypedDict):
180
182
  """The time the cron was created."""
181
183
  updated_at: datetime
182
184
  """The last time the cron was updated."""
185
+ user_id: UUID | None
186
+ """The ID of the user."""
183
187
  payload: Fragment
184
188
  """The run payload to use for creating new run."""
189
+ next_run_date: datetime
190
+ """The next run date of the cron."""
191
+ metadata: Fragment
192
+ """The cron metadata."""
185
193
 
186
194
 
187
195
  class ThreadUpdateResponse(TypedDict):
langgraph_api/worker.py CHANGED
@@ -16,12 +16,12 @@ from langgraph_api.config import (
16
16
  BG_JOB_MAX_RETRIES,
17
17
  BG_JOB_TIMEOUT_SECS,
18
18
  )
19
- from langgraph_api.errors import UserInterrupt, UserRollback
19
+ from langgraph_api.errors import UserInterrupt, UserRollback, UserTimeout
20
20
  from langgraph_api.js.errors import RemoteException
21
21
  from langgraph_api.metadata import incr_runs
22
22
  from langgraph_api.schema import Run
23
23
  from langgraph_api.state import state_snapshot_to_thread_state
24
- from langgraph_api.stream import astream_state, consume
24
+ from langgraph_api.stream import AnyStream, astream_state, consume
25
25
  from langgraph_api.utils import with_user
26
26
  from langgraph_runtime.database import connect
27
27
  from langgraph_runtime.ops import Runs, Threads
@@ -79,8 +79,11 @@ async def worker(
79
79
  "__request_start_time_ms__"
80
80
  )
81
81
  after_seconds = run["kwargs"]["config"]["configurable"].get("__after_seconds__", 0)
82
+ run_started_at_dt = datetime.now(UTC)
83
+ run_started_at = run_started_at_dt.isoformat()
84
+ run_ended_at_dt: datetime | None = None
82
85
  run_ended_at: str | None = None
83
- run_started_at = datetime.now(UTC)
86
+
84
87
  # Note that "created_at" is inclusive of the `after_seconds`
85
88
  run_creation_ms = (
86
89
  int(
@@ -103,13 +106,13 @@ async def worker(
103
106
  "request_id": _get_request_id(run),
104
107
  }
105
108
  )
106
- run_stream_started_at = datetime.now(UTC)
109
+ run_stream_started_at_dt = datetime.now(UTC)
107
110
  await logger.ainfo(
108
111
  "Starting background run",
109
- run_started_at=run_started_at.isoformat(),
112
+ run_started_at=run_started_at,
110
113
  run_creation_ms=run_creation_ms,
111
- run_queue_ms=ms(run_started_at, run["created_at"]),
112
- run_stream_start_ms=ms(run_stream_started_at, run_started_at),
114
+ run_queue_ms=ms(run_started_at_dt, run["created_at"]),
115
+ run_stream_start_ms=ms(run_stream_started_at_dt, run_started_at_dt),
113
116
  )
114
117
 
115
118
  def on_checkpoint(checkpoint_arg: CheckpointPayload):
@@ -123,6 +126,21 @@ async def worker(
123
126
  task.update(task_result)
124
127
  break
125
128
 
129
+ # Wrap the graph execution to separate user errors from server errors
130
+ async def wrap_user_errors(stream: AnyStream, run_id: str, resumable: bool):
131
+ try:
132
+ await consume(stream, run_id, resumable)
133
+ except Exception as e:
134
+ logger.info(
135
+ f"Run encountered an error in graph: {type(e)}({e})",
136
+ exc_info=e,
137
+ )
138
+ # TimeoutError is a special case where we rely on asyncio.wait_for to timeout runs
139
+ # Convert user TimeoutErrors to a custom class so we can distinguish and later convert back
140
+ if isinstance(e, TimeoutError):
141
+ raise UserTimeout(e) from e
142
+ raise
143
+
126
144
  async with Runs.enter(run_id, main_loop) as done:
127
145
  # attempt the run
128
146
  try:
@@ -163,25 +181,9 @@ async def worker(
163
181
  on_task_result=on_task_result,
164
182
  )
165
183
  await asyncio.wait_for(
166
- consume(stream, run_id, resumable),
184
+ wrap_user_errors(stream, run_id, resumable),
167
185
  BG_JOB_TIMEOUT_SECS,
168
186
  )
169
- run_ended_at_dt = datetime.now(UTC)
170
- run_ended_at = run_ended_at_dt.isoformat()
171
- await logger.ainfo(
172
- "Background run succeeded",
173
- run_id=str(run_id),
174
- run_attempt=attempt,
175
- run_created_at=run_created_at,
176
- run_started_at=run_started_at.isoformat(),
177
- run_ended_at=run_ended_at,
178
- run_exec_ms=ms(run_ended_at_dt, run_started_at),
179
- run_completed_in_ms=(
180
- int((run_ended_at_dt.timestamp() * 1_000) - request_created_at)
181
- if request_created_at is not None
182
- else None
183
- ),
184
- )
185
187
  except (Exception, asyncio.CancelledError) as ee:
186
188
  exception = ee
187
189
  except BaseException as eee:
@@ -192,11 +194,33 @@ async def worker(
192
194
  exception=str(eee),
193
195
  )
194
196
  raise
197
+ finally:
198
+ run_ended_at_dt = datetime.now(UTC)
199
+ run_ended_at = run_ended_at_dt.isoformat()
195
200
 
196
201
  # handle exceptions and set status
197
202
  async with connect() as conn:
203
+ log_info = {
204
+ "run_id": str(run_id),
205
+ "run_attempt": attempt,
206
+ "run_created_at": run_created_at,
207
+ "run_started_at": run_started_at,
208
+ "run_ended_at": run_ended_at,
209
+ "run_exec_ms": ms(run_ended_at_dt, run_started_at_dt),
210
+ "run_completed_in_ms": (
211
+ int((run_ended_at_dt.timestamp() * 1_000) - request_created_at)
212
+ if request_created_at is not None
213
+ else None
214
+ ),
215
+ }
216
+
198
217
  if exception is None:
199
218
  status = "success"
219
+
220
+ await logger.ainfo(
221
+ "Background run succeeded",
222
+ **log_info,
223
+ )
200
224
  # If a stateful run succeeded but no checkpoint was returned, likely
201
225
  # there was a retriable exception that resumed right at the end
202
226
  if checkpoint is None and not temporary:
@@ -222,56 +246,28 @@ async def worker(
222
246
  )
223
247
  elif isinstance(exception, TimeoutError):
224
248
  status = "timeout"
225
- run_ended_at = datetime.now(UTC).isoformat()
226
249
  await logger.awarning(
227
250
  "Background run timed out",
228
- run_id=str(run_id),
229
- run_attempt=attempt,
230
- run_created_at=run_created_at,
231
- run_started_at=run_started_at.isoformat(),
232
- run_ended_at=run_ended_at,
233
- run_exec_ms=ms(datetime.now(UTC), run_started_at),
234
- run_completed_in_ms=(
235
- int((run_ended_at_dt.timestamp() * 1_000) - request_created_at)
236
- if request_created_at is not None
237
- else None
238
- ),
251
+ **log_info,
239
252
  )
240
253
  await Threads.set_joint_status(
241
254
  conn, run["thread_id"], run_id, status, checkpoint=checkpoint
242
255
  )
243
256
  elif isinstance(exception, UserRollback):
244
257
  status = "rollback"
245
- run_ended_at_dt = datetime.now(UTC)
246
- run_ended_at = run_ended_at_dt.isoformat()
247
258
  try:
248
259
  await Threads.set_joint_status(
249
260
  conn, run["thread_id"], run_id, status, checkpoint=checkpoint
250
261
  )
251
262
  await logger.ainfo(
252
263
  "Background run rolled back",
253
- run_id=str(run_id),
254
- run_attempt=attempt,
255
- run_created_at=run_created_at,
256
- run_started_at=run_started_at.isoformat(),
257
- run_ended_at=run_ended_at,
258
- run_exec_ms=ms(run_ended_at_dt, run_started_at),
259
- run_completed_in_ms=(
260
- int(
261
- (run_ended_at_dt.timestamp() * 1_000)
262
- - request_created_at
263
- )
264
- if request_created_at is not None
265
- else None
266
- ),
264
+ **log_info,
267
265
  )
268
266
  except HTTPException as e:
269
267
  if e.status_code == 404:
270
268
  await logger.ainfo(
271
269
  "Ignoring rollback error for missing run",
272
- run_id=str(run_id),
273
- run_attempt=attempt,
274
- run_created_at=run_created_at,
270
+ **log_info,
275
271
  )
276
272
  else:
277
273
  raise
@@ -279,54 +275,32 @@ async def worker(
279
275
  checkpoint = None # reset the checkpoint
280
276
  elif isinstance(exception, UserInterrupt):
281
277
  status = "interrupted"
282
- run_ended_at_dt = datetime.now(UTC)
283
- run_ended_at = run_ended_at_dt.isoformat()
284
278
  await logger.ainfo(
285
279
  "Background run interrupted",
286
- run_id=str(run_id),
287
- run_attempt=attempt,
288
- run_created_at=run_created_at,
289
- run_started_at=run_started_at.isoformat(),
290
- run_ended_at=run_ended_at,
291
- run_exec_ms=ms(run_ended_at_dt, run_started_at),
292
- run_completed_in_ms=(
293
- int((run_ended_at_dt.timestamp() * 1_000) - request_created_at)
294
- if request_created_at is not None
295
- else None
296
- ),
280
+ **log_info,
297
281
  )
298
282
  await Threads.set_joint_status(
299
283
  conn, run["thread_id"], run_id, status, checkpoint, exception
300
284
  )
301
285
  elif isinstance(exception, ALL_RETRIABLE_EXCEPTIONS):
302
286
  status = "retry"
303
- run_ended_at_dt = datetime.now(UTC)
304
- run_ended_at = run_ended_at_dt.isoformat()
305
287
  await logger.awarning(
306
288
  f"Background run failed, will retry. Exception: {type(exception)}({exception})",
307
- exc_info=True,
308
- run_id=str(run_id),
309
- run_attempt=attempt,
310
- run_created_at=run_created_at,
311
- run_started_at=run_started_at.isoformat(),
312
- run_ended_at=run_ended_at,
313
- run_exec_ms=ms(run_ended_at_dt, run_started_at),
289
+ **log_info,
314
290
  )
315
291
  # Don't update thread status yet.
316
292
  await Runs.set_status(conn, run_id, "pending")
317
293
  else:
318
294
  status = "error"
319
- run_ended_at_dt = datetime.now(UTC)
320
- run_ended_at = run_ended_at_dt.isoformat()
295
+
296
+ # Convert UserTimeout to TimeoutError for customers
297
+ if isinstance(exception, UserTimeout):
298
+ exception = exception.timeout_error
299
+
321
300
  await logger.aexception(
322
301
  f"Background run failed. Exception: {type(exception)}({exception})",
323
302
  exc_info=not isinstance(exception, RemoteException),
324
- run_id=str(run_id),
325
- run_attempt=attempt,
326
- run_created_at=run_created_at,
327
- run_started_at=run_started_at.isoformat(),
328
- run_ended_at=run_ended_at,
329
- run_exec_ms=ms(run_ended_at_dt, run_started_at),
303
+ **log_info,
330
304
  )
331
305
  await Threads.set_joint_status(
332
306
  conn, run["thread_id"], run_id, status, checkpoint, exception
@@ -363,7 +337,7 @@ async def worker(
363
337
  exception=exception,
364
338
  run=run,
365
339
  webhook=webhook,
366
- run_started_at=run_started_at.isoformat(),
340
+ run_started_at=run_started_at,
367
341
  run_ended_at=run_ended_at,
368
342
  )
369
343
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: langgraph-api
3
- Version: 0.2.68
3
+ Version: 0.2.70
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
@@ -12,7 +12,7 @@ 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
14
  Requires-Dist: langgraph-runtime-inmem<0.4,>=0.3.0
15
- Requires-Dist: langgraph-sdk>=0.1.66
15
+ Requires-Dist: langgraph-sdk>=0.1.71
16
16
  Requires-Dist: langgraph>=0.3.27
17
17
  Requires-Dist: langsmith>=0.3.45
18
18
  Requires-Dist: orjson>=3.9.7
@@ -1,11 +1,11 @@
1
- langgraph_api/__init__.py,sha256=VhcIWUc8CMbglTSx2PRXJQXLxGPIWajEYdegulJBOPk,23
1
+ langgraph_api/__init__.py,sha256=nvBmUT-8UzEzR76L42ZDv_0mtdkVtoC42_s4j3hsMkk,23
2
2
  langgraph_api/asgi_transport.py,sha256=eqifhHxNnxvI7jJqrY1_8RjL4Fp9NdN4prEub2FWBt8,5091
3
3
  langgraph_api/asyncio.py,sha256=Odnc6mAJIGF3eFWT8Xcrg2Zam7FwzXkfCWEHaXfrzQQ,9371
4
4
  langgraph_api/cli.py,sha256=13mKb-WT7fGx_yqcbWITPB9ICEHCrPzIP1ddZ5RbXbY,16015
5
5
  langgraph_api/command.py,sha256=3O9v3i0OPa96ARyJ_oJbLXkfO8rPgDhLCswgO9koTFA,768
6
6
  langgraph_api/config.py,sha256=jmtO5LXubet2Hl7S2tF2BRyB_q2yqCzFqCwN7n6za4Y,11727
7
7
  langgraph_api/cron_scheduler.py,sha256=i87j4pJrcsmsqMKeKUs69gaAjrGaSM3pM3jnXdN5JDQ,2630
8
- langgraph_api/errors.py,sha256=Bu_i5drgNTyJcLiyrwVE_6-XrSU50BHf9TDpttki9wQ,1690
8
+ langgraph_api/errors.py,sha256=zlnl3xXIwVG0oGNKKpXf1an9Rn_SBDHSyhe53hU6aLw,1858
9
9
  langgraph_api/graph.py,sha256=t18rq0NHHRILUI5cONhKPzKhbqLGn6_BRytiEh0gdcg,23561
10
10
  langgraph_api/http.py,sha256=gYbxxjY8aLnsXeJymcJ7G7Nj_yToOGpPYQqmZ1_ggfA,5240
11
11
  langgraph_api/logging.py,sha256=Do62kNJtY7Ns7q7XrP2VIxho3c85jt8_l3yfRtqM7xM,4370
@@ -13,7 +13,7 @@ langgraph_api/metadata.py,sha256=Gx0b6YszLRjdWLDVN8OcVgC_YYQG_nQitPfUfgQx1w8,464
13
13
  langgraph_api/patch.py,sha256=Dgs0PXHytekX4SUL6KsjjN0hHcOtGLvv1GRGbh6PswU,1408
14
14
  langgraph_api/queue_entrypoint.py,sha256=hC8j-A4cUxibusiiPJBlK0mkmChNZxNcXn5GVwL0yic,4889
15
15
  langgraph_api/route.py,sha256=4VBkJMeusfiZtLzyUaKm1HwLHTq0g15y2CRiRhM6xyA,4773
16
- langgraph_api/schema.py,sha256=2711t4PIBk5dky4gmMndrTRC9CVvAgH47C9FKDxhkBo,5444
16
+ langgraph_api/schema.py,sha256=a6it0h9ku4jrTXiW9MhnGok_wignyQ4cXBra67FiryM,5678
17
17
  langgraph_api/serde.py,sha256=8fQXg7T7RVUqj_jgOoSOJrWVpQDW0qJKjAjSsEhPHo4,4803
18
18
  langgraph_api/server.py,sha256=Z_VL-kIphybTRDWBIqHMfRhgCmAFyTRqAGlgnHQF0Zg,6973
19
19
  langgraph_api/sse.py,sha256=F7swfjKBDrlUmXZ_dWuDVHtp-3o1Cpjq1lwp0bJD-nw,4223
@@ -24,13 +24,13 @@ langgraph_api/thread_ttl.py,sha256=-Ox8NFHqUH3wGNdEKMIfAXUubY5WGifIgCaJ7npqLgw,1
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=2LZUzcZGyK8_-ajmGHdoKhU7HT0SdBPLDLEJlBDyz2w,16021
27
+ langgraph_api/worker.py,sha256=Cl1sS63HYngQ92vkPFef6qYp-LLIJQyExqNzBlpVl5E,14145
28
28
  langgraph_api/api/__init__.py,sha256=YVzpbn5IQotvuuLG9fhS9QMrxXfP4s4EpEMG0n4q3Nw,5625
29
29
  langgraph_api/api/assistants.py,sha256=6IPVKQBlI95-Z4nYdqBY9st9oynGJAocL67cwnDaZCk,15744
30
30
  langgraph_api/api/mcp.py,sha256=RvRYgANqRzNQzSmgjNkq4RlKTtoEJYil04ot9lsmEtE,14352
31
31
  langgraph_api/api/meta.py,sha256=MU9Ehdo2M8oaxGVBXVQFNRP6qSTXyrsGXFcndRlnvIE,3924
32
32
  langgraph_api/api/openapi.py,sha256=362m6Ny8wOwZ6HrDK9JAVUzPkyLYWKeV1E71hPOaA0U,11278
33
- langgraph_api/api/runs.py,sha256=9jU9C4myBhgZXyvR9MzNn9KrpNo7DvWbg8uNeWzSmKE,19524
33
+ langgraph_api/api/runs.py,sha256=1rNUbFleakTYAqG20cGtpWyY2TS5EoVgT4Pxe1AQ68E,19692
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
@@ -85,9 +85,9 @@ langgraph_runtime/retry.py,sha256=V0duD01fO7GUQ_btQkp1aoXcEOFhXooGVP6q4yMfuyY,11
85
85
  langgraph_runtime/store.py,sha256=7mowndlsIroGHv3NpTSOZDJR0lCuaYMBoTnTrewjslw,114
86
86
  LICENSE,sha256=ZPwVR73Biwm3sK6vR54djCrhaRiM4cAD2zvOQZV8Xis,3859
87
87
  logging.json,sha256=3RNjSADZmDq38eHePMm1CbP6qZ71AmpBtLwCmKU9Zgo,379
88
- openapi.json,sha256=J4ICw3-W3LdxQOfsTuzcZVYt3e9UFeLb6oPr_a-5iHU,141823
89
- langgraph_api-0.2.68.dist-info/METADATA,sha256=tMf14kWcDmBYEZlH7COkzGx7xq6WD4g1-9m3c7d0AH8,3891
90
- langgraph_api-0.2.68.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
91
- langgraph_api-0.2.68.dist-info/entry_points.txt,sha256=hGedv8n7cgi41PypMfinwS_HfCwA7xJIfS0jAp8htV8,78
92
- langgraph_api-0.2.68.dist-info/licenses/LICENSE,sha256=ZPwVR73Biwm3sK6vR54djCrhaRiM4cAD2zvOQZV8Xis,3859
93
- langgraph_api-0.2.68.dist-info/RECORD,,
88
+ openapi.json,sha256=NVgY0hdCu6v5anNus9I-CVYKKcrDLKd1qhILy-kQpq8,142590
89
+ langgraph_api-0.2.70.dist-info/METADATA,sha256=nbh82X9tCCJpITWyy2Ex8uGZ4WhQHoaF0rly6mvjQkU,3891
90
+ langgraph_api-0.2.70.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
91
+ langgraph_api-0.2.70.dist-info/entry_points.txt,sha256=hGedv8n7cgi41PypMfinwS_HfCwA7xJIfS0jAp8htV8,78
92
+ langgraph_api-0.2.70.dist-info/licenses/LICENSE,sha256=ZPwVR73Biwm3sK6vR54djCrhaRiM4cAD2zvOQZV8Xis,3859
93
+ langgraph_api-0.2.70.dist-info/RECORD,,
openapi.json CHANGED
@@ -3243,6 +3243,12 @@
3243
3243
  "title": "Schedule",
3244
3244
  "description": "The cron schedule to execute this job on."
3245
3245
  },
3246
+ "end_time": {
3247
+ "type": "string",
3248
+ "format": "date-time",
3249
+ "title": "End Time",
3250
+ "description": "The end date to stop running the cron."
3251
+ },
3246
3252
  "assistant_id": {
3247
3253
  "anyOf": [
3248
3254
  {
@@ -3392,6 +3398,20 @@
3392
3398
  "description": "The number of results to skip.",
3393
3399
  "default": 0,
3394
3400
  "minimum": 0
3401
+ },
3402
+ "sort_by": {
3403
+ "type": "string",
3404
+ "title": "Sort By",
3405
+ "description": "The field to sort by.",
3406
+ "default": "created_at",
3407
+ "enum": ["cron_id", "assistant_id", "thread_id", "next_run_date", "end_time", "created_at", "updated_at"]
3408
+ },
3409
+ "sort_order": {
3410
+ "type": "string",
3411
+ "title": "Sort Order",
3412
+ "description": "The order to sort by.",
3413
+ "default": "desc",
3414
+ "enum": ["asc", "desc"]
3395
3415
  }
3396
3416
  },
3397
3417
  "type": "object",
@@ -3513,13 +3533,14 @@
3513
3533
  "type": "string",
3514
3534
  "enum": [
3515
3535
  "pending",
3536
+ "running",
3516
3537
  "error",
3517
3538
  "success",
3518
3539
  "timeout",
3519
3540
  "interrupted"
3520
3541
  ],
3521
3542
  "title": "Status",
3522
- "description": "The status of the run. One of 'pending', 'error', 'success', 'timeout', 'interrupted'."
3543
+ "description": "The status of the run. One of 'pending', 'running', 'error', 'success', 'timeout', 'interrupted'."
3523
3544
  },
3524
3545
  "metadata": {
3525
3546
  "type": "object",