langgraph-runtime-inmem 0.13.0__py3-none-any.whl → 0.14.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.13.0"
12
+ __version__ = "0.14.0"
13
13
  __all__ = [
14
14
  "ops",
15
15
  "database",
@@ -108,9 +108,10 @@ class StreamManager:
108
108
  thread_id = _ensure_uuid(thread_id)
109
109
 
110
110
  message.id = _generate_ms_seq_id().encode()
111
+ # For resumable run streams, embed the generated message ID into the frame
112
+ topic = message.topic.decode()
111
113
  if resumable:
112
114
  self.message_stores[thread_id][run_id].append(message)
113
- topic = message.topic.decode()
114
115
  if "control" in topic:
115
116
  self.control_keys[thread_id][run_id] = message
116
117
  queues = self.control_queues[thread_id][run_id]
@@ -1720,6 +1720,9 @@ class Threads(Authenticated):
1720
1720
  stream_modes: list[ThreadStreamMode],
1721
1721
  ) -> AsyncIterator[tuple[bytes, bytes, bytes | None]]:
1722
1722
  """Stream the thread output."""
1723
+ from langgraph_api.utils.stream_codec import (
1724
+ decode_stream_message,
1725
+ )
1723
1726
 
1724
1727
  def should_filter_event(event_name: str, message_bytes: bytes) -> bool:
1725
1728
  """Check if an event should be filtered out based on stream_modes."""
@@ -1738,8 +1741,6 @@ class Threads(Authenticated):
1738
1741
  pass
1739
1742
  return True
1740
1743
 
1741
- from langgraph_api.serde import json_loads
1742
-
1743
1744
  stream_manager = get_stream_manager()
1744
1745
  seen_runs: set[UUID] = set()
1745
1746
  created_queues: list[tuple[UUID, asyncio.Queue]] = []
@@ -1768,35 +1769,26 @@ class Threads(Authenticated):
1768
1769
 
1769
1770
  # Yield sorted events
1770
1771
  for message, run_id in all_events:
1771
- data = json_loads(message.data)
1772
- event_name = data["event"]
1773
- message_content = data["message"]
1772
+ decoded = decode_stream_message(
1773
+ message.data, channel=message.topic
1774
+ )
1775
+ event_bytes = decoded.event_bytes
1776
+ message_bytes = decoded.message_bytes
1774
1777
 
1775
- if event_name == "control":
1776
- if message_content == b"done":
1778
+ if event_bytes == b"control":
1779
+ if message_bytes == b"done":
1777
1780
  event_bytes = b"metadata"
1778
1781
  message_bytes = orjson.dumps(
1779
1782
  {"status": "run_done", "run_id": run_id}
1780
1783
  )
1781
- # Filter events based on stream_modes
1782
- if not should_filter_event(
1783
- "metadata", message_bytes
1784
- ):
1785
- yield (
1786
- event_bytes,
1787
- message_bytes,
1788
- message.id,
1789
- )
1790
- else:
1791
- event_bytes = event_name.encode()
1792
- message_bytes = base64.b64decode(message_content)
1793
- # Filter events based on stream_modes
1794
- if not should_filter_event(event_name, message_bytes):
1795
- yield (
1796
- event_bytes,
1797
- message_bytes,
1798
- message.id,
1799
- )
1784
+ if not should_filter_event(
1785
+ event_bytes.decode("utf-8"), message_bytes
1786
+ ):
1787
+ yield (
1788
+ event_bytes,
1789
+ message_bytes,
1790
+ message.id,
1791
+ )
1800
1792
 
1801
1793
  # Listen for live messages from all queues
1802
1794
  while True:
@@ -1813,40 +1805,27 @@ class Threads(Authenticated):
1813
1805
  message = await asyncio.wait_for(
1814
1806
  queue.get(), timeout=0.2
1815
1807
  )
