From 7fb81863b0cfccd33933843be78d8676514d92c2 Mon Sep 17 00:00:00 2001 From: Eugene Yurtsev Date: Thu, 16 Oct 2025 17:15:06 -0400 Subject: [PATCH] Revert "fix(langchain): conditional edge from tools to end (#33520)" This reverts commit e10d99b72801fe84e33f2b3ab2ef9dc4fbf2c483. --- libs/langchain_v1/langchain/agents/factory.py | 11 +-- .../__snapshots__/test_middleware_agent.ambr | 7 ++ .../test_return_direct_graph.ambr | 69 ------------------ .../agents/test_return_direct_graph.py | 73 ------------------- 4 files changed, 8 insertions(+), 152 deletions(-) delete mode 100644 libs/langchain_v1/tests/unit_tests/agents/__snapshots__/test_return_direct_graph.ambr delete mode 100644 libs/langchain_v1/tests/unit_tests/agents/test_return_direct_graph.py diff --git a/libs/langchain_v1/langchain/agents/factory.py b/libs/langchain_v1/langchain/agents/factory.py index 3af577d0a42f0..5c0d34529e795 100644 --- a/libs/langchain_v1/langchain/agents/factory.py +++ b/libs/langchain_v1/langchain/agents/factory.py @@ -1225,15 +1225,6 @@ async def amodel_node(state: AgentState, runtime: Runtime[ContextT]) -> dict[str graph.add_edge(START, entry_node) # add conditional edges only if tools exist if tool_node is not None: - # Only include exit_node in destinations if any tool has return_direct=True - # or if there are structured output tools - tools_to_model_destinations = [loop_entry_node] - if ( - any(tool.return_direct for tool in tool_node.tools_by_name.values()) - or structured_output_tools - ): - tools_to_model_destinations.append(exit_node) - graph.add_conditional_edges( "tools", _make_tools_to_model_edge( @@ -1242,7 +1233,7 @@ async def amodel_node(state: AgentState, runtime: Runtime[ContextT]) -> dict[str structured_output_tools=structured_output_tools, end_destination=exit_node, ), - tools_to_model_destinations, + [loop_entry_node, exit_node], ) # base destinations are tools and exit_node diff --git a/libs/langchain_v1/tests/unit_tests/agents/__snapshots__/test_middleware_agent.ambr b/libs/langchain_v1/tests/unit_tests/agents/__snapshots__/test_middleware_agent.ambr index 75be381108bcf..6f1e17badccbe 100644 --- a/libs/langchain_v1/tests/unit_tests/agents/__snapshots__/test_middleware_agent.ambr +++ b/libs/langchain_v1/tests/unit_tests/agents/__snapshots__/test_middleware_agent.ambr @@ -20,6 +20,7 @@ __start__ --> NoopZero\2ebefore_agent; model -.-> NoopTwo\2eafter_agent; model -.-> tools; + tools -.-> NoopTwo\2eafter_agent; tools -.-> model; NoopOne\2eafter_agent --> __end__; classDef default fill:#f2f0ff,line-height:1.2 @@ -342,6 +343,7 @@ __start__ --> NoopSeven\2ebefore_model; model --> NoopEight\2eafter_model; tools -.-> NoopSeven\2ebefore_model; + tools -.-> __end__; classDef default fill:#f2f0ff,line-height:1.2 classDef first fill-opacity:0 classDef last fill:#bfb6fc @@ -374,6 +376,7 @@ __start__ --> NoopSeven\2ebefore_model; model --> NoopEight\2eafter_model; tools -.-> NoopSeven\2ebefore_model; + tools -.-> __end__; classDef default fill:#f2f0ff,line-height:1.2 classDef first fill-opacity:0 classDef last fill:#bfb6fc @@ -406,6 +409,7 @@ __start__ --> NoopSeven\2ebefore_model; model --> NoopEight\2eafter_model; tools -.-> NoopSeven\2ebefore_model; + tools -.-> __end__; classDef default fill:#f2f0ff,line-height:1.2 classDef first fill-opacity:0 classDef last fill:#bfb6fc @@ -438,6 +442,7 @@ __start__ --> NoopSeven\2ebefore_model; model --> NoopEight\2eafter_model; tools -.-> NoopSeven\2ebefore_model; + tools -.-> __end__; classDef default fill:#f2f0ff,line-height:1.2 classDef first fill-opacity:0 classDef last fill:#bfb6fc @@ -470,6 +475,7 @@ __start__ --> NoopSeven\2ebefore_model; model --> NoopEight\2eafter_model; tools -.-> NoopSeven\2ebefore_model; + tools -.-> __end__; classDef default fill:#f2f0ff,line-height:1.2 classDef first fill-opacity:0 classDef last fill:#bfb6fc @@ -491,6 +497,7 @@ __start__ --> model; model -.-> __end__; model -.-> tools; + tools -.-> __end__; tools -.-> model; classDef default fill:#f2f0ff,line-height:1.2 classDef first fill-opacity:0 diff --git a/libs/langchain_v1/tests/unit_tests/agents/__snapshots__/test_return_direct_graph.ambr b/libs/langchain_v1/tests/unit_tests/agents/__snapshots__/test_return_direct_graph.ambr deleted file mode 100644 index f3e223f8df6b2..0000000000000 --- a/libs/langchain_v1/tests/unit_tests/agents/__snapshots__/test_return_direct_graph.ambr +++ /dev/null @@ -1,69 +0,0 @@ -# serializer version: 1 -# name: test_agent_graph_with_mixed_tools - ''' - --- - config: - flowchart: - curve: linear - --- - graph TD; - __start__([

__start__

]):::first - model(model) - tools(tools) - __end__([

__end__

]):::last - __start__ --> model; - model -.-> __end__; - model -.-> tools; - tools -.-> __end__; - tools -.-> model; - classDef default fill:#f2f0ff,line-height:1.2 - classDef first fill-opacity:0 - classDef last fill:#bfb6fc - - ''' -# --- -# name: test_agent_graph_with_return_direct_tool - ''' - --- - config: - flowchart: - curve: linear - --- - graph TD; - __start__([

