langgraph-runtime-inmem 0.36.0.dev2__tar.gz → 0.36.0.dev4__tar.gz

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.
Files changed (18) hide show
  1. {langgraph_runtime_inmem-0.36.0.dev2 → langgraph_runtime_inmem-0.36.0.dev4}/PKG-INFO +1 -1
  2. {langgraph_runtime_inmem-0.36.0.dev2 → langgraph_runtime_inmem-0.36.0.dev4}/langgraph_runtime_inmem/__init__.py +1 -1
  3. {langgraph_runtime_inmem-0.36.0.dev2 → langgraph_runtime_inmem-0.36.0.dev4}/langgraph_runtime_inmem/inmem_stream.py +2 -0
  4. {langgraph_runtime_inmem-0.36.0.dev2 → langgraph_runtime_inmem-0.36.0.dev4}/langgraph_runtime_inmem/ops.py +31 -16
  5. {langgraph_runtime_inmem-0.36.0.dev2 → langgraph_runtime_inmem-0.36.0.dev4}/.gitignore +0 -0
  6. {langgraph_runtime_inmem-0.36.0.dev2 → langgraph_runtime_inmem-0.36.0.dev4}/Makefile +0 -0
  7. {langgraph_runtime_inmem-0.36.0.dev2 → langgraph_runtime_inmem-0.36.0.dev4}/README.md +0 -0
  8. {langgraph_runtime_inmem-0.36.0.dev2 → langgraph_runtime_inmem-0.36.0.dev4}/langgraph_runtime_inmem/_persistence.py +0 -0
  9. {langgraph_runtime_inmem-0.36.0.dev2 → langgraph_runtime_inmem-0.36.0.dev4}/langgraph_runtime_inmem/checkpoint.py +0 -0
  10. {langgraph_runtime_inmem-0.36.0.dev2 → langgraph_runtime_inmem-0.36.0.dev4}/langgraph_runtime_inmem/database.py +0 -0
  11. {langgraph_runtime_inmem-0.36.0.dev2 → langgraph_runtime_inmem-0.36.0.dev4}/langgraph_runtime_inmem/lifespan.py +0 -0
  12. {langgraph_runtime_inmem-0.36.0.dev2 → langgraph_runtime_inmem-0.36.0.dev4}/langgraph_runtime_inmem/metrics.py +0 -0
  13. {langgraph_runtime_inmem-0.36.0.dev2 → langgraph_runtime_inmem-0.36.0.dev4}/langgraph_runtime_inmem/queue.py +0 -0
  14. {langgraph_runtime_inmem-0.36.0.dev2 → langgraph_runtime_inmem-0.36.0.dev4}/langgraph_runtime_inmem/retry.py +0 -0
  15. {langgraph_runtime_inmem-0.36.0.dev2 → langgraph_runtime_inmem-0.36.0.dev4}/langgraph_runtime_inmem/routes.py +0 -0
  16. {langgraph_runtime_inmem-0.36.0.dev2 → langgraph_runtime_inmem-0.36.0.dev4}/langgraph_runtime_inmem/store.py +0 -0
  17. {langgraph_runtime_inmem-0.36.0.dev2 → langgraph_runtime_inmem-0.36.0.dev4}/pyproject.toml +0 -0
  18. {langgraph_runtime_inmem-0.36.0.dev2 → langgraph_runtime_inmem-0.36.0.dev4}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: langgraph-runtime-inmem
3
- Version: 0.36.0.dev2
3
+ Version: 0.36.0.dev4
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
@@ -10,7 +10,7 @@ from langgraph_runtime_inmem import (
10
10
  store,
11
11
  )
12
12
 
13
- __version__ = "0.36.0.dev2"
13
+ __version__ = "0.36.0.dev4"
14
14
  __all__ = [
15
15
  "ops",
16
16
  "database",
@@ -26,6 +26,8 @@ class Message:
26
26
  topic: bytes
27
27
  data: bytes
28
28
  id: bytes | None = None
29
+ # Control messages only: server-generated explanation of an interrupt/rollback
30
+ reason: str | None = None
29
31
 
30
32
 
31
33
  class ContextQueue(asyncio.Queue):
@@ -620,6 +620,7 @@ class Assistants(Authenticated):
620
620
  assistant_id=assistant_id,
621
621
  action="interrupt",
622
622
  ctx=ctx,
623
+ reason=f"assistant {assistant_id} was deleted",
623
624
  )
624
625
 
