Skip to content

Release v0.0.4 #22

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Apr 9, 2025
3 changes: 2 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ on:

schedule:
- cron: "0 2 * * *" # 2 AM UTC nightly

workflow_dispatch:


Expand Down Expand Up @@ -44,6 +44,7 @@ jobs:

- name: Install dependencies
run: |
pip wheel --no-cache-dir --use-pep517 ml-dtypes
poetry install --all-extras

- name: Set Redis image name
Expand Down
14 changes: 7 additions & 7 deletions examples/Dockerfile.jupyter
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ RUN useradd -m jupyter

WORKDIR /home/jupyter/workspace

# Copy the library files
COPY . /home/jupyter/workspace
# Copy the library files (only copy the checkpoint-redis directory)
COPY ./libs/checkpoint-redis /home/jupyter/workspace/libs/checkpoint-redis

# Create necessary directories and set permissions
RUN mkdir -p /home/jupyter/workspace/libs/checkpoint-redis/docs && \
RUN mkdir -p /home/jupyter/workspace/libs/checkpoint-redis/examples && \
chown -R jupyter:jupyter /home/jupyter/workspace

# Switch to non-root user
Expand All @@ -21,12 +21,12 @@ ENV PATH="/home/jupyter/venv/bin:$PATH"

# Install dependencies
RUN pip install --no-cache-dir --upgrade pip && \
pip install --no-cache-dir langgraph && \
pip install --no-cache-dir langgraph==0.3.25 && \
pip install --no-cache-dir -e /home/jupyter/workspace/libs/checkpoint-redis && \
pip install --no-cache-dir jupyter redis
pip install --no-cache-dir jupyter redis langchain-openai langchain-anthropic python-ulid

# Set the working directory to the docs folder
WORKDIR /home/jupyter/workspace/libs/checkpoint-redis/docs
# Set the working directory to the examples folder
WORKDIR /home/jupyter/workspace/libs/checkpoint-redis/examples

# Expose Jupyter port
EXPOSE 8888
Expand Down
2 changes: 1 addition & 1 deletion examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ This directory contains Jupyter notebooks demonstrating the usage of the Redis w
To run these notebooks using the local development versions of LangChain and the Redis partner package:

