jarvis-ai-assistant 0.1.125__py3-none-any.whl → 0.1.128__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_agent/__init__.py +205 -187
- jarvis/jarvis_code_agent/code_agent.py +116 -109
- jarvis/jarvis_code_agent/patch.py +157 -138
- jarvis/jarvis_code_agent/shell_input_handler.py +22 -0
- jarvis/jarvis_codebase/main.py +314 -288
- jarvis/jarvis_dev/main.py +695 -716
- jarvis/jarvis_lsp/base.py +0 -12
- jarvis/jarvis_lsp/cpp.py +0 -9
- jarvis/jarvis_lsp/go.py +0 -9
- jarvis/jarvis_lsp/python.py +0 -28
- jarvis/jarvis_lsp/registry.py +0 -1
- jarvis/jarvis_lsp/rust.py +0 -9
- jarvis/jarvis_multi_agent/__init__.py +52 -52
- jarvis/jarvis_platform/base.py +6 -5
- jarvis/jarvis_platform_manager/main.py +1 -1
- jarvis/jarvis_rag/main.py +250 -186
- jarvis/jarvis_smart_shell/main.py +0 -1
- jarvis/jarvis_tools/ask_codebase.py +10 -9
- jarvis/jarvis_tools/ask_user.py +2 -2
- jarvis/jarvis_tools/base.py +4 -4
- jarvis/jarvis_tools/chdir.py +28 -28
- jarvis/jarvis_tools/code_review.py +44 -39
- jarvis/jarvis_tools/create_code_agent.py +4 -4
- jarvis/jarvis_tools/create_sub_agent.py +7 -7
- jarvis/jarvis_tools/execute_shell.py +53 -23
- jarvis/jarvis_tools/execute_shell_script.py +3 -3
- jarvis/jarvis_tools/file_operation.py +70 -41
- jarvis/jarvis_tools/git_commiter.py +61 -51
- jarvis/jarvis_tools/lsp_find_definition.py +7 -7
- jarvis/jarvis_tools/lsp_prepare_rename.py +7 -7
- jarvis/jarvis_tools/methodology.py +6 -6
- jarvis/jarvis_tools/rag.py +5 -5
- jarvis/jarvis_tools/read_webpage.py +52 -32
- jarvis/jarvis_tools/registry.py +167 -180
- jarvis/jarvis_tools/search_web.py +66 -41
- jarvis/jarvis_tools/select_code_files.py +3 -3
- jarvis/jarvis_tools/tool_generator.py +68 -55
- jarvis/jarvis_utils/methodology.py +77 -59
- jarvis/jarvis_utils/output.py +1 -0
- {jarvis_ai_assistant-0.1.125.dist-info → jarvis_ai_assistant-0.1.128.dist-info}/METADATA +31 -17
- jarvis_ai_assistant-0.1.128.dist-info/RECORD +74 -0
- {jarvis_ai_assistant-0.1.125.dist-info → jarvis_ai_assistant-0.1.128.dist-info}/WHEEL +1 -1
- jarvis/jarvis_tools/lsp_validate_edit.py +0 -141
- jarvis/jarvis_tools/read_code.py +0 -192
- jarvis_ai_assistant-0.1.125.dist-info/RECORD +0 -75
- {jarvis_ai_assistant-0.1.125.dist-info → jarvis_ai_assistant-0.1.128.dist-info}/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.125.dist-info → jarvis_ai_assistant-0.1.128.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.1.125.dist-info → jarvis_ai_assistant-0.1.128.dist-info}/top_level.txt +0 -0
jarvis/jarvis_tools/registry.py
CHANGED
|
@@ -5,6 +5,7 @@ import sys
|
|
|
5
5
|
from typing import Any, Callable, Dict, List, Optional, Tuple
|
|
6
6
|
|
|
7
7
|
import yaml
|
|
8
|
+
from yaspin import yaspin
|
|
8
9
|
|
|
9
10
|
from jarvis.jarvis_agent.output_handler import OutputHandler
|
|
10
11
|
from jarvis.jarvis_platform.registry import PlatformRegistry
|
|
@@ -16,41 +17,41 @@ from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
tool_call_help = """
|
|
19
|
-
# 🛠️
|
|
20
|
-
|
|
20
|
+
# 🛠️ 工具使用系统
|
|
21
|
+
您正在使用一个需要精确格式和严格规则的工具执行系统。
|
|
21
22
|
|
|
22
|
-
# 📋
|
|
23
|
+
# 📋 工具调用格式
|
|
23
24
|
<TOOL_CALL>
|
|
24
|
-
name:
|
|
25
|
+
name: 工具名称
|
|
25
26
|
arguments:
|
|
26
|
-
param1:
|
|
27
|
-
param2:
|
|
27
|
+
param1: 值1
|
|
28
|
+
param2: 值2
|
|
28
29
|
</TOOL_CALL>
|
|
29
30
|
|
|
30
|
-
# ❗
|
|
31
|
-
1.
|
|
32
|
-
-
|
|
33
|
-
-
|
|
31
|
+
# ❗ 关键规则
|
|
32
|
+
1. 每次只使用一个工具
|
|
33
|
+
- 一次只执行一个工具
|
|
34
|
+
- 等待结果后再进行下一步
|
|
34
35
|
|
|
35
|
-
2.
|
|
36
|
-
-
|
|
37
|
-
-
|
|
38
|
-
-
|
|
36
|
+
2. 严格遵守格式
|
|
37
|
+
- 完全按照上述格式
|
|
38
|
+
- 使用正确的YAML缩进
|
|
39
|
+
- 包含所有必需参数
|
|
39
40
|
|
|
40
|
-
3.
|
|
41
|
-
-
|
|
42
|
-
-
|
|
43
|
-
-
|
|
44
|
-
-
|
|
41
|
+
3. 结果处理
|
|
42
|
+
- 等待执行结果
|
|
43
|
+
- 不要假设结果
|
|
44
|
+
- 不要创建虚假响应
|
|
45
|
+
- 不要想象对话
|
|
45
46
|
|
|
46
|
-
4.
|
|
47
|
-
-
|
|
48
|
-
-
|
|
49
|
-
-
|
|
50
|
-
-
|
|
47
|
+
4. 信息管理
|
|
48
|
+
- 如果信息不足,询问用户
|
|
49
|
+
- 跳过不必要的步骤
|
|
50
|
+
- 如果卡住,请求指导
|
|
51
|
+
- 不要在没有完整信息的情况下继续
|
|
51
52
|
|
|
52
|
-
# 📝
|
|
53
|
-
|
|
53
|
+
# 📝 字符串参数格式
|
|
54
|
+
始终使用 | 语法表示字符串参数:
|
|
54
55
|
|
|
55
56
|
<TOOL_CALL>
|
|
56
57
|
name: execute_shell
|
|
@@ -59,19 +60,19 @@ arguments:
|
|
|
59
60
|
git status --porcelain
|
|
60
61
|
</TOOL_CALL>
|
|
61
62
|
|
|
62
|
-
# 💡
|
|
63
|
-
-
|
|
64
|
-
-
|
|
65
|
-
-
|
|
66
|
-
-
|
|
67
|
-
-
|
|
68
|
-
|
|
69
|
-
# ⚠️
|
|
70
|
-
-
|
|
71
|
-
-
|
|
72
|
-
-
|
|
73
|
-
-
|
|
74
|
-
-
|
|
63
|
+
# 💡 最佳实践
|
|
64
|
+
- 准备好后立即开始执行
|
|
65
|
+
- 无需请求许可即可开始
|
|
66
|
+
- 使用正确的字符串格式
|
|
67
|
+
- 监控进度并调整
|
|
68
|
+
- 遇到困难时请求帮助
|
|
69
|
+
|
|
70
|
+
# ⚠️ 常见错误
|
|
71
|
+
- 同时调用多个工具
|
|
72
|
+
- 字符串参数缺少 |
|
|
73
|
+
- 假设工具结果
|
|
74
|
+
- 创建虚构对话
|
|
75
|
+
- 在没有所需信息的情况下继续
|
|
75
76
|
"""
|
|
76
77
|
|
|
77
78
|
class ToolRegistry(OutputHandler):
|
|
@@ -85,14 +86,14 @@ class ToolRegistry(OutputHandler):
|
|
|
85
86
|
return False
|
|
86
87
|
|
|
87
88
|
def prompt(self) -> str:
|
|
88
|
-
"""
|
|
89
|
+
"""加载工具"""
|
|
89
90
|
tools = self.get_all_tools()
|
|
90
91
|
if tools:
|
|
91
|
-
tools_prompt = "##
|
|
92
|
+
tools_prompt = "## 可用工具:\n"
|
|
92
93
|
for tool in tools:
|
|
93
|
-
tools_prompt += f"-
|
|
94
|
-
tools_prompt += f"
|
|
95
|
-
tools_prompt += f"
|
|
94
|
+
tools_prompt += f"- 名称: {tool['name']}\n"
|
|
95
|
+
tools_prompt += f" 描述: {tool['description']}\n"
|
|
96
|
+
tools_prompt += f" 参数: {tool['parameters']}\n"
|
|
96
97
|
tools_prompt += tool_call_help
|
|
97
98
|
return tools_prompt
|
|
98
99
|
return ""
|
|
@@ -101,87 +102,87 @@ class ToolRegistry(OutputHandler):
|
|
|
101
102
|
tool_calls = self._extract_tool_calls(response)
|
|
102
103
|
if len(tool_calls) > 1:
|
|
103
104
|
PrettyOutput.print(f"操作失败:检测到多个操作。一次只能执行一个操作。尝试执行的操作:{', '.join([tool_call['name'] for tool_call in tool_calls])}", OutputType.WARNING)
|
|
104
|
-
return False, f"
|
|
105
|
+
return False, f"调用失败:请一次只处理一个工具调用。"
|
|
105
106
|
if len(tool_calls) == 0:
|
|
106
107
|
return False, ""
|
|
107
108
|
tool_call = tool_calls[0]
|
|
108
109
|
return False, self.handle_tool_calls(tool_call)
|
|
109
110
|
|
|
110
111
|
def __init__(self):
|
|
111
|
-
"""
|
|
112
|
+
"""初始化工具注册表"""
|
|
112
113
|
self.tools: Dict[str, Tool] = {}
|
|
113
|
-
#
|
|
114
|
+
# 加载内置工具和外部工具
|
|
114
115
|
self._load_builtin_tools()
|
|
115
116
|
self._load_external_tools()
|
|
116
|
-
#
|
|
117
|
+
# 确保max_token_count是整数
|
|
117
118
|
self.max_token_count = int(get_max_token_count() * 0.8)
|
|
118
119
|
|
|
119
120
|
def use_tools(self, name: List[str]):
|
|
120
|
-
"""
|
|
121
|
+
"""使用指定工具"""
|
|
121
122
|
missing_tools = [tool_name for tool_name in name if tool_name not in self.tools]
|
|
122
123
|
if missing_tools:
|
|
123
124
|
PrettyOutput.print(f"工具 {missing_tools} 不存在,可用的工具有: {', '.join(self.tools.keys())}", OutputType.WARNING)
|
|
124
125
|
self.tools = {tool_name: self.tools[tool_name] for tool_name in name}
|
|
125
126
|
|
|
126
127
|
def dont_use_tools(self, names: List[str]):
|
|
127
|
-
"""
|
|
128
|
+
"""从注册表中移除指定工具"""
|
|
128
129
|
self.tools = {name: tool for name, tool in self.tools.items() if name not in names}
|
|
129
130
|
|
|
130
131
|
def _load_builtin_tools(self):
|
|
131
|
-
"""
|
|
132
|
+
"""从内置工具目录加载工具"""
|
|
132
133
|
tools_dir = Path(__file__).parent
|
|
133
134
|
|
|
134
|
-
#
|
|
135
|
+
# 遍历目录中的所有.py文件
|
|
135
136
|
for file_path in tools_dir.glob("*.py"):
|
|
136
|
-
#
|
|
137
|
+
# 跳过base.py和__init__.py
|
|
137
138
|
if file_path.name in ["base.py", "__init__.py", "registry.py"]:
|
|
138
139
|
continue
|
|
139
140
|
|
|
140
141
|
self.register_tool_by_file(str(file_path))
|
|
141
142
|
|
|
142
143
|
def _load_external_tools(self):
|
|
143
|
-
"""
|
|
144
|
+
"""从~/.jarvis/tools加载外部工具"""
|
|
144
145
|
external_tools_dir = Path.home() / '.jarvis/tools'
|
|
145
146
|
if not external_tools_dir.exists():
|
|
146
147
|
return
|
|
147
148
|
|
|
148
|
-
#
|
|
149
|
+
# 遍历目录中的所有.py文件
|
|
149
150
|
for file_path in external_tools_dir.glob("*.py"):
|
|
150
|
-
#
|
|
151
|
+
# 跳过__init__.py
|
|
151
152
|
if file_path.name == "__init__.py":
|
|
152
153
|
continue
|
|
153
154
|
|
|
154
155
|
self.register_tool_by_file(str(file_path))
|
|
155
156
|
|
|
156
157
|
def register_tool_by_file(self, file_path: str):
|
|
157
|
-
"""
|
|
158
|
+
"""从指定文件加载并注册工具
|
|
158
159
|
|
|
159
|
-
|
|
160
|
-
file_path:
|
|
160
|
+
参数:
|
|
161
|
+
file_path: 工具文件的路径
|
|
161
162
|
|
|
162
|
-
|
|
163
|
-
bool:
|
|
163
|
+
返回:
|
|
164
|
+
bool: 工具是否加载成功
|
|
164
165
|
"""
|
|
165
166
|
try:
|
|
166
|
-
p_file_path = Path(file_path).resolve() #
|
|
167
|
+
p_file_path = Path(file_path).resolve() # 获取绝对路径
|
|
167
168
|
if not p_file_path.exists() or not p_file_path.is_file():
|
|
168
169
|
PrettyOutput.print(f"文件不存在: {p_file_path}", OutputType.ERROR)
|
|
169
170
|
return False
|
|
170
171
|
|
|
171
|
-
#
|
|
172
|
+
# 临时将父目录添加到sys.path
|
|
172
173
|
parent_dir = str(p_file_path.parent)
|
|
173
174
|
sys.path.insert(0, parent_dir)
|
|
174
175
|
|
|
175
176
|
try:
|
|
176
|
-
#
|
|
177
|
+
# 使用标准导入机制导入模块
|
|
177
178
|
module_name = p_file_path.stem
|
|
178
179
|
module = __import__(module_name)
|
|
179
180
|
|
|
180
|
-
#
|
|
181
|
+
# 在模块中查找工具类
|
|
181
182
|
tool_found = False
|
|
182
183
|
for item_name in dir(module):
|
|
183
184
|
item = getattr(module, item_name)
|
|
184
|
-
#
|
|
185
|
+
# 检查是否是类并具有必要属性
|
|
185
186
|
if (isinstance(item, type) and
|
|
186
187
|
hasattr(item, 'name') and
|
|
187
188
|
hasattr(item, 'description') and
|
|
@@ -193,10 +194,10 @@ class ToolRegistry(OutputHandler):
|
|
|
193
194
|
if not item.check():
|
|
194
195
|
continue
|
|
195
196
|
|
|
196
|
-
#
|
|
197
|
+
# 实例化工具类
|
|
197
198
|
tool_instance = item()
|
|
198
199
|
|
|
199
|
-
#
|
|
200
|
+
# 注册工具
|
|
200
201
|
self.register_tool(
|
|
201
202
|
name=tool_instance.name,
|
|
202
203
|
description=tool_instance.description,
|
|
@@ -212,7 +213,7 @@ class ToolRegistry(OutputHandler):
|
|
|
212
213
|
return True
|
|
213
214
|
|
|
214
215
|
finally:
|
|
215
|
-
#
|
|
216
|
+
# 从sys.path中移除目录
|
|
216
217
|
sys.path.remove(parent_dir)
|
|
217
218
|
|
|
218
219
|
except Exception as e:
|
|
@@ -220,18 +221,18 @@ class ToolRegistry(OutputHandler):
|
|
|
220
221
|
return False
|
|
221
222
|
@staticmethod
|
|
222
223
|
def _extract_tool_calls(content: str) -> List[Dict]:
|
|
223
|
-
"""
|
|
224
|
+
"""从内容中提取工具调用。
|
|
224
225
|
|
|
225
|
-
|
|
226
|
-
content:
|
|
226
|
+
参数:
|
|
227
|
+
content: 包含工具调用的内容
|
|
227
228
|
|
|
228
|
-
|
|
229
|
-
List[Dict]:
|
|
229
|
+
返回:
|
|
230
|
+
List[Dict]: 包含名称和参数的提取工具调用列表
|
|
230
231
|
|
|
231
|
-
|
|
232
|
-
Exception:
|
|
232
|
+
异常:
|
|
233
|
+
Exception: 如果工具调用缺少必要字段
|
|
233
234
|
"""
|
|
234
|
-
#
|
|
235
|
+
# 将内容拆分为行
|
|
235
236
|
data = re.findall(r'<TOOL_CALL>(.*?)</TOOL_CALL>', content, re.DOTALL)
|
|
236
237
|
ret = []
|
|
237
238
|
for item in data:
|
|
@@ -244,68 +245,68 @@ class ToolRegistry(OutputHandler):
|
|
|
244
245
|
return ret
|
|
245
246
|
|
|
246
247
|
def register_tool(self, name: str, description: str, parameters: Dict, func: Callable):
|
|
247
|
-
"""
|
|
248
|
+
"""注册新工具"""
|
|
248
249
|
self.tools[name] = Tool(name, description, parameters, func)
|
|
249
250
|
|
|
250
251
|
def get_tool(self, name: str) -> Optional[Tool]:
|
|
251
|
-
"""
|
|
252
|
+
"""获取工具"""
|
|
252
253
|
return self.tools.get(name)
|
|
253
254
|
|
|
254
255
|
def get_all_tools(self) -> List[Dict]:
|
|
255
|
-
"""
|
|
256
|
+
"""获取所有工具(Ollama格式定义)"""
|
|
256
257
|
return [tool.to_dict() for tool in self.tools.values()]
|
|
257
258
|
|
|
258
259
|
def execute_tool(self, name: str, arguments: Dict) -> Dict[str, Any]:
|
|
259
|
-
"""
|
|
260
|
+
"""执行指定工具"""
|
|
260
261
|
tool = self.get_tool(name)
|
|
261
262
|
if tool is None:
|
|
262
|
-
return {"success": False, "stderr": f"
|
|
263
|
+
return {"success": False, "stderr": f"工具 {name} 不存在,可用的工具有: {', '.join(self.tools.keys())}", "stdout": ""}
|
|
263
264
|
return tool.execute(arguments)
|
|
264
265
|
|
|
265
266
|
def handle_tool_calls(self, tool_call: Dict) -> str:
|
|
266
|
-
"""
|
|
267
|
+
"""处理工具调用,只处理第一个工具"""
|
|
267
268
|
try:
|
|
268
|
-
#
|
|
269
|
+
# 只处理第一个工具调用
|
|
269
270
|
name = tool_call["name"]
|
|
270
271
|
args = tool_call["arguments"]
|
|
271
272
|
|
|
272
273
|
tool_call_help = """
|
|
273
|
-
# 🛠️
|
|
274
|
-
|
|
274
|
+
# 🛠️ 工具使用系统
|
|
275
|
+
您正在使用一个需要精确格式和严格规则的工具执行系统。
|
|
275
276
|
|
|
276
|
-
# 📋
|
|
277
|
+
# 📋 工具调用格式
|
|
277
278
|
|
|
278
279
|
<TOOL_CALL>
|
|
279
|
-
name:
|
|
280
|
+
name: 工具名称
|
|
280
281
|
arguments:
|
|
281
|
-
param1:
|
|
282
|
-
param2:
|
|
282
|
+
param1: 值1
|
|
283
|
+
param2: 值2
|
|
283
284
|
</TOOL_CALL>
|
|
284
285
|
|
|
285
|
-
# ❗
|
|
286
|
-
1.
|
|
287
|
-
-
|
|
288
|
-
-
|
|
286
|
+
# ❗ 关键规则
|
|
287
|
+
1. 每次只使用一个工具
|
|
288
|
+
- 一次只执行一个工具
|
|
289
|
+
- 等待结果后再进行下一步
|
|
289
290
|
|
|
290
|
-
2.
|
|
291
|
-
-
|
|
292
|
-
-
|
|
293
|
-
-
|
|
291
|
+
2. 严格遵守格式
|
|
292
|
+
- 完全按照上述格式
|
|
293
|
+
- 使用正确的YAML缩进
|
|
294
|
+
- 包含所有必需参数
|
|
294
295
|
|
|
295
|
-
3.
|
|
296
|
-
-
|
|
297
|
-
-
|
|
298
|
-
-
|
|
299
|
-
-
|
|
296
|
+
3. 结果处理
|
|
297
|
+
- 等待执行结果
|
|
298
|
+
- 不要假设结果
|
|
299
|
+
- 不要创建虚假响应
|
|
300
|
+
- 不要想象对话
|
|
300
301
|
|
|
301
|
-
4.
|
|
302
|
-
-
|
|
303
|
-
-
|
|
304
|
-
-
|
|
305
|
-
-
|
|
302
|
+
4. 信息管理
|
|
303
|
+
- 如果信息不足,询问用户
|
|
304
|
+
- 跳过不必要的步骤
|
|
305
|
+
- 如果卡住,请求指导
|
|
306
|
+
- 不要在没有完整信息的情况下继续
|
|
306
307
|
|
|
307
|
-
# 📝
|
|
308
|
-
|
|
308
|
+
# 📝 字符串参数格式
|
|
309
|
+
始终使用 | 语法表示字符串参数:
|
|
309
310
|
|
|
310
311
|
<TOOL_CALL>
|
|
311
312
|
name: execute_shell
|
|
@@ -314,19 +315,19 @@ arguments:
|
|
|
314
315
|
git status --porcelain
|
|
315
316
|
</TOOL_CALL>
|
|
316
317
|
|
|
317
|
-
# 💡
|
|
318
|
-
-
|
|
319
|
-
-
|
|
320
|
-
-
|
|
321
|
-
-
|
|
322
|
-
-
|
|
323
|
-
|
|
324
|
-
# ⚠️
|
|
325
|
-
-
|
|
326
|
-
-
|
|
327
|
-
-
|
|
328
|
-
-
|
|
329
|
-
-
|
|
318
|
+
# 💡 最佳实践
|
|
319
|
+
- 准备好后立即开始执行
|
|
320
|
+
- 无需请求许可即可开始
|
|
321
|
+
- 使用正确的字符串格式
|
|
322
|
+
- 监控进度并调整
|
|
323
|
+
- 遇到困难时请求帮助
|
|
324
|
+
|
|
325
|
+
# ⚠️ 常见错误
|
|
326
|
+
- 同时调用多个工具
|
|
327
|
+
- 字符串参数缺少 |
|
|
328
|
+
- 假设工具结果
|
|
329
|
+
- 创建虚构对话
|
|
330
|
+
- 在没有所需信息的情况下继续
|
|
330
331
|
"""
|
|
331
332
|
|
|
332
333
|
if isinstance(args, str):
|
|
@@ -335,17 +336,6 @@ arguments:
|
|
|
335
336
|
except json.JSONDecodeError:
|
|
336
337
|
PrettyOutput.print(f"工具参数格式无效: {name} {tool_call_help}", OutputType.ERROR)
|
|
337
338
|
return ""
|
|
338
|
-
|
|
339
|
-
# Display tool call information
|
|
340
|
-
PrettyOutput.section(f"执行工具: {name}", OutputType.TOOL)
|
|
341
|
-
params = "参数:\n"
|
|
342
|
-
if isinstance(args, dict):
|
|
343
|
-
for key, value in args.items():
|
|
344
|
-
params += f"{key} = {value}\n"
|
|
345
|
-
else:
|
|
346
|
-
params += f"{args}"
|
|
347
|
-
|
|
348
|
-
PrettyOutput.print(params, OutputType.INFO)
|
|
349
339
|
|
|
350
340
|
# Execute tool call
|
|
351
341
|
result = self.execute_tool(name, args)
|
|
@@ -354,60 +344,57 @@ arguments:
|
|
|
354
344
|
stderr = result.get("stderr", "")
|
|
355
345
|
output_parts = []
|
|
356
346
|
if stdout:
|
|
357
|
-
output_parts.append(f"
|
|
347
|
+
output_parts.append(f"输出:\n{stdout}")
|
|
358
348
|
if stderr:
|
|
359
|
-
output_parts.append(f"
|
|
349
|
+
output_parts.append(f"错误:\n{stderr}")
|
|
360
350
|
output = "\n\n".join(output_parts)
|
|
361
|
-
output = "
|
|
351
|
+
output = "无输出和错误" if not output else output
|
|
362
352
|
|
|
363
353
|
# Process the result
|
|
364
354
|
if result["success"]:
|
|
365
|
-
|
|
366
|
-
PrettyOutput.section("执行成功", OutputType.SUCCESS)
|
|
367
|
-
|
|
368
355
|
# If the output exceeds 4k characters, use a large model to summarize
|
|
369
356
|
if get_context_token_count(output) > self.max_token_count:
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
357
|
+
with yaspin(text="正在总结输出...", color="yellow") as spinner:
|
|
358
|
+
try:
|
|
359
|
+
|
|
360
|
+
model = PlatformRegistry.get_global_platform_registry().get_normal_platform()
|
|
361
|
+
|
|
362
|
+
# If the output exceeds the maximum context length, only take the last part
|
|
363
|
+
max_count = self.max_token_count
|
|
364
|
+
if get_context_token_count(output) > max_count:
|
|
365
|
+
output_to_summarize = output[-max_count:]
|
|
366
|
+
truncation_notice = f"\n(注意:由于输出过长,仅总结最后 {max_count} 个字符)"
|
|
367
|
+
else:
|
|
368
|
+
output_to_summarize = output
|
|
369
|
+
truncation_notice = ""
|
|
370
|
+
|
|
371
|
+
prompt = f"""请总结以下工具的执行结果,提取关键信息和重要结果。注意:
|
|
372
|
+
1. 保留所有重要的数值、路径、错误信息等
|
|
373
|
+
2. 保持结果的准确性
|
|
374
|
+
3. 用简洁的语言描述主要内容
|
|
375
|
+
4. 如果有错误信息,确保包含在总结中
|
|
376
|
+
|
|
377
|
+
工具名称: {name}
|
|
378
|
+
执行结果:
|
|
379
|
+
{output_to_summarize}
|
|
380
|
+
|
|
381
|
+
请提供总结:"""
|
|
382
|
+
|
|
383
|
+
summary = model.chat_until_success(prompt)
|
|
384
|
+
output = f"""--- 原始输出过长,以下是总结 ---{truncation_notice}
|
|
385
|
+
|
|
386
|
+
{summary}
|
|
387
|
+
|
|
388
|
+
--- 总结结束 ---"""
|
|
389
|
+
spinner.text = "总结完成"
|
|
390
|
+
spinner.ok("✅")
|
|
391
|
+
except Exception as e:
|
|
392
|
+
spinner.text = "总结失败"
|
|
393
|
+
spinner.fail("❌")
|
|
394
|
+
PrettyOutput.print(f"总结失败: {str(e)}", OutputType.ERROR)
|
|
395
|
+
output = f"输出过长 ({len(output)} 字符),建议查看原始输出。\n前300字符预览:\n{output[:300]}..."
|
|
409
396
|
return output
|
|
410
397
|
|
|
411
398
|
except Exception as e:
|
|
412
399
|
PrettyOutput.print(f"工具执行失败:{str(e)}", OutputType.ERROR)
|
|
413
|
-
return f"
|
|
400
|
+
return f"工具调用失败: {str(e)}"
|