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.
@@ -1 +1 @@
1
- __version__ = "1.2.16"
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.0
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=7RIJ-Nh9kHJf5O5NvahUeP8DNXq6oIzbYcIt_yKv0lQ,23
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=mr-Q3fxxV_yEN3l8p-Rk0uxXvKjDUGEZDtrg9HRwr-8,3732
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=EECbcYcHXQAMA-guJNRGwCVi9jG957d0nOaoIuyIKC0,832
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.0.dist-info/METADATA,sha256=_fA9O0n1NOwnh6Vg4ExNxmJ0Sa7yBJdhwvOyK4Cbycw,4515
36
- langchain_dev_utils-1.3.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
37
- langchain_dev_utils-1.3.0.dist-info/licenses/LICENSE,sha256=AWAOzNEcsvCEzHOF0qby5OKxviVH_eT9Yce1sgJTico,1084
38
- langchain_dev_utils-1.3.0.dist-info/RECORD,,
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,,