1816
- data = json_loads(message.data)
1817
- event_name = data["event"]
1818
- message_content = data["message"]
1819
-
1820
- if event_name == "control":
1821
- if message_content == b"done":
1822
- # Extract run_id from topic
1823
- topic = message.topic.decode()
1824
- run_id = topic.split("run:")[1].split(":")[0]
1825
- event_bytes = b"metadata"
1826
- message_bytes = orjson.dumps(
1827
- {"status": "run_done", "run_id": run_id}
1828
- )
1829
- # Filter events based on stream_modes
1830
- if not should_filter_event(
1831
- "metadata", message_bytes
1832
- ):
1833
- yield (
1834
- event_bytes,
1835
- message_bytes,
1836
- message.id,
1837
- )
1838
- else:
1839
- event_bytes = event_name.encode()
1840
- message_bytes = base64.b64decode(message_content)
1841
- # Filter events based on stream_modes
1808
+ decoded = decode_stream_message(
1809
+ message.data, channel=message.topic
1810
+ )
1811
+ event = decoded.event_bytes
1812
+ event_name = event.decode("utf-8")
1813
+ payload = decoded.message_bytes
1814
+
1815
+ if event == b"control" and payload == b"done":
1816
+ topic = message.topic.decode()
1817
+ run_id = topic.split("run:")[1].split(":")[0]
1818
+ meta_event = b"metadata"
1819
+ meta_payload = orjson.dumps(
1820
+ {"status": "run_done", "run_id": run_id}
1821
+ )
1842
1822
  if not should_filter_event(
1843
- event_name, message_bytes
1823
+ "metadata", meta_payload
1844
1824
  ):
1845
- yield (
1846
- event_bytes,
1847
- message_bytes,
1848
- message.id,
1849
- )
1825
+ yield (meta_event, meta_payload, message.id)
1826
+ else:
1827
+ if not should_filter_event(event_name, payload):
1828
+ yield (event, payload, message.id)
1850
1829
 
1851
1830
  except TimeoutError:
1852
1831
  continue
@@ -1882,18 +1861,12 @@ class Threads(Authenticated):
1882
1861
  message: bytes,
1883
1862
  ) -> None:
1884
1863
  """Publish a thread-level event to the thread stream."""
1885
- from langgraph_api.serde import json_dumpb
1864
+ from langgraph_api.utils.stream_codec import STREAM_CODEC
1886
1865
 
1887
1866
  topic = f"thread:{thread_id}:stream".encode()
1888
1867
 
1889
1868
  stream_manager = get_stream_manager()
1890
- # Send to thread stream topic
1891
- payload = json_dumpb(
1892
- {
1893
- "event": event,
1894
- "message": message,
1895
- }
1896
- )
1869
+ payload = STREAM_CODEC.encode(event, message)
1897
1870
  await stream_manager.put_thread(
1898
1871
  str(thread_id), Message(topic=topic, data=payload)
1899
1872
  )
@@ -2065,6 +2038,7 @@ class Runs(Authenticated):
2065
2038
  This method should be called as a context manager by a worker executing a run.
