jarvis-ai-assistant 0.1.193__py3-none-any.whl → 0.1.195__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.
- jarvis/__init__.py +1 -1
- jarvis/jarvis_agent/__init__.py +45 -41
- jarvis/jarvis_agent/builtin_input_handler.py +26 -4
- jarvis/jarvis_agent/jarvis.py +30 -19
- jarvis/jarvis_agent/main.py +20 -12
- jarvis/jarvis_agent/output_handler.py +7 -7
- jarvis/jarvis_agent/shell_input_handler.py +14 -11
- jarvis/jarvis_code_agent/code_agent.py +81 -79
- jarvis/jarvis_code_agent/lint.py +92 -105
- jarvis/jarvis_code_analysis/checklists/__init__.py +1 -1
- jarvis/jarvis_code_analysis/checklists/c_cpp.py +1 -1
- jarvis/jarvis_code_analysis/checklists/csharp.py +1 -1
- jarvis/jarvis_code_analysis/checklists/data_format.py +1 -1
- jarvis/jarvis_code_analysis/checklists/devops.py +1 -1
- jarvis/jarvis_code_analysis/checklists/docs.py +1 -1
- jarvis/jarvis_code_analysis/checklists/go.py +1 -1
- jarvis/jarvis_code_analysis/checklists/infrastructure.py +1 -1
- jarvis/jarvis_code_analysis/checklists/java.py +1 -1
- jarvis/jarvis_code_analysis/checklists/javascript.py +1 -1
- jarvis/jarvis_code_analysis/checklists/kotlin.py +1 -1
- jarvis/jarvis_code_analysis/checklists/loader.py +31 -29
- jarvis/jarvis_code_analysis/checklists/php.py +1 -1
- jarvis/jarvis_code_analysis/checklists/python.py +1 -1
- jarvis/jarvis_code_analysis/checklists/ruby.py +1 -1
- jarvis/jarvis_code_analysis/checklists/rust.py +1 -1
- jarvis/jarvis_code_analysis/checklists/shell.py +1 -1
- jarvis/jarvis_code_analysis/checklists/sql.py +1 -1
- jarvis/jarvis_code_analysis/checklists/swift.py +1 -1
- jarvis/jarvis_code_analysis/checklists/web.py +1 -1
- jarvis/jarvis_code_analysis/code_review.py +292 -190
- jarvis/jarvis_dev/main.py +73 -56
- jarvis/jarvis_git_details/main.py +29 -33
- jarvis/jarvis_git_squash/main.py +13 -11
- jarvis/jarvis_git_utils/git_commiter.py +15 -5
- jarvis/jarvis_mcp/__init__.py +8 -10
- jarvis/jarvis_mcp/sse_mcp_client.py +182 -205
- jarvis/jarvis_mcp/stdio_mcp_client.py +93 -120
- jarvis/jarvis_mcp/streamable_mcp_client.py +117 -142
- jarvis/jarvis_methodology/main.py +71 -39
- jarvis/jarvis_multi_agent/__init__.py +24 -16
- jarvis/jarvis_multi_agent/main.py +10 -4
- jarvis/jarvis_platform/__init__.py +1 -1
- jarvis/jarvis_platform/base.py +44 -18
- jarvis/jarvis_platform/human.py +15 -3
- jarvis/jarvis_platform/kimi.py +117 -81
- jarvis/jarvis_platform/openai.py +23 -28
- jarvis/jarvis_platform/registry.py +43 -29
- jarvis/jarvis_platform/tongyi.py +16 -10
- jarvis/jarvis_platform/yuanbao.py +197 -144
- jarvis/jarvis_platform_manager/main.py +4 -2
- jarvis/jarvis_smart_shell/main.py +35 -30
- jarvis/jarvis_tools/ask_user.py +8 -16
- jarvis/jarvis_tools/base.py +3 -2
- jarvis/jarvis_tools/chdir.py +7 -19
- jarvis/jarvis_tools/cli/main.py +14 -10
- jarvis/jarvis_tools/code_plan.py +10 -31
- jarvis/jarvis_tools/create_code_agent.py +6 -11
- jarvis/jarvis_tools/create_sub_agent.py +10 -22
- jarvis/jarvis_tools/edit_file.py +98 -76
- jarvis/jarvis_tools/execute_script.py +46 -46
- jarvis/jarvis_tools/file_analyzer.py +22 -34
- jarvis/jarvis_tools/file_operation.py +69 -62
- jarvis/jarvis_tools/generate_new_tool.py +0 -2
- jarvis/jarvis_tools/methodology.py +19 -23
- jarvis/jarvis_tools/read_code.py +35 -35
- jarvis/jarvis_tools/read_webpage.py +7 -16
- jarvis/jarvis_tools/registry.py +63 -30
- jarvis/jarvis_tools/rewrite_file.py +26 -29
- jarvis/jarvis_tools/search_web.py +5 -8
- jarvis/jarvis_tools/virtual_tty.py +133 -122
- jarvis/jarvis_utils/__init__.py +0 -1
- jarvis/jarvis_utils/builtin_replace_map.py +9 -9
- jarvis/jarvis_utils/config.py +60 -37
- jarvis/jarvis_utils/embedding.py +24 -19
- jarvis/jarvis_utils/file_processors.py +16 -9
- jarvis/jarvis_utils/git_utils.py +157 -107
- jarvis/jarvis_utils/globals.py +1 -1
- jarvis/jarvis_utils/input.py +85 -52
- jarvis/jarvis_utils/jarvis_history.py +43 -0
- jarvis/jarvis_utils/methodology.py +31 -24
- jarvis/jarvis_utils/output.py +164 -80
- jarvis/jarvis_utils/tag.py +2 -1
- jarvis/jarvis_utils/utils.py +84 -52
- {jarvis_ai_assistant-0.1.193.dist-info → jarvis_ai_assistant-0.1.195.dist-info}/METADATA +362 -230
- jarvis_ai_assistant-0.1.195.dist-info/RECORD +98 -0
- jarvis/jarvis_agent/file_input_handler.py +0 -112
- jarvis/jarvis_event/__init__.py +0 -0
- jarvis_ai_assistant-0.1.193.dist-info/RECORD +0 -99
- {jarvis_ai_assistant-0.1.193.dist-info → jarvis_ai_assistant-0.1.195.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.193.dist-info → jarvis_ai_assistant-0.1.195.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.1.193.dist-info → jarvis_ai_assistant-0.1.195.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.193.dist-info → jarvis_ai_assistant-0.1.195.dist-info}/top_level.txt +0 -0
@@ -11,23 +11,23 @@ from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
11
11
|
|
12
12
|
class FileAnalyzerTool:
|
13
13
|
name = "file_analyzer"
|
14
|
-
description =
|
14
|
+
description = (
|
15
|
+
"""分析文件内容并提取关键信息。支持的文件:文本文件、word文档、pdf文件、图片"""
|
16
|
+
)
|
15
17
|
parameters = {
|
16
18
|
"type": "object",
|
17
19
|
"properties": {
|
18
20
|
"file_paths": {
|
19
21
|
"type": "array",
|
20
|
-
"items": {
|
21
|
-
|
22
|
-
},
|
23
|
-
"description": "要分析的文件路径列表"
|
22
|
+
"items": {"type": "string"},
|
23
|
+
"description": "要分析的文件路径列表",
|
24
24
|
},
|
25
25
|
"prompt": {
|
26
26
|
"type": "string",
|
27
|
-
"description": "分析文件的提示词,指导模型提取什么样的信息"
|
28
|
-
}
|
27
|
+
"description": "分析文件的提示词,指导模型提取什么样的信息",
|
28
|
+
},
|
29
29
|
},
|
30
|
-
"required": ["file_paths", "prompt"]
|
30
|
+
"required": ["file_paths", "prompt"],
|
31
31
|
}
|
32
32
|
|
33
33
|
@staticmethod
|
@@ -46,7 +46,7 @@ class FileAnalyzerTool:
|
|
46
46
|
try:
|
47
47
|
file_paths = args["file_paths"]
|
48
48
|
prompt = args["prompt"]
|
49
|
-
|
49
|
+
|
50
50
|
agent = args["agent"]
|
51
51
|
agent.reset_tool_call_count()
|
52
52
|
|
@@ -57,30 +57,26 @@ class FileAnalyzerTool:
|
|
57
57
|
valid_files.append(file_path)
|
58
58
|
else:
|
59
59
|
PrettyOutput.print(f"文件不存在: {file_path}", OutputType.WARNING)
|
60
|
-
|
60
|
+
|
61
61
|
if not valid_files:
|
62
|
-
return {
|
63
|
-
"success": False,
|
64
|
-
"stdout": "",
|
65
|
-
"stderr": "没有找到有效的文件"
|
66
|
-
}
|
62
|
+
return {"success": False, "stdout": "", "stderr": "没有找到有效的文件"}
|
67
63
|
|
68
64
|
# 创建thinking平台实例
|
69
65
|
platform = PlatformRegistry().get_thinking_platform()
|
70
|
-
|
66
|
+
|
71
67
|
if not platform:
|
72
68
|
return {
|
73
69
|
"success": False,
|
74
70
|
"stdout": "",
|
75
|
-
"stderr": "无法创建thinking平台实例"
|
71
|
+
"stderr": "无法创建thinking平台实例",
|
76
72
|
}
|
77
|
-
|
73
|
+
|
78
74
|
# 设置系统消息
|
79
75
|
system_message = """你是一个文件分析助手。你的任务是分析提供的文件内容,并根据用户的提示提取关键信息。
|
80
76
|
请保持客观,只关注文件中实际存在的内容。如果无法确定某些信息,请明确指出。
|
81
77
|
请以结构化的方式组织你的回答,使用标题、列表和代码块等格式来提高可读性。"""
|
82
78
|
platform.set_system_prompt(system_message)
|
83
|
-
|
79
|
+
|
84
80
|
# 上传文件
|
85
81
|
with yaspin(Spinners.dots, text="正在上传文件...") as spinner:
|
86
82
|
try:
|
@@ -92,7 +88,7 @@ class FileAnalyzerTool:
|
|
92
88
|
return {
|
93
89
|
"success": False,
|
94
90
|
"stdout": "",
|
95
|
-
"stderr": "文件上传失败"
|
91
|
+
"stderr": "文件上传失败",
|
96
92
|
}
|
97
93
|
spinner.text = "文件上传成功"
|
98
94
|
spinner.ok("✅")
|
@@ -102,11 +98,11 @@ class FileAnalyzerTool:
|
|
102
98
|
return {
|
103
99
|
"success": False,
|
104
100
|
"stdout": "",
|
105
|
-
"stderr": f"文件上传失败: {str(e)}"
|
101
|
+
"stderr": f"文件上传失败: {str(e)}",
|
106
102
|
}
|
107
103
|
|
108
104
|
platform.set_suppress_output(False)
|
109
|
-
|
105
|
+
|
110
106
|
# 构建分析请求
|
111
107
|
analysis_request = f"""
|
112
108
|
请根据以下提示分析这些文件。
|
@@ -120,19 +116,11 @@ class FileAnalyzerTool:
|
|
120
116
|
analysis_result = platform.chat_until_success(analysis_request)
|
121
117
|
spinner.text = "分析完成"
|
122
118
|
spinner.ok("✅")
|
123
|
-
|
119
|
+
|
124
120
|
# 清理会话
|
125
121
|
platform.delete_chat()
|
126
|
-
|
127
|
-
return {
|
128
|
-
"success": True,
|
129
|
-
"stdout": analysis_result,
|
130
|
-
"stderr": ""
|
131
|
-
}
|
122
|
+
|
123
|
+
return {"success": True, "stdout": analysis_result, "stderr": ""}
|
132
124
|
|
133
125
|
except Exception as e:
|
134
|
-
return {
|
135
|
-
"success": False,
|
136
|
-
"stdout": "",
|
137
|
-
"stderr": f"文件分析失败: {str(e)}"
|
138
|
-
}
|
126
|
+
return {"success": False, "stdout": "", "stderr": f"文件分析失败: {str(e)}"}
|
@@ -19,7 +19,7 @@ class FileOperationTool:
|
|
19
19
|
"operation": {
|
20
20
|
"type": "string",
|
21
21
|
"enum": ["read", "write"],
|
22
|
-
"description": "要执行的文件操作类型(读取或写入多个文件)"
|
22
|
+
"description": "要执行的文件操作类型(读取或写入多个文件)",
|
23
23
|
},
|
24
24
|
"files": {
|
25
25
|
"type": "array",
|
@@ -27,41 +27,48 @@ class FileOperationTool:
|
|
27
27
|
"type": "object",
|
28
28
|
"properties": {
|
29
29
|
"path": {"type": "string"},
|
30
|
-
"content": {"type": "string"}
|
30
|
+
"content": {"type": "string"},
|
31
31
|
},
|
32
|
-
"required": ["path"]
|
32
|
+
"required": ["path"],
|
33
33
|
},
|
34
|
-
"description": "要操作的文件列表"
|
35
|
-
}
|
34
|
+
"description": "要操作的文件列表",
|
35
|
+
},
|
36
36
|
},
|
37
|
-
"required": ["operation", "files"]
|
37
|
+
"required": ["operation", "files"],
|
38
38
|
}
|
39
39
|
|
40
40
|
def _get_file_processor(self, file_path: str):
|
41
41
|
"""获取适合处理指定文件的处理器"""
|
42
|
-
processors = [
|
43
|
-
|
44
|
-
]
|
45
|
-
|
42
|
+
processors = [TextFileProcessor] # 文本文件处理器(放在最后作为兜底)
|
43
|
+
|
46
44
|
for processor in processors:
|
47
45
|
if processor.can_handle(file_path):
|
48
46
|
return processor
|
49
|
-
|
47
|
+
|
50
48
|
return None # 如果没有合适的处理器,返回None
|
51
|
-
|
52
|
-
def _handle_single_file(
|
53
|
-
|
49
|
+
|
50
|
+
def _handle_single_file(
|
51
|
+
self,
|
52
|
+
operation: str,
|
53
|
+
filepath: str,
|
54
|
+
content: str = "",
|
55
|
+
start_line: int = 1,
|
56
|
+
end_line: int = -1,
|
57
|
+
agent: Any = None,
|
58
|
+
) -> Dict[str, Any]:
|
54
59
|
"""Handle operations for a single file"""
|
55
60
|
try:
|
56
61
|
abs_path = os.path.abspath(filepath)
|
57
|
-
|
62
|
+
|
58
63
|
if operation == "read":
|
59
|
-
with yaspin(
|
64
|
+
with yaspin(
|
65
|
+
text=f"正在读取文件: {abs_path}...", color="cyan"
|
66
|
+
) as spinner:
|
60
67
|
if not os.path.exists(abs_path):
|
61
68
|
return {
|
62
69
|
"success": False,
|
63
70
|
"stdout": "",
|
64
|
-
"stderr": f"文件不存在: {abs_path}"
|
71
|
+
"stderr": f"文件不存在: {abs_path}",
|
65
72
|
}
|
66
73
|
|
67
74
|
# 检查文件大小
|
@@ -69,30 +76,40 @@ class FileOperationTool:
|
|
69
76
|
return {
|
70
77
|
"success": False,
|
71
78
|
"stdout": "",
|
72
|
-
"stderr": "文件过大 (>30MB),无法处理"
|
79
|
+
"stderr": "文件过大 (>30MB),无法处理",
|
73
80
|
}
|
74
|
-
|
81
|
+
|
75
82
|
file_extension = Path(abs_path).suffix.lower()
|
76
|
-
|
83
|
+
|
77
84
|
# 获取文件处理器
|
78
85
|
processor = self._get_file_processor(abs_path)
|
79
|
-
|
86
|
+
|
80
87
|
if processor is None:
|
81
88
|
return {
|
82
89
|
"success": False,
|
83
90
|
"stdout": "",
|
84
|
-
"stderr": f"不支持的文件类型: {file_extension}"
|
91
|
+
"stderr": f"不支持的文件类型: {file_extension}",
|
85
92
|
}
|
86
|
-
|
93
|
+
|
87
94
|
# 特殊处理纯文本文件,支持行范围选择
|
88
95
|
if processor == TextFileProcessor:
|
89
96
|
try:
|
90
|
-
with open(
|
97
|
+
with open(
|
98
|
+
abs_path, "r", encoding="utf-8", errors="ignore"
|
99
|
+
) as f:
|
91
100
|
lines = f.readlines()
|
92
101
|
|
93
102
|
total_lines = len(lines)
|
94
|
-
start_line =
|
95
|
-
|
103
|
+
start_line = (
|
104
|
+
start_line
|
105
|
+
if start_line >= 0
|
106
|
+
else total_lines + start_line + 1
|
107
|
+
)
|
108
|
+
end_line = (
|
109
|
+
end_line
|
110
|
+
if end_line >= 0
|
111
|
+
else total_lines + end_line + 1
|
112
|
+
)
|
96
113
|
start_line = max(1, min(start_line, total_lines))
|
97
114
|
end_line = max(1, min(end_line, total_lines))
|
98
115
|
if end_line == -1:
|
@@ -105,27 +122,27 @@ class FileOperationTool:
|
|
105
122
|
return {
|
106
123
|
"success": False,
|
107
124
|
"stdout": "",
|
108
|
-
"stderr": error_msg
|
125
|
+
"stderr": error_msg,
|
109
126
|
}
|
110
127
|
|
111
|
-
content = "".join(lines[start_line - 1:end_line])
|
128
|
+
content = "".join(lines[start_line - 1 : end_line])
|
112
129
|
file_info = f"\n文件: {abs_path} (文本文件)\n行: [{start_line}-{end_line}]/{total_lines}"
|
113
130
|
except Exception as e:
|
114
131
|
return {
|
115
132
|
"success": False,
|
116
133
|
"stdout": "",
|
117
|
-
"stderr": f"读取文本文件失败: {str(e)}"
|
134
|
+
"stderr": f"读取文本文件失败: {str(e)}",
|
118
135
|
}
|
119
136
|
else:
|
120
137
|
return {
|
121
138
|
"success": False,
|
122
139
|
"stdout": "",
|
123
|
-
"stderr": f"不支持的文件类型: {file_extension}"
|
140
|
+
"stderr": f"不支持的文件类型: {file_extension}",
|
124
141
|
}
|
125
|
-
|
142
|
+
|
126
143
|
# 构建输出信息
|
127
144
|
output = f"{file_info}\n{content}" + "\n\n"
|
128
|
-
|
145
|
+
|
129
146
|
spinner.text = f"文件读取完成: {abs_path}"
|
130
147
|
spinner.ok("✅")
|
131
148
|
|
@@ -136,36 +153,32 @@ class FileOperationTool:
|
|
136
153
|
else:
|
137
154
|
files = [abs_path]
|
138
155
|
agent.set_user_data("files", files)
|
139
|
-
|
140
|
-
return {
|
141
|
-
"success": True,
|
142
|
-
"stdout": output,
|
143
|
-
"stderr": ""
|
144
|
-
}
|
156
|
+
|
157
|
+
return {"success": True, "stdout": output, "stderr": ""}
|
145
158
|
elif operation == "write":
|
146
|
-
with yaspin(
|
147
|
-
|
148
|
-
|
159
|
+
with yaspin(
|
160
|
+
text=f"正在写入文件: {abs_path}...", color="cyan"
|
161
|
+
) as spinner:
|
162
|
+
os.makedirs(
|
163
|
+
os.path.dirname(os.path.abspath(abs_path)), exist_ok=True
|
164
|
+
)
|
165
|
+
with open(abs_path, "w", encoding="utf-8", errors="ignore") as f:
|
149
166
|
f.write(content)
|
150
167
|
spinner.text = f"文件写入完成: {abs_path}"
|
151
168
|
spinner.ok("✅")
|
152
169
|
return {
|
153
170
|
"success": True,
|
154
171
|
"stdout": f"文件写入成功: {abs_path}",
|
155
|
-
"stderr": ""
|
172
|
+
"stderr": "",
|
156
173
|
}
|
157
|
-
return {
|
158
|
-
"success": False,
|
159
|
-
"stdout": "",
|
160
|
-
"stderr": f"未知操作: {operation}"
|
161
|
-
}
|
174
|
+
return {"success": False, "stdout": "", "stderr": f"未知操作: {operation}"}
|
162
175
|
|
163
176
|
except Exception as e:
|
164
177
|
PrettyOutput.print(str(e), OutputType.ERROR)
|
165
178
|
return {
|
166
179
|
"success": False,
|
167
180
|
"stdout": "",
|
168
|
-
"stderr": f"文件操作失败 {abs_path}: {str(e)}"
|
181
|
+
"stderr": f"文件操作失败 {abs_path}: {str(e)}",
|
169
182
|
}
|
170
183
|
|
171
184
|
def execute(self, args: Dict) -> Dict[str, Any]:
|
@@ -187,7 +200,7 @@ class FileOperationTool:
|
|
187
200
|
return {
|
188
201
|
"success": False,
|
189
202
|
"stdout": "",
|
190
|
-
"stderr": "files参数是必需的,且必须是一个列表"
|
203
|
+
"stderr": "files参数是必需的,且必须是一个列表",
|
191
204
|
}
|
192
205
|
|
193
206
|
all_outputs = []
|
@@ -204,28 +217,22 @@ class FileOperationTool:
|
|
204
217
|
content,
|
205
218
|
file_info.get("start_line", 1),
|
206
219
|
file_info.get("end_line", -1),
|
207
|
-
agent
|
220
|
+
agent,
|
208
221
|
)
|
209
222
|
|
210
223
|
if result["success"]:
|
211
224
|
all_outputs.append(result["stdout"])
|
212
225
|
else:
|
213
|
-
all_outputs.append(
|
226
|
+
all_outputs.append(
|
227
|
+
f"处理文件 {file_info['path']} 时出错: {result['stderr']}"
|
228
|
+
)
|
214
229
|
success = success and result["success"]
|
215
230
|
|
216
231
|
# Combine all outputs with separators
|
217
|
-
combined_output = "\n\n" + "="*80 + "\n\n".join(all_outputs)
|
232
|
+
combined_output = "\n\n" + "=" * 80 + "\n\n".join(all_outputs)
|
218
233
|
|
219
|
-
return {
|
220
|
-
"success": success,
|
221
|
-
"stdout": combined_output,
|
222
|
-
"stderr": ""
|
223
|
-
}
|
234
|
+
return {"success": success, "stdout": combined_output, "stderr": ""}
|
224
235
|
|
225
236
|
except Exception as e:
|
226
237
|
PrettyOutput.print(str(e), OutputType.ERROR)
|
227
|
-
return {
|
228
|
-
"success": False,
|
229
|
-
"stdout": "",
|
230
|
-
"stderr": f"文件操作失败: {str(e)}"
|
231
|
-
}
|
238
|
+
return {"success": False, "stdout": "", "stderr": f"文件操作失败: {str(e)}"}
|
@@ -19,19 +19,19 @@ class MethodologyTool:
|
|
19
19
|
"operation": {
|
20
20
|
"type": "string",
|
21
21
|
"description": "操作类型(delete/update/add)",
|
22
|
-
"enum": ["delete", "update", "add"]
|
22
|
+
"enum": ["delete", "update", "add"],
|
23
23
|
},
|
24
24
|
"problem_type": {
|
25
25
|
"type": "string",
|
26
|
-
"description": "问题类型,例如:部署开源项目、生成提交信息"
|
26
|
+
"description": "问题类型,例如:部署开源项目、生成提交信息",
|
27
27
|
},
|
28
28
|
"content": {
|
29
29
|
"type": "string",
|
30
30
|
"description": "方法论内容(更新和添加时必填)",
|
31
|
-
"optional": True
|
32
|
-
}
|
31
|
+
"optional": True,
|
32
|
+
},
|
33
33
|
},
|
34
|
-
"required": ["operation", "problem_type"]
|
34
|
+
"required": ["operation", "problem_type"],
|
35
35
|
}
|
36
36
|
|
37
37
|
def __init__(self):
|
@@ -58,10 +58,9 @@ class MethodologyTool:
|
|
58
58
|
str: 方法论文件路径
|
59
59
|
"""
|
60
60
|
# 使用MD5哈希作为文件名,避免文件名中的特殊字符
|
61
|
-
safe_filename = hashlib.md5(problem_type.encode(
|
61
|
+
safe_filename = hashlib.md5(problem_type.encode("utf-8")).hexdigest()
|
62
62
|
return os.path.join(self.methodology_dir, f"{safe_filename}.json")
|
63
63
|
|
64
|
-
|
65
64
|
def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
|
66
65
|
"""执行管理方法论的操作
|
67
66
|
|
@@ -82,7 +81,7 @@ class MethodologyTool:
|
|
82
81
|
return {
|
83
82
|
"success": False,
|
84
83
|
"stdout": "",
|
85
|
-
"stderr": "缺少必要参数: operation和problem_type"
|
84
|
+
"stderr": "缺少必要参数: operation和problem_type",
|
86
85
|
}
|
87
86
|
|
88
87
|
try:
|
@@ -96,13 +95,13 @@ class MethodologyTool:
|
|
96
95
|
return {
|
97
96
|
"success": True,
|
98
97
|
"stdout": f"已删除问题类型'{problem_type}'对应的方法论",
|
99
|
-
"stderr": ""
|
98
|
+
"stderr": "",
|
100
99
|
}
|
101
100
|
else:
|
102
101
|
return {
|
103
102
|
"success": False,
|
104
103
|
"stdout": "",
|
105
|
-
"stderr": f"未找到问题类型'{problem_type}'对应的方法论"
|
104
|
+
"stderr": f"未找到问题类型'{problem_type}'对应的方法论",
|
106
105
|
}
|
107
106
|
|
108
107
|
elif operation in ["update", "add"]:
|
@@ -110,7 +109,7 @@ class MethodologyTool:
|
|
110
109
|
return {
|
111
110
|
"success": False,
|
112
111
|
"stdout": "",
|
113
|
-
"stderr": "需要提供方法论内容"
|
112
|
+
"stderr": "需要提供方法论内容",
|
114
113
|
}
|
115
114
|
|
116
115
|
# 确保目录存在
|
@@ -121,10 +120,12 @@ class MethodologyTool:
|
|
121
120
|
|
122
121
|
# 保存方法论到单独的文件
|
123
122
|
with open(file_path, "w", encoding="utf-8", errors="ignore") as f:
|
124
|
-
json.dump(
|
125
|
-
"problem_type": problem_type,
|
126
|
-
|
127
|
-
|
123
|
+
json.dump(
|
124
|
+
{"problem_type": problem_type, "content": content},
|
125
|
+
f,
|
126
|
+
ensure_ascii=False,
|
127
|
+
indent=2,
|
128
|
+
)
|
128
129
|
|
129
130
|
PrettyOutput.print(f"方法论已保存到 {file_path}", OutputType.INFO)
|
130
131
|
|
@@ -132,20 +133,15 @@ class MethodologyTool:
|
|
132
133
|
return {
|
133
134
|
"success": True,
|
134
135
|
"stdout": f"{action}了问题类型'{problem_type}'对应的方法论",
|
135
|
-
"stderr": ""
|
136
|
+
"stderr": "",
|
136
137
|
}
|
137
138
|
|
138
139
|
else:
|
139
140
|
return {
|
140
141
|
"success": False,
|
141
142
|
"stdout": "",
|
142
|
-
"stderr": f"不支持的操作类型: {operation}"
|
143
|
+
"stderr": f"不支持的操作类型: {operation}",
|
143
144
|
}
|
144
145
|
|
145
146
|
except Exception as e:
|
146
|
-
return {
|
147
|
-
"success": False,
|
148
|
-
"stdout": "",
|
149
|
-
"stderr": f"执行失败: {str(e)}"
|
150
|
-
}
|
151
|
-
|
147
|
+
return {"success": False, "stdout": "", "stderr": f"执行失败: {str(e)}"}
|
jarvis/jarvis_tools/read_code.py
CHANGED
@@ -21,17 +21,19 @@ class ReadCodeTool:
|
|
21
21
|
"properties": {
|
22
22
|
"path": {"type": "string"},
|
23
23
|
"start_line": {"type": "number", "default": 1},
|
24
|
-
"end_line": {"type": "number", "default": -1}
|
24
|
+
"end_line": {"type": "number", "default": -1},
|
25
25
|
},
|
26
|
-
"required": ["path"]
|
26
|
+
"required": ["path"],
|
27
27
|
},
|
28
|
-
"description": "要读取的文件列表"
|
28
|
+
"description": "要读取的文件列表",
|
29
29
|
}
|
30
30
|
},
|
31
|
-
"required": ["files"]
|
31
|
+
"required": ["files"],
|
32
32
|
}
|
33
33
|
|
34
|
-
def _handle_single_file(
|
34
|
+
def _handle_single_file(
|
35
|
+
self, filepath: str, start_line: int = 1, end_line: int = -1, agent: Any = None
|
36
|
+
) -> Dict[str, Any]:
|
35
37
|
"""处理单个文件的读取操作
|
36
38
|
|
37
39
|
Args:
|
@@ -50,7 +52,7 @@ class ReadCodeTool:
|
|
50
52
|
return {
|
51
53
|
"success": False,
|
52
54
|
"stdout": "",
|
53
|
-
"stderr": f"文件不存在: {abs_path}"
|
55
|
+
"stderr": f"文件不存在: {abs_path}",
|
54
56
|
}
|
55
57
|
|
56
58
|
# 文件大小限制检查(10MB)
|
@@ -58,45 +60,55 @@ class ReadCodeTool:
|
|
58
60
|
return {
|
59
61
|
"success": False,
|
60
62
|
"stdout": "",
|
61
|
-
"stderr": "文件过大 (>10MB)"
|
63
|
+
"stderr": "文件过大 (>10MB)",
|
62
64
|
}
|
63
65
|
|
64
66
|
# 读取文件内容
|
65
|
-
with open(abs_path,
|
67
|
+
with open(abs_path, "r", encoding="utf-8", errors="ignore") as f:
|
66
68
|
lines = f.readlines()
|
67
69
|
|
68
70
|
total_lines = len(lines)
|
69
|
-
|
71
|
+
|
70
72
|
# 处理空文件情况
|
71
73
|
if total_lines == 0:
|
72
74
|
spinner.ok("✅")
|
73
75
|
return {
|
74
76
|
"success": True,
|
75
77
|
"stdout": f"\n🔍 文件: {abs_path}\n📄 文件为空 (0行)\n",
|
76
|
-
"stderr": ""
|
78
|
+
"stderr": "",
|
77
79
|
}
|
78
80
|
|
79
81
|
# 处理特殊值-1表示文件末尾
|
80
82
|
if end_line == -1:
|
81
83
|
end_line = total_lines
|
82
84
|
else:
|
83
|
-
end_line =
|
84
|
-
|
85
|
-
|
85
|
+
end_line = (
|
86
|
+
max(1, min(end_line, total_lines))
|
87
|
+
if end_line >= 0
|
88
|
+
else total_lines + end_line + 1
|
89
|
+
)
|
90
|
+
|
91
|
+
start_line = (
|
92
|
+
max(1, min(start_line, total_lines))
|
93
|
+
if start_line >= 0
|
94
|
+
else total_lines + start_line + 1
|
95
|
+
)
|
86
96
|
|
87
97
|
if start_line > end_line:
|
88
98
|
spinner.fail("❌")
|
89
99
|
return {
|
90
100
|
"success": False,
|
91
101
|
"stdout": "",
|
92
|
-
"stderr": f"无效的行范围 [{start_line}-{end_line}] (总行数: {total_lines})"
|
102
|
+
"stderr": f"无效的行范围 [{start_line}-{end_line}] (总行数: {total_lines})",
|
93
103
|
}
|
94
104
|
|
95
105
|
# 添加行号并构建输出内容
|
96
|
-
selected_lines = lines[start_line-1:end_line]
|
106
|
+
selected_lines = lines[start_line - 1 : end_line]
|
97
107
|
numbered_content = "".join(
|
98
|
-
[
|
99
|
-
|
108
|
+
[
|
109
|
+
f"{i:4d}:{line}"
|
110
|
+
for i, line in enumerate(selected_lines, start=start_line)
|
111
|
+
]
|
100
112
|
)
|
101
113
|
|
102
114
|
# 构建输出格式
|
@@ -116,19 +128,11 @@ class ReadCodeTool:
|
|
116
128
|
files = [abs_path]
|
117
129
|
agent.set_user_data("files", files)
|
118
130
|
|
119
|
-
return {
|
120
|
-
"success": True,
|
121
|
-
"stdout": output,
|
122
|
-
"stderr": ""
|
123
|
-
}
|
131
|
+
return {"success": True, "stdout": output, "stderr": ""}
|
124
132
|
|
125
133
|
except Exception as e:
|
126
134
|
PrettyOutput.print(str(e), OutputType.ERROR)
|
127
|
-
return {
|
128
|
-
"success": False,
|
129
|
-
"stdout": "",
|
130
|
-
"stderr": f"文件读取失败: {str(e)}"
|
131
|
-
}
|
135
|
+
return {"success": False, "stdout": "", "stderr": f"文件读取失败: {str(e)}"}
|
132
136
|
|
133
137
|
def execute(self, args: Dict) -> Dict[str, Any]:
|
134
138
|
"""执行代码读取操作
|
@@ -145,7 +149,7 @@ class ReadCodeTool:
|
|
145
149
|
return {
|
146
150
|
"success": False,
|
147
151
|
"stdout": "",
|
148
|
-
"stderr": "参数中必须包含文件列表"
|
152
|
+
"stderr": "参数中必须包含文件列表",
|
149
153
|
}
|
150
154
|
|
151
155
|
all_outputs = []
|
@@ -159,7 +163,7 @@ class ReadCodeTool:
|
|
159
163
|
file_info["path"].strip(),
|
160
164
|
file_info.get("start_line", 1),
|
161
165
|
file_info.get("end_line", -1),
|
162
|
-
agent
|
166
|
+
agent,
|
163
167
|
)
|
164
168
|
|
165
169
|
if result["success"]:
|
@@ -171,13 +175,9 @@ class ReadCodeTool:
|
|
171
175
|
return {
|
172
176
|
"success": overall_success,
|
173
177
|
"stdout": "\n".join(all_outputs),
|
174
|
-
"stderr": ""
|
178
|
+
"stderr": "",
|
175
179
|
}
|
176
180
|
|
177
181
|
except Exception as e:
|
178
182
|
PrettyOutput.print(str(e), OutputType.ERROR)
|
179
|
-
return {
|
180
|
-
"success": False,
|
181
|
-
"stdout": "",
|
182
|
-
"stderr": f"代码读取失败: {str(e)}"
|
183
|
-
}
|
183
|
+
return {"success": False, "stdout": "", "stderr": f"代码读取失败: {str(e)}"}
|