langchain-dev-utils 1.3.0__py3-none-any.whl → 1.3.1__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/factory.py +1 -1
- langchain_dev_utils/agents/middleware/__init__.py +3 -0
- langchain_dev_utils/agents/middleware/handoffs.py +138 -0
- {langchain_dev_utils-1.3.0.dist-info → langchain_dev_utils-1.3.1.dist-info}/METADATA +2 -1
- {langchain_dev_utils-1.3.0.dist-info → langchain_dev_utils-1.3.1.dist-info}/RECORD +8 -7
- {langchain_dev_utils-1.3.0.dist-info → langchain_dev_utils-1.3.1.dist-info}/WHEEL +0 -0
- {langchain_dev_utils-1.3.0.dist-info → langchain_dev_utils-1.3.1.dist-info}/licenses/LICENSE +0 -0
langchain_dev_utils/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "1.
|
|
1
|
+
__version__ = "1.3.1"
|
|
@@ -5,9 +5,9 @@ from langchain.agents.middleware.types import (
|
|
|
5
5
|
AgentMiddleware,
|
|
6
6
|
AgentState,
|
|
7
7
|
ResponseT,
|
|
8
|
+
StateT_co,
|
|
8
9
|
_InputAgentState,
|
|
9
10
|
_OutputAgentState,
|
|
10
|
-
StateT_co,
|
|
11
11
|
)
|
|
12
12
|
from langchain.agents.structured_output import ResponseFormat
|
|
13
13
|
from langchain_core.messages import SystemMessage
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from .format_prompt import format_prompt
|
|
2
|
+
from .handoffs import HandoffsAgentMiddleware, create_handoffs_tool
|
|
2
3
|
from .model_fallback import ModelFallbackMiddleware
|
|
3
4
|
from .model_router import ModelRouterMiddleware
|
|
4
5
|
from .plan import (
|
|
@@ -24,4 +25,6 @@ __all__ = [
|
|
|
24
25
|
"ModelRouterMiddleware",
|
|
25
26
|
"ToolCallRepairMiddleware",
|
|
26
27
|
"format_prompt",
|
|
28
|
+
"create_handoffs_tool",
|
|
29
|
+
"HandoffsAgentMiddleware",
|
|
27
30
|
]
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
from typing import Any, Awaitable, Callable
|
|
2
|
+
|
|
3
|
+
from langchain.agents import AgentState
|
|
4
|
+
from langchain.agents.middleware import AgentMiddleware, ModelRequest, ModelResponse
|
|
5
|
+
from langchain.agents.middleware.types import ModelCallResult
|
|
6
|
+
from langchain.tools import BaseTool, ToolRuntime, tool
|
|
7
|
+
from langchain_core.language_models.chat_models import BaseChatModel
|
|
8
|
+
from langchain_core.messages import SystemMessage, ToolMessage
|
|
9
|
+
from langgraph.types import Command
|
|
10
|
+
from typing_extensions import NotRequired, Optional, TypedDict
|
|
11
|
+
|
|
12
|
+
from langchain_dev_utils.chat_models import load_chat_model
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class MultiAgentState(AgentState):
|
|
16
|
+
active_agent: NotRequired[str]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class AgentConfig(TypedDict):
|
|
20
|
+
model: NotRequired[str | BaseChatModel]
|
|
21
|
+
prompt: str | SystemMessage
|
|
22
|
+
tools: list[BaseTool | dict[str, Any]]
|
|
23
|
+
default: NotRequired[bool]
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def create_handoffs_tool(
|
|
27
|
+
agent_name: str,
|
|
28
|
+
tool_name: Optional[str] = None,
|
|
29
|
+
tool_description: Optional[str] = None,
|
|
30
|
+
):
|
|
31
|
+
"""Create a tool for handoffs to a specified agent.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
agent_name (str): The name of the agent to transfer to.
|
|
35
|
+
tool_name (Optional[str], optional): The name of the tool. Defaults to None.
|
|
36
|
+
tool_description (Optional[str], optional): The description of the tool. Defaults to None.
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
BaseTool: A tool instance for handoffs to the specified agent.
|
|
40
|
+
|
|
41
|
+
Example:
|
|
42
|
+
Basic usage
|
|
43
|
+
>>> from langchain_dev_utils.agents.middleware import create_handoffs_tool
|
|
44
|
+
>>> handoffs_tool = create_handoffs_tool("time_agent")
|
|
45
|
+
"""
|
|
46
|
+
if tool_name is None:
|
|
47
|
+
tool_name = f"transfer_to_{agent_name}"
|
|
48
|
+
if not tool_name.endswith("_agent"):
|
|
49
|
+
tool_name += "_agent"
|
|
50
|
+
|
|
51
|
+
if tool_description is None:
|
|
52
|
+
tool_description = f"Transfer to the {agent_name}"
|
|
53
|
+
|
|
54
|
+
@tool(name_or_callable=tool_name, description=tool_description)
|
|
55
|
+
def handoffs_tool(runtime: ToolRuntime) -> Command:
|
|
56
|
+
return Command(
|
|
57
|
+
update={
|
|
58
|
+
"messages": [
|
|
59
|
+
ToolMessage(
|
|
60
|
+
content=f"Transferred to {agent_name}",
|
|
61
|
+
tool_call_id=runtime.tool_call_id,
|
|
62
|
+
)
|
|
63
|
+
],
|
|
64
|
+
"active_agent": agent_name,
|
|
65
|
+
}
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
return handoffs_tool
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _get_default_active_agent(state: dict[str, AgentConfig]) -> Optional[str]:
|
|
72
|
+
for agent_name, config in state.items():
|
|
73
|
+
if config.get("default", False):
|
|
74
|
+
return agent_name
|
|
75
|
+
return None
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class HandoffsAgentMiddleware(AgentMiddleware):
|
|
79
|
+
"""Agent middleware for switching between multiple agents.
|
|
80
|
+
This middleware dynamically replaces model call parameters based on the currently active agent configuration, enabling seamless switching between different agents.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
agents_config (dict[str, AgentConfig]): A dictionary of agent configurations.
|
|
84
|
+
|
|
85
|
+
Examples:
|
|
86
|
+
```python
|
|
87
|
+
from langchain_dev_utils.agents.middleware import HandoffsAgentMiddleware
|
|
88
|
+
middleware = HandoffsAgentMiddleware(agents_config)
|
|
89
|
+
```
|
|
90
|
+
"""
|
|
91
|
+
|
|
92
|
+
state_schema = MultiAgentState
|
|
93
|
+
|
|
94
|
+
def __init__(self, agents_config: dict[str, AgentConfig]):
|
|
95
|
+
default_agent_name = _get_default_active_agent(agents_config)
|
|
96
|
+
if default_agent_name is None:
|
|
97
|
+
raise ValueError(
|
|
98
|
+
"No default agent found, you must set one by set default=True"
|
|
99
|
+
)
|
|
100
|
+
self.default_agent_name = default_agent_name
|
|
101
|
+
self.agents_config = agents_config
|
|
102
|
+
|
|
103
|
+
def _get_active_agent_config(self, request: ModelRequest) -> dict[str, Any]:
|
|
104
|
+
active_agent_name = request.state.get("active_agent", self.default_agent_name)
|
|
105
|
+
|
|
106
|
+
_config = self.agents_config[active_agent_name]
|
|
107
|
+
|
|
108
|
+
params = {}
|
|
109
|
+
if _config.get("model"):
|
|
110
|
+
model = _config.get("model")
|
|
111
|
+
if isinstance(model, str):
|
|
112
|
+
model = load_chat_model(model)
|
|
113
|
+
params["model"] = model
|
|
114
|
+
if _config.get("prompt"):
|
|
115
|
+
params["system_prompt"] = _config.get("prompt")
|
|
116
|
+
if _config.get("tools"):
|
|
117
|
+
params["tools"] = _config.get("tools")
|
|
118
|
+
return params
|
|
119
|
+
|
|
120
|
+
def wrap_model_call(
|
|
121
|
+
self, request: ModelRequest, handler: Callable[[ModelRequest], ModelResponse]
|
|
122
|
+
) -> ModelCallResult:
|
|
123
|
+
override_kwargs = self._get_active_agent_config(request)
|
|
124
|
+
if override_kwargs:
|
|
125
|
+
return handler(request.override(**override_kwargs))
|
|
126
|
+
else:
|
|
127
|
+
return handler(request)
|
|
128
|
+
|
|
129
|
+
async def awrap_model_call(
|
|
130
|
+
self,
|
|
131
|
+
request: ModelRequest,
|
|
132
|
+
handler: Callable[[ModelRequest], Awaitable[ModelResponse]],
|
|
133
|
+
) -> ModelCallResult:
|
|
134
|
+
override_kwargs = self._get_active_agent_config(request)
|
|
135
|
+
if override_kwargs:
|
|
136
|
+
return await handler(request.override(**override_kwargs))
|
|
137
|
+
else:
|
|
138
|
+
return await handler(request)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: langchain-dev-utils
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.1
|
|
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
|
|
@@ -8,6 +8,7 @@ Project-URL: documentation, https://tbice123123.github.io/langchain-dev-utils
|
|
|
8
8
|
Author-email: tiebingice <tiebingice123@outlook.com>
|
|
9
9
|
License-File: LICENSE
|
|
10
10
|
Requires-Python: >=3.11
|
|
11
|
+
Requires-Dist: langchain-core>=1.2.5
|
|
11
12
|
Requires-Dist: langchain>=1.2.0
|
|
12
13
|
Requires-Dist: langgraph>=1.0.0
|
|
13
14
|
Provides-Extra: standard
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
langchain_dev_utils/__init__.py,sha256
|
|
1
|
+
langchain_dev_utils/__init__.py,sha256=-ypEJktJToAL9by62JJKWEzDo_KPCQtmE5kwFgX24z4,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
4
|
langchain_dev_utils/agents/__init__.py,sha256=PJ-lSDZv_AXMYA3H4fx-HzJa14tPbkGmq1HX8LNfaPo,125
|
|
5
|
-
langchain_dev_utils/agents/factory.py,sha256=
|
|
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
8
|
langchain_dev_utils/agents/wrap.py,sha256=RuchoH_VotPmKFuYEn2SXoSgNxZhSA9jKM0Iv_8oHLk,4718
|
|
9
|
-
langchain_dev_utils/agents/middleware/__init__.py,sha256=
|
|
9
|
+
langchain_dev_utils/agents/middleware/__init__.py,sha256=n3PsbL8LSmariEe94rUMoT0GnUQMrZUNdSj-z4om2cY,962
|
|
10
10
|
langchain_dev_utils/agents/middleware/format_prompt.py,sha256=LzYiQXCRvkpfDhGPxhZwdepeU3j-HUWPJqcx3FWsfT4,2357
|
|
11
|
+
langchain_dev_utils/agents/middleware/handoffs.py,sha256=aCD90yTiAPyG8pC_DAr0eDi-iYW57W0wt6LzIoKLT_Y,5024
|
|
11
12
|
langchain_dev_utils/agents/middleware/model_fallback.py,sha256=8xiNjTJ0yiRkPLCRfAGNnqY1TLstj1Anmiqyv5w2mA8,1633
|
|
12
13
|
langchain_dev_utils/agents/middleware/model_router.py,sha256=qBspvj9ZoKfmC1pHWTO0EHHfxjgCUd-TuSbqvZl0kmg,7977
|
|
13
14
|
langchain_dev_utils/agents/middleware/plan.py,sha256=0qDCmenxgY_zrwMfOyYlgLfhYNw-HszNLeeOkfj14NA,16002
|
|
@@ -32,7 +33,7 @@ langchain_dev_utils/pipeline/types.py,sha256=T3aROKKXeWvd0jcH5XkgMDQfEkLfPaiOhhV
|
|
|
32
33
|
langchain_dev_utils/tool_calling/__init__.py,sha256=mu_WxKMcu6RoTf4vkTPbA1WSBSNc6YIqyBtOQ6iVQj4,322
|
|
33
34
|
langchain_dev_utils/tool_calling/human_in_the_loop.py,sha256=7Z_QO5OZUR6K8nLoIcafc6osnvX2IYNorOJcbx6bVso,9672
|
|
34
35
|
langchain_dev_utils/tool_calling/utils.py,sha256=S4-KXQ8jWmpGTXYZitovF8rxKpaSSUkFruM8LDwvcvE,2765
|
|
35
|
-
langchain_dev_utils-1.3.
|
|
36
|
-
langchain_dev_utils-1.3.
|
|
37
|
-
langchain_dev_utils-1.3.
|
|
38
|
-
langchain_dev_utils-1.3.
|
|
36
|
+
langchain_dev_utils-1.3.1.dist-info/METADATA,sha256=6UJeWibp3qpwITK0THhTdFpM8tq7XyLyoUvbkMnRhLc,4552
|
|
37
|
+
langchain_dev_utils-1.3.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
38
|
+
langchain_dev_utils-1.3.1.dist-info/licenses/LICENSE,sha256=AWAOzNEcsvCEzHOF0qby5OKxviVH_eT9Yce1sgJTico,1084
|
|
39
|
+
langchain_dev_utils-1.3.1.dist-info/RECORD,,
|
|
File without changes
|
{langchain_dev_utils-1.3.0.dist-info → langchain_dev_utils-1.3.1.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|