langgraph[patch]: rename parameter (#3268)

Rename `tool_call_parallelism` (has not been released yet).
This commit is contained in:
ccurme
2025-01-31 19:36:55 +00:00
committed by GitHub
parent a37c4d6f49
commit 8d8e514924
2 changed files with 46 additions and 49 deletions
@@ -248,9 +248,7 @@ def create_react_agent(
interrupt_before: Optional[list[str]] = None,
interrupt_after: Optional[list[str]] = None,
debug: bool = False,
tool_call_parallelism: Literal[
"single_tool_node", "parallel_tool_nodes"
] = "single_tool_node",
version: Literal["v1", "v2"] = "v1",
) -> CompiledGraph:
"""Creates a graph that works with a chat model that utilizes tool calling.
@@ -300,12 +298,12 @@ def create_react_agent(
Should be one of the following: "agent", "tools".
This is useful if you want to return directly or run additional processing on an output.
debug: A flag indicating whether to enable debug mode.
tool_call_parallelism: Determines what state is sent to the tool node.
version: Determines the version of the graph to create.
Can be one of:
- `"single_tool_node"`: The tool node processes a single message. All tool
- `"v1"`: The tool node processes a single message. All tool
calls in the message are executed in parallel within the tool node.
- `"parallel_tool_nodes"`: The tool node processes a tool call.
- `"v2"`: The tool node processes a tool call.
Tool calls are distributed across multiple instances of the tool
node using the [Send](https://langchain-ai.github.io/langgraph/concepts/low_level/#send)
API.
@@ -584,10 +582,9 @@ def create_react_agent(
TimeoutError: Timed out at step 2
```
"""
if tool_call_parallelism not in ("single_tool_node", "parallel_tool_nodes"):
if version not in ("v1", "v2"):
raise ValueError(
f"Invalid version {tool_call_parallelism}. Supported versions are "
"'single_tool_node' and 'parallel_tool_nodes'."
f"Invalid version {version}. Supported versions are 'v1' and 'v2'."
)
if state_schema is not None:
@@ -772,9 +769,9 @@ def create_react_agent(
return END if response_format is None else "generate_structured_response"
# Otherwise if there is, we continue
else:
if tool_call_parallelism == "single_tool_node":
if version == "v1":
return "tools"
elif tool_call_parallelism == "parallel_tool_nodes":
elif version == "v2":
tool_calls = [
tool_node.inject_tool_args(call, state, store) # type: ignore[arg-type]
for call in last_message.tool_calls
+38 -38
View File
@@ -73,7 +73,7 @@ from tests.messages import _AnyIdHumanMessage, _AnyIdToolMessage
pytestmark = pytest.mark.anyio
REACT_TOOL_CALL_PARALLELISM = ["single_tool_node", "parallel_tool_nodes"]
REACT_TOOL_CALL_VERSIONS = ["v1", "v2"]
class FakeToolCallingModel(BaseChatModel):
@@ -150,9 +150,9 @@ class FakeToolCallingModel(BaseChatModel):
@pytest.mark.parametrize("checkpointer_name", ALL_CHECKPOINTERS_SYNC)
@pytest.mark.parametrize("tool_call_parallelism", REACT_TOOL_CALL_PARALLELISM)
@pytest.mark.parametrize("version", REACT_TOOL_CALL_VERSIONS)
def test_no_prompt(
request: pytest.FixtureRequest, checkpointer_name: str, tool_call_parallelism: str
request: pytest.FixtureRequest, checkpointer_name: str, version: str
) -> None:
checkpointer: BaseCheckpointSaver = request.getfixturevalue(
"checkpointer_" + checkpointer_name
@@ -163,7 +163,7 @@ def test_no_prompt(
model,
[],
checkpointer=checkpointer,
tool_call_parallelism=tool_call_parallelism,
version=version,
)
inputs = [HumanMessage("hi?")]
thread = {"configurable": {"thread_id": "123"}}
@@ -326,8 +326,8 @@ def test_runnable_prompt():
assert response == expected_response
@pytest.mark.parametrize("tool_call_parallelism", REACT_TOOL_CALL_PARALLELISM)
def test_prompt_with_store(tool_call_parallelism: str):
@pytest.mark.parametrize("version", REACT_TOOL_CALL_VERSIONS)
def test_prompt_with_store(version: str):
def add(a: int, b: int):
"""Adds a and b"""
return a + b
@@ -352,7 +352,7 @@ def test_prompt_with_store(tool_call_parallelism: str):
[add],
prompt=prompt,
store=in_memory_store,
tool_call_parallelism=tool_call_parallelism,
version=version,
)
response = agent.invoke(
{"messages": [("user", "hi")]}, {"configurable": {"user_id": "1"}}
@@ -365,7 +365,7 @@ def test_prompt_with_store(tool_call_parallelism: str):
[add],
prompt=prompt_no_store,
store=in_memory_store,
tool_call_parallelism=tool_call_parallelism,
version=version,
)
response = agent.invoke(
{"messages": [("user", "hi")]}, {"configurable": {"user_id": "2"}}
@@ -416,8 +416,8 @@ async def test_prompt_with_store_async():
@pytest.mark.parametrize("tool_style", ["openai", "anthropic"])
@pytest.mark.parametrize("tool_call_parallelism", REACT_TOOL_CALL_PARALLELISM)
def test_model_with_tools(tool_style: str, tool_call_parallelism: str):
@pytest.mark.parametrize("version", REACT_TOOL_CALL_VERSIONS)
def test_model_with_tools(tool_style: str, version: str):
model = FakeToolCallingModel(tool_style=tool_style)
@dec_tool
@@ -434,7 +434,7 @@ def test_model_with_tools(tool_style: str, tool_call_parallelism: str):
agent = create_react_agent(
model.bind_tools([tool1, tool2]),
[tool1, tool2],
tool_call_parallelism=tool_call_parallelism,
version=version,
)
result = agent.nodes["tools"].invoke(
{
@@ -602,8 +602,8 @@ def test__infer_handled_types() -> None:
not IS_LANGCHAIN_CORE_030_OR_GREATER,
reason="Pydantic v1 is required for this test to pass in langchain-core < 0.3",
)
@pytest.mark.parametrize("tool_call_parallelism", REACT_TOOL_CALL_PARALLELISM)
def test_react_agent_with_structured_response(tool_call_parallelism: str) -> None:
@pytest.mark.parametrize("version", REACT_TOOL_CALL_VERSIONS)
def test_react_agent_with_structured_response(version: str) -> None:
class WeatherResponse(BaseModel):
temperature: float = Field(description="The temperature in fahrenheit")
@@ -622,7 +622,7 @@ def test_react_agent_with_structured_response(tool_call_parallelism: str) -> Non
model,
[get_weather],
response_format=response_format,
tool_call_parallelism=tool_call_parallelism,
version=version,
)
response = agent.invoke({"messages": [HumanMessage("What's the weather?")]})
assert response["structured_response"] == expected_structured_response
@@ -1070,8 +1070,8 @@ def test_tool_node_incorrect_tool_name():
assert tool_message.tool_call_id == "some 0"
@pytest.mark.parametrize("tool_call_parallelism", REACT_TOOL_CALL_PARALLELISM)
def test_tool_node_node_interrupt(tool_call_parallelism: str):
@pytest.mark.parametrize("version", REACT_TOOL_CALL_VERSIONS)
def test_tool_node_node_interrupt(version: str):
def tool_normal(some_val: int) -> str:
"""Tool docstring."""
return "normal"
@@ -1120,7 +1120,7 @@ def test_tool_node_node_interrupt(tool_call_parallelism: str):
model,
[tool_interrupt, tool_normal],
checkpointer=checkpointer,
tool_call_parallelism=tool_call_parallelism,
version=version,
)
result = agent.invoke({"messages": [HumanMessage("hi?")]}, config)
expected_messages = [
@@ -1145,10 +1145,10 @@ def test_tool_node_node_interrupt(tool_call_parallelism: str):
),
_AnyIdToolMessage(content="normal", name="tool_normal", tool_call_id="2"),
]
if tool_call_parallelism == "single_tool_node":
if version == "v1":
# Interrupt blocks second tool result
assert result["messages"] == expected_messages[:-1]
elif tool_call_parallelism == "parallel_tool_nodes":
elif version == "v2":
assert result["messages"] == expected_messages
state = agent.get_state(config)
@@ -1723,8 +1723,8 @@ async def test_tool_node_command_list_input():
not IS_LANGCHAIN_CORE_030_OR_GREATER,
reason="Langchain core 0.3.0 or greater is required",
)
@pytest.mark.parametrize("tool_call_parallelism", REACT_TOOL_CALL_PARALLELISM)
def test_react_agent_update_state(tool_call_parallelism: str):
@pytest.mark.parametrize("version", REACT_TOOL_CALL_VERSIONS)
def test_react_agent_update_state(version: str):
from langchain_core.tools.base import InjectedToolCallId
class State(AgentState):
@@ -1762,7 +1762,7 @@ def test_react_agent_update_state(tool_call_parallelism: str):
state_schema=State,
prompt=prompt,
checkpointer=checkpointer,
tool_call_parallelism=tool_call_parallelism,
version=version,
)
config = {"configurable": {"thread_id": "1"}}
# run until interrpupted
@@ -1782,8 +1782,8 @@ def test_react_agent_update_state(tool_call_parallelism: str):
not IS_LANGCHAIN_CORE_030_OR_GREATER,
reason="Langchain core 0.3.0 or greater is required",
)
@pytest.mark.parametrize("tool_call_parallelism", REACT_TOOL_CALL_PARALLELISM)
def test_react_agent_parallel_tool_calls(tool_call_parallelism: str):
@pytest.mark.parametrize("version", REACT_TOOL_CALL_VERSIONS)
def test_react_agent_parallel_tool_calls(version: str):
human_assistance_execution_count = 0
@dec_tool
@@ -1816,7 +1816,7 @@ def test_react_agent_parallel_tool_calls(tool_call_parallelism: str):
model,
[human_assistance, get_weather],
checkpointer=checkpointer,
tool_call_parallelism=tool_call_parallelism,
version=version,
)
config = {"configurable": {"thread_id": "1"}}
query = "Get user assistance and also check the weather"
@@ -1826,12 +1826,12 @@ def test_react_agent_parallel_tool_calls(tool_call_parallelism: str):
):
message_types.append([message.type for message in event["messages"]])
if tool_call_parallelism == "single_tool_node":
if version == "v1":
assert message_types == [
["human"],
["human", "ai"],
]
elif tool_call_parallelism == "parallel_tool_nodes":
elif version == "v2":
assert message_types == [
["human"],
["human", "ai"],
@@ -1851,10 +1851,10 @@ def test_react_agent_parallel_tool_calls(tool_call_parallelism: str):
["human", "ai", "tool", "tool", "ai"],
]
if tool_call_parallelism == "single_tool_node":
if version == "v1":
assert human_assistance_execution_count == 1
assert get_weather_execution_count == 2
elif tool_call_parallelism == "parallel_tool_nodes":
elif version == "v2":
assert human_assistance_execution_count == 1
assert get_weather_execution_count == 1
@@ -2047,8 +2047,8 @@ def test_tool_node_inject_state(schema_: Type[T]) -> None:
assert tool_message.content == "hi?"
@pytest.mark.parametrize("tool_call_parallelism", REACT_TOOL_CALL_PARALLELISM)
def test_create_react_agent_inject_vars(tool_call_parallelism: str) -> None:
@pytest.mark.parametrize("version", REACT_TOOL_CALL_VERSIONS)
def test_create_react_agent_inject_vars(version: str) -> None:
class AgentStateExtraKey(AgentState):
foo: int
@@ -2077,7 +2077,7 @@ def test_create_react_agent_inject_vars(tool_call_parallelism: str) -> None:
[tool1],
state_schema=AgentStateExtraKey,
store=store,
tool_call_parallelism=tool_call_parallelism,
version=version,
)
input_message = HumanMessage("hi")
result = agent.invoke({"messages": [input_message], "foo": 2})
@@ -2223,8 +2223,8 @@ def test_tool_node_messages_key() -> None:
]
@pytest.mark.parametrize("tool_call_parallelism", REACT_TOOL_CALL_PARALLELISM)
async def test_return_direct(tool_call_parallelism: str) -> None:
@pytest.mark.parametrize("version", REACT_TOOL_CALL_VERSIONS)
async def test_return_direct(version: str) -> None:
@dec_tool(return_direct=True)
def tool_return_direct(input: str) -> str:
"""A tool that returns directly."""
@@ -2251,7 +2251,7 @@ async def test_return_direct(tool_call_parallelism: str) -> None:
agent = create_react_agent(
model,
[tool_return_direct, tool_normal],
tool_call_parallelism=tool_call_parallelism,
version=version,
)
# Test direct return for tool_return_direct
@@ -2346,8 +2346,8 @@ def test_inspect_react() -> None:
inspect.getclosurevars(agent.nodes["agent"].bound.func)
@pytest.mark.parametrize("tool_call_parallelism", REACT_TOOL_CALL_PARALLELISM)
def test_react_with_subgraph_tools(tool_call_parallelism: str) -> None:
@pytest.mark.parametrize("version", REACT_TOOL_CALL_VERSIONS)
def test_react_with_subgraph_tools(version: str) -> None:
class State(TypedDict):
a: int
b: int
@@ -2400,7 +2400,7 @@ def test_react_with_subgraph_tools(tool_call_parallelism: str) -> None:
model,
tool_node,
checkpointer=checkpointer,
tool_call_parallelism=tool_call_parallelism,
version=version,
)
result = agent.invoke(
{"messages": [HumanMessage(content="What's 2 + 3 and 2 * 3?")]},