langgraph-api 0.2.39__tar.gz → 0.2.42__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.

Files changed (92) hide show
  1. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/PKG-INFO +1 -1
  2. langgraph_api-0.2.42/langgraph_api/__init__.py +1 -0
  3. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/api/runs.py +7 -0
  4. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/middleware/request_id.py +2 -0
  5. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/models/run.py +15 -2
  6. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/worker.py +62 -13
  7. langgraph_api-0.2.39/langgraph_api/__init__.py +0 -1
  8. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/.gitignore +0 -0
  9. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/LICENSE +0 -0
  10. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/Makefile +0 -0
  11. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/README.md +0 -0
  12. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/benchmark/weather.js +0 -0
  13. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/constraints.txt +0 -0
  14. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/forbidden.txt +0 -0
  15. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/healthcheck.py +0 -0
  16. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/api/__init__.py +0 -0
  17. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/api/assistants.py +0 -0
  18. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/api/mcp.py +0 -0
  19. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/api/meta.py +0 -0
  20. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/api/openapi.py +0 -0
  21. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/api/store.py +0 -0
  22. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/api/threads.py +0 -0
  23. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/api/ui.py +0 -0
  24. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/asgi_transport.py +0 -0
  25. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/asyncio.py +0 -0
  26. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/auth/__init__.py +0 -0
  27. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/auth/custom.py +0 -0
  28. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/auth/langsmith/__init__.py +0 -0
  29. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/auth/langsmith/backend.py +0 -0
  30. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/auth/langsmith/client.py +0 -0
  31. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/auth/middleware.py +0 -0
  32. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/auth/noop.py +0 -0
  33. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/auth/studio_user.py +0 -0
  34. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/cli.py +0 -0
  35. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/command.py +0 -0
  36. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/config.py +0 -0
  37. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/cron_scheduler.py +0 -0
  38. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/errors.py +0 -0
  39. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/graph.py +0 -0
  40. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/http.py +0 -0
  41. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/js/.gitignore +0 -0
  42. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/js/.prettierrc +0 -0
  43. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/js/__init__.py +0 -0
  44. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/js/base.py +0 -0
  45. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/js/build.mts +0 -0
  46. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/js/client.http.mts +0 -0
  47. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/js/client.mts +0 -0
  48. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/js/errors.py +0 -0
  49. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/js/global.d.ts +0 -0
  50. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/js/package.json +0 -0
  51. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/js/remote.py +0 -0
  52. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/js/schema.py +0 -0
  53. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/js/src/graph.mts +0 -0
  54. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/js/src/load.hooks.mjs +0 -0
  55. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/js/src/preload.mjs +0 -0
  56. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/js/src/utils/files.mts +0 -0
  57. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/js/src/utils/importMap.mts +0 -0
  58. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/js/src/utils/pythonSchemas.mts +0 -0
  59. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/js/src/utils/serde.mts +0 -0
  60. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/js/sse.py +0 -0
  61. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/js/tsconfig.json +0 -0
  62. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/js/ui.py +0 -0
  63. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/js/yarn.lock +0 -0
  64. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/logging.py +0 -0
  65. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/metadata.py +0 -0
  66. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/middleware/__init__.py +0 -0
  67. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/middleware/http_logger.py +0 -0
  68. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/middleware/private_network.py +0 -0
  69. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/models/__init__.py +0 -0
  70. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/patch.py +0 -0
  71. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/queue_entrypoint.py +0 -0
  72. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/route.py +0 -0
  73. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/schema.py +0 -0
  74. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/serde.py +0 -0
  75. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/server.py +0 -0
  76. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/sse.py +0 -0
  77. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/state.py +0 -0
  78. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/store.py +0 -0
  79. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/stream.py +0 -0
  80. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/thread_ttl.py +0 -0
  81. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/tunneling/cloudflare.py +0 -0
  82. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/utils.py +0 -0
  83. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/validation.py +0 -0
  84. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_api/webhook.py +0 -0
  85. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_license/__init__.py +0 -0
  86. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_license/validation.py +0 -0
  87. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/langgraph_runtime/__init__.py +0 -0
  88. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/logging.json +0 -0
  89. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/openapi.json +0 -0
  90. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/pyproject.toml +0 -0
  91. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/scripts/create_license.py +0 -0
  92. {langgraph_api-0.2.39 → langgraph_api-0.2.42}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: langgraph-api
3
- Version: 0.2.39
3
+ Version: 0.2.42
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
@@ -0,0 +1 @@
1
+ __version__ = "0.2.42"
@@ -38,6 +38,7 @@ async def create_run(request: ApiRequest):
38
38
  thread_id,
