langgraph-api 0.0.14__py3-none-any.whl → 0.0.16__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/api/__init__.py +2 -1
- langgraph_api/api/assistants.py +4 -4
- langgraph_api/api/store.py +67 -15
- langgraph_api/asyncio.py +5 -0
- langgraph_api/auth/custom.py +20 -5
- langgraph_api/config.py +1 -0
- langgraph_api/graph.py +6 -13
- langgraph_api/js/base.py +9 -0
- langgraph_api/js/build.mts +2 -0
- langgraph_api/js/client.mts +383 -409
- langgraph_api/js/client.new.mts +856 -0
- langgraph_api/js/errors.py +11 -0
- langgraph_api/js/package.json +3 -1
- langgraph_api/js/remote.py +16 -673
- langgraph_api/js/remote_new.py +693 -0
- langgraph_api/js/remote_old.py +665 -0
- langgraph_api/js/schema.py +29 -0
- langgraph_api/js/src/utils/serde.mts +7 -0
- langgraph_api/js/tests/api.test.mts +125 -8
- langgraph_api/js/tests/compose-postgres.yml +2 -1
- langgraph_api/js/tests/graphs/agent.mts +2 -0
- langgraph_api/js/tests/graphs/delay.mts +30 -0
- langgraph_api/js/tests/graphs/langgraph.json +2 -1
- langgraph_api/js/yarn.lock +870 -18
- langgraph_api/models/run.py +1 -0
- langgraph_api/queue.py +129 -31
- langgraph_api/route.py +8 -3
- langgraph_api/schema.py +1 -1
- langgraph_api/stream.py +12 -5
- langgraph_api/utils.py +11 -5
- {langgraph_api-0.0.14.dist-info → langgraph_api-0.0.16.dist-info}/METADATA +3 -3
- {langgraph_api-0.0.14.dist-info → langgraph_api-0.0.16.dist-info}/RECORD +37 -30
- langgraph_storage/ops.py +9 -2
- openapi.json +5 -5
- {langgraph_api-0.0.14.dist-info → langgraph_api-0.0.16.dist-info}/LICENSE +0 -0
- {langgraph_api-0.0.14.dist-info → langgraph_api-0.0.16.dist-info}/WHEEL +0 -0
- {langgraph_api-0.0.14.dist-info → langgraph_api-0.0.16.dist-info}/entry_points.txt +0 -0
langgraph_api/models/run.py
CHANGED
|
@@ -191,6 +191,7 @@ async def create_valid_run(
|
|
|
191
191
|
user_id = get_user_id(user)
|
|
192
192
|
config["configurable"]["langgraph_auth_user"] = user
|
|
193
193
|
config["configurable"]["langgraph_auth_user_id"] = user_id
|
|
194
|
+
config["configurable"]["langgraph_auth_permissions"] = ctx.permissions
|
|
194
195
|
else:
|
|
195
196
|
user_id = None
|
|
196
197
|
run_coro = Runs.put(
|
langgraph_api/queue.py
CHANGED
|
@@ -1,33 +1,41 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
-
from
|
|
2
|
+
from collections.abc import AsyncGenerator
|
|
3
|
+
from contextlib import AsyncExitStack, asynccontextmanager
|
|
3
4
|
from datetime import UTC, datetime
|
|
4
5
|
from random import random
|
|
5
|
-
from typing import cast
|
|
6
|
+
from typing import TypedDict, cast
|
|
6
7
|
|
|
7
8
|
import structlog
|
|
8
9
|
from langgraph.pregel.debug import CheckpointPayload, TaskResultPayload
|
|
9
10
|
|
|
11
|
+
from langgraph_api.auth.custom import normalize_user
|
|
10
12
|
from langgraph_api.config import BG_JOB_NO_DELAY, STATS_INTERVAL_SECS
|
|
11
13
|
from langgraph_api.errors import (
|
|
12
14
|
UserInterrupt,
|
|
13
15
|
UserRollback,
|
|
14
16
|
)
|
|
15
17
|
from langgraph_api.http import get_http_client
|
|
16
|
-
from langgraph_api.js.
|
|
18
|
+
from langgraph_api.js.errors import RemoteException
|
|
17
19
|
from langgraph_api.metadata import incr_runs
|
|
18
20
|
from langgraph_api.schema import Run
|
|
19
21
|
from langgraph_api.stream import (
|
|
20
22
|
astream_state,
|
|
21
23
|
consume,
|
|
22
24
|
)
|
|
23
|
-
from langgraph_api.utils import AsyncConnectionProto
|
|
25
|
+
from langgraph_api.utils import AsyncConnectionProto, set_auth_ctx, with_user
|
|
24
26
|
from langgraph_storage.database import connect
|
|
25
27
|
from langgraph_storage.ops import Runs, Threads
|
|
26
28
|
from langgraph_storage.retry import RETRIABLE_EXCEPTIONS
|
|
27
29
|
|
|
30
|
+
try:
|
|
31
|
+
from psycopg.errors import InFailedSqlTransaction
|
|
32
|
+
except ImportError:
|
|
33
|
+
InFailedSqlTransaction = ()
|
|
34
|
+
|
|
28
35
|
logger = structlog.stdlib.get_logger(__name__)
|
|
29
36
|
|
|
30
37
|
WORKERS: set[asyncio.Task] = set()
|
|
38
|
+
WEBHOOKS: set[asyncio.Task] = set()
|
|
31
39
|
MAX_RETRY_ATTEMPTS = 3
|
|
32
40
|
SHUTDOWN_GRACE_PERIOD_SECS = 5
|
|
33
41
|
|
|
@@ -45,10 +53,46 @@ async def queue(concurrency: int, timeout: float):
|
|
|
45
53
|
WORKERS.remove(task)
|
|
46
54
|
semaphore.release()
|
|
47
55
|
try:
|
|
48
|
-
|
|
56
|
+
result: WorkerResult | None = task.result()
|
|
57
|
+
exc = task.exception()
|
|
58
|
+
if exc:
|
|
49
59
|
logger.exception("Background worker failed", exc_info=exc)
|
|
60
|
+
if result and result["webhook"]:
|
|
61
|
+
checkpoint = result["checkpoint"]
|
|
62
|
+
payload = {
|
|
63
|
+
**result["run"],
|
|
64
|
+
"status": result["status"],
|
|
65
|
+
"run_started_at": result["run_started_at"],
|
|
66
|
+
"run_ended_at": result["run_ended_at"],
|
|
67
|
+
"webhook_sent_at": datetime.now(UTC).isoformat(),
|
|
68
|
+
"values": checkpoint["values"] if checkpoint else None,
|
|
69
|
+
}
|
|
70
|
+
if exception := result["exception"]:
|
|
71
|
+
payload["error"] = str(exception)
|
|
72
|
+
|
|
73
|
+
async def _call_webhook() -> None:
|
|
74
|
+
try:
|
|
75
|
+
await get_http_client().post(
|
|
76
|
+
result["webhook"], json=payload, total_timeout=20
|
|
77
|
+
)
|
|
78
|
+
except Exception as exc:
|
|
79
|
+
logger.exception(
|
|
80
|
+
f"Background worker failed to call webhook {result['webhook']}",
|
|
81
|
+
exc_info=exc,
|
|
82
|
+
webhook=result["webhook"],
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
hook_task = asyncio.create_task(
|
|
86
|
+
_call_webhook(),
|
|
87
|
+
name=f"webhook-{result['run']['run_id']}",
|
|
88
|
+
)
|
|
89
|
+
WEBHOOKS.add(hook_task)
|
|
90
|
+
hook_task.add_done_callback(WEBHOOKS.remove)
|
|
91
|
+
|
|
50
92
|
except asyncio.CancelledError:
|
|
51
93
|
pass
|
|
94
|
+
except Exception as exc:
|
|
95
|
+
logger.exception("Background worker cleanup failed", exc_info=exc)
|
|
52
96
|
|
|
53
97
|
await logger.ainfo(f"Starting {concurrency} background workers")
|
|
54
98
|
try:
|
|
@@ -73,9 +117,10 @@ async def queue(concurrency: int, timeout: float):
|
|
|
73
117
|
stats = await Runs.stats(conn)
|
|
74
118
|
await logger.ainfo("Queue stats", **stats)
|
|
75
119
|
if tup := await exit.enter_async_context(Runs.next(conn)):
|
|
120
|
+
run_, attempt_ = tup
|
|
76
121
|
task = asyncio.create_task(
|
|
77
|
-
worker(timeout, exit, conn,
|
|
78
|
-
name=f"run-{
|
|
122
|
+
worker(timeout, exit, conn, run_, attempt_),
|
|
123
|
+
name=f"run-{run_['run_id']}-attempt-{attempt_}",
|
|
79
124
|
)
|
|
80
125
|
task.add_done_callback(cleanup)
|
|
81
126
|
WORKERS.add(task)
|
|
@@ -93,28 +138,61 @@ async def queue(concurrency: int, timeout: float):
|
|
|
93
138
|
logger.info("Shutting down background workers")
|
|
94
139
|
for task in WORKERS:
|
|
95
140
|
task.cancel()
|
|
141
|
+
for task in WEBHOOKS:
|
|
142
|
+
task.cancel()
|
|
96
143
|
await asyncio.wait_for(
|
|
97
|
-
asyncio.gather(*WORKERS, return_exceptions=True),
|
|
144
|
+
asyncio.gather(*WORKERS, *WEBHOOKS, return_exceptions=True),
|
|
145
|
+
SHUTDOWN_GRACE_PERIOD_SECS,
|
|
98
146
|
)
|
|
99
147
|
|
|
100
148
|
|
|
149
|
+
class WorkerResult(TypedDict):
|
|
150
|
+
checkpoint: CheckpointPayload | None
|
|
151
|
+
status: str | None
|
|
152
|
+
exception: Exception | None
|
|
153
|
+
run: Run
|
|
154
|
+
webhook: str | None
|
|
155
|
+
run_started_at: str
|
|
156
|
+
run_ended_at: str | None
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
@asynccontextmanager
|
|
160
|
+
async def set_auth_ctx_for_run(run: Run) -> AsyncGenerator[None, None]:
|
|
161
|
+
try:
|
|
162
|
+
user = run["kwargs"]["config"]["configurable"]["langgraph_auth_user"]
|
|
163
|
+
permissions = run["kwargs"]["config"]["configurable"][
|
|
164
|
+
"langgraph_auth_permissions"
|
|
165
|
+
]
|
|
166
|
+
if user is not None:
|
|
167
|
+
user = normalize_user(user)
|
|
168
|
+
async with with_user(user, permissions):
|
|
169
|
+
yield None
|
|
170
|
+
else:
|
|
171
|
+
yield None
|
|
172
|
+
|
|
173
|
+
except KeyError:
|
|
174
|
+
pass
|
|
175
|
+
|
|
176
|
+
|
|
101
177
|
async def worker(
|
|
102
178
|
timeout: float,
|
|
103
179
|
exit: AsyncExitStack,
|
|
104
180
|
conn: AsyncConnectionProto,
|
|
105
181
|
run: Run,
|
|
106
182
|
attempt: int,
|
|
107
|
-
):
|
|
183
|
+
) -> WorkerResult:
|
|
108
184
|
run_id = run["run_id"]
|
|
109
185
|
if attempt == 1:
|
|
110
186
|
incr_runs()
|
|
111
|
-
|
|
187
|
+
checkpoint: CheckpointPayload | None = None
|
|
188
|
+
exception: Exception | None = None
|
|
189
|
+
status: str | None = None
|
|
190
|
+
webhook = run["kwargs"].pop("webhook", None)
|
|
191
|
+
run_started_at = datetime.now(UTC)
|
|
192
|
+
run_ended_at: str | None = None
|
|
193
|
+
|
|
194
|
+
async with set_auth_ctx_for_run(run), Runs.enter(run_id) as done, exit:
|
|
112
195
|
temporary = run["kwargs"].get("temporary", False)
|
|
113
|
-
webhook = run["kwargs"].pop("webhook", None)
|
|
114
|
-
checkpoint: CheckpointPayload | None = None
|
|
115
|
-
exception: Exception | None = None
|
|
116
|
-
status: str | None = None
|
|
117
|
-
run_started_at = datetime.now(UTC)
|
|
118
196
|
run_created_at = run["created_at"].isoformat()
|
|
119
197
|
await logger.ainfo(
|
|
120
198
|
"Starting background run",
|
|
@@ -154,13 +232,14 @@ async def worker(
|
|
|
154
232
|
on_task_result=on_task_result,
|
|
155
233
|
)
|
|
156
234
|
await asyncio.wait_for(consume(stream, run_id), timeout)
|
|
235
|
+
run_ended_at = datetime.now(UTC).isoformat()
|
|
157
236
|
await logger.ainfo(
|
|
158
237
|
"Background run succeeded",
|
|
159
238
|
run_id=str(run_id),
|
|
160
239
|
run_attempt=attempt,
|
|
161
240
|
run_created_at=run_created_at,
|
|
162
241
|
run_started_at=run_started_at.isoformat(),
|
|
163
|
-
run_ended_at=
|
|
242
|
+
run_ended_at=run_ended_at,
|
|
164
243
|
run_exec_ms=ms(datetime.now(UTC), run_started_at),
|
|
165
244
|
)
|
|
166
245
|
status = "success"
|
|
@@ -168,45 +247,62 @@ async def worker(
|
|
|
168
247
|
except TimeoutError as e:
|
|
169
248
|
exception = e
|
|
170
249
|
status = "timeout"
|
|
250
|
+
run_ended_at = datetime.now(UTC).isoformat()
|
|
171
251
|
await logger.awarning(
|
|
172
252
|
"Background run timed out",
|
|
173
253
|
run_id=str(run_id),
|
|
174
254
|
run_attempt=attempt,
|
|
175
255
|
run_created_at=run_created_at,
|
|
176
256
|
run_started_at=run_started_at.isoformat(),
|
|
177
|
-
run_ended_at=
|
|
257
|
+
run_ended_at=run_ended_at,
|
|
178
258
|
run_exec_ms=ms(datetime.now(UTC), run_started_at),
|
|
179
259
|
)
|
|
180
260
|
await Runs.set_status(conn, run_id, "timeout")
|
|
181
261
|
except UserRollback as e:
|
|
182
262
|
exception = e
|
|
183
263
|
status = "rollback"
|
|
264
|
+
run_ended_at = datetime.now(UTC).isoformat()
|
|
184
265
|
await logger.ainfo(
|
|
185
266
|
"Background run rolled back",
|
|
186
267
|
run_id=str(run_id),
|
|
187
268
|
run_attempt=attempt,
|
|
188
269
|
run_created_at=run_created_at,
|
|
189
270
|
run_started_at=run_started_at.isoformat(),
|
|
190
|
-
run_ended_at=
|
|
271
|
+
run_ended_at=run_ended_at,
|
|
191
272
|
run_exec_ms=ms(datetime.now(UTC), run_started_at),
|
|
192
273
|
)
|
|
193
|
-
|
|
274
|
+
try:
|
|
275
|
+
await Runs.delete(conn, run_id, thread_id=run["thread_id"])
|
|
276
|
+
except InFailedSqlTransaction as e:
|
|
277
|
+
await logger.ainfo(
|
|
278
|
+
"Ignoring rollback error",
|
|
279
|
+
run_id=str(run_id),
|
|
280
|
+
run_attempt=attempt,
|
|
281
|
+
run_created_at=run_created_at,
|
|
282
|
+
exc=str(e),
|
|
283
|
+
)
|
|
284
|
+
# We need to clean up the transaction early if we want to
|
|
285
|
+
# update the thread status with the same connection
|
|
286
|
+
await exit.aclose()
|
|
287
|
+
checkpoint = None # reset the checkpoint
|
|
194
288
|
except UserInterrupt as e:
|
|
195
289
|
exception = e
|
|
196
290
|
status = "interrupted"
|
|
291
|
+
run_ended_at = datetime.now(UTC).isoformat()
|
|
197
292
|
await logger.ainfo(
|
|
198
293
|
"Background run interrupted",
|
|
199
294
|
run_id=str(run_id),
|
|
200
295
|
run_attempt=attempt,
|
|
201
296
|
run_created_at=run_created_at,
|
|
202
297
|
run_started_at=run_started_at.isoformat(),
|
|
203
|
-
run_ended_at=
|
|
298
|
+
run_ended_at=run_ended_at,
|
|
204
299
|
run_exec_ms=ms(datetime.now(UTC), run_started_at),
|
|
205
300
|
)
|
|
206
301
|
await Runs.set_status(conn, run_id, "interrupted")
|
|
207
302
|
except RETRIABLE_EXCEPTIONS as e:
|
|
208
303
|
exception = e
|
|
209
304
|
status = "retry"
|
|
305
|
+
run_ended_at = datetime.now(UTC).isoformat()
|
|
210
306
|
await logger.awarning(
|
|
211
307
|
"Background run failed, will retry",
|
|
212
308
|
exc_info=True,
|
|
@@ -214,7 +310,7 @@ async def worker(
|
|
|
214
310
|
run_attempt=attempt,
|
|
215
311
|
run_created_at=run_created_at,
|
|
216
312
|
run_started_at=run_started_at.isoformat(),
|
|
217
|
-
run_ended_at=
|
|
313
|
+
run_ended_at=run_ended_at,
|
|
218
314
|
run_exec_ms=ms(datetime.now(UTC), run_started_at),
|
|
219
315
|
)
|
|
220
316
|
raise
|
|
@@ -223,6 +319,7 @@ async def worker(
|
|
|
223
319
|
except Exception as exc:
|
|
224
320
|
exception = exc
|
|
225
321
|
status = "error"
|
|
322
|
+
run_ended_at = datetime.now(UTC).isoformat()
|
|
226
323
|
await logger.aexception(
|
|
227
324
|
"Background run failed",
|
|
228
325
|
exc_info=not isinstance(exc, RemoteException),
|
|
@@ -230,24 +327,25 @@ async def worker(
|
|
|
230
327
|
run_attempt=attempt,
|
|
231
328
|
run_created_at=run_created_at,
|
|
232
329
|
run_started_at=run_started_at.isoformat(),
|
|
233
|
-
run_ended_at=
|
|
330
|
+
run_ended_at=run_ended_at,
|
|
234
331
|
run_exec_ms=ms(datetime.now(UTC), run_started_at),
|
|
235
332
|
)
|
|
236
333
|
await Runs.set_status(conn, run_id, "error")
|
|
334
|
+
set_auth_ctx(None, None)
|
|
237
335
|
# delete or set status of thread
|
|
238
336
|
if temporary:
|
|
239
337
|
await Threads.delete(conn, run["thread_id"])
|
|
240
338
|
else:
|
|
241
339
|
await Threads.set_status(conn, run["thread_id"], checkpoint, exception)
|
|
242
|
-
if webhook:
|
|
243
|
-
# TODO add error, values to webhook payload
|
|
244
|
-
# TODO add retries for webhook calls
|
|
245
|
-
try:
|
|
246
|
-
await get_http_client().post(
|
|
247
|
-
webhook, json={**run, "status": status}, total_timeout=5
|
|
248
|
-
)
|
|
249
|
-
except Exception as e:
|
|
250
|
-
logger.warning("Failed to send webhook", exc_info=e)
|
|
251
340
|
# Note we don't handle asyncio.CancelledError here, as we want to
|
|
252
341
|
# let it bubble up and rollback db transaction, thus marking the run
|
|
253
342
|
# as available to be picked up by another worker
|
|
343
|
+
return {
|
|
344
|
+
"checkpoint": checkpoint,
|
|
345
|
+
"status": status,
|
|
346
|
+
"run_started_at": run_started_at.isoformat(),
|
|
347
|
+
"run_ended_at": run_ended_at,
|
|
348
|
+
"run": run,
|
|
349
|
+
"exception": exception,
|
|
350
|
+
"webhook": webhook,
|
|
351
|
+
}
|
langgraph_api/route.py
CHANGED
|
@@ -14,7 +14,7 @@ from starlette.routing import Route, compile_path, get_name
|
|
|
14
14
|
from starlette.types import ASGIApp, Receive, Scope, Send
|
|
15
15
|
|
|
16
16
|
from langgraph_api.serde import json_dumpb
|
|
17
|
-
from langgraph_api.utils import
|
|
17
|
+
from langgraph_api.utils import get_auth_ctx, with_user
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
def api_request_response(
|
|
@@ -116,5 +116,10 @@ class ApiRoute(Route):
|
|
|
116
116
|
async def handle(self, scope: Scope, receive: Receive, send: Send) -> None:
|
|
117
117
|
# https://asgi.readthedocs.io/en/latest/specs/www.html#http-connection-scope
|
|
118
118
|
scope["route"] = self.path
|
|
119
|
-
|
|
120
|
-
|
|
119
|
+
ctx = get_auth_ctx()
|
|
120
|
+
if ctx:
|
|
121
|
+
user, auth = ctx.user, ctx.permissions
|
|
122
|
+
else:
|
|
123
|
+
user, auth = scope.get("user"), scope.get("auth")
|
|
124
|
+
async with with_user(user, auth):
|
|
125
|
+
return await super().handle(scope, receive, send)
|
langgraph_api/schema.py
CHANGED
langgraph_api/stream.py
CHANGED
|
@@ -25,7 +25,7 @@ from pydantic.v1 import ValidationError as ValidationErrorLegacy
|
|
|
25
25
|
|
|
26
26
|
from langgraph_api.asyncio import ValueEvent, wait_if_not_done
|
|
27
27
|
from langgraph_api.graph import get_graph
|
|
28
|
-
from langgraph_api.js.
|
|
28
|
+
from langgraph_api.js.base import BaseRemotePregel
|
|
29
29
|
from langgraph_api.metadata import HOST, PLAN, incr_nodes
|
|
30
30
|
from langgraph_api.schema import Run, RunCommand, StreamMode
|
|
31
31
|
from langgraph_api.serde import json_dumpb
|
|
@@ -75,8 +75,15 @@ def _map_cmd(cmd: RunCommand) -> Command:
|
|
|
75
75
|
if goto is not None and not isinstance(goto, list):
|
|
76
76
|
goto = [cmd.get("goto")]
|
|
77
77
|
|
|
78
|
+
update = cmd.get("update")
|
|
79
|
+
if isinstance(update, tuple | list) and all(
|
|
80
|
+
isinstance(t, tuple | list) and len(t) == 2 and isinstance(t[0], str)
|
|
81
|
+
for t in update
|
|
82
|
+
):
|
|
83
|
+
update = [tuple(t) for t in update]
|
|
84
|
+
|
|
78
85
|
return Command(
|
|
79
|
-
update=
|
|
86
|
+
update=update,
|
|
80
87
|
goto=(
|
|
81
88
|
[
|
|
82
89
|
it if isinstance(it, str) else Send(it["node"], it["input"])
|
|
@@ -133,7 +140,7 @@ async def astream_state(
|
|
|
133
140
|
config["metadata"]["langgraph_plan"] = PLAN
|
|
134
141
|
config["metadata"]["langgraph_host"] = HOST
|
|
135
142
|
# attach node counter
|
|
136
|
-
if not isinstance(graph,
|
|
143
|
+
if not isinstance(graph, BaseRemotePregel):
|
|
137
144
|
config["configurable"]["__pregel_node_finished"] = incr_nodes
|
|
138
145
|
# TODO add node tracking for JS graphs
|
|
139
146
|
# attach run_id to config
|
|
@@ -142,7 +149,7 @@ async def astream_state(
|
|
|
142
149
|
# set up state
|
|
143
150
|
checkpoint: CheckpointPayload | None = None
|
|
144
151
|
messages: dict[str, BaseMessageChunk] = {}
|
|
145
|
-
use_astream_events = "events" in stream_mode or isinstance(graph,
|
|
152
|
+
use_astream_events = "events" in stream_mode or isinstance(graph, BaseRemotePregel)
|
|
146
153
|
# yield metadata chunk
|
|
147
154
|
yield "metadata", {"run_id": run_id, "attempt": attempt}
|
|
148
155
|
# stream run
|
|
@@ -166,7 +173,7 @@ async def astream_state(
|
|
|
166
173
|
break
|
|
167
174
|
if event.get("tags") and "langsmith:hidden" in event["tags"]:
|
|
168
175
|
continue
|
|
169
|
-
if "messages" in stream_mode and isinstance(graph,
|
|
176
|
+
if "messages" in stream_mode and isinstance(graph, BaseRemotePregel):
|
|
170
177
|
if event["event"] == "on_custom_event" and event["name"] in (
|
|
171
178
|
"messages/complete",
|
|
172
179
|
"messages/partial",
|
langgraph_api/utils.py
CHANGED
|
@@ -17,22 +17,28 @@ AuthContext = contextvars.ContextVar[Auth.types.BaseAuthContext | None](
|
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
@asynccontextmanager
|
|
20
|
-
async def with_user(
|
|
20
|
+
async def with_user(
|
|
21
|
+
user: BaseUser | None = None, auth: AuthCredentials | list[str] | None = None
|
|
22
|
+
):
|
|
21
23
|
current = get_auth_ctx()
|
|
22
24
|
set_auth_ctx(user, auth)
|
|
23
25
|
yield
|
|
24
26
|
if current is None:
|
|
25
27
|
return
|
|
26
|
-
set_auth_ctx(current.user, AuthCredentials(scopes=current.
|
|
28
|
+
set_auth_ctx(current.user, AuthCredentials(scopes=current.permissions))
|
|
27
29
|
|
|
28
30
|
|
|
29
|
-
def set_auth_ctx(
|
|
30
|
-
|
|
31
|
+
def set_auth_ctx(
|
|
32
|
+
user: BaseUser | None, auth: AuthCredentials | list[str] | None
|
|
33
|
+
) -> None:
|
|
34
|
+
if user is None and auth is None:
|
|
31
35
|
AuthContext.set(None)
|
|
32
36
|
else:
|
|
33
37
|
AuthContext.set(
|
|
34
38
|
Auth.types.BaseAuthContext(
|
|
35
|
-
permissions=
|
|
39
|
+
permissions=(
|
|
40
|
+
auth.scopes if isinstance(auth, AuthCredentials) else (auth or [])
|
|
41
|
+
),
|
|
36
42
|
user=user or SimpleUser(""),
|
|
37
43
|
)
|
|
38
44
|
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: langgraph-api
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.16
|
|
4
4
|
Summary:
|
|
5
5
|
License: Elastic-2.0
|
|
6
6
|
Author: Nuno Campos
|
|
@@ -16,11 +16,11 @@ Requires-Dist: jsonschema-rs (>=0.25.0,<0.26.0)
|
|
|
16
16
|
Requires-Dist: langchain-core (>=0.2.38,<0.4.0)
|
|
17
17
|
Requires-Dist: langgraph (>=0.2.56,<0.3.0)
|
|
18
18
|
Requires-Dist: langgraph-checkpoint (>=2.0.7,<3.0)
|
|
19
|
-
Requires-Dist: langgraph-sdk (>=0.1.
|
|
19
|
+
Requires-Dist: langgraph-sdk (>=0.1.51,<0.2.0)
|
|
20
20
|
Requires-Dist: langsmith (>=0.1.63,<0.3.0)
|
|
21
21
|
Requires-Dist: orjson (>=3.10.1)
|
|
22
22
|
Requires-Dist: pyjwt (>=2.9.0,<3.0.0)
|
|
23
|
-
Requires-Dist: sse-starlette (>=2.1.0,<
|
|
23
|
+
Requires-Dist: sse-starlette (>=2.1.0,<2.2.0)
|
|
24
24
|
Requires-Dist: starlette (>=0.38.6)
|
|
25
25
|
Requires-Dist: structlog (>=24.4.0,<25.0.0)
|
|
26
26
|
Requires-Dist: tenacity (>=8.3.0,<9.0.0)
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
LICENSE,sha256=ZPwVR73Biwm3sK6vR54djCrhaRiM4cAD2zvOQZV8Xis,3859
|
|
2
2
|
langgraph_api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
-
langgraph_api/api/__init__.py,sha256=
|
|
4
|
-
langgraph_api/api/assistants.py,sha256=
|
|
3
|
+
langgraph_api/api/__init__.py,sha256=zAdS_0jgjmCJK6E0VwEuNcNRkaknMXfQ2C_OES5tEI4,2066
|
|
4
|
+
langgraph_api/api/assistants.py,sha256=nn-0Q5FTaEbdPq-oesrpVzqu223PDSzeejFy9fd5Xjw,11599
|
|
5
5
|
langgraph_api/api/meta.py,sha256=hueasWpTDQ6xYLo9Bzt2jhNH8XQRzreH8FTeFfnRoxQ,2700
|
|
6
6
|
langgraph_api/api/openapi.py,sha256=AUxfnD5hlRp7s-0g2hBC5dNSNk3HTwOLeJiF489DT44,2762
|
|
7
7
|
langgraph_api/api/runs.py,sha256=wAzPXi_kcYB9BcLBL4FXgkBohWwCPIpe4XERnsnWnsA,16042
|
|
8
|
-
langgraph_api/api/store.py,sha256=
|
|
8
|
+
langgraph_api/api/store.py,sha256=VzAJVOwO0IxosBB7km5TTf2rhlWGyPkVz_LpvbxetVY,5437
|
|
9
9
|
langgraph_api/api/threads.py,sha256=taU61XPcCEhBPCYPZcMDsgVDwwWUWJs8p-PrXFXWY48,8661
|
|
10
|
-
langgraph_api/asyncio.py,sha256=
|
|
10
|
+
langgraph_api/asyncio.py,sha256=2fOlx-cZvuj1gQ867Kw1R_wsBsl9jdHYHcUtK2a-x-U,6264
|
|
11
11
|
langgraph_api/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
|
-
langgraph_api/auth/custom.py,sha256=
|
|
12
|
+
langgraph_api/auth/custom.py,sha256=g_u7FdKm1Qj8eu_MZdnJeMsI4DlWyU5Mg0rPJzdOTSE,20913
|
|
13
13
|
langgraph_api/auth/langsmith/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
14
|
langgraph_api/auth/langsmith/backend.py,sha256=InScaL-HYCnxYEauhxU198gRZV9pJn9SzzBoR9Edn7g,2654
|
|
15
15
|
langgraph_api/auth/langsmith/client.py,sha256=eKchvAom7hdkUXauD8vHNceBDDUijrFgdTV8bKd7x4Q,3998
|
|
@@ -17,18 +17,24 @@ langgraph_api/auth/middleware.py,sha256=qc7SbaFoeWaqxS1wbjZ2PPQ4iI2p9T0shWL7c6g0
|
|
|
17
17
|
langgraph_api/auth/noop.py,sha256=vDJmzG2vArJxVzdHePvrJWahEa0dvGnhc2LEMMeiFz0,391
|
|
18
18
|
langgraph_api/auth/studio_user.py,sha256=FzFQRROKDlA9JjtBuwyZvk6Mbwno5M9RVYjDO6FU3F8,186
|
|
19
19
|
langgraph_api/cli.py,sha256=7vQQiD3F50r-8KkbuFjwIz8LLbdKUTd4xZGUJPiO3yQ,11688
|
|
20
|
-
langgraph_api/config.py,sha256=
|
|
20
|
+
langgraph_api/config.py,sha256=HPNSCb-owhu_sU8KBLbTbKLdGIPGVLcSgdvKFKXg7uE,2816
|
|
21
21
|
langgraph_api/cron_scheduler.py,sha256=CybK-9Jwopi_scObTHRyB7gyb0KjC4gqaT2GLe-WOFg,2587
|
|
22
22
|
langgraph_api/errors.py,sha256=Bu_i5drgNTyJcLiyrwVE_6-XrSU50BHf9TDpttki9wQ,1690
|
|
23
|
-
langgraph_api/graph.py,sha256=
|
|
23
|
+
langgraph_api/graph.py,sha256=FombjYQkqj8jrXJFEVkl3m2UyFcq5nSVNswR2HoRsQY,16385
|
|
24
24
|
langgraph_api/http.py,sha256=XrbyxpjtfSvnaWWh5ZLGpgZmY83WoDCrP_1GPguNiXI,4712
|
|
25
25
|
langgraph_api/http_logger.py,sha256=Sxo_q-65tElauRvkzVLt9lJojgNdgtcHGBYD0IRyX7M,3146
|
|
26
26
|
langgraph_api/js/.gitignore,sha256=qAah3Fq0HWAlfRj5ktZyC6QRQIsAolGLRGcRukA1XJI,33
|
|
27
|
-
langgraph_api/js/
|
|
28
|
-
langgraph_api/js/
|
|
27
|
+
langgraph_api/js/base.py,sha256=BpE8-xkUp8HFPRjSKx1tfUQubvoV4jYl6OwZdre3veI,209
|
|
28
|
+
langgraph_api/js/build.mts,sha256=sAZXB3xVSoG8exJ1ZEytFyikRmEsXJ_0OlLjDDgD79o,1342
|
|
29
|
+
langgraph_api/js/client.mts,sha256=ksiytm222KTUWj92ZnajqFku_y2AkRmfENmKie5LSPw,22519
|
|
30
|
+
langgraph_api/js/client.new.mts,sha256=9FrArkM20IeD176Q7u5lJNruaQXqAfAdDcqJkF0TPPA,23493
|
|
31
|
+
langgraph_api/js/errors.py,sha256=Cm1TKWlUCwZReDC5AQ6SgNIVGD27Qov2xcgHyf8-GXo,361
|
|
29
32
|
langgraph_api/js/global.d.ts,sha256=zR_zLYfpzyPfxpEFth5RgZoyfGulIXyZYPRf7cU0K0Y,106
|
|
30
|
-
langgraph_api/js/package.json,sha256=
|
|
31
|
-
langgraph_api/js/remote.py,sha256=
|
|
33
|
+
langgraph_api/js/package.json,sha256=BGnWhiMMvxocEuPciTq14fEHp5NFmHo6fYV8q62n3t4,840
|
|
34
|
+
langgraph_api/js/remote.py,sha256=D9cqcEgXau-fm_trpNwCHMra5BXntgUa469lgs_a9JQ,622
|
|
35
|
+
langgraph_api/js/remote_new.py,sha256=T_Vr8459bax1C9xxqz_ZYmGivq5Vhspg2Iu9TL0Qc-Q,22707
|
|
36
|
+
langgraph_api/js/remote_old.py,sha256=2a-3ooAYUZs8aPsfnXafbBd4pP7lRmokoU7TiO7P9Js,22546
|
|
37
|
+
langgraph_api/js/schema.py,sha256=7idnv7URlYUdSNMBXQcw7E4SxaPxCq_Oxwnlml8q5ik,408
|
|
32
38
|
langgraph_api/js/server_sent_events.py,sha256=DLgXOHauemt7706vnfDUCG1GI3TidKycSizccdz9KgA,3702
|
|
33
39
|
langgraph_api/js/src/graph.mts,sha256=EO1ITYoKiUykzO_8V8mnQb6NYybooR1VXIovThZzywc,2998
|
|
34
40
|
langgraph_api/js/src/hooks.mjs,sha256=XtktgmIHlls_DsknAuwib-z7TqCm0haRoTXvnkgzMuo,601
|
|
@@ -38,35 +44,36 @@ langgraph_api/js/src/schema/types.mts,sha256=SUj0vpvWVbID1mnGr2SUtumDBQkJ9zjfvJd
|
|
|
38
44
|
langgraph_api/js/src/schema/types.template.mts,sha256=c-FA0Ykzp4KvPyYA6a-hDf60KdQRMyFEjmGVJyD2OPM,2011
|
|
39
45
|
langgraph_api/js/src/utils/importMap.mts,sha256=pX4TGOyUpuuWF82kXcxcv3-8mgusRezOGe6Uklm2O5A,1644
|
|
40
46
|
langgraph_api/js/src/utils/pythonSchemas.mts,sha256=98IW7Z_VP7L_CHNRMb3_MsiV3BgLE2JsWQY_PQcRR3o,685
|
|
41
|
-
langgraph_api/js/src/utils/serde.mts,sha256=
|
|
42
|
-
langgraph_api/js/tests/api.test.mts,sha256=
|
|
43
|
-
langgraph_api/js/tests/compose-postgres.yml,sha256=
|
|
47
|
+
langgraph_api/js/src/utils/serde.mts,sha256=OuyyO9btvwWd55rU_H4x91dFEJiaPxL-lL9O6Zgo908,742
|
|
48
|
+
langgraph_api/js/tests/api.test.mts,sha256=2EpDEs888pJGdZnsyc76GdMp7uuRxM_SNlHBwITU-5I,55668
|
|
49
|
+
langgraph_api/js/tests/compose-postgres.yml,sha256=pbNfeqVUqhWILBuUdwAgQOYsVU_fgkCVm0YlTgU8og8,1721
|
|
44
50
|
langgraph_api/js/tests/graphs/.gitignore,sha256=26J8MarZNXh7snXD5eTpV3CPFTht5Znv8dtHYCLNfkw,12
|
|
45
|
-
langgraph_api/js/tests/graphs/agent.mts,sha256=
|
|
51
|
+
langgraph_api/js/tests/graphs/agent.mts,sha256=fFHm9vW04UN_2mGcHVHqtFIvPhjyFurBg62DAW-GJd4,3889
|
|
52
|
+
langgraph_api/js/tests/graphs/delay.mts,sha256=CFneKxqI4bGGK0lYjSbe80QirowPQlsRSuhDUKfydhk,703
|
|
46
53
|
langgraph_api/js/tests/graphs/error.mts,sha256=l4tk89449dj1BnEF_0ZcfPt0Ikk1gl8L1RaSnRfr3xo,487
|
|
47
|
-
langgraph_api/js/tests/graphs/langgraph.json,sha256
|
|
54
|
+
langgraph_api/js/tests/graphs/langgraph.json,sha256=frxd7ZWILdeMYSZgUBH6UO-IR7I2YJSOfOlx2mnO1sI,189
|
|
48
55
|
langgraph_api/js/tests/graphs/nested.mts,sha256=4G7jSOSaFVQAza-_ARbK-Iai1biLlF2DIPDZXf7PLIY,1245
|
|
49
56
|
langgraph_api/js/tests/graphs/package.json,sha256=kG5a7jRCnlSQMV2WXUsXegmp5cCWm9F3AOIBUUqPn8A,118
|
|
50
57
|
langgraph_api/js/tests/graphs/weather.mts,sha256=A7mLK3xW8h5B-ZyJNAyX2M2fJJwzPJzXs4DYesJwreQ,1655
|
|
51
58
|
langgraph_api/js/tests/graphs/yarn.lock,sha256=q-1S--E5VWLYtkSv03shqtNzeDDv-N_J-N26FszLsjs,7903
|
|
52
59
|
langgraph_api/js/tests/parser.test.mts,sha256=3zAbboUNhI-cY3hj4Ssr7J-sQXCBTeeI1ItrkG0Ftuk,26257
|
|
53
60
|
langgraph_api/js/tests/utils.mts,sha256=2kTybJ3O7Yfe1q3ehDouqV54ibXkNzsPZ_wBZLJvY-4,421
|
|
54
|
-
langgraph_api/js/yarn.lock,sha256=
|
|
61
|
+
langgraph_api/js/yarn.lock,sha256=JtRgt5AXlsD4qBm1Nrtzxg-TLtZkFWtRKCvyS-V8CLg,103690
|
|
55
62
|
langgraph_api/lifespan.py,sha256=Uj7NV-NqxxD1fgx_umM9pVqclcy-VlqrIxDljyj2he0,1820
|
|
56
63
|
langgraph_api/logging.py,sha256=tiDNrEFwqaIdL5ywZv908OXlzzfXsPCws9GXeoFtBV8,3367
|
|
57
64
|
langgraph_api/metadata.py,sha256=mih2G7ScQxiqyUlbksVXkqR3Oo-pM1b6lXtzOsgR1sw,3044
|
|
58
65
|
langgraph_api/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
59
|
-
langgraph_api/models/run.py,sha256=
|
|
66
|
+
langgraph_api/models/run.py,sha256=qBN_w8mUpSbAZNVL1683_DfZHQ0zvYMNyqGg-g1sz6Y,9625
|
|
60
67
|
langgraph_api/patch.py,sha256=94ddcTSZJe22JcpjxiSNjFZdYVnmeoWjk4IX4iBSoyk,1249
|
|
61
|
-
langgraph_api/queue.py,sha256=
|
|
62
|
-
langgraph_api/route.py,sha256=
|
|
63
|
-
langgraph_api/schema.py,sha256=
|
|
68
|
+
langgraph_api/queue.py,sha256=nYtcjbqjwvELK5OXxD2aw5BWAlSJ-VPyCXSODMMXIj0,13353
|
|
69
|
+
langgraph_api/route.py,sha256=fM4qYCGbmH0a3_cV8uKocb1sLklehxO6HhdRXqLK6OM,4421
|
|
70
|
+
langgraph_api/schema.py,sha256=4aZCFY-dxd_nTot71bdcd9S8QCIgKajuRyj0p2QfgJ4,5291
|
|
64
71
|
langgraph_api/serde.py,sha256=VoJ7Z1IuqrQGXFzEP1qijAITtWCrmjtVqlCRuScjXJI,3533
|
|
65
72
|
langgraph_api/server.py,sha256=afHDnL6b_fAIu_q4icnK60a74lHTTZOMIe1egdhRXIk,1522
|
|
66
73
|
langgraph_api/sse.py,sha256=2wNodCOP2eg7a9mpSu0S3FQ0CHk2BBV_vv0UtIgJIcc,4034
|
|
67
74
|
langgraph_api/state.py,sha256=8jx4IoTCOjTJuwzuXJKKFwo1VseHjNnw_CCq4x1SW14,2284
|
|
68
|
-
langgraph_api/stream.py,sha256=
|
|
69
|
-
langgraph_api/utils.py,sha256=
|
|
75
|
+
langgraph_api/stream.py,sha256=Uygx6zcY5Wi9lBhRjtxqVDyLZSF1bsaqxg6mYoYVYcY,11900
|
|
76
|
+
langgraph_api/utils.py,sha256=fMl3DHOQEwAqkFtrnP0Alfbrqw1UvwZ_JVLm-WTSQJk,2654
|
|
70
77
|
langgraph_api/validation.py,sha256=McizHlz-Ez8Jhdbc79mbPSde7GIuf2Jlbjx2yv_l6dA,4475
|
|
71
78
|
langgraph_license/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
72
79
|
langgraph_license/middleware.py,sha256=_ODIYzQkymr6W9_Fp9wtf1kAQspnpsmr53xuzyF2GA0,612
|
|
@@ -74,15 +81,15 @@ langgraph_license/validation.py,sha256=Uu_G8UGO_WTlLsBEY0gTVWjRR4czYGfw5YAD3HLZo
|
|
|
74
81
|
langgraph_storage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
75
82
|
langgraph_storage/checkpoint.py,sha256=V4t2GwYEJdPCHbhq_4Udhlv0TWKDzlMu_rlNPdTDc50,3589
|
|
76
83
|
langgraph_storage/database.py,sha256=Nr5zE9Fur3-tESkqe7xNXMf2QlBuw3H0CUie7jVa6Q4,6003
|
|
77
|
-
langgraph_storage/ops.py,sha256=
|
|
84
|
+
langgraph_storage/ops.py,sha256=7kmfm7EO7YbP_ItEjMvFPKPsM0a2X6RMhjaKof63HaQ,68206
|
|
78
85
|
langgraph_storage/queue.py,sha256=6cTZ0ubHu3S1T43yxHMVOwsQsDaJupByiU0sTUFFls8,3261
|
|
79
86
|
langgraph_storage/retry.py,sha256=uvYFuXJ-T6S1QY1ZwkZHyZQbsvS-Ab68LSbzbUUSI2E,696
|
|
80
87
|
langgraph_storage/store.py,sha256=D-p3cWc_umamkKp-6Cz3cAriSACpvM5nxUIvND6PuxE,2710
|
|
81
88
|
langgraph_storage/ttl_dict.py,sha256=FlpEY8EANeXWKo_G5nmIotPquABZGyIJyk6HD9u6vqY,1533
|
|
82
89
|
logging.json,sha256=3RNjSADZmDq38eHePMm1CbP6qZ71AmpBtLwCmKU9Zgo,379
|
|
83
|
-
openapi.json,sha256=
|
|
84
|
-
langgraph_api-0.0.
|
|
85
|
-
langgraph_api-0.0.
|
|
86
|
-
langgraph_api-0.0.
|
|
87
|
-
langgraph_api-0.0.
|
|
88
|
-
langgraph_api-0.0.
|
|
90
|
+
openapi.json,sha256=qf2Rw3ieawlAcSJu4mGonh9mNOb6solBD70CGL3w24A,124699
|
|
91
|
+
langgraph_api-0.0.16.dist-info/LICENSE,sha256=ZPwVR73Biwm3sK6vR54djCrhaRiM4cAD2zvOQZV8Xis,3859
|
|
92
|
+
langgraph_api-0.0.16.dist-info/METADATA,sha256=HLMkdfTmxuTMN59uOzDQ4VCRILZvgslETZShl2Mdruw,4041
|
|
93
|
+
langgraph_api-0.0.16.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
94
|
+
langgraph_api-0.0.16.dist-info/entry_points.txt,sha256=3EYLgj89DfzqJHHYGxPH4A_fEtClvlRbWRUHaXO7hj4,77
|
|
95
|
+
langgraph_api-0.0.16.dist-info/RECORD,,
|
langgraph_storage/ops.py
CHANGED
|
@@ -1325,7 +1325,10 @@ class Runs(Authenticated):
|
|
|
1325
1325
|
thread = Thread(
|
|
1326
1326
|
thread_id=thread_id,
|
|
1327
1327
|
status="busy",
|
|
1328
|
-
metadata={
|
|
1328
|
+
metadata={
|
|
1329
|
+
"graph_id": assistant["graph_id"],
|
|
1330
|
+
"assistant_id": str(assistant_id),
|
|
1331
|
+
},
|
|
1329
1332
|
config=Runs._merge_jsonb(
|
|
1330
1333
|
assistant["config"],
|
|
1331
1334
|
config,
|
|
@@ -1345,7 +1348,11 @@ class Runs(Authenticated):
|
|
|
1345
1348
|
if existing_thread["status"] != "busy":
|
|
1346
1349
|
existing_thread["status"] = "busy"
|
|
1347
1350
|
existing_thread["metadata"] = Runs._merge_jsonb(
|
|
1348
|
-
existing_thread["metadata"],
|
|
1351
|
+
existing_thread["metadata"],
|
|
1352
|
+
{
|
|
1353
|
+
"graph_id": assistant["graph_id"],
|
|
1354
|
+
"assistant_id": str(assistant_id),
|
|
1355
|
+
},
|
|
1349
1356
|
)
|
|
1350
1357
|
existing_thread["config"] = Runs._merge_jsonb(
|
|
1351
1358
|
assistant["config"],
|
openapi.json
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"description": "A run is an invocation of a graph / assistant, with no state or memory persistence."
|
|
23
23
|
},
|
|
24
24
|
{
|
|
25
|
-
"name": "Crons (
|
|
25
|
+
"name": "Crons (Plus tier)",
|
|
26
26
|
"description": "A cron is a periodic run that recurs on a given schedule. The repeats can be isolated, or share state in a thread"
|
|
27
27
|
},
|
|
28
28
|
{
|
|
@@ -1473,7 +1473,7 @@
|
|
|
1473
1473
|
"/threads/{thread_id}/runs/crons": {
|
|
1474
1474
|
"post": {
|
|
1475
1475
|
"tags": [
|
|
1476
|
-
"Crons (
|
|
1476
|
+
"Crons (Plus tier)"
|
|
1477
1477
|
],
|
|
1478
1478
|
"summary": "Create Thread Cron",
|
|
1479
1479
|
"description": "Create a cron to schedule runs on a thread.",
|
|
@@ -2058,7 +2058,7 @@
|
|
|
2058
2058
|
"/runs/crons": {
|
|
2059
2059
|
"post": {
|
|
2060
2060
|
"tags": [
|
|
2061
|
-
"Crons (
|
|
2061
|
+
"Crons (Plus tier)"
|
|
2062
2062
|
],
|
|
2063
2063
|
"summary": "Create Cron",
|
|
2064
2064
|
"description": "Create a cron to schedule runs on new threads.",
|
|
@@ -2110,7 +2110,7 @@
|
|
|
2110
2110
|
"/runs/crons/search": {
|
|
2111
2111
|
"post": {
|
|
2112
2112
|
"tags": [
|
|
2113
|
-
"Crons (
|
|
2113
|
+
"Crons (Plus tier)"
|
|
2114
2114
|
],
|
|
2115
2115
|
"summary": "Search Crons",
|
|
2116
2116
|
"description": "Search all active crons",
|
|
@@ -2399,7 +2399,7 @@
|
|
|
2399
2399
|
"/runs/crons/{cron_id}": {
|
|
2400
2400
|
"delete": {
|
|
2401
2401
|
"tags": [
|
|
2402
|
-
"Crons (
|
|
2402
|
+
"Crons (Plus tier)"
|
|
2403
2403
|
],
|
|
2404
2404
|
"summary": "Delete Cron",
|
|
2405
2405
|
"description": "Delete a cron by ID.",
|