langgraph-runtime-inmem 0.6.11__py3-none-any.whl → 0.6.13__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.6.11"
12
+ __version__ = "0.6.13"
13
13
  __all__ = [
14
14
  "ops",
15
15
  "database",
@@ -1001,6 +1001,7 @@ class Threads(Authenticated):
1001
1001
  thread_id: UUID,
1002
1002
  run_id: UUID,
1003
1003
  run_status: RunStatus | Literal["rollback"],
1004
+ graph_id: str,
1004
1005
  checkpoint: CheckpointPayload | None = None,
1005
1006
  exception: BaseException | None = None,
1006
1007
  ) -> None:
@@ -1080,6 +1081,7 @@ class Threads(Authenticated):
1080
1081
  final_thread_status = "busy"
1081
1082
  else:
1082
1083
  final_thread_status = base_thread_status
1084
+ thread["metadata"]["graph_id"] = graph_id
1083
1085
  thread.update(
1084
1086
  {
1085
1087
  "updated_at": now,
@@ -1273,7 +1275,15 @@ class Threads(Authenticated):
1273
1275
  metadata = thread.get("metadata", {})
1274
1276
  thread_config = thread.get("config", {})
1275
1277
 
1276
- if graph_id := metadata.get("graph_id"):
1278
+ # Fallback to graph_id from run if not in thread metadata
1279
+ graph_id = metadata.get("graph_id")
1280
+ if not graph_id:
1281
+ for run in conn.store["runs"]:
1282
+ if run["thread_id"] == thread_id:
1283
+ graph_id = run["kwargs"]["config"]["configurable"]["graph_id"]
1284
+ break
1285
+
1286
+ if graph_id:
1277
1287
  # format latest checkpoint for response
1278
1288
  checkpointer.latest_iter = checkpoint
1279
1289
  async with get_graph(
@@ -1351,7 +1361,15 @@ class Threads(Authenticated):
1351
1361
  detail=f"Thread {thread_id} has in-flight runs: {pending_runs}",
1352
1362
  )
1353
1363
 
1354
- if graph_id := metadata.get("graph_id"):
1364
+ # Fallback to graph_id from run if not in thread metadata
1365
+ graph_id = metadata.get("graph_id")
1366
+ if not graph_id:
1367
+ for run in conn.store["runs"]:
1368
+ if run["thread_id"] == thread_id:
1369
+ graph_id = run["kwargs"]["config"]["configurable"]["graph_id"]
1370
+ break
1371
+
1372
+ if graph_id:
1355
1373
  config["configurable"].setdefault("graph_id", graph_id)
1356
1374
 
1357
1375
  checkpointer.latest_iter = checkpoint
@@ -1389,7 +1407,11 @@ class Threads(Authenticated):
1389
1407
  checkpoint_id=next_config["configurable"]["checkpoint_id"],
1390
1408
  )
1391
1409
  else:
1392
- raise HTTPException(status_code=400, detail="Thread has no graph ID.")
1410
+ raise HTTPException(
1411
+ status_code=400,
1412
+ detail=f"Thread '{thread['thread_id']}' has no assigned graph ID. This usually occurs when no runs have been made on this particular thread."
1413
+ " This operation requires a graph ID. Please ensure a run has been made for the thread or manually update the thread metadata (by setting the 'graph_id' field) before running this operation.",
1414
+ )
1393
1415
 
1394
1416
  @staticmethod
1395
1417
  async def bulk(
@@ -1471,7 +1493,11 @@ class Threads(Authenticated):
1471
1493
  checkpoint=next_config["configurable"],
1472
1494
  )
1473
1495
  else:
1474
- raise HTTPException(status_code=400, detail="Thread has no graph ID")
1496
+ raise HTTPException(
1497
+ status_code=400,
1498
+ detail=f"Thread '{thread['thread_id']}' has no assigned graph ID. This usually occurs when no runs have been made on this particular thread."
1499
+ " This operation requires a graph ID. Please ensure a run has been made for the thread or manually update the thread metadata (by setting the 'graph_id' field) before running this operation.",
1500
+ )
1475
1501
 
1476
1502
  @staticmethod
1477
1503
  async def list(
@@ -1678,9 +1704,9 @@ class Runs(Authenticated):
1678
1704
  await stream_manager.remove_control_queue(run_id, queue)
1679
1705
 
1680
1706
  @staticmethod
1681
- async def sweep(conn: InMemConnectionProto) -> list[UUID]:
1707
+ async def sweep() -> None:
1682
1708
  """Sweep runs that are no longer running"""
1683
- return []
1709
+ pass
1684
1710
 
1685
1711
  @staticmethod
1686
1712
  def _merge_jsonb(*objects: dict) -> dict:
@@ -1714,6 +1740,7 @@ class Runs(Authenticated):
1714
1740
  ctx: Auth.types.BaseAuthContext | None = None,
1715
1741
  ) -> AsyncIterator[Run]:
1716
1742
  """Create a run."""
1743
+ from langgraph_api.config import FF_RICH_THREADS
1717
1744
  from langgraph_api.schema import Run, Thread
1718
1745
 
1719
1746
  assistant_id = _ensure_uuid(assistant_id)
@@ -1759,34 +1786,50 @@ class Runs(Authenticated):
1759
1786
  # Create new thread
1760
1787
  if thread_id is None:
1761
1788
  thread_id = uuid4()
1762
- thread = Thread(
1763
- thread_id=thread_id,
1764
- status="busy",
1765
- metadata={
1766
- "graph_id": assistant["graph_id"],
1767
- "assistant_id": str(assistant_id),
1768
- **(config.get("metadata") or {}),
1769
- **metadata,
1770
- },
1771
- config=Runs._merge_jsonb(
1772
- assistant["config"],
1773
- config,
1774
- {
1775
- "configurable": Runs._merge_jsonb(
1776
- Runs._get_configurable(assistant["config"]),
1777
- Runs._get_configurable(config),
1778
- )
1789
+ if FF_RICH_THREADS:
1790
+ thread = Thread(
1791
+ thread_id=thread_id,
1792
+ status="busy",
1793
+ metadata={
1794
+ "graph_id": assistant["graph_id"],
1795
+ "assistant_id": str(assistant_id),
1796
+ **(config.get("metadata") or {}),
1797
+ **metadata,
1779
1798
  },
1780
- ),
1781
- created_at=datetime.now(UTC),
1782
- updated_at=datetime.now(UTC),
1783
- values=b"",
1784
- )
1799
+ config=Runs._merge_jsonb(
1800
+ assistant["config"],
1801
+ config,
1802
+ {
1803
+ "configurable": Runs._merge_jsonb(
1804
+ Runs._get_configurable(assistant["config"]),
1805
+ Runs._get_configurable(config),
1806
+ )
1807
+ },
1808
+ ),
1809
+ created_at=datetime.now(UTC),
1810
+ updated_at=datetime.now(UTC),
1811
+ values=b"",
1812
+ )
1813
+ else:
1814
+ thread = Thread(
1815
+ thread_id=thread_id,
1816
+ status="idle",
1817
+ metadata={
1818
+ "graph_id": assistant["graph_id"],
1819
+ "assistant_id": str(assistant_id),
1820
+ **(config.get("metadata") or {}),
1821
+ **metadata,
1822
+ },
1823
+ config={},
1824
+ created_at=datetime.now(UTC),
1825
+ updated_at=datetime.now(UTC),
1826
+ values=b"",
1827
+ )
1785
1828
  await logger.ainfo("Creating thread", thread_id=thread_id)
1786
1829
  conn.store["threads"].append(thread)
1787
1830
  elif existing_thread:
1788
1831
  # Update existing thread
1789
- if existing_thread["status"] != "busy":
1832
+ if FF_RICH_THREADS and existing_thread["status"] != "busy":
1790
1833
  existing_thread["status"] = "busy"
1791
1834
  existing_thread["metadata"] = Runs._merge_jsonb(
1792
1835
  existing_thread["metadata"],
@@ -1875,7 +1918,9 @@ class Runs(Authenticated):
1875
1918
  "metadata": merged_metadata,
1876
1919
  },
1877
1920
  ),
1878
- "context": configurable,
1921
+ "context": Runs._merge_jsonb(
1922
+ assistant.get("context", {}), kwargs.get("context", {})
1923
+ ),
1879
1924
  },
