langgraph-prebuilt 0.2.1__tar.gz → 0.2.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {langgraph_prebuilt-0.2.1 → langgraph_prebuilt-0.2.3}/PKG-INFO +1 -1
- {langgraph_prebuilt-0.2.1 → langgraph_prebuilt-0.2.3}/langgraph/prebuilt/chat_agent_executor.py +10 -4
- {langgraph_prebuilt-0.2.1 → langgraph_prebuilt-0.2.3}/pyproject.toml +1 -1
- {langgraph_prebuilt-0.2.1 → langgraph_prebuilt-0.2.3}/tests/model.py +4 -1
- {langgraph_prebuilt-0.2.1 → langgraph_prebuilt-0.2.3}/tests/test_react_agent.py +81 -3
- {langgraph_prebuilt-0.2.1 → langgraph_prebuilt-0.2.3}/uv.lock +743 -743
- {langgraph_prebuilt-0.2.1 → langgraph_prebuilt-0.2.3}/.gitignore +0 -0
- {langgraph_prebuilt-0.2.1 → langgraph_prebuilt-0.2.3}/LICENSE +0 -0
- {langgraph_prebuilt-0.2.1 → langgraph_prebuilt-0.2.3}/Makefile +0 -0
- {langgraph_prebuilt-0.2.1 → langgraph_prebuilt-0.2.3}/README.md +0 -0
- {langgraph_prebuilt-0.2.1 → langgraph_prebuilt-0.2.3}/langgraph/prebuilt/__init__.py +0 -0
- {langgraph_prebuilt-0.2.1 → langgraph_prebuilt-0.2.3}/langgraph/prebuilt/interrupt.py +0 -0
- {langgraph_prebuilt-0.2.1 → langgraph_prebuilt-0.2.3}/langgraph/prebuilt/py.typed +0 -0
- {langgraph_prebuilt-0.2.1 → langgraph_prebuilt-0.2.3}/langgraph/prebuilt/tool_node.py +0 -0
- {langgraph_prebuilt-0.2.1 → langgraph_prebuilt-0.2.3}/langgraph/prebuilt/tool_validator.py +0 -0
- {langgraph_prebuilt-0.2.1 → langgraph_prebuilt-0.2.3}/tests/__init__.py +0 -0
- {langgraph_prebuilt-0.2.1 → langgraph_prebuilt-0.2.3}/tests/__snapshots__/test_react_agent_graph.ambr +0 -0
- {langgraph_prebuilt-0.2.1 → langgraph_prebuilt-0.2.3}/tests/any_str.py +0 -0
- {langgraph_prebuilt-0.2.1 → langgraph_prebuilt-0.2.3}/tests/compose-postgres.yml +0 -0
- {langgraph_prebuilt-0.2.1 → langgraph_prebuilt-0.2.3}/tests/conftest.py +0 -0
- {langgraph_prebuilt-0.2.1 → langgraph_prebuilt-0.2.3}/tests/conftest_checkpointer.py +0 -0
- {langgraph_prebuilt-0.2.1 → langgraph_prebuilt-0.2.3}/tests/conftest_store.py +0 -0
- {langgraph_prebuilt-0.2.1 → langgraph_prebuilt-0.2.3}/tests/memory_assert.py +0 -0
- {langgraph_prebuilt-0.2.1 → langgraph_prebuilt-0.2.3}/tests/messages.py +0 -0
- {langgraph_prebuilt-0.2.1 → langgraph_prebuilt-0.2.3}/tests/test_react_agent_graph.py +0 -0
- {langgraph_prebuilt-0.2.1 → langgraph_prebuilt-0.2.3}/tests/test_tool_node.py +0 -0
- {langgraph_prebuilt-0.2.1 → langgraph_prebuilt-0.2.3}/tests/test_validation_node.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: langgraph-prebuilt
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
4
4
|
Summary: Library with high-level APIs for creating and executing LangGraph agents and tools.
|
|
5
5
|
Project-URL: Repository, https://www.github.com/langchain-ai/langgraph
|
|
6
6
|
License-Expression: MIT
|
{langgraph_prebuilt-0.2.1 → langgraph_prebuilt-0.2.3}/langgraph/prebuilt/chat_agent_executor.py
RENAMED
|
@@ -140,7 +140,9 @@ def _get_prompt_runnable(prompt: Optional[Prompt]) -> Runnable:
|
|
|
140
140
|
return prompt_runnable
|
|
141
141
|
|
|
142
142
|
|
|
143
|
-
def _should_bind_tools(
|
|
143
|
+
def _should_bind_tools(
|
|
144
|
+
model: LanguageModelLike, tools: Sequence[BaseTool], num_builtin: int = 0
|
|
145
|
+
) -> bool:
|
|
144
146
|
if isinstance(model, RunnableSequence):
|
|
145
147
|
model = next(
|
|
146
148
|
(
|
|
@@ -158,9 +160,10 @@ def _should_bind_tools(model: LanguageModelLike, tools: Sequence[BaseTool]) -> b
|
|
|
158
160
|
return True
|
|
159
161
|
|
|
160
162
|
bound_tools = model.kwargs["tools"]
|
|
161
|
-
if len(tools) != len(bound_tools):
|
|
163
|
+
if len(tools) != len(bound_tools) - num_builtin:
|
|
162
164
|
raise ValueError(
|
|
163
165
|
"Number of tools in the model.bind_tools() and tools passed to create_react_agent must match"
|
|
166
|
+
f" Got {len(tools)} tools, expected {len(bound_tools) - num_builtin}"
|
|
164
167
|
)
|
|
165
168
|
|
|
166
169
|
tool_names = set(tool.name for tool in tools)
|
|
@@ -444,9 +447,8 @@ def create_react_agent(
|
|
|
444
447
|
tool_calling_enabled = len(tool_classes) > 0
|
|
445
448
|
|
|
446
449
|
if (
|
|
447
|
-
_should_bind_tools(model, tool_classes)
|
|
450
|
+
_should_bind_tools(model, tool_classes, num_builtin=len(llm_builtin_tools))
|
|
448
451
|
and len(tool_classes) > 0
|
|
449
|
-
or (len(llm_builtin_tools) > 0)
|
|
450
452
|
):
|
|
451
453
|
model = cast(BaseChatModel, model).bind_tools(tool_classes + llm_builtin_tools) # type: ignore[operator]
|
|
452
454
|
|
|
@@ -727,6 +729,10 @@ def create_react_agent(
|
|
|
727
729
|
]
|
|
728
730
|
|
|
729
731
|
if pending_tool_calls:
|
|
732
|
+
pending_tool_calls = [
|
|
733
|
+
tool_node.inject_tool_args(call, state, store) # type: ignore[arg-type]
|
|
734
|
+
for call in pending_tool_calls
|
|
735
|
+
]
|
|
730
736
|
return [Send("tools", [tool_call]) for tool_call in pending_tool_calls]
|
|
731
737
|
elif isinstance(messages[-1], ToolMessage):
|
|
732
738
|
return entrypoint
|
|
@@ -73,9 +73,12 @@ class FakeToolCallingModel(BaseChatModel):
|
|
|
73
73
|
|
|
74
74
|
tool_dicts = []
|
|
75
75
|
for tool in tools:
|
|
76
|
+
if isinstance(tool, dict):
|
|
77
|
+
tool_dicts.append(tool)
|
|
78
|
+
continue
|
|
76
79
|
if not isinstance(tool, BaseTool):
|
|
77
80
|
raise TypeError(
|
|
78
|
-
"Only BaseTool is supported by FakeToolCallingModel.bind_tools"
|
|
81
|
+
"Only BaseTool and dict is supported by FakeToolCallingModel.bind_tools"
|
|
79
82
|
)
|
|
80
83
|
|
|
81
84
|
# NOTE: this is a simplified tool spec for testing purposes only
|
|
@@ -275,7 +275,8 @@ async def test_prompt_with_store_async():
|
|
|
275
275
|
|
|
276
276
|
@pytest.mark.parametrize("tool_style", ["openai", "anthropic"])
|
|
277
277
|
@pytest.mark.parametrize("version", REACT_TOOL_CALL_VERSIONS)
|
|
278
|
-
|
|
278
|
+
@pytest.mark.parametrize("include_builtin", [True, False])
|
|
279
|
+
def test_model_with_tools(tool_style: str, version: str, include_builtin: bool):
|
|
279
280
|
model = FakeToolCallingModel(tool_style=tool_style)
|
|
280
281
|
|
|
281
282
|
@dec_tool
|
|
@@ -288,10 +289,27 @@ def test_model_with_tools(tool_style: str, version: str):
|
|
|
288
289
|
"""Tool 2 docstring."""
|
|
289
290
|
return f"Tool 2: {some_val}"
|
|
290
291
|
|
|
292
|
+
tools = [tool1, tool2]
|
|
293
|
+
if include_builtin:
|
|
294
|
+
tools.append(
|
|
295
|
+
{
|
|
296
|
+
"type": "mcp",
|
|
297
|
+
"server_label": "atest_sever",
|
|
298
|
+
"server_url": "https://some.mcp.somewhere.com/sse",
|
|
299
|
+
"headers": {"foo": "bar"},
|
|
300
|
+
"allowed_tools": [
|
|
301
|
+
"mcp_tool_1",
|
|
302
|
+
"set_active_account",
|
|
303
|
+
"get_url_markdown",
|
|
304
|
+
"get_url_screenshot",
|
|
305
|
+
],
|
|
306
|
+
"require_approval": "never",
|
|
307
|
+
}
|
|
308
|
+
)
|
|
291
309
|
# check valid agent constructor
|
|
292
310
|
agent = create_react_agent(
|
|
293
|
-
model.bind_tools(
|
|
294
|
-
|
|
311
|
+
model.bind_tools(tools),
|
|
312
|
+
tools,
|
|
295
313
|
version=version,
|
|
296
314
|
)
|
|
297
315
|
result = agent.nodes["tools"].invoke(
|
|
@@ -1540,3 +1558,63 @@ def test_post_model_hook_with_structured_output() -> None:
|
|
|
1540
1558
|
}
|
|
1541
1559
|
},
|
|
1542
1560
|
]
|
|
1561
|
+
|
|
1562
|
+
|
|
1563
|
+
@pytest.mark.parametrize(
|
|
1564
|
+
"state_schema", [AgentStateExtraKey, AgentStateExtraKeyPydantic]
|
|
1565
|
+
)
|
|
1566
|
+
def test_create_react_agent_inject_vars_with_post_model_hook(
|
|
1567
|
+
state_schema: StateSchemaType,
|
|
1568
|
+
) -> None:
|
|
1569
|
+
store = InMemoryStore()
|
|
1570
|
+
namespace = ("test",)
|
|
1571
|
+
store.put(namespace, "test_key", {"bar": 3})
|
|
1572
|
+
|
|
1573
|
+
if issubclass(state_schema, AgentStatePydantic):
|
|
1574
|
+
|
|
1575
|
+
def tool1(
|
|
1576
|
+
some_val: int,
|
|
1577
|
+
state: Annotated[AgentStateExtraKeyPydantic, InjectedState],
|
|
1578
|
+
store: Annotated[BaseStore, InjectedStore()],
|
|
1579
|
+
) -> str:
|
|
1580
|
+
"""Tool 1 docstring."""
|
|
1581
|
+
store_val = store.get(namespace, "test_key").value["bar"]
|
|
1582
|
+
return some_val + state.foo + store_val
|
|
1583
|
+
else:
|
|
1584
|
+
|
|
1585
|
+
def tool1(
|
|
1586
|
+
some_val: int,
|
|
1587
|
+
state: Annotated[dict, InjectedState],
|
|
1588
|
+
store: Annotated[BaseStore, InjectedStore()],
|
|
1589
|
+
) -> str:
|
|
1590
|
+
"""Tool 1 docstring."""
|
|
1591
|
+
store_val = store.get(namespace, "test_key").value["bar"]
|
|
1592
|
+
return some_val + state["foo"] + store_val
|
|
1593
|
+
|
|
1594
|
+
tool_call = {
|
|
1595
|
+
"name": "tool1",
|
|
1596
|
+
"args": {"some_val": 1},
|
|
1597
|
+
"id": "some 0",
|
|
1598
|
+
"type": "tool_call",
|
|
1599
|
+
}
|
|
1600
|
+
|
|
1601
|
+
def post_model_hook(state: dict) -> None:
|
|
1602
|
+
return
|
|
1603
|
+
|
|
1604
|
+
model = FakeToolCallingModel(tool_calls=[[tool_call], []])
|
|
1605
|
+
agent = create_react_agent(
|
|
1606
|
+
model,
|
|
1607
|
+
[tool1],
|
|
1608
|
+
state_schema=state_schema,
|
|
1609
|
+
store=store,
|
|
1610
|
+
post_model_hook=post_model_hook,
|
|
1611
|
+
)
|
|
1612
|
+
input_message = HumanMessage("hi")
|
|
1613
|
+
result = agent.invoke({"messages": [input_message], "foo": 2})
|
|
1614
|
+
assert result["messages"] == [
|
|
1615
|
+
input_message,
|
|
1616
|
+
AIMessage(content="hi", tool_calls=[tool_call], id="0"),
|
|
1617
|
+
_AnyIdToolMessage(content="6", name="tool1", tool_call_id="some 0"),
|
|
1618
|
+
AIMessage("hi-hi-6", id="1"),
|
|
1619
|
+
]
|
|
1620
|
+
assert result["foo"] == 2
|