mirror of
https://github.com/langchain-ai/langgraph.git
synced 2026-08-25 09:02:25 +02:00
Avoid raise-catch strategy in BaseChannel.checkpoint()
- This mirrors the work done earlier on BaseChannel.get() - Comparing to a sentinel value is significantly faster than raising and catching an exception
This commit is contained in:
@@ -124,6 +124,7 @@ def copy_checkpoint(checkpoint: Checkpoint) -> Checkpoint:
|
||||
)
|
||||
|
||||
|
||||
# Kept for backwards compat, newer versions of LangGraph no longer use this.
|
||||
def create_checkpoint(
|
||||
checkpoint: Checkpoint,
|
||||
channels: Optional[Mapping[str, ChannelProtocol]],
|
||||
|
||||
@@ -34,7 +34,7 @@ if __name__ == "__main__":
|
||||
|
||||
import uvloop
|
||||
|
||||
graph = create_sequential(2000).compile()
|
||||
graph = create_sequential(3000).compile()
|
||||
input = {"messages": []} # Empty list of messages
|
||||
config = {"recursion_limit": 20000000000}
|
||||
|
||||
|
||||
@@ -55,3 +55,6 @@ class AnyValue(Generic[Value], BaseChannel[Value, Value, Value]):
|
||||
|
||||
def is_available(self) -> bool:
|
||||
return self.value is not MISSING
|
||||
|
||||
def checkpoint(self) -> Value:
|
||||
return self.value
|
||||
|
||||
@@ -3,6 +3,7 @@ from typing import Any, Generic, Sequence, TypeVar
|
||||
|
||||
from typing_extensions import Self
|
||||
|
||||
from langgraph.constants import MISSING
|
||||
from langgraph.errors import EmptyChannelError, InvalidUpdateError
|
||||
|
||||
Value = TypeVar("Value")
|
||||
@@ -33,7 +34,10 @@ class BaseChannel(Generic[Value, Update, C], ABC):
|
||||
"""Return a serializable representation of the channel's current state.
|
||||
Raises EmptyChannelError if the channel is empty (never updated yet),
|
||||
or doesn't support checkpoints."""
|
||||
return self.get()
|
||||
try:
|
||||
return self.get()
|
||||
except EmptyChannelError:
|
||||
return MISSING
|
||||
|
||||
@abstractmethod
|
||||
def from_checkpoint(self, checkpoint: C) -> Self:
|
||||
|
||||
@@ -90,3 +90,6 @@ class BinaryOperatorAggregate(Generic[Value], BaseChannel[Value, Value, Value]):
|
||||
|
||||
def is_available(self) -> bool:
|
||||
return self.value is not MISSING
|
||||
|
||||
def checkpoint(self) -> Value:
|
||||
return self.value
|
||||
|
||||
@@ -59,3 +59,6 @@ class EphemeralValue(Generic[Value], BaseChannel[Value, Value, Value]):
|
||||
|
||||
def is_available(self) -> bool:
|
||||
return self.value is not MISSING
|
||||
|
||||
def checkpoint(self) -> Value:
|
||||
return self.value
|
||||
|
||||
@@ -61,3 +61,6 @@ class LastValue(Generic[Value], BaseChannel[Value, Value, Value]):
|
||||
|
||||
def is_available(self) -> bool:
|
||||
return self.value is not MISSING
|
||||
|
||||
def checkpoint(self) -> Value:
|
||||
return self.value
|
||||
|
||||
@@ -31,7 +31,7 @@ class UntrackedValue(Generic[Value], BaseChannel[Value, Value, Value]):
|
||||
return self.typ
|
||||
|
||||
def checkpoint(self) -> Value:
|
||||
raise EmptyChannelError()
|
||||
return MISSING
|
||||
|
||||
def from_checkpoint(self, checkpoint: Value) -> Self:
|
||||
empty = self.__class__(self.typ, self.guard)
|
||||
|
||||
@@ -50,7 +50,6 @@ from langgraph.checkpoint.base import (
|
||||
BaseCheckpointSaver,
|
||||
CheckpointTuple,
|
||||
copy_checkpoint,
|
||||
create_checkpoint,
|
||||
empty_checkpoint,
|
||||
)
|
||||
from langgraph.constants import (
|
||||
@@ -91,6 +90,7 @@ from langgraph.pregel.algo import (
|
||||
local_write,
|
||||
prepare_next_tasks,
|
||||
)
|
||||
from langgraph.pregel.checkpoint import create_checkpoint
|
||||
from langgraph.pregel.debug import tasks_w_writes
|
||||
from langgraph.pregel.io import map_input, read_channels
|
||||
from langgraph.pregel.loop import AsyncPregelLoop, StreamProtocol, SyncPregelLoop
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
from datetime import datetime, timezone
|
||||
from typing import Mapping, Optional
|
||||
|
||||
from langgraph.channels.base import BaseChannel
|
||||
from langgraph.checkpoint.base import LATEST_VERSION, Checkpoint
|
||||
from langgraph.checkpoint.base.id import uuid6
|
||||
from langgraph.constants import MISSING
|
||||
|
||||
|
||||
def create_checkpoint(
|
||||
checkpoint: Checkpoint,
|
||||
channels: Optional[Mapping[str, BaseChannel]],
|
||||
step: int,
|
||||
*,
|
||||
id: Optional[str] = None,
|
||||
) -> Checkpoint:
|
||||
"""Create a checkpoint for the given channels."""
|
||||
ts = datetime.now(timezone.utc).isoformat()
|
||||
if channels is None:
|
||||
values = checkpoint["channel_values"]
|
||||
else:
|
||||
values = {}
|
||||
for k in channels:
|
||||
if k not in checkpoint["channel_versions"]:
|
||||
continue
|
||||
v = channels[k].checkpoint()
|
||||
if v is not MISSING:
|
||||
values[k] = v
|
||||
return Checkpoint(
|
||||
v=LATEST_VERSION,
|
||||
ts=ts,
|
||||
id=id or str(uuid6(clock_seq=step)),
|
||||
channel_values=values,
|
||||
channel_versions=checkpoint["channel_versions"],
|
||||
versions_seen=checkpoint["versions_seen"],
|
||||
pending_sends=checkpoint.get("pending_sends", []),
|
||||
)
|
||||
@@ -38,7 +38,6 @@ from langgraph.checkpoint.base import (
|
||||
CheckpointTuple,
|
||||
PendingWrite,
|
||||
copy_checkpoint,
|
||||
create_checkpoint,
|
||||
empty_checkpoint,
|
||||
)
|
||||
from langgraph.constants import (
|
||||
@@ -88,6 +87,7 @@ from langgraph.pregel.algo import (
|
||||
should_interrupt,
|
||||
task_path_str,
|
||||
)
|
||||
from langgraph.pregel.checkpoint import create_checkpoint
|
||||
from langgraph.pregel.debug import (
|
||||
map_debug_checkpoint,
|
||||
map_debug_task_results,
|
||||
|
||||
Reference in New Issue
Block a user