39
39
  payload,
40
40
  request.headers,
41
+ request_start_time=request.scope.get("request_start_time_ms"),
41
42
  )
42
43
  return ApiResponse(
43
44
  run,
@@ -55,6 +56,7 @@ async def create_stateless_run(request: ApiRequest):
55
56
  None,
56
57
  payload,
57
58
  request.headers,
59
+ request_start_time=request.scope.get("request_start_time_ms"),
58
60
  )
59
61
  return ApiResponse(
60
62
  run,
@@ -75,6 +77,7 @@ async def create_stateless_run_batch(request: ApiRequest):
75
77
  payload,
76
78
  request.headers,
77
79
  barrier,
80
+ request_start_time=request.scope.get("request_start_time_ms"),
78
81
  )
79
82
  for payload in batch_payload
80
83
  ]
@@ -100,6 +103,7 @@ async def stream_run(
100
103
  payload,
101
104
  request.headers,
102
105
  run_id=run_id,
106
+ request_start_time=request.scope.get("request_start_time_ms"),
103
107
  )
104
108
  except Exception:
105
109
  if not sub.cancelled():
@@ -139,6 +143,7 @@ async def stream_run_stateless(
139
143
  payload,
140
144
  request.headers,
141
145
  run_id=run_id,
146
+ request_start_time=request.scope.get("request_start_time_ms"),
142
147
  )
143
148
  except Exception:
144
149
  if not sub.cancelled():
@@ -178,6 +183,7 @@ async def wait_run(request: ApiRequest):
178
183
  payload,
179
184
  request.headers,
180
185
  run_id=run_id,
186
+ request_start_time=request.scope.get("request_start_time_ms"),
181
187
  )
182
188
  except Exception:
183
189
  if not sub.cancelled():
@@ -250,6 +256,7 @@ async def wait_run_stateless(request: ApiRequest):
250
256
  payload,
251
257
  request.headers,
252
258
  run_id=run_id,
259
+ request_start_time=request.scope.get("request_start_time_ms"),
253
260
  )
254
261
  except Exception:
255
262
  if not sub.cancelled():
@@ -1,6 +1,7 @@
1
1
  """Middleware to handle setting request IDs for logging."""
2
2
 
3
3
  import re
4
+ import time
4
5
  import uuid
5
6
 
6
7
  from starlette.types import ASGIApp, Receive, Scope, Send
@@ -27,4 +28,5 @@ class RequestIdMiddleware:
27
28
  if request_id is None:
28
29
  request_id = str(uuid.uuid4()).encode()
29
30
  scope["headers"].append((b"x-request-id", request_id))
31
+ scope["request_start_time_ms"] = int(time.time() * 1000)
30
32
  await self.app(scope, receive, send)
@@ -1,6 +1,7 @@
1
1
  import asyncio
2
2
  import functools
3
3
  import re
4
+ import time
4
5
  import urllib.parse
5
6
  import uuid
6
7
  from collections.abc import Mapping, Sequence
@@ -249,6 +250,7 @@ async def create_valid_run(
249
250
  headers: Mapping[str, str],
250
251
  barrier: asyncio.Barrier | None = None,
251
252
  run_id: UUID | None = None,
253
+ request_start_time: float | None = None,
252
254
  ) -> Run:
253
255
  request_id = headers.get("x-request-id") # Will be null in the crons scheduler.
