langchain-dev-utils 1.3.2__py3-none-any.whl → 1.3.3__py3-none-any.whl
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.
- langchain_dev_utils/__init__.py +1 -1
- langchain_dev_utils/agents/__init__.py +2 -2
- langchain_dev_utils/agents/middleware/handoffs.py +17 -2
- langchain_dev_utils/agents/wrap.py +138 -4
- {langchain_dev_utils-1.3.2.dist-info → langchain_dev_utils-1.3.3.dist-info}/METADATA +1 -1
- {langchain_dev_utils-1.3.2.dist-info → langchain_dev_utils-1.3.3.dist-info}/RECORD +8 -8
- {langchain_dev_utils-1.3.2.dist-info → langchain_dev_utils-1.3.3.dist-info}/WHEEL +0 -0
- {langchain_dev_utils-1.3.2.dist-info → langchain_dev_utils-1.3.3.dist-info}/licenses/LICENSE +0 -0
langchain_dev_utils/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "1.3.
|
|
1
|
+
__version__ = "1.3.3"
|
|
@@ -78,7 +78,19 @@ def _transform_agent_config(
|
|
|
78
78
|
dict[str, AgentConfig]: The transformed agent config.
|
|
79
79
|
"""
|
|
80
80
|
|
|
81
|
+
new_config = {}
|
|
81
82
|
for agent_name, _cfg in config.items():
|
|
83
|
+
new_config[agent_name] = {}
|
|
84
|
+
|
|
85
|
+
if "model" in _cfg:
|
|
86
|
+
new_config[agent_name]["model"] = _cfg["model"]
|
|
87
|
+
if "prompt" in _cfg:
|
|
88
|
+
new_config[agent_name]["prompt"] = _cfg["prompt"]
|
|
89
|
+
if "default" in _cfg:
|
|
90
|
+
new_config[agent_name]["default"] = _cfg["default"]
|
|
91
|
+
if "tools" in _cfg:
|
|
92
|
+
new_config[agent_name]["tools"] = _cfg["tools"]
|
|
93
|
+
|
|
82
94
|
handoffs = _cfg.get("handoffs", [])
|
|
83
95
|
if handoffs == "all":
|
|
84
96
|
handoff_tools = [
|
|
@@ -102,8 +114,11 @@ def _transform_agent_config(
|
|
|
102
114
|
]
|
|
103
115
|
]
|
|
104
116
|
|
|
105
|
-
|
|
106
|
-
|
|
117
|
+
new_config[agent_name]["tools"] = [
|
|
118
|
+
*new_config[agent_name].get("tools", []),
|
|
119
|
+
*handoff_tools,
|
|
120
|
+
]
|
|
121
|
+
return new_config
|
|
107
122
|
|
|
108
123
|
|
|
109
124
|
class HandoffAgentMiddleware(AgentMiddleware):
|
|
@@ -5,11 +5,8 @@ from langchain.tools import ToolRuntime
|
|
|
5
5
|
from langchain_core.messages import AnyMessage, HumanMessage
|
|
6
6
|
from langchain_core.tools import BaseTool, StructuredTool
|
|
7
7
|
from langgraph.graph.state import CompiledStateGraph
|
|
8
|
-
from pydantic import BaseModel, Field
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
class AgentToolInput(BaseModel):
|
|
12
|
-
request: str = Field(description="The input to the agent")
|
|
9
|
+
from langchain_dev_utils.message_convert import format_sequence
|
|
13
10
|
|
|
14
11
|
|
|
15
12
|
def _process_input(request: str, runtime: ToolRuntime) -> str:
|
|
@@ -138,3 +135,140 @@ def wrap_agent_as_tool(
|
|
|
138
135
|
name=tool_name,
|
|
139
136
|
description=tool_description,
|
|
140
137
|
)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def wrap_all_agents_as_tool(
|
|
141
|
+
agents: list[CompiledStateGraph],
|
|
142
|
+
tool_name: Optional[str] = None,
|
|
143
|
+
tool_description: Optional[str] = None,
|
|
144
|
+
pre_input_hooks: Optional[
|
|
145
|
+
tuple[
|
|
146
|
+
Callable[[str, ToolRuntime], str],
|
|
147
|
+
Callable[[str, ToolRuntime], Awaitable[str]],
|
|
148
|
+
]
|
|
149
|
+
| Callable[[str, ToolRuntime], str]
|
|
150
|
+
] = None,
|
|
151
|
+
post_output_hooks: Optional[
|
|
152
|
+
tuple[
|
|
153
|
+
Callable[[str, list[AnyMessage], ToolRuntime], Any],
|
|
154
|
+
Callable[[str, list[AnyMessage], ToolRuntime], Awaitable[Any]],
|
|
155
|
+
]
|
|
156
|
+
| Callable[[str, list[AnyMessage], ToolRuntime], Any]
|
|
157
|
+
] = None,
|
|
158
|
+
) -> BaseTool:
|
|
159
|
+
"""Wraps all agents as single tool
|
|
160
|
+
|
|
161
|
+
Args:
|
|
162
|
+
agents: The agents to wrap
|
|
163
|
+
tool_name: The name of the tool, default to "task"
|
|
164
|
+
tool_description: The description of the tool
|
|
165
|
+
pre_input_hooks: Hooks to run before the input is processed
|
|
166
|
+
post_output_hooks: Hooks to run after the output is processed
|
|
167
|
+
|
|
168
|
+
Returns:
|
|
169
|
+
BaseTool: The wrapped agents as single tool
|
|
170
|
+
|
|
171
|
+
Example:
|
|
172
|
+
>>> from langchain_dev_utils.agents import wrap_all_agents_as_tool, create_agent
|
|
173
|
+
>>>
|
|
174
|
+
>>> call_time_agent_tool = wrap_all_agents_as_tool(
|
|
175
|
+
... [time_agent,weather_agent],
|
|
176
|
+
... tool_name="call_sub_agents",
|
|
177
|
+
... tool_description="Used to invoke the sub-agents to perform tasks"
|
|
178
|
+
... )
|
|
179
|
+
>>>
|
|
180
|
+
>>> agent = create_agent("vllm:qwen3-4b", tools=[call_sub_agents_tool], name="agent")
|
|
181
|
+
|
|
182
|
+
>>> response = agent.invoke({"messages": [HumanMessage(content="What time is it now?")]})
|
|
183
|
+
>>> response
|
|
184
|
+
"""
|
|
185
|
+
if len(agents) <= 1:
|
|
186
|
+
raise ValueError("At least more than one agent must be provided")
|
|
187
|
+
|
|
188
|
+
agents_map = {}
|
|
189
|
+
|
|
190
|
+
for agent in agents:
|
|
191
|
+
if agent.name is None:
|
|
192
|
+
raise ValueError("Agent name must not be provided")
|
|
193
|
+
if agent.name in agents_map:
|
|
194
|
+
raise ValueError("Agent name must be unique")
|
|
195
|
+
agents_map[agent.name] = agent
|
|
196
|
+
|
|
197
|
+
process_input = _process_input
|
|
198
|
+
process_input_async = _process_input
|
|
199
|
+
process_output = _process_output
|
|
200
|
+
process_output_async = _process_output
|
|
201
|
+
|
|
202
|
+
if pre_input_hooks:
|
|
203
|
+
if isinstance(pre_input_hooks, tuple):
|
|
204
|
+
process_input = pre_input_hooks[0]
|
|
205
|
+
process_input_async = pre_input_hooks[1]
|
|
206
|
+
else:
|
|
207
|
+
process_input = pre_input_hooks
|
|
208
|
+
process_input_async = pre_input_hooks
|
|
209
|
+
|
|
210
|
+
if post_output_hooks:
|
|
211
|
+
if isinstance(post_output_hooks, tuple):
|
|
212
|
+
process_output = post_output_hooks[0]
|
|
213
|
+
process_output_async = post_output_hooks[1]
|
|
214
|
+
else:
|
|
215
|
+
process_output = post_output_hooks
|
|
216
|
+
process_output_async = post_output_hooks
|
|
217
|
+
|
|
218
|
+
def call_agent(
|
|
219
|
+
agent_name: str,
|
|
220
|
+
description: str,
|
|
221
|
+
runtime: ToolRuntime,
|
|
222
|
+
) -> str:
|
|
223
|
+
task_description = (
|
|
224
|
+
process_input(description, runtime) if process_input else description
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
if agent_name not in agents_map:
|
|
228
|
+
raise ValueError(f"Agent {agent_name} not found")
|
|
229
|
+
|
|
230
|
+
messages = [HumanMessage(content=task_description)]
|
|
231
|
+
response = agents_map[agent_name].invoke({"messages": messages})
|
|
232
|
+
|
|
233
|
+
response = process_output(task_description, response["messages"], runtime)
|
|
234
|
+
return response
|
|
235
|
+
|
|
236
|
+
async def acall_agent(
|
|
237
|
+
agent_name: str,
|
|
238
|
+
description: str,
|
|
239
|
+
runtime: ToolRuntime,
|
|
240
|
+
) -> str:
|
|
241
|
+
if asyncio.iscoroutinefunction(process_input_async):
|
|
242
|
+
task_description = await process_input_async(description, runtime)
|
|
243
|
+
else:
|
|
244
|
+
task_description = cast(str, process_input_async(description, runtime))
|
|
245
|
+
|
|
246
|
+
if agent_name not in agents_map:
|
|
247
|
+
raise ValueError(f"Agent {agent_name} not found")
|
|
248
|
+
|
|
249
|
+
messages = [HumanMessage(content=task_description)]
|
|
250
|
+
response = await agents_map[agent_name].ainvoke({"messages": messages})
|
|
251
|
+
|
|
252
|
+
if asyncio.iscoroutinefunction(process_output_async):
|
|
253
|
+
response = await process_output_async(
|
|
254
|
+
task_description, response["messages"], runtime
|
|
255
|
+
)
|
|
256
|
+
else:
|
|
257
|
+
response = process_output(task_description, response["messages"], runtime)
|
|
258
|
+
|
|
259
|
+
return response
|
|
260
|
+
|
|
261
|
+
if tool_name is None:
|
|
262
|
+
tool_name = "task"
|
|
263
|
+
|
|
264
|
+
if tool_description is None:
|
|
265
|
+
tool_description = (
|
|
266
|
+
"Launch an ephemeral subagent for a task.\nAvailable agents:\n "
|
|
267
|
+
+ format_sequence(list(agents_map.keys()), with_num=True)
|
|
268
|
+
)
|
|
269
|
+
return StructuredTool.from_function(
|
|
270
|
+
func=call_agent,
|
|
271
|
+
coroutine=acall_agent,
|
|
272
|
+
name=tool_name,
|
|
273
|
+
description=tool_description,
|
|
274
|
+
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: langchain-dev-utils
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.3
|
|
4
4
|
Summary: A practical utility library for LangChain and LangGraph development
|
|
5
5
|
Project-URL: Source Code, https://github.com/TBice123123/langchain-dev-utils
|
|
6
6
|
Project-URL: repository, https://github.com/TBice123123/langchain-dev-utils
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
langchain_dev_utils/__init__.py,sha256=
|
|
1
|
+
langchain_dev_utils/__init__.py,sha256=Vi6om3KImlKsS_Wg5CjUgYffoi2zx7T-SRPnnGL0G7M,22
|
|
2
2
|
langchain_dev_utils/_utils.py,sha256=MFEzR1BjXMj6HEVwt2x2omttFuDJ_rYAEbNqe99r9pM,1338
|
|
3
3
|
langchain_dev_utils/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
-
langchain_dev_utils/agents/__init__.py,sha256=
|
|
4
|
+
langchain_dev_utils/agents/__init__.py,sha256=69_biZzyJvW9OBT1g8TX_77mp9-I_TvWo9QtlvHq83E,177
|
|
5
5
|
langchain_dev_utils/agents/factory.py,sha256=8XB6y_ddf58vXlTLHBL6KCirFqkD2GjtzsuOt98sS7U,3732
|
|
6
6
|
langchain_dev_utils/agents/file_system.py,sha256=Yk3eetREE26WNrnTWLoiDUpOyCJ-rhjlfFDk6foLa1E,8468
|
|
7
7
|
langchain_dev_utils/agents/plan.py,sha256=WwhoiJBmVYVI9bT8HfjCzTJ_SIp9WFil0gOeznv2omQ,6497
|
|
8
|
-
langchain_dev_utils/agents/wrap.py,sha256=
|
|
8
|
+
langchain_dev_utils/agents/wrap.py,sha256=O8LSieRhlqL4cwf_BPNIiJD3lhTyL6civBHcQPWCqSU,9490
|
|
9
9
|
langchain_dev_utils/agents/middleware/__init__.py,sha256=QVQibaNHvHPyNTZ2UNFfYL153ZboaCHcoioTHK0FsiY,710
|
|
10
10
|
langchain_dev_utils/agents/middleware/format_prompt.py,sha256=LzYiQXCRvkpfDhGPxhZwdepeU3j-HUWPJqcx3FWsfT4,2357
|
|
11
|
-
langchain_dev_utils/agents/middleware/handoffs.py,sha256=
|
|
11
|
+
langchain_dev_utils/agents/middleware/handoffs.py,sha256=r196Xk0Jws1Tz6JQuvy5HEc3HAAQejCxFmJpB6KrvLU,7230
|
|
12
12
|
langchain_dev_utils/agents/middleware/model_fallback.py,sha256=8xiNjTJ0yiRkPLCRfAGNnqY1TLstj1Anmiqyv5w2mA8,1633
|
|
13
13
|
langchain_dev_utils/agents/middleware/model_router.py,sha256=qBspvj9ZoKfmC1pHWTO0EHHfxjgCUd-TuSbqvZl0kmg,7977
|
|
14
14
|
langchain_dev_utils/agents/middleware/plan.py,sha256=-ZLkp85QQTSCX9thMblacJ1N86h0BYPoTwCfJlJ_jzQ,14981
|
|
@@ -33,7 +33,7 @@ langchain_dev_utils/pipeline/types.py,sha256=T3aROKKXeWvd0jcH5XkgMDQfEkLfPaiOhhV
|
|
|
33
33
|
langchain_dev_utils/tool_calling/__init__.py,sha256=mu_WxKMcu6RoTf4vkTPbA1WSBSNc6YIqyBtOQ6iVQj4,322
|
|
34
34
|
langchain_dev_utils/tool_calling/human_in_the_loop.py,sha256=7Z_QO5OZUR6K8nLoIcafc6osnvX2IYNorOJcbx6bVso,9672
|
|
35
35
|
langchain_dev_utils/tool_calling/utils.py,sha256=S4-KXQ8jWmpGTXYZitovF8rxKpaSSUkFruM8LDwvcvE,2765
|
|
36
|
-
langchain_dev_utils-1.3.
|
|
37
|
-
langchain_dev_utils-1.3.
|
|
38
|
-
langchain_dev_utils-1.3.
|
|
39
|
-
langchain_dev_utils-1.3.
|
|
36
|
+
langchain_dev_utils-1.3.3.dist-info/METADATA,sha256=PEt8qHRYBK2l-A2djg8eJEuz6uZdxZq-fPa6U6yR8Cc,4552
|
|
37
|
+
langchain_dev_utils-1.3.3.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
38
|
+
langchain_dev_utils-1.3.3.dist-info/licenses/LICENSE,sha256=AWAOzNEcsvCEzHOF0qby5OKxviVH_eT9Yce1sgJTico,1084
|
|
39
|
+
langchain_dev_utils-1.3.3.dist-info/RECORD,,
|
|
File without changes
|
{langchain_dev_utils-1.3.2.dist-info → langchain_dev_utils-1.3.3.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|