agentic-kit-common 0.0.17__tar.gz → 0.0.21__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.
- {agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/PKG-INFO +3 -1
- agentic_kit_common-0.0.21/agentic_kit_common/config/__init__.py +21 -0
- agentic_kit_common-0.0.21/agentic_kit_common/config/config_loader.py +311 -0
- {agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/agentic_kit_common/llm/openai.py +2 -2
- {agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/agentic_kit_common/log/logger.py +2 -2
- agentic_kit_common-0.0.21/agentic_kit_common/mcp/mcp_client.py +344 -0
- {agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/agentic_kit_common/orm/session.py +2 -2
- agentic_kit_common-0.0.21/agentic_kit_common/redis/redis_pool_manager.py +118 -0
- {agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/agentic_kit_common/sms/ali_sms_client.py +2 -2
- agentic_kit_common-0.0.21/agentic_kit_common/web/http/__init__.py +0 -0
- {agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/agentic_kit_common.egg-info/PKG-INFO +3 -1
- {agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/agentic_kit_common.egg-info/SOURCES.txt +9 -0
- {agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/agentic_kit_common.egg-info/requires.txt +2 -0
- {agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/setup.py +5 -1
- agentic_kit_common-0.0.21/test/__init__.py +0 -0
- agentic_kit_common-0.0.21/test/conf.yaml +56 -0
- agentic_kit_common-0.0.21/test/test_config_manager.py +29 -0
- agentic_kit_common-0.0.21/test/test_mcp_client.py +29 -0
- {agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/README.md +0 -0
- {agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/agentic_kit_common/__init__.py +0 -0
- {agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/agentic_kit_common/llm/__init__.py +0 -0
- {agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/agentic_kit_common/llm/utils.py +0 -0
- {agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/agentic_kit_common/log/__init__.py +0 -0
- {agentic_kit_common-0.0.17/agentic_kit_common/minio → agentic_kit_common-0.0.21/agentic_kit_common/mcp}/__init__.py +0 -0
- {agentic_kit_common-0.0.17/agentic_kit_common/sms → agentic_kit_common-0.0.21/agentic_kit_common/minio}/__init__.py +0 -0
- {agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/agentic_kit_common/minio/minio_manager.py +0 -0
- {agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/agentic_kit_common/mongodb/__init__.py +0 -0
- {agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/agentic_kit_common/mongodb/mongodb_manager.py +0 -0
- {agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/agentic_kit_common/orm/__init__.py +0 -0
- {agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/agentic_kit_common/orm/base.py +0 -0
- {agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/agentic_kit_common/orm/execution.py +0 -0
- {agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/agentic_kit_common/orm/manager.py +0 -0
- {agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/agentic_kit_common/orm/multi_session.py +0 -0
- {agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/agentic_kit_common/orm/schema.py +0 -0
- {agentic_kit_common-0.0.17/agentic_kit_common/vector → agentic_kit_common-0.0.21/agentic_kit_common/redis}/__init__.py +0 -0
- {agentic_kit_common-0.0.17/agentic_kit_common/web → agentic_kit_common-0.0.21/agentic_kit_common/sms}/__init__.py +0 -0
- {agentic_kit_common-0.0.17/agentic_kit_common/web/http → agentic_kit_common-0.0.21/agentic_kit_common/vector}/__init__.py +0 -0
- {agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/agentic_kit_common/vector/embedding/__init__.py +0 -0
- {agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/agentic_kit_common/vector/embedding/embedding.py +0 -0
- {agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/agentic_kit_common/vector/manager/__init__.py +0 -0
- {agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/agentic_kit_common/vector/manager/milvus_manager.py +0 -0
- {agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/agentic_kit_common/vector/schema/__init__.py +0 -0
- {agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/agentic_kit_common/vector/schema/base.py +0 -0
- {agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/agentic_kit_common/vector/schema/milvus_schema.py +0 -0
- {agentic_kit_common-0.0.17/test → agentic_kit_common-0.0.21/agentic_kit_common/web}/__init__.py +0 -0
- {agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/agentic_kit_common/web/http/response.py +0 -0
- {agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/agentic_kit_common.egg-info/dependency_links.txt +0 -0
- {agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/agentic_kit_common.egg-info/top_level.txt +0 -0
- {agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/setup.cfg +0 -0
- {agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/test/config.py +0 -0
- {agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/test/settings.py +0 -0
- {agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/test/test_embedding.py +0 -0
- {agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/test/test_minio.py +0 -0
- {agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/test/test_orm.py +0 -0
- {agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/test/test_vector.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentic-kit-common
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.21
|
|
4
4
|
Summary: Common utilities and tools for agentic kit ecosystem
|
|
5
5
|
Home-page:
|
|
6
6
|
Author: manson
|
|
@@ -25,12 +25,14 @@ Requires-Dist: langgraph
|
|
|
25
25
|
Requires-Dist: langchain_community
|
|
26
26
|
Requires-Dist: langchain_experimental
|
|
27
27
|
Requires-Dist: langchain-openai
|
|
28
|
+
Requires-Dist: langchain_mcp_adapters
|
|
28
29
|
Requires-Dist: mysql-connector-python
|
|
29
30
|
Requires-Dist: sqlalchemy
|
|
30
31
|
Requires-Dist: sqlglot
|
|
31
32
|
Requires-Dist: pymilvus
|
|
32
33
|
Requires-Dist: xinference_client
|
|
33
34
|
Requires-Dist: pymongo
|
|
35
|
+
Requires-Dist: redis
|
|
34
36
|
Requires-Dist: aliyun-python-sdk-core
|
|
35
37
|
Requires-Dist: aliyun-python-sdk-dysmsapi
|
|
36
38
|
Dynamic: author
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from .config_loader import (
|
|
2
|
+
ConfigManager,
|
|
3
|
+
load_config,
|
|
4
|
+
get_llm_config,
|
|
5
|
+
get_rag_config,
|
|
6
|
+
get_database_config,
|
|
7
|
+
get_full_config,
|
|
8
|
+
reload_config,
|
|
9
|
+
set_config_manager,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"ConfigManager",
|
|
14
|
+
"set_config_manager",
|
|
15
|
+
"load_config",
|
|
16
|
+
"get_llm_config",
|
|
17
|
+
"get_rag_config",
|
|
18
|
+
"get_database_config",
|
|
19
|
+
"get_full_config",
|
|
20
|
+
"reload_config",
|
|
21
|
+
]
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import os
|
|
3
|
+
from typing import Any, Dict, Optional
|
|
4
|
+
|
|
5
|
+
import yaml
|
|
6
|
+
from dotenv import load_dotenv, find_dotenv
|
|
7
|
+
|
|
8
|
+
logger = logging.getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
load_dotenv(find_dotenv(usecwd=True))
|
|
12
|
+
_config_root_path = os.getenv("DELTA_CONFIG_PATH", None)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ConfigManager:
|
|
16
|
+
"""
|
|
17
|
+
配置管理器 - 支持多种配置源
|
|
18
|
+
|
|
19
|
+
支持的配置方式(优先级从高到低):
|
|
20
|
+
1. 环境变量(最高优先级)
|
|
21
|
+
2. 初始化时传入的 config 参数
|
|
22
|
+
3. 配置文件(config_path 或默认的 conf.yaml)
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(
|
|
26
|
+
self,
|
|
27
|
+
config: Optional[Dict[str, Any]] = None,
|
|
28
|
+
config_path: Optional[str] = None
|
|
29
|
+
):
|
|
30
|
+
"""
|
|
31
|
+
初始化配置管理器
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
config: 直接传入的配置字典(适合外部 SDK 调用)
|
|
35
|
+
格式示例:
|
|
36
|
+
{
|
|
37
|
+
"BASIC_MODEL": {
|
|
38
|
+
"base_url": "http://...",
|
|
39
|
+
"model": "qwen",
|
|
40
|
+
"api_key": "sk-xxx"
|
|
41
|
+
},
|
|
42
|
+
"VISION_MODEL": {
|
|
43
|
+
"base_url": "http://...",
|
|
44
|
+
"model": "vision",
|
|
45
|
+
"api_key": "sk-xxx"
|
|
46
|
+
},
|
|
47
|
+
"RAG_CLIENT": {
|
|
48
|
+
"base_url": "http://...",
|
|
49
|
+
"timeout": 120
|
|
50
|
+
},
|
|
51
|
+
"DATABASE_CLIENT": {
|
|
52
|
+
"base_url": "http://...",
|
|
53
|
+
"timeout": 120
|
|
54
|
+
},
|
|
55
|
+
"MCP_SETTINGS": {
|
|
56
|
+
"default_servers": {
|
|
57
|
+
"file-processor": {
|
|
58
|
+
"transport": "streamable_http",
|
|
59
|
+
"url": "http://...",
|
|
60
|
+
"enabled_tools": ["convert_to_markdown"]
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
config_path: 配置文件路径(可选)
|
|
67
|
+
- 如果不提供,默认使用项目根目录的 conf.yaml
|
|
68
|
+
- 如果提供,使用指定路径的配置文件
|
|
69
|
+
|
|
70
|
+
Examples:
|
|
71
|
+
# 方式1: 直接传入配置(外部 SDK 推荐)
|
|
72
|
+
config_mgr = ConfigManager(config={
|
|
73
|
+
"BASIC_MODEL": {...},
|
|
74
|
+
"RAG_CLIENT": {...}
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
# 方式2: 指定配置文件路径
|
|
78
|
+
config_mgr = ConfigManager(config_path="/path/to/conf.yaml")
|
|
79
|
+
|
|
80
|
+
# 方式3: 使用默认配置文件(项目根目录/conf.yaml)
|
|
81
|
+
config_mgr = ConfigManager()
|
|
82
|
+
"""
|
|
83
|
+
self._external_config = config or {}
|
|
84
|
+
self._config_path = config_path or _config_root_path
|
|
85
|
+
self._config_cache: Optional[Dict[str, Any]] = None
|
|
86
|
+
|
|
87
|
+
def load_config(self, force_reload: bool = False) -> Dict[str, Any]:
|
|
88
|
+
"""
|
|
89
|
+
加载配置(带缓存)
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
force_reload: 是否强制重新加载
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
Dict[str, Any]: 完整配置字典
|
|
96
|
+
"""
|
|
97
|
+
if self._config_cache is not None and not force_reload:
|
|
98
|
+
return self._config_cache
|
|
99
|
+
|
|
100
|
+
# 如果有外部配置,直接使用
|
|
101
|
+
if self._external_config:
|
|
102
|
+
self._config_cache = self._external_config.copy()
|
|
103
|
+
logger.info("使用外部传入的配置")
|
|
104
|
+
return self._config_cache
|
|
105
|
+
|
|
106
|
+
# 从配置文件加载
|
|
107
|
+
conf_path = self._config_path
|
|
108
|
+
|
|
109
|
+
if not os.path.exists(conf_path):
|
|
110
|
+
logger.warning(f"配置文件不存在: {conf_path},使用空配置")
|
|
111
|
+
self._config_cache = {}
|
|
112
|
+
return self._config_cache
|
|
113
|
+
|
|
114
|
+
try:
|
|
115
|
+
with open(conf_path, 'r', encoding='utf-8') as f:
|
|
116
|
+
config = yaml.safe_load(f) or {}
|
|
117
|
+
self._config_cache = config
|
|
118
|
+
logger.info(f"成功加载配置文件: {conf_path}")
|
|
119
|
+
except Exception as e:
|
|
120
|
+
logger.error(f"加载配置文件失败: {e}")
|
|
121
|
+
self._config_cache = {}
|
|
122
|
+
|
|
123
|
+
return self._config_cache
|
|
124
|
+
|
|
125
|
+
def get_llm_config(self, model_type: str = "BASIC_MODEL") -> Dict[str, Any]:
|
|
126
|
+
"""
|
|
127
|
+
获取LLM配置
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
model_type: 模型类型,可选 "BASIC_MODEL", "VISION_MODEL"
|
|
131
|
+
|
|
132
|
+
Returns:
|
|
133
|
+
Dict[str, Any]: LLM配置
|
|
134
|
+
"""
|
|
135
|
+
config = self.load_config()
|
|
136
|
+
base_config = config.get(model_type, {}).copy() if isinstance(config.get(model_type), dict) else {}
|
|
137
|
+
|
|
138
|
+
# 环境变量覆盖(优先级最高)
|
|
139
|
+
prefix = f"{model_type}__"
|
|
140
|
+
for key, value in os.environ.items():
|
|
141
|
+
if key.startswith(prefix):
|
|
142
|
+
conf_key = key[len(prefix):].lower()
|
|
143
|
+
base_config[conf_key] = value
|
|
144
|
+
|
|
145
|
+
return base_config
|
|
146
|
+
|
|
147
|
+
def get_rag_config(self) -> Dict[str, Any]:
|
|
148
|
+
"""
|
|
149
|
+
获取RAG客户端配置
|
|
150
|
+
|
|
151
|
+
Returns:
|
|
152
|
+
Dict[str, Any]: RAG配置
|
|
153
|
+
"""
|
|
154
|
+
config = self.load_config()
|
|
155
|
+
rag_config = config.get("RAG_CLIENT", {}).copy() if isinstance(config.get("RAG_CLIENT"), dict) else {}
|
|
156
|
+
|
|
157
|
+
# 支持环境变量覆盖
|
|
158
|
+
env_overrides = {
|
|
159
|
+
"base_url": os.getenv("RAG_CLIENT__base_url"),
|
|
160
|
+
"timeout": os.getenv("RAG_CLIENT__timeout"),
|
|
161
|
+
"max_retries": os.getenv("RAG_CLIENT__max_retries"),
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
for key, value in env_overrides.items():
|
|
165
|
+
if value is not None:
|
|
166
|
+
rag_config[key] = value
|
|
167
|
+
|
|
168
|
+
return rag_config
|
|
169
|
+
|
|
170
|
+
def get_mcp_config(self) -> Dict[str, Any]:
|
|
171
|
+
"""
|
|
172
|
+
获取MCP服务器配置
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
Dict[str, Any]: MCP配置
|
|
176
|
+
"""
|
|
177
|
+
config = self.load_config()
|
|
178
|
+
return config.get("MCP_SETTINGS", {})
|
|
179
|
+
|
|
180
|
+
def get_database_config(self) -> Dict[str, Any]:
|
|
181
|
+
"""
|
|
182
|
+
获取数据库客户端配置
|
|
183
|
+
|
|
184
|
+
Returns:
|
|
185
|
+
Dict[str, Any]: 数据库配置
|
|
186
|
+
"""
|
|
187
|
+
config = self.load_config()
|
|
188
|
+
db_config = config.get("DATABASE_CLIENT", {}).copy() if isinstance(config.get("DATABASE_CLIENT"), dict) else {}
|
|
189
|
+
|
|
190
|
+
# 支持环境变量覆盖
|
|
191
|
+
env_overrides = {
|
|
192
|
+
"base_url": os.getenv("DATABASE_CLIENT__base_url"),
|
|
193
|
+
"timeout": os.getenv("DATABASE_CLIENT__timeout"),
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
for key, value in env_overrides.items():
|
|
197
|
+
if value is not None:
|
|
198
|
+
db_config[key] = value
|
|
199
|
+
|
|
200
|
+
return db_config
|
|
201
|
+
|
|
202
|
+
def get_full_config(self) -> Dict[str, Any]:
|
|
203
|
+
"""
|
|
204
|
+
获取完整配置
|
|
205
|
+
|
|
206
|
+
Returns:
|
|
207
|
+
Dict[str, Any]: 完整配置字典
|
|
208
|
+
"""
|
|
209
|
+
return self.load_config()
|
|
210
|
+
|
|
211
|
+
def reload_config(self):
|
|
212
|
+
"""重新加载配置(清除缓存)"""
|
|
213
|
+
self._config_cache = None
|
|
214
|
+
logger.info("配置已重新加载")
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
# ============================================================================
|
|
218
|
+
# 全局默认配置管理器(向后兼容)
|
|
219
|
+
# ============================================================================
|
|
220
|
+
|
|
221
|
+
_default_config_manager: Optional[ConfigManager] = None
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def _get_default_config_manager() -> ConfigManager:
|
|
225
|
+
"""获取默认配置管理器实例"""
|
|
226
|
+
global _default_config_manager
|
|
227
|
+
if _default_config_manager is None:
|
|
228
|
+
_default_config_manager = ConfigManager()
|
|
229
|
+
return _default_config_manager
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def set_config_manager(config_manager: ConfigManager):
|
|
233
|
+
"""
|
|
234
|
+
设置全局配置管理器(用于外部 SDK)
|
|
235
|
+
|
|
236
|
+
Args:
|
|
237
|
+
config_manager: ConfigManager 实例
|
|
238
|
+
|
|
239
|
+
Example:
|
|
240
|
+
# 在外部 SDK 中设置自定义配置
|
|
241
|
+
config_mgr = ConfigManager(config={...})
|
|
242
|
+
set_config_manager(config_mgr)
|
|
243
|
+
"""
|
|
244
|
+
global _default_config_manager
|
|
245
|
+
_default_config_manager = config_manager
|
|
246
|
+
logger.info("已设置全局配置管理器")
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
# ============================================================================
|
|
250
|
+
# 向后兼容的函数接口
|
|
251
|
+
# ============================================================================
|
|
252
|
+
|
|
253
|
+
def load_config(force_reload: bool = False) -> Dict[str, Any]:
|
|
254
|
+
"""
|
|
255
|
+
加载配置文件(带缓存)
|
|
256
|
+
|
|
257
|
+
Args:
|
|
258
|
+
force_reload: 是否强制重新加载
|
|
259
|
+
|
|
260
|
+
Returns:
|
|
261
|
+
Dict[str, Any]: 完整配置字典
|
|
262
|
+
"""
|
|
263
|
+
return _get_default_config_manager().load_config(force_reload)
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def get_llm_config(model_type: str = "BASIC_MODEL") -> Dict[str, Any]:
|
|
267
|
+
"""
|
|
268
|
+
获取LLM配置
|
|
269
|
+
|
|
270
|
+
Args:
|
|
271
|
+
model_type: 模型类型,可选 "BASIC_MODEL", "VISION_MODEL"
|
|
272
|
+
|
|
273
|
+
Returns:
|
|
274
|
+
Dict[str, Any]: LLM配置
|
|
275
|
+
"""
|
|
276
|
+
return _get_default_config_manager().get_llm_config(model_type)
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
def get_rag_config() -> Dict[str, Any]:
|
|
280
|
+
"""
|
|
281
|
+
获取RAG客户端配置
|
|
282
|
+
|
|
283
|
+
Returns:
|
|
284
|
+
Dict[str, Any]: RAG配置
|
|
285
|
+
"""
|
|
286
|
+
return _get_default_config_manager().get_rag_config()
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
def get_database_config() -> Dict[str, Any]:
|
|
290
|
+
"""
|
|
291
|
+
获取数据库客户端配置
|
|
292
|
+
|
|
293
|
+
Returns:
|
|
294
|
+
Dict[str, Any]: 数据库配置
|
|
295
|
+
"""
|
|
296
|
+
return _get_default_config_manager().get_database_config()
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
def get_full_config() -> Dict[str, Any]:
|
|
300
|
+
"""
|
|
301
|
+
获取完整配置
|
|
302
|
+
|
|
303
|
+
Returns:
|
|
304
|
+
Dict[str, Any]: 完整配置字典
|
|
305
|
+
"""
|
|
306
|
+
return _get_default_config_manager().get_full_config()
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def reload_config():
|
|
310
|
+
"""重新加载配置(清除缓存)"""
|
|
311
|
+
_get_default_config_manager().reload_config()
|
|
@@ -5,9 +5,9 @@ from logging.handlers import TimedRotatingFileHandler
|
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
from typing import Union
|
|
7
7
|
|
|
8
|
-
from dotenv import load_dotenv
|
|
8
|
+
from dotenv import load_dotenv, find_dotenv
|
|
9
9
|
|
|
10
|
-
load_dotenv()
|
|
10
|
+
load_dotenv(find_dotenv(usecwd=True))
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
logger_root_path = os.getenv("LOGGER_ROOT_PATH", None)
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Dict, Any, List, Optional, TYPE_CHECKING
|
|
3
|
+
|
|
4
|
+
from langchain_mcp_adapters.client import MultiServerMCPClient
|
|
5
|
+
from langchain_core.tools import BaseTool
|
|
6
|
+
|
|
7
|
+
# if TYPE_CHECKING:
|
|
8
|
+
# from src.core.config import ConfigManager
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
logger.setLevel(logging.ERROR)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class MCPToolsNotAvailableError(Exception):
|
|
15
|
+
"""MCP工具不可用异常"""
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class MCPClient:
|
|
20
|
+
"""
|
|
21
|
+
MCP (Model Context Protocol) 客户端
|
|
22
|
+
|
|
23
|
+
支持的配置方式(优先级从高到低):
|
|
24
|
+
1. 初始化时传入的 config 参数
|
|
25
|
+
2. 配置管理器 (config_manager)
|
|
26
|
+
3. 默认配置文件(项目根目录/conf.yaml)
|
|
27
|
+
|
|
28
|
+
Examples:
|
|
29
|
+
# 方式1: 直接传入配置(外部 SDK 推荐)
|
|
30
|
+
client = MCPClient(config={
|
|
31
|
+
"default_servers": {
|
|
32
|
+
"web_search": {
|
|
33
|
+
"url": "http://your-server.com/mcp",
|
|
34
|
+
"transport": "streamable_http",
|
|
35
|
+
"enabled_tools": ["web_search", "crawl_page"] # 可选,不传则使用所有工具
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
# 方式2: 使用配置管理器
|
|
41
|
+
from src.core.config import ConfigManager
|
|
42
|
+
config_mgr = ConfigManager(config={
|
|
43
|
+
"MCP_SETTINGS": {
|
|
44
|
+
"default_servers": {...}
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
client = MCPClient(config_manager=config_mgr)
|
|
48
|
+
|
|
49
|
+
# 方式3: 使用默认配置文件(conf.yaml)
|
|
50
|
+
client = MCPClient()
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
def __init__(
|
|
54
|
+
self,
|
|
55
|
+
config: Optional[Dict[str, Any]] = None,
|
|
56
|
+
config_manager: Optional['ConfigManager'] = None
|
|
57
|
+
):
|
|
58
|
+
"""
|
|
59
|
+
初始化MCP客户端
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
config: 直接传入的配置字典(可选)
|
|
63
|
+
格式示例:
|
|
64
|
+
{
|
|
65
|
+
"default_servers": {
|
|
66
|
+
"server_name": {
|
|
67
|
+
"url": "http://...",
|
|
68
|
+
"transport": "sse" | "streamable_http",
|
|
69
|
+
"enabled_tools": ["tool1", "tool2"] # 可选,不传则使用所有工具
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
config_manager: 配置管理器实例(可选)
|
|
74
|
+
"""
|
|
75
|
+
assert not (config is None and config_manager is None), "config 与 config_manager 不能同时为 None"
|
|
76
|
+
|
|
77
|
+
self._config = config
|
|
78
|
+
self._config_manager = config_manager
|
|
79
|
+
self._client: Optional[MultiServerMCPClient] = None
|
|
80
|
+
self._initialized = False
|
|
81
|
+
self._enabled_tools_map: Dict[str, List[str]] = {} # 服务器名 -> 启用的工具列表
|
|
82
|
+
self._server_tools_cache: Dict[str, List[BaseTool]] = {} # 服务器名 -> 工具列表缓存
|
|
83
|
+
|
|
84
|
+
def _get_mcp_config(self) -> Dict[str, Any]:
|
|
85
|
+
"""
|
|
86
|
+
获取 MCP 配置
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
Dict[str, Any]: MCP 配置
|
|
90
|
+
"""
|
|
91
|
+
if self._config:
|
|
92
|
+
return self._config
|
|
93
|
+
|
|
94
|
+
if self._config_manager:
|
|
95
|
+
return self._config_manager.get_mcp_config()
|
|
96
|
+
|
|
97
|
+
async def initialize(self):
|
|
98
|
+
"""初始化MCP客户端"""
|
|
99
|
+
if self._initialized:
|
|
100
|
+
return
|
|
101
|
+
|
|
102
|
+
try:
|
|
103
|
+
mcp_config = self._get_mcp_config()
|
|
104
|
+
default_servers = mcp_config.get('default_servers', {})
|
|
105
|
+
|
|
106
|
+
if not default_servers:
|
|
107
|
+
logger.warning("配置文件中没有MCP服务器")
|
|
108
|
+
return
|
|
109
|
+
|
|
110
|
+
logger.info(f"开始初始化 {len(default_servers)} 个MCP服务器...")
|
|
111
|
+
|
|
112
|
+
server_configs = {}
|
|
113
|
+
for server_name, server_config in default_servers.items():
|
|
114
|
+
url = server_config.get('url')
|
|
115
|
+
transport = server_config.get('transport', 'sse')
|
|
116
|
+
enabled_tools = server_config.get('enabled_tools')
|
|
117
|
+
|
|
118
|
+
if not url:
|
|
119
|
+
logger.warning(f"服务器 {server_name} 缺少URL配置")
|
|
120
|
+
continue
|
|
121
|
+
|
|
122
|
+
server_configs[server_name] = {
|
|
123
|
+
'url': url,
|
|
124
|
+
'transport': transport
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if enabled_tools:
|
|
128
|
+
self._enabled_tools_map[server_name] = enabled_tools
|
|
129
|
+
logger.info(f"服务器 {server_name} 启用工具: {enabled_tools}")
|
|
130
|
+
else:
|
|
131
|
+
logger.info(f"服务器 {server_name} 将使用所有可用工具")
|
|
132
|
+
|
|
133
|
+
if not server_configs:
|
|
134
|
+
logger.warning("没有有效的MCP服务器配置")
|
|
135
|
+
return
|
|
136
|
+
|
|
137
|
+
self._client = MultiServerMCPClient(server_configs)
|
|
138
|
+
|
|
139
|
+
self._initialized = True
|
|
140
|
+
|
|
141
|
+
tools = await self.get_all_tools()
|
|
142
|
+
logger.info(f"成功初始化MCP客户端,加载了 {len(tools)} 个工具")
|
|
143
|
+
|
|
144
|
+
except Exception as e:
|
|
145
|
+
logger.error(f"MCP客户端初始化失败: {str(e)}", exc_info=True)
|
|
146
|
+
raise MCPToolsNotAvailableError(f"初始化失败: {str(e)}") from e
|
|
147
|
+
|
|
148
|
+
async def get_all_tools(self) -> List[BaseTool]:
|
|
149
|
+
"""
|
|
150
|
+
获取所有MCP工具
|
|
151
|
+
|
|
152
|
+
如果配置了 enabled_tools,只返回启用的工具;
|
|
153
|
+
否则返回所有可用工具。
|
|
154
|
+
|
|
155
|
+
Returns:
|
|
156
|
+
List[BaseTool]: 所有可用工具的列表(LangChain工具)
|
|
157
|
+
"""
|
|
158
|
+
if not self._initialized:
|
|
159
|
+
await self.initialize()
|
|
160
|
+
|
|
161
|
+
if not self._client:
|
|
162
|
+
logger.warning("MCP客户端未初始化")
|
|
163
|
+
return []
|
|
164
|
+
|
|
165
|
+
try:
|
|
166
|
+
all_tools = await self._client.get_tools()
|
|
167
|
+
|
|
168
|
+
if not self._enabled_tools_map:
|
|
169
|
+
logger.debug(f"获取到 {len(all_tools)} 个MCP工具(使用所有工具)")
|
|
170
|
+
return all_tools
|
|
171
|
+
|
|
172
|
+
enabled_tools = []
|
|
173
|
+
all_enabled_tool_names = set()
|
|
174
|
+
|
|
175
|
+
for server_name, tool_names in self._enabled_tools_map.items():
|
|
176
|
+
all_enabled_tool_names.update(tool_names)
|
|
177
|
+
|
|
178
|
+
for tool in all_tools:
|
|
179
|
+
if tool.name in all_enabled_tool_names:
|
|
180
|
+
enabled_tools.append(tool)
|
|
181
|
+
|
|
182
|
+
logger.info(f"获取到 {len(all_tools)} 个MCP工具,启用了 {len(enabled_tools)} 个工具")
|
|
183
|
+
if len(enabled_tools) < len(all_enabled_tool_names):
|
|
184
|
+
missing_tools = all_enabled_tool_names - {t.name for t in enabled_tools}
|
|
185
|
+
logger.warning(f"配置中的某些工具未找到: {missing_tools}")
|
|
186
|
+
|
|
187
|
+
return enabled_tools
|
|
188
|
+
|
|
189
|
+
except Exception as e:
|
|
190
|
+
logger.error(f"获取MCP工具失败: {str(e)}", exc_info=True)
|
|
191
|
+
return []
|
|
192
|
+
|
|
193
|
+
async def get_tool_by_name(self, tool_name: str) -> Optional[BaseTool]:
|
|
194
|
+
"""
|
|
195
|
+
根据名称获取特定工具
|
|
196
|
+
|
|
197
|
+
Args:
|
|
198
|
+
tool_name: 工具名称
|
|
199
|
+
|
|
200
|
+
Returns:
|
|
201
|
+
工具实例,如果未找到返回None
|
|
202
|
+
"""
|
|
203
|
+
tools = await self.get_all_tools()
|
|
204
|
+
for tool in tools:
|
|
205
|
+
if tool.name == tool_name:
|
|
206
|
+
return tool
|
|
207
|
+
return None
|
|
208
|
+
|
|
209
|
+
async def get_tools_by_server(self, server_names: str | List[str]) -> List[BaseTool]:
|
|
210
|
+
"""
|
|
211
|
+
根据服务器名称获取工具(支持单个或多个服务器)
|
|
212
|
+
|
|
213
|
+
Args:
|
|
214
|
+
server_names: 服务器名称或服务器名称列表
|
|
215
|
+
|
|
216
|
+
Returns:
|
|
217
|
+
List[BaseTool]: 工具列表(如果是多个服务器,会合并去重)
|
|
218
|
+
|
|
219
|
+
Examples:
|
|
220
|
+
# 获取单个服务器的工具
|
|
221
|
+
tools = await mcp_client.get_tools_by_server("web_search_server")
|
|
222
|
+
|
|
223
|
+
# 获取多个服务器的工具
|
|
224
|
+
tools = await mcp_client.get_tools_by_server(["web_search_server", "file-processor"])
|
|
225
|
+
|
|
226
|
+
# 也支持传入逗号分隔的字符串
|
|
227
|
+
tools = await mcp_client.get_tools_by_server("web_search_server,file-processor")
|
|
228
|
+
"""
|
|
229
|
+
if not self._initialized:
|
|
230
|
+
await self.initialize()
|
|
231
|
+
|
|
232
|
+
if not self._client:
|
|
233
|
+
logger.warning("MCP客户端未初始化")
|
|
234
|
+
return []
|
|
235
|
+
|
|
236
|
+
# 统一处理输入格式
|
|
237
|
+
if isinstance(server_names, str):
|
|
238
|
+
# 支持逗号分隔的字符串
|
|
239
|
+
if ',' in server_names:
|
|
240
|
+
server_list = [s.strip() for s in server_names.split(',') if s.strip()]
|
|
241
|
+
else:
|
|
242
|
+
server_list = [server_names]
|
|
243
|
+
else:
|
|
244
|
+
server_list = server_names
|
|
245
|
+
|
|
246
|
+
if not server_list:
|
|
247
|
+
logger.warning("未提供有效的服务器名称")
|
|
248
|
+
return []
|
|
249
|
+
|
|
250
|
+
# 收集所有工具(去重)
|
|
251
|
+
all_server_tools = []
|
|
252
|
+
seen_tool_names = set()
|
|
253
|
+
|
|
254
|
+
for server_name in server_list:
|
|
255
|
+
# 检查缓存
|
|
256
|
+
if server_name in self._server_tools_cache:
|
|
257
|
+
logger.debug(f"使用缓存的服务器工具: {server_name}")
|
|
258
|
+
server_tools = self._server_tools_cache[server_name]
|
|
259
|
+
else:
|
|
260
|
+
# 获取该服务器的工具
|
|
261
|
+
server_tools = await self._get_single_server_tools(server_name)
|
|
262
|
+
# 缓存结果
|
|
263
|
+
self._server_tools_cache[server_name] = server_tools
|
|
264
|
+
|
|
265
|
+
# 添加到结果中(去重)
|
|
266
|
+
for tool in server_tools:
|
|
267
|
+
if tool.name not in seen_tool_names:
|
|
268
|
+
all_server_tools.append(tool)
|
|
269
|
+
seen_tool_names.add(tool.name)
|
|
270
|
+
|
|
271
|
+
if len(server_list) == 1:
|
|
272
|
+
logger.info(f"服务器 {server_list[0]} 有 {len(all_server_tools)} 个工具")
|
|
273
|
+
else:
|
|
274
|
+
logger.info(f"从 {len(server_list)} 个服务器获取了 {len(all_server_tools)} 个工具(已去重)")
|
|
275
|
+
|
|
276
|
+
return all_server_tools
|
|
277
|
+
|
|
278
|
+
async def _get_single_server_tools(self, server_name: str) -> List[BaseTool]:
|
|
279
|
+
"""
|
|
280
|
+
获取单个服务器的工具(内部方法)
|
|
281
|
+
|
|
282
|
+
Args:
|
|
283
|
+
server_name: 服务器名称
|
|
284
|
+
|
|
285
|
+
Returns:
|
|
286
|
+
List[BaseTool]: 该服务器的工具列表
|
|
287
|
+
"""
|
|
288
|
+
try:
|
|
289
|
+
all_tools = await self._client.get_tools()
|
|
290
|
+
server_tools = []
|
|
291
|
+
|
|
292
|
+
for tool in all_tools:
|
|
293
|
+
# 方式1: 检查 tool.server 属性
|
|
294
|
+
if hasattr(tool, 'server') and tool.server == server_name:
|
|
295
|
+
server_tools.append(tool)
|
|
296
|
+
# 方式2: 检查 tool.metadata
|
|
297
|
+
elif hasattr(tool, 'metadata') and tool.metadata is not None and tool.metadata.get('server') == server_name:
|
|
298
|
+
server_tools.append(tool)
|
|
299
|
+
# 方式3: 检查 enabled_tools_map 配置
|
|
300
|
+
elif server_name in self._enabled_tools_map:
|
|
301
|
+
if tool.name in self._enabled_tools_map[server_name]:
|
|
302
|
+
server_tools.append(tool)
|
|
303
|
+
|
|
304
|
+
# 如果前面的方式都没找到,但配置了 enabled_tools,尝试按工具名匹配
|
|
305
|
+
if not server_tools and server_name in self._enabled_tools_map:
|
|
306
|
+
enabled_tool_names = self._enabled_tools_map[server_name]
|
|
307
|
+
server_tools = [
|
|
308
|
+
tool for tool in all_tools
|
|
309
|
+
if tool.name in enabled_tool_names
|
|
310
|
+
]
|
|
311
|
+
|
|
312
|
+
logger.debug(f"服务器 {server_name} 有 {len(server_tools)} 个工具")
|
|
313
|
+
return server_tools
|
|
314
|
+
|
|
315
|
+
except Exception as e:
|
|
316
|
+
logger.error(f"获取服务器 {server_name} 的工具失败: {str(e)}", exc_info=True)
|
|
317
|
+
return []
|
|
318
|
+
|
|
319
|
+
async def list_servers(self) -> List[str]:
|
|
320
|
+
"""
|
|
321
|
+
列出所有配置的服务器名称
|
|
322
|
+
|
|
323
|
+
Returns:
|
|
324
|
+
List[str]: 服务器名称列表
|
|
325
|
+
|
|
326
|
+
Examples:
|
|
327
|
+
servers = await mcp_client.list_servers()
|
|
328
|
+
print(f"已配置的服务器: {servers}")
|
|
329
|
+
"""
|
|
330
|
+
mcp_config = self._get_mcp_config()
|
|
331
|
+
default_servers = mcp_config.get('default_servers', {})
|
|
332
|
+
return list(default_servers.keys())
|
|
333
|
+
|
|
334
|
+
def close(self):
|
|
335
|
+
"""
|
|
336
|
+
清理 MCP 客户端
|
|
337
|
+
"""
|
|
338
|
+
if self._client and self._initialized:
|
|
339
|
+
self._initialized = False
|
|
340
|
+
self._client = None
|
|
341
|
+
self._server_tools_cache.clear()
|
|
342
|
+
logger.info("MCP客户端已清理")
|
|
343
|
+
|
|
344
|
+
# mcp_client = MCPClient()
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import os
|
|
3
3
|
from contextlib import contextmanager
|
|
4
|
-
from dotenv import load_dotenv
|
|
4
|
+
from dotenv import load_dotenv, find_dotenv
|
|
5
5
|
from sqlalchemy import create_engine, text
|
|
6
6
|
from sqlalchemy.exc import OperationalError
|
|
7
7
|
from sqlalchemy.orm import sessionmaker, scoped_session
|
|
8
8
|
|
|
9
|
-
load_dotenv()
|
|
9
|
+
load_dotenv(find_dotenv(usecwd=True))
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
sqlalchemy_database_uri = os.getenv("SQLALCHEMY_DATABASE_URI", "sqlite:///fallback.db")
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import time
|
|
5
|
+
from typing import Dict
|
|
6
|
+
|
|
7
|
+
from redis.asyncio import ConnectionPool, Redis
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class RedisPoolManager:
|
|
11
|
+
"""
|
|
12
|
+
单例,负责:
|
|
13
|
+
1. 持有全局 ConnectionPool
|
|
14
|
+
2. 记录 client_id -> Redis 实例
|
|
15
|
+
3. 生命周期内统一创建/销毁
|
|
16
|
+
"""
|
|
17
|
+
_inst: RedisPoolManager | None = None
|
|
18
|
+
_lock = asyncio.Lock()
|
|
19
|
+
|
|
20
|
+
def __new__(cls, *a, **kw):
|
|
21
|
+
if cls._inst is None:
|
|
22
|
+
cls._inst = super().__new__(cls)
|
|
23
|
+
return cls._inst
|
|
24
|
+
|
|
25
|
+
def __init__(
|
|
26
|
+
self,
|
|
27
|
+
redis_url: str = "redis://localhost:6379/0",
|
|
28
|
+
max_connections: int = 256,
|
|
29
|
+
):
|
|
30
|
+
# 只允许初始化一次
|
|
31
|
+
if hasattr(self, "_init"):
|
|
32
|
+
return
|
|
33
|
+
self.redis_url = redis_url
|
|
34
|
+
self.max_connections = max_connections
|
|
35
|
+
self._pool: ConnectionPool | None = None
|
|
36
|
+
self._clients: Dict[str, Redis] = {}
|
|
37
|
+
self._init = True
|
|
38
|
+
|
|
39
|
+
async def ensure_pool(self):
|
|
40
|
+
"""延迟创建pool"""
|
|
41
|
+
if self._pool is None:
|
|
42
|
+
self._pool = ConnectionPool.from_url(
|
|
43
|
+
self.redis_url,
|
|
44
|
+
max_connections=self.max_connections,
|
|
45
|
+
decode_responses=True, # 直接 str,免手动 decode
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
async def startup(self):
|
|
49
|
+
"""FastAPI startup 事件回调"""
|
|
50
|
+
await self.ensure_pool()
|
|
51
|
+
|
|
52
|
+
async def shutdown(self):
|
|
53
|
+
"""FastAPI shutdown 事件回调"""
|
|
54
|
+
async with self._lock:
|
|
55
|
+
# 1. 关闭所有客户端
|
|
56
|
+
await asyncio.gather(*(c.aclose() for c in self._clients.values()))
|
|
57
|
+
|
|
58
|
+
self._clients.clear()
|
|
59
|
+
# 2. 关闭连接池
|
|
60
|
+
if self._pool:
|
|
61
|
+
await self._pool.aclose()
|
|
62
|
+
self._pool = None
|
|
63
|
+
|
|
64
|
+
async def get_client(self, client_id: str) -> Redis:
|
|
65
|
+
"""线程安全地获取(或创建)一个 Redis 实例,复用同一池"""
|
|
66
|
+
async with self._lock:
|
|
67
|
+
if client_id in self._clients:
|
|
68
|
+
return self._clients[client_id]
|
|
69
|
+
await self.ensure_pool()
|
|
70
|
+
redis = Redis.from_pool(connection_pool=self._pool)
|
|
71
|
+
self._clients[client_id] = redis
|
|
72
|
+
return redis
|
|
73
|
+
|
|
74
|
+
async def close_client(self, client_id: str) -> bool:
|
|
75
|
+
"""线程安全地关闭一个 Redis 实例"""
|
|
76
|
+
async with self._lock:
|
|
77
|
+
if client_id in self._clients:
|
|
78
|
+
await self._clients[client_id].aclose()
|
|
79
|
+
await self._clients.pop(client_id)
|
|
80
|
+
return True
|
|
81
|
+
return False
|
|
82
|
+
|
|
83
|
+
async def list_clients(self) -> None:
|
|
84
|
+
"""线程安全地关闭一个 Redis 实例"""
|
|
85
|
+
async with self._lock:
|
|
86
|
+
clients = [c for c in self._clients.values()]
|
|
87
|
+
print(f'共{len(clients)}个client')
|
|
88
|
+
|
|
89
|
+
async def __aenter__(self):
|
|
90
|
+
"""异步上下文管理器入口"""
|
|
91
|
+
await self.startup()
|
|
92
|
+
return self
|
|
93
|
+
|
|
94
|
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
95
|
+
"""异步上下文管理器出口"""
|
|
96
|
+
await self.shutdown()
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
if __name__ == '__main__':
|
|
100
|
+
global_redis_pool_manager = RedisPoolManager()
|
|
101
|
+
|
|
102
|
+
async def _main():
|
|
103
|
+
client = await global_redis_pool_manager.get_client(client_id='test_1234')
|
|
104
|
+
await global_redis_pool_manager.list_clients()
|
|
105
|
+
|
|
106
|
+
await client.set('k1', 'hello', ex=3) # 设值 + 30 秒过期
|
|
107
|
+
val = await client.get('k1')
|
|
108
|
+
print(f'get redis cache: {val}')
|
|
109
|
+
|
|
110
|
+
time.sleep(3)
|
|
111
|
+
|
|
112
|
+
val = await client.get('k1')
|
|
113
|
+
print(f'get redis cache: {val}')
|
|
114
|
+
|
|
115
|
+
await global_redis_pool_manager.close_client(client_id='test_1234')
|
|
116
|
+
await global_redis_pool_manager.list_clients()
|
|
117
|
+
|
|
118
|
+
asyncio.run(_main())
|
{agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/agentic_kit_common/sms/ali_sms_client.py
RENAMED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
from aliyunsdkcore.client import AcsClient
|
|
2
2
|
from aliyunsdkcore.request import CommonRequest
|
|
3
|
-
from dotenv import load_dotenv
|
|
3
|
+
from dotenv import load_dotenv, find_dotenv
|
|
4
4
|
from pydantic import Field
|
|
5
5
|
from pydantic_settings import BaseSettings
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
load_dotenv()
|
|
8
|
+
load_dotenv(find_dotenv(usecwd=True))
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
class SmsSettings(BaseSettings):
|
|
File without changes
|
{agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/agentic_kit_common.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentic-kit-common
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.21
|
|
4
4
|
Summary: Common utilities and tools for agentic kit ecosystem
|
|
5
5
|
Home-page:
|
|
6
6
|
Author: manson
|
|
@@ -25,12 +25,14 @@ Requires-Dist: langgraph
|
|
|
25
25
|
Requires-Dist: langchain_community
|
|
26
26
|
Requires-Dist: langchain_experimental
|
|
27
27
|
Requires-Dist: langchain-openai
|
|
28
|
+
Requires-Dist: langchain_mcp_adapters
|
|
28
29
|
Requires-Dist: mysql-connector-python
|
|
29
30
|
Requires-Dist: sqlalchemy
|
|
30
31
|
Requires-Dist: sqlglot
|
|
31
32
|
Requires-Dist: pymilvus
|
|
32
33
|
Requires-Dist: xinference_client
|
|
33
34
|
Requires-Dist: pymongo
|
|
35
|
+
Requires-Dist: redis
|
|
34
36
|
Requires-Dist: aliyun-python-sdk-core
|
|
35
37
|
Requires-Dist: aliyun-python-sdk-dysmsapi
|
|
36
38
|
Dynamic: author
|
{agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/agentic_kit_common.egg-info/SOURCES.txt
RENAMED
|
@@ -6,11 +6,15 @@ agentic_kit_common.egg-info/SOURCES.txt
|
|
|
6
6
|
agentic_kit_common.egg-info/dependency_links.txt
|
|
7
7
|
agentic_kit_common.egg-info/requires.txt
|
|
8
8
|
agentic_kit_common.egg-info/top_level.txt
|
|
9
|
+
agentic_kit_common/config/__init__.py
|
|
10
|
+
agentic_kit_common/config/config_loader.py
|
|
9
11
|
agentic_kit_common/llm/__init__.py
|
|
10
12
|
agentic_kit_common/llm/openai.py
|
|
11
13
|
agentic_kit_common/llm/utils.py
|
|
12
14
|
agentic_kit_common/log/__init__.py
|
|
13
15
|
agentic_kit_common/log/logger.py
|
|
16
|
+
agentic_kit_common/mcp/__init__.py
|
|
17
|
+
agentic_kit_common/mcp/mcp_client.py
|
|
14
18
|
agentic_kit_common/minio/__init__.py
|
|
15
19
|
agentic_kit_common/minio/minio_manager.py
|
|
16
20
|
agentic_kit_common/mongodb/__init__.py
|
|
@@ -22,6 +26,8 @@ agentic_kit_common/orm/manager.py
|
|
|
22
26
|
agentic_kit_common/orm/multi_session.py
|
|
23
27
|
agentic_kit_common/orm/schema.py
|
|
24
28
|
agentic_kit_common/orm/session.py
|
|
29
|
+
agentic_kit_common/redis/__init__.py
|
|
30
|
+
agentic_kit_common/redis/redis_pool_manager.py
|
|
25
31
|
agentic_kit_common/sms/__init__.py
|
|
26
32
|
agentic_kit_common/sms/ali_sms_client.py
|
|
27
33
|
agentic_kit_common/vector/__init__.py
|
|
@@ -36,9 +42,12 @@ agentic_kit_common/web/__init__.py
|
|
|
36
42
|
agentic_kit_common/web/http/__init__.py
|
|
37
43
|
agentic_kit_common/web/http/response.py
|
|
38
44
|
test/__init__.py
|
|
45
|
+
test/conf.yaml
|
|
39
46
|
test/config.py
|
|
40
47
|
test/settings.py
|
|
48
|
+
test/test_config_manager.py
|
|
41
49
|
test/test_embedding.py
|
|
50
|
+
test/test_mcp_client.py
|
|
42
51
|
test/test_minio.py
|
|
43
52
|
test/test_orm.py
|
|
44
53
|
test/test_vector.py
|
{agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/agentic_kit_common.egg-info/requires.txt
RENAMED
|
@@ -7,11 +7,13 @@ langgraph
|
|
|
7
7
|
langchain_community
|
|
8
8
|
langchain_experimental
|
|
9
9
|
langchain-openai
|
|
10
|
+
langchain_mcp_adapters
|
|
10
11
|
mysql-connector-python
|
|
11
12
|
sqlalchemy
|
|
12
13
|
sqlglot
|
|
13
14
|
pymilvus
|
|
14
15
|
xinference_client
|
|
15
16
|
pymongo
|
|
17
|
+
redis
|
|
16
18
|
aliyun-python-sdk-core
|
|
17
19
|
aliyun-python-sdk-dysmsapi
|
|
@@ -4,7 +4,7 @@ from setuptools import setup, find_packages
|
|
|
4
4
|
|
|
5
5
|
setup(
|
|
6
6
|
name='agentic-kit-common',
|
|
7
|
-
version="0.0.
|
|
7
|
+
version="0.0.21",
|
|
8
8
|
author="manson",
|
|
9
9
|
author_email="manson.li3307@gmail.com",
|
|
10
10
|
description='Common utilities and tools for agentic kit ecosystem',
|
|
@@ -38,6 +38,7 @@ setup(
|
|
|
38
38
|
"langchain_community",
|
|
39
39
|
"langchain_experimental",
|
|
40
40
|
"langchain-openai",
|
|
41
|
+
"langchain_mcp_adapters",
|
|
41
42
|
|
|
42
43
|
# sqlalchemy
|
|
43
44
|
"mysql-connector-python",
|
|
@@ -55,6 +56,9 @@ setup(
|
|
|
55
56
|
# mongodb
|
|
56
57
|
"pymongo",
|
|
57
58
|
|
|
59
|
+
# redis
|
|
60
|
+
"redis",
|
|
61
|
+
|
|
58
62
|
# aliyun sms
|
|
59
63
|
"aliyun-python-sdk-core",
|
|
60
64
|
"aliyun-python-sdk-dysmsapi",
|
|
File without changes
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
BASIC_MODEL:
|
|
2
|
+
default: qwen3-235b-a22b
|
|
3
|
+
models:
|
|
4
|
+
qwen3-235b-a22b:
|
|
5
|
+
base_url: http://45.120.102.120:8990/v1
|
|
6
|
+
model: /mnt/data0/hf_models/models/Qwen/Qwen3-235B-A22B-Instruct-2507-FP8
|
|
7
|
+
api_key: YOUR_API_KEY
|
|
8
|
+
temperature: 0.1
|
|
9
|
+
|
|
10
|
+
VISION_MODEL:
|
|
11
|
+
default: qwen3-vl-235b-instruct
|
|
12
|
+
models:
|
|
13
|
+
qwen3-vl-235b-instruct:
|
|
14
|
+
base_url: http://45.120.102.120:10021/v1
|
|
15
|
+
model: Qwen3-VL-235B-A22B-Instruct-FP8
|
|
16
|
+
api_key: YOUR_API_KEY
|
|
17
|
+
temperature: 0.1
|
|
18
|
+
|
|
19
|
+
llm_ocr:
|
|
20
|
+
base_url: https://dashscope.aliyuncs.com/compatible-mode/v1
|
|
21
|
+
model: qwen-vl-ocr-latest
|
|
22
|
+
api_key: sk-c254cefb0b60414aa9a9686459c05602
|
|
23
|
+
temperature: 0.1
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# RAG 客户端配置
|
|
27
|
+
RAG_CLIENT:
|
|
28
|
+
base_url: http://45.120.102.233:8900
|
|
29
|
+
timeout: 120
|
|
30
|
+
|
|
31
|
+
# NL2SQL 数据库查询配置
|
|
32
|
+
DATABASE_CLIENT:
|
|
33
|
+
base_url: http://45.120.102.233:8991
|
|
34
|
+
timeout: 30
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
# MCP 服务器配置
|
|
38
|
+
MCP_SETTINGS:
|
|
39
|
+
default_servers:
|
|
40
|
+
file-processor:
|
|
41
|
+
transport: streamable_http
|
|
42
|
+
url: http://45.120.102.231:8920/mcp
|
|
43
|
+
enabled_tools:
|
|
44
|
+
- convert_to_markdown
|
|
45
|
+
|
|
46
|
+
web_search_server:
|
|
47
|
+
transport: streamable_http
|
|
48
|
+
url: http://45.120.102.231:8910/mcp
|
|
49
|
+
enabled_tools:
|
|
50
|
+
- web_search
|
|
51
|
+
|
|
52
|
+
crawl_page_server:
|
|
53
|
+
transport: streamable_http
|
|
54
|
+
url: http://45.120.102.231:8926/mcp
|
|
55
|
+
enabled_tools:
|
|
56
|
+
- crawl_page
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import sys
|
|
3
|
+
import unittest
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
project_root = Path(__file__).parent.parent
|
|
8
|
+
sys.path.insert(0, str(project_root))
|
|
9
|
+
|
|
10
|
+
logging.basicConfig(level=logging.DEBUG)
|
|
11
|
+
|
|
12
|
+
from agentic_kit_common.config import ConfigManager
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class MyTestCase(unittest.TestCase):
|
|
16
|
+
def test_config_manager(self):
|
|
17
|
+
config_manager = ConfigManager()
|
|
18
|
+
config_manager.load_config(force_reload=True)
|
|
19
|
+
|
|
20
|
+
print(config_manager.get_llm_config())
|
|
21
|
+
print(config_manager.get_llm_config(model_type='VISION_MODEL'))
|
|
22
|
+
print(config_manager.get_rag_config())
|
|
23
|
+
print(config_manager.get_mcp_config())
|
|
24
|
+
print(config_manager.get_database_config())
|
|
25
|
+
print(config_manager.get_full_config())
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
if __name__ == '__main__':
|
|
29
|
+
unittest.main()
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import logging
|
|
3
|
+
import sys
|
|
4
|
+
import unittest
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from agentic_kit_common.mcp.mcp_client import MCPClient
|
|
8
|
+
|
|
9
|
+
project_root = Path(__file__).parent.parent
|
|
10
|
+
sys.path.insert(0, str(project_root))
|
|
11
|
+
|
|
12
|
+
logging.basicConfig(level=logging.DEBUG)
|
|
13
|
+
|
|
14
|
+
from agentic_kit_common.config import ConfigManager
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class MyTestCase(unittest.TestCase):
|
|
18
|
+
def test_mcp_client(self):
|
|
19
|
+
config_manager = ConfigManager()
|
|
20
|
+
config_manager.load_config(force_reload=True)
|
|
21
|
+
|
|
22
|
+
mcp_client = MCPClient(config_manager=config_manager)
|
|
23
|
+
mcp_client.initialize()
|
|
24
|
+
print(asyncio.run(mcp_client.list_servers()))
|
|
25
|
+
print(asyncio.run(mcp_client.get_all_tools()))
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
if __name__ == '__main__':
|
|
29
|
+
unittest.main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/agentic_kit_common/minio/minio_manager.py
RENAMED
|
File without changes
|
{agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/agentic_kit_common/mongodb/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/agentic_kit_common/orm/multi_session.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/agentic_kit_common/vector/schema/__init__.py
RENAMED
|
File without changes
|
{agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/agentic_kit_common/vector/schema/base.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_kit_common-0.0.17/test → agentic_kit_common-0.0.21/agentic_kit_common/web}/__init__.py
RENAMED
|
File without changes
|
{agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/agentic_kit_common/web/http/response.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_kit_common-0.0.17 → agentic_kit_common-0.0.21}/agentic_kit_common.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|