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.
Files changed (92) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/__init__.py +45 -41
  3. jarvis/jarvis_agent/builtin_input_handler.py +26 -4
  4. jarvis/jarvis_agent/jarvis.py +30 -19
  5. jarvis/jarvis_agent/main.py +20 -12
  6. jarvis/jarvis_agent/output_handler.py +7 -7
  7. jarvis/jarvis_agent/shell_input_handler.py +14 -11
  8. jarvis/jarvis_code_agent/code_agent.py +81 -79
  9. jarvis/jarvis_code_agent/lint.py +92 -105
  10. jarvis/jarvis_code_analysis/checklists/__init__.py +1 -1
  11. jarvis/jarvis_code_analysis/checklists/c_cpp.py +1 -1
  12. jarvis/jarvis_code_analysis/checklists/csharp.py +1 -1
  13. jarvis/jarvis_code_analysis/checklists/data_format.py +1 -1
  14. jarvis/jarvis_code_analysis/checklists/devops.py +1 -1
  15. jarvis/jarvis_code_analysis/checklists/docs.py +1 -1
  16. jarvis/jarvis_code_analysis/checklists/go.py +1 -1
  17. jarvis/jarvis_code_analysis/checklists/infrastructure.py +1 -1
  18. jarvis/jarvis_code_analysis/checklists/java.py +1 -1
  19. jarvis/jarvis_code_analysis/checklists/javascript.py +1 -1
  20. jarvis/jarvis_code_analysis/checklists/kotlin.py +1 -1
  21. jarvis/jarvis_code_analysis/checklists/loader.py +31 -29
  22. jarvis/jarvis_code_analysis/checklists/php.py +1 -1
  23. jarvis/jarvis_code_analysis/checklists/python.py +1 -1
  24. jarvis/jarvis_code_analysis/checklists/ruby.py +1 -1
  25. jarvis/jarvis_code_analysis/checklists/rust.py +1 -1
  26. jarvis/jarvis_code_analysis/checklists/shell.py +1 -1
  27. jarvis/jarvis_code_analysis/checklists/sql.py +1 -1
  28. jarvis/jarvis_code_analysis/checklists/swift.py +1 -1
  29. jarvis/jarvis_code_analysis/checklists/web.py +1 -1
  30. jarvis/jarvis_code_analysis/code_review.py +292 -190
  31. jarvis/jarvis_dev/main.py +73 -56
  32. jarvis/jarvis_git_details/main.py +29 -33
  33. jarvis/jarvis_git_squash/main.py +13 -11
  34. jarvis/jarvis_git_utils/git_commiter.py +15 -5
  35. jarvis/jarvis_mcp/__init__.py +8 -10
  36. jarvis/jarvis_mcp/sse_mcp_client.py +182 -205
  37. jarvis/jarvis_mcp/stdio_mcp_client.py +93 -120
  38. jarvis/jarvis_mcp/streamable_mcp_client.py +117 -142
  39. jarvis/jarvis_methodology/main.py +71 -39
  40. jarvis/jarvis_multi_agent/__init__.py +24 -16
  41. jarvis/jarvis_multi_agent/main.py +10 -4
  42. jarvis/jarvis_platform/__init__.py +1 -1
  43. jarvis/jarvis_platform/base.py +44 -18
  44. jarvis/jarvis_platform/human.py +15 -3
  45. jarvis/jarvis_platform/kimi.py +117 -81
  46. jarvis/jarvis_platform/openai.py +23 -28
  47. jarvis/jarvis_platform/registry.py +43 -29
  48. jarvis/jarvis_platform/tongyi.py +16 -10
  49. jarvis/jarvis_platform/yuanbao.py +197 -144
  50. jarvis/jarvis_platform_manager/main.py +4 -2
  51. jarvis/jarvis_smart_shell/main.py +35 -30
  52. jarvis/jarvis_tools/ask_user.py +8 -16
  53. jarvis/jarvis_tools/base.py +3 -2
  54. jarvis/jarvis_tools/chdir.py +7 -19
  55. jarvis/jarvis_tools/cli/main.py +14 -10
  56. jarvis/jarvis_tools/code_plan.py +10 -31
  57. jarvis/jarvis_tools/create_code_agent.py +6 -11
  58. jarvis/jarvis_tools/create_sub_agent.py +10 -22
  59. jarvis/jarvis_tools/edit_file.py +98 -76
  60. jarvis/jarvis_tools/execute_script.py +46 -46
  61. jarvis/jarvis_tools/file_analyzer.py +22 -34
  62. jarvis/jarvis_tools/file_operation.py +69 -62
  63. jarvis/jarvis_tools/generate_new_tool.py +0 -2
  64. jarvis/jarvis_tools/methodology.py +19 -23
  65. jarvis/jarvis_tools/read_code.py +35 -35
  66. jarvis/jarvis_tools/read_webpage.py +7 -16
  67. jarvis/jarvis_tools/registry.py +63 -30
  68. jarvis/jarvis_tools/rewrite_file.py +26 -29
  69. jarvis/jarvis_tools/search_web.py +5 -8
  70. jarvis/jarvis_tools/virtual_tty.py +133 -122
  71. jarvis/jarvis_utils/__init__.py +0 -1
  72. jarvis/jarvis_utils/builtin_replace_map.py +9 -9
  73. jarvis/jarvis_utils/config.py +60 -37
  74. jarvis/jarvis_utils/embedding.py +24 -19
  75. jarvis/jarvis_utils/file_processors.py +16 -9
  76. jarvis/jarvis_utils/git_utils.py +157 -107
  77. jarvis/jarvis_utils/globals.py +1 -1
  78. jarvis/jarvis_utils/input.py +85 -52
  79. jarvis/jarvis_utils/jarvis_history.py +43 -0
  80. jarvis/jarvis_utils/methodology.py +31 -24
  81. jarvis/jarvis_utils/output.py +164 -80
  82. jarvis/jarvis_utils/tag.py +2 -1
  83. jarvis/jarvis_utils/utils.py +84 -52
  84. {jarvis_ai_assistant-0.1.193.dist-info → jarvis_ai_assistant-0.1.195.dist-info}/METADATA +362 -230
  85. jarvis_ai_assistant-0.1.195.dist-info/RECORD +98 -0
  86. jarvis/jarvis_agent/file_input_handler.py +0 -112
  87. jarvis/jarvis_event/__init__.py +0 -0
  88. jarvis_ai_assistant-0.1.193.dist-info/RECORD +0 -99
  89. {jarvis_ai_assistant-0.1.193.dist-info → jarvis_ai_assistant-0.1.195.dist-info}/WHEEL +0 -0
  90. {jarvis_ai_assistant-0.1.193.dist-info → jarvis_ai_assistant-0.1.195.dist-info}/entry_points.txt +0 -0
  91. {jarvis_ai_assistant-0.1.193.dist-info → jarvis_ai_assistant-0.1.195.dist-info}/licenses/LICENSE +0 -0
  92. {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 = """分析文件内容并提取关键信息。支持的文件:文本文件、word文档、pdf文件、图片"""
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
- "type": "string"
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
- TextFileProcessor # 文本文件处理器(放在最后作为兜底)
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(self, operation: str, filepath: str, content: str = "",
53
- start_line: int = 1, end_line: int = -1, agent: Any = None) -> Dict[str, Any]:
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(text=f"正在读取文件: {abs_path}...", color="cyan") as spinner:
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(abs_path, 'r', encoding='utf-8', errors="ignore") as f:
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 = start_line if start_line >= 0 else total_lines + start_line + 1
95
- end_line = end_line if end_line >= 0 else total_lines + end_line + 1
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(text=f"正在写入文件: {abs_path}...", color="cyan") as spinner:
147
- os.makedirs(os.path.dirname(os.path.abspath(abs_path)), exist_ok=True)
148
- with open(abs_path, 'w', encoding='utf-8', errors="ignore") as f:
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(f"处理文件 {file_info['path']} 时出错: {result['stderr']}")
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)}"}
@@ -135,8 +135,6 @@ class generate_new_tool:
135
135
 
136
136
  # 检查并安装缺失的依赖
137
137
  try:
138
- import re
139
-
140
138
  required_packages = set()
141
139
 
142
140
  # 从代码中提取import语句
@@ -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('utf-8')).hexdigest()
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
- "content": content
127
- }, f, ensure_ascii=False, indent=2)
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)}"}
@@ -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(self, filepath: str, start_line: int = 1, end_line: int = -1, agent: Any = None) -> Dict[str, Any]:
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, 'r', encoding='utf-8', errors="ignore") as f:
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 = max(1, min(end_line, total_lines)) if end_line >= 0 else total_lines + end_line + 1
84
-
85
- start_line = max(1, min(start_line, total_lines)) if start_line >= 0 else total_lines + start_line + 1
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
- [f"{i:4d}:{line}"
99
- for i, line in enumerate(selected_lines, start=start_line)]
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)}"}