langgraph-runtime-inmem 0.12.0__py3-none-any.whl → 0.13.0__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.
- langgraph_runtime_inmem/__init__.py +1 -1
- langgraph_runtime_inmem/lifespan.py +2 -1
- langgraph_runtime_inmem/ops.py +34 -89
- {langgraph_runtime_inmem-0.12.0.dist-info → langgraph_runtime_inmem-0.13.0.dist-info}/METADATA +1 -1
- {langgraph_runtime_inmem-0.12.0.dist-info → langgraph_runtime_inmem-0.13.0.dist-info}/RECORD +6 -6
- {langgraph_runtime_inmem-0.12.0.dist-info → langgraph_runtime_inmem-0.13.0.dist-info}/WHEEL +0 -0
|
@@ -17,6 +17,7 @@ logger = structlog.stdlib.get_logger(__name__)
|
|
|
17
17
|
@asynccontextmanager
|
|
18
18
|
async def lifespan(
|
|
19
19
|
app: Starlette | None = None,
|
|
20
|
+
cancel_event: asyncio.Event | None = None,
|
|
20
21
|
taskset: set[asyncio.Task] | None = None,
|
|
21
22
|
**kwargs: Any,
|
|
22
23
|
):
|
|
@@ -47,7 +48,7 @@ async def lifespan(
|
|
|
47
48
|
try:
|
|
48
49
|
async with SimpleTaskGroup(
|
|
49
50
|
cancel=True,
|
|
50
|
-
|
|
51
|
+
cancel_event=cancel_event,
|
|
51
52
|
taskgroup_name="Lifespan",
|
|
52
53
|
) as tg:
|
|
53
54
|
tg.create_task(metadata_loop())
|
langgraph_runtime_inmem/ops.py
CHANGED
|
@@ -11,7 +11,6 @@ import uuid
|
|
|
11
11
|
from collections import defaultdict
|
|
12
12
|
from collections.abc import AsyncIterator, Sequence
|
|
13
13
|
from contextlib import asynccontextmanager
|
|
14
|
-
from copy import deepcopy
|
|
15
14
|
from datetime import UTC, datetime, timedelta
|
|
16
15
|
from typing import Any, Literal, cast
|
|
17
16
|
from uuid import UUID, uuid4
|
|
@@ -63,9 +62,9 @@ if typing.TYPE_CHECKING:
|
|
|
63
62
|
ThreadUpdateResponse,
|
|
64
63
|
)
|
|
65
64
|
from langgraph_api.schema import Interrupt as InterruptSchema
|
|
66
|
-
from langgraph_api.serde import Fragment
|
|
67
65
|
from langgraph_api.utils import AsyncConnectionProto
|
|
68
66
|
|
|
67
|
+
StreamHandler = ContextQueue
|
|
69
68
|
|
|
70
69
|
logger = structlog.stdlib.get_logger(__name__)
|
|
71
70
|
|
|
@@ -230,7 +229,7 @@ class Assistants(Authenticated):
|
|
|
230
229
|
if assistant["assistant_id"] == assistant_id and (
|
|
231
230
|
not filters or _check_filter_match(assistant["metadata"], filters)
|
|
232
231
|
):
|
|
233
|
-
yield assistant
|
|
232
|
+
yield copy.deepcopy(assistant)
|
|
234
233
|
|
|
235
234
|
return _yield_result()
|
|
236
235
|
|
|
@@ -1256,7 +1255,7 @@ class Threads(Authenticated):
|
|
|
1256
1255
|
"thread_id": new_thread_id,
|
|
1257
1256
|
"created_at": datetime.now(tz=UTC),
|
|
1258
1257
|
"updated_at": datetime.now(tz=UTC),
|
|
1259
|
-
"metadata": deepcopy(original_thread["metadata"]),
|
|
1258
|
+
"metadata": copy.deepcopy(original_thread["metadata"]),
|
|
1260
1259
|
"status": "idle",
|
|
1261
1260
|
"config": {},
|
|
1262
1261
|
}
|
|
@@ -2400,66 +2399,6 @@ class Runs(Authenticated):
|
|
|
2400
2399
|
|
|
2401
2400
|
return _yield_deleted()
|
|
2402
2401
|
|
|
2403
|
-
@staticmethod
|
|
2404
|
-
async def join(
|
|
2405
|
-
run_id: UUID,
|
|
2406
|
-
*,
|
|
2407
|
-
thread_id: UUID,
|
|
2408
|
-
ctx: Auth.types.BaseAuthContext | None = None,
|
|
2409
|
-
) -> Fragment:
|
|
2410
|
-
"""Wait for a run to complete. If already done, return immediately.
|
|
2411
|
-
|
|
2412
|
-
Returns:
|
|
2413
|
-
the final state of the run.
|
|
2414
|
-
"""
|
|
2415
|
-
from langgraph_api.serde import Fragment
|
|
2416
|
-
from langgraph_api.utils import fetchone
|
|
2417
|
-
|
|
2418
|
-
async with connect() as conn:
|
|
2419
|
-
# Validate ownership
|
|
2420
|
-
thread_iter = await Threads.get(conn, thread_id, ctx=ctx)
|
|
2421
|
-
await fetchone(thread_iter)
|
|
2422
|
-
last_chunk: bytes | None = None
|
|
2423
|
-
# wait for the run to complete
|
|
2424
|
-
# Rely on this join's auth
|
|
2425
|
-
async for mode, chunk, _ in Runs.Stream.join(
|
|
2426
|
-
run_id,
|
|
2427
|
-
thread_id=thread_id,
|
|
2428
|
-
ctx=ctx,
|
|
2429
|
-
ignore_404=True,
|
|
2430
|
-
stream_mode=["values", "updates", "error"],
|
|
2431
|
-
):
|
|
2432
|
-
if mode == b"values":
|
|
2433
|
-
last_chunk = chunk
|
|
2434
|
-
elif mode == b"updates" and b"__interrupt__" in chunk:
|
|
2435
|
-
last_chunk = chunk
|
|
2436
|
-
elif mode == b"error":
|
|
2437
|
-
last_chunk = orjson.dumps({"__error__": orjson.Fragment(chunk)})
|
|
2438
|
-
# if we received a final chunk, return it
|
|
2439
|
-
if last_chunk is not None:
|
|
2440
|
-
# ie. if the run completed while we were waiting for it
|
|
2441
|
-
return Fragment(last_chunk)
|
|
2442
|
-
else:
|
|
2443
|
-
# otherwise, the run had already finished, so fetch the state from thread
|
|
2444
|
-
async with connect() as conn:
|
|
2445
|
-
thread_iter = await Threads.get(conn, thread_id, ctx=ctx)
|
|
2446
|
-
thread = await fetchone(thread_iter)
|
|
2447
|
-
if thread["status"] == "error":
|
|
2448
|
-
return Fragment(
|
|
2449
|
-
orjson.dumps({"__error__": orjson.Fragment(thread["error"])})
|
|
2450
|
-
)
|
|
2451
|
-
if thread["status"] == "interrupted":
|
|
2452
|
-
# Get an interrupt for the thread. There is the case where there are multiple interrupts for the same run and we may not show the same
|
|
2453
|
-
# interrupt, but we'll always show one. Long term we should show all of them.
|
|
2454
|
-
try:
|
|
2455
|
-
interrupt_map = thread["interrupts"]
|
|
2456
|
-
interrupt = [next(iter(interrupt_map.values()))[0]]
|
|
2457
|
-
return Fragment(orjson.dumps({"__interrupt__": interrupt}))
|
|
2458
|
-
except Exception:
|
|
2459
|
-
# No interrupt, but status is interrupted from a before/after block. Default back to values.
|
|
2460
|
-
pass
|
|
2461
|
-
return thread["values"]
|
|
2462
|
-
|
|
2463
2402
|
@staticmethod
|
|
2464
2403
|
async def cancel(
|
|
2465
2404
|
conn: InMemConnectionProto | AsyncConnectionProto,
|
|
@@ -2709,41 +2648,25 @@ class Runs(Authenticated):
|
|
|
2709
2648
|
async def join(
|
|
2710
2649
|
run_id: UUID,
|
|
2711
2650
|
*,
|
|
2651
|
+
stream_channel: asyncio.Queue,
|
|
2712
2652
|
thread_id: UUID,
|
|
2713
2653
|
ignore_404: bool = False,
|
|
2714
2654
|
cancel_on_disconnect: bool = False,
|
|
2715
|
-
stream_channel: asyncio.Queue | None = None,
|
|
2716
2655
|
stream_mode: list[StreamMode] | StreamMode | None = None,
|
|
2717
2656
|
last_event_id: str | None = None,
|
|
2718
2657
|
ctx: Auth.types.BaseAuthContext | None = None,
|
|
2719
2658
|
) -> AsyncIterator[tuple[bytes, bytes, bytes | None]]:
|
|
2720
2659
|
"""Stream the run output."""
|
|
2721
2660
|
from langgraph_api.asyncio import create_task
|
|
2722
|
-
from langgraph_api.serde import json_loads
|
|
2723
|
-
|
|
2724
|
-
queue = (
|
|
2725
|
-
stream_channel
|
|
2726
|
-
if stream_channel
|
|
2727
|
-
else await Runs.Stream.subscribe(run_id, thread_id)
|
|
2728
|
-
)
|
|
2661
|
+
from langgraph_api.serde import json_dumpb, json_loads
|
|
2729
2662
|
|
|
2663
|
+
queue = stream_channel
|
|
2730
2664
|
try:
|
|
2731
2665
|
async with connect() as conn:
|
|
2732
|
-
|
|
2733
|
-
ctx
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
)
|
|
2737
|
-
if filters:
|
|
2738
|
-
thread = await Threads._get_with_filters(
|
|
2739
|
-
cast(InMemConnectionProto, conn), thread_id, filters
|
|
2740
|
-
)
|
|
2741
|
-
if not thread:
|
|
2742
|
-
raise WrappedHTTPException(
|
|
2743
|
-
HTTPException(
|
|
2744
|
-
status_code=404, detail="Thread not found"
|
|
2745
|
-
)
|
|
2746
|
-
)
|
|
2666
|
+
try:
|
|
2667
|
+
await Runs.Stream.check_run_stream_auth(run_id, thread_id, ctx)
|
|
2668
|
+
except HTTPException as e:
|
|
2669
|
+
raise WrappedHTTPException(e) from None
|
|
2747
2670
|
run = await Runs.get(conn, run_id, thread_id=thread_id, ctx=ctx)
|
|
2748
2671
|
|
|
2749
2672
|
for message in get_stream_manager().restore_messages(
|
|
@@ -2822,8 +2745,10 @@ class Runs(Authenticated):
|
|
|
2822
2745
|
elif run is None:
|
|
2823
2746
|
yield (
|
|
2824
2747
|
b"error",
|
|
2825
|
-
|
|
2826
|
-
|
|
2748
|
+
json_dumpb(
|
|
2749
|
+
HTTPException(
|
|
2750
|
+
status_code=404, detail="Run not found"
|
|
2751
|
+
)
|
|
2827
2752
|
),
|
|
2828
2753
|
None,
|
|
2829
2754
|
)
|
|
@@ -2840,6 +2765,25 @@ class Runs(Authenticated):
|
|
|
2840
2765
|
stream_manager = get_stream_manager()
|
|
2841
2766
|
await stream_manager.remove_queue(run_id, thread_id, queue)
|
|
2842
2767
|
|
|
2768
|
+
@staticmethod
|
|
2769
|
+
async def check_run_stream_auth(
|
|
2770
|
+
run_id: UUID,
|
|
2771
|
+
thread_id: UUID,
|
|
2772
|
+
ctx: Auth.types.BaseAuthContext | None = None,
|
|
2773
|
+
) -> None:
|
|
2774
|
+
async with connect() as conn:
|
|
2775
|
+
filters = await Runs.handle_event(
|
|
2776
|
+
ctx,
|
|
2777
|
+
"read",
|
|
2778
|
+
Auth.types.ThreadsRead(thread_id=thread_id),
|
|
2779
|
+
)
|
|
2780
|
+
if filters:
|
|
2781
|
+
thread = await Threads._get_with_filters(
|
|
2782
|
+
cast(InMemConnectionProto, conn), thread_id, filters
|
|
2783
|
+
)
|
|
2784
|
+
if not thread:
|
|
2785
|
+
raise HTTPException(status_code=404, detail="Thread not found")
|
|
2786
|
+
|
|
2843
2787
|
@staticmethod
|
|
2844
2788
|
async def publish(
|
|
2845
2789
|
run_id: UUID | str,
|
|
@@ -3041,6 +2985,7 @@ async def _empty_generator():
|
|
|
3041
2985
|
|
|
3042
2986
|
|
|
3043
2987
|
__all__ = [
|
|
2988
|
+
"StreamHandler",
|
|
3044
2989
|
"Assistants",
|
|
3045
2990
|
"Crons",
|
|
3046
2991
|
"Runs",
|
{langgraph_runtime_inmem-0.12.0.dist-info → langgraph_runtime_inmem-0.13.0.dist-info}/RECORD
RENAMED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
langgraph_runtime_inmem/__init__.py,sha256=
|
|
1
|
+
langgraph_runtime_inmem/__init__.py,sha256=BfkPnL0o38bb46SxdkPISETcTeuk3iLRkwBytAH1XJk,311
|
|
2
2
|
langgraph_runtime_inmem/checkpoint.py,sha256=nc1G8DqVdIu-ibjKTqXfbPfMbAsKjPObKqegrSzo6Po,4432
|
|
3
3
|
langgraph_runtime_inmem/database.py,sha256=QgaA_WQo1IY6QioYd8r-e6-0B0rnC5anS0muIEJWby0,6364
|
|
4
4
|
langgraph_runtime_inmem/inmem_stream.py,sha256=utL1OlOJsy6VDkSGAA6eX9nETreZlM6K6nhfNoubmRQ,9011
|
|
5
|
-
langgraph_runtime_inmem/lifespan.py,sha256=
|
|
5
|
+
langgraph_runtime_inmem/lifespan.py,sha256=tngIYHMhDwTFd2zgpq9CZOxcBLONYYnkhwv2d2T5WWQ,3614
|
|
6
6
|
langgraph_runtime_inmem/metrics.py,sha256=HhO0RC2bMDTDyGBNvnd2ooLebLA8P1u5oq978Kp_nAA,392
|
|
7
|
-
langgraph_runtime_inmem/ops.py,sha256=
|
|
7
|
+
langgraph_runtime_inmem/ops.py,sha256=62xhcMEXY2Ijpe_jPqavOaY5EGSlm8p2j7BDKCoAYhM,108891
|
|
8
8
|
langgraph_runtime_inmem/queue.py,sha256=33qfFKPhQicZ1qiibllYb-bTFzUNSN2c4bffPACP5es,9952
|
|
9
9
|
langgraph_runtime_inmem/retry.py,sha256=XmldOP4e_H5s264CagJRVnQMDFcEJR_dldVR1Hm5XvM,763
|
|
10
10
|
langgraph_runtime_inmem/store.py,sha256=rTfL1JJvd-j4xjTrL8qDcynaWF6gUJ9-GDVwH0NBD_I,3506
|
|
11
|
-
langgraph_runtime_inmem-0.
|
|
12
|
-
langgraph_runtime_inmem-0.
|
|
13
|
-
langgraph_runtime_inmem-0.
|
|
11
|
+
langgraph_runtime_inmem-0.13.0.dist-info/METADATA,sha256=HSj4R2J9De58icVXoVx2b1tN0zxPDmkjj16r3q5Bvlw,566
|
|
12
|
+
langgraph_runtime_inmem-0.13.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
13
|
+
langgraph_runtime_inmem-0.13.0.dist-info/RECORD,,
|
|
File without changes
|