langgraph-runtime-inmem 0.12.1__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.
@@ -9,7 +9,7 @@ from langgraph_runtime_inmem import (
9
9
  store,
10
10
  )
11
11
 
12
- __version__ = "0.12.1"
12
+ __version__ = "0.13.0"
13
13
  __all__ = [
14
14
  "ops",
15
15
  "database",
@@ -62,9 +62,9 @@ if typing.TYPE_CHECKING:
62
62
  ThreadUpdateResponse,
63
63
  )
64
64
  from langgraph_api.schema import Interrupt as InterruptSchema
65
- from langgraph_api.serde import Fragment
66
65
  from langgraph_api.utils import AsyncConnectionProto
67
66
 
67
+ StreamHandler = ContextQueue
68
68
 
69
69
  logger = structlog.stdlib.get_logger(__name__)
70
70
 
@@ -2399,68 +2399,6 @@ class Runs(Authenticated):
2399
2399
 
2400
2400
  return _yield_deleted()
2401
2401
 
2402
- @staticmethod
2403
- async def join(
2404
- run_id: UUID,
2405
- *,
2406
- thread_id: UUID,
2407
- ctx: Auth.types.BaseAuthContext | None = None,
2408
- ) -> Fragment:
2409
- """Wait for a run to complete. If already done, return immediately.
2410
-
2411
- Returns:
2412
- the final state of the run.
2413
- """
2414
- from langgraph_api.serde import Fragment
2415
- from langgraph_api.utils import fetchone
2416
-
2417
- async with connect() as conn:
2418
- # Validate ownership
2419
- thread_iter = await Threads.get(conn, thread_id, ctx=ctx)
2420
- await fetchone(thread_iter)
2421
- last_chunk: bytes | None = None
2422
- # wait for the run to complete
2423
- # Rely on this join's auth
2424
- async with await Runs.Stream.subscribe(run_id, thread_id) as sub:
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_channel=sub,
2431
- stream_mode=["values", "updates", "error"],
2432
- ):
2433
- if mode == b"values":
2434
- last_chunk = chunk
2435
- elif mode == b"updates" and b"__interrupt__" in chunk:
2436
- last_chunk = chunk
2437
- elif mode == b"error":
2438
- last_chunk = orjson.dumps({"__error__": orjson.Fragment(chunk)})
2439
- # if we received a final chunk, return it
2440
- if last_chunk is not None:
2441
- # ie. if the run completed while we were waiting for it
2442
- return Fragment(last_chunk)
2443
- else:
2444
- # otherwise, the run had already finished, so fetch the state from thread
2445
- async with connect() as conn:
2446
- thread_iter = await Threads.get(conn, thread_id, ctx=ctx)
2447
- thread = await fetchone(thread_iter)
2448
- if thread["status"] == "error":
2449
- return Fragment(
2450
- orjson.dumps({"__error__": orjson.Fragment(thread["error"])})
2451
- )
2452
- if thread["status"] == "interrupted":
2453
- # 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
2454
- # interrupt, but we'll always show one. Long term we should show all of them.
2455
- try:
2456
- interrupt_map = thread["interrupts"]
2457
- interrupt = [next(iter(interrupt_map.values()))[0]]
2458
- return Fragment(orjson.dumps({"__interrupt__": interrupt}))
2459
- except Exception:
2460
- # No interrupt, but status is interrupted from a before/after block. Default back to values.
2461
- pass
2462
- return thread["values"]
2463
-
2464
2402
  @staticmethod
2465
2403
  async def cancel(
2466
2404
  conn: InMemConnectionProto | AsyncConnectionProto,
@@ -2720,26 +2658,15 @@ class Runs(Authenticated):
2720
2658
  ) -> AsyncIterator[tuple[bytes, bytes, bytes | None]]:
2721
2659
  """Stream the run output."""
2722
2660
  from langgraph_api.asyncio import create_task
2723
- from langgraph_api.serde import json_loads
2661
+ from langgraph_api.serde import json_dumpb, json_loads
2724
2662
 
2725
2663
  queue = stream_channel
2726
2664
  try:
2727
2665
  async with connect() as conn:
2728
- filters = await Runs.handle_event(
2729
- ctx,
2730
- "read",
2731
- Auth.types.ThreadsRead(thread_id=thread_id),
2732
- )
2733
- if filters:
2734
- thread = await Threads._get_with_filters(
2735
- cast(InMemConnectionProto, conn), thread_id, filters
2736
- )
2737
- if not thread:
2738
- raise WrappedHTTPException(
2739
- HTTPException(
2740
- status_code=404, detail="Thread not found"
2741
- )
2742
- )
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
2743
2670
  run = await Runs.get(conn, run_id, thread_id=thread_id, ctx=ctx)
2744
2671
 
2745
2672
  for message in get_stream_manager().restore_messages(
@@ -2818,8 +2745,10 @@ class Runs(Authenticated):
2818
2745
  elif run is None:
2819
2746
  yield (
2820
2747
  b"error",
2821
- HTTPException(
2822
- status_code=404, detail="Run not found"
2748
+ json_dumpb(
2749
+ HTTPException(
2750
+ status_code=404, detail="Run not found"
2751
+ )
2823
2752
  ),
2824
2753
  None,
2825
2754
  )
@@ -2836,6 +2765,25 @@ class Runs(Authenticated):
2836
2765
  stream_manager = get_stream_manager()
2837
2766
  await stream_manager.remove_queue(run_id, thread_id, queue)
2838
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
+
2839
2787
  @staticmethod
2840
2788
  async def publish(
2841
2789
  run_id: UUID | str,
@@ -3037,6 +2985,7 @@ async def _empty_generator():
3037
2985
 
3038
2986
 
3039
2987
  __all__ = [
2988
+ "StreamHandler",
3040
2989
  "Assistants",
3041
2990
  "Crons",
3042
2991
  "Runs",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: langgraph-runtime-inmem
3
- Version: 0.12.1
3
+ Version: 0.13.0
4
4
  Summary: Inmem implementation for the LangGraph API server.
5
5
  Author-email: Will Fu-Hinthorn <will@langchain.dev>
6
6
  License: Elastic-2.0
@@ -1,13 +1,13 @@
1
- langgraph_runtime_inmem/__init__.py,sha256=tv9_9neTzC-cY8ATa9lnqpF4WJ-YZW3fYhQ9rSL4Yu8,311
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
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=593xx2A5E7y2TY6nLpbkFSsODH6guwm1y9z-ars-seU,111327
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.1.dist-info/METADATA,sha256=faLaXWGpAJnAK6Z5XS0TmGBtafg7Cef16_nc_Viw8yg,566
12
- langgraph_runtime_inmem-0.12.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
13
- langgraph_runtime_inmem-0.12.1.dist-info/RECORD,,
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,,