__start__

]):::first - model(model) - tools(tools) - __end__([

__end__

]):::last - __start__ --> model; - model -.-> __end__; - model -.-> tools; - tools -.-> __end__; - tools -.-> model; - classDef default fill:#f2f0ff,line-height:1.2 - classDef first fill-opacity:0 - classDef last fill:#bfb6fc - - ''' -# --- -# name: test_agent_graph_without_return_direct_tools - ''' - --- - config: - flowchart: - curve: linear - --- - graph TD; - __start__([

__start__

]):::first - model(model) - tools(tools) - __end__([

__end__

]):::last - __start__ --> model; - model -.-> __end__; - model -.-> tools; - tools -.-> model; - classDef default fill:#f2f0ff,line-height:1.2 - classDef first fill-opacity:0 - classDef last fill:#bfb6fc - - ''' -# --- diff --git a/libs/langchain_v1/tests/unit_tests/agents/test_return_direct_graph.py b/libs/langchain_v1/tests/unit_tests/agents/test_return_direct_graph.py deleted file mode 100644 index 6907aa01a8c03..0000000000000 --- a/libs/langchain_v1/tests/unit_tests/agents/test_return_direct_graph.py +++ /dev/null @@ -1,73 +0,0 @@ -"""Tests for return_direct tool graph structure.""" - -from langchain_core.tools import tool -from syrupy.assertion import SnapshotAssertion - -from langchain.agents.factory import create_agent - -from .model import FakeToolCallingModel - - -def test_agent_graph_without_return_direct_tools(snapshot: SnapshotAssertion) -> None: - """Test that graph WITHOUT return_direct tools does NOT have edge from tools to end.""" - - @tool - def normal_tool(input_string: str) -> str: - """A normal tool without return_direct.""" - return input_string - - agent = create_agent( - model=FakeToolCallingModel(), - tools=[normal_tool], - system_prompt="You are a helpful assistant.", - ) - - # The mermaid diagram should NOT include an edge from tools to __end__ - # when no tools have return_direct=True - mermaid_diagram = agent.get_graph().draw_mermaid() - assert mermaid_diagram == snapshot - - -def test_agent_graph_with_return_direct_tool(snapshot: SnapshotAssertion) -> None: - """Test that graph WITH return_direct tools has correct edge from tools to end.""" - - @tool(return_direct=True) - def return_direct_tool(input_string: str) -> str: - """A tool with return_direct=True.""" - return input_string - - agent = create_agent( - model=FakeToolCallingModel(), - tools=[return_direct_tool], - system_prompt="You are a helpful assistant.", - ) - - # The mermaid diagram SHOULD include an edge from tools to __end__ - # when at least one tool has return_direct=True - mermaid_diagram = agent.get_graph().draw_mermaid() - assert mermaid_diagram == snapshot - - -def test_agent_graph_with_mixed_tools(snapshot: SnapshotAssertion) -> None: - """Test that graph with mixed tools (some return_direct, some not) has correct edges.""" - - @tool(return_direct=True) - def return_direct_tool(input_string: str) -> str: - """A tool with return_direct=True.""" - return input_string - - @tool - def normal_tool(input_string: str) -> str: - """A normal tool without return_direct.""" - return input_string - - agent = create_agent( - model=FakeToolCallingModel(), - tools=[return_direct_tool, normal_tool], - system_prompt="You are a helpful assistant.", - ) - - # The mermaid diagram SHOULD include an edge from tools to __end__ - # because at least one tool has return_direct=True - mermaid_diagram = agent.get_graph().draw_mermaid() - assert mermaid_diagram == snapshot