2066
2039
  """
2067
2040
  from langgraph_api.asyncio import SimpleTaskGroup, ValueEvent
2041
+ from langgraph_api.utils.stream_codec import STREAM_CODEC
2068
2042
 
2069
2043
  stream_manager = get_stream_manager()
2070
2044
  # Get control queue for this run (normal queue is created during run creation)
@@ -2084,10 +2058,10 @@ class Runs(Authenticated):
2084
2058
  )
2085
2059
  await stream_manager.put(run_id, thread_id, control_message)
2086
2060
 
2087
- # Signal done to all subscribers
2061
+ # Signal done to all subscribers using stream codec
2088
2062
  stream_message = Message(
2089
2063
  topic=f"run:{run_id}:stream".encode(),
2090
- data={"event": "control", "message": b"done"},
2064
+ data=STREAM_CODEC.encode("control", b"done"),
2091
2065
  )
2092
2066
  await stream_manager.put(
2093
2067
  run_id, thread_id, stream_message, resumable=resumable
@@ -2658,7 +2632,8 @@ class Runs(Authenticated):
2658
2632
  ) -> AsyncIterator[tuple[bytes, bytes, bytes | None]]:
2659
2633
  """Stream the run output."""
2660
2634
  from langgraph_api.asyncio import create_task
2661
- from langgraph_api.serde import json_dumpb, json_loads
2635
+ from langgraph_api.serde import json_dumpb
2636
+ from langgraph_api.utils.stream_codec import decode_stream_message
2662
2637
 
2663
2638
  queue = stream_channel
2664
2639
  try:
@@ -2673,13 +2648,12 @@ class Runs(Authenticated):
2673
2648
  run_id, thread_id, last_event_id
2674
2649
  ):
2675
2650
  data, id = message.data, message.id
2676
-
2677
- data = json_loads(data)
2678
- mode = data["event"]
2679
- message = data["message"]
2651
+ decoded = decode_stream_message(data, channel=message.topic)
2652
+ mode = decoded.event_bytes.decode("utf-8")
2653
+ payload = decoded.message_bytes
2680
2654
 
2681
2655
  if mode == "control":
2682
- if message == b"done":
2656
+ if payload == b"done":
2683
2657
  return
2684
2658
  elif (
2685
2659
  not stream_mode
@@ -2692,7 +2666,7 @@ class Runs(Authenticated):
2692
2666
  and mode.startswith("messages")
2693
2667
  )
2694
2668
  ):
2695
- yield mode.encode(), base64.b64decode(message), id
2669
+ yield mode.encode(), payload, id
2696
2670
  logger.debug(
2697
2671
  "Replayed run event",
2698
2672
  run_id=str(run_id),
@@ -2706,13 +2680,12 @@ class Runs(Authenticated):
2706
2680
  # Wait for messages with a timeout
2707
2681
  message = await asyncio.wait_for(queue.get(), timeout=0.5)
2708
2682
  data, id = message.data, message.id
2709
-
2710
- data = json_loads(data)
2711
- mode = data["event"]
2712
- message = data["message"]
2683
+ decoded = decode_stream_message(data, channel=message.topic)
2684
+ mode = decoded.event_bytes.decode("utf-8")
2685
+ payload = decoded.message_bytes
2713
2686
 
2714
2687
  if mode == "control":
2715
- if message == b"done":
2688
+ if payload == b"done":
2716
2689
  break
2717
2690
  elif (
2718
2691
  not stream_mode
@@ -2725,13 +2698,13 @@ class Runs(Authenticated):
2725
2698
  and mode.startswith("messages")
2726
2699
  )
2727
2700
  ):
2728
- yield mode.encode(), base64.b64decode(message), id
2701
+ yield mode.encode(), payload, id
2729
2702
  logger.debug(
2730
2703
  "Streamed run event",
2731
2704
  run_id=str(run_id),
2732
2705
  stream_mode=mode,
2733
2706
  message_id=id,
2734
- data=message,
2707
+ data=payload,
2735
2708
  )
2736
2709
  except TimeoutError:
2737
2710
  # Check if the run is still pending
@@ -2794,18 +2767,13 @@ class Runs(Authenticated):
2794
2767
  resumable: bool = False,
2795
2768
  ) -> None:
2796
2769
  """Publish a message to all subscribers of the run stream."""
2797
- from langgraph_api.serde import json_dumpb
2770
+ from langgraph_api.utils.stream_codec import STREAM_CODEC
2798
2771
 
2799
2772
  topic = f"run:{run_id}:stream".encode()
2800
2773
 
2801
2774
  stream_manager = get_stream_manager()
2802
- # Send to all queues subscribed to this run_id
2803
- payload = json_dumpb(
2804
- {
2805
- "event": event,
2806
- "message": message,
2807
- }
2808
- )
2775
+ # Send to all queues subscribed to this run_id using protocol frame
2776
+ payload = STREAM_CODEC.encode(event, message)
2809
2777
  await stream_manager.put(
2810
2778
  run_id, thread_id, Message(topic=topic, data=payload), resumable
2811
2779
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: langgraph-runtime-inmem
3
- Version: 0.13.0
3
+ Version: 0.14.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=BfkPnL0o38bb46SxdkPISETcTeuk3iLRkwBytAH1XJk,311
1
+ langgraph_runtime_inmem/__init__.py,sha256=csu7K0Iyy69kpS21MCa9q3MkfeJLSBXmsT02eK_hGXc,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
- langgraph_runtime_inmem/inmem_stream.py,sha256=utL1OlOJsy6VDkSGAA6eX9nETreZlM6K6nhfNoubmRQ,9011
4
+ langgraph_runtime_inmem/inmem_stream.py,sha256=PFLWbsxU8RqbT5mYJgNk6v5q6TWJRIY1hkZWhJF8nkI,9094
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=62xhcMEXY2Ijpe_jPqavOaY5EGSlm8p2j7BDKCoAYhM,108891
7
+ langgraph_runtime_inmem/ops.py,sha256=63uV88PijGnNxzgWGL_SljeXIeHd8dAwowBrWi9X4Xo,107645
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.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,,
11
+ langgraph_runtime_inmem-0.14.0.dist-info/METADATA,sha256=jegaYI5exlmydXtt4oxMbgFBCIrKaV7HawwHKNr2MrU,566
12
+ langgraph_runtime_inmem-0.14.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
13
+ langgraph_runtime_inmem-0.14.0.dist-info/RECORD,,