Commit Graph
170 Commits
Author SHA1 Message Date
open-swe[bot] 01e7d027fc Apply patch [skip ci] 2025-08-11 20:28:47 +00:00
open-swe[bot] 03bf206805 Apply patch [skip ci] 2025-08-11 20:28:29 +00:00
open-swe[bot] 5aa0525965 Apply patch [skip ci] 2025-08-11 20:27:15 +00:00
open-swe[bot] db409f4e1a Apply patch [skip ci] 2025-08-11 20:26:55 +00:00
open-swe[bot] e168ea4505 Apply patch [skip ci] 2025-08-11 20:26:33 +00:00
open-swe[bot] 8bdd96b2fc Apply patch [skip ci] 2025-08-11 20:26:00 +00:00
open-swe[bot] 8f1cfbfd7c Apply patch [skip ci] 2025-08-11 20:25:25 +00:00
open-swe[bot] 3a5d791ce5 Apply patch [skip ci] 2025-08-11 20:24:22 +00:00
open-swe[bot] 5e28ac3000 Apply patch [skip ci] 2025-08-11 20:24:00 +00:00
open-swe[bot] 6cf20694ff Apply patch [skip ci] 2025-08-11 20:23:30 +00:00
open-swe[bot] 250d781af1 Apply patch [skip ci] 2025-08-11 20:22:22 +00:00
open-swe[bot] b1d480521c Apply patch [skip ci] 2025-08-11 20:21:42 +00:00
open-swe[bot] 44a64dacb3 Apply patch [skip ci] 2025-08-11 20:21:01 +00:00
open-swe[bot] 1115c53f9a Apply patch [skip ci] 2025-08-11 20:20:04 +00:00
open-swe[bot] 6c8269909d Apply patch [skip ci] 2025-08-11 20:19:16 +00:00
open-swe[bot] ad8946655f Apply patch [skip ci] 2025-08-11 20:18:59 +00:00
open-swe[bot] 2d4988dc59 Apply patch [skip ci] 2025-08-11 20:18:29 +00:00
open-swe[bot] f8c1e4477a Apply patch [skip ci] 2025-08-11 20:17:33 +00:00
open-swe[bot] a69de5596d Apply patch [skip ci] 2025-08-11 20:17:18 +00:00
open-swe[bot] ebd88829b8 Apply patch [skip ci] 2025-08-11 20:16:47 +00:00
open-swe[bot] 9f7aa90e05 Apply patch [skip ci] 2025-08-11 20:15:48 +00:00
open-swe[bot] aaf1265a17 Apply patch [skip ci] 2025-08-11 20:13:22 +00:00
open-swe[bot] 74c537b2d9 Apply patch [skip ci] 2025-08-11 20:12:29 +00:00
open-swe[bot] 71b8316140 Apply patch [skip ci] 2025-08-11 20:12:05 +00:00
open-swe[bot] 2d242baaa5 Apply patch [skip ci] 2025-08-11 20:11:21 +00:00
open-swe[bot] 669e941fce Apply patch [skip ci] 2025-08-11 20:11:09 +00:00
open-swe[bot] a94dd39edb Apply patch [skip ci] 2025-08-11 20:10:43 +00:00
open-swe[bot] d0d88ba871 Apply patch [skip ci] 2025-08-11 20:10:19 +00:00
open-swe[bot] e968421b75 Apply patch [skip ci] 2025-08-11 20:10:06 +00:00
open-swe[bot] 3711cca7a1 Apply patch [skip ci] 2025-08-11 20:09:17 +00:00
open-swe[bot] f5b007c196 Apply patch [skip ci] 2025-08-11 20:08:34 +00:00
open-swe[bot] 665792bbd2 Apply patch [skip ci] 2025-08-11 20:07:49 +00:00
open-swe[bot] b73d94a5f1 Apply patch [skip ci] 2025-08-11 20:07:35 +00:00
open-swe[bot] e5a560cb7d Apply patch [skip ci] 2025-08-11 20:06:05 +00:00
Sam CrowderandGitHub 16b363fbb0 feat(langgraph): implement redis node level cache (#5834)
###   Description

Adds Redis as a supported cache backend for LangGraph node-level
caching, enabling distributed caching across multiple processes/servers.
This implementation follows the same patterns as existing InMemoryCache
and SqliteCache.

###  Key changes
  - New RedisCache class implementing the BaseCache interface
  - Support for TTL-based expiration and batch operations
  - Worker-specific cache prefixes for parallel test isolation

###  Dependencies

  - redis package (already included in dev dependencies)

### Test Plan

- Unit tests: Added Redis cache tests covering basic operations, TTL,
batch operations, and error handling
- Integration tests: Redis cache integrated into existing LangGraph test
suite, tested with all checkpointer combinations
2025-08-11 09:19:34 -07:00
Sydney RunkleandGitHub 68a75135b0 release: langgraph + prebuilt 0.6.4 (#5854) 2025-08-07 18:12:26 +00:00
4571b708d9 fix(langgraph): support emitting messages from subgraphs when messages mode explicitly requested (#5836)
Reproduces:
https://github.com/langchain-ai/langgraph/issues/5249#issuecomment-3156519635
Caused after this change:
https://github.com/langchain-ai/langgraph/pull/4843

Fix to allow emitting messages from subgraphs if the subgraphs
explicitly used a stream mode "messages".

```python

def node_in_parent(...):
   # subgraph was called as a function.
   # messages are explicitly requested.
   for event in subgraph.stream(..., stream_mode="messages"):
      # something is done with `event`
   return ...

# subgraphs = False!
parent_graph.invoke(..., subgraphs=False)
```

The code above should continue to work correctly regardless of the value
of subgraphs as streaming messages was requested explicitly in the
parent node!

---------

Co-authored-by: Sydney Runkle <54324534+sydney-runkle@users.noreply.github.com>
2025-08-07 10:10:52 -04:00
Sydney RunkleandGitHub e365b2b8bd fix(prebuilt): raise on additional deprecated kwargs (#5848) 2025-08-06 21:08:42 +00:00
Sydney RunkleandGitHub 0bd7dd2c52 chore(langgraph): deprecate MessageGraph (#5843)
`MessageGraph` is deprecated, to be removed in v2.

A `StateGraph` with a `messages` key should be used instead.
Alternatively, folks can use `Annotated[list[AnyMessage], add_messages]` as their state schema.
2025-08-06 14:17:50 +00:00
Sydney RunkleandGitHub 82978a8dd8 chore(prebuilt): revert tool arg injection refactor (#5842)
Reverts https://github.com/langchain-ai/langgraph/pull/5562

I anticipate that we want to do another pass at a refactor here in the
short term, but this makes it easier to adapt to new langchain core
message types for v0.4 support in the short term.
2025-08-06 10:12:08 -04:00
Sydney RunkleandGitHub 2920a9dd19 fix(langgraph): Tidy up AgentState (#5801)
Fixes https://github.com/langchain-ai/langgraph/issues/5784

* Removes usage of `is_last_step`, no longer needed with
`remaining_steps`
* Make `remaining_steps` `NotRequired` so that json schema doesn't
suggest need for user input
* Move `PregelScratchpad` to shared utils file to prevent circular
import issue (it's used from `channels/managed` and other pregel files).
* Ensures that managed values wrapped in `NotRequired` or `Required` are
still recognized!
2025-08-03 07:12:53 -04:00
Sydney RunkleandGitHub a2fe4df89b release: langgraph + prebuilt 0.6.3 (#5799) 2025-08-01 14:52:38 -04:00
08295ecadb chore(prebuilt): add supported input types for model in create_react_agent (#5748)
- **Description:** Update the type annotations in create_react_agent to
allow one to provide a callable for the model that uses bind_tools and
returns a Runnable[LanguageModelInput, BaseMessage]
  - **Issue:** #5739

---------

Co-authored-by: Eugene Yurtsev <eyurtsev@gmail.com>
2025-07-31 14:00:12 -04:00
Sydney RunkleandGitHub f43c806736 release(langgraph): 0.6.2 (#5750) 2025-07-30 20:35:27 +00:00
Sydney RunkleandGitHub 36f444dcb6 release(prebuilt): 0.6.2 (#5749) 2025-07-30 20:27:10 +00:00
Sydney RunkleandGitHub 781a115f92 fix(prebuilt): assign context_schema to config_schema with correct condition (#5746) 2025-07-30 20:08:45 +00:00
Eugene YurtsevandGitHub 72e418e4d0 release(prebuilt): 0.6.1 (#5713)
Release 0.6.1 allowing ToolNode to handle Command that removes all
messages
2025-07-29 20:39:42 +00:00
8cea8ae1de fix(prebuilt): update ToolNode to allow Command update to remove all messages (#5678)
## Description

Previously, when a tool returned `Command` to update the graph's state,
the `_validate_tool_command` method in `ToolNode` would raise a
`ValueError` if the `messages_update` list contained only a
`RemoveMessage(id=REMOVE_ALL_MESSAGES)` object. This was because the
validation logic expected a matching `ToolMessage` for the tool call and
did not account for this specific state-clearing scenario.

This commit modifies the validation logic to check if the
`messages_update` list contains a single
`RemoveMessage(id=REMOVE_ALL_MESSAGES)` element. If this condition is
met, the `ToolMessage` validation is bypassed, allowing a tool to clear
the entire message history without causing a validation error.

A new test case, `test_tool_node_command_remove_all_messages`, has been
added to `tests/test_tool_node.py` to verify this change and prevent
future regressions.

## Example

Here is a self-contained example that illustrates the problem and the
fix. Without this change, the code block for `Example 2` would raise a
`ValueError`.

```python
from typing import Annotated, List

from langchain_core.messages import (
    AIMessage,
    AnyMessage,
    HumanMessage,
    RemoveMessage,
    ToolMessage,
)
from langchain_core.tools import InjectedToolCallId, tool
from langchain_openai import ChatOpenAI
from langgraph.graph import END, StateGraph, add_messages
from langgraph.graph.message import REMOVE_ALL_MESSAGES
from langgraph.prebuilt import InjectedState, ToolNode
from langgraph.types import Command
from pydantic import BaseModel, Field


# Agent state tracks current and all messages
class AgentState(BaseModel):
    messages: Annotated[List[AnyMessage], add_messages] = Field(
        default_factory=list, description="Current conversation messages."
    )
    all_messages: Annotated[List[AnyMessage], add_messages] = Field(
        default_factory=list, description="All messages, including removed ones."
    )


# Tool to clear history if long enough, otherwise returns a warning
@tool
def clear_history_tool(
    state: Annotated[AgentState, InjectedState],
    tool_call_id: Annotated[str, InjectedToolCallId],
):
    """Clears message history if it's long enough."""
    if len(state.messages) < 3:
        return Command(
            update={
                "messages": [
                    ToolMessage(
                        "History is not long enough to be cleared. Please try again.",
                        tool_call_id=tool_call_id,
                    )
                ]
            }
        )
    else:
        return Command(
            update={
                "messages": [RemoveMessage(id=REMOVE_ALL_MESSAGES)],
                "all_messages": state.messages
                + [
                    ToolMessage(
                        "History has been successfully cleared.",
                        tool_call_id=tool_call_id,
                    )
                ],
            }
        )


# Bind the tool to the model
model = ChatOpenAI(model="gpt-4o-mini").bind_tools([clear_history_tool])


def model_node(state: AgentState):
    return {"messages": [model.invoke(state.messages)]}


# Build the agent graph
graph_builder = StateGraph(AgentState)
graph_builder.add_node("model", model_node)
graph_builder.add_node("tools", ToolNode([clear_history_tool]))
graph_builder.set_entry_point("model")
graph_builder.add_edge("model", "tools")
graph_builder.add_edge("tools", END)
graph = graph_builder.compile()


def print_messages(header, messages):
    print(f"\n{header}")
    for message in messages:
        message.pretty_print()


### Example 1: Not enough history to clear
state_1 = AgentState(
    messages=[HumanMessage(content="Please clear my message history.")]
)
output_1 = graph.invoke(state_1)
print_messages("First call: State 'messages'", output_1["messages"])
print_messages("First call: State 'all_messages'", output_1["all_messages"])

### Example 2: History is cleared
state_2 = AgentState(
    messages=[
        HumanMessage(content="Will this PR get merged?"),
        AIMessage(content="Maybe, if it's good enough."),
        HumanMessage(content="Please clear my message history."),
    ]
)
# Without the changes in this PR, the following line will raise a ValueError
output_2 = graph.invoke(state_2)
print_messages("Second call: State 'messages'", output_2["messages"])
print_messages("Second call: State 'all_messages'", output_2["all_messages"])
```

### Outputs

*Without the changes in this PR:*

```
First call: State 'messages'
================================ Human Message =================================

Please clear my message history.
================================== Ai Message ==================================
Tool Calls:
  clear_history_tool (ba421ac3-1e1a-4208-a8f6-c5500ee0abcc)
 Call ID: ba421ac3-1e1a-4208-a8f6-c5500ee0abcc
  Args:
================================= Tool Message =================================
Name: clear_history_tool

History is not long enough to be cleared. Please try again.

First call: State 'all_messages'


Traceback (most recent call last):
  File "main.py", line 114, in <module>
    output_2 = graph.invoke(state_2)
               ^^^^^^^^^^^^^^^^^^^^^
  File ".venv/lib/python3.11/site-packages/langgraph/pregel/__init__.py", line 2844, in invoke
    for chunk in self.stream(
  File ".venv/lib/python3.11/site-packages/langgraph/pregel/__init__.py", line 2534, in stream
    for _ in runner.tick(
  File ".venv/lib/python3.11/site-packages/langgraph/prebuilt/tool_node.py", line 241, in _func
    outputs = [
              ^
  File ".venv/lib/python3.11/concurrent/futures/_base.py", line 619, in result_iterator
    yield _result_or_cancel(fs.pop())
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".venv/lib/python3.11/concurrent/futures/_base.py", line 317, in _result_or_cancel
    return fut.result(timeout)
           ^^^^^^^^^^^^^^^^^^^
  File ".venv/lib/python3.11/concurrent/futures/_base.py", line 449, in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
  File ".venv/lib/python3.11/concurrent/futures/_base.py", line 401, in __get_result
    raise self._exception
  File ".venv/lib/python3.11/concurrent/futures/thread.py", line 58, in run
    result = self.fn(*self.args, **self.kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".venv/lib/python3.11/site-packages/langchain_core/runnables/config.py", line 555, in _wrapped_fn
    return contexts.pop().run(fn, *args)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".venv/lib/python3.11/site-packages/langgraph/prebuilt/tool_node.py", line 353, in _run_one
    return self._validate_tool_command(response, call, input_type)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".venv/lib/python3.11/site-packages/langgraph/prebuilt/tool_node.py", line 616, in _validate_tool_command
    raise ValueError(
ValueError: Expected to have a matching ToolMessage in Command.update for tool 'clear_history_tool', got: [RemoveMessage(content='', additional_kwargs={}, response_metadata={}, id='__remove_all__')]. Every tool call (LLM requesting to call a tool) in the message history MUST have a corresponding ToolMessage. You can fix it by modifying the tool to return `Command(update={"messages": [ToolMessage("Success", tool_call_id=tool_call_id), ...]}, ...)`.
```

*With the changes in this PR:*

```
First call: State 'messages'
================================ Human Message =================================

Please clear my message history.
================================== Ai Message ==================================
Tool Calls:
  clear_history_tool (ba421ac3-1e1a-4208-a8f6-c5500ee0abcc)
 Call ID: ba421ac3-1e1a-4208-a8f6-c5500ee0abcc
  Args:
================================= Tool Message =================================
Name: clear_history_tool

History is not long enough to be cleared. Please try again.

First call: State 'all_messages'


Second call: State 'messages'

Second call: State 'all_messages'
================================ Human Message =================================

Will this PR get merged?
================================== Ai Message ==================================

Maybe, if it's good enough.
================================ Human Message =================================

Please clear my message history.
================================== Ai Message ==================================
Tool Calls:
  clear_history_tool (499b1be3-6df1-493f-85e5-8d7e429dead8)
 Call ID: 499b1be3-6df1-493f-85e5-8d7e429dead8
  Args:
================================= Tool Message =================================
Name: clear_history_tool

History has been successfully cleared.
```

## Twitter handle

[@samuelpullely](https://x.com/samuelpullely)

---------

Co-authored-by: Eugene Yurtsev <eyurtsev@gmail.com>
2025-07-29 20:30:42 +00:00
Sydney RunkleandGitHub 85d2c7623a release(langgraph): 0.6.1 (#5712) 2025-07-29 20:25:49 +00:00
Sydney Runkle a8b3746356 release prep v0.6 2025-07-28 09:05:23 -04:00