langchain-dev-utils 1.3.7__tar.gz → 1.4.1__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.
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/.vscode/settings.json +2 -1
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/PKG-INFO +8 -6
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/README.md +6 -5
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/README_cn.md +6 -5
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/pyproject.toml +63 -47
- langchain_dev_utils-1.4.1/src/langchain_dev_utils/__init__.py +1 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/src/langchain_dev_utils/_utils.py +23 -3
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/src/langchain_dev_utils/agents/middleware/__init__.py +5 -3
- langchain_dev_utils-1.4.1/src/langchain_dev_utils/agents/middleware/format_prompt.py +156 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/src/langchain_dev_utils/agents/middleware/tool_call_repair.py +3 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/src/langchain_dev_utils/agents/wrap.py +20 -7
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/src/langchain_dev_utils/chat_models/adapters/openai_compatible.py +10 -5
- langchain_dev_utils-1.4.1/src/langchain_dev_utils/graph/__init__.py +7 -0
- langchain_dev_utils-1.4.1/src/langchain_dev_utils/graph/parallel.py +119 -0
- langchain_dev_utils-1.4.1/src/langchain_dev_utils/graph/sequential.py +78 -0
- langchain_dev_utils-1.4.1/src/langchain_dev_utils/graph/types.py +3 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/src/langchain_dev_utils/message_convert/format.py +34 -1
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/src/langchain_dev_utils/pipeline/parallel.py +6 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/src/langchain_dev_utils/pipeline/sequential.py +6 -0
- langchain_dev_utils-1.4.1/tests/test_graph.py +64 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/tests/test_messages.py +16 -10
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/tests/test_wrap_agent.py +37 -4
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/uv.lock +4125 -2883
- langchain_dev_utils-1.3.7/src/langchain_dev_utils/__init__.py +0 -1
- langchain_dev_utils-1.3.7/src/langchain_dev_utils/agents/file_system.py +0 -252
- langchain_dev_utils-1.3.7/src/langchain_dev_utils/agents/middleware/format_prompt.py +0 -66
- langchain_dev_utils-1.3.7/src/langchain_dev_utils/agents/plan.py +0 -188
- langchain_dev_utils-1.3.7/tests/test_pipline.py +0 -76
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/.gitignore +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/.python-version +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/LICENSE +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/src/langchain_dev_utils/agents/__init__.py +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/src/langchain_dev_utils/agents/factory.py +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/src/langchain_dev_utils/agents/middleware/handoffs.py +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/src/langchain_dev_utils/agents/middleware/model_fallback.py +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/src/langchain_dev_utils/agents/middleware/model_router.py +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/src/langchain_dev_utils/agents/middleware/plan.py +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/src/langchain_dev_utils/agents/middleware/summarization.py +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/src/langchain_dev_utils/agents/middleware/tool_emulator.py +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/src/langchain_dev_utils/agents/middleware/tool_selection.py +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/src/langchain_dev_utils/chat_models/__init__.py +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/src/langchain_dev_utils/chat_models/adapters/__init__.py +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/src/langchain_dev_utils/chat_models/adapters/create_utils.py +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/src/langchain_dev_utils/chat_models/adapters/register_profiles.py +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/src/langchain_dev_utils/chat_models/base.py +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/src/langchain_dev_utils/chat_models/types.py +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/src/langchain_dev_utils/embeddings/__init__.py +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/src/langchain_dev_utils/embeddings/adapters/__init__.py +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/src/langchain_dev_utils/embeddings/adapters/create_utils.py +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/src/langchain_dev_utils/embeddings/adapters/openai_compatible.py +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/src/langchain_dev_utils/embeddings/base.py +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/src/langchain_dev_utils/message_convert/__init__.py +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/src/langchain_dev_utils/message_convert/content.py +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/src/langchain_dev_utils/pipeline/__init__.py +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/src/langchain_dev_utils/pipeline/types.py +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/src/langchain_dev_utils/py.typed +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/src/langchain_dev_utils/tool_calling/__init__.py +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/src/langchain_dev_utils/tool_calling/human_in_the_loop.py +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/src/langchain_dev_utils/tool_calling/utils.py +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/tests/__init__.py +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/tests/test_agent.py +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/tests/test_chat_models.py +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/tests/test_embedding.py +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/tests/test_handoffs_middleware.py +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/tests/test_human_in_the_loop.py +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/tests/test_load_embbeding.py +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/tests/test_load_model.py +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/tests/test_model_tool_emulator.py +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/tests/test_plan_middleware.py +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/tests/test_router_model.py +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/tests/test_tool_call_repair.py +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/tests/test_tool_calling.py +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/tests/utils/__init__.py +0 -0
- {langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/tests/utils/register.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: langchain-dev-utils
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4.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
|
|
@@ -12,6 +12,7 @@ Requires-Dist: langchain-core>=1.2.5
|
|
|
12
12
|
Requires-Dist: langchain>=1.2.0
|
|
13
13
|
Requires-Dist: langgraph>=1.0.0
|
|
14
14
|
Provides-Extra: standard
|
|
15
|
+
Requires-Dist: jinja2>=3.1.6; extra == 'standard'
|
|
15
16
|
Requires-Dist: json-repair>=0.53.1; extra == 'standard'
|
|
16
17
|
Requires-Dist: langchain-openai; extra == 'standard'
|
|
17
18
|
Description-Content-Type: text/markdown
|
|
@@ -27,10 +28,11 @@ Description-Content-Type: text/markdown
|
|
|
27
28
|
<a href="https://tbice123123.github.io/langchain-dev-utils/zh/">中文</a>
|
|
28
29
|
</p>
|
|
29
30
|
|
|
30
|
-
[](https://github.com/TBice123123/langchain-dev-utils)
|
|
32
|
+
[](https://pypi.org/project/langchain-dev-utils/)
|
|
33
|
+
[](https://python.org)
|
|
34
|
+
[](https://opensource.org/licenses/MIT)
|
|
35
|
+
[](https://github.com/TBice123123/langchain-dev-utils)
|
|
34
36
|
[](https://tbice123123.github.io/langchain-dev-utils)
|
|
35
37
|
|
|
36
38
|
> This is the English version. For the Chinese version, please visit [中文版本](https://github.com/TBice123123/langchain-dev-utils/blob/master/README_cn.md)
|
|
@@ -51,7 +53,7 @@ Tired of writing repetitive code in LangChain development? `langchain-dev-utils`
|
|
|
51
53
|
- **💬 Flexible message handling** - Support for chain-of-thought concatenation, streaming processing, and message formatting
|
|
52
54
|
- **🛠️ Powerful tool calling** - Built-in tool call detection, parameter parsing, and human review functionality
|
|
53
55
|
- **🤖 Efficient Agent development** - Simplify agent creation process, expand more common middleware
|
|
54
|
-
- **📊
|
|
56
|
+
- **📊 Convenient State Graph Construction** - Provides pre-built functions to easily create sequential or parallel state graphs
|
|
55
57
|
|
|
56
58
|
## ⚡ Quick Start
|
|
57
59
|
|
|
@@ -9,10 +9,11 @@
|
|
|
9
9
|
<a href="https://tbice123123.github.io/langchain-dev-utils/zh/">中文</a>
|
|
10
10
|
</p>
|
|
11
11
|
|
|
12
|
-
[](https://github.com/TBice123123/langchain-dev-utils)
|
|
13
|
+
[](https://pypi.org/project/langchain-dev-utils/)
|
|
14
|
+
[](https://python.org)
|
|
15
|
+
[](https://opensource.org/licenses/MIT)
|
|
16
|
+
[](https://github.com/TBice123123/langchain-dev-utils)
|
|
16
17
|
[](https://tbice123123.github.io/langchain-dev-utils)
|
|
17
18
|
|
|
18
19
|
> This is the English version. For the Chinese version, please visit [中文版本](https://github.com/TBice123123/langchain-dev-utils/blob/master/README_cn.md)
|
|
@@ -33,7 +34,7 @@ Tired of writing repetitive code in LangChain development? `langchain-dev-utils`
|
|
|
33
34
|
- **💬 Flexible message handling** - Support for chain-of-thought concatenation, streaming processing, and message formatting
|
|
34
35
|
- **🛠️ Powerful tool calling** - Built-in tool call detection, parameter parsing, and human review functionality
|
|
35
36
|
- **🤖 Efficient Agent development** - Simplify agent creation process, expand more common middleware
|
|
36
|
-
- **📊
|
|
37
|
+
- **📊 Convenient State Graph Construction** - Provides pre-built functions to easily create sequential or parallel state graphs
|
|
37
38
|
|
|
38
39
|
## ⚡ Quick Start
|
|
39
40
|
|
|
@@ -9,10 +9,11 @@
|
|
|
9
9
|
<a href="https://tbice123123.github.io/langchain-dev-utils/zh/">中文</a>
|
|
10
10
|
</p>
|
|
11
11
|
|
|
12
|
-
[](https://github.com/TBice123123/langchain-dev-utils)
|
|
13
|
+
[](https://pypi.org/project/langchain-dev-utils/)
|
|
14
|
+
[](https://python.org)
|
|
15
|
+
[](https://opensource.org/licenses/MIT)
|
|
16
|
+
[](https://github.com/TBice123123/langchain-dev-utils)
|
|
16
17
|
[](https://tbice123123.github.io/langchain-dev-utils/zh/)
|
|
17
18
|
|
|
18
19
|
> 当前为中文版,英文版请访问[English Version](https://github.com/TBice123123/langchain-dev-utils/blob/master/README.md)
|
|
@@ -33,7 +34,7 @@
|
|
|
33
34
|
- **💬 灵活的消息处理** - 支持思维链拼接、流式处理和消息格式化
|
|
34
35
|
- **🛠️ 强大的工具调用** - 内置工具调用检测、参数解析和人工审核功能
|
|
35
36
|
- **🤖 高效的 Agent 开发** - 简化智能体创建流程,扩充更多的常用中间件
|
|
36
|
-
- **📊
|
|
37
|
+
- **📊 便捷的状态图构建** - 提供预构建函数方便构建顺序或者并行的状态图
|
|
37
38
|
|
|
38
39
|
## ⚡ 快速开始
|
|
39
40
|
|
|
@@ -1,47 +1,63 @@
|
|
|
1
|
-
[project]
|
|
2
|
-
name = "langchain-dev-utils"
|
|
3
|
-
version = "1.
|
|
4
|
-
description = "A practical utility library for LangChain and LangGraph development"
|
|
5
|
-
readme = "README.md"
|
|
6
|
-
authors = [{ name = "tiebingice", email = "tiebingice123@outlook.com" }]
|
|
7
|
-
requires-python = ">=3.11"
|
|
8
|
-
dependencies = [
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
"
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
[
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
1
|
+
[project]
|
|
2
|
+
name = "langchain-dev-utils"
|
|
3
|
+
version = "1.4.1"
|
|
4
|
+
description = "A practical utility library for LangChain and LangGraph development"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [{ name = "tiebingice", email = "tiebingice123@outlook.com" }]
|
|
7
|
+
requires-python = ">=3.11"
|
|
8
|
+
dependencies = [
|
|
9
|
+
"langchain>=1.2.0",
|
|
10
|
+
"langchain-core>=1.2.5",
|
|
11
|
+
"langgraph>=1.0.0",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
[project.urls]
|
|
15
|
+
"Source Code" = "https://github.com/TBice123123/langchain-dev-utils"
|
|
16
|
+
repository = "https://github.com/TBice123123/langchain-dev-utils"
|
|
17
|
+
documentation = "https://tbice123123.github.io/langchain-dev-utils"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
[project.optional-dependencies]
|
|
21
|
+
standard = [
|
|
22
|
+
"jinja2>=3.1.6",
|
|
23
|
+
"json-repair>=0.53.1",
|
|
24
|
+
"langchain-openai",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[build-system]
|
|
28
|
+
requires = ["hatchling"]
|
|
29
|
+
build-backend = "hatchling.build"
|
|
30
|
+
|
|
31
|
+
[tool.hatch.build]
|
|
32
|
+
exclude = ["/data", "/docs", "mkdocs.yml"]
|
|
33
|
+
|
|
34
|
+
[tool.pytest.ini_options]
|
|
35
|
+
asyncio_mode = "auto"
|
|
36
|
+
testpaths = ["tests"]
|
|
37
|
+
python_files = ["test_*.py"]
|
|
38
|
+
python_functions = ["test_*"]
|
|
39
|
+
|
|
40
|
+
[dependency-groups]
|
|
41
|
+
dev = [
|
|
42
|
+
"dashscope>=1.25.9",
|
|
43
|
+
"langchain-model-profiles>=0.0.5",
|
|
44
|
+
"ruff>=0.14.5",
|
|
45
|
+
]
|
|
46
|
+
docs = [
|
|
47
|
+
"jupyter>=1.1.1",
|
|
48
|
+
"mkdocs-material>=9.7.0",
|
|
49
|
+
"mkdocs-static-i18n>=1.3.0",
|
|
50
|
+
]
|
|
51
|
+
tests = [
|
|
52
|
+
"python-dotenv>=1.1.1",
|
|
53
|
+
"langchain-tests>=1.0.0",
|
|
54
|
+
"langchain-deepseek>=1.0.0",
|
|
55
|
+
"langchain-qwq>=0.3.0",
|
|
56
|
+
"langchain-ollama>=1.0.0",
|
|
57
|
+
"langchain-community>=0.4.1",
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
[tool.ruff.lint]
|
|
62
|
+
select = ["E", "F", "I", "PGH003", "T201"]
|
|
63
|
+
ignore = ["E501"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.4.1"
|
|
@@ -1,17 +1,37 @@
|
|
|
1
1
|
from importlib import util
|
|
2
|
-
from typing import Literal, Optional
|
|
2
|
+
from typing import Literal, Optional, cast
|
|
3
3
|
|
|
4
|
+
from langgraph.graph import StateGraph
|
|
5
|
+
from langgraph.graph.state import StateNode
|
|
4
6
|
from pydantic import BaseModel
|
|
5
7
|
|
|
6
8
|
|
|
9
|
+
def _transform_node_to_tuple(
|
|
10
|
+
node: StateNode | tuple[str, StateNode],
|
|
11
|
+
) -> tuple[str, StateNode]:
|
|
12
|
+
if not isinstance(node, tuple):
|
|
13
|
+
if isinstance(node, StateGraph):
|
|
14
|
+
node = node.compile()
|
|
15
|
+
name = node.name
|
|
16
|
+
return name, node
|
|
17
|
+
name = cast(str, getattr(node, "name", getattr(node, "__name__", None)))
|
|
18
|
+
if name is None:
|
|
19
|
+
raise ValueError("Node name must be provided if action is not a function")
|
|
20
|
+
return name, node
|
|
21
|
+
else:
|
|
22
|
+
return node
|
|
23
|
+
|
|
24
|
+
|
|
7
25
|
def _check_pkg_install(
|
|
8
|
-
pkg: Literal["langchain_openai", "json_repair"],
|
|
26
|
+
pkg: Literal["langchain_openai", "json_repair", "jinja2"],
|
|
9
27
|
) -> None:
|
|
10
28
|
if not util.find_spec(pkg):
|
|
11
29
|
if pkg == "langchain_openai":
|
|
12
30
|
msg = "Please install langchain_dev_utils[standard],when use 'openai-compatible'"
|
|
13
|
-
|
|
31
|
+
elif pkg == "json_repair":
|
|
14
32
|
msg = "Please install langchain_dev_utils[standard] to use ToolCallRepairMiddleware."
|
|
33
|
+
else:
|
|
34
|
+
msg = "Please install langchain_dev_utils[standard] to use FormatPromptMiddleware."
|
|
15
35
|
raise ImportError(msg)
|
|
16
36
|
|
|
17
37
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
from .format_prompt import format_prompt
|
|
1
|
+
from .format_prompt import FormatPromptMiddleware, format_prompt
|
|
2
2
|
from .handoffs import HandoffAgentMiddleware
|
|
3
3
|
from .model_fallback import ModelFallbackMiddleware
|
|
4
4
|
from .model_router import ModelRouterMiddleware
|
|
5
5
|
from .plan import PlanMiddleware
|
|
6
6
|
from .summarization import SummarizationMiddleware
|
|
7
|
-
from .tool_call_repair import ToolCallRepairMiddleware
|
|
7
|
+
from .tool_call_repair import ToolCallRepairMiddleware, tool_call_repair
|
|
8
8
|
from .tool_emulator import LLMToolEmulator
|
|
9
9
|
from .tool_selection import LLMToolSelectorMiddleware
|
|
10
10
|
|
|
@@ -16,6 +16,8 @@ __all__ = [
|
|
|
16
16
|
"LLMToolEmulator",
|
|
17
17
|
"ModelRouterMiddleware",
|
|
18
18
|
"ToolCallRepairMiddleware",
|
|
19
|
-
"
|
|
19
|
+
"FormatPromptMiddleware",
|
|
20
20
|
"HandoffAgentMiddleware",
|
|
21
|
+
"tool_call_repair",
|
|
22
|
+
"format_prompt",
|
|
21
23
|
]
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
from typing import Awaitable, Callable, Literal
|
|
2
|
+
|
|
3
|
+
from langchain.agents.middleware import ModelRequest
|
|
4
|
+
from langchain.agents.middleware.types import (
|
|
5
|
+
AgentMiddleware,
|
|
6
|
+
ModelCallResult,
|
|
7
|
+
ModelResponse,
|
|
8
|
+
)
|
|
9
|
+
from langchain_core.messages import SystemMessage
|
|
10
|
+
from langchain_core.prompts.string import get_template_variables
|
|
11
|
+
|
|
12
|
+
from langchain_dev_utils._utils import _check_pkg_install
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class FormatPromptMiddleware(AgentMiddleware):
|
|
16
|
+
"""Format the system prompt with variables from state and context.
|
|
17
|
+
|
|
18
|
+
This middleware function extracts template variables from the system prompt
|
|
19
|
+
and populates them with values from the agent's state and runtime context.
|
|
20
|
+
Variables are first resolved from the state, then from the context if not found.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
template_format: The format of the template. Defaults to "f-string".
|
|
24
|
+
|
|
25
|
+
Example:
|
|
26
|
+
|
|
27
|
+
# Use format_prompt middleware instance rather than FormatPromptMiddleware class (Recommended)
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
from langchain_dev_utils.agents.middleware import format_prompt
|
|
31
|
+
from langchain.agents import create_agent
|
|
32
|
+
from langchain_core.messages import HumanMessage
|
|
33
|
+
from dataclasses import dataclass
|
|
34
|
+
|
|
35
|
+
@dataclass
|
|
36
|
+
class Context:
|
|
37
|
+
name: str
|
|
38
|
+
user: str
|
|
39
|
+
|
|
40
|
+
agent = create_agent(
|
|
41
|
+
model=model,
|
|
42
|
+
tools=tools,
|
|
43
|
+
system_prompt="You are a helpful assistant. Your name is {name}. Your user is {user}.",
|
|
44
|
+
middleware=[format_prompt],
|
|
45
|
+
context_schema=Context,
|
|
46
|
+
)
|
|
47
|
+
agent.invoke(
|
|
48
|
+
{
|
|
49
|
+
"messages": [HumanMessage(content="Hello")],
|
|
50
|
+
},
|
|
51
|
+
context=Context(name="assistant", user="Tom"),
|
|
52
|
+
)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
# Use FormatPromptMiddleware class(Use when template_format is jinja2)
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
from langchain_dev_utils.agents.middleware import FormatPromptMiddleware
|
|
59
|
+
from langchain.agents import create_agent
|
|
60
|
+
from langchain_core.messages import HumanMessage
|
|
61
|
+
from dataclasses import dataclass
|
|
62
|
+
|
|
63
|
+
@dataclass
|
|
64
|
+
class Context:
|
|
65
|
+
name: str
|
|
66
|
+
user: str
|
|
67
|
+
|
|
68
|
+
agent = create_agent(
|
|
69
|
+
model=model,
|
|
70
|
+
tools=tools,
|
|
71
|
+
system_prompt="You are a helpful assistant. Your name is {{ name }}. Your user is {{ user }}.",
|
|
72
|
+
middleware=[FormatPromptMiddleware(template_format="jinja2")],
|
|
73
|
+
context_schema=Context,
|
|
74
|
+
)
|
|
75
|
+
agent.invoke(
|
|
76
|
+
{
|
|
77
|
+
"messages": [HumanMessage(content="Hello")],
|
|
78
|
+
},
|
|
79
|
+
context=Context(name="assistant", user="Tom"),
|
|
80
|
+
)
|
|
81
|
+
```
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
def __init__(
|
|
85
|
+
self,
|
|
86
|
+
*,
|
|
87
|
+
template_format: Literal["f-string", "jinja2"] = "f-string",
|
|
88
|
+
) -> None:
|
|
89
|
+
super().__init__()
|
|
90
|
+
|
|
91
|
+
self.template_format = template_format
|
|
92
|
+
|
|
93
|
+
if template_format == "jinja2":
|
|
94
|
+
_check_pkg_install("jinja2")
|
|
95
|
+
|
|
96
|
+
def _format_prompt(self, request: ModelRequest) -> str:
|
|
97
|
+
"""Add the plan system prompt to the system message."""
|
|
98
|
+
system_msg = request.system_message
|
|
99
|
+
if system_msg is None:
|
|
100
|
+
raise ValueError(
|
|
101
|
+
"system_message must be provided,while use format_prompt in middleware."
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
system_prompt = "\n".join(
|
|
105
|
+
[content.get("text", "") for content in system_msg.content_blocks]
|
|
106
|
+
)
|
|
107
|
+
variables = get_template_variables(system_prompt, self.template_format)
|
|
108
|
+
|
|
109
|
+
format_params = {}
|
|
110
|
+
|
|
111
|
+
state = request.state
|
|
112
|
+
for key in variables:
|
|
113
|
+
if var := state.get(key, None):
|
|
114
|
+
format_params[key] = var
|
|
115
|
+
|
|
116
|
+
other_var_keys = set(variables) - set(format_params.keys())
|
|
117
|
+
|
|
118
|
+
if other_var_keys:
|
|
119
|
+
context = request.runtime.context
|
|
120
|
+
if context is not None:
|
|
121
|
+
for key in other_var_keys:
|
|
122
|
+
if var := getattr(context, key, None):
|
|
123
|
+
format_params[key] = var
|
|
124
|
+
|
|
125
|
+
if self.template_format == "jinja2":
|
|
126
|
+
from jinja2 import Template
|
|
127
|
+
|
|
128
|
+
template = Template(system_prompt)
|
|
129
|
+
return template.render(**format_params)
|
|
130
|
+
else:
|
|
131
|
+
return system_prompt.format(**format_params)
|
|
132
|
+
|
|
133
|
+
def wrap_model_call(
|
|
134
|
+
self,
|
|
135
|
+
request: ModelRequest,
|
|
136
|
+
handler: Callable[[ModelRequest], ModelResponse],
|
|
137
|
+
) -> ModelCallResult:
|
|
138
|
+
"""Update the system prompt with variables from state and context."""
|
|
139
|
+
prompt = self._format_prompt(request)
|
|
140
|
+
request = request.override(system_message=SystemMessage(content=prompt))
|
|
141
|
+
return handler(request)
|
|
142
|
+
|
|
143
|
+
async def awrap_model_call(
|
|
144
|
+
self,
|
|
145
|
+
request: ModelRequest,
|
|
146
|
+
handler: Callable[[ModelRequest], Awaitable[ModelResponse]],
|
|
147
|
+
) -> ModelCallResult:
|
|
148
|
+
"""Update the system prompt with variables from state and context."""
|
|
149
|
+
prompt = self._format_prompt(request)
|
|
150
|
+
override_request = request.override(
|
|
151
|
+
system_message=SystemMessage(content=prompt)
|
|
152
|
+
)
|
|
153
|
+
return await handler(override_request)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
format_prompt = FormatPromptMiddleware()
|
{langchain_dev_utils-1.3.7 → langchain_dev_utils-1.4.1}/src/langchain_dev_utils/agents/wrap.py
RENAMED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import
|
|
2
|
-
from typing import Any, Awaitable, Callable, Optional
|
|
1
|
+
import inspect
|
|
2
|
+
from typing import Any, Awaitable, Callable, Optional, cast
|
|
3
3
|
|
|
4
4
|
from langchain.tools import ToolRuntime
|
|
5
|
-
from langchain_core.messages import HumanMessage
|
|
5
|
+
from langchain_core.messages import AIMessage, HumanMessage
|
|
6
6
|
from langchain_core.tools import BaseTool, StructuredTool
|
|
7
7
|
from langgraph.graph.state import CompiledStateGraph
|
|
8
8
|
|
|
9
9
|
from langchain_dev_utils.message_convert import format_sequence
|
|
10
|
+
from langchain_dev_utils.tool_calling import parse_tool_calling
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
def _process_input(request: str, runtime: ToolRuntime) -> str:
|
|
@@ -19,6 +20,18 @@ def _process_output(
|
|
|
19
20
|
return response["messages"][-1].content
|
|
20
21
|
|
|
21
22
|
|
|
23
|
+
def get_subagent_name(runtime: ToolRuntime) -> str:
|
|
24
|
+
messages = runtime.state.get("messages", [])
|
|
25
|
+
last_ai_msg = cast(
|
|
26
|
+
AIMessage,
|
|
27
|
+
next((msg for msg in reversed(messages) if isinstance(msg, AIMessage)), None),
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
_, args = parse_tool_calling(last_ai_msg, first_tool_call_only=True)
|
|
31
|
+
args = cast(dict[str, Any], args)
|
|
32
|
+
return args["agent_name"]
|
|
33
|
+
|
|
34
|
+
|
|
22
35
|
def wrap_agent_as_tool(
|
|
23
36
|
agent: CompiledStateGraph,
|
|
24
37
|
tool_name: Optional[str] = None,
|
|
@@ -115,7 +128,7 @@ def wrap_agent_as_tool(
|
|
|
115
128
|
request: str,
|
|
116
129
|
runtime: ToolRuntime,
|
|
117
130
|
):
|
|
118
|
-
if
|
|
131
|
+
if inspect.iscoroutinefunction(process_input_async):
|
|
119
132
|
_processed_input = await process_input_async(request, runtime)
|
|
120
133
|
else:
|
|
121
134
|
_processed_input = (
|
|
@@ -135,7 +148,7 @@ def wrap_agent_as_tool(
|
|
|
135
148
|
|
|
136
149
|
response = await agent.ainvoke(agent_input)
|
|
137
150
|
|
|
138
|
-
if
|
|
151
|
+
if inspect.iscoroutinefunction(process_output_async):
|
|
139
152
|
response = await process_output_async(request, response, runtime)
|
|
140
153
|
else:
|
|
141
154
|
response = (
|
|
@@ -277,7 +290,7 @@ def wrap_all_agents_as_tool(
|
|
|
277
290
|
if agent_name not in agents_map:
|
|
278
291
|
raise ValueError(f"Agent {agent_name} not found")
|
|
279
292
|
|
|
280
|
-
if
|
|
293
|
+
if inspect.iscoroutinefunction(process_input_async):
|
|
281
294
|
_processed_input = await process_input_async(description, runtime)
|
|
282
295
|
else:
|
|
283
296
|
_processed_input = (
|
|
@@ -297,7 +310,7 @@ def wrap_all_agents_as_tool(
|
|
|
297
310
|
|
|
298
311
|
response = await agents_map[agent_name].ainvoke(agent_input)
|
|
299
312
|
|
|
300
|
-
if
|
|
313
|
+
if inspect.iscoroutinefunction(process_output_async):
|
|
301
314
|
response = await process_output_async(description, response, runtime)
|
|
302
315
|
else:
|
|
303
316
|
response = (
|
|
@@ -218,14 +218,15 @@ class _BaseChatOpenAICompatible(BaseChatOpenAI):
|
|
|
218
218
|
stop: list[str] | None = None,
|
|
219
219
|
**kwargs: Any,
|
|
220
220
|
) -> dict:
|
|
221
|
+
if stop is not None:
|
|
222
|
+
kwargs["stop"] = stop
|
|
223
|
+
|
|
221
224
|
payload = {**self._default_params, **kwargs}
|
|
222
225
|
|
|
223
226
|
if self._use_responses_api(payload):
|
|
224
227
|
return super()._get_request_payload(input_, stop=stop, **kwargs)
|
|
225
228
|
|
|
226
229
|
messages = self._convert_input(input_).to_messages()
|
|
227
|
-
if stop is not None:
|
|
228
|
-
kwargs["stop"] = stop
|
|
229
230
|
|
|
230
231
|
payload_messages = []
|
|
231
232
|
last_human_index = -1
|
|
@@ -260,6 +261,8 @@ class _BaseChatOpenAICompatible(BaseChatOpenAI):
|
|
|
260
261
|
payload_messages.append(_convert_message_to_dict(m))
|
|
261
262
|
|
|
262
263
|
payload["messages"] = payload_messages
|
|
264
|
+
if "tools" in payload and len(payload["tools"]) == 0:
|
|
265
|
+
payload.pop("tools")
|
|
263
266
|
return payload
|
|
264
267
|
|
|
265
268
|
@model_validator(mode="after")
|
|
@@ -301,6 +304,8 @@ class _BaseChatOpenAICompatible(BaseChatOpenAI):
|
|
|
301
304
|
ModelProfile,
|
|
302
305
|
_get_profile_by_provider_and_model(self._provider, self.model_name),
|
|
303
306
|
)
|
|
307
|
+
if "json_schema" in self.supported_response_format:
|
|
308
|
+
self.profile.update({"structured_output": True})
|
|
304
309
|
return self
|
|
305
310
|
|
|
306
311
|
def _create_chat_result(
|
|
@@ -346,9 +351,9 @@ class _BaseChatOpenAICompatible(BaseChatOpenAI):
|
|
|
346
351
|
if isinstance(model_extra, dict) and (
|
|
347
352
|
reasoning := model_extra.get("reasoning")
|
|
348
353
|
):
|
|
349
|
-
rtn.generations[0].message.additional_kwargs[
|
|
350
|
-
|
|
351
|
-
|
|
354
|
+
rtn.generations[0].message.additional_kwargs[
|
|
355
|
+
"reasoning_content"
|
|
356
|
+
] = reasoning
|
|
352
357
|
|
|
353
358
|
return rtn
|
|
354
359
|
|