1880
1925
  ),
1881
1926
  multitask_strategy=multitask_strategy,
@@ -128,8 +128,7 @@ async def queue():
128
128
  # sweep runs if needed
129
129
  if do_sweep:
130
130
  last_sweep_secs = loop.time()
131
- run_ids = await ops.Runs.sweep(conn)
132
- logger.info("Swept runs", run_ids=run_ids)
131
+ await ops.Runs.sweep()
133
132
  except Exception as exc:
134
133
  # keep trying to run the scheduler indefinitely
135
134
  logger.exception("Background worker scheduler failed", exc_info=exc)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: langgraph-runtime-inmem
3
- Version: 0.6.11
3
+ Version: 0.6.13
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=FaiDP9SdI1qgH5N7_RMO7yqFhq5967V9hXeJsDFc9PA,311
1
+ langgraph_runtime_inmem/__init__.py,sha256=mPj20Y7jJEr9XATlg7oD3Q0F4BJdwWnfN7JMijIiRHc,311
2
2
  langgraph_runtime_inmem/checkpoint.py,sha256=nc1G8DqVdIu-ibjKTqXfbPfMbAsKjPObKqegrSzo6Po,4432
3
3
  langgraph_runtime_inmem/database.py,sha256=G_6L2khpRDSpS2Vs_SujzHayODcwG5V2IhFP7LLBXgw,6349
4
4
  langgraph_runtime_inmem/inmem_stream.py,sha256=UWk1srLF44HZPPbRdArGGhsy0MY0UOJKSIxBSO7Hosc,5138
5
5
  langgraph_runtime_inmem/lifespan.py,sha256=t0w2MX2dGxe8yNtSX97Z-d2pFpllSLS4s1rh2GJDw5M,3557
6
6
  langgraph_runtime_inmem/metrics.py,sha256=HhO0RC2bMDTDyGBNvnd2ooLebLA8P1u5oq978Kp_nAA,392
7
- langgraph_runtime_inmem/ops.py,sha256=pf5wtLPTJWwmjr9zsGXHdN7slXrYR2PQvCx71KujFqE,91593
8
- langgraph_runtime_inmem/queue.py,sha256=nqfgz7j_Jkh5Ek5-RsHB2Uvwbxguu9IUPkGXIxvFPns,10037
7
+ langgraph_runtime_inmem/ops.py,sha256=ffxYACydXPmWKt89AY22M1j8s75JbFMtzXI1SKC3R50,93949
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.6.11.dist-info/METADATA,sha256=U4PqBeXV9YamUB2A8etc50Z8mZ2WxYJ0swoo3WSy6nk,566
12
- langgraph_runtime_inmem-0.6.11.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
13
- langgraph_runtime_inmem-0.6.11.dist-info/RECORD,,
11
+ langgraph_runtime_inmem-0.6.13.dist-info/METADATA,sha256=GUxT1ClUkx_1b0nR-tiuetNRDfSoB5iejMXS2ieX9HA,566
12
+ langgraph_runtime_inmem-0.6.13.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
13
+ langgraph_runtime_inmem-0.6.13.dist-info/RECORD,,