1. Ensure you have Docker and Docker Compose installed on your system.
2. Navigate to this directory (`langgraph/docs`) in your terminal.
2. Navigate to this directory (`examples`) in your terminal.
3. Run the following command:
```bash
docker compose up
Expand Down
76 changes: 40 additions & 36 deletions examples/create-react-agent-memory.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -120,57 +120,41 @@
"execution_count": 3,
"id": "7a154152-973e-4b5d-aa13-48c617744a4c",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"22:31:51 redisvl.index.index INFO Index already exists, not overwriting.\n",
"22:31:51 redisvl.index.index INFO Index already exists, not overwriting.\n",
"22:31:51 redisvl.index.index INFO Index already exists, not overwriting.\n"
]
}
],
"outputs": [],
"source": [
"from typing import Literal\n",
"\n",
"from langchain_core.tools import tool\n",
"\n",
"# First we initialize the model we want to use.\n",
"from langchain_openai import ChatOpenAI\n",
"\n",
"from langgraph.checkpoint.redis import RedisSaver\n",
"from langgraph.prebuilt import create_react_agent\n",
"\n",
"model = ChatOpenAI(model=\"gpt-4o\", temperature=0)\n",
"\n",
"\n",
"# For this tutorial we will use custom tool that returns pre-defined values for weather in two cities (NYC & SF)\n",
"\n",
"from langchain_core.tools import tool\n",
"\n",
"\n",
"@tool\n",
"def get_weather(city: Literal[\"nyc\", \"sf\"]):\n",
"def get_weather(location: str) -> str:\n",
" \"\"\"Use this to get weather information.\"\"\"\n",
" if city == \"nyc\":\n",
" if any([city in location.lower() for city in [\"nyc\", \"new york city\"]]):\n",
" return \"It might be cloudy in nyc\"\n",
" elif city == \"sf\":\n",
" elif any([city in location.lower() for city in [\"sf\", \"san francisco\"]]):\n",
" return \"It's always sunny in sf\"\n",
" else:\n",
" raise AssertionError(\"Unknown city\")\n",
" return f\"I am not sure what the weather is in {location}\"\n",
"\n",
"\n",
"tools = [get_weather]\n",
"\n",
"# We can add \"chat memory\" to the graph with LangGraph's Redis checkpointer\n",
"# We can add \"chat memory\" to the graph with LangGraph's checkpointer\n",
"# to retain the chat context between interactions\n",
"from langgraph.checkpoint.memory import MemorySaver\n",
"\n",
"\n",
"REDIS_URI = \"redis://redis:6379\"\n",
"memory = None\n",
"with RedisSaver.from_conn_string(REDIS_URI) as cp:\n",
" cp.setup()\n",
" memory = cp\n",
"memory = MemorySaver()\n",
"\n",
"# Define the graph\n",
"\n",
"from langgraph.prebuilt import create_react_agent\n",
"\n",
"graph = create_react_agent(model, tools=tools, checkpointer=memory)"
]
Expand Down Expand Up @@ -216,17 +200,17 @@
"What's the weather in NYC?\n",
"==================================\u001b[1m Ai Message \u001b[0m==================================\n",
"Tool Calls:\n",
" get_weather (call_Edwfw0WiyIJ7vt9xzU9xvyeg)\n",
" Call ID: call_Edwfw0WiyIJ7vt9xzU9xvyeg\n",
" get_weather (call_LDM16pwsyYeZPQ78UlZCMs7n)\n",
" Call ID: call_LDM16pwsyYeZPQ78UlZCMs7n\n",
" Args:\n",
" city: nyc\n",
" location: New York City\n",
"=================================\u001b[1m Tool Message \u001b[0m=================================\n",
"Name: get_weather\n",
"\n",
"It might be cloudy in nyc\n",
"==================================\u001b[1m Ai Message \u001b[0m==================================\n",
"\n",
"The weather in NYC might be cloudy.\n"
"The weather in New York City might be cloudy.\n"
]
}
],
Expand All @@ -242,7 +226,7 @@
"id": "838a043f-90ad-4e69-9d1d-6e22db2c346c",
"metadata": {},
"source": [
"Notice that when we pass the same the same thread ID, the chat history is preserved"
"Notice that when we pass the same thread ID, the chat history is preserved."
]
},
{
Expand All @@ -260,14 +244,35 @@
"What's it known for?\n",
"==================================\u001b[1m Ai Message \u001b[0m==================================\n",
"\n",
"Could you please specify what \"it\" refers to? Are you asking about a specific city, person, event, or something else?\n"
"New York City is known for a variety of iconic landmarks, cultural institutions, and vibrant neighborhoods. Some of the most notable features include:\n",
"\n",
"1. **Statue of Liberty**: A symbol of freedom and democracy, located on Liberty Island.\n",
"2. **Times Square**: Known for its bright lights, Broadway theaters, and bustling atmosphere.\n",
"3. **Central Park**: A large public park offering a natural oasis amidst the urban environment.\n",
"4. **Empire State Building**: An iconic skyscraper offering panoramic views of the city.\n",
"5. **Broadway**: Famous for its world-class theater productions and musicals.\n",
"6. **Wall Street**: The financial hub of the city, home to the New York Stock Exchange.\n",
"7. **Museums**: Including the Metropolitan Museum of Art, Museum of Modern Art (MoMA), and the American Museum of Natural History.\n",
"8. **Diverse Cuisine**: A melting pot of cultures, offering a wide range of international foods.\n",
"9. **Brooklyn Bridge**: A historic bridge connecting Manhattan and Brooklyn, known for its architectural beauty.\n",
"10. **Cultural Diversity**: A rich tapestry of cultures and communities, making it a global city.\n",
"\n",
"These are just a few highlights of what makes New York City a unique and exciting place to visit or live.\n"
]
}
],
"source": [
"inputs = {\"messages\": [(\"user\", \"What's it known for?\")]}\n",
"print_stream(graph.stream(inputs, config=config, stream_mode=\"values\"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c461eb47-b4f9-406f-8923-c68db7c5687f",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
Expand All @@ -292,4 +297,3 @@
"nbformat": 4,
"nbformat_minor": 5
}

70 changes: 18 additions & 52 deletions examples/cross-thread-persistence.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
"outputs": [],
"source": [
"%%capture --no-stderr\n",
"%pip install -U langchain_openai langchain_anthropic langgraph"
"%pip install -U langchain_openai langgraph"
]
},
{
Expand Down Expand Up @@ -129,26 +129,15 @@
"metadata": {},
"outputs": [],
"source": [
"from langgraph.store.memory import InMemoryStore\n",
"from langchain_openai import OpenAIEmbeddings\n",
"\n",
"from langgraph.store.base import IndexConfig\n",
"from langgraph.store.redis import RedisStore\n",
"\n",
"REDIS_URI = \"redis://redis:6379\"\n",
"\n",
"index_config: IndexConfig = {\n",
" \"dims\": 1536,\n",
" \"embed\": OpenAIEmbeddings(model=\"text-embedding-3-small\"),\n",
" \"ann_index_config\": {\n",
" \"vector_type\": \"vector\",\n",
" },\n",
" \"distance_type\": \"cosine\",\n",
"}\n",
"\n",
"redis_store = None\n",
"with RedisStore.from_conn_string(REDIS_URI, index=index_config) as s:\n",
" s.setup()\n",
" redis_store = s"
"in_memory_store = InMemoryStore(\n",
" index={\n",
" \"embed\": OpenAIEmbeddings(model=\"text-embedding-3-small\"),\n",
" \"dims\": 1536,\n",
" }\n",
")"
]
},
{
Expand All @@ -164,27 +153,19 @@
"execution_count": 4,
"id": "2a30a362-528c-45ee-9df6-630d2d843588",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"22:32:41 redisvl.index.index INFO Index already exists, not overwriting.\n",
"22:32:41 redisvl.index.index INFO Index already exists, not overwriting.\n",
"22:32:41 redisvl.index.index INFO Index already exists, not overwriting.\n"
]
}
],
"outputs": [],
"source": [
"import uuid\n",
"from typing import Annotated\n",
"from typing_extensions import TypedDict\n",
"\n",
"from langchain_anthropic import ChatAnthropic\n",
"from langchain_core.runnables import RunnableConfig\n",
"\n",
"from langgraph.checkpoint.redis import RedisSaver\n",
"from langgraph.graph import START, MessagesState, StateGraph\n",
"from langgraph.graph import StateGraph, MessagesState, START\n",
"from langgraph.checkpoint.memory import MemorySaver\n",
"from langgraph.store.base import BaseStore\n",
"\n",
"\n",
"model = ChatAnthropic(model=\"claude-3-5-sonnet-20240620\")\n",
"\n",
"\n",
Expand Down Expand Up @@ -213,15 +194,8 @@
"builder.add_node(\"call_model\", call_model)\n",
"builder.add_edge(START, \"call_model\")\n",
"\n",
"\n",
"REDIS_URI = \"redis://redis:6379\"\n",
"checkpointer = None\n",
"with RedisSaver.from_conn_string(REDIS_URI) as cp:\n",
" cp.setup()\n",
" checkpointer = cp\n",
"\n",
"# NOTE: we're passing the store object here when compiling the graph\n",
"graph = builder.compile(checkpointer=checkpointer, store=redis_store)\n",
"graph = builder.compile(checkpointer=MemorySaver(), store=in_memory_store)\n",
"# If you're using LangGraph Cloud or LangGraph Studio, you don't need to pass the store or checkpointer when compiling the graph, since it's done automatically."
]
},
Expand Down Expand Up @@ -311,7 +285,7 @@
"id": "80fd01ec-f135-4811-8743-daff8daea422",
"metadata": {},
"source": [
"We can now inspect the Redis store and verify that we have in fact saved the memories for the user:"
"We can now inspect our in-memory store and verify that we have in fact saved the memories for the user:"
]
},
{
Expand All @@ -329,7 +303,7 @@
}
],
"source": [
"for memory in redis_store.search((\"memories\", \"1\")):\n",
"for memory in in_memory_store.search((\"memories\", \"1\")):\n",
" print(memory.value)"
]
},
Expand All @@ -356,7 +330,7 @@
"what is my name?\n",
"==================================\u001b[1m Ai Message \u001b[0m==================================\n",
"\n",
"I apologize, but I don't have any information about your name. As an AI assistant, I don't have access to personal information about users unless it's explicitly provided in our conversation. If you'd like, you can tell me your name and I'll be happy to use it in our discussion.\n"
"I apologize, but I don't have any information about your name. As an AI assistant, I don't have access to personal information about users unless it's specifically provided in our conversation. If you'd like, you can tell me your name and I'll be happy to use it in our discussion.\n"
]
}
],
Expand All @@ -366,14 +340,6 @@
"for chunk in graph.stream({\"messages\": [input_message]}, config, stream_mode=\"values\"):\n",
" chunk[\"messages\"][-1].pretty_print()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "60787b3c-216e-4f38-b974-ea1d7f9d8642",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
Expand Down
8 changes: 4 additions & 4 deletions examples/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@ name: langgraph-redis-notebooks
services:
jupyter:
build:
context: ../../../.. # This should point to the root of langgraph-redis
dockerfile: libs/checkpoint-redis/langgraph/docs/Dockerfile.jupyter
context: ../../.. # This should point to the root of langgraph-redis
dockerfile: libs/checkpoint-redis/examples/Dockerfile.jupyter
ports:
- "8888:8888"
volumes:
- ./:/home/jupyter/workspace/libs/checkpoint-redis/docs
- ./:/home/jupyter/workspace/libs/checkpoint-redis/examples
environment:
- REDIS_URL=redis://redis:6379
- USER_AGENT=LangGraphRedisJupyterNotebooks/0.0.4
user: jupyter
working_dir: /home/jupyter/workspace/libs/checkpoint-redis/docs
working_dir: /home/jupyter/workspace/libs/checkpoint-redis/examples
depends_on:
- redis

Expand Down
Loading