From 118016a21c8ee51e8c3cef92a94606addacf8fd4 Mon Sep 17 00:00:00 2001 From: Nuno Campos Date: Mon, 31 Mar 2025 16:15:56 -0700 Subject: [PATCH 1/5] Add fast path to serialize None values --- libs/checkpoint/langgraph/checkpoint/serde/jsonplus.py | 9 +++++++-- libs/langgraph/langgraph/graph/state.py | 4 ++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/libs/checkpoint/langgraph/checkpoint/serde/jsonplus.py b/libs/checkpoint/langgraph/checkpoint/serde/jsonplus.py index 531edd185..49577b3aa 100644 --- a/libs/checkpoint/langgraph/checkpoint/serde/jsonplus.py +++ b/libs/checkpoint/langgraph/checkpoint/serde/jsonplus.py @@ -30,6 +30,7 @@ from langgraph.checkpoint.serde.types import SendProtocol from langgraph.store.base import Item LC_REVIVER = Reviver() +EMPTY_BYTES = b"" class JsonPlusSerializer(SerializerProtocol): @@ -194,7 +195,9 @@ class JsonPlusSerializer(SerializerProtocol): ) def dumps_typed(self, obj: Any) -> tuple[str, bytes]: - if isinstance(obj, bytes): + if obj is None: + return "null", EMPTY_BYTES + elif isinstance(obj, bytes): return "bytes", obj elif isinstance(obj, bytearray): return "bytearray", obj @@ -211,7 +214,9 @@ class JsonPlusSerializer(SerializerProtocol): def loads_typed(self, data: tuple[str, bytes]) -> Any: type_, data_ = data - if type_ == "bytes": + if type_ == "null": + return None + elif type_ == "bytes": return data_ elif type_ == "bytearray": return bytearray(data_) diff --git a/libs/langgraph/langgraph/graph/state.py b/libs/langgraph/langgraph/graph/state.py index 750ed30df..93fd65052 100644 --- a/libs/langgraph/langgraph/graph/state.py +++ b/libs/langgraph/langgraph/graph/state.py @@ -845,7 +845,7 @@ class CompiledStateGraph(CompiledGraph): if end != END: self.nodes[starts].writers.append( ChannelWrite( - (ChannelWriteEntry(CHANNEL_BRANCH_TO.format(end), starts),) + (ChannelWriteEntry(CHANNEL_BRANCH_TO.format(end), None),) ) ) elif end != END: @@ -871,7 +871,7 @@ class CompiledStateGraph(CompiledGraph): if filtered := [p for p in packets if p != END]: writes = [ ( - ChannelWriteEntry(CHANNEL_BRANCH_TO.format(p), start) + ChannelWriteEntry(CHANNEL_BRANCH_TO.format(p), None) if not isinstance(p, Send) else p ) From 0425d4e65d62fb87540e79bbfbe2ba6cfc04e6ba Mon Sep 17 00:00:00 2001 From: Nuno Campos Date: Mon, 31 Mar 2025 16:29:07 -0700 Subject: [PATCH 2/5] Update --- libs/langgraph/langgraph/channels/any_value.py | 2 +- libs/langgraph/langgraph/channels/binop.py | 2 +- .../langgraph/channels/dynamic_barrier_value.py | 3 ++- libs/langgraph/langgraph/channels/ephemeral_value.py | 2 +- libs/langgraph/langgraph/channels/last_value.py | 2 +- libs/langgraph/langgraph/channels/named_barrier_value.py | 3 ++- libs/langgraph/langgraph/channels/topic.py | 3 ++- libs/langgraph/langgraph/pregel/manager.py | 5 +++-- libs/langgraph/tests/test_channels.py | 9 +++++---- libs/langgraph/tests/test_pregel.py | 8 ++++---- libs/langgraph/tests/test_pregel_async.py | 8 ++++---- 11 files changed, 26 insertions(+), 21 deletions(-) diff --git a/libs/langgraph/langgraph/channels/any_value.py b/libs/langgraph/langgraph/channels/any_value.py index 35452084f..412436d4f 100644 --- a/libs/langgraph/langgraph/channels/any_value.py +++ b/libs/langgraph/langgraph/channels/any_value.py @@ -33,7 +33,7 @@ class AnyValue(Generic[Value], BaseChannel[Value, Value, Value]): def from_checkpoint(self, checkpoint: Optional[Value]) -> Self: empty = self.__class__(self.typ) empty.key = self.key - if checkpoint is not None: + if checkpoint is not MISSING: empty.value = checkpoint return empty diff --git a/libs/langgraph/langgraph/channels/binop.py b/libs/langgraph/langgraph/channels/binop.py index 413e0b91a..9ed2f0ca5 100644 --- a/libs/langgraph/langgraph/channels/binop.py +++ b/libs/langgraph/langgraph/channels/binop.py @@ -75,7 +75,7 @@ class BinaryOperatorAggregate(Generic[Value], BaseChannel[Value, Value, Value]): def from_checkpoint(self, checkpoint: Optional[Value]) -> Self: empty = self.__class__(self.typ, self.operator) empty.key = self.key - if checkpoint is not None: + if checkpoint is not MISSING: empty.value = checkpoint return empty diff --git a/libs/langgraph/langgraph/channels/dynamic_barrier_value.py b/libs/langgraph/langgraph/channels/dynamic_barrier_value.py index 155c65446..d9ea1ba8b 100644 --- a/libs/langgraph/langgraph/channels/dynamic_barrier_value.py +++ b/libs/langgraph/langgraph/channels/dynamic_barrier_value.py @@ -3,6 +3,7 @@ from typing import Any, Generic, NamedTuple, Optional, Sequence, Type, Union from typing_extensions import Self from langgraph.channels.base import BaseChannel, Value +from langgraph.constants import MISSING from langgraph.errors import EmptyChannelError, InvalidUpdateError @@ -54,7 +55,7 @@ class DynamicBarrierValue( ) -> Self: empty = self.__class__(self.typ) empty.key = self.key - if checkpoint is not None: + if checkpoint is not MISSING: names, seen = checkpoint empty.names = names if names is not None else None empty.seen = seen diff --git a/libs/langgraph/langgraph/channels/ephemeral_value.py b/libs/langgraph/langgraph/channels/ephemeral_value.py index 29a9a698c..23e80c017 100644 --- a/libs/langgraph/langgraph/channels/ephemeral_value.py +++ b/libs/langgraph/langgraph/channels/ephemeral_value.py @@ -33,7 +33,7 @@ class EphemeralValue(Generic[Value], BaseChannel[Value, Value, Value]): def from_checkpoint(self, checkpoint: Optional[Value]) -> Self: empty = self.__class__(self.typ, self.guard) empty.key = self.key - if checkpoint is not None: + if checkpoint is not MISSING: empty.value = checkpoint return empty diff --git a/libs/langgraph/langgraph/channels/last_value.py b/libs/langgraph/langgraph/channels/last_value.py index 61669d390..dd67872b8 100644 --- a/libs/langgraph/langgraph/channels/last_value.py +++ b/libs/langgraph/langgraph/channels/last_value.py @@ -37,7 +37,7 @@ class LastValue(Generic[Value], BaseChannel[Value, Value, Value]): def from_checkpoint(self, checkpoint: Optional[Value]) -> Self: empty = self.__class__(self.typ) empty.key = self.key - if checkpoint is not None: + if checkpoint is not MISSING: empty.value = checkpoint return empty diff --git a/libs/langgraph/langgraph/channels/named_barrier_value.py b/libs/langgraph/langgraph/channels/named_barrier_value.py index 553316e19..4402dce95 100644 --- a/libs/langgraph/langgraph/channels/named_barrier_value.py +++ b/libs/langgraph/langgraph/channels/named_barrier_value.py @@ -3,6 +3,7 @@ from typing import Generic, Optional, Sequence, Type from typing_extensions import Self from langgraph.channels.base import BaseChannel, Value +from langgraph.constants import MISSING from langgraph.errors import EmptyChannelError, InvalidUpdateError @@ -38,7 +39,7 @@ class NamedBarrierValue(Generic[Value], BaseChannel[Value, Value, set[Value]]): def from_checkpoint(self, checkpoint: Optional[set[Value]]) -> Self: empty = self.__class__(self.typ, self.names) empty.key = self.key - if checkpoint is not None: + if checkpoint is not MISSING: empty.seen = checkpoint return empty diff --git a/libs/langgraph/langgraph/channels/topic.py b/libs/langgraph/langgraph/channels/topic.py index 5b081ee4c..2f3e73955 100644 --- a/libs/langgraph/langgraph/channels/topic.py +++ b/libs/langgraph/langgraph/channels/topic.py @@ -3,6 +3,7 @@ from typing import Any, Generic, Iterator, Optional, Sequence, Type, Union from typing_extensions import Self from langgraph.channels.base import BaseChannel, Value +from langgraph.constants import MISSING from langgraph.errors import EmptyChannelError @@ -55,7 +56,7 @@ class Topic( def from_checkpoint(self, checkpoint: Optional[list[Value]]) -> Self: empty = self.__class__(self.typ, self.accumulate) empty.key = self.key - if checkpoint is not None: + if checkpoint is not MISSING: if isinstance(checkpoint, tuple): empty.values = checkpoint[1] else: diff --git a/libs/langgraph/langgraph/pregel/manager.py b/libs/langgraph/langgraph/pregel/manager.py index 641e1d8fe..b117e830c 100644 --- a/libs/langgraph/langgraph/pregel/manager.py +++ b/libs/langgraph/langgraph/pregel/manager.py @@ -4,6 +4,7 @@ from typing import AsyncIterator, Iterator, Mapping, Union from langgraph.channels.base import BaseChannel from langgraph.checkpoint.base import Checkpoint +from langgraph.constants import MISSING from langgraph.managed.base import ( ConfiguredManagedValue, ManagedValueMapping, @@ -36,7 +37,7 @@ def ChannelsManager( with ExitStack() as stack: yield ( { - k: v.from_checkpoint(checkpoint["channel_values"].get(k)) + k: v.from_checkpoint(checkpoint["channel_values"].get(k, MISSING)) for k, v in channel_specs.items() }, ManagedValueMapping( @@ -90,7 +91,7 @@ async def AsyncChannelsManager( yield ( # channels: enter each channel with checkpoint { - k: v.from_checkpoint(checkpoint["channel_values"].get(k)) + k: v.from_checkpoint(checkpoint["channel_values"].get(k, MISSING)) for k, v in channel_specs.items() }, # managed: build mapping from spec to result diff --git a/libs/langgraph/tests/test_channels.py b/libs/langgraph/tests/test_channels.py index 7c6fb162b..b65036e54 100644 --- a/libs/langgraph/tests/test_channels.py +++ b/libs/langgraph/tests/test_channels.py @@ -6,13 +6,14 @@ import pytest from langgraph.channels.binop import BinaryOperatorAggregate from langgraph.channels.last_value import LastValue from langgraph.channels.topic import Topic +from langgraph.constants import MISSING from langgraph.errors import EmptyChannelError, InvalidUpdateError pytestmark = pytest.mark.anyio def test_last_value() -> None: - channel = LastValue(int).from_checkpoint(None) + channel = LastValue(int).from_checkpoint(MISSING) assert channel.ValueType is int assert channel.UpdateType is int @@ -31,7 +32,7 @@ def test_last_value() -> None: def test_topic() -> None: - channel = Topic(str).from_checkpoint(None) + channel = Topic(str).from_checkpoint(MISSING) assert channel.ValueType is Sequence[str] assert channel.UpdateType is Union[str, list[str]] @@ -55,7 +56,7 @@ def test_topic() -> None: def test_topic_accumulate() -> None: - channel = Topic(str, accumulate=True).from_checkpoint(None) + channel = Topic(str, accumulate=True).from_checkpoint(MISSING) assert channel.ValueType is Sequence[str] assert channel.UpdateType is Union[str, list[str]] @@ -73,7 +74,7 @@ def test_topic_accumulate() -> None: def test_binop() -> None: - channel = BinaryOperatorAggregate(int, operator.add).from_checkpoint(None) + channel = BinaryOperatorAggregate(int, operator.add).from_checkpoint(MISSING) assert channel.ValueType is int assert channel.UpdateType is int diff --git a/libs/langgraph/tests/test_pregel.py b/libs/langgraph/tests/test_pregel.py index 34549caf4..2264ec756 100644 --- a/libs/langgraph/tests/test_pregel.py +++ b/libs/langgraph/tests/test_pregel.py @@ -1310,8 +1310,8 @@ def test_pending_writes_resume( }, "channel_values": { "value": 1, - "branch:to:one": "__start__", - "branch:to:two": "__start__", + "branch:to:one": None, + "branch:to:two": None, }, }, metadata={ @@ -1363,8 +1363,8 @@ def test_pending_writes_resume( parent_config=None, pending_writes=UnsortedSequence( (AnyStr(), "value", 1), - (AnyStr(), "branch:to:one", "__start__"), - (AnyStr(), "branch:to:two", "__start__"), + (AnyStr(), "branch:to:one", None), + (AnyStr(), "branch:to:two", None), ), ) diff --git a/libs/langgraph/tests/test_pregel_async.py b/libs/langgraph/tests/test_pregel_async.py index d50589a24..e5b94ac60 100644 --- a/libs/langgraph/tests/test_pregel_async.py +++ b/libs/langgraph/tests/test_pregel_async.py @@ -2146,8 +2146,8 @@ async def test_pending_writes_resume( }, "channel_values": { "value": 1, - "branch:to:one": "__start__", - "branch:to:two": "__start__", + "branch:to:one": None, + "branch:to:two": None, }, }, metadata={ @@ -2201,8 +2201,8 @@ async def test_pending_writes_resume( parent_config=None, pending_writes=UnsortedSequence( (AnyStr(), "value", 1), - (AnyStr(), "branch:to:one", "__start__"), - (AnyStr(), "branch:to:two", "__start__"), + (AnyStr(), "branch:to:one", None), + (AnyStr(), "branch:to:two", None), ), ) From 881b07cf7f20ba34dc37a3cab4c8fdfdd86012ca Mon Sep 17 00:00:00 2001 From: Nuno Campos Date: Mon, 31 Mar 2025 16:36:16 -0700 Subject: [PATCH 3/5] Lint --- libs/langgraph/langgraph/channels/any_value.py | 4 ++-- libs/langgraph/langgraph/channels/base.py | 6 +++--- libs/langgraph/langgraph/channels/binop.py | 10 ++-------- .../langgraph/channels/dynamic_barrier_value.py | 3 +-- libs/langgraph/langgraph/channels/ephemeral_value.py | 4 ++-- libs/langgraph/langgraph/channels/last_value.py | 4 ++-- .../langgraph/channels/named_barrier_value.py | 4 ++-- libs/langgraph/langgraph/channels/topic.py | 11 +++++------ libs/langgraph/langgraph/channels/untracked_value.py | 4 ++-- libs/langgraph/langgraph/utils/future.py | 2 +- 10 files changed, 22 insertions(+), 30 deletions(-) diff --git a/libs/langgraph/langgraph/channels/any_value.py b/libs/langgraph/langgraph/channels/any_value.py index 412436d4f..0276030aa 100644 --- a/libs/langgraph/langgraph/channels/any_value.py +++ b/libs/langgraph/langgraph/channels/any_value.py @@ -1,4 +1,4 @@ -from typing import Any, Generic, Optional, Sequence, Type +from typing import Any, Generic, Sequence, Type from typing_extensions import Self @@ -30,7 +30,7 @@ class AnyValue(Generic[Value], BaseChannel[Value, Value, Value]): """The type of the update received by the channel.""" return self.typ - def from_checkpoint(self, checkpoint: Optional[Value]) -> Self: + def from_checkpoint(self, checkpoint: Value) -> Self: empty = self.__class__(self.typ) empty.key = self.key if checkpoint is not MISSING: diff --git a/libs/langgraph/langgraph/channels/base.py b/libs/langgraph/langgraph/channels/base.py index b9239be7a..82fd059d1 100644 --- a/libs/langgraph/langgraph/channels/base.py +++ b/libs/langgraph/langgraph/channels/base.py @@ -1,5 +1,5 @@ from abc import ABC, abstractmethod -from typing import Any, Generic, Optional, Sequence, TypeVar +from typing import Any, Generic, Sequence, TypeVar from typing_extensions import Self @@ -29,14 +29,14 @@ class BaseChannel(Generic[Value, Update, C], ABC): # serialize/deserialize methods - def checkpoint(self) -> Optional[C]: + def checkpoint(self) -> C: """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() @abstractmethod - def from_checkpoint(self, checkpoint: Optional[C]) -> Self: + def from_checkpoint(self, checkpoint: C) -> Self: """Return a new identical channel, optionally initialized from a checkpoint. If the checkpoint contains complex data structures, they should be copied.""" diff --git a/libs/langgraph/langgraph/channels/binop.py b/libs/langgraph/langgraph/channels/binop.py index 9ed2f0ca5..eb90cae8c 100644 --- a/libs/langgraph/langgraph/channels/binop.py +++ b/libs/langgraph/langgraph/channels/binop.py @@ -1,11 +1,5 @@ import collections.abc -from typing import ( - Callable, - Generic, - Optional, - Sequence, - Type, -) +from typing import Callable, Generic, Sequence, Type from typing_extensions import NotRequired, Required, Self @@ -72,7 +66,7 @@ class BinaryOperatorAggregate(Generic[Value], BaseChannel[Value, Value, Value]): """The type of the update received by the channel.""" return self.typ - def from_checkpoint(self, checkpoint: Optional[Value]) -> Self: + def from_checkpoint(self, checkpoint: Value) -> Self: empty = self.__class__(self.typ, self.operator) empty.key = self.key if checkpoint is not MISSING: diff --git a/libs/langgraph/langgraph/channels/dynamic_barrier_value.py b/libs/langgraph/langgraph/channels/dynamic_barrier_value.py index d9ea1ba8b..511c311f3 100644 --- a/libs/langgraph/langgraph/channels/dynamic_barrier_value.py +++ b/libs/langgraph/langgraph/channels/dynamic_barrier_value.py @@ -50,8 +50,7 @@ class DynamicBarrierValue( return (self.names, self.seen) def from_checkpoint( - self, - checkpoint: Optional[tuple[Optional[set[Value]], set[Value]]], + self, checkpoint: tuple[Optional[set[Value]], set[Value]] ) -> Self: empty = self.__class__(self.typ) empty.key = self.key diff --git a/libs/langgraph/langgraph/channels/ephemeral_value.py b/libs/langgraph/langgraph/channels/ephemeral_value.py index 23e80c017..242149fe6 100644 --- a/libs/langgraph/langgraph/channels/ephemeral_value.py +++ b/libs/langgraph/langgraph/channels/ephemeral_value.py @@ -1,4 +1,4 @@ -from typing import Any, Generic, Optional, Sequence, Type +from typing import Any, Generic, Sequence, Type from typing_extensions import Self @@ -30,7 +30,7 @@ class EphemeralValue(Generic[Value], BaseChannel[Value, Value, Value]): """The type of the update received by the channel.""" return self.typ - def from_checkpoint(self, checkpoint: Optional[Value]) -> Self: + def from_checkpoint(self, checkpoint: Value) -> Self: empty = self.__class__(self.typ, self.guard) empty.key = self.key if checkpoint is not MISSING: diff --git a/libs/langgraph/langgraph/channels/last_value.py b/libs/langgraph/langgraph/channels/last_value.py index dd67872b8..32a951a4b 100644 --- a/libs/langgraph/langgraph/channels/last_value.py +++ b/libs/langgraph/langgraph/channels/last_value.py @@ -1,4 +1,4 @@ -from typing import Any, Generic, Optional, Sequence, Type +from typing import Any, Generic, Sequence, Type from typing_extensions import Self @@ -34,7 +34,7 @@ class LastValue(Generic[Value], BaseChannel[Value, Value, Value]): """The type of the update received by the channel.""" return self.typ - def from_checkpoint(self, checkpoint: Optional[Value]) -> Self: + def from_checkpoint(self, checkpoint: Value) -> Self: empty = self.__class__(self.typ) empty.key = self.key if checkpoint is not MISSING: diff --git a/libs/langgraph/langgraph/channels/named_barrier_value.py b/libs/langgraph/langgraph/channels/named_barrier_value.py index 4402dce95..2145d0f73 100644 --- a/libs/langgraph/langgraph/channels/named_barrier_value.py +++ b/libs/langgraph/langgraph/channels/named_barrier_value.py @@ -1,4 +1,4 @@ -from typing import Generic, Optional, Sequence, Type +from typing import Generic, Sequence, Type from typing_extensions import Self @@ -36,7 +36,7 @@ class NamedBarrierValue(Generic[Value], BaseChannel[Value, Value, set[Value]]): def checkpoint(self) -> set[Value]: return self.seen - def from_checkpoint(self, checkpoint: Optional[set[Value]]) -> Self: + def from_checkpoint(self, checkpoint: set[Value]) -> Self: empty = self.__class__(self.typ, self.names) empty.key = self.key if checkpoint is not MISSING: diff --git a/libs/langgraph/langgraph/channels/topic.py b/libs/langgraph/langgraph/channels/topic.py index 2f3e73955..8fc998353 100644 --- a/libs/langgraph/langgraph/channels/topic.py +++ b/libs/langgraph/langgraph/channels/topic.py @@ -1,4 +1,4 @@ -from typing import Any, Generic, Iterator, Optional, Sequence, Type, Union +from typing import Any, Generic, Iterator, Sequence, Type, Union from typing_extensions import Self @@ -17,9 +17,7 @@ def flatten(values: Sequence[Union[Value, list[Value]]]) -> Iterator[Value]: class Topic( Generic[Value], - BaseChannel[ - Sequence[Value], Union[Value, list[Value]], tuple[set[Value], list[Value]] - ], + BaseChannel[Sequence[Value], Union[Value, list[Value]], list[Value]], ): """A configurable PubSub Topic. @@ -50,14 +48,15 @@ class Topic( """The type of the update received by the channel.""" return Union[self.typ, list[self.typ]] # type: ignore[name-defined] - def checkpoint(self) -> tuple[set[Value], list[Value]]: + def checkpoint(self) -> list[Value]: return self.values - def from_checkpoint(self, checkpoint: Optional[list[Value]]) -> Self: + def from_checkpoint(self, checkpoint: list[Value]) -> Self: empty = self.__class__(self.typ, self.accumulate) empty.key = self.key if checkpoint is not MISSING: if isinstance(checkpoint, tuple): + # backwards compatibility empty.values = checkpoint[1] else: empty.values = checkpoint diff --git a/libs/langgraph/langgraph/channels/untracked_value.py b/libs/langgraph/langgraph/channels/untracked_value.py index f9168131e..cc9c99bee 100644 --- a/libs/langgraph/langgraph/channels/untracked_value.py +++ b/libs/langgraph/langgraph/channels/untracked_value.py @@ -1,4 +1,4 @@ -from typing import Generic, Optional, Sequence, Type +from typing import Generic, Sequence, Type from typing_extensions import Self @@ -33,7 +33,7 @@ class UntrackedValue(Generic[Value], BaseChannel[Value, Value, Value]): def checkpoint(self) -> Value: raise EmptyChannelError() - def from_checkpoint(self, checkpoint: Optional[Value]) -> Self: + def from_checkpoint(self, checkpoint: Value) -> Self: empty = self.__class__(self.typ, self.guard) empty.key = self.key return empty diff --git a/libs/langgraph/langgraph/utils/future.py b/libs/langgraph/langgraph/utils/future.py index a311133df..a373d1cce 100644 --- a/libs/langgraph/langgraph/utils/future.py +++ b/libs/langgraph/langgraph/utils/future.py @@ -164,7 +164,7 @@ def _ensure_future( elif EAGER_NOT_SUPPORTED or lazy: return loop.create_task(coro_or_future, name=name, context=context) else: - return asyncio.eager_task_factory( + return asyncio.eager_task_factory( # type:ignore[attr-defined] loop, coro_or_future, name=name, context=context ) except RuntimeError: From c49a077789b56595df4bace160a9370a91af9a7c Mon Sep 17 00:00:00 2001 From: Nuno Campos Date: Mon, 31 Mar 2025 17:24:26 -0700 Subject: [PATCH 4/5] Lint --- libs/langgraph/langgraph/utils/future.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/langgraph/langgraph/utils/future.py b/libs/langgraph/langgraph/utils/future.py index a373d1cce..a895fe885 100644 --- a/libs/langgraph/langgraph/utils/future.py +++ b/libs/langgraph/langgraph/utils/future.py @@ -164,7 +164,7 @@ def _ensure_future( elif EAGER_NOT_SUPPORTED or lazy: return loop.create_task(coro_or_future, name=name, context=context) else: - return asyncio.eager_task_factory( # type:ignore[attr-defined] + return asyncio.eager_task_factory( # type:ignore loop, coro_or_future, name=name, context=context ) except RuntimeError: From 5e9e7b79fe801c212e1d9f12def2f66a09360505 Mon Sep 17 00:00:00 2001 From: Nuno Campos Date: Mon, 31 Mar 2025 17:36:00 -0700 Subject: [PATCH 5/5] Lint --- libs/langgraph/langgraph/utils/future.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/langgraph/langgraph/utils/future.py b/libs/langgraph/langgraph/utils/future.py index a895fe885..a311133df 100644 --- a/libs/langgraph/langgraph/utils/future.py +++ b/libs/langgraph/langgraph/utils/future.py @@ -164,7 +164,7 @@ def _ensure_future( elif EAGER_NOT_SUPPORTED or lazy: return loop.create_task(coro_or_future, name=name, context=context) else: - return asyncio.eager_task_factory( # type:ignore + return asyncio.eager_task_factory( loop, coro_or_future, name=name, context=context ) except RuntimeError: