mirror of
https://github.com/hwchase17/langchain.git
synced 2026-07-11 09:26:29 +00:00
feat(core): add subagent_name attribute to BaseTool
Declares the subagent a tool dispatches to. Accepts a static string or a Callable[[ToolCall], str] for dynamic resolution at dispatch time. This is a pure attribute addition with no behavior. Downstream consumers (langgraph ToolNode, langchain create_agent's typed projection) will read this attribute to surface subagent identity on streaming lifecycle events.
This commit is contained in:
@@ -530,6 +530,20 @@ class ChildTool(BaseTool):
|
||||
```
|
||||
"""
|
||||
|
||||
subagent_name: str | Callable[[ToolCall], str] | None = None
|
||||
"""Declared name of the subagent this tool dispatches to, if any.
|
||||
|
||||
A static string declares a fixed dispatch target (one tool -> one subagent).
|
||||
A callable resolves the name from the parsed `ToolCall` at dispatch time,
|
||||
enabling registry-style dispatching (one tool -> many subagents based on
|
||||
LLM-supplied args).
|
||||
|
||||
Read by `ToolNode` at dispatch time and surfaced on the wire as
|
||||
`LifecyclePayload.graphName`. Purely declarative: the framework stamps the
|
||||
resolved value into runtime config metadata; consumers project it onto
|
||||
typed surfaces. Setting this does not change tool execution behavior.
|
||||
"""
|
||||
|
||||
def __init__(self, **kwargs: Any) -> None:
|
||||
"""Initialize the tool.
|
||||
|
||||
|
||||
@@ -3741,3 +3741,42 @@ def test_tool_invoke_returns_list_of_mixin() -> None:
|
||||
assert isinstance(result, list)
|
||||
assert len(result) == 3
|
||||
assert all(isinstance(m, ToolMessage) for m in result)
|
||||
|
||||
|
||||
# --- subagent_name attribute tests ---
|
||||
|
||||
|
||||
class _SubagentNameDummyTool(BaseTool):
|
||||
"""Minimal BaseTool subclass for subagent_name attribute tests."""
|
||||
|
||||
name: str = "dummy"
|
||||
description: str = "A dummy tool used in subagent_name tests."
|
||||
|
||||
def _run(self, *args: Any, **kwargs: Any) -> str:
|
||||
return "dummy result"
|
||||
|
||||
|
||||
def test_basetool_subagent_name_default_none() -> None:
|
||||
tool = _SubagentNameDummyTool()
|
||||
assert tool.subagent_name is None
|
||||
|
||||
|
||||
def test_basetool_subagent_name_accepts_static_string() -> None:
|
||||
tool = _SubagentNameDummyTool(subagent_name="weather_agent")
|
||||
assert tool.subagent_name == "weather_agent"
|
||||
|
||||
|
||||
def test_basetool_subagent_name_accepts_callable() -> None:
|
||||
def resolver(call: ToolCall) -> str:
|
||||
return str(call["args"]["subagent_type"])
|
||||
|
||||
tool = _SubagentNameDummyTool(subagent_name=resolver)
|
||||
assert tool.subagent_name is resolver
|
||||
fake_call: ToolCall = {
|
||||
"name": "task",
|
||||
"args": {"subagent_type": "researcher"},
|
||||
"id": "id-1",
|
||||
"type": "tool_call",
|
||||
}
|
||||
assert callable(tool.subagent_name)
|
||||
assert tool.subagent_name(fake_call) == "researcher"
|
||||
|
||||
Reference in New Issue
Block a user