Replace get_catch w is_available

This commit is contained in:
Nuno Campos
2025-03-18 08:19:22 -07:00
parent ce1077da40
commit 47d38a3022
10 changed files with 47 additions and 27 deletions
+15 -8
View File
@@ -1,8 +1,9 @@
from typing import Generic, Optional, Sequence, Type
from typing import Any, 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
@@ -12,6 +13,10 @@ class AnyValue(Generic[Value], BaseChannel[Value, Value, Value]):
__slots__ = ("typ", "value")
def __init__(self, typ: Any, key: str = "") -> None:
super().__init__(typ, key)
self.value = MISSING
def __eq__(self, value: object) -> bool:
return isinstance(value, AnyValue)
@@ -34,17 +39,19 @@ class AnyValue(Generic[Value], BaseChannel[Value, Value, Value]):
def update(self, values: Sequence[Value]) -> bool:
if len(values) == 0:
try:
del self.value
return True
except AttributeError:
if self.value is MISSING:
return False
else:
self.value = MISSING
return True
self.value = values[-1]
return True
def get(self) -> Value:
try:
return self.value
except AttributeError:
if self.value is MISSING:
raise EmptyChannelError()
return self.value
def is_available(self) -> bool:
return self.value is not MISSING
+8 -6
View File
@@ -3,7 +3,6 @@ from typing import Any, Generic, Optional, Sequence, TypeVar
from typing_extensions import Self
from langgraph.constants import MISSING
from langgraph.errors import EmptyChannelError, InvalidUpdateError
Value = TypeVar("Value")
@@ -65,13 +64,16 @@ class BaseChannel(Generic[Value, Update, C], ABC):
"""
return False
def get_catch(self) -> Value:
"""Return the current value of the channel, or MISSING if the channel
is empty. Subclasses can override to skip the EmptyChannelError check."""
def is_available(self) -> bool:
"""Return True if the channel is available (not empty), False otherwise.
Subclasses should override this method to provide a more efficient
implementation than calling get() and catching EmptyChannelError.
"""
try:
return self.get()
self.get()
return True
except EmptyChannelError:
return MISSING
return False
__all__ = [
+8 -5
View File
@@ -10,6 +10,7 @@ from typing import (
from typing_extensions import NotRequired, Required, Self
from langgraph.channels.base import BaseChannel, Value
from langgraph.constants import MISSING
from langgraph.errors import EmptyChannelError
@@ -51,7 +52,7 @@ class BinaryOperatorAggregate(Generic[Value], BaseChannel[Value, Value, Value]):
try:
self.value = typ()
except Exception:
pass
self.value = MISSING
def __eq__(self, value: object) -> bool:
return isinstance(value, BinaryOperatorAggregate) and (
@@ -81,7 +82,7 @@ class BinaryOperatorAggregate(Generic[Value], BaseChannel[Value, Value, Value]):
def update(self, values: Sequence[Value]) -> bool:
if not values:
return False
if not hasattr(self, "value"):
if self.value is MISSING:
self.value = values[0]
values = values[1:]
for value in values:
@@ -89,7 +90,9 @@ class BinaryOperatorAggregate(Generic[Value], BaseChannel[Value, Value, Value]):
return True
def get(self) -> Value:
try:
return self.value
except AttributeError:
if self.value is MISSING:
raise EmptyChannelError()
return self.value
def is_available(self) -> bool:
return self.value is not MISSING
@@ -85,6 +85,9 @@ class DynamicBarrierValue(
raise EmptyChannelError()
return None
def is_available(self) -> bool:
return self.seen == self.names
def consume(self) -> bool:
if self.seen == self.names:
self.seen = set()
@@ -57,5 +57,5 @@ class EphemeralValue(Generic[Value], BaseChannel[Value, Value, Value]):
raise EmptyChannelError()
return self.value
def get_catch(self) -> Value:
return self.value
def is_available(self) -> bool:
return self.value is not MISSING
@@ -59,5 +59,5 @@ class LastValue(Generic[Value], BaseChannel[Value, Value, Value]):
raise EmptyChannelError()
return self.value
def get_catch(self) -> Value:
return self.value
def is_available(self) -> bool:
return self.value is not MISSING
@@ -60,6 +60,9 @@ class NamedBarrierValue(Generic[Value], BaseChannel[Value, Value, set[Value]]):
raise EmptyChannelError()
return None
def is_available(self) -> bool:
return self.seen == self.names
def consume(self) -> bool:
if self.seen == self.names:
self.seen = set()
@@ -75,3 +75,6 @@ class Topic(
return list(self.values)
else:
raise EmptyChannelError
def is_available(self) -> bool:
return bool(self.values)
@@ -54,5 +54,5 @@ class UntrackedValue(Generic[Value], BaseChannel[Value, Value, Value]):
raise EmptyChannelError()
return self.value
def get_catch(self) -> Value:
return self.value
def is_available(self) -> bool:
return self.value is not MISSING
+1 -2
View File
@@ -48,7 +48,6 @@ from langgraph.constants import (
EMPTY_SEQ,
ERROR,
INTERRUPT,
MISSING,
NO_WRITES,
NS_END,
NS_SEP,
@@ -650,7 +649,7 @@ def prepare_single_task(
if triggers := sorted(
chan
for chan in proc.triggers
if channels[chan].get_catch() is not MISSING
if channels[chan].is_available()
and checkpoint["channel_versions"].get(chan, null_version) # type: ignore[operator]
> seen.get(chan, null_version)
):