diff --git a/langgraph/channels/base.py b/langgraph/channels/base.py index 4384cc273..a2a4c2d0d 100644 --- a/langgraph/channels/base.py +++ b/langgraph/channels/base.py @@ -13,9 +13,9 @@ from typing import ( ) from typing_extensions import Self -from uuid6 import uuid6 from langgraph.checkpoint.base import Checkpoint +from langgraph.checkpoint.id import uuid6 from langgraph.errors import EmptyChannelError, InvalidUpdateError Value = TypeVar("Value") diff --git a/langgraph/checkpoint/base.py b/langgraph/checkpoint/base.py index 1823e1eac..2bdb52055 100644 --- a/langgraph/checkpoint/base.py +++ b/langgraph/checkpoint/base.py @@ -12,8 +12,8 @@ from typing import ( ) from langchain_core.runnables import ConfigurableFieldSpec, RunnableConfig -from uuid6 import uuid6 +from langgraph.checkpoint.id import uuid6 from langgraph.serde.base import SerializerProtocol from langgraph.serde.jsonplus import JsonPlusSerializer diff --git a/langgraph/checkpoint/id.py b/langgraph/checkpoint/id.py new file mode 100644 index 000000000..f14672208 --- /dev/null +++ b/langgraph/checkpoint/id.py @@ -0,0 +1,42 @@ +"""Adapted from +https://github.com/oittaa/uuid6-python/blob/main/src/uuid6/__init__.py#L95 +Bundled in to avoid install issues with uuid6 package +""" + +import secrets +import time +from typing import Optional +from uuid import UUID + + +def uuid6(node: Optional[int] = None, clock_seq: Optional[int] = None) -> UUID: + r"""UUID version 6 is a field-compatible version of UUIDv1, reordered for + improved DB locality. It is expected that UUIDv6 will primarily be + used in contexts where there are existing v1 UUIDs. Systems that do + not involve legacy UUIDv1 SHOULD consider using UUIDv7 instead. + + If 'node' is not given, a random 48-bit number is chosen. + + If 'clock_seq' is given, it is used as the sequence number; + otherwise a random 14-bit sequence number is chosen.""" + + global _last_v6_timestamp + + nanoseconds = time.time_ns() + # 0x01b21dd213814000 is the number of 100-ns intervals between the + # UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00. + timestamp = nanoseconds // 100 + 0x01B21DD213814000 + if _last_v6_timestamp is not None and timestamp <= _last_v6_timestamp: + timestamp = _last_v6_timestamp + 1 + _last_v6_timestamp = timestamp + if clock_seq is None: + clock_seq = secrets.randbits(14) # instead of stable storage + if node is None: + node = secrets.randbits(48) + time_high_and_time_mid = (timestamp >> 12) & 0xFFFFFFFFFFFF + time_low_and_version = timestamp & 0x0FFF + uuid_int = time_high_and_time_mid << 80 + uuid_int |= time_low_and_version << 64 + uuid_int |= (clock_seq & 0x3FFF) << 48 + uuid_int |= node & 0xFFFFFFFFFFFF + return UUID(int=uuid_int, version=6) diff --git a/poetry.lock b/poetry.lock index 20b2d5192..de62224a0 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3840,17 +3840,6 @@ h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] -[[package]] -name = "uuid6" -version = "2024.1.12" -description = "New time-based UUID formats which are suited for use as a database key" -optional = false -python-versions = ">=3.8" -files = [ - {file = "uuid6-2024.1.12-py3-none-any.whl", hash = "sha256:8150093c8d05a331bc0535bc5ef6cf57ac6eceb2404fd319bc10caee2e02c065"}, - {file = "uuid6-2024.1.12.tar.gz", hash = "sha256:ed0afb3a973057575f9883201baefe402787ca5e11e1d24e377190f0c43f1993"}, -] - [[package]] name = "watchdog" version = "4.0.0" @@ -4077,4 +4066,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = ">=3.9.0,<4.0" -content-hash = "396cb9a3938f1cc31440d45292757c13d3894d11374799e0c8ccfa1aa877fcb5" +content-hash = "47f653979a2e0bcb14264ceedef65670ff2ddce7e70c6de46043194aa4688c1a" diff --git a/pyproject.toml b/pyproject.toml index 1948b606d..6d71f58d1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,7 +10,6 @@ repository = "https://www.github.com/langchain-ai/langgraph" [tool.poetry.dependencies] python = ">=3.9.0,<4.0" langchain-core = ">=0.2,<0.3" -uuid6 = "^2024.1.12" [tool.poetry.group.test.dependencies]