625
626
  # 4. Delete assistant
@@ -2858,6 +2859,7 @@ class Runs(Authenticated):
2858
2859
  status: Literal["pending", "running", "all"] | None = None,
2859
2860
  assistant_id: UUID | None = None,
2860
2861
  ctx: Auth.types.BaseAuthContext | None = None,
2862
+ reason: str | None = None,
2861
2863
  ) -> None:
2862
2864
  """
2863
2865
  Cancel runs in memory. Must provide either:
@@ -2971,6 +2973,7 @@ class Runs(Authenticated):
2971
2973
  control_message = Message(
2972
2974
  topic=f"run:{run_id}:control".encode(),
2973
2975
  data=action.encode(),
2976
+ reason=reason,
2974
2977
  )
2975
2978
  coros.append(stream_manager.put(run_id, thread_id, control_message))
2976
2979
 
@@ -3187,7 +3190,8 @@ class Runs(Authenticated):
3187
3190
  # We only return a stream ID if the run is resumable
3188
3191
  stream_id = (
3189
3192
  id
3190
- if run.get("kwargs", {}).get("resumable")
3193
+ if run is not None
3194
+ and run.get("kwargs", {}).get("resumable")
3191
3195
  else None
3192
3196
  )
3193
3197
  yield mode.encode(), payload, stream_id
@@ -3224,7 +3228,13 @@ class Runs(Authenticated):
3224
3228
  raise e.http_exception from None
3225
3229
  except:
3226
3230
  if cancel_on_disconnect:
3227
- create_task(cancel_run(thread_id, run_id))
3231
+ create_task(
3232
+ cancel_run(
3233
+ thread_id,
3234
+ run_id,
3235
+ reason="client disconnected from the run stream (on_disconnect=cancel)",
3236
+ )
3237
+ )
3228
3238
  raise
3229
3239
  finally:
3230
3240
  stream_manager = get_stream_manager()
@@ -3279,25 +3289,27 @@ async def listen_for_cancellation(
3279
3289
 
3280
3290
  stream_manager = get_stream_manager()
3281
3291
 
3292
+ def _handle_control_message(message: Message) -> bool:
3293
+ """Set `done` from a control message. Returns True once the run is done."""
3294
+ reason = message.reason
3295
+ if message.data == b"rollback":
3296
+ done.set(UserRollback(reason) if reason else UserRollback())
3297
+ elif message.data == b"interrupt":
3298
+ done.set(UserInterrupt(reason) if reason else UserInterrupt())
3299
+ elif message.data == b"done":
3300
+ done.set()
3301
+ return True
3302
+ return False
3303
+
3282
3304
  if control_key := stream_manager.get_control_key(run_id, thread_id):
3283
- payload = control_key.data
3284
- if payload == b"rollback":
3285
- done.set(UserRollback())
3286
- elif payload == b"interrupt":
3287
- done.set(UserInterrupt())
3305
+ _handle_control_message(control_key)
3288
3306
 
3289
3307
  while not done.is_set():
3290
3308
  try:
3291
3309
  # This task gets cancelled when Runs.enter exits anyway,
3292
3310
  # so we can have a pretty lengthy timeout here
3293
3311
  message = await asyncio.wait_for(queue.get(), timeout=240)
3294
- payload = message.data
3295
- if payload == b"rollback":
3296
- done.set(UserRollback())
3297
- elif payload == b"interrupt":
3298
- done.set(UserInterrupt())
3299
- elif payload == b"done":
3300
- done.set()
3312
+ if _handle_control_message(message):
3301
3313
  break
3302
3314
  except TimeoutError:
3303
3315
  break
@@ -3896,10 +3908,13 @@ class Crons(Authenticated):
3896
3908
 
3897
3909
 
3898
3910
  async def cancel_run(
3899
- thread_id: UUID, run_id: UUID, ctx: Auth.types.BaseAuthContext | None = None
3911
+ thread_id: UUID,
3912
+ run_id: UUID,
3913
+ ctx: Auth.types.BaseAuthContext | None = None,
3914
+ reason: str | None = None,
3900
3915
  ) -> None:
3901
3916
  async with connect() as conn:
3902
- await Runs.cancel(conn, [run_id], thread_id=thread_id, ctx=ctx)
3917
+ await Runs.cancel(conn, [run_id], thread_id=thread_id, ctx=ctx, reason=reason)
3903
3918
 
3904
3919
 
3905
3920
  async def _get_checkpointer(