jarvis-ai-assistant 0.1.179__py3-none-any.whl → 0.1.180__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.
Potentially problematic release.
This version of jarvis-ai-assistant might be problematic. Click here for more details.
- jarvis/__init__.py +1 -1
- jarvis/jarvis_data/config_schema.json +260 -0
- jarvis/jarvis_git_utils/git_commiter.py +1 -1
- jarvis/jarvis_platform/kimi.py +0 -22
- jarvis/jarvis_platform/openai.py +0 -15
- jarvis/jarvis_platform/yuanbao.py +0 -23
- jarvis/jarvis_smart_shell/main.py +6 -3
- jarvis/jarvis_tools/edit_file.py +1 -1
- jarvis/jarvis_tools/registry.py +41 -35
- jarvis/jarvis_utils/config.py +61 -20
- jarvis/jarvis_utils/git_utils.py +28 -15
- jarvis/jarvis_utils/utils.py +101 -61
- {jarvis_ai_assistant-0.1.179.dist-info → jarvis_ai_assistant-0.1.180.dist-info}/METADATA +44 -49
- {jarvis_ai_assistant-0.1.179.dist-info → jarvis_ai_assistant-0.1.180.dist-info}/RECORD +18 -17
- {jarvis_ai_assistant-0.1.179.dist-info → jarvis_ai_assistant-0.1.180.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.179.dist-info → jarvis_ai_assistant-0.1.180.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.1.179.dist-info → jarvis_ai_assistant-0.1.180.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.179.dist-info → jarvis_ai_assistant-0.1.180.dist-info}/top_level.txt +0 -0
jarvis/__init__.py
CHANGED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"title": "Jarvis环境变量配置模式",
|
|
4
|
+
"description": "Jarvis系统配置模式",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"JARVIS_MCP": {
|
|
8
|
+
"type": "array",
|
|
9
|
+
"description": "MCP工具配置列表",
|
|
10
|
+
"items": {
|
|
11
|
+
"type": "object",
|
|
12
|
+
"oneOf": [
|
|
13
|
+
{
|
|
14
|
+
"type": "object",
|
|
15
|
+
"required": [
|
|
16
|
+
"type",
|
|
17
|
+
"base_url"
|
|
18
|
+
],
|
|
19
|
+
"properties": {
|
|
20
|
+
"type": {
|
|
21
|
+
"type": "string",
|
|
22
|
+
"enum": [
|
|
23
|
+
"sse",
|
|
24
|
+
"streamable"
|
|
25
|
+
],
|
|
26
|
+
"description": "MCP客户端类型"
|
|
27
|
+
},
|
|
28
|
+
"base_url": {
|
|
29
|
+
"type": "string",
|
|
30
|
+
"format": "uri",
|
|
31
|
+
"description": "MCP服务器基础URL"
|
|
32
|
+
},
|
|
33
|
+
"auth_token": {
|
|
34
|
+
"type": "string",
|
|
35
|
+
"description": "认证令牌(可选)"
|
|
36
|
+
},
|
|
37
|
+
"headers": {
|
|
38
|
+
"type": "object",
|
|
39
|
+
"additionalProperties": {
|
|
40
|
+
"type": "string"
|
|
41
|
+
},
|
|
42
|
+
"description": "额外的HTTP头(可选)"
|
|
43
|
+
},
|
|
44
|
+
"name": {
|
|
45
|
+
"type": "string",
|
|
46
|
+
"description": "工具名称(可选)"
|
|
47
|
+
},
|
|
48
|
+
"enable": {
|
|
49
|
+
"type": "boolean",
|
|
50
|
+
"default": true,
|
|
51
|
+
"description": "是否启用该工具(可选)"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"type": "object",
|
|
57
|
+
"required": [
|
|
58
|
+
"type",
|
|
59
|
+
"command"
|
|
60
|
+
],
|
|
61
|
+
"properties": {
|
|
62
|
+
"type": {
|
|
63
|
+
"type": "string",
|
|
64
|
+
"enum": [
|
|
65
|
+
"stdio"
|
|
66
|
+
],
|
|
67
|
+
"description": "MCP客户端类型"
|
|
68
|
+
},
|
|
69
|
+
"command": {
|
|
70
|
+
"type": "string",
|
|
71
|
+
"description": "要执行的命令"
|
|
72
|
+
},
|
|
73
|
+
"args": {
|
|
74
|
+
"type": "array",
|
|
75
|
+
"items": {
|
|
76
|
+
"type": "string"
|
|
77
|
+
},
|
|
78
|
+
"description": "命令参数列表(可选)"
|
|
79
|
+
},
|
|
80
|
+
"env": {
|
|
81
|
+
"type": "object",
|
|
82
|
+
"additionalProperties": {
|
|
83
|
+
"type": "string"
|
|
84
|
+
},
|
|
85
|
+
"description": "环境变量(可选)"
|
|
86
|
+
},
|
|
87
|
+
"name": {
|
|
88
|
+
"type": "string",
|
|
89
|
+
"description": "工具名称(可选)"
|
|
90
|
+
},
|
|
91
|
+
"enable": {
|
|
92
|
+
"type": "boolean",
|
|
93
|
+
"default": true,
|
|
94
|
+
"description": "是否启用该工具(可选)"
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
]
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
"ENV": {
|
|
102
|
+
"type": "object",
|
|
103
|
+
"description": "需要设置的额外环境变量",
|
|
104
|
+
"additionalProperties": {
|
|
105
|
+
"type": "string"
|
|
106
|
+
},
|
|
107
|
+
"default": {}
|
|
108
|
+
},
|
|
109
|
+
"JARVIS_GIT_COMMIT_PROMPT": {
|
|
110
|
+
"type": "string",
|
|
111
|
+
"description": "Git提交信息生成提示模板",
|
|
112
|
+
"default": ""
|
|
113
|
+
},
|
|
114
|
+
"JARVIS_MAX_TOKEN_COUNT": {
|
|
115
|
+
"type": "string",
|
|
116
|
+
"description": "模型能处理的最大token数量",
|
|
117
|
+
"default": "960000"
|
|
118
|
+
},
|
|
119
|
+
"JARVIS_MAX_INPUT_TOKEN_COUNT": {
|
|
120
|
+
"type": "string",
|
|
121
|
+
"description": "模型能处理的最大输入token数量",
|
|
122
|
+
"default": "32000"
|
|
123
|
+
},
|
|
124
|
+
"JARVIS_AUTO_COMPLETE": {
|
|
125
|
+
"type": "string",
|
|
126
|
+
"description": "是否启用自动补全功能",
|
|
127
|
+
"default": "false",
|
|
128
|
+
"enum": [
|
|
129
|
+
"true",
|
|
130
|
+
"false"
|
|
131
|
+
]
|
|
132
|
+
},
|
|
133
|
+
"SHELL": {
|
|
134
|
+
"type": "string",
|
|
135
|
+
"description": "系统shell名称(如: bash, zsh)",
|
|
136
|
+
"default": "/bin/bash"
|
|
137
|
+
},
|
|
138
|
+
"JARVIS_PLATFORM": {
|
|
139
|
+
"type": "string",
|
|
140
|
+
"description": "常规操作平台名称",
|
|
141
|
+
"default": "yuanbao"
|
|
142
|
+
},
|
|
143
|
+
"JARVIS_MODEL": {
|
|
144
|
+
"type": "string",
|
|
145
|
+
"description": "常规操作模型名称",
|
|
146
|
+
"default": "deep_seek_v3"
|
|
147
|
+
},
|
|
148
|
+
"JARVIS_THINKING_PLATFORM": {
|
|
149
|
+
"type": "string",
|
|
150
|
+
"description": "思考操作平台名称",
|
|
151
|
+
"default": "yuanbao"
|
|
152
|
+
},
|
|
153
|
+
"JARVIS_THINKING_MODEL": {
|
|
154
|
+
"type": "string",
|
|
155
|
+
"description": "思考操作模型名称",
|
|
156
|
+
"default": "deep_seek"
|
|
157
|
+
},
|
|
158
|
+
"JARVIS_EXECUTE_TOOL_CONFIRM": {
|
|
159
|
+
"type": "string",
|
|
160
|
+
"description": "执行工具前是否需要确认",
|
|
161
|
+
"default": "false",
|
|
162
|
+
"enum": [
|
|
163
|
+
"true",
|
|
164
|
+
"false"
|
|
165
|
+
]
|
|
166
|
+
},
|
|
167
|
+
"JARVIS_CONFIRM_BEFORE_APPLY_PATCH": {
|
|
168
|
+
"type": "string",
|
|
169
|
+
"description": "应用补丁前是否需要确认",
|
|
170
|
+
"default": "true",
|
|
171
|
+
"enum": [
|
|
172
|
+
"true",
|
|
173
|
+
"false"
|
|
174
|
+
]
|
|
175
|
+
},
|
|
176
|
+
"JARVIS_MAX_TOOL_CALL_COUNT": {
|
|
177
|
+
"type": "string",
|
|
178
|
+
"description": "最大连续工具调用次数",
|
|
179
|
+
"default": "20"
|
|
180
|
+
},
|
|
181
|
+
"JARVIS_DATA_PATH": {
|
|
182
|
+
"type": "string",
|
|
183
|
+
"description": "Jarvis数据存储目录路径",
|
|
184
|
+
"default": "~/.jarvis"
|
|
185
|
+
},
|
|
186
|
+
"JARVIS_AUTO_UPDATE": {
|
|
187
|
+
"type": "string",
|
|
188
|
+
"description": "是否自动更新git仓库",
|
|
189
|
+
"default": "true",
|
|
190
|
+
"enum": [
|
|
191
|
+
"true",
|
|
192
|
+
"false"
|
|
193
|
+
]
|
|
194
|
+
},
|
|
195
|
+
"JARVIS_MAX_BIG_CONTENT_SIZE": {
|
|
196
|
+
"type": "string",
|
|
197
|
+
"description": "最大大内容尺寸",
|
|
198
|
+
"default": "1024000"
|
|
199
|
+
},
|
|
200
|
+
"JARVIS_PRETTY_OUTPUT": {
|
|
201
|
+
"type": "string",
|
|
202
|
+
"description": "是否启用美化输出",
|
|
203
|
+
"default": "false",
|
|
204
|
+
"enum": [
|
|
205
|
+
"true",
|
|
206
|
+
"false"
|
|
207
|
+
]
|
|
208
|
+
},
|
|
209
|
+
"JARVIS_USE_METHODOLOGY": {
|
|
210
|
+
"type": "string",
|
|
211
|
+
"description": "是否启用方法论",
|
|
212
|
+
"default": "false",
|
|
213
|
+
"enum": [
|
|
214
|
+
"true",
|
|
215
|
+
"false"
|
|
216
|
+
]
|
|
217
|
+
},
|
|
218
|
+
"JARVIS_USE_ANALYSIS": {
|
|
219
|
+
"type": "string",
|
|
220
|
+
"description": "是否启用任务分析",
|
|
221
|
+
"default": "false",
|
|
222
|
+
"enum": [
|
|
223
|
+
"true",
|
|
224
|
+
"false"
|
|
225
|
+
]
|
|
226
|
+
},
|
|
227
|
+
"JARVIS_PRINT_PROMPT": {
|
|
228
|
+
"type": "string",
|
|
229
|
+
"description": "是否打印提示",
|
|
230
|
+
"default": "false",
|
|
231
|
+
"enum": [
|
|
232
|
+
"true",
|
|
233
|
+
"false"
|
|
234
|
+
]
|
|
235
|
+
},
|
|
236
|
+
"JARVIS_REPLACE_MAP": {
|
|
237
|
+
"type": "object",
|
|
238
|
+
"description": "自定义替换映射表配置",
|
|
239
|
+
"additionalProperties": {
|
|
240
|
+
"type": "object",
|
|
241
|
+
"properties": {
|
|
242
|
+
"append": {
|
|
243
|
+
"type": "boolean",
|
|
244
|
+
"description": "Whether to append to existing template"
|
|
245
|
+
},
|
|
246
|
+
"template": {
|
|
247
|
+
"type": "string",
|
|
248
|
+
"description": "Replacement template content"
|
|
249
|
+
},
|
|
250
|
+
"description": {
|
|
251
|
+
"type": "string",
|
|
252
|
+
"description": "Description of the replacement"
|
|
253
|
+
}
|
|
254
|
+
},
|
|
255
|
+
"required": ["template"]
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
},
|
|
259
|
+
"additionalProperties": false
|
|
260
|
+
}
|
jarvis/jarvis_platform/kimi.py
CHANGED
|
@@ -6,10 +6,6 @@ import time
|
|
|
6
6
|
from typing import Dict, Generator, List, Tuple
|
|
7
7
|
|
|
8
8
|
import requests # type: ignore
|
|
9
|
-
from rich import box
|
|
10
|
-
from rich.live import Live
|
|
11
|
-
from rich.panel import Panel
|
|
12
|
-
from rich.text import Text
|
|
13
9
|
|
|
14
10
|
from jarvis.jarvis_platform.base import BasePlatform
|
|
15
11
|
from jarvis.jarvis_utils.config import get_data_dir
|
|
@@ -37,24 +33,6 @@ class KimiModel(BasePlatform):
|
|
|
37
33
|
self.chat_id = ""
|
|
38
34
|
self.api_key = os.getenv("KIMI_API_KEY")
|
|
39
35
|
if not self.api_key:
|
|
40
|
-
message = (
|
|
41
|
-
"需要设置 KIMI_API_KEY 才能使用 Jarvis。请按照以下步骤操作:\n"
|
|
42
|
-
"1. 获取 Kimi API Key:\n"
|
|
43
|
-
" • 访问 Kimi AI 平台: https://kimi.moonshot.cn\n"
|
|
44
|
-
" • 登录您的账户\n"
|
|
45
|
-
" • 打开浏览器开发者工具 (F12 或右键 -> 检查)\n"
|
|
46
|
-
" • 切换到网络标签\n"
|
|
47
|
-
" • 发送任意消息\n"
|
|
48
|
-
" • 在请求中找到 Authorization 头\n"
|
|
49
|
-
" • 复制 token 值(去掉 'Bearer ' 前缀)\n"
|
|
50
|
-
"2. 设置环境变量:\n"
|
|
51
|
-
" • 方法 1: 创建或编辑配置文件:\n"
|
|
52
|
-
f" echo 'KIMI_API_KEY=your_key_here' > {get_data_dir()}/env\n"
|
|
53
|
-
" • 方法 2: 直接设置环境变量:\n"
|
|
54
|
-
" export KIMI_API_KEY=your_key_here\n"
|
|
55
|
-
"设置后,重新运行 Jarvis。"
|
|
56
|
-
)
|
|
57
|
-
PrettyOutput.print(message, OutputType.INFO)
|
|
58
36
|
PrettyOutput.print("KIMI_API_KEY 未设置", OutputType.WARNING)
|
|
59
37
|
self.auth_header = f"Bearer {self.api_key}"
|
|
60
38
|
self.uploaded_files = [] # 存储已上传文件的信息
|
jarvis/jarvis_platform/openai.py
CHANGED
|
@@ -19,21 +19,6 @@ class OpenAIModel(BasePlatform):
|
|
|
19
19
|
self.system_message = ""
|
|
20
20
|
self.api_key = os.getenv("OPENAI_API_KEY")
|
|
21
21
|
if not self.api_key:
|
|
22
|
-
message = (
|
|
23
|
-
"需要设置以下环境变量才能使用 OpenAI 模型:\n"
|
|
24
|
-
" • OPENAI_API_KEY: API 密钥\n"
|
|
25
|
-
" • OPENAI_API_BASE: (可选) API 基础地址, 默认使用 https://api.openai.com/v1\n"
|
|
26
|
-
"您可以通过以下方式设置它们:\n"
|
|
27
|
-
"1. 创建或编辑 ~/.jarvis/env 文件:\n"
|
|
28
|
-
" OPENAI_API_KEY=your_api_key\n"
|
|
29
|
-
" OPENAI_API_BASE=your_api_base\n"
|
|
30
|
-
" OPENAI_MODEL_NAME=your_model_name\n"
|
|
31
|
-
"2. 直接设置环境变量:\n"
|
|
32
|
-
" export OPENAI_API_KEY=your_api_key\n"
|
|
33
|
-
" export OPENAI_API_BASE=your_api_base\n"
|
|
34
|
-
" export OPENAI_MODEL_NAME=your_model_name"
|
|
35
|
-
)
|
|
36
|
-
PrettyOutput.print(message, OutputType.INFO)
|
|
37
22
|
PrettyOutput.print("OPENAI_API_KEY 未设置", OutputType.WARNING)
|
|
38
23
|
|
|
39
24
|
self.base_url = os.getenv("OPENAI_API_BASE", "https://api.openai.com/v1")
|
|
@@ -9,10 +9,6 @@ from typing import Dict, Generator, List, Tuple
|
|
|
9
9
|
|
|
10
10
|
import requests
|
|
11
11
|
from PIL import Image
|
|
12
|
-
from rich import box
|
|
13
|
-
from rich.live import Live
|
|
14
|
-
from rich.panel import Panel
|
|
15
|
-
from rich.text import Text
|
|
16
12
|
from yaspin import yaspin
|
|
17
13
|
from yaspin.api import Yaspin
|
|
18
14
|
from yaspin.spinners import Spinners
|
|
@@ -43,25 +39,6 @@ class YuanbaoPlatform(BasePlatform):
|
|
|
43
39
|
self.agent_id = os.getenv("YUANBAO_AGENT_ID") # 代理ID
|
|
44
40
|
|
|
45
41
|
if not self.cookies:
|
|
46
|
-
message = (
|
|
47
|
-
"需要设置 YUANBAO_COOKIES 和 YUANBAO_AGENT_ID 才能使用 Jarvis 的元宝功能。请按照以下步骤操作:\n"
|
|
48
|
-
"1. 获取元宝 API 参数:\n"
|
|
49
|
-
" • 访问元宝平台: https://yuanbao.tencent.com\n"
|
|
50
|
-
" • 登录您的账户\n"
|
|
51
|
-
" • 打开浏览器开发者工具 (F12 或右键 -> 检查)\n"
|
|
52
|
-
" • 切换到网络标签\n"
|
|
53
|
-
" • 发送任意消息\n"
|
|
54
|
-
" • 查看请求中的 Cookie 和 AgentID 值(具体位置见README.md中截图)\n"
|
|
55
|
-
"2. 设置环境变量:\n"
|
|
56
|
-
" • 方法 1: 创建或编辑配置文件:\n"
|
|
57
|
-
f" echo 'YUANBAO_COOKIES=your_cookies_here' >> {get_data_dir()}/env\n"
|
|
58
|
-
f" echo 'YUANBAO_AGENT_ID=your_agent_id_here' >> {get_data_dir()}/env\n"
|
|
59
|
-
" • 方法 2: 直接设置环境变量:\n"
|
|
60
|
-
" export YUANBAO_COOKIES=your_cookies_here\n"
|
|
61
|
-
" export YUANBAO_AGENT_ID=your_agent_id_here\n"
|
|
62
|
-
"设置后,重新运行 Jarvis。"
|
|
63
|
-
)
|
|
64
|
-
PrettyOutput.print(message, OutputType.INFO)
|
|
65
42
|
PrettyOutput.print("YUANBAO_COOKIES 未设置", OutputType.WARNING)
|
|
66
43
|
|
|
67
44
|
self.system_message = "" # 系统消息,用于初始化对话
|
|
@@ -8,7 +8,7 @@ from typing import Optional
|
|
|
8
8
|
from sympy import false
|
|
9
9
|
|
|
10
10
|
from jarvis.jarvis_platform.registry import PlatformRegistry
|
|
11
|
-
from jarvis.jarvis_utils.config import get_shell_name
|
|
11
|
+
from jarvis.jarvis_utils.config import get_shell_name, set_config
|
|
12
12
|
from jarvis.jarvis_utils.input import get_multiline_input
|
|
13
13
|
from jarvis.jarvis_utils.utils import init_env
|
|
14
14
|
|
|
@@ -90,7 +90,7 @@ def process_request(request: str) -> Optional[str]:
|
|
|
90
90
|
|
|
91
91
|
# 规则
|
|
92
92
|
1. 只输出命令
|
|
93
|
-
2.
|
|
93
|
+
2. 不要输出任何命令之外的内容
|
|
94
94
|
3. 单行输出
|
|
95
95
|
4. 多个命令用&&连接
|
|
96
96
|
|
|
@@ -116,8 +116,11 @@ def process_request(request: str) -> Optional[str]:
|
|
|
116
116
|
return None
|
|
117
117
|
|
|
118
118
|
def main() -> int:
|
|
119
|
-
# 创建参数解析器
|
|
119
|
+
# 创建参数解析器
|
|
120
120
|
init_env("")
|
|
121
|
+
|
|
122
|
+
set_config("JARVIS_PRINT_PROMPT", "false")
|
|
123
|
+
|
|
121
124
|
parser = argparse.ArgumentParser(
|
|
122
125
|
description="将自然语言要求转换为shell命令",
|
|
123
126
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
jarvis/jarvis_tools/edit_file.py
CHANGED
|
@@ -156,7 +156,7 @@ class FileSearchReplaceTool:
|
|
|
156
156
|
with yaspin(text=f"正在处理文件 {file_path}...", color="cyan") as spinner:
|
|
157
157
|
success, temp_content = fast_edit(file_path, changes, spinner)
|
|
158
158
|
if not success:
|
|
159
|
-
success, temp_content = slow_edit(file_path, yaml.safe_dump(changes), spinner)
|
|
159
|
+
success, temp_content = slow_edit(file_path, yaml.safe_dump(changes, allow_unicode=True), spinner)
|
|
160
160
|
|
|
161
161
|
# 只有当所有替换操作都成功时,才写回文件
|
|
162
162
|
if success and (temp_content != original_content or not file_exists):
|
jarvis/jarvis_tools/registry.py
CHANGED
|
@@ -198,7 +198,7 @@ class ToolRegistry(OutputHandlerProtocol):
|
|
|
198
198
|
stats_file = Path(get_data_dir()) / "tool_stat.yaml"
|
|
199
199
|
try:
|
|
200
200
|
with open(stats_file, "w", encoding="utf-8") as f:
|
|
201
|
-
yaml.safe_dump(stats, f)
|
|
201
|
+
yaml.safe_dump(stats, f, allow_unicode=True)
|
|
202
202
|
except Exception as e:
|
|
203
203
|
PrettyOutput.print(
|
|
204
204
|
f"保存工具调用统计失败: {str(e)}", OutputType.WARNING
|
|
@@ -229,14 +229,36 @@ class ToolRegistry(OutputHandlerProtocol):
|
|
|
229
229
|
}
|
|
230
230
|
|
|
231
231
|
def _load_mcp_tools(self) -> None:
|
|
232
|
-
"""
|
|
232
|
+
"""加载MCP工具,优先从配置获取,其次从目录扫描"""
|
|
233
|
+
from jarvis.jarvis_utils.config import get_mcp_config
|
|
234
|
+
|
|
235
|
+
# 优先从配置获取MCP工具配置
|
|
236
|
+
mcp_configs = get_mcp_config()
|
|
237
|
+
if mcp_configs:
|
|
238
|
+
for config in mcp_configs:
|
|
239
|
+
self.register_mcp_tool_by_config(config)
|
|
240
|
+
return
|
|
241
|
+
|
|
242
|
+
# 如果配置中没有,则扫描目录
|
|
233
243
|
mcp_tools_dir = Path(get_data_dir()) / "mcp"
|
|
234
244
|
if not mcp_tools_dir.exists():
|
|
235
245
|
return
|
|
236
246
|
|
|
247
|
+
# 添加警告信息
|
|
248
|
+
PrettyOutput.print(
|
|
249
|
+
"警告: 从文件目录加载MCP工具的方式将在未来版本中废弃,请尽快迁移到JARVIS_MCP配置方式",
|
|
250
|
+
OutputType.WARNING
|
|
251
|
+
)
|
|
252
|
+
|
|
237
253
|
# 遍历目录中的所有.yaml文件
|
|
238
254
|
for file_path in mcp_tools_dir.glob("*.yaml"):
|
|
239
|
-
|
|
255
|
+
try:
|
|
256
|
+
config = yaml.safe_load(open(file_path, "r", encoding="utf-8"))
|
|
257
|
+
self.register_mcp_tool_by_config(config)
|
|
258
|
+
except Exception as e:
|
|
259
|
+
PrettyOutput.print(
|
|
260
|
+
f"文件 {file_path} 加载失败: {str(e)}", OutputType.WARNING
|
|
261
|
+
)
|
|
240
262
|
|
|
241
263
|
def _load_builtin_tools(self) -> None:
|
|
242
264
|
"""从内置工具目录加载工具"""
|
|
@@ -264,29 +286,26 @@ class ToolRegistry(OutputHandlerProtocol):
|
|
|
264
286
|
|
|
265
287
|
self.register_tool_by_file(str(file_path))
|
|
266
288
|
|
|
267
|
-
def
|
|
268
|
-
"""
|
|
289
|
+
def register_mcp_tool_by_config(self, config: Dict[str, Any]) -> bool:
|
|
290
|
+
"""从配置字典加载并注册工具
|
|
269
291
|
|
|
270
292
|
参数:
|
|
271
|
-
|
|
293
|
+
config: MCP工具配置字典
|
|
272
294
|
|
|
273
295
|
返回:
|
|
274
296
|
bool: 工具是否加载成功
|
|
275
297
|
"""
|
|
276
298
|
try:
|
|
277
|
-
config = yaml.safe_load(open(file_path, "r", encoding="utf-8"))
|
|
278
299
|
if "type" not in config:
|
|
279
|
-
PrettyOutput.print(f"
|
|
300
|
+
PrettyOutput.print(f"配置{config.get('name', '')}缺少type字段", OutputType.WARNING)
|
|
280
301
|
return False
|
|
281
302
|
|
|
282
303
|
# 检查enable标志
|
|
283
304
|
if not config.get("enable", True):
|
|
284
|
-
PrettyOutput.print(
|
|
285
|
-
f"文件 {file_path} 已禁用(enable=false),跳过注册", OutputType.INFO
|
|
286
|
-
)
|
|
305
|
+
PrettyOutput.print(f"MCP配置{config.get('name', '')}已禁用(enable=false),跳过注册", OutputType.INFO)
|
|
287
306
|
return False
|
|
288
307
|
|
|
289
|
-
name = config.get("name",
|
|
308
|
+
name = config.get("name", "mcp")
|
|
290
309
|
|
|
291
310
|
# 注册资源工具
|
|
292
311
|
def create_resource_list_func(client: McpClient):
|
|
@@ -296,11 +315,11 @@ class ToolRegistry(OutputHandlerProtocol):
|
|
|
296
315
|
args.pop("want", None)
|
|
297
316
|
ret = client.get_resource_list()
|
|
298
317
|
PrettyOutput.print(
|
|
299
|
-
f"MCP {name} 资源列表:\n{yaml.safe_dump(ret)}", OutputType.TOOL
|
|
318
|
+
f"MCP {name} 资源列表:\n{yaml.safe_dump(ret, allow_unicode=True)}", OutputType.TOOL
|
|
300
319
|
)
|
|
301
320
|
return {
|
|
302
321
|
"success": True,
|
|
303
|
-
"stdout": yaml.safe_dump(ret),
|
|
322
|
+
"stdout": yaml.safe_dump(ret, allow_unicode=True),
|
|
304
323
|
"stderr": "",
|
|
305
324
|
}
|
|
306
325
|
|
|
@@ -319,7 +338,7 @@ class ToolRegistry(OutputHandlerProtocol):
|
|
|
319
338
|
}
|
|
320
339
|
ret = client.get_resource(args["uri"])
|
|
321
340
|
PrettyOutput.print(
|
|
322
|
-
f"MCP {name} 获取资源:\n{yaml.safe_dump(ret)}", OutputType.TOOL
|
|
341
|
+
f"MCP {name} 获取资源:\n{yaml.safe_dump(ret, allow_unicode=True)}", OutputType.TOOL
|
|
323
342
|
)
|
|
324
343
|
return ret
|
|
325
344
|
|
|
@@ -332,7 +351,7 @@ class ToolRegistry(OutputHandlerProtocol):
|
|
|
332
351
|
args.pop("want", None)
|
|
333
352
|
ret = client.execute(tool_name, args)
|
|
334
353
|
PrettyOutput.print(
|
|
335
|
-
f"MCP {name} {tool_name} 执行结果:\n{yaml.safe_dump(ret)}",
|
|
354
|
+
f"MCP {name} {tool_name} 执行结果:\n{yaml.safe_dump(ret, allow_unicode=True)}",
|
|
336
355
|
OutputType.TOOL,
|
|
337
356
|
)
|
|
338
357
|
return ret
|
|
@@ -341,26 +360,18 @@ class ToolRegistry(OutputHandlerProtocol):
|
|
|
341
360
|
|
|
342
361
|
if config["type"] == "stdio":
|
|
343
362
|
if "command" not in config:
|
|
344
|
-
PrettyOutput.print(
|
|
345
|
-
f"文件 {file_path} 缺少command字段", OutputType.WARNING
|
|
346
|
-
)
|
|
363
|
+
PrettyOutput.print(f"配置{config.get('name', '')}缺少command字段", OutputType.WARNING)
|
|
347
364
|
return False
|
|
348
365
|
elif config["type"] == "sse":
|
|
349
366
|
if "base_url" not in config:
|
|
350
|
-
PrettyOutput.print(
|
|
351
|
-
f"文件 {file_path} 缺少base_url字段", OutputType.WARNING
|
|
352
|
-
)
|
|
367
|
+
PrettyOutput.print(f"配置{config.get('name', '')}缺少base_url字段", OutputType.WARNING)
|
|
353
368
|
return False
|
|
354
369
|
elif config["type"] == "streamable":
|
|
355
370
|
if "base_url" not in config:
|
|
356
|
-
PrettyOutput.print(
|
|
357
|
-
f"文件 {file_path} 缺少base_url字段", OutputType.WARNING
|
|
358
|
-
)
|
|
371
|
+
PrettyOutput.print(f"配置{config.get('name', '')}缺少base_url字段", OutputType.WARNING)
|
|
359
372
|
return False
|
|
360
373
|
else:
|
|
361
|
-
PrettyOutput.print(
|
|
362
|
-
f"文件 {file_path} 类型错误: {config['type']}", OutputType.WARNING
|
|
363
|
-
)
|
|
374
|
+
PrettyOutput.print(f"不支持的MCP客户端类型: {config['type']}", OutputType.WARNING)
|
|
364
375
|
return False
|
|
365
376
|
|
|
366
377
|
# 创建MCP客户端
|
|
@@ -376,14 +387,11 @@ class ToolRegistry(OutputHandlerProtocol):
|
|
|
376
387
|
# 获取工具信息
|
|
377
388
|
tools = mcp_client.get_tool_list()
|
|
378
389
|
if not tools:
|
|
379
|
-
PrettyOutput.print(
|
|
380
|
-
f"从 {file_path} 获取工具列表失败", OutputType.WARNING
|
|
381
|
-
)
|
|
390
|
+
PrettyOutput.print(f"从配置{config.get('name', '')}获取工具列表失败", OutputType.WARNING)
|
|
382
391
|
return False
|
|
383
392
|
|
|
384
393
|
# 注册每个工具
|
|
385
394
|
for tool in tools:
|
|
386
|
-
|
|
387
395
|
# 注册工具
|
|
388
396
|
self.register_tool(
|
|
389
397
|
name=f"{name}.tool_call.{tool['name']}",
|
|
@@ -417,9 +425,7 @@ class ToolRegistry(OutputHandlerProtocol):
|
|
|
417
425
|
return True
|
|
418
426
|
|
|
419
427
|
except Exception as e:
|
|
420
|
-
PrettyOutput.print(
|
|
421
|
-
f"文件 {file_path} 加载失败: {str(e)}", OutputType.WARNING
|
|
422
|
-
)
|
|
428
|
+
PrettyOutput.print(f"MCP配置{config.get('name', '')}加载失败: {str(e)}", OutputType.WARNING)
|
|
423
429
|
return False
|
|
424
430
|
|
|
425
431
|
def register_tool_by_file(self, file_path: str) -> bool:
|