diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index 83bbf116f..f48e92bf6 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -7,35 +7,29 @@ body: value: > Thank you for taking the time to file a bug report. - Use this to report bugs in LangChain. - - If you're not certain that your issue is due to a bug in LangChain, please use [GitHub Discussions](https://github.com/langchain-ai/langchain/discussions) - to ask for help with your issue. + Use this to report BUGS in LangGraph. For usage questions, feature requests and general design questions, please use [GitHub Discussions](https://github.com/langchain-ai/langgraph/discussions). Relevant links to check before filing a bug report to see if your issue has already been reported, fixed or if there's another way to solve your problem: - [LangGraph documentation](https://langchain-ai.github.io/langgraph/). + [LangGraph Github Discussions](https://github.com/langchain-ai/langgraph/discussions), + [LangGraph Github Issues](https://github.com/langchain-ai/langgraph/issues), + [LangGraph how-to guides](https://langchain-ai.github.io/langgraph/how-tos/). [LangChain documentation with the integrated search](https://python.langchain.com/docs/get_started/introduction), [GitHub search](https://github.com/langchain-ai/langgraph), - [LangChain Github Discussions](https://github.com/langchain-ai/langgraph/discussions), - [LangChain Github Issues](https://github.com/langchain-ai/langgraph/issues), - [LangChain ChatBot](https://chat.langchain.com/) - type: checkboxes id: checks attributes: label: Checked other resources - description: Please confirm and check all the following options. + description: Before submitting this issue, please confirm that you have completed all the steps below by checking each option. These steps help ensure your issue is well-defined, relevant, and actionable. options: - - label: I added a very descriptive title to this issue. + - label: This is a bug, not a usage question. For questions, please use GitHub Discussions. required: true - - label: I searched the [LangGraph](https://langchain-ai.github.io/langgraph/)/LangChain documentation with the integrated search. + - label: I added a clear and detailed title that summarizes the issue. required: true - - label: I used the GitHub search to find a similar question and didn't find it. + - label: I read what a minimal reproducible example is (https://stackoverflow.com/help/minimal-reproducible-example). required: true - - label: I am sure that this is a bug in LangGraph/LangChain rather than my code. - required: true - - label: I am sure this is better as an issue [rather than a GitHub discussion](https://github.com/langchain-ai/langgraph/discussions/new/choose), since this is a LangGraph bug and not a design question. + - label: I included a self-contained, minimal example that demonstrates the issue INCLUDING all the relevant imports. The code run AS IS to reproduce the issue. required: true - type: textarea id: reproduction @@ -45,14 +39,6 @@ body: label: Example Code description: | Please add a self-contained, [minimal, reproducible, example](https://stackoverflow.com/help/minimal-reproducible-example) with your use case. - - If a maintainer can copy it, run it, and see it right away, there's a much higher chance that you'll be able to get help. - - **Important!** - - * Reduce your code to the minimum required to reproduce the issue if possible. This makes it much easier for others to help you. - * Avoid screenshots when possible, as they are hard to read and (more importantly) don't allow others to copy-and-paste your code. - placeholder: | from langgraph.graph import StateGraph @@ -92,25 +78,8 @@ body: attributes: label: System Info description: | - Please share your system info with us. - - "pip freeze | grep langchain" - platform (windows / linux / mac) - python version - - OR if you're on a recent version of langchain-core you can paste the output of: - python -m langchain_core.sys_info placeholder: | - "pip freeze | grep langgraph" - platform - python version - - Alternatively, if you're on a recent version of langchain-core you can paste the output of: - python -m langchain_core.sys_info - - These will only surface LangChain packages, don't forget to include any other relevant - packages you're using (if you're not sure what's relevant, you can paste the entire output of `pip freeze`). validations: required: true diff --git a/.github/workflows/_lint.yml b/.github/workflows/_lint.yml index c6616bb4b..69b990b6a 100644 --- a/.github/workflows/_lint.yml +++ b/.github/workflows/_lint.yml @@ -42,7 +42,6 @@ jobs: with: python-version: ${{ matrix.python-version }} poetry-version: ${{ env.POETRY_VERSION }} - working-directory: ${{ inputs.working-directory }} cache-key: lint-${{ inputs.working-directory }} - name: Check Poetry File diff --git a/.github/workflows/_test.yml b/.github/workflows/_test.yml index 29eab4cd3..3329da546 100644 --- a/.github/workflows/_test.yml +++ b/.github/workflows/_test.yml @@ -31,7 +31,6 @@ jobs: with: python-version: ${{ matrix.python-version }} poetry-version: ${{ env.POETRY_VERSION }} - working-directory: ${{ inputs.working-directory }} cache-key: test-${{ inputs.working-directory }} - name: Login to Docker Hub uses: docker/login-action@v3 diff --git a/.github/workflows/_test_langgraph.yml b/.github/workflows/_test_langgraph.yml index 5c3f5182e..2708d0f23 100644 --- a/.github/workflows/_test_langgraph.yml +++ b/.github/workflows/_test_langgraph.yml @@ -60,7 +60,7 @@ jobs: env: LANGGRAPH_FF_SEND_V2: ${{ matrix.ff-send-v2 }} run: | - make test + make test_parallel - name: Ensure the tests did not create any additional files shell: bash diff --git a/.github/workflows/_test_release.yml b/.github/workflows/_test_release.yml index a4d81e1e2..46e065d33 100644 --- a/.github/workflows/_test_release.yml +++ b/.github/workflows/_test_release.yml @@ -29,7 +29,6 @@ jobs: with: python-version: ${{ env.PYTHON_VERSION }} poetry-version: ${{ env.POETRY_VERSION }} - working-directory: ${{ inputs.working-directory }} cache-key: release # We want to keep this build stage *separate* from the release stage, diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d3d8626aa..d1d5b2aaf 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -31,7 +31,6 @@ jobs: with: python-version: ${{ env.PYTHON_VERSION }} poetry-version: ${{ env.POETRY_VERSION }} - working-directory: ${{ inputs.working-directory }} cache-key: release # We want to keep this build stage *separate* from the release stage, @@ -169,7 +168,6 @@ jobs: with: python-version: ${{ env.PYTHON_VERSION }} poetry-version: ${{ env.POETRY_VERSION }} - working-directory: ${{ inputs.working-directory }} - name: Import published package shell: bash @@ -256,7 +254,6 @@ jobs: with: python-version: ${{ env.PYTHON_VERSION }} poetry-version: ${{ env.POETRY_VERSION }} - working-directory: ${{ inputs.working-directory }} cache-key: release - uses: actions/download-artifact@v4 @@ -298,7 +295,6 @@ jobs: with: python-version: ${{ env.PYTHON_VERSION }} poetry-version: ${{ env.POETRY_VERSION }} - working-directory: ${{ inputs.working-directory }} cache-key: release - uses: actions/download-artifact@v4 diff --git a/docs/cassettes/semantic-search_10.msgpack.zlib b/docs/cassettes/semantic-search_10.msgpack.zlib new file mode 100644 index 000000000..b55c7fcf2 --- /dev/null +++ b/docs/cassettes/semantic-search_10.msgpack.zlib @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/docs/cassettes/semantic-search_13.msgpack.zlib b/docs/cassettes/semantic-search_13.msgpack.zlib new file mode 100644 index 000000000..b01db0846 --- /dev/null +++ b/docs/cassettes/semantic-search_13.msgpack.zlib @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/docs/cassettes/semantic-search_15.msgpack.zlib b/docs/cassettes/semantic-search_15.msgpack.zlib new file mode 100644 index 000000000..f5810c73a --- /dev/null +++ b/docs/cassettes/semantic-search_15.msgpack.zlib @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/docs/cassettes/semantic-search_17.msgpack.zlib b/docs/cassettes/semantic-search_17.msgpack.zlib new file mode 100644 index 000000000..23469642a --- /dev/null +++ b/docs/cassettes/semantic-search_17.msgpack.zlib @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/docs/cassettes/semantic-search_19.msgpack.zlib b/docs/cassettes/semantic-search_19.msgpack.zlib new file mode 100644 index 000000000..d0604b031 --- /dev/null +++ b/docs/cassettes/semantic-search_19.msgpack.zlib @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/docs/cassettes/semantic-search_6.msgpack.zlib b/docs/cassettes/semantic-search_6.msgpack.zlib new file mode 100644 index 000000000..9e8ecf09a --- /dev/null +++ b/docs/cassettes/semantic-search_6.msgpack.zlib @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/docs/cassettes/semantic-search_8.msgpack.zlib b/docs/cassettes/semantic-search_8.msgpack.zlib new file mode 100644 index 000000000..b9b99ebd7 --- /dev/null +++ b/docs/cassettes/semantic-search_8.msgpack.zlib @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/docs/docs/cloud/deployment/semantic_search.md b/docs/docs/cloud/deployment/semantic_search.md index 1ea48be13..c9dc58633 100644 --- a/docs/docs/cloud/deployment/semantic_search.md +++ b/docs/docs/cloud/deployment/semantic_search.md @@ -111,8 +111,8 @@ from langgraph_sdk import get_client async def search_store(): client = get_client() - results = await client.store.search( - namespace=("memory", "facts"), + results = await client.store.search_items( + ("memory", "facts"), query="your search query", limit=3 # number of results to return ) diff --git a/docs/docs/concepts/low_level.md b/docs/docs/concepts/low_level.md index 05ceacdea..1d059568b 100644 --- a/docs/docs/concepts/low_level.md +++ b/docs/docs/concepts/low_level.md @@ -283,6 +283,9 @@ You can optionally provide a dictionary that maps the `routing_function`'s outpu graph.add_conditional_edges("node_a", routing_function, {True: "node_b", False: "node_c"}) ``` +!!! tip + Use [`Command`](#command) instead of conditional edges if you want to combine state updates and routing in a single function. + ### Entry Point The entry point is the first node(s) that are run when the graph starts. You can use the [`add_edge`][langgraph.graph.StateGraph.add_edge] method from the virtual [`START`][langgraph.constants.START] node to the first node to execute to specify where to enter the graph. @@ -322,6 +325,65 @@ def continue_to_jokes(state: OverallState): graph.add_conditional_edges("node_a", continue_to_jokes) ``` +## `Command` + +It can be useful to combine control flow (edges) and state updates (nodes). For example, you might want to BOTH perform state updates AND decide which node to go to next in the SAME node. LangGraph provides a way to do so by returning a [`Command`][langgraph.types.Command] object from node functions: + +```python +def my_node(state: State) -> Command[Literal["my_other_node"]]: + return Command( + # state update + update={"foo": "bar"}, + # control flow + goto="my_other_node" + ) +``` + +`Command` has the following properties: + +| Property | Description | +| --- | --- | +| `graph` | Graph to send the command to. Supported values:
- `None`: the current graph (default)
- `Command.PARENT`: closest parent graph | +| `update` | Update to apply to the graph's state. | +| `resume` | Value to resume execution with. To be used together with [`interrupt()`][langgraph.types.interrupt]. | +| `goto` | Can be one of the following:
- name of the node to navigate to next (any node that belongs to the specified `graph`)
- sequence of node names to navigate to next
- `Send` object (to execute a node with the input provided)
- sequence of `Send` objects
If `goto` is not specified and there are no other tasks left in the graph, the graph will halt after executing the current superstep. | + +```python +from langgraph.graph import StateGraph, START +from langgraph.types import Command +from typing_extensions import Literal, TypedDict + +class State(TypedDict): + foo: str + +def my_node(state: State) -> Command[Literal["my_other_node"]]: + return Command(update={"foo": "bar"}, goto="my_other_node") + +def my_other_node(state: State): + return {"foo": state["foo"] + "baz"} + +builder = StateGraph(State) +builder.add_edge(START, "my_node") +builder.add_node("my_node", my_node) +builder.add_node("my_other_node", my_other_node) + +graph = builder.compile() +``` + +With `Command` you can also achieve dynamic control flow behavior (identical to [conditional edges](#conditional-edges)): + +```python +def my_node(state: State) -> Command[Literal["my_other_node"]]: + if state["foo"] == "bar": + return Command(update={"foo": "baz"}, goto="my_other_node") +``` + +!!! important + + When returning `Command` in your node functions, you must add return type annotations with the list of node names the node is routing to, e.g. `Command[Literal["node_b", "node_c"]]`. This is necessary for the graph compilation and rendering, and tells LangGraph that `node_a` can navigate to `node_b` and `node_c`. + +Check out this [how-to guide](../how-tos/command.ipynb) for an end-to-end example of how to use `Command`. + ## Persistence LangGraph provides built-in persistence for your agent's state using [checkpointers][langgraph.checkpoint.base.BaseCheckpointSaver]. Checkpointers save snapshots of the graph state at every superstep, allowing resumption at any time. This enables features like human-in-the-loop interactions, memory management, and fault-tolerance. You can even directly manipulate a graph's state after its execution using the diff --git a/docs/docs/concepts/memory.md b/docs/docs/concepts/memory.md index 126b35993..cdcd8ae5b 100644 --- a/docs/docs/concepts/memory.md +++ b/docs/docs/concepts/memory.md @@ -236,6 +236,9 @@ Different applications require various types of memory. Although the analogy isn [Semantic memory](https://en.wikipedia.org/wiki/Semantic_memory), both in humans and AI agents, involves the retention of specific facts and concepts. In humans, it can include information learned in school and the understanding of concepts and their relationships. For AI agents, semantic memory is often used to personalize applications by remembering facts or concepts from past interactions. +> Note: Not to be confused with "semantic search" which is a technique for finding similar content using "meaning" (usually as embeddings). Semantic memory is a term from psychology, referring to storing facts and knowledge, while semantic search is a method for retrieving information based on meaning rather than exact matches. + + #### Profile Semantic memories can be managed in different ways. For example, memories can be a single, continuously updated "profile" of well-scoped and specific information about a user, organization, or other entity (including the agent itself). A profile is generally just a JSON document with various key-value pairs you've selected to represent your domain. diff --git a/docs/docs/concepts/multi_agent.md b/docs/docs/concepts/multi_agent.md index 46bf4eeda..d8ef0a73b 100644 --- a/docs/docs/concepts/multi_agent.md +++ b/docs/docs/concepts/multi_agent.md @@ -28,12 +28,7 @@ There are several ways to connect agents in a multi-agent system: ### Network -In this architecture, agents are defined as graph nodes. Each agent can communicate with every other agent (many-to-many connections) and can decide which agent to call next. While very flexible, this architecture doesn't scale well as the number of agents grows: - -- hard to enforce which agent should be called next -- hard to determine how much [information](#shared-message-list) should be passed between the agents - -We recommend avoiding this architecture in production and using one of the below architectures instead. +In this architecture, agents are defined as graph nodes. Each agent can communicate with every other agent (many-to-many connections) and can decide which agent to call next. This architecture is good for problems that do not have a clear hierarchy of agents or a specific sequence in which agents should be called. ### Supervisor diff --git a/docs/docs/concepts/persistence.md b/docs/docs/concepts/persistence.md index 6637fbee0..0ec126316 100644 --- a/docs/docs/concepts/persistence.md +++ b/docs/docs/concepts/persistence.md @@ -276,9 +276,11 @@ The attributes it has are: Beyond simple retrieval, the store also supports semantic search, allowing you to find memories based on meaning rather than exact matches. To enable this, configure the store with an embedding model: ```python +from langchain.embeddings import init_embeddings + store = InMemoryStore( index={ - "embed": "openai:text-embedding-3-small", # Embedding provider + "embed": init_embeddings("openai:text-embedding-3-small"), # Embedding provider "dims": 1536, # Embedding dimensions "fields": ["food_preference", "$"] # Fields to embed } @@ -289,6 +291,7 @@ Now when searching, you can use natural language queries to find relevant memori ```python # Find memories about food preferences +# (This can be done after putting memories into the store) memories = store.search( namespace_for_memory, query="What does the user like to eat?", @@ -412,7 +415,22 @@ for update in graph.stream( print(update) ``` -When we use the LangGraph API, either locally (e.g., in LangGraph Studio) or with LangGraph Cloud, the base store is available to use by default and does not need to be specified during graph compilation. For cloud deployments, semantic search is automatically configured based on your `langgraph.json` settings. See the [deployment guide](../deployment/semantic_search.md) for more details. +When we use the LangGraph Platform, either locally (e.g., in LangGraph Studio) or with LangGraph Cloud, the base store is available to use by default and does not need to be specified during graph compilation. To enable semantic search, however, you **do** need to configure the indexing settings in your `langgraph.json` file. For example: + +```json +{ + ... + "store": { + "index": { + "embed": "openai:text-embeddings-3-small", + "dims": 1536, + "fields": ["$"] + } + } +} +``` + +See the [deployment guide](../cloud/deployment/semantic_search.md) for more details and configuration options. ## Checkpointer libraries diff --git a/docs/docs/concepts/template_applications.md b/docs/docs/concepts/template_applications.md index df8bc5e63..32209ad47 100644 --- a/docs/docs/concepts/template_applications.md +++ b/docs/docs/concepts/template_applications.md @@ -1,14 +1,21 @@ # Template Applications -!!! note Prerequisites - - - [LangGraph Studio](./langgraph_studio.md) - Templates are open source reference applications designed to help you get started quickly when building with LangGraph. They provide working examples of common agentic workflows that can be customized to your needs. -Templates can be accessed via [LangGraph Studio (macOS only)](langgraph_studio.md), or cloned directly from Github. You can download LangGraph Studio and see available templates [here](https://studio.langchain.com/). +You can create an application from a template using the LangGraph CLI. -## Available templates +!!! info "Requirements" + + - Python >= 3.11 + - [LangGraph CLI](https://langchain-ai.github.io/langgraph/cloud/reference/cli/): Requires langchain-cli[inmem] >= 0.1.58 + +## Install the LangGraph CLI + +```bash +pip install "langgraph-cli[inmem]==0.1.58" python-dotenv +``` + +## Available Templates | Template | Description | Python | JS/TS | |---------------------------|------------------------------------------------------------------------------------------|------------------------------------------------------------------|---------------------------------------------------------------------| @@ -17,3 +24,39 @@ Templates can be accessed via [LangGraph Studio (macOS only)](langgraph_studio.m | **Memory Agent** | A ReAct-style agent with an additional tool to store memories for use across threads. | [Repo](https://github.com/langchain-ai/memory-agent) | [Repo](https://github.com/langchain-ai/memory-agent-js) | | **Retrieval Agent** | An agent that includes a retrieval-based question-answering system. | [Repo](https://github.com/langchain-ai/retrieval-agent-template) | [Repo](https://github.com/langchain-ai/retrieval-agent-template-js) | | **Data-Enrichment Agent** | An agent that performs web searches and organizes its findings into a structured format. | [Repo](https://github.com/langchain-ai/data-enrichment) | [Repo](https://github.com/langchain-ai/data-enrichment-js) | + + +## 🌱 Create a LangGraph App + +To create a new app from a template, use the `langgraph new` command. + +```bash +langgraph new +``` + +## Next Steps + +Review the `README.md` file in the root of your new LangGraph app for more information about the template and how to customize it. + +After configuring the app properly and adding your API keys, you can start the app using the LangGraph CLI: + +```bash +langgraph dev +``` + +See the following guides for more information on how to deploy your app: + +- **[Launch Local LangGraph Server](../tutorials/langgraph-platform/local-server.md)**: This quick start guide shows how to start a LangGraph Server locally for the **ReAct Agent** template. The steps are similar for other templates. +- **[Deploy to LangGraph Cloud](../cloud/quick_start.md)**: Deploy your LangGraph app using LangGraph Cloud. + +### LangGraph Framework + +- **[LangGraph Concepts](../concepts/index.md)**: Learn the foundational concepts of LangGraph. +- **[LangGraph How-to Guides](../how-tos/index.md)**: Guides for common tasks with LangGraph. + +### 📚 Learn More about LangGraph Platform + +Expand your knowledge with these resources: + +- **[LangGraph Platform Concepts](../concepts/index.md#langgraph-platform)**: Understand the foundational concepts of the LangGraph Platform. +- **[LangGraph Platform How-to Guides](../how-tos/index.md#langgraph-platform)**: Discover step-by-step guides to build and deploy applications. diff --git a/docs/docs/how-tos/command.ipynb b/docs/docs/how-tos/command.ipynb new file mode 100644 index 000000000..3f3a4c0ef --- /dev/null +++ b/docs/docs/how-tos/command.ipynb @@ -0,0 +1,259 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "d33ecddc-6818-41a3-9d0d-b1b1cbcd286d", + "metadata": {}, + "source": [ + "# How to combine control flow and state updates with Command" + ] + }, + { + "cell_type": "markdown", + "id": "7c0a8d03-80b4-47fd-9b17-e26aa9b081f3", + "metadata": {}, + "source": [ + "!!! info \"Prerequisites\"\n", + " This guide assumes familiarity with the following:\n", + " \n", + " - [State](../../concepts/low_level/#state)\n", + " - [Nodes](../../concepts/low_level/#nodes)\n", + " - [Edges](../../concepts/low_level/#edges)\n", + " - [Command](../../concepts/low_level/#command)\n", + "\n", + "It can be useful to combine control flow (edges) and state updates (nodes). For example, you might want to BOTH perform state updates AND decide which node to go to next in the SAME node. LangGraph provides a way to do so by returning a `Command` object from node functions:\n", + "\n", + "```python\n", + "def my_node(state: State) -> Command[Literal[\"my_other_node\"]]:\n", + " return GraphCommand(\n", + " # state update\n", + " update={\"foo\": \"bar\"},\n", + " # control flow\n", + " goto=\"my_other_node\"\n", + " )\n", + "```\n", + "\n", + "This guide shows how you can do use `Command` to add dynamic control flow in your LangGraph app." + ] + }, + { + "cell_type": "markdown", + "id": "d1c3f866-8c20-40c7-a201-35f6c9f4b680", + "metadata": {}, + "source": [ + "## Setup\n", + "\n", + "First, let's install the required packages" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "6999c7fe-31bb-4c19-946a-85c2edc57da7", + "metadata": {}, + "outputs": [], + "source": [ + "%%capture --no-stderr\n", + "%pip install -U langgraph" + ] + }, + { + "cell_type": "markdown", + "id": "0f131c92-4744-431c-a89c-7c382a15b79f", + "metadata": {}, + "source": [ + "
\n", + "

Set up LangSmith for LangGraph development

\n", + "

\n", + " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started here. \n", + "

\n", + "
" + ] + }, + { + "cell_type": "markdown", + "id": "f22c228f-6882-4757-8e7e-1ca51328af4a", + "metadata": {}, + "source": [ + "Let's create a simple graph with 3 nodes: A, B and C. We will first execute node A, and then decide whether to go to Node B or Node C next based on the output of node A." + ] + }, + { + "cell_type": "markdown", + "id": "6a08d957-b3d2-4538-bf4a-68ef90a51b98", + "metadata": {}, + "source": [ + "## Define graph" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "4539b81b-09e9-4660-ac55-1b1775e13892", + "metadata": {}, + "outputs": [], + "source": [ + "import random\n", + "from typing_extensions import TypedDict, Literal\n", + "\n", + "from langgraph.graph import StateGraph, START\n", + "from langgraph.types import Command\n", + "\n", + "\n", + "# Define graph state\n", + "class State(TypedDict):\n", + " foo: str\n", + "\n", + "\n", + "# Define the nodes\n", + "\n", + "\n", + "def node_a(state: State) -> Command[Literal[\"node_b\", \"node_c\"]]:\n", + " print(\"Called A\")\n", + " value = random.choice([\"a\", \"b\"])\n", + " # this is a replacement for a conditional edge function\n", + " if value == \"a\":\n", + " goto = \"node_b\"\n", + " else:\n", + " goto = \"node_c\"\n", + "\n", + " # note how Command allows you to BOTH update the graph state AND route to the next node\n", + " return Command(\n", + " # this is the state update\n", + " update={\"foo\": value},\n", + " # this is a replacement for an edge\n", + " goto=goto,\n", + " )\n", + "\n", + "\n", + "# Nodes B and C are unchanged\n", + "\n", + "\n", + "def node_b(state: State):\n", + " print(\"Called B\")\n", + " return {\"foo\": state[\"foo\"] + \"b\"}\n", + "\n", + "\n", + "def node_c(state: State):\n", + " print(\"Called C\")\n", + " return {\"foo\": state[\"foo\"] + \"c\"}" + ] + }, + { + "cell_type": "markdown", + "id": "badc25eb-4876-482e-bb10-d763023cdaad", + "metadata": {}, + "source": [ + "We can now create the `StateGraph` with the above nodes. Notice that the graph doesn't have [conditional edges](../../concepts/low_level#conditional-edges) for routing! This is because control flow is defined with `GraphCommand` inside `node_a`." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "d6711650-4380-4551-a007-2805f49ab2d8", + "metadata": {}, + "outputs": [], + "source": [ + "builder = StateGraph(State)\n", + "builder.add_edge(START, \"node_a\")\n", + "builder.add_node(node_a)\n", + "builder.add_node(node_b)\n", + "builder.add_node(node_c)\n", + "# NOTE: there are no edges between nodes A, B and C!\n", + "\n", + "graph = builder.compile()" + ] + }, + { + "cell_type": "markdown", + "id": "0ab344c5-d634-4d7d-b3b4-edf4fa875311", + "metadata": {}, + "source": [ + "!!! important\n", + "\n", + " You might have noticed that we used `Command` as a return type annotation, e.g. `Command[Literal[\"node_b\", \"node_c\"]]`. This is necessary for the graph compilation and rendering, and tells LangGraph that `node_a` can navigate to `node_b` and `node_c`." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "eeb810e5-8822-4c09-8d53-c55cd0f5d42e", + "metadata": {}, + "outputs": [ + { + "data": { + "image/jpeg": "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", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from IPython.display import display, Image\n", + "\n", + "display(Image(graph.get_graph().draw_mermaid_png()))" + ] + }, + { + "cell_type": "markdown", + "id": "58fb6c32-e6fb-4c94-8182-e351ed52a45d", + "metadata": {}, + "source": [ + "If we run the graph multiple times, we'd see it take different paths (A -> B or A -> C) based on the random choice in node A." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "d88a5d9b-ee08-4ed4-9c65-6e868210bfac", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Called A\n", + "Called C\n" + ] + }, + { + "data": { + "text/plain": [ + "{'foo': 'bc'}" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "graph.invoke({\"foo\": \"\"})" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/docs/how-tos/index.md b/docs/docs/how-tos/index.md index e579902d9..8256a9adb 100644 --- a/docs/docs/how-tos/index.md +++ b/docs/docs/how-tos/index.md @@ -20,6 +20,7 @@ These how-to guides show how to achieve that controllability. - [How to create branches for parallel execution](branching.ipynb) - [How to create map-reduce branches for parallel execution](map-reduce.ipynb) - [How to control graph recursion limit](recursion-limit.ipynb) +- [How to combine control flow and state updates with Command](command.ipynb) ### Persistence @@ -39,7 +40,8 @@ LangGraph makes it easy to manage conversation [memory](../concepts/memory.md) i - [How to manage conversation history](memory/manage-conversation-history.ipynb) - [How to delete messages](memory/delete-messages.ipynb) - [How to add summary conversation memory](memory/add-summary-conversation-history.ipynb) -- [Add long-term memory (cross-thread)](cross-thread-persistence.ipynb) +- [How to add long-term memory (cross-thread)](cross-thread-persistence.ipynb) +- [How to use semantic search for long-term memory](memory/semantic-search.ipynb) ### Human-in-the-loop @@ -119,6 +121,7 @@ These guides show how to use the prebuilt ReAct agent: - [How to add a custom system prompt to a ReAct agent](create-react-agent-system-prompt.ipynb) - [How to add human-in-the-loop processes to a ReAct agent](create-react-agent-hitl.ipynb) - [How to create prebuilt ReAct agent from scratch](react-agent-from-scratch.ipynb) +- [How to add semantic search for long-term memory to a ReAct agent](memory/semantic-search.ipynb#using-in-create-react-agent) ## LangGraph Platform diff --git a/docs/docs/how-tos/memory/semantic-search.ipynb b/docs/docs/how-tos/memory/semantic-search.ipynb new file mode 100644 index 000000000..8e7a8d057 --- /dev/null +++ b/docs/docs/how-tos/memory/semantic-search.ipynb @@ -0,0 +1,532 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# How to add semantic search to your agent's memory\n", + "\n", + "This guide shows how to enable semantic search in your agent's memory store. This lets search for items in the store by semantic similarity.\n", + "\n", + "!!! tip Prerequisites\n", + " This guide assumes familiarity with the [memory in LangGraph](https://langchain-ai.github.io/langgraph/concepts/memory/).\n", + "\n", + "First, install this guide's prerequisites." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%capture --no-stderr\n", + "%pip install -U langgraph langchain-openai langchain" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import getpass\n", + "import os\n", + "\n", + "\n", + "def _set_env(var: str):\n", + " if not os.environ.get(var):\n", + " os.environ[var] = getpass.getpass(f\"{var}: \")\n", + "\n", + "\n", + "_set_env(\"OPENAI_API_KEY\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, create the store with an [index configuration](https://langchain-ai.github.io/langgraph/reference/store/#langgraph.store.base.IndexConfig). By default, stores are configured without semantic/vector search. You can opt in to indexing items when creating the store by providing an [IndexConfig](https://langchain-ai.github.io/langgraph/reference/store/#langgraph.store.base.IndexConfig) to the store's constructor. If your store class does not implement this interface, or if you do not pass in an index configuration, semantic search is disabled, and all `index` arguments passed to `put` or `aput` will have no effect. Below is an example." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/var/folders/gf/6rnp_mbx5914kx7qmmh7xzmw0000gn/T/ipykernel_83572/2318027494.py:5: LangChainBetaWarning: The function `init_embeddings` is in beta. It is actively being worked on, so the API may change.\n", + " embeddings = init_embeddings(\"openai:text-embedding-3-small\")\n" + ] + } + ], + "source": [ + "from langchain.embeddings import init_embeddings\n", + "from langgraph.store.memory import InMemoryStore\n", + "\n", + "# Create store with semantic search enabled\n", + "embeddings = init_embeddings(\"openai:text-embedding-3-small\")\n", + "store = InMemoryStore(\n", + " index={\n", + " \"embed\": embeddings,\n", + " \"dims\": 1536,\n", + " }\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now let's store some memories:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "# Store some memories\n", + "store.put((\"user_123\", \"memories\"), \"1\", {\"text\": \"I love pizza\"})\n", + "store.put((\"user_123\", \"memories\"), \"2\", {\"text\": \"I prefer Italian food\"})\n", + "store.put((\"user_123\", \"memories\"), \"3\", {\"text\": \"I don't like spicy food\"})\n", + "store.put((\"user_123\", \"memories\"), \"3\", {\"text\": \"I am studying econometrics\"})\n", + "store.put((\"user_123\", \"memories\"), \"3\", {\"text\": \"I am a plumber\"})" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Search memories using natural language:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Memory: I prefer Italian food (similarity: 0.46482669521168163)\n", + "Memory: I love pizza (similarity: 0.35514845174380766)\n", + "Memory: I am a plumber (similarity: 0.155698702336571)\n" + ] + } + ], + "source": [ + "# Find memories about food preferences\n", + "memories = store.search((\"user_123\", \"memories\"), query=\"I like food?\", limit=5)\n", + "\n", + "for memory in memories:\n", + " print(f'Memory: {memory.value[\"text\"]} (similarity: {memory.score})')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Using in your agent\n", + "\n", + "Add semantic search to any node by injecting the store." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "What are you in the mood for? Since you love Italian food and pizza, would you like to order a pizza or try making one at home?" + ] + } + ], + "source": [ + "from typing import Optional\n", + "\n", + "from langchain.chat_models import init_chat_model\n", + "from langgraph.store.base import BaseStore\n", + "\n", + "from langgraph.graph import START, MessagesState, StateGraph\n", + "\n", + "llm = init_chat_model(\"openai:gpt-4o-mini\")\n", + "\n", + "\n", + "def chat(state, *, store: BaseStore):\n", + " # Search based on user's last message\n", + " items = store.search(\n", + " (\"user_123\", \"memories\"), query=state[\"messages\"][-1].content, limit=2\n", + " )\n", + " memories = \"\\n\".join(item.value[\"text\"] for item in items)\n", + " memories = f\"## Memories of user\\n{memories}\" if memories else \"\"\n", + " response = llm.invoke(\n", + " [\n", + " {\"role\": \"system\", \"content\": f\"You are a helpful assistant.\\n{memories}\"},\n", + " *state[\"messages\"],\n", + " ]\n", + " )\n", + " return {\"messages\": [response]}\n", + "\n", + "\n", + "builder = StateGraph(MessagesState)\n", + "builder.add_node(chat)\n", + "builder.add_edge(START, \"chat\")\n", + "graph = builder.compile(store=store)\n", + "\n", + "for message, metadata in graph.stream(\n", + " input={\"messages\": [{\"role\": \"user\", \"content\": \"I'm hungry\"}]},\n", + " stream_mode=\"messages\",\n", + "):\n", + " print(message.content, end=\"\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Using in `create_react_agent`\n", + "\n", + "Add semantic search to your tool calling agent by injecting the store in the `state_modifier`. You can also use the store in a tool to let your agent manually store or search for memories." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "import uuid\n", + "from typing import Optional\n", + "\n", + "from langchain.chat_models import init_chat_model\n", + "from langchain_core.tools import InjectedToolArg\n", + "from langgraph.store.base import BaseStore\n", + "from typing_extensions import Annotated\n", + "\n", + "from langgraph.prebuilt import create_react_agent\n", + "\n", + "\n", + "def prepare_messages(state, *, store: BaseStore):\n", + " # Search based on user's last message\n", + " items = store.search(\n", + " (\"user_123\", \"memories\"), query=state[\"messages\"][-1].content, limit=2\n", + " )\n", + " memories = \"\\n\".join(item.value[\"text\"] for item in items)\n", + " memories = f\"## Memories of user\\n{memories}\" if memories else \"\"\n", + " return [\n", + " {\"role\": \"system\", \"content\": f\"You are a helpful assistant.\\n{memories}\"}\n", + " ] + state[\"messages\"]\n", + "\n", + "\n", + "# You can also use the store directly within a tool!\n", + "def upsert_memory(\n", + " content: str,\n", + " *,\n", + " memory_id: Optional[uuid.UUID] = None,\n", + " store: Annotated[BaseStore, InjectedToolArg],\n", + "):\n", + " \"\"\"Upsert a memory in the database.\"\"\"\n", + " # The LLM can use this tool to store a new memory\n", + " mem_id = memory_id or uuid.uuid4()\n", + " store.put(\n", + " (\"user_123\", \"memories\"),\n", + " key=str(mem_id),\n", + " value={\"text\": content},\n", + " )\n", + " return f\"Stored memory {mem_id}\"\n", + "\n", + "\n", + "agent = create_react_agent(\n", + " init_chat_model(\"openai:gpt-4o-mini\"),\n", + " tools=[upsert_memory],\n", + " # The state_modifier is run to prepare the messages for the LLM. It is called\n", + " # right before each LLM call\n", + " state_modifier=prepare_messages,\n", + " store=store,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "What are you in the mood for? Since you love Italian food and pizza, maybe something in that realm would be great! Would you like suggestions for a specific dish or restaurant?" + ] + } + ], + "source": [ + "for message, metadata in agent.stream(\n", + " input={\"messages\": [{\"role\": \"user\", \"content\": \"I'm hungry\"}]},\n", + " stream_mode=\"messages\",\n", + "):\n", + " print(message.content, end=\"\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Advanced Usage\n", + "\n", + "#### Multi-vector indexing\n", + "\n", + "Store and search different aspects of memories separately to improve recall or omit certain fields from being indexed." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Expect mem 2\n", + "Item: mem2; Score (0.5895009051396596)\n", + "Memory: Ate alone at home\n", + "Emotion: felt a bit lonely\n", + "\n", + "Expect mem1\n", + "Item: mem1; Score (0.6207546534134083)\n", + "Memory: Had pizza with friends at Mario's\n", + "Emotion: felt happy and connected\n", + "\n", + "Expect random lower score (ravioli not indexed)\n", + "Item: mem1; Score (0.2686278787315685)\n", + "Memory: Had pizza with friends at Mario's\n", + "Emotion: felt happy and connected\n", + "\n" + ] + } + ], + "source": [ + "# Configure store to embed both memory content and emotional context\n", + "store = InMemoryStore(\n", + " index={\"embed\": embeddings, \"dims\": 1536, \"fields\": [\"memory\", \"emotional_context\"]}\n", + ")\n", + "# Store memories with different content/emotion pairs\n", + "store.put(\n", + " (\"user_123\", \"memories\"),\n", + " \"mem1\",\n", + " {\n", + " \"memory\": \"Had pizza with friends at Mario's\",\n", + " \"emotional_context\": \"felt happy and connected\",\n", + " \"this_isnt_indexed\": \"I prefer ravioli though\",\n", + " },\n", + ")\n", + "store.put(\n", + " (\"user_123\", \"memories\"),\n", + " \"mem2\",\n", + " {\n", + " \"memory\": \"Ate alone at home\",\n", + " \"emotional_context\": \"felt a bit lonely\",\n", + " \"this_isnt_indexed\": \"I like pie\",\n", + " },\n", + ")\n", + "\n", + "# Search focusing on emotional state - matches mem2\n", + "results = store.search(\n", + " (\"user_123\", \"memories\"), query=\"times they felt isolated\", limit=1\n", + ")\n", + "print(\"Expect mem 2\")\n", + "for r in results:\n", + " print(f\"Item: {r.key}; Score ({r.score})\")\n", + " print(f\"Memory: {r.value['memory']}\")\n", + " print(f\"Emotion: {r.value['emotional_context']}\\n\")\n", + "\n", + "# Search focusing on social eating - matches mem1\n", + "print(\"Expect mem1\")\n", + "results = store.search((\"user_123\", \"memories\"), query=\"fun pizza\", limit=1)\n", + "for r in results:\n", + " print(f\"Item: {r.key}; Score ({r.score})\")\n", + " print(f\"Memory: {r.value['memory']}\")\n", + " print(f\"Emotion: {r.value['emotional_context']}\\n\")\n", + "\n", + "print(\"Expect random lower score (ravioli not indexed)\")\n", + "results = store.search((\"user_123\", \"memories\"), query=\"ravioli\", limit=1)\n", + "for r in results:\n", + " print(f\"Item: {r.key}; Score ({r.score})\")\n", + " print(f\"Memory: {r.value['memory']}\")\n", + " print(f\"Emotion: {r.value['emotional_context']}\\n\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Override fields at storage time\n", + "You can override which fields to embed when storing a specific memory using `put(..., index=[...fields])`, regardless of the store's default configuration." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Expect mem1\n", + "Item: mem1; Score (0.3374968677940555)\n", + "Memory: I love spicy food\n", + "Context: At a Thai restaurant\n", + "\n", + "Expect mem2\n", + "Item: mem2; Score (0.36784461593247436)\n", + "Memory: The restaurant was too loud\n", + "Context: Dinner at an Italian place\n", + "\n" + ] + } + ], + "source": [ + "store = InMemoryStore(\n", + " index={\n", + " \"embed\": embeddings,\n", + " \"dims\": 1536,\n", + " \"fields\": [\"memory\"],\n", + " } # Default to embed memory field\n", + ")\n", + "\n", + "# Store one memory with default indexing\n", + "store.put(\n", + " (\"user_123\", \"memories\"),\n", + " \"mem1\",\n", + " {\"memory\": \"I love spicy food\", \"context\": \"At a Thai restaurant\"},\n", + ")\n", + "\n", + "# Store another overriding which fields to embed\n", + "store.put(\n", + " (\"user_123\", \"memories\"),\n", + " \"mem2\",\n", + " {\"memory\": \"The restaurant was too loud\", \"context\": \"Dinner at an Italian place\"},\n", + " index=[\"context\"], # Override: only embed the context\n", + ")\n", + "\n", + "# Search about food - matches mem1 (using default field)\n", + "print(\"Expect mem1\")\n", + "results = store.search(\n", + " (\"user_123\", \"memories\"), query=\"what food do they like\", limit=1\n", + ")\n", + "for r in results:\n", + " print(f\"Item: {r.key}; Score ({r.score})\")\n", + " print(f\"Memory: {r.value['memory']}\")\n", + " print(f\"Context: {r.value['context']}\\n\")\n", + "\n", + "# Search about restaurant atmosphere - matches mem2 (using overridden field)\n", + "print(\"Expect mem2\")\n", + "results = store.search(\n", + " (\"user_123\", \"memories\"), query=\"restaurant environment\", limit=1\n", + ")\n", + "for r in results:\n", + " print(f\"Item: {r.key}; Score ({r.score})\")\n", + " print(f\"Memory: {r.value['memory']}\")\n", + " print(f\"Context: {r.value['context']}\\n\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Disable Indexing for Specific Memories\n", + "\n", + "Some memories shouldn't be searchable by content. You can disable indexing for these while still storing them using \n", + "`put(..., index=False)`. Example:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Expect mem1\n", + "Item: mem1; Score (0.32269984224327286)\n", + "Memory: I love chocolate ice cream\n", + "Type: preference\n", + "\n", + "Expect low score (mem2 not indexed)\n", + "Item: mem1; Score (0.010241633698527089)\n", + "Memory: I love chocolate ice cream\n", + "Type: preference\n", + "\n" + ] + } + ], + "source": [ + "store = InMemoryStore(index={\"embed\": embeddings, \"dims\": 1536, \"fields\": [\"memory\"]})\n", + "\n", + "# Store a normal indexed memory\n", + "store.put(\n", + " (\"user_123\", \"memories\"),\n", + " \"mem1\",\n", + " {\"memory\": \"I love chocolate ice cream\", \"type\": \"preference\"},\n", + ")\n", + "\n", + "# Store a system memory without indexing\n", + "store.put(\n", + " (\"user_123\", \"memories\"),\n", + " \"mem2\",\n", + " {\"memory\": \"User completed onboarding\", \"type\": \"system\"},\n", + " index=False, # Disable indexing entirely\n", + ")\n", + "\n", + "# Search about food preferences - finds mem1\n", + "print(\"Expect mem1\")\n", + "results = store.search((\"user_123\", \"memories\"), query=\"what food preferences\", limit=1)\n", + "for r in results:\n", + " print(f\"Item: {r.key}; Score ({r.score})\")\n", + " print(f\"Memory: {r.value['memory']}\")\n", + " print(f\"Type: {r.value['type']}\\n\")\n", + "\n", + "# Search about onboarding - won't find mem2 (not indexed)\n", + "print(\"Expect low score (mem2 not indexed)\")\n", + "results = store.search((\"user_123\", \"memories\"), query=\"onboarding status\", limit=1)\n", + "for r in results:\n", + " print(f\"Item: {r.key}; Score ({r.score})\")\n", + " print(f\"Memory: {r.value['memory']}\")\n", + " print(f\"Type: {r.value['type']}\\n\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.2" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/docs/docs/reference/types.md b/docs/docs/reference/types.md index 06a6ac2a5..b42b11f35 100644 --- a/docs/docs/reference/types.md +++ b/docs/docs/reference/types.md @@ -13,4 +13,5 @@ - PregelExecutableTask - StateSnapshot - Send + - Command - interrupt diff --git a/docs/docs/tutorials/index.md b/docs/docs/tutorials/index.md index d9593c9b8..286137479 100644 --- a/docs/docs/tutorials/index.md +++ b/docs/docs/tutorials/index.md @@ -13,6 +13,7 @@ New to LangGraph or LLM app development? Read this material to get up and runnin - [LangGraph Quickstart](introduction.ipynb): Build a chatbot that can use tools and keep track of conversation history. Add human-in-the-loop capabilities and explore how time-travel works. - [LangGraph Server Quickstart](langgraph-platform/local-server.md): Launch a LangGraph server locally and interact with it using the REST API and LangGraph Studio Web UI. - [LangGraph Cloud QuickStart](../cloud/quick_start.md): Deploy a LangGraph app using LangGraph Cloud. +- [LangGraph Template Quickstart](../concepts/template_applications.md): Quickly start building with LangGraph Platform using a template application. ## Use cases 🛠️ diff --git a/docs/docs/tutorials/langgraph-platform/local-server.md b/docs/docs/tutorials/langgraph-platform/local-server.md index db7f53fea..0b57db2bd 100644 --- a/docs/docs/tutorials/langgraph-platform/local-server.md +++ b/docs/docs/tutorials/langgraph-platform/local-server.md @@ -250,4 +250,4 @@ Access detailed documentation for development and API usage: - **[LangGraph Server API Reference](../../cloud/reference/api/api_ref.html)**: Explore the LangGraph Server API documentation. - **[Python SDK Reference](../../cloud/reference/sdk/python_sdk_ref.md)**: Explore the Python SDK API Reference. -- **[JS/TS SDK Reference](../../cloud/reference/sdk/js_ts_sdk_ref.md)**: Explore the Python SDK API Reference. \ No newline at end of file +- **[JS/TS SDK Reference](../../cloud/reference/sdk/js_ts_sdk_ref.md)**: Explore the Python SDK API Reference. diff --git a/docs/docs/tutorials/tnt-llm/tnt-llm.ipynb b/docs/docs/tutorials/tnt-llm/tnt-llm.ipynb index c68fb81e1..d952ab592 100644 --- a/docs/docs/tutorials/tnt-llm/tnt-llm.ipynb +++ b/docs/docs/tutorials/tnt-llm/tnt-llm.ipynb @@ -43,7 +43,7 @@ "outputs": [], "source": [ "%%capture --no-stderr\n", - "%pip install -U langgraph langchain_anthropic langsmith\n", + "%pip install -U langgraph langchain_anthropic langsmith langchain-community\n", "%pip install -U sklearn langchain_openai" ] }, @@ -632,7 +632,7 @@ "metadata": {}, "outputs": [], "source": [ - "from langchain.cache import InMemoryCache\n", + "from langchain_community.cache import InMemoryCache\n", "from langchain.globals import set_llm_cache\n", "\n", "# Optional. If you are running into errors or rate limits and want to avoid repeated computation,\n", diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 3167d5520..bc1ff59ea 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -151,6 +151,7 @@ nav: - how-tos/branching.ipynb - how-tos/map-reduce.ipynb - how-tos/recursion-limit.ipynb + - how-tos/command.ipynb - Persistence: - Persistence: how-tos#persistence - how-tos/persistence.ipynb @@ -164,6 +165,7 @@ nav: - how-tos/memory/manage-conversation-history.ipynb - how-tos/memory/delete-messages.ipynb - how-tos/memory/add-summary-conversation-history.ipynb + - how-tos/memory/semantic-search.ipynb - Human-in-the-loop: - Human-in-the-loop: how-tos#human-in-the-loop - how-tos/human_in_the_loop/breakpoints.ipynb @@ -225,6 +227,7 @@ nav: - cloud/deployment/setup.md - cloud/deployment/setup_pyproject.md - cloud/deployment/setup_javascript.md + - cloud/deployment/semantic_search.md - cloud/deployment/custom_docker.md - cloud/deployment/test_locally.md - cloud/deployment/graph_rebuild.md diff --git a/libs/checkpoint-postgres/langgraph/store/postgres/aio.py b/libs/checkpoint-postgres/langgraph/store/postgres/aio.py index 9be44ded6..4a516557a 100644 --- a/libs/checkpoint-postgres/langgraph/store/postgres/aio.py +++ b/libs/checkpoint-postgres/langgraph/store/postgres/aio.py @@ -72,6 +72,8 @@ class AsyncPostgresStore(AsyncBatchedBaseStore, BasePostgresStore[_ainternal.Con # Store documents await store.aput(("docs",), "doc1", {"text": "Python tutorial"}) await store.aput(("docs",), "doc2", {"text": "TypeScript guide"}) + # Don't index the following + await store.aput(("docs",), "doc3", {"text": "Other guide"}, index=False) # Search by similarity results = await store.asearch(("docs",), query="python programming") @@ -97,6 +99,11 @@ class AsyncPostgresStore(AsyncBatchedBaseStore, BasePostgresStore[_ainternal.Con 1. Call `setup()` before first use to create necessary tables and indexes 2. Have the pgvector extension available to use vector search 3. Use Python 3.10+ for async functionality + + Note: + Semantic search is disabled by default. You can enable it by providing an `index` configuration + when creating the store. Without this configuration, all `index` arguments passed to + `put` or `aput`will have no effect. """ __slots__ = ( diff --git a/libs/checkpoint-postgres/langgraph/store/postgres/base.py b/libs/checkpoint-postgres/langgraph/store/postgres/base.py index e12a59667..839b2429e 100644 --- a/libs/checkpoint-postgres/langgraph/store/postgres/base.py +++ b/libs/checkpoint-postgres/langgraph/store/postgres/base.py @@ -569,10 +569,15 @@ class PostgresStore(BaseStore, BasePostgresStore[_pg_internal.Conn]): # Store documents store.put(("docs",), "doc1", {"text": "Python tutorial"}) store.put(("docs",), "doc2", {"text": "TypeScript guide"}) + store.put(("docs",), "doc2", {"text": "Other guide"}, index=False) # don't index # Search by similarity results = store.search(("docs",), query="python programming") - ``` + + Note: + Semantic search is disabled by default. You can enable it by providing an `index` configuration + when creating the store. Without this configuration, all `index` arguments passed to + `put` or `aput`will have no effect. Warning: Make sure to call `setup()` before first use to create necessary tables and indexes. diff --git a/libs/checkpoint/langgraph/store/base/__init__.py b/libs/checkpoint/langgraph/store/base/__init__.py index 3f36b7f16..b2ab49527 100644 --- a/libs/checkpoint/langgraph/store/base/__init__.py +++ b/libs/checkpoint/langgraph/store/base/__init__.py @@ -471,7 +471,11 @@ class InvalidNamespaceError(ValueError): class IndexConfig(TypedDict, total=False): - """Configuration for indexing documents for semantic search in the store.""" + """Configuration for indexing documents for semantic search in the store. + + If not provided to the store, the store will not support vector search. + In that case, all `index` arguments to put() and `aput()` operations will be ignored. + """ dims: int """Number of dimensions in the embedding vectors. @@ -557,10 +561,15 @@ class IndexConfig(TypedDict, total=False): """Fields to extract text from for embedding generation. Controls which parts of stored items are embedded for semantic search. Follows JSON path syntax: - - ["$"] (default): Embeds the entire JSON object as one vector - - ["field1", "field2"]: Embeds specific top-level fields - - ["parent.child"]: Embeds nested fields using dot notation - - ["array[*].field"]: Embeds field from each array element separately + + - ["$"]: Embeds the entire JSON object as one vector (default) + - ["field1", "field2"]: Embeds specific top-level fields + - ["parent.child"]: Embeds nested fields using dot notation + - ["array[*].field"]: Embeds field from each array element separately + + Note: + You can always override this behavior when storing an item using the + `index` parameter in the `put` or `aput` operations. ???+ example "Examples" ```python @@ -590,6 +599,15 @@ class BaseStore(ABC): Stores enable persistence and memory that can be shared across threads, scoped to user IDs, assistant IDs, or other arbitrary namespaces. + Some implementations may support semantic search capabilities through + an optional `index` configuration. + + Note: + Semantic search capabilities vary by implementation and are typically + disabled by default. Stores that support this feature can be configured + by providing an `index` configuration at creation time. Without this + configuration, semantic search is disabled and any `index` arguments + to storage operations will have no effect. """ __slots__ = ("__weakref__",) @@ -706,6 +724,8 @@ class BaseStore(ABC): index: Controls how the item's fields are indexed for search: - None (default): Use `fields` you configured when creating the store (if any) + If you do not initialize the store with indexing capabilities, + the `index` parameter will be ignored - False: Disable indexing for this item - list[str]: List of field paths to index, supporting: - Nested fields: "metadata.title" @@ -713,8 +733,9 @@ class BaseStore(ABC): - Specific indices: "authors[0].name" Note: - Indexing capabilities depend on your store implementation. - Some implementations may support only a subset of indexing features. + Indexing support depends on your store implementation. + If you do not initialize the store with indexing capabilities, + the `index` parameter will be ignored. ???+ example "Examples" Store item. Indexing depends on how you configure the store. @@ -890,6 +911,8 @@ class BaseStore(ABC): index: Controls how the item's fields are indexed for search: - None (default): Use `fields` you configured when creating the store (if any) + If you do not initialize the store with indexing capabilities, + the `index` parameter will be ignored - False: Disable indexing for this item - list[str]: List of field paths to index, supporting: - Nested fields: "metadata.title" @@ -897,8 +920,9 @@ class BaseStore(ABC): - Specific indices: "authors[0].name" Note: - Indexing capabilities depend on your store implementation. - Some implementations may support only a subset of indexing features. + Indexing support depends on your store implementation. + If you do not initialize the store with indexing capabilities, + the `index` parameter will be ignored. ???+ example "Examples" Store item. Indexing depends on how you configure the store. diff --git a/libs/checkpoint/langgraph/store/memory/__init__.py b/libs/checkpoint/langgraph/store/memory/__init__.py index d2786db48..ff2d53592 100644 --- a/libs/checkpoint/langgraph/store/memory/__init__.py +++ b/libs/checkpoint/langgraph/store/memory/__init__.py @@ -154,6 +154,11 @@ class InMemoryStore(BaseStore): # Search by similarity results = store.search(("docs",), query="python programming") + Note: + Semantic search is disabled by default. You can enable it by providing an `index` configuration + when creating the store. Without this configuration, all `index` arguments passed to + `put` or `aput`will have no effect. + Warning: This store keeps all data in memory. Data is lost when the process exits. For persistence, use a database-backed store like PostgresStore. diff --git a/libs/langgraph/Makefile b/libs/langgraph/Makefile index 43d0c7afe..8974fcd32 100644 --- a/libs/langgraph/Makefile +++ b/libs/langgraph/Makefile @@ -48,6 +48,12 @@ test: make stop-postgres; \ exit $$EXIT_CODE +test_parallel: + make start-postgres && poetry run pytest -n auto --dist worksteal $(TEST); \ + EXIT_CODE=$$?; \ + make stop-postgres; \ + exit $$EXIT_CODE + WORKERS ?= auto XDIST_ARGS := $(if $(WORKERS),-n $(WORKERS) --dist worksteal,) MAXFAIL ?= diff --git a/libs/langgraph/langgraph/constants.py b/libs/langgraph/langgraph/constants.py index 478f23d68..e2d9f069a 100644 --- a/libs/langgraph/langgraph/constants.py +++ b/libs/langgraph/langgraph/constants.py @@ -72,9 +72,11 @@ CONFIG_KEY_CHECKPOINT_ID = sys.intern("checkpoint_id") CONFIG_KEY_CHECKPOINT_NS = sys.intern("checkpoint_ns") # holds the current checkpoint_ns, "" for root graph CONFIG_KEY_NODE_FINISHED = sys.intern("__pregel_node_finished") -# callback to be called when a node is finished -CONFIG_KEY_RESUME_VALUE = sys.intern("__pregel_resume_value") # holds the value that "answers" an interrupt() call +CONFIG_KEY_WRITES = sys.intern("__pregel_writes") +# read-only list of existing task writes +CONFIG_KEY_SCRATCHPAD = sys.intern("__pregel_scratchpad") +# holds a mutable dict for temporary storage scoped to the current task # --- Other constants --- PUSH = sys.intern("__pregel_push") diff --git a/libs/langgraph/langgraph/graph/__init__.py b/libs/langgraph/langgraph/graph/__init__.py index 241106a3a..c81ad9903 100644 --- a/libs/langgraph/langgraph/graph/__init__.py +++ b/libs/langgraph/langgraph/graph/__init__.py @@ -1,13 +1,12 @@ from langgraph.graph.graph import END, START, Graph from langgraph.graph.message import MessageGraph, MessagesState, add_messages -from langgraph.graph.state import GraphCommand, StateGraph +from langgraph.graph.state import StateGraph __all__ = [ "END", "START", "Graph", "StateGraph", - "GraphCommand", "MessageGraph", "add_messages", "MessagesState", diff --git a/libs/langgraph/langgraph/graph/state.py b/libs/langgraph/langgraph/graph/state.py index 1a7208a2a..e63f25111 100644 --- a/libs/langgraph/langgraph/graph/state.py +++ b/libs/langgraph/langgraph/graph/state.py @@ -1,4 +1,3 @@ -import dataclasses import inspect import logging import typing @@ -9,7 +8,6 @@ from types import FunctionType from typing import ( Any, Callable, - Generic, Literal, NamedTuple, Optional, @@ -55,7 +53,7 @@ from langgraph.managed.base import ( from langgraph.pregel.read import ChannelRead, PregelNode from langgraph.pregel.write import SKIP_WRITE, ChannelWrite, ChannelWriteEntry from langgraph.store.base import BaseStore -from langgraph.types import _DC_KWARGS, All, Checkpointer, Command, N, RetryPolicy +from langgraph.types import All, Checkpointer, Command, RetryPolicy from langgraph.utils.fields import get_field_default from langgraph.utils.pydantic import create_model from langgraph.utils.runnable import RunnableCallable, coerce_to_runnable @@ -84,22 +82,6 @@ def _get_node_name(node: RunnableLike) -> str: raise TypeError(f"Unsupported node type: {type(node)}") -@dataclasses.dataclass(**_DC_KWARGS) -class GraphCommand(Generic[N], Command[N]): - """One or more commands to update a StateGraph's state and go to, or send messages to nodes.""" - - goto: Union[str, Sequence[str]] = () - - def __repr__(self) -> str: - # get all non-None values - contents = ", ".join( - f"{key}={value!r}" - for key, value in dataclasses.asdict(self).items() - if value - ) - return f"Command({contents})" - - class StateNodeSpec(NamedTuple): runnable: Runnable metadata: Optional[dict[str, Any]] @@ -392,7 +374,7 @@ class StateGraph(Graph): input = input_hint if ( (rtn := hints.get("return")) - and get_origin(rtn) in (Command, GraphCommand) + and get_origin(rtn) is Command and (rargs := get_args(rtn)) and get_origin(rargs[0]) is Literal and (vals := get_args(rargs[0])) @@ -834,15 +816,12 @@ def _control_branch(value: Any) -> Sequence[Union[str, Send]]: if value.graph == Command.PARENT: raise ParentCommand(value) rtn: list[Union[str, Send]] = [] - if isinstance(value, GraphCommand): - if isinstance(value.goto, str): - rtn.append(value.goto) - else: - rtn.extend(value.goto) - if isinstance(value.send, Send): - rtn.append(value.send) + if isinstance(value.goto, Send): + rtn.append(value.goto) + elif isinstance(value.goto, str): + rtn.append(value.goto) else: - rtn.extend(value.send) + rtn.extend(value.goto) return rtn @@ -854,15 +833,12 @@ async def _acontrol_branch(value: Any) -> Sequence[Union[str, Send]]: if value.graph == Command.PARENT: raise ParentCommand(value) rtn: list[Union[str, Send]] = [] - if isinstance(value, GraphCommand): - if isinstance(value.goto, str): - rtn.append(value.goto) - else: - rtn.extend(value.goto) - if isinstance(value.send, Send): - rtn.append(value.send) + if isinstance(value.goto, Send): + rtn.append(value.goto) + elif isinstance(value.goto, str): + rtn.append(value.goto) else: - rtn.extend(value.send) + rtn.extend(value.goto) return rtn diff --git a/libs/langgraph/langgraph/prebuilt/tool_node.py b/libs/langgraph/langgraph/prebuilt/tool_node.py index 1ea0dd56c..38c349edb 100644 --- a/libs/langgraph/langgraph/prebuilt/tool_node.py +++ b/libs/langgraph/langgraph/prebuilt/tool_node.py @@ -1,15 +1,10 @@ -from __future__ import annotations - import asyncio import inspect import json from copy import copy from typing import ( - TYPE_CHECKING, Any, Callable, - Dict, - List, Literal, Optional, Sequence, @@ -35,22 +30,20 @@ from langchain_core.runnables.utils import Input from langchain_core.tools import BaseTool, InjectedToolArg from langchain_core.tools import tool as create_tool from langchain_core.tools.base import get_all_basemodel_annotations +from pydantic import BaseModel from typing_extensions import Annotated, get_args, get_origin from langgraph.errors import GraphBubbleUp from langgraph.store.base import BaseStore from langgraph.utils.runnable import RunnableCallable -if TYPE_CHECKING: - from pydantic import BaseModel - INVALID_TOOL_NAME_ERROR_TEMPLATE = ( "Error: {requested_tool} is not a valid tool, try one of [{available_tools}]." ) TOOL_CALL_ERROR_TEMPLATE = "Error: {error}\n Please fix your mistakes." -def msg_content_output(output: Any) -> str | List[dict]: +def msg_content_output(output: Any) -> Union[str, list[dict]]: recognized_content_block_types = ("image", "image_url", "text", "json") if isinstance(output, str): return output @@ -95,7 +88,7 @@ def _handle_tool_error( return content -def _infer_handled_types(handler: Callable[..., str]) -> tuple[type[Exception]]: +def _infer_handled_types(handler: Callable[..., str]) -> tuple[type[Exception], ...]: sig = inspect.signature(handler) params = list(sig.parameters.values()) if params: @@ -194,9 +187,9 @@ class ToolNode(RunnableCallable): messages_key: str = "messages", ) -> None: super().__init__(self._func, self._afunc, name=name, tags=tags, trace=False) - self.tools_by_name: Dict[str, BaseTool] = {} - self.tool_to_state_args: Dict[str, Dict[str, Optional[str]]] = {} - self.tool_to_store_arg: Dict[str, Optional[str]] = {} + self.tools_by_name: dict[str, BaseTool] = {} + self.tool_to_state_args: dict[str, dict[str, Optional[str]]] = {} + self.tool_to_store_arg: dict[str, Optional[str]] = {} self.handle_tool_errors = handle_tool_errors self.messages_key = messages_key for tool_ in tools: @@ -346,7 +339,7 @@ class ToolNode(RunnableCallable): BaseModel, ], store: BaseStore, - ) -> Tuple[List[ToolCall], Literal["list", "dict"]]: + ) -> Tuple[list[ToolCall], Literal["list", "dict"]]: if isinstance(input, list): output_type = "list" message: AnyMessage = input[-1] @@ -656,9 +649,9 @@ def _is_injection( return False -def _get_state_args(tool: BaseTool) -> Dict[str, Optional[str]]: +def _get_state_args(tool: BaseTool) -> dict[str, Optional[str]]: full_schema = tool.get_input_schema() - tool_args_to_state_fields: Dict = {} + tool_args_to_state_fields: dict = {} for name, type_ in get_all_basemodel_annotations(full_schema).items(): injections = [ diff --git a/libs/langgraph/langgraph/pregel/__init__.py b/libs/langgraph/langgraph/pregel/__init__.py index 62506142d..e714afe21 100644 --- a/libs/langgraph/langgraph/pregel/__init__.py +++ b/libs/langgraph/langgraph/pregel/__init__.py @@ -673,7 +673,7 @@ class Pregel(PregelProtocol): self, config: RunnableConfig, *, subgraphs: bool = False ) -> StateSnapshot: """Get the current state of the graph.""" - checkpointer: Optional[BaseCheckpointSaver] = config[CONF].get( + checkpointer: Optional[BaseCheckpointSaver] = ensure_config(config)[CONF].get( CONFIG_KEY_CHECKPOINTER, self.checkpointer ) if not checkpointer: @@ -710,7 +710,7 @@ class Pregel(PregelProtocol): self, config: RunnableConfig, *, subgraphs: bool = False ) -> StateSnapshot: """Get the current state of the graph.""" - checkpointer: Optional[BaseCheckpointSaver] = config[CONF].get( + checkpointer: Optional[BaseCheckpointSaver] = ensure_config(config)[CONF].get( CONFIG_KEY_CHECKPOINTER, self.checkpointer ) if not checkpointer: @@ -751,8 +751,9 @@ class Pregel(PregelProtocol): before: Optional[RunnableConfig] = None, limit: Optional[int] = None, ) -> Iterator[StateSnapshot]: + config = ensure_config(config) """Get the history of the state of the graph.""" - checkpointer: Optional[BaseCheckpointSaver] = config[CONF].get( + checkpointer: Optional[BaseCheckpointSaver] = ensure_config(config)[CONF].get( CONFIG_KEY_CHECKPOINTER, self.checkpointer ) if not checkpointer: @@ -800,8 +801,9 @@ class Pregel(PregelProtocol): before: Optional[RunnableConfig] = None, limit: Optional[int] = None, ) -> AsyncIterator[StateSnapshot]: + config = ensure_config(config) """Get the history of the state of the graph.""" - checkpointer: Optional[BaseCheckpointSaver] = config[CONF].get( + checkpointer: Optional[BaseCheckpointSaver] = ensure_config(config)[CONF].get( CONFIG_KEY_CHECKPOINTER, self.checkpointer ) if not checkpointer: @@ -855,7 +857,7 @@ class Pregel(PregelProtocol): node `as_node`. If `as_node` is not provided, it will be set to the last node that updated the state, if not ambiguous. """ - checkpointer: Optional[BaseCheckpointSaver] = config[CONF].get( + checkpointer: Optional[BaseCheckpointSaver] = ensure_config(config)[CONF].get( CONFIG_KEY_CHECKPOINTER, self.checkpointer ) if not checkpointer: @@ -1130,7 +1132,7 @@ class Pregel(PregelProtocol): values: dict[str, Any] | Any, as_node: Optional[str] = None, ) -> RunnableConfig: - checkpointer: Optional[BaseCheckpointSaver] = config[CONF].get( + checkpointer: Optional[BaseCheckpointSaver] = ensure_config(config)[CONF].get( CONFIG_KEY_CHECKPOINTER, self.checkpointer ) if not checkpointer: diff --git a/libs/langgraph/langgraph/pregel/algo.py b/libs/langgraph/langgraph/pregel/algo.py index 5d104a85f..0885f12aa 100644 --- a/libs/langgraph/langgraph/pregel/algo.py +++ b/libs/langgraph/langgraph/pregel/algo.py @@ -37,13 +37,13 @@ from langgraph.constants import ( CONFIG_KEY_CHECKPOINT_NS, CONFIG_KEY_CHECKPOINTER, CONFIG_KEY_READ, - CONFIG_KEY_RESUME_VALUE, + CONFIG_KEY_SCRATCHPAD, CONFIG_KEY_SEND, CONFIG_KEY_STORE, CONFIG_KEY_TASK_ID, + CONFIG_KEY_WRITES, EMPTY_SEQ, INTERRUPT, - MISSING, NO_WRITES, NS_END, NS_SEP, @@ -589,14 +589,13 @@ def prepare_single_task( }, CONFIG_KEY_CHECKPOINT_ID: None, CONFIG_KEY_CHECKPOINT_NS: task_checkpoint_ns, - CONFIG_KEY_RESUME_VALUE: next( - ( - v - for tid, c, v in pending_writes - if tid in (NULL_TASK_ID, task_id) and c == RESUME - ), - configurable.get(CONFIG_KEY_RESUME_VALUE, MISSING), - ), + CONFIG_KEY_WRITES: [ + w + for w in pending_writes + + configurable.get(CONFIG_KEY_WRITES, []) + if w[0] in (NULL_TASK_ID, task_id) + ], + CONFIG_KEY_SCRATCHPAD: {}, }, ), triggers, @@ -713,15 +712,13 @@ def prepare_single_task( }, CONFIG_KEY_CHECKPOINT_ID: None, CONFIG_KEY_CHECKPOINT_NS: task_checkpoint_ns, - CONFIG_KEY_RESUME_VALUE: next( - ( - v - for tid, c, v in pending_writes - if tid in (NULL_TASK_ID, task_id) - and c == RESUME - ), - configurable.get(CONFIG_KEY_RESUME_VALUE, MISSING), - ), + CONFIG_KEY_WRITES: [ + w + for w in pending_writes + + configurable.get(CONFIG_KEY_WRITES, []) + if w[0] in (NULL_TASK_ID, task_id) + ], + CONFIG_KEY_SCRATCHPAD: {}, }, ), triggers, diff --git a/libs/langgraph/langgraph/pregel/io.py b/libs/langgraph/langgraph/pregel/io.py index 693dffce2..b2596d3ad 100644 --- a/libs/langgraph/langgraph/pregel/io.py +++ b/libs/langgraph/langgraph/pregel/io.py @@ -4,6 +4,7 @@ from uuid import UUID from langchain_core.runnables.utils import AddableDict from langgraph.channels.base import BaseChannel, EmptyChannelError +from langgraph.checkpoint.base import PendingWrite from langgraph.constants import ( EMPTY_SEQ, ERROR, @@ -66,26 +67,31 @@ def read_channels( def map_command( - cmd: Command, + cmd: Command, pending_writes: list[PendingWrite] ) -> Iterator[tuple[str, str, Any]]: """Map input chunk to a sequence of pending writes in the form (channel, value).""" if cmd.graph == Command.PARENT: raise InvalidUpdateError("There is not parent graph") - if cmd.send: - if isinstance(cmd.send, (tuple, list)): - sends = cmd.send + if cmd.goto: + if isinstance(cmd.goto, (tuple, list)): + sends = cmd.goto else: - sends = [cmd.send] + sends = [cmd.goto] for send in sends: if not isinstance(send, Send): raise TypeError( - f"In Command.send, expected Send, got {type(send).__name__}" + f"In Command.goto, expected Send, got {type(send).__name__}" ) yield (NULL_TASK_ID, PUSH if FF_SEND_V2 else TASKS, send) + # TODO handle goto str for state graph if cmd.resume: if isinstance(cmd.resume, dict) and all(is_task_id(k) for k in cmd.resume): for tid, resume in cmd.resume.items(): - yield (tid, RESUME, resume) + existing: list[Any] = next( + (w[2] for w in pending_writes if w[0] == tid and w[1] == RESUME), [] + ) + existing.append(resume) + yield (tid, RESUME, existing) else: yield (NULL_TASK_ID, RESUME, cmd.resume) if cmd.update: diff --git a/libs/langgraph/langgraph/pregel/loop.py b/libs/langgraph/langgraph/pregel/loop.py index 2a68b00f2..d9af9279e 100644 --- a/libs/langgraph/langgraph/pregel/loop.py +++ b/libs/langgraph/langgraph/pregel/loop.py @@ -26,6 +26,7 @@ from typing_extensions import ParamSpec, Self from langgraph.channels.base import BaseChannel from langgraph.checkpoint.base import ( + WRITES_IDX_MAP, BaseCheckpointSaver, ChannelVersions, Checkpoint, @@ -263,8 +264,28 @@ class PregelLoop(LoopProtocol): """Put writes for a task, to be read by the next tick.""" if not writes: return + # deduplicate writes to special channels, last write wins + if all(w[0] in WRITES_IDX_MAP for w in writes): + writes = list({w[0]: w for w in writes}.values()) # save writes - self.checkpoint_pending_writes.extend((task_id, k, v) for k, v in writes) + for c, v in writes: + if ( + c in WRITES_IDX_MAP + and ( + idx := next( + ( + i + for i, w in enumerate(self.checkpoint_pending_writes) + if w[0] == task_id and w[1] == c + ), + None, + ) + ) + is not None + ): + self.checkpoint_pending_writes[idx] = (task_id, c, v) + else: + self.checkpoint_pending_writes.append((task_id, c, v)) if self.checkpointer_put_writes is not None: self.submit( self.checkpointer_put_writes, @@ -536,7 +557,7 @@ class PregelLoop(LoopProtocol): elif isinstance(self.input, Command): writes: defaultdict[str, list[tuple[str, Any]]] = defaultdict(list) # group writes by task ID - for tid, c, v in map_command(self.input): + for tid, c, v in map_command(self.input, self.checkpoint_pending_writes): writes[tid].append((c, v)) if not writes: raise EmptyInputError("Received empty Command input") diff --git a/libs/langgraph/langgraph/pregel/runner.py b/libs/langgraph/langgraph/pregel/runner.py index 9e3879b0f..f46210459 100644 --- a/libs/langgraph/langgraph/pregel/runner.py +++ b/libs/langgraph/langgraph/pregel/runner.py @@ -21,6 +21,7 @@ from langgraph.constants import ( INTERRUPT, NO_WRITES, PUSH, + RESUME, TAG_HIDDEN, ) from langgraph.errors import GraphBubbleUp, GraphInterrupt @@ -297,6 +298,8 @@ class PregelRunner: if isinstance(exception, GraphInterrupt): # save interrupt to checkpointer if interrupts := [(INTERRUPT, i) for i in exception.args[0]]: + if resumes := [w for w in task.writes if w[0] == RESUME]: + interrupts.extend(resumes) self.put_writes(task.id, interrupts) elif isinstance(exception, GraphBubbleUp): raise exception diff --git a/libs/langgraph/langgraph/types.py b/libs/langgraph/langgraph/types.py index 8a614f458..456196e44 100644 --- a/libs/langgraph/langgraph/types.py +++ b/libs/langgraph/langgraph/types.py @@ -13,6 +13,7 @@ from typing import ( Optional, Sequence, Type, + TypedDict, TypeVar, Union, cast, @@ -21,11 +22,16 @@ from typing import ( from langchain_core.runnables import Runnable, RunnableConfig from typing_extensions import Self -from langgraph.checkpoint.base import BaseCheckpointSaver, CheckpointMetadata +from langgraph.checkpoint.base import ( + BaseCheckpointSaver, + CheckpointMetadata, + PendingWrite, +) if TYPE_CHECKING: from langgraph.store.base import BaseStore + All = Literal["*"] """Special value to indicate that graph should interrupt on all nodes.""" @@ -239,12 +245,27 @@ N = TypeVar("N", bound=Hashable) @dataclasses.dataclass(**_DC_KWARGS) class Command(Generic[N]): - """One or more commands to update the graph's state and send messages to nodes.""" + """One or more commands to update the graph's state and send messages to nodes. + + Args: + graph: graph to send the command to. Supported values are: + + - None: the current graph (default) + - GraphCommand.PARENT: closest parent graph + update: update to apply to the graph's state. + resume: value to resume execution with. To be used together with [`interrupt()`][langgraph.types.interrupt]. + goto: can be one of the following: + + - name of the node to navigate to next (any node that belongs to the specified `graph`) + - sequence of node names to navigate to next + - `Send` object (to execute a node with the input provided) + - sequence of `Send` objects + """ graph: Optional[str] = None update: Optional[dict[str, Any]] = None - send: Union[Send, Sequence[Send]] = () resume: Optional[Union[Any, dict[str, Any]]] = None + goto: Union[Send, Sequence[Union[Send, str]], str] = () def __repr__(self) -> str: # get all non-None values @@ -300,6 +321,12 @@ class LoopProtocol: self.stop = stop +class PregelScratchpad(TypedDict, total=False): + interrupt_counter: int + used_null_resume: bool + resume: list[Any] + + def interrupt(value: Any) -> Any: """Interrupt the graph with a resumable exception from within a node. @@ -338,23 +365,50 @@ def interrupt(value: Any) -> Any: """ from langgraph.constants import ( CONFIG_KEY_CHECKPOINT_NS, - CONFIG_KEY_RESUME_VALUE, - MISSING, + CONFIG_KEY_SCRATCHPAD, + CONFIG_KEY_SEND, + CONFIG_KEY_TASK_ID, + CONFIG_KEY_WRITES, NS_SEP, + NULL_TASK_ID, + RESUME, ) from langgraph.errors import GraphInterrupt from langgraph.utils.config import get_configurable conf = get_configurable() - if (resume := conf.get(CONFIG_KEY_RESUME_VALUE, MISSING)) and resume is not MISSING: - return resume + # track interrupt index + scratchpad: PregelScratchpad = conf[CONFIG_KEY_SCRATCHPAD] + if "interrupt_counter" not in scratchpad: + scratchpad["interrupt_counter"] = 0 else: - raise GraphInterrupt( - ( - Interrupt( - value=value, - resumable=True, - ns=cast(str, conf[CONFIG_KEY_CHECKPOINT_NS]).split(NS_SEP), - ), - ) + scratchpad["interrupt_counter"] += 1 + idx = scratchpad["interrupt_counter"] + # find previous resume values + task_id = conf[CONFIG_KEY_TASK_ID] + writes: list[PendingWrite] = conf[CONFIG_KEY_WRITES] + scratchpad.setdefault( + "resume", next((w[2] for w in writes if w[0] == task_id and w[1] == RESUME), []) + ) + if scratchpad["resume"]: + if idx < len(scratchpad["resume"]): + return scratchpad["resume"][idx] + # find current resume value + if not scratchpad.get("used_null_resume"): + scratchpad["used_null_resume"] = True + for tid, c, v in sorted(writes, key=lambda x: x[0], reverse=True): + if tid == NULL_TASK_ID and c == RESUME: + assert len(scratchpad["resume"]) == idx, (scratchpad["resume"], idx) + scratchpad["resume"].append(v) + conf[CONFIG_KEY_SEND]([(RESUME, scratchpad["resume"])]) + return v + # no resume value found + raise GraphInterrupt( + ( + Interrupt( + value=value, + resumable=True, + ns=cast(str, conf[CONFIG_KEY_CHECKPOINT_NS]).split(NS_SEP), + ), ) + ) diff --git a/libs/langgraph/pyproject.toml b/libs/langgraph/pyproject.toml index e66600939..0a1f0b084 100644 --- a/libs/langgraph/pyproject.toml +++ b/libs/langgraph/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "langgraph" -version = "0.2.54" +version = "0.2.56" description = "Building stateful, multi-actor applications with LLMs" authors = [] license = "MIT" diff --git a/libs/langgraph/tests/test_pregel.py b/libs/langgraph/tests/test_pregel.py index 4ff56ca3e..f69d36ed3 100644 --- a/libs/langgraph/tests/test_pregel.py +++ b/libs/langgraph/tests/test_pregel.py @@ -65,7 +65,7 @@ from langgraph.constants import ( START, ) from langgraph.errors import InvalidUpdateError, MultipleSubgraphsError, NodeInterrupt -from langgraph.graph import END, Graph, GraphCommand, StateGraph +from langgraph.graph import END, Graph, StateGraph from langgraph.graph.message import MessageGraph, MessagesState, add_messages from langgraph.managed.shared_value import SharedValue from langgraph.prebuilt.chat_agent_executor import create_tool_calling_executor @@ -270,10 +270,10 @@ def test_graph_validation_with_command() -> None: bar: str def node_a(state: State): - return GraphCommand(goto="b", update={"foo": "bar"}) + return Command(goto="b", update={"foo": "bar"}) def node_b(state: State): - return GraphCommand(goto=END, update={"bar": "baz"}) + return Command(goto=END, update={"bar": "baz"}) builder = StateGraph(State) builder.add_node("a", node_a) @@ -1925,8 +1925,8 @@ def test_send_sequences() -> None: def send_for_fun(state): return [ - Send("2", Command(send=Send("2", 3))), - Send("2", GraphCommand(send=Send("2", 4))), + Send("2", Command(goto=Send("2", 3))), + Send("2", Command(goto=Send("2", 4))), "3.1", ] @@ -1947,8 +1947,8 @@ def test_send_sequences() -> None: == [ "0", "1", - "2|Command(send=Send(node='2', arg=3))", - "2|Command(send=Send(node='2', arg=4))", + "2|Command(goto=Send(node='2', arg=3))", + "2|Command(goto=Send(node='2', arg=4))", "2|3", "2|4", "3", @@ -1959,8 +1959,8 @@ def test_send_sequences() -> None: "0", "1", "3.1", - "2|Command(send=Send(node='2', arg=3))", - "2|Command(send=Send(node='2', arg=4))", + "2|Command(goto=Send(node='2', arg=3))", + "2|Command(goto=Send(node='2', arg=4))", "3", "2|3", "2|4", @@ -1969,7 +1969,6 @@ def test_send_sequences() -> None: ) -@pytest.mark.repeat(20) @pytest.mark.parametrize("checkpointer_name", ALL_CHECKPOINTERS_SYNC) def test_send_dedupe_on_resume( request: pytest.FixtureRequest, checkpointer_name: str @@ -2000,15 +1999,15 @@ def test_send_dedupe_on_resume( if isinstance(state, list) else ["|".join((self.name, str(state)))] ) - if isinstance(state, GraphCommand): + if isinstance(state, Command): return replace(state, update=update) else: return update def send_for_fun(state): return [ - Send("2", GraphCommand(send=Send("2", 3))), - Send("2", GraphCommand(send=Send("flaky", 4))), + Send("2", Command(goto=Send("2", 3))), + Send("2", Command(goto=Send("flaky", 4))), "3.1", ] @@ -2030,8 +2029,8 @@ def test_send_dedupe_on_resume( assert graph.invoke(["0"], thread1, debug=1) == [ "0", "1", - "2|Command(send=Send(node='2', arg=3))", - "2|Command(send=Send(node='flaky', arg=4))", + "2|Command(goto=Send(node='2', arg=3))", + "2|Command(goto=Send(node='flaky', arg=4))", "2|3", ] assert builder.nodes["2"].runnable.func.ticks == 3 @@ -2046,8 +2045,8 @@ def test_send_dedupe_on_resume( assert graph.invoke(None, thread1, debug=1) == [ "0", "1", - "2|Command(send=Send(node='2', arg=3))", - "2|Command(send=Send(node='flaky', arg=4))", + "2|Command(goto=Send(node='2', arg=3))", + "2|Command(goto=Send(node='flaky', arg=4))", "2|3", "flaky|4", "3", @@ -2069,8 +2068,8 @@ def test_send_dedupe_on_resume( values=[ "0", "1", - "2|Command(send=Send(node='2', arg=3))", - "2|Command(send=Send(node='flaky', arg=4))", + "2|Command(goto=Send(node='2', arg=3))", + "2|Command(goto=Send(node='flaky', arg=4))", "2|3", "flaky|4", "3", @@ -2105,8 +2104,8 @@ def test_send_dedupe_on_resume( values=[ "0", "1", - "2|Command(send=Send(node='2', arg=3))", - "2|Command(send=Send(node='flaky', arg=4))", + "2|Command(goto=Send(node='2', arg=3))", + "2|Command(goto=Send(node='flaky', arg=4))", "2|3", "flaky|4", ], @@ -2123,8 +2122,8 @@ def test_send_dedupe_on_resume( "writes": { "1": ["1"], "2": [ - ["2|Command(send=Send(node='2', arg=3))"], - ["2|Command(send=Send(node='flaky', arg=4))"], + ["2|Command(goto=Send(node='2', arg=3))"], + ["2|Command(goto=Send(node='flaky', arg=4))"], ["2|3"], ], "flaky": ["flaky|4"], @@ -2209,7 +2208,7 @@ def test_send_dedupe_on_resume( error=None, interrupts=(), state=None, - result=["2|Command(send=Send(node='2', arg=3))"], + result=["2|Command(goto=Send(node='2', arg=3))"], ), PregelTask( id=AnyStr(), @@ -2223,7 +2222,7 @@ def test_send_dedupe_on_resume( error=None, interrupts=(), state=None, - result=["2|Command(send=Send(node='flaky', arg=4))"], + result=["2|Command(goto=Send(node='flaky', arg=4))"], ), PregelTask( id=AnyStr(), @@ -2786,10 +2785,10 @@ def test_send_react_interrupt_control( tool_calls=[ToolCall(name="foo", args={"hi": [1, 2, 3]}, id=AnyStr())], ) - def agent(state) -> GraphCommand[Literal["foo"]]: - return GraphCommand( + def agent(state) -> Command[Literal["foo"]]: + return Command( update={"messages": ai_message}, - send=[Send(call["name"], call) for call in ai_message.tool_calls], + goto=[Send(call["name"], call) for call in ai_message.tool_calls], ) foo_called = 0 @@ -14580,9 +14579,9 @@ def test_parent_command(request: pytest.FixtureRequest, checkpointer_name: str) from langchain_core.tools import tool @tool(return_direct=True) - def get_user_name() -> GraphCommand: + def get_user_name() -> Command: """Retrieve user name""" - return GraphCommand(update={"user_name": "Meow"}, graph=GraphCommand.PARENT) + return Command(update={"user_name": "Meow"}, graph=Command.PARENT) subgraph_builder = StateGraph(MessagesState) subgraph_builder.add_node("tool", get_user_name) @@ -14680,3 +14679,143 @@ def test_interrupt_subgraph(request: pytest.FixtureRequest, checkpointer_name: s assert graph.invoke({"baz": ""}, thread1) # Resume with answer assert graph.invoke(Command(resume="bar"), thread1) + + +@pytest.mark.parametrize("checkpointer_name", ALL_CHECKPOINTERS_SYNC) +def test_interrupt_multiple(request: pytest.FixtureRequest, checkpointer_name: str): + checkpointer = request.getfixturevalue(f"checkpointer_{checkpointer_name}") + + class State(TypedDict): + my_key: Annotated[str, operator.add] + + def node(s: State) -> State: + answer = interrupt({"value": 1}) + answer2 = interrupt({"value": 2}) + return {"my_key": answer + " " + answer2} + + builder = StateGraph(State) + builder.add_node("node", node) + builder.add_edge(START, "node") + + graph = builder.compile(checkpointer=checkpointer) + thread1 = {"configurable": {"thread_id": "1"}} + + assert [e for e in graph.stream({"my_key": "DE", "market": "DE"}, thread1)] == [ + { + "__interrupt__": ( + Interrupt( + value={"value": 1}, + resumable=True, + ns=[AnyStr("node:")], + when="during", + ), + ) + } + ] + + assert [ + event + for event in graph.stream( + Command(resume="answer 1", update={"my_key": "foofoo"}), thread1 + ) + ] == [ + { + "__interrupt__": ( + Interrupt( + value={"value": 2}, + resumable=True, + ns=[AnyStr("node:")], + when="during", + ), + ) + } + ] + + assert [event for event in graph.stream(Command(resume="answer 2"), thread1)] == [ + {"node": {"my_key": "answer 1 answer 2"}}, + ] + + +@pytest.mark.parametrize("checkpointer_name", ALL_CHECKPOINTERS_SYNC) +def test_interrupt_loop(request: pytest.FixtureRequest, checkpointer_name: str): + checkpointer = request.getfixturevalue(f"checkpointer_{checkpointer_name}") + + class State(TypedDict): + age: int + other: str + + def ask_age(s: State): + """Ask an expert for help.""" + question = "How old are you?" + value = None + for _ in range(10): + value: str = interrupt(question) + if not value.isdigit() or int(value) < 18: + question = "invalid response" + value = None + else: + break + + return {"age": int(value)} + + builder = StateGraph(State) + builder.add_node("node", ask_age) + builder.add_edge(START, "node") + + graph = builder.compile(checkpointer=checkpointer) + thread1 = {"configurable": {"thread_id": "1"}} + + assert [e for e in graph.stream({"other": ""}, thread1)] == [ + { + "__interrupt__": ( + Interrupt( + value="How old are you?", + resumable=True, + ns=[AnyStr("node:")], + when="during", + ), + ) + } + ] + + assert [ + event + for event in graph.stream( + Command(resume="13"), + thread1, + ) + ] == [ + { + "__interrupt__": ( + Interrupt( + value="invalid response", + resumable=True, + ns=[AnyStr("node:")], + when="during", + ), + ) + } + ] + + assert [ + event + for event in graph.stream( + Command(resume="15"), + thread1, + ) + ] == [ + { + "__interrupt__": ( + Interrupt( + value="invalid response", + resumable=True, + ns=[AnyStr("node:")], + when="during", + ), + ) + } + ] + + assert [event for event in graph.stream(Command(resume="19"), thread1)] == [ + {"node": {"age": 19}}, + ] diff --git a/libs/langgraph/tests/test_pregel_async.py b/libs/langgraph/tests/test_pregel_async.py index cc244c363..514703781 100644 --- a/libs/langgraph/tests/test_pregel_async.py +++ b/libs/langgraph/tests/test_pregel_async.py @@ -62,7 +62,7 @@ from langgraph.constants import ( START, ) from langgraph.errors import InvalidUpdateError, MultipleSubgraphsError, NodeInterrupt -from langgraph.graph import END, Graph, GraphCommand, StateGraph +from langgraph.graph import END, Graph, StateGraph from langgraph.graph.message import MessageGraph, MessagesState, add_messages from langgraph.managed.shared_value import SharedValue from langgraph.prebuilt.chat_agent_executor import create_tool_calling_executor @@ -847,7 +847,6 @@ async def test_node_not_cancelled_on_other_node_interrupted( assert awhiles == 1 -@pytest.mark.repeat(10) async def test_step_timeout_on_stream_hang() -> None: inner_task_cancelled = False @@ -2559,7 +2558,6 @@ async def test_concurrent_emit_sends() -> None: ) -@pytest.mark.repeat(10) @pytest.mark.parametrize("checkpointer_name", ALL_CHECKPOINTERS_ASYNC) async def test_send_sequences(checkpointer_name: str) -> None: class Node: @@ -2580,8 +2578,8 @@ async def test_send_sequences(checkpointer_name: str) -> None: async def send_for_fun(state): return [ - Send("2", Command(send=Send("2", 3))), - Send("2", GraphCommand(send=Send("2", 4))), + Send("2", Command(goto=Send("2", 3))), + Send("2", Command(goto=Send("2", 4))), "3.1", ] @@ -2602,8 +2600,8 @@ async def test_send_sequences(checkpointer_name: str) -> None: == [ "0", "1", - "2|Command(send=Send(node='2', arg=3))", - "2|Command(send=Send(node='2', arg=4))", + "2|Command(goto=Send(node='2', arg=3))", + "2|Command(goto=Send(node='2', arg=4))", "2|3", "2|4", "3", @@ -2614,8 +2612,8 @@ async def test_send_sequences(checkpointer_name: str) -> None: "0", "1", "3.1", - "2|Command(send=Send(node='2', arg=3))", - "2|Command(send=Send(node='2', arg=4))", + "2|Command(goto=Send(node='2', arg=3))", + "2|Command(goto=Send(node='2', arg=4))", "3", "2|3", "2|4", @@ -2632,16 +2630,16 @@ async def test_send_sequences(checkpointer_name: str) -> None: assert await graph.ainvoke(["0"], thread1) == [ "0", "1", - "2|Command(send=Send(node='2', arg=3))", - "2|Command(send=Send(node='2', arg=4))", + "2|Command(goto=Send(node='2', arg=3))", + "2|Command(goto=Send(node='2', arg=4))", "2|3", "2|4", ] assert await graph.ainvoke(None, thread1) == [ "0", "1", - "2|Command(send=Send(node='2', arg=3))", - "2|Command(send=Send(node='2', arg=4))", + "2|Command(goto=Send(node='2', arg=3))", + "2|Command(goto=Send(node='2', arg=4))", "2|3", "2|4", "3", @@ -2649,7 +2647,6 @@ async def test_send_sequences(checkpointer_name: str) -> None: ] -@pytest.mark.repeat(20) @pytest.mark.parametrize("checkpointer_name", ALL_CHECKPOINTERS_ASYNC) async def test_send_dedupe_on_resume(checkpointer_name: str) -> None: if not FF_SEND_V2: @@ -2677,15 +2674,15 @@ async def test_send_dedupe_on_resume(checkpointer_name: str) -> None: if isinstance(state, list) else ["|".join((self.name, str(state)))] ) - if isinstance(state, GraphCommand): + if isinstance(state, Command): return replace(state, update=update) else: return update def send_for_fun(state): return [ - Send("2", GraphCommand(send=Send("2", 3))), - Send("2", GraphCommand(send=Send("flaky", 4))), + Send("2", Command(goto=Send("2", 3))), + Send("2", Command(goto=Send("flaky", 4))), "3.1", ] @@ -2708,8 +2705,8 @@ async def test_send_dedupe_on_resume(checkpointer_name: str) -> None: assert await graph.ainvoke(["0"], thread1, debug=1) == [ "0", "1", - "2|Command(send=Send(node='2', arg=3))", - "2|Command(send=Send(node='flaky', arg=4))", + "2|Command(goto=Send(node='2', arg=3))", + "2|Command(goto=Send(node='flaky', arg=4))", "2|3", ] assert builder.nodes["2"].runnable.func.ticks == 3 @@ -2718,8 +2715,8 @@ async def test_send_dedupe_on_resume(checkpointer_name: str) -> None: assert await graph.ainvoke(None, thread1, debug=1) == [ "0", "1", - "2|Command(send=Send(node='2', arg=3))", - "2|Command(send=Send(node='flaky', arg=4))", + "2|Command(goto=Send(node='2', arg=3))", + "2|Command(goto=Send(node='flaky', arg=4))", "2|3", "flaky|4", "3", @@ -2736,8 +2733,8 @@ async def test_send_dedupe_on_resume(checkpointer_name: str) -> None: values=[ "0", "1", - "2|Command(send=Send(node='2', arg=3))", - "2|Command(send=Send(node='flaky', arg=4))", + "2|Command(goto=Send(node='2', arg=3))", + "2|Command(goto=Send(node='flaky', arg=4))", "2|3", "flaky|4", "3", @@ -2772,8 +2769,8 @@ async def test_send_dedupe_on_resume(checkpointer_name: str) -> None: values=[ "0", "1", - "2|Command(send=Send(node='2', arg=3))", - "2|Command(send=Send(node='flaky', arg=4))", + "2|Command(goto=Send(node='2', arg=3))", + "2|Command(goto=Send(node='flaky', arg=4))", "2|3", "flaky|4", ], @@ -2790,8 +2787,8 @@ async def test_send_dedupe_on_resume(checkpointer_name: str) -> None: "writes": { "1": ["1"], "2": [ - ["2|Command(send=Send(node='2', arg=3))"], - ["2|Command(send=Send(node='flaky', arg=4))"], + ["2|Command(goto=Send(node='2', arg=3))"], + ["2|Command(goto=Send(node='flaky', arg=4))"], ["2|3"], ], "flaky": ["flaky|4"], @@ -2876,7 +2873,7 @@ async def test_send_dedupe_on_resume(checkpointer_name: str) -> None: error=None, interrupts=(), state=None, - result=["2|Command(send=Send(node='2', arg=3))"], + result=["2|Command(goto=Send(node='2', arg=3))"], ), PregelTask( id=AnyStr(), @@ -2890,7 +2887,7 @@ async def test_send_dedupe_on_resume(checkpointer_name: str) -> None: error=None, interrupts=(), state=None, - result=["2|Command(send=Send(node='flaky', arg=4))"], + result=["2|Command(goto=Send(node='flaky', arg=4))"], ), PregelTask( id=AnyStr(), @@ -3448,9 +3445,9 @@ async def test_send_react_interrupt_control( ) async def agent(state) -> Command[Literal["foo"]]: - return GraphCommand( + return Command( update={"messages": ai_message}, - send=[Send(call["name"], call) for call in ai_message.tool_calls], + goto=[Send(call["name"], call) for call in ai_message.tool_calls], ) foo_called = 0 @@ -3761,13 +3758,13 @@ async def test_max_concurrency(checkpointer_name: str) -> None: @pytest.mark.parametrize("checkpointer_name", ALL_CHECKPOINTERS_ASYNC) async def test_max_concurrency_control(checkpointer_name: str) -> None: - async def node1(state) -> GraphCommand[Literal["2"]]: - return GraphCommand(update=["1"], send=[Send("2", idx) for idx in range(100)]) + async def node1(state) -> Command[Literal["2"]]: + return Command(update=["1"], goto=[Send("2", idx) for idx in range(100)]) node2_currently = 0 node2_max_currently = 0 - async def node2(state) -> GraphCommand[Literal["3"]]: + async def node2(state) -> Command[Literal["3"]]: nonlocal node2_currently, node2_max_currently node2_currently += 1 if node2_currently > node2_max_currently: @@ -3775,7 +3772,7 @@ async def test_max_concurrency_control(checkpointer_name: str) -> None: await asyncio.sleep(0.1) node2_currently -= 1 - return GraphCommand(update=[state], goto="3") + return Command(update=[state], goto="3") async def node3(state) -> Literal["3"]: return ["3"] @@ -12788,9 +12785,9 @@ async def test_parent_command(checkpointer_name: str) -> None: from langchain_core.tools import tool @tool(return_direct=True) - def get_user_name() -> GraphCommand: + def get_user_name() -> Command: """Retrieve user name""" - return GraphCommand(update={"user_name": "Meow"}, graph=GraphCommand.PARENT) + return Command(update={"user_name": "Meow"}, graph=Command.PARENT) subgraph_builder = StateGraph(MessagesState) subgraph_builder.add_node("tool", get_user_name) @@ -12896,3 +12893,160 @@ async def test_interrupt_subgraph(checkpointer_name: str): assert await graph.ainvoke({"baz": ""}, thread1) # Resume with answer assert await graph.ainvoke(Command(resume="bar"), thread1) + + +@pytest.mark.skipif( + sys.version_info < (3, 11), + reason="Python 3.11+ is required for async contextvars support", +) +@pytest.mark.parametrize("checkpointer_name", ALL_CHECKPOINTERS_ASYNC) +async def test_interrupt_multiple(checkpointer_name: str): + class State(TypedDict): + my_key: Annotated[str, operator.add] + + async def node(s: State) -> State: + answer = interrupt({"value": 1}) + answer2 = interrupt({"value": 2}) + return {"my_key": answer + " " + answer2} + + builder = StateGraph(State) + builder.add_node("node", node) + builder.add_edge(START, "node") + + async with awith_checkpointer(checkpointer_name) as checkpointer: + graph = builder.compile(checkpointer=checkpointer) + thread1 = {"configurable": {"thread_id": "1"}} + + assert [ + e async for e in graph.astream({"my_key": "DE", "market": "DE"}, thread1) + ] == [ + { + "__interrupt__": ( + Interrupt( + value={"value": 1}, + resumable=True, + ns=[AnyStr("node:")], + when="during", + ), + ) + } + ] + + assert [ + event + async for event in graph.astream( + Command(resume="answer 1", update={"my_key": "foofoo"}), + thread1, + stream_mode="updates", + ) + ] == [ + { + "__interrupt__": ( + Interrupt( + value={"value": 2}, + resumable=True, + ns=[AnyStr("node:")], + when="during", + ), + ) + } + ] + + assert [ + event + async for event in graph.astream( + Command(resume="answer 2"), thread1, stream_mode="updates" + ) + ] == [ + {"node": {"my_key": "answer 1 answer 2"}}, + ] + + +@pytest.mark.skipif( + sys.version_info < (3, 11), + reason="Python 3.11+ is required for async contextvars support", +) +@pytest.mark.parametrize("checkpointer_name", ALL_CHECKPOINTERS_ASYNC) +async def test_interrupt_loop(checkpointer_name: str): + class State(TypedDict): + age: int + other: str + + async def ask_age(s: State): + """Ask an expert for help.""" + question = "How old are you?" + value = None + for _ in range(10): + value: str = interrupt(question) + if not value.isdigit() or int(value) < 18: + question = "invalid response" + value = None + else: + break + + return {"age": int(value)} + + builder = StateGraph(State) + builder.add_node("node", ask_age) + builder.add_edge(START, "node") + + async with awith_checkpointer(checkpointer_name) as checkpointer: + graph = builder.compile(checkpointer=checkpointer) + thread1 = {"configurable": {"thread_id": "1"}} + + assert [e async for e in graph.astream({"other": ""}, thread1)] == [ + { + "__interrupt__": ( + Interrupt( + value="How old are you?", + resumable=True, + ns=[AnyStr("node:")], + when="during", + ), + ) + } + ] + + assert [ + event + async for event in graph.astream( + Command(resume="13"), + thread1, + ) + ] == [ + { + "__interrupt__": ( + Interrupt( + value="invalid response", + resumable=True, + ns=[AnyStr("node:")], + when="during", + ), + ) + } + ] + + assert [ + event + async for event in graph.astream( + Command(resume="15"), + thread1, + ) + ] == [ + { + "__interrupt__": ( + Interrupt( + value="invalid response", + resumable=True, + ns=[AnyStr("node:")], + when="during", + ), + ) + } + ] + + assert [ + event async for event in graph.astream(Command(resume="19"), thread1) + ] == [ + {"node": {"age": 19}}, + ] diff --git a/libs/scheduler-kafka/tests/any.py b/libs/scheduler-kafka/tests/any.py index 73744a1e8..3ea224173 100644 --- a/libs/scheduler-kafka/tests/any.py +++ b/libs/scheduler-kafka/tests/any.py @@ -35,3 +35,21 @@ class AnyDict(dict): return False else: return True + + +class AnyList(list): + def __init__(self, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + + def __eq__(self, other: object) -> bool: + if not self and isinstance(other, list): + return True + if not isinstance(other, list) or len(self) != len(other): + return False + for i, v in enumerate(self): + if v == other[i]: + continue + else: + return False + else: + return True diff --git a/libs/scheduler-kafka/tests/test_push.py b/libs/scheduler-kafka/tests/test_push.py index 15e9211a2..3d2e4d43d 100644 --- a/libs/scheduler-kafka/tests/test_push.py +++ b/libs/scheduler-kafka/tests/test_push.py @@ -11,10 +11,10 @@ from aiokafka import AIOKafkaProducer from langgraph.checkpoint.base import BaseCheckpointSaver from langgraph.constants import FF_SEND_V2, START from langgraph.errors import NodeInterrupt -from langgraph.graph.state import CompiledStateGraph, GraphCommand, StateGraph +from langgraph.graph.state import CompiledStateGraph, StateGraph from langgraph.scheduler.kafka import serde from langgraph.scheduler.kafka.types import MessageToOrchestrator, Topics -from langgraph.types import Send +from langgraph.types import Command, Send from tests.any import AnyDict from tests.drain import drain_topics_async @@ -48,15 +48,15 @@ def mk_push_graph( if isinstance(state, list) else ["|".join((self.name, str(state)))] ) - if isinstance(state, GraphCommand): + if isinstance(state, Command): return state.copy(update=update) else: return update def send_for_fun(state): return [ - Send("2", GraphCommand(send=Send("2", 3))), - Send("2", GraphCommand(send=Send("flaky", 4))), + Send("2", Command(goto=Send("2", 3))), + Send("2", Command(goto=Send("flaky", 4))), "3.1", ] @@ -105,8 +105,8 @@ async def test_push_graph(topics: Topics, acheckpointer: BaseCheckpointSaver) -> == [ "0", "1", - "2|Control(send=Send(node='2', arg=3))", - "2|Control(send=Send(node='flaky', arg=4))", + "2|Control(goto=Send(node='2', arg=3))", + "2|Control(goto=Send(node='flaky', arg=4))", "2|3", ] ) @@ -182,8 +182,8 @@ async def test_push_graph(topics: Topics, acheckpointer: BaseCheckpointSaver) -> == [ "0", "1", - "2|Control(send=Send(node='2', arg=3))", - "2|Control(send=Send(node='flaky', arg=4))", + "2|Control(goto=Send(node='2', arg=3))", + "2|Control(goto=Send(node='flaky', arg=4))", "2|3", "flaky|4", "3", diff --git a/libs/scheduler-kafka/tests/test_push_sync.py b/libs/scheduler-kafka/tests/test_push_sync.py index 27cd96cb7..ee33d613e 100644 --- a/libs/scheduler-kafka/tests/test_push_sync.py +++ b/libs/scheduler-kafka/tests/test_push_sync.py @@ -10,11 +10,11 @@ import pytest from langgraph.checkpoint.base import BaseCheckpointSaver from langgraph.constants import FF_SEND_V2, START from langgraph.errors import NodeInterrupt -from langgraph.graph.state import CompiledStateGraph, GraphCommand, StateGraph +from langgraph.graph.state import CompiledStateGraph, StateGraph from langgraph.scheduler.kafka import serde from langgraph.scheduler.kafka.default_sync import DefaultProducer from langgraph.scheduler.kafka.types import MessageToOrchestrator, Topics -from langgraph.types import Send +from langgraph.types import Command, Send from tests.any import AnyDict from tests.drain import drain_topics @@ -48,15 +48,15 @@ def mk_push_graph( if isinstance(state, list) else ["|".join((self.name, str(state)))] ) - if isinstance(state, GraphCommand): + if isinstance(state, Command): return state.copy(update=update) else: return update def send_for_fun(state): return [ - Send("2", GraphCommand(send=Send("2", 3))), - Send("2", GraphCommand(send=Send("flaky", 4))), + Send("2", Command(goto=Send("2", 3))), + Send("2", Command(goto=Send("flaky", 4))), "3.1", ] @@ -106,8 +106,8 @@ def test_push_graph(topics: Topics, acheckpointer: BaseCheckpointSaver) -> None: == [ "0", "1", - "2|Control(send=Send(node='2', arg=3))", - "2|Control(send=Send(node='flaky', arg=4))", + "2|Control(goto=Send(node='2', arg=3))", + "2|Control(goto=Send(node='flaky', arg=4))", "2|3", ] ) @@ -184,8 +184,8 @@ def test_push_graph(topics: Topics, acheckpointer: BaseCheckpointSaver) -> None: == [ "0", "1", - "2|Control(send=Send(node='2', arg=3))", - "2|Control(send=Send(node='flaky', arg=4))", + "2|Control(goto=Send(node='2', arg=3))", + "2|Control(goto=Send(node='flaky', arg=4))", "2|3", "flaky|4", "3", diff --git a/libs/scheduler-kafka/tests/test_subgraph.py b/libs/scheduler-kafka/tests/test_subgraph.py index ebaaea580..4ab92676c 100644 --- a/libs/scheduler-kafka/tests/test_subgraph.py +++ b/libs/scheduler-kafka/tests/test_subgraph.py @@ -15,7 +15,7 @@ from langgraph.graph.state import StateGraph from langgraph.pregel import Pregel from langgraph.scheduler.kafka import serde from langgraph.scheduler.kafka.types import MessageToOrchestrator, Topics -from tests.any import AnyDict +from tests.any import AnyDict, AnyList from tests.drain import drain_topics_async from tests.messages import _AnyIdAIMessage, _AnyIdHumanMessage @@ -196,7 +196,8 @@ async def test_subgraph_w_interrupt( "__pregel_resuming": False, "__pregel_store": None, "__pregel_task_id": history[0].tasks[0].id, - "__pregel_resume_value": None, + "__pregel_scratchpad": {}, + "__pregel_writes": AnyList(), "checkpoint_id": None, "checkpoint_map": { "": history[0].config["configurable"]["checkpoint_id"] @@ -261,7 +262,8 @@ async def test_subgraph_w_interrupt( "__pregel_resuming": False, "__pregel_store": None, "__pregel_task_id": history[0].tasks[0].id, - "__pregel_resume_value": None, + "__pregel_scratchpad": {}, + "__pregel_writes": AnyList(), "checkpoint_id": c.config["configurable"]["checkpoint_id"], "checkpoint_map": { "": history[0].config["configurable"]["checkpoint_id"] @@ -356,7 +358,8 @@ async def test_subgraph_w_interrupt( "__pregel_resuming": False, "__pregel_store": None, "__pregel_task_id": history[0].tasks[0].id, - "__pregel_resume_value": None, + "__pregel_scratchpad": {}, + "__pregel_writes": AnyList(), "checkpoint_id": c.config["configurable"]["checkpoint_id"], "checkpoint_map": { "": history[0].config["configurable"]["checkpoint_id"] @@ -461,7 +464,8 @@ async def test_subgraph_w_interrupt( "__pregel_resuming": True, "__pregel_store": None, "__pregel_task_id": history[1].tasks[0].id, - "__pregel_resume_value": None, + "__pregel_scratchpad": {}, + "__pregel_writes": AnyList(), "checkpoint_id": None, "checkpoint_map": { "": history[1].config["configurable"]["checkpoint_id"] @@ -521,7 +525,8 @@ async def test_subgraph_w_interrupt( "__pregel_resuming": True, "__pregel_store": None, "__pregel_task_id": history[1].tasks[0].id, - "__pregel_resume_value": None, + "__pregel_scratchpad": {}, + "__pregel_writes": AnyList(), "checkpoint_id": c.config["configurable"]["checkpoint_id"], "checkpoint_map": { "": history[1].config["configurable"]["checkpoint_id"] @@ -637,7 +642,8 @@ async def test_subgraph_w_interrupt( "__pregel_resuming": True, "__pregel_store": None, "__pregel_task_id": history[1].tasks[0].id, - "__pregel_resume_value": None, + "__pregel_scratchpad": {}, + "__pregel_writes": AnyList(), "checkpoint_id": c.config["configurable"]["checkpoint_id"], "checkpoint_map": { "": history[1].config["configurable"]["checkpoint_id"] diff --git a/libs/scheduler-kafka/tests/test_subgraph_sync.py b/libs/scheduler-kafka/tests/test_subgraph_sync.py index 75b9d6e73..5fa43998a 100644 --- a/libs/scheduler-kafka/tests/test_subgraph_sync.py +++ b/libs/scheduler-kafka/tests/test_subgraph_sync.py @@ -15,7 +15,7 @@ from langgraph.pregel import Pregel from langgraph.scheduler.kafka import serde from langgraph.scheduler.kafka.default_sync import DefaultProducer from langgraph.scheduler.kafka.types import MessageToOrchestrator, Topics -from tests.any import AnyDict +from tests.any import AnyDict, AnyList from tests.drain import drain_topics from tests.messages import _AnyIdAIMessage, _AnyIdHumanMessage @@ -195,7 +195,8 @@ def test_subgraph_w_interrupt( "__pregel_resuming": False, "__pregel_store": None, "__pregel_task_id": history[0].tasks[0].id, - "__pregel_resume_value": None, + "__pregel_scratchpad": {}, + "__pregel_writes": AnyList(), "checkpoint_id": None, "checkpoint_map": { "": history[0].config["configurable"]["checkpoint_id"] @@ -260,7 +261,8 @@ def test_subgraph_w_interrupt( "__pregel_dedupe_tasks": True, "__pregel_resuming": False, "__pregel_task_id": history[0].tasks[0].id, - "__pregel_resume_value": None, + "__pregel_scratchpad": {}, + "__pregel_writes": AnyList(), "checkpoint_id": c.config["configurable"]["checkpoint_id"], "checkpoint_map": { "": history[0].config["configurable"]["checkpoint_id"] @@ -355,7 +357,8 @@ def test_subgraph_w_interrupt( "__pregel_store": None, "__pregel_resuming": False, "__pregel_task_id": history[0].tasks[0].id, - "__pregel_resume_value": None, + "__pregel_scratchpad": {}, + "__pregel_writes": AnyList(), "checkpoint_id": c.config["configurable"]["checkpoint_id"], "checkpoint_map": { "": history[0].config["configurable"]["checkpoint_id"] @@ -459,7 +462,8 @@ def test_subgraph_w_interrupt( "__pregel_store": None, "__pregel_resuming": True, "__pregel_task_id": history[1].tasks[0].id, - "__pregel_resume_value": None, + "__pregel_scratchpad": {}, + "__pregel_writes": AnyList(), "checkpoint_id": None, "checkpoint_map": { "": history[1].config["configurable"]["checkpoint_id"] @@ -519,7 +523,8 @@ def test_subgraph_w_interrupt( "__pregel_store": None, "__pregel_resuming": True, "__pregel_task_id": history[1].tasks[0].id, - "__pregel_resume_value": None, + "__pregel_scratchpad": {}, + "__pregel_writes": AnyList(), "checkpoint_id": c.config["configurable"]["checkpoint_id"], "checkpoint_map": { "": history[1].config["configurable"]["checkpoint_id"] @@ -635,7 +640,8 @@ def test_subgraph_w_interrupt( "__pregel_resuming": True, "__pregel_store": None, "__pregel_task_id": history[1].tasks[0].id, - "__pregel_resume_value": None, + "__pregel_scratchpad": {}, + "__pregel_writes": AnyList(), "checkpoint_id": c.config["configurable"]["checkpoint_id"], "checkpoint_map": { "": history[1].config["configurable"]["checkpoint_id"] diff --git a/libs/sdk-py/langgraph_sdk/client.py b/libs/sdk-py/langgraph_sdk/client.py index c453eb749..3436188c7 100644 --- a/libs/sdk-py/langgraph_sdk/client.py +++ b/libs/sdk-py/langgraph_sdk/client.py @@ -278,7 +278,12 @@ class HttpClient: raise e async def stream( - self, path: str, method: str, *, json: Optional[dict] = None + self, + path: str, + method: str, + *, + json: Optional[dict] = None, + params: Optional[QueryParamTypes] = None, ) -> AsyncIterator[StreamPart]: """Stream results using SSE.""" headers, content = await aencode_json(json) @@ -286,7 +291,7 @@ class HttpClient: headers["Cache-Control"] = "no-store" async with self.client.stream( - method, path, headers=headers, content=content + method, path, headers=headers, content=content, params=params ) as res: # check status try: @@ -314,6 +319,8 @@ class HttpClient: async def aencode_json(json: Any) -> tuple[dict[str, str], bytes]: + if json is None: + return {}, None body = await asyncio.get_running_loop().run_in_executor( None, orjson.dumps, @@ -2447,11 +2454,18 @@ class SyncHttpClient: raise e def stream( - self, path: str, method: str, *, json: Optional[dict] = None + self, + path: str, + method: str, + *, + json: Optional[dict] = None, + params: Optional[QueryParamTypes] = None, ) -> Iterator[StreamPart]: """Stream the results of a request using SSE.""" headers, content = encode_json(json) - with self.client.stream(method, path, headers=headers, content=content) as res: + with self.client.stream( + method, path, headers=headers, content=content, params=params + ) as res: # check status try: res.raise_for_status() diff --git a/libs/sdk-py/langgraph_sdk/schema.py b/libs/sdk-py/langgraph_sdk/schema.py index 1ccae3e89..6237ea5bd 100644 --- a/libs/sdk-py/langgraph_sdk/schema.py +++ b/libs/sdk-py/langgraph_sdk/schema.py @@ -373,6 +373,6 @@ class Send(TypedDict): class Command(TypedDict, total=False): - send: Union[Send, Sequence[Send]] + goto: Union[Send, str, Sequence[Union[Send, str]]] update: dict[str, Any] resume: Any diff --git a/libs/sdk-py/pyproject.toml b/libs/sdk-py/pyproject.toml index edf8a2510..991076ea9 100644 --- a/libs/sdk-py/pyproject.toml +++ b/libs/sdk-py/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "langgraph-sdk" -version = "0.1.42" +version = "0.1.43" description = "SDK for interacting with LangGraph API" authors = [] license = "MIT" diff --git a/poetry.lock b/poetry.lock index d8f321637..e0a15a09c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "aiohappyeyeballs" @@ -2862,30 +2862,30 @@ adal = ["adal (>=1.0.2)"] [[package]] name = "langchain" -version = "0.3.1" +version = "0.3.9" description = "Building applications with LLMs through composability" optional = false python-versions = "<4.0,>=3.9" files = [ - {file = "langchain-0.3.1-py3-none-any.whl", hash = "sha256:94e5ee7464d4366e4b158aa5704953c39701ea237b9ed4b200096d49e83bb3ae"}, - {file = "langchain-0.3.1.tar.gz", hash = "sha256:54d6e3abda2ec056875a231a418a4130ba7576e629e899067e499bfc847b7586"}, + {file = "langchain-0.3.9-py3-none-any.whl", hash = "sha256:ade5a1fee2f94f2e976a6c387f97d62cc7f0b9f26cfe0132a41d2bda761e1045"}, + {file = "langchain-0.3.9.tar.gz", hash = "sha256:4950c4ad627d0aa95ce6bda7de453e22059b7e7836b562a8f781fb0b05d7294c"}, ] [package.dependencies] aiohttp = ">=3.8.3,<4.0.0" async-timeout = {version = ">=4.0.0,<5.0.0", markers = "python_version < \"3.11\""} -langchain-core = ">=0.3.6,<0.4.0" +langchain-core = ">=0.3.21,<0.4.0" langchain-text-splitters = ">=0.3.0,<0.4.0" langsmith = ">=0.1.17,<0.2.0" numpy = [ - {version = ">=1,<2", markers = "python_version < \"3.12\""}, - {version = ">=1.26.0,<2.0.0", markers = "python_version >= \"3.12\""}, + {version = ">=1.22.4,<2", markers = "python_version < \"3.12\""}, + {version = ">=1.26.2,<3", markers = "python_version >= \"3.12\""}, ] pydantic = ">=2.7.4,<3.0.0" PyYAML = ">=5.3" requests = ">=2,<3" SQLAlchemy = ">=1.4,<3" -tenacity = ">=8.1.0,<8.4.0 || >8.4.0,<9.0.0" +tenacity = ">=8.1.0,<8.4.0 || >8.4.0,<10" [[package]] name = "langchain-anthropic" @@ -2933,13 +2933,13 @@ tenacity = ">=8.1.0,<8.4.0 || >8.4.0,<9.0.0" [[package]] name = "langchain-core" -version = "0.3.15" +version = "0.3.21" description = "Building applications with LLMs through composability" optional = false python-versions = "<4.0,>=3.9" files = [ - {file = "langchain_core-0.3.15-py3-none-any.whl", hash = "sha256:3d4ca6dbb8ed396a6ee061063832a2451b0ce8c345570f7b086ffa7288e4fa29"}, - {file = "langchain_core-0.3.15.tar.gz", hash = "sha256:b1a29787a4ffb7ec2103b4e97d435287201da7809b369740dd1e32f176325aba"}, + {file = "langchain_core-0.3.21-py3-none-any.whl", hash = "sha256:7e723dff80946a1198976c6876fea8326dc82566ef9bcb5f8d9188f738733665"}, + {file = "langchain_core-0.3.21.tar.gz", hash = "sha256:561b52b258ffa50a9fb11d7a1940ebfd915654d1ec95b35e81dfd5ee84143411"}, ] [package.dependencies] @@ -3035,7 +3035,7 @@ langchain-core = ">=0.3.0,<0.4.0" [[package]] name = "langgraph" -version = "0.2.52" +version = "0.2.54" description = "Building stateful, multi-actor applications with LLMs" optional = false python-versions = ">=3.9.0,<4.0" @@ -3045,7 +3045,7 @@ develop = true [package.dependencies] langchain-core = ">=0.2.43,<0.4.0,!=0.3.0,!=0.3.1,!=0.3.2,!=0.3.3,!=0.3.4,!=0.3.5,!=0.3.6,!=0.3.7,!=0.3.8,!=0.3.9,!=0.3.10,!=0.3.11,!=0.3.12,!=0.3.13,!=0.3.14" langgraph-checkpoint = "^2.0.4" -langgraph-sdk = "^0.1.32" +langgraph-sdk = "^0.1.42" [package.source] type = "directory" @@ -3053,7 +3053,7 @@ url = "libs/langgraph" [[package]] name = "langgraph-checkpoint" -version = "2.0.5" +version = "2.0.8" description = "Library with base interfaces for LangGraph checkpoint savers." optional = false python-versions = "^3.9.0,<4.0" @@ -3070,7 +3070,7 @@ url = "libs/checkpoint" [[package]] name = "langgraph-checkpoint-postgres" -version = "2.0.3" +version = "2.0.7" description = "Library with a Postgres implementation of LangGraph checkpoint saver." optional = false python-versions = "^3.9.0,<4.0" @@ -3078,10 +3078,10 @@ files = [] develop = true [package.dependencies] -langgraph-checkpoint = "^2.0.2" +langgraph-checkpoint = "^2.0.7" orjson = ">=3.10.1" -psycopg = "^3.0.0" -psycopg-pool = "^3.0.0" +psycopg = "^3.2.0" +psycopg-pool = "^3.2.0" [package.source] type = "directory" @@ -3106,7 +3106,7 @@ url = "libs/checkpoint-sqlite" [[package]] name = "langgraph-sdk" -version = "0.1.36" +version = "0.1.42" description = "SDK for interacting with LangGraph API" optional = false python-versions = "^3.9.0,<4.0" @@ -3115,7 +3115,6 @@ develop = true [package.dependencies] httpx = ">=0.25.2" -httpx-sse = ">=0.4.0" orjson = ">=3.10.1" [package.source] @@ -3586,7 +3585,6 @@ optional = false python-versions = ">=3.6" files = [ {file = "mkdocs-redirects-1.2.1.tar.gz", hash = "sha256:9420066d70e2a6bb357adf86e67023dcdca1857f97f07c7fe450f8f1fb42f861"}, - {file = "mkdocs_redirects-1.2.1-py3-none-any.whl", hash = "sha256:497089f9e0219e7389304cffefccdfa1cac5ff9509f2cb706f4c9b221726dffb"}, ] [package.dependencies] @@ -6964,7 +6962,6 @@ description = "Automatically mock your HTTP interactions to simplify and speed u optional = false python-versions = ">=3.8" files = [ - {file = "vcrpy-6.0.1-py2.py3-none-any.whl", hash = "sha256:621c3fb2d6bd8aa9f87532c688e4575bcbbde0c0afeb5ebdb7e14cac409edfdd"}, {file = "vcrpy-6.0.1.tar.gz", hash = "sha256:9e023fee7f892baa0bbda2f7da7c8ac51165c1c6e38ff8688683a12a4bde9278"}, ] @@ -7476,4 +7473,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "776ee42630769f08e3896338f18ec81830166695d32d2208dc31dedb22d3b22d" +content-hash = "cf18eed5e183fc4f7786d095540b6c9261e130750f2d1fcc427e08b78d522c61" diff --git a/pyproject.toml b/pyproject.toml index 31fe17172..c198ae5e4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,7 +34,7 @@ ruff = "^0.6.8" jupyter = "^1.1.1" [tool.poetry.group.test.dependencies] -langchain = "^0.3.1" +langchain = "^0.3.8" langchain-openai = "^0.2.0" langchain-anthropic = "^0.2.1" langchain-nomic = "^0.1.3"