254
256
  (
@@ -293,6 +295,11 @@ async def create_valid_run(
293
295
  user_id = None
294
296
  if not configurable.get("langgraph_request_id"):
295
297
  configurable["langgraph_request_id"] = request_id
298
+ if request_start_time:
299
+ configurable["__request_start_time_ms__"] = request_start_time
300
+ after_seconds = payload.get("after_seconds", 0)
301
+ configurable["__after_seconds__"] = after_seconds
302
+ put_time_start = time.time()
296
303
  run_coro = Runs.put(
297
304
  conn,
298
305
  assistant_id,
@@ -317,7 +324,7 @@ async def create_valid_run(
317
324
  run_id=run_id,
318
325
  multitask_strategy=multitask_strategy,
319
326
  prevent_insert_if_inflight=prevent_insert_if_inflight,
320
- after_seconds=payload.get("after_seconds", 0),
327
+ after_seconds=after_seconds,
321
328
  if_not_exists=payload.get("if_not_exists", "reject"),
322
329
  )
323
330
  run_ = await run_coro
@@ -344,8 +351,14 @@ async def create_valid_run(
344
351
  multitask_strategy=multitask_strategy,
345
352
  stream_mode=stream_mode,
346
353
  temporary=temporary,
347
- after_seconds=payload.get("after_seconds", 0),
354
+ after_seconds=after_seconds,
348
355
  if_not_exists=payload.get("if_not_exists", "reject"),
356
+ run_create_ms=(
357
+ int(time.time() * 1_000) - request_start_time
358
+ if request_start_time
359
+ else None
360
+ ),
361
+ run_put_ms=int((time.time() - put_time_start) * 1_000),
349
362
  )
350
363
  # inserted, proceed
351
364
  if multitask_strategy in ("interrupt", "rollback") and inflight_runs:
@@ -1,4 +1,5 @@
1
1
  import asyncio
2
+ import time
2
3
  from collections.abc import AsyncGenerator
3
4
  from contextlib import AsyncExitStack, asynccontextmanager
4
5
  from datetime import UTC, datetime
@@ -74,8 +75,21 @@ async def worker(
74
75
  exception: Exception | None = None
75
76
  status: str | None = None
76
77
  webhook = run["kwargs"].get("webhook", None)
77
- run_started_at = datetime.now(UTC)
78
+ request_created_at: int | None = run["kwargs"]["config"]["configurable"].get(
79
+ "__request_start_time_ms__"
80
+ )
81
+ after_seconds = run["kwargs"]["config"]["configurable"].get("__after_seconds__", 0)
78
82
  run_ended_at: str | None = None
83
+ run_started_at = datetime.now(UTC)
84
+ # Note that "created_at" is inclusive of the `after_seconds`
85
+ run_creation_ms = (
86
+ int(
87
+ ((run["created_at"].timestamp() - after_seconds) * 1_000)
88
+ - request_created_at
89
+ )
90
+ if request_created_at is not None
91
+ else None
92
+ )
79
93
 
80
94
  async with (
81
95
  connect() as conn,
@@ -95,11 +109,13 @@ async def worker(
95
109
  "request_id": _get_request_id(run),
96
110
  }
97
111
  )
98
-
112
+ run_stream_started_at = datetime.now(UTC)
99
113
  await logger.ainfo(
100
114
  "Starting background run",
101
115
  run_started_at=run_started_at.isoformat(),
116
+ run_creation_ms=run_creation_ms,
102
117
  run_queue_ms=ms(run_started_at, run["created_at"]),
118
+ run_stream_start_ms=ms(run_stream_started_at, run_started_at),
103
119
  )
104
120
 
105
121
  def on_checkpoint(checkpoint_arg: CheckpointPayload):
@@ -115,7 +131,15 @@ async def worker(
115
131
 
116
132
  try:
117
133
  if attempt > BG_JOB_MAX_RETRIES:
118
- await logger.aerror("Run exceeded max attempts", run_id=run["run_id"])
134
+ await logger.aerror(
135
+ "Run exceeded max attempts",
136
+ run_id=run["run_id"],
137
+ run_completed_in_ms=(
138
+ int((time.time() * 1_000) - request_created_at)
139
+ if request_created_at is not None
140
+ else None
141
+ ),
142
+ )
119
143
 
120
144
  error_message = (
121
145
  f"Run {run['run_id']} exceeded max attempts ({BG_JOB_MAX_RETRIES}).\n\n"
@@ -149,7 +173,8 @@ async def worker(
149
173
  consume(stream, run_id, resumable),
150
174
  BG_JOB_TIMEOUT_SECS,
151
175
  )
152
- run_ended_at = datetime.now(UTC).isoformat()
176
+ run_ended_at_dt = datetime.now(UTC)
177
+ run_ended_at = run_ended_at_dt.isoformat()
153
178
  await logger.ainfo(
154
179
  "Background run succeeded",
155
180
  run_id=str(run_id),
@@ -157,7 +182,12 @@ async def worker(
157
182
  run_created_at=run_created_at,
158
183
  run_started_at=run_started_at.isoformat(),
159
184
  run_ended_at=run_ended_at,
160
- run_exec_ms=ms(datetime.now(UTC), run_started_at),
185
+ run_exec_ms=ms(run_ended_at_dt, run_started_at),
186
+ run_completed_in_ms=(
187
+ int((run_ended_at_dt.timestamp() * 1_000) - request_created_at)
188
+ if request_created_at is not None
189
+ else None
190
+ ),
161
191
  )
162
192
  status = "success"
163
193
  await Runs.set_status(conn, run_id, "success")
@@ -173,12 +203,18 @@ async def worker(
173
203
  run_started_at=run_started_at.isoformat(),
174
204
  run_ended_at=run_ended_at,
175
205
  run_exec_ms=ms(datetime.now(UTC), run_started_at),
206
+ run_completed_in_ms=(
207
+ int((run_ended_at_dt.timestamp() * 1_000) - request_created_at)
208
+ if request_created_at is not None
209
+ else None
210
+ ),
176
211
  )
177
212
  await Runs.set_status(conn, run_id, "timeout")
178
213
  except UserRollback as e:
179
214
  exception = e
180
215
  status = "rollback"
181
- run_ended_at = datetime.now(UTC).isoformat()
216
+ run_ended_at_dt = datetime.now(UTC)
217
+ run_ended_at = run_ended_at_dt.isoformat()
182
218
  try:
183
219
  await Runs.delete(conn, run_id, thread_id=run["thread_id"])
184
220
  await logger.ainfo(
@@ -188,7 +224,12 @@ async def worker(
188
224
  run_created_at=run_created_at,
189
225
  run_started_at=run_started_at.isoformat(),
190
226
  run_ended_at=run_ended_at,
191
- run_exec_ms=ms(datetime.now(UTC), run_started_at),
227
+ run_exec_ms=ms(run_ended_at_dt, run_started_at),
228
+ run_completed_in_ms=(
229
+ int((run_ended_at_dt.timestamp() * 1_000) - request_created_at)
230
+ if request_created_at is not None
231
+ else None
232
+ ),
192
233
  )
193
234
 
194
235
  except InFailedSqlTransaction as e:
@@ -217,7 +258,8 @@ async def worker(
217
258
  except UserInterrupt as e:
218
259
  exception = e
219
260
  status = "interrupted"
220
- run_ended_at = datetime.now(UTC).isoformat()
261
+ run_ended_at_dt = datetime.now(UTC)
262
+ run_ended_at = run_ended_at_dt.isoformat()
221
263
  await logger.ainfo(
222
264
  "Background run interrupted",
223
265
  run_id=str(run_id),
@@ -225,13 +267,19 @@ async def worker(
225
267
  run_created_at=run_created_at,
226
268
  run_started_at=run_started_at.isoformat(),
227
269
  run_ended_at=run_ended_at,
228
- run_exec_ms=ms(datetime.now(UTC), run_started_at),
270
+ run_exec_ms=ms(run_ended_at_dt, run_started_at),
271
+ run_completed_in_ms=(
272
+ int((run_ended_at_dt.timestamp() * 1_000) - request_created_at)
273
+ if request_created_at is not None
274
+ else None
275
+ ),
229
276
  )
230
277
  await Runs.set_status(conn, run_id, "interrupted")
231
278
  except RETRIABLE_EXCEPTIONS as e:
232
279
  exception = e
233
280
  status = "retry"
234
- run_ended_at = datetime.now(UTC).isoformat()
281
+ run_ended_at_dt = datetime.now(UTC)
282
+ run_ended_at = run_ended_at_dt.isoformat()
235
283
  await logger.awarning(
236
284
  f"Background run failed, will retry. Exception: {e}",
237
285
  exc_info=True,
@@ -240,14 +288,15 @@ async def worker(
240
288
  run_created_at=run_created_at,
241
289
  run_started_at=run_started_at.isoformat(),
242
290
  run_ended_at=run_ended_at,
243
- run_exec_ms=ms(datetime.now(UTC), run_started_at),
291
+ run_exec_ms=ms(run_ended_at_dt, run_started_at),
244
292
  )
245
293
  await Runs.set_status(conn, run_id, "pending")
246
294
  raise
247
295
  except Exception as exc:
248
296
  exception = exc
249
297
  status = "error"
250
- run_ended_at = datetime.now(UTC).isoformat()
298
+ run_ended_at_dt = datetime.now(UTC)
299
+ run_ended_at = run_ended_at_dt.isoformat()
251
300
  await logger.aexception(
252
301
  f"Background run failed. Exception: {exc}",
253
302
  exc_info=not isinstance(exc, RemoteException),
@@ -256,7 +305,7 @@ async def worker(
256
305
  run_created_at=run_created_at,
257
306
  run_started_at=run_started_at.isoformat(),
258
307
  run_ended_at=run_ended_at,
259
- run_exec_ms=ms(datetime.now(UTC), run_started_at),
308
+ run_exec_ms=ms(run_ended_at_dt, run_started_at),
260
309
  )
261
310
  await Runs.set_status(conn, run_id, "error")
262
311
  set_auth_ctx(None, None)
@@ -1 +0,0 @@
1
- __version__ = "0.2.39"
File without changes
File without changes
File without changes
File without changes