diff --git a/langgraph/store/redis/__init__.py b/langgraph/store/redis/__init__.py index a41bbbd..79d3cb1 100644 --- a/langgraph/store/redis/__init__.py +++ b/langgraph/store/redis/__init__.py @@ -5,10 +5,10 @@ import asyncio import json import math -import uuid from contextlib import contextmanager from datetime import datetime, timezone from typing import Any, Iterable, Iterator, Optional, Sequence, cast +from ulid import ULID from langgraph.store.base import ( BaseStore, @@ -223,7 +223,7 @@ def _batch_put_ops( # Generate IDs for PUT operations for _, op in put_ops: if op.value is not None: - generated_doc_id = uuid.uuid4().hex + generated_doc_id = str(ULID()) namespace = _namespace_to_text(op.namespace) doc_ids[(namespace, op.key)] = generated_doc_id diff --git a/langgraph/store/redis/aio.py b/langgraph/store/redis/aio.py index bcaacdb..8625122 100644 --- a/langgraph/store/redis/aio.py +++ b/langgraph/store/redis/aio.py @@ -2,12 +2,12 @@ import asyncio import json -import uuid import weakref from contextlib import asynccontextmanager from datetime import datetime, timezone from types import TracebackType from typing import Any, AsyncIterator, Iterable, Optional, Sequence, cast +from ulid import ULID from langgraph.store.base import ( BaseStore, @@ -398,7 +398,7 @@ async def _batch_put_ops( # Generate IDs for PUT operations for _, op in put_ops: if op.value is not None: - generated_doc_id = uuid.uuid4().hex + generated_doc_id = str(ULID()) namespace = _namespace_to_text(op.namespace) doc_ids[(namespace, op.key)] = generated_doc_id diff --git a/poetry.lock b/poetry.lock index afb21c4..266b053 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1508,6 +1508,20 @@ files = [ [package.extras] cli = ["click (>=5.0)"] +[[package]] +name = "python-ulid" +version = "3.0.0" +description = "Universally unique lexicographically sortable identifier" +optional = false +python-versions = ">=3.9" +files = [ + {file = "python_ulid-3.0.0-py3-none-any.whl", hash = "sha256:e4c4942ff50dbd79167ad01ac725ec58f924b4018025ce22c858bfcff99a5e31"}, + {file = "python_ulid-3.0.0.tar.gz", hash = "sha256:e50296a47dc8209d28629a22fc81ca26c00982c78934bd7766377ba37ea49a9f"}, +] + +[package.extras] +pydantic = ["pydantic (>=2.0)"] + [[package]] name = "pywin32" version = "308" @@ -2271,4 +2285,4 @@ cffi = ["cffi (>=1.11)"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.13" -content-hash = "065903b047fb88be4267859ff3e6a979da0c52e424237048ed004ca717c1cf5a" +content-hash = "4752616bd33f211c275fd830ceb231466ae138aff257a45136815a9d603919ce" diff --git a/pyproject.toml b/pyproject.toml index d4ee3ca..8c5eab1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,6 +21,7 @@ python = ">=3.9,<3.13" langgraph-checkpoint = "^2.0.10" redisvl = "^0.3.9" redis = "^5.2.1" +python-ulid = "^3.0.0" langgraph = "^0.2.70" [tool.poetry.group.dev.dependencies] diff --git a/tests/test_async_store.py b/tests/test_async_store.py index 186e7d8..b1b98e6 100644 --- a/tests/test_async_store.py +++ b/tests/test_async_store.py @@ -1,6 +1,5 @@ """Tests for AsyncRedisStore.""" -import uuid from typing import Any, AsyncGenerator, Dict, Sequence, cast import pytest @@ -8,6 +7,10 @@ from langchain_core.messages import BaseMessage, HumanMessage from langchain_core.runnables import RunnableConfig from langchain_openai import OpenAIEmbeddings +from redis.asyncio import Redis +from ulid import ULID + +from langgraph.checkpoint.redis import AsyncRedisSaver from langgraph.constants import START from langgraph.graph import MessagesState, StateGraph from langgraph.store.base import ( @@ -286,6 +289,7 @@ async def test_list_namespaces(store: AsyncRedisStore) -> None: for namespace in test_namespaces: await store.adelete(namespace, "dummy") + # TODO @pytest.mark.skip(reason="Skipping for v0.0.1 release") @pytest.mark.asyncio @@ -527,7 +531,7 @@ def call_model( # Store new memories if the user asks the model to remember if "remember" in last_message.content.lower(): # type:ignore[union-attr] memory = "User name is Bob" - store.put(namespace, str(uuid.uuid4()), {"data": memory}) + store.put(namespace, str(ULID()), {"data": memory}) messages = [{"role": "system", "content": system_msg}] messages.extend([msg.model_dump() for msg in state["messages"]]) diff --git a/tests/test_store.py b/tests/test_store.py index 4dd56d9..e47e958 100644 --- a/tests/test_store.py +++ b/tests/test_store.py @@ -1,4 +1,3 @@ -import uuid from typing import Any, Dict, Sequence, cast import pytest @@ -6,6 +5,10 @@ from langchain_core.messages import BaseMessage, HumanMessage from langchain_core.runnables import RunnableConfig from langchain_openai import OpenAIEmbeddings +from redis import Redis +from ulid import ULID + +from langgraph.checkpoint.redis import RedisSaver from langgraph.graph import START, MessagesState, StateGraph from langgraph.store.base import ( BaseStore, @@ -19,9 +22,6 @@ SearchItem, SearchOp, ) -from redis import Redis - -from langgraph.checkpoint.redis import RedisSaver from langgraph.store.redis import RedisStore from tests.conftest import VECTOR_TYPES from tests.embed_test_utils import CharacterEmbeddings @@ -464,7 +464,7 @@ def call_model( # Store new memories if the user asks the model to remember if "remember" in last_message.content.lower(): # type:ignore[union-attr] memory = "User name is Bob" - store.put(namespace, str(uuid.uuid4()), {"data": memory}) + store.put(namespace, str(ULID()), {"data": memory}) messages = [{"role": "system", "content": system_msg}] messages.extend([msg.model_dump() for msg in state["messages"]]) diff --git a/tests/test_sync.py b/tests/test_sync.py index 2f5323d..9e4b0a4 100644 --- a/tests/test_sync.py +++ b/tests/test_sync.py @@ -8,6 +8,9 @@ from langchain_core.tools import tool from langchain_core.tools.base import BaseTool from langchain_openai import ChatOpenAI +from redis import Redis +from redis.exceptions import ConnectionError as RedisConnectionError + from langgraph.checkpoint.base import ( WRITES_IDX_MAP, Checkpoint, @@ -15,11 +18,8 @@ create_checkpoint, empty_checkpoint, ) -from langgraph.prebuilt import create_react_agent -from redis import Redis -from redis.exceptions import ConnectionError as RedisConnectionError - from langgraph.checkpoint.redis import BaseRedisSaver, RedisSaver +from langgraph.prebuilt import create_react_agent @pytest.fixture