Skip to content

Commit a6b5c10

Browse files
authored
chore(deps): bump langgraph lower bounds to fix security vulnerabilities (#165)
* chore(deps): bump langgraph and langgraph-checkpoint lower bounds for security fixes - langgraph-checkpoint: >=3.0.0 → >=4.0.0 (fixes CVE for BaseCache deserialization RCE, Dependabot alert #17) - langgraph: >=0.3.0 → >=1.0.10 (fixes unsafe msgpack deserialization, Dependabot alert #18) * fix: align prune()/aprune() signatures with upstream BaseCheckpointSaver langgraph-checkpoint 4.0.0 changed the base class signature from no prune() to prune(strategy="keep_latest"). Update all 4 implementations to accept the upstream `strategy` parameter while keeping `keep_last` as an optional override for backwards compatibility. Mapping: strategy="keep_latest" → keep_last=1, strategy="delete" → keep_last=0.
1 parent 541b631 commit a6b5c10

6 files changed

Lines changed: 99 additions & 69 deletions

File tree

langgraph/checkpoint/redis/__init__.py

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1660,34 +1660,39 @@ def prune(
16601660
self,
16611661
thread_ids: Sequence[str],
16621662
*,
1663-
keep_last: int = 1,
1663+
strategy: str = "keep_latest",
1664+
keep_last: Optional[int] = None,
16641665
max_results: int = 10000,
16651666
) -> None:
16661667
"""Prune old checkpoints for the given threads per namespace.
16671668
1668-
Retains the ``keep_last`` most-recent checkpoints **per checkpoint
1669-
namespace** and removes the rest, along with their associated write
1670-
keys and key-registry sorted sets.
1669+
Retains the most-recent checkpoints **per checkpoint namespace** and
1670+
removes the rest, along with their associated write keys and
1671+
key-registry sorted sets.
16711672
16721673
Each namespace (root ``""`` and any subgraph namespaces) is treated as
1673-
an independent checkpoint chain, so ``keep_last`` is applied separately
1674-
within each namespace. Channel values are stored inline within each
1675-
checkpoint document, so they are automatically removed when the
1676-
checkpoint document is deleted.
1674+
an independent checkpoint chain. Channel values are stored inline
1675+
within each checkpoint document, so they are automatically removed
1676+
when the checkpoint document is deleted.
16771677
16781678
Args:
16791679
thread_ids: Thread IDs whose old checkpoints should be pruned.
1680-
keep_last: Number of recent checkpoints to retain per namespace.
1681-
Use ``keep_last=1`` to keep only the latest checkpoint (default).
1682-
Use ``keep_last=0`` to remove all checkpoints for the thread.
1683-
For multi-tool interrupt chains, ``max(10, n_tool_calls * 3 + 5)``
1684-
is a safe heuristic.
1680+
strategy: Pruning strategy. ``"keep_latest"`` retains only the
1681+
most recent checkpoint per namespace (default). ``"delete"``
1682+
removes all checkpoints for the thread.
1683+
keep_last: Optional override — number of recent checkpoints to
1684+
retain per namespace. When provided, takes precedence over
1685+
``strategy``. Use ``keep_last=0`` to remove all checkpoints.
16851686
max_results: Maximum number of checkpoints fetched from the index
1686-
per thread in a single query. Threads with more checkpoints
1687-
than this limit will only have the first ``max_results`` entries
1688-
considered for pruning. Raise this value for very long-lived
1689-
threads. Defaults to 10 000.
1687+
per thread in a single query. Defaults to 10 000.
16901688
"""
1689+
# Resolve keep_last from strategy if not explicitly provided
1690+
if keep_last is None:
1691+
if strategy == "delete":
1692+
keep_last = 0
1693+
else:
1694+
keep_last = 1
1695+
16911696
# Validate input
16921697
if not thread_ids:
16931698
raise ValueError("``thread_ids`` must be a non-empty sequence")

langgraph/checkpoint/redis/aio.py

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2047,34 +2047,39 @@ async def aprune(
20472047
self,
20482048
thread_ids: Sequence[str],
20492049
*,
2050-
keep_last: int = 1,
2050+
strategy: str = "keep_latest",
2051+
keep_last: Optional[int] = None,
20512052
max_results: int = 10000,
20522053
) -> None:
20532054
"""Prune old checkpoints for the given threads per namespace.
20542055
2055-
Retains the ``keep_last`` most-recent checkpoints **per checkpoint
2056-
namespace** and removes the rest, along with their associated write
2057-
keys and key-registry sorted sets.
2056+
Retains the most-recent checkpoints **per checkpoint namespace** and
2057+
removes the rest, along with their associated write keys and
2058+
key-registry sorted sets.
20582059
20592060
Each namespace (root ``""`` and any subgraph namespaces) is treated as
2060-
an independent checkpoint chain, so ``keep_last`` is applied separately
2061-
within each namespace. Channel values are stored inline within each
2062-
checkpoint document, so they are automatically removed when the
2063-
checkpoint document is deleted.
2061+
an independent checkpoint chain. Channel values are stored inline
2062+
within each checkpoint document, so they are automatically removed
2063+
when the checkpoint document is deleted.
20642064
20652065
Args:
20662066
thread_ids: Thread IDs whose old checkpoints should be pruned.
2067-
keep_last: Number of recent checkpoints to retain per namespace.
2068-
Use ``keep_last=1`` to keep only the latest checkpoint (default).
2069-
Use ``keep_last=0`` to remove all checkpoints for the thread.
2070-
For multi-tool interrupt chains, ``max(10, n_tool_calls * 3 + 5)``
2071-
is a safe heuristic.
2067+
strategy: Pruning strategy. ``"keep_latest"`` retains only the
2068+
most recent checkpoint per namespace (default). ``"delete"``
2069+
removes all checkpoints for the thread.
2070+
keep_last: Optional override — number of recent checkpoints to
2071+
retain per namespace. When provided, takes precedence over
2072+
``strategy``. Use ``keep_last=0`` to remove all checkpoints.
20722073
max_results: Maximum number of checkpoints fetched from the index
2073-
per thread in a single query. Threads with more checkpoints
2074-
than this limit will only have the first ``max_results`` entries
2075-
considered for pruning. Raise this value for very long-lived
2076-
threads. Defaults to 10 000.
2074+
per thread in a single query. Defaults to 10 000.
20772075
"""
2076+
# Resolve keep_last from strategy if not explicitly provided
2077+
if keep_last is None:
2078+
if strategy == "delete":
2079+
keep_last = 0
2080+
else:
2081+
keep_last = 1
2082+
20782083
# Validate inputs
20792084
if not thread_ids:
20802085
raise ValueError("``thread_ids`` must be a non-empty sequence")

langgraph/checkpoint/redis/ashallow.py

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -901,23 +901,33 @@ async def aprune(
901901
self,
902902
thread_ids: Sequence[str],
903903
*,
904-
keep_last: int = 1,
904+
strategy: str = "keep_latest",
905+
keep_last: Optional[int] = None,
905906
) -> None:
906907
"""Prune checkpoints for the given threads.
907908
908909
``AsyncShallowRedisSaver`` stores at most one checkpoint per namespace
909-
by design, so ``keep_last >= 1`` is always a no-op. ``keep_last=0``
910-
removes all checkpoints for each thread (equivalent to
911-
``adelete_thread``).
910+
by design, so ``strategy="keep_latest"`` (or ``keep_last >= 1``) is
911+
always a no-op. ``strategy="delete"`` (or ``keep_last=0``) removes
912+
all checkpoints for each thread (equivalent to ``adelete_thread``).
912913
913914
Args:
914915
thread_ids: Thread IDs to prune.
915-
keep_last: Checkpoints to retain per namespace. Any value >= 1
916-
is a no-op for shallow savers. Pass ``0`` to delete all.
916+
strategy: Pruning strategy. ``"keep_latest"`` is a no-op for
917+
shallow savers (default). ``"delete"`` removes all.
918+
keep_last: Optional override. Any value >= 1 is a no-op.
919+
Pass ``0`` to delete all.
917920
"""
921+
# Resolve keep_last from strategy if not explicitly provided
922+
if keep_last is None:
923+
if strategy == "delete":
924+
keep_last = 0
925+
else:
926+
keep_last = 1
927+
918928
# Validate input
919929
if not thread_ids:
920-
raise ValueError(f"``thread_ids`` must be a non-empty sequence")
930+
raise ValueError("``thread_ids`` must be a non-empty sequence")
921931

922932
if keep_last < 0:
923933
raise ValueError(f"``keep_last`` must be >= 0, got {keep_last}")

langgraph/checkpoint/redis/shallow.py

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -769,23 +769,33 @@ def prune(
769769
self,
770770
thread_ids: Sequence[str],
771771
*,
772-
keep_last: int = 1,
772+
strategy: str = "keep_latest",
773+
keep_last: Optional[int] = None,
773774
) -> None:
774775
"""Prune checkpoints for the given threads.
775776
776777
``ShallowRedisSaver`` stores at most one checkpoint per namespace by
777-
design, so ``keep_last >= 1`` is always a no-op. ``keep_last=0``
778-
removes all checkpoints for each thread (equivalent to
779-
``delete_thread``).
778+
design, so ``strategy="keep_latest"`` (or ``keep_last >= 1``) is
779+
always a no-op. ``strategy="delete"`` (or ``keep_last=0``) removes
780+
all checkpoints for each thread (equivalent to ``delete_thread``).
780781
781782
Args:
782783
thread_ids: Thread IDs to prune.
783-
keep_last: Checkpoints to retain per namespace. Any value >= 1
784-
is a no-op for shallow savers. Pass ``0`` to delete all.
784+
strategy: Pruning strategy. ``"keep_latest"`` is a no-op for
785+
shallow savers (default). ``"delete"`` removes all.
786+
keep_last: Optional override. Any value >= 1 is a no-op.
787+
Pass ``0`` to delete all.
785788
"""
789+
# Resolve keep_last from strategy if not explicitly provided
790+
if keep_last is None:
791+
if strategy == "delete":
792+
keep_last = 0
793+
else:
794+
keep_last = 1
795+
786796
# Validate input
787797
if not thread_ids:
788-
raise ValueError(f"``thread_ids`` must be a non-empty sequence")
798+
raise ValueError("``thread_ids`` must be a non-empty sequence")
789799

790800
if keep_last < 0:
791801
raise ValueError(f"``keep_last`` must be >= 0, got {keep_last}")

poetry.lock

Lines changed: 19 additions & 19 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,14 @@ packages = [{ include = "langgraph" }]
1919

2020
[tool.poetry.dependencies]
2121
python = ">=3.10,<3.15"
22-
langgraph-checkpoint = ">=3.0.0,<5.0.0"
22+
langgraph-checkpoint = ">=4.0.0,<5.0.0"
2323
redisvl = ">=0.15.0,<1.0.0"
2424
redis = ">=5.2.1"
2525
orjson = "^3.9.0"
2626
tomli = { version = "^2.0.1", python = "<3.11" }
2727

2828
[tool.poetry.group.dev.dependencies]
29-
langgraph = ">=0.3.0"
29+
langgraph = ">=1.0.10"
3030
black = "^25.1.0"
3131
codespell = "^2.4.1"
3232
pytest = "^8.4.1"

0 commit comments

Comments
 (0)