jarvis-ai-assistant 0.1.134__py3-none-any.whl → 0.1.138__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.

Files changed (78) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/__init__.py +201 -79
  3. jarvis/jarvis_agent/builtin_input_handler.py +16 -6
  4. jarvis/jarvis_agent/file_input_handler.py +9 -9
  5. jarvis/jarvis_agent/jarvis.py +10 -10
  6. jarvis/jarvis_agent/main.py +12 -11
  7. jarvis/jarvis_agent/output_handler.py +3 -3
  8. jarvis/jarvis_agent/patch.py +86 -62
  9. jarvis/jarvis_agent/shell_input_handler.py +5 -3
  10. jarvis/jarvis_code_agent/code_agent.py +134 -99
  11. jarvis/jarvis_code_agent/file_select.py +24 -24
  12. jarvis/jarvis_dev/main.py +45 -51
  13. jarvis/jarvis_git_details/__init__.py +0 -0
  14. jarvis/jarvis_git_details/main.py +179 -0
  15. jarvis/jarvis_git_squash/main.py +7 -7
  16. jarvis/jarvis_lsp/base.py +11 -11
  17. jarvis/jarvis_lsp/cpp.py +14 -14
  18. jarvis/jarvis_lsp/go.py +13 -13
  19. jarvis/jarvis_lsp/python.py +8 -8
  20. jarvis/jarvis_lsp/registry.py +21 -21
  21. jarvis/jarvis_lsp/rust.py +15 -15
  22. jarvis/jarvis_methodology/main.py +101 -0
  23. jarvis/jarvis_multi_agent/__init__.py +11 -11
  24. jarvis/jarvis_multi_agent/main.py +6 -6
  25. jarvis/jarvis_platform/__init__.py +1 -1
  26. jarvis/jarvis_platform/ai8.py +67 -89
  27. jarvis/jarvis_platform/base.py +14 -13
  28. jarvis/jarvis_platform/kimi.py +25 -28
  29. jarvis/jarvis_platform/ollama.py +24 -26
  30. jarvis/jarvis_platform/openai.py +15 -19
  31. jarvis/jarvis_platform/oyi.py +48 -50
  32. jarvis/jarvis_platform/registry.py +27 -28
  33. jarvis/jarvis_platform/yuanbao.py +38 -42
  34. jarvis/jarvis_platform_manager/main.py +81 -81
  35. jarvis/jarvis_platform_manager/openai_test.py +21 -21
  36. jarvis/jarvis_rag/file_processors.py +18 -18
  37. jarvis/jarvis_rag/main.py +261 -277
  38. jarvis/jarvis_smart_shell/main.py +12 -12
  39. jarvis/jarvis_tools/ask_codebase.py +28 -28
  40. jarvis/jarvis_tools/ask_user.py +8 -8
  41. jarvis/jarvis_tools/base.py +4 -4
  42. jarvis/jarvis_tools/chdir.py +9 -9
  43. jarvis/jarvis_tools/code_review.py +19 -19
  44. jarvis/jarvis_tools/create_code_agent.py +15 -15
  45. jarvis/jarvis_tools/execute_python_script.py +3 -3
  46. jarvis/jarvis_tools/execute_shell.py +11 -11
  47. jarvis/jarvis_tools/execute_shell_script.py +3 -3
  48. jarvis/jarvis_tools/file_analyzer.py +29 -29
  49. jarvis/jarvis_tools/file_operation.py +22 -20
  50. jarvis/jarvis_tools/find_caller.py +25 -25
  51. jarvis/jarvis_tools/find_methodolopy.py +65 -0
  52. jarvis/jarvis_tools/find_symbol.py +24 -24
  53. jarvis/jarvis_tools/function_analyzer.py +27 -27
  54. jarvis/jarvis_tools/git_commiter.py +9 -9
  55. jarvis/jarvis_tools/lsp_get_diagnostics.py +19 -19
  56. jarvis/jarvis_tools/methodology.py +23 -62
  57. jarvis/jarvis_tools/project_analyzer.py +29 -33
  58. jarvis/jarvis_tools/rag.py +15 -15
  59. jarvis/jarvis_tools/read_code.py +24 -22
  60. jarvis/jarvis_tools/read_webpage.py +31 -31
  61. jarvis/jarvis_tools/registry.py +72 -52
  62. jarvis/jarvis_tools/tool_generator.py +18 -18
  63. jarvis/jarvis_utils/config.py +23 -23
  64. jarvis/jarvis_utils/embedding.py +83 -83
  65. jarvis/jarvis_utils/git_utils.py +20 -20
  66. jarvis/jarvis_utils/globals.py +18 -6
  67. jarvis/jarvis_utils/input.py +10 -9
  68. jarvis/jarvis_utils/methodology.py +140 -136
  69. jarvis/jarvis_utils/output.py +11 -11
  70. jarvis/jarvis_utils/utils.py +22 -70
  71. {jarvis_ai_assistant-0.1.134.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/METADATA +1 -1
  72. jarvis_ai_assistant-0.1.138.dist-info/RECORD +85 -0
  73. {jarvis_ai_assistant-0.1.134.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/entry_points.txt +2 -0
  74. jarvis/jarvis_tools/select_code_files.py +0 -62
  75. jarvis_ai_assistant-0.1.134.dist-info/RECORD +0 -82
  76. {jarvis_ai_assistant-0.1.134.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/LICENSE +0 -0
  77. {jarvis_ai_assistant-0.1.134.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/WHEEL +0 -0
  78. {jarvis_ai_assistant-0.1.134.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/top_level.txt +0 -0
@@ -10,7 +10,7 @@ from jarvis.jarvis_utils.output import OutputType, PrettyOutput
10
10
 
11
11
  class MethodologyTool:
12
12
  """经验管理工具"""
13
-
13
+
14
14
  name = "methodology"
15
15
  description = "管理问题解决方法论,支持添加、更新和删除操作"
16
16
  parameters = {
@@ -33,12 +33,12 @@ class MethodologyTool:
33
33
  },
34
34
  "required": ["operation", "problem_type"]
35
35
  }
36
-
36
+
37
37
  def __init__(self):
38
38
  """初始化经验管理工具"""
39
39
  self.methodology_dir = os.path.expanduser("~/.jarvis/methodologies")
40
40
  self._ensure_dir_exists()
41
-
41
+
42
42
  def _ensure_dir_exists(self):
43
43
  """确保方法论目录存在"""
44
44
  if not os.path.exists(self.methodology_dir):
@@ -46,70 +46,50 @@ class MethodologyTool:
46
46
  os.makedirs(self.methodology_dir, exist_ok=True)
47
47
  except Exception as e:
48
48
  PrettyOutput.print(f"创建方法论目录失败:{str(e)}", OutputType.ERROR)
49
-
49
+
50
50
  def _get_methodology_file_path(self, problem_type: str) -> str:
51
51
  """
52
52
  根据问题类型获取对应的方法论文件路径
53
-
53
+
54
54
  参数:
55
55
  problem_type: 问题类型
56
-
56
+
57
57
  返回:
58
58
  str: 方法论文件路径
59
59
  """
60
60
  # 使用MD5哈希作为文件名,避免文件名中的特殊字符
61
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
-
64
- def _load_methodologies(self) -> Dict[str, str]:
65
- """加载所有方法论"""
66
- all_methodologies = {}
67
-
68
- if not os.path.exists(self.methodology_dir):
69
- return all_methodologies
70
-
71
- for filepath in glob.glob(os.path.join(self.methodology_dir, "*.json")):
72
- try:
73
- with open(filepath, "r", encoding="utf-8", errors="ignore") as f:
74
- methodology = json.load(f)
75
- problem_type = methodology.get("problem_type", "")
76
- content = methodology.get("content", "")
77
- if problem_type and content:
78
- all_methodologies[problem_type] = content
79
- except Exception as e:
80
- filename = os.path.basename(filepath)
81
- PrettyOutput.print(f"加载方法论文件 {filename} 失败: {str(e)}", OutputType.WARNING)
82
-
83
- return all_methodologies
84
-
63
+
64
+
85
65
  def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
86
66
  """执行管理方法论的操作
87
-
67
+
88
68
  Args:
89
69
  args: 包含操作参数的字典
90
70
  - operation: 操作类型 (delete/update/add)
91
71
  - problem_type: 问题类型
92
72
  - content: 方法论内容 (更新和添加时必填)
93
-
73
+
94
74
  Returns:
95
75
  Dict[str, Any]: 包含执行结果的字典
96
76
  """
97
77
  operation = args.get("operation", "").strip()
98
78
  problem_type = args.get("problem_type", "").strip()
99
79
  content = args.get("content", "").strip()
100
-
80
+
101
81
  if not operation or not problem_type:
102
82
  return {
103
83
  "success": False,
104
84
  "stdout": "",
105
85
  "stderr": "Missing required parameters: operation and problem_type"
106
86
  }
107
-
87
+
108
88
  try:
109
89
  if operation == "delete":
110
90
  # 获取方法论文件路径
111
91
  file_path = self._get_methodology_file_path(problem_type)
112
-
92
+
113
93
  # 检查文件是否存在
114
94
  if os.path.exists(file_path):
115
95
  os.remove(file_path)
@@ -124,7 +104,7 @@ class MethodologyTool:
124
104
  "stdout": "",
125
105
  "stderr": f"Methodology for problem type '{problem_type}' not found"
126
106
  }
127
-
107
+
128
108
  elif operation in ["update", "add"]:
129
109
  if not content:
130
110
  return {
@@ -132,59 +112,40 @@ class MethodologyTool:
132
112
  "stdout": "",
133
113
  "stderr": "Need to provide methodology content"
134
114
  }
135
-
115
+
136
116
  # 确保目录存在
137
117
  self._ensure_dir_exists()
138
-
118
+
139
119
  # 获取方法论文件路径
140
120
  file_path = self._get_methodology_file_path(problem_type)
141
-
121
+
142
122
  # 保存方法论到单独的文件
143
123
  with open(file_path, "w", encoding="utf-8", errors="ignore") as f:
144
124
  json.dump({
145
125
  "problem_type": problem_type,
146
126
  "content": content
147
127
  }, f, ensure_ascii=False, indent=2)
148
-
128
+
129
+ PrettyOutput.print(f"方法论已保存到 {file_path}", OutputType.INFO)
130
+
149
131
  action = "Updated" if os.path.exists(file_path) else "Added"
150
132
  return {
151
133
  "success": True,
152
134
  "stdout": f"{action} methodology for problem type '{problem_type}'",
153
135
  "stderr": ""
154
136
  }
155
-
137
+
156
138
  else:
157
139
  return {
158
140
  "success": False,
159
141
  "stdout": "",
160
142
  "stderr": f"Unsupported operation type: {operation}"
161
143
  }
162
-
144
+
163
145
  except Exception as e:
164
146
  return {
165
147
  "success": False,
166
148
  "stdout": "",
167
149
  "stderr": f"Execution failed: {str(e)}"
168
150
  }
169
-
170
- def get_methodology(self, problem_type: str) -> Optional[str]:
171
- """获取特定问题类型的方法论
172
-
173
- Args:
174
- problem_type: 问题类型
175
-
176
- Returns:
177
- Optional[str]: 方法论内容,如果不存在则返回 None
178
- """
179
- file_path = self._get_methodology_file_path(problem_type)
180
-
181
- if not os.path.exists(file_path):
182
- return None
183
-
184
- try:
185
- with open(file_path, "r", encoding="utf-8", errors="ignore") as f:
186
- methodology = json.load(f)
187
- return methodology.get("content")
188
- except Exception as e:
189
- PrettyOutput.print(f"读取方法论失败: {str(e)}", OutputType.ERROR)
190
- return None
151
+
@@ -11,7 +11,7 @@ class ProjectAnalyzerTool:
11
11
  项目分析工具
12
12
  使用agent分析项目结构、入口点、模块划分等信息(支持所有文件类型)
13
13
  """
14
-
14
+
15
15
  name = "project_analyzer"
16
16
  description = "分析项目结构、入口点、模块划分等信息,提供项目概览(支持所有文件类型)"
17
17
  parameters = {
@@ -46,51 +46,51 @@ class ProjectAnalyzerTool:
46
46
  },
47
47
  "required": []
48
48
  }
49
-
49
+
50
50
  def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
51
51
  """
52
52
  执行项目分析工具
53
-
53
+
54
54
  Args:
55
55
  args: 包含参数的字典
56
-
56
+
57
57
  Returns:
58
58
  包含执行结果的字典
59
59
  """
60
60
  # 存储原始目录
61
61
  original_dir = os.getcwd()
62
-
62
+
63
63
  try:
64
64
  # 解析参数
65
65
  root_dir = args.get("root_dir", ".")
66
66
  focus_dirs = args.get("focus_dirs", [])
67
67
  exclude_dirs = args.get("exclude_dirs", [])
68
68
  objective = args.get("objective", "")
69
-
69
+
70
70
  # 创建agent的system prompt
71
71
  system_prompt = self._create_system_prompt(
72
72
  root_dir, focus_dirs, exclude_dirs, objective
73
73
  )
74
-
74
+
75
75
  # 创建agent的summary prompt
76
76
  summary_prompt = self._create_summary_prompt(root_dir, objective)
77
-
77
+
78
78
  # 切换到根目录
79
79
  os.chdir(root_dir)
80
-
80
+
81
81
  # 构建使用的工具
82
82
  from jarvis.jarvis_tools.registry import ToolRegistry
83
83
  tool_registry = ToolRegistry()
84
84
  tool_registry.use_tools([
85
- "execute_shell",
86
- "read_code",
85
+ "execute_shell",
86
+ "read_code",
87
87
  "find_symbol",
88
88
  "function_analyzer",
89
89
  "find_caller",
90
90
  "file_analyzer",
91
91
  "ask_codebase"
92
92
  ])
93
-
93
+
94
94
  # 创建并运行agent
95
95
  analyzer_agent = Agent(
96
96
  system_prompt=system_prompt,
@@ -102,17 +102,17 @@ class ProjectAnalyzerTool:
102
102
  execute_tool_confirm=False,
103
103
  auto_complete=True
104
104
  )
105
-
105
+
106
106
  # 运行agent并获取结果
107
107
  task_input = f"分析项目结构、入口点、模块划分等信息,提供项目概览"
108
108
  result = analyzer_agent.run(task_input)
109
-
109
+
110
110
  return {
111
111
  "success": True,
112
112
  "stdout": result,
113
113
  "stderr": ""
114
114
  }
115
-
115
+
116
116
  except Exception as e:
117
117
  PrettyOutput.print(str(e), OutputType.ERROR)
118
118
  return {
@@ -123,47 +123,46 @@ class ProjectAnalyzerTool:
123
123
  finally:
124
124
  # 恢复原始目录
125
125
  os.chdir(original_dir)
126
-
127
- def _create_system_prompt(self, root_dir: str, focus_dirs: List[str],
126
+
127
+ def _create_system_prompt(self, root_dir: str, focus_dirs: List[str],
128
128
  exclude_dirs: List[str], objective: str) -> str:
129
129
  """
130
130
  创建Agent的system prompt
131
-
131
+
132
132
  Args:
133
133
  root_dir: 项目根目录
134
134
  focus_dirs: 重点分析的目录列表
135
135
  exclude_dirs: 排除的目录列表
136
136
  objective: 分析目标
137
-
137
+
138
138
  Returns:
139
139
  系统提示文本
140
140
  """
141
141
  focus_dirs_str = ", ".join(focus_dirs) if focus_dirs else "整个项目"
142
142
  exclude_dirs_str = ", ".join(exclude_dirs) if exclude_dirs else "无"
143
-
143
+
144
144
  objective_text = f"\n\n## 分析目标\n{objective}" if objective else "\n\n## 分析目标\n全面了解项目结构、模块划分和关键组件"
145
-
145
+
146
146
  return f"""# 项目架构分析专家
147
147
 
148
148
  ## 任务描述
149
149
  对项目 `{root_dir}` 进行针对性分析,专注于分析目标所需的内容,生成有针对性、深入且有洞察力的项目分析报告。{objective_text}
150
150
 
151
151
  ## 工具使用优先级
152
- 1. **优先使用 execute_shell 执行 fd 命令**:
152
+ 1. **优先使用 execute_shell 执行 fd 命令**:
153
153
  - `fd -t f -e py` 查找所有Python文件
154
154
  - `fd -t d` 列出所有目录
155
155
  - `fd README.md` 查找所有README文件
156
156
 
157
- 2. **优先使用 execute_shell 执行 rg 命令**:
157
+ 2. **优先使用 execute_shell 执行 rg 命令**:
158
158
  - `rg "import" --type py` 搜索导入语句
159
159
  - `rg "class|def" --type py` 搜索类和函数定义
160
160
  - `rg "TODO|FIXME" --type py` 搜索代码注释
161
161
 
162
- 3. **优先使用 execute_shell 执行 loc 命令**:
162
+ 3. **优先使用 execute_shell 执行 loc 命令**:
163
163
  - `loc` 统计所有代码行数
164
- - `loc --include="*.py"` 统计Python代码行数
165
164
 
166
- 4. **辅以 read_code 读取关键文件**:
165
+ 4. **辅以 read_code 读取关键文件**:
167
166
  - 读取README.md、配置文件、主要模块
168
167
  - 对于较大的文件,可读取关键部分
169
168
 
@@ -232,9 +231,6 @@ class ProjectAnalyzerTool:
232
231
 
233
232
  ### 代码统计分析
234
233
  - `loc` 获取项目总体代码统计
235
- - `loc --include="*.py"` 统计Python代码量
236
- - `loc --include="*.js" --include="*.jsx" --include="*.ts" --include="*.tsx"` 统计JavaScript/TypeScript代码量
237
- - `loc --exclude="test"` 排除测试代码后的统计
238
234
 
239
235
  ### 依赖分析
240
236
  - `read_code requirements.txt` 读取Python依赖
@@ -280,16 +276,16 @@ class ProjectAnalyzerTool:
280
276
  def _create_summary_prompt(self, root_dir: str, objective: str) -> str:
281
277
  """
282
278
  创建Agent的summary prompt
283
-
279
+
284
280
  Args:
285
281
  root_dir: 项目根目录
286
282
  objective: 分析目标
287
-
283
+
288
284
  Returns:
289
285
  总结提示文本
290
286
  """
291
287
  objective_text = f"\n\n## 具体分析目标\n{objective}" if objective else ""
292
-
288
+
293
289
  return f"""# 项目分析报告: `{root_dir}`{objective_text}
294
290
 
295
291
  ## 报告要求
@@ -305,4 +301,4 @@ class ProjectAnalyzerTool:
305
301
  - 根据分析目标灵活组织报告结构,不必包含所有传统的项目分析章节
306
302
  - 以清晰的Markdown格式呈现,简洁明了
307
303
 
308
- 在分析中保持灵活性,避免固定思维模式。你的任务不是提供全面的项目概览,而是直接解决分析目标中提出的具体问题。"""
304
+ 在分析中保持灵活性,避免固定思维模式。你的任务不是提供全面的项目概览,而是直接解决分析目标中提出的具体问题。"""
@@ -32,10 +32,10 @@ class RAGTool:
32
32
 
33
33
  def _get_rag_instance(self, dir_path: str) -> RAGCore:
34
34
  """Get or create RAG instance
35
-
35
+
36
36
  Args:
37
37
  dir_path: The absolute path of the document directory
38
-
38
+
39
39
  Returns:
40
40
  RAGCore: RAG instance
41
41
  """
@@ -45,13 +45,13 @@ class RAGTool:
45
45
 
46
46
  def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
47
47
  """执行文档问答
48
-
48
+
49
49
  Args:
50
50
  args: 包含参数的字典
51
51
  - dir: 文档目录路径
52
52
  - question: 要询问的问题
53
53
  - rebuild_index: 是否重建索引
54
-
54
+
55
55
  Returns:
56
56
  Dict[str, Any]: 执行结果,包含以下字段:
57
57
  - success: 布尔值,表示操作是否成功
@@ -64,7 +64,7 @@ class RAGTool:
64
64
  dir_path = os.path.abspath(dir_path)
65
65
  question = args["question"]
66
66
  rebuild_index = args.get("rebuild_index", False)
67
-
67
+
68
68
  # 检查目录是否存在
69
69
  if not os.path.exists(dir_path):
70
70
  return {
@@ -72,7 +72,7 @@ class RAGTool:
72
72
  "stdout": "",
73
73
  "stderr": f"Directory does not exist: {dir_path}"
74
74
  }
75
-
75
+
76
76
  # 检查路径是否为目录
77
77
  if not os.path.isdir(dir_path):
78
78
  return {
@@ -80,19 +80,19 @@ class RAGTool:
80
80
  "stdout": "",
81
81
  "stderr": f"The path is not a directory: {dir_path}"
82
82
  }
83
-
83
+
84
84
  # 获取RAG实例
85
85
  rag = self._get_rag_instance(dir_path)
86
-
86
+
87
87
  # 如果需要重建索引或索引不存在
88
88
  if rebuild_index or not rag.is_index_built():
89
89
  PrettyOutput.print("正在构建文档索引...", OutputType.INFO)
90
90
  rag.build_index(dir_path)
91
-
91
+
92
92
  # 执行问答
93
93
  PrettyOutput.print(f"问题: {question}", OutputType.INFO)
94
94
  response = rag.ask(question)
95
-
95
+
96
96
  # 处理未找到相关文档的情况
97
97
  if response is None:
98
98
  return {
@@ -100,14 +100,14 @@ class RAGTool:
100
100
  "stdout": "",
101
101
  "stderr": "Failed to get answer, possibly no relevant documents found"
102
102
  }
103
-
103
+
104
104
  # 返回成功响应
105
105
  return {
106
106
  "success": True,
107
107
  "stdout": response,
108
108
  "stderr": ""
109
109
  }
110
-
110
+
111
111
  except Exception as e:
112
112
  # 处理任何意外错误
113
113
  PrettyOutput.print(f"文档问答失败:{str(e)}", OutputType.ERROR)
@@ -120,20 +120,20 @@ class RAGTool:
120
120
  def main():
121
121
  """Run the tool directly from the command line"""
122
122
  import argparse
123
-
123
+
124
124
  parser = argparse.ArgumentParser(description='Document question and answer tool')
125
125
  parser.add_argument('--dir', required=True, help='Document directory path')
126
126
  parser.add_argument('--question', required=True, help='The question to ask')
127
127
  parser.add_argument('--rebuild', action='store_true', help='Rebuild index')
128
128
  args = parser.parse_args()
129
-
129
+
130
130
  tool = RAGTool()
131
131
  result = tool.execute({
132
132
  "dir": args.dir,
133
133
  "question": args.question,
134
134
  "rebuild_index": args.rebuild
135
135
  })
136
-
136
+
137
137
  if result["success"]:
138
138
  PrettyOutput.print(f"{result['stdout']}", OutputType.INFO, lang="markdown")
139
139
  else:
@@ -1,8 +1,10 @@
1
1
  from typing import Dict, Any
2
2
  import os
3
3
 
4
+ from pkg_resources import add_activation_listener
4
5
  from yaspin import yaspin
5
6
 
7
+ from jarvis.jarvis_utils.globals import add_read_file_record
6
8
  from jarvis.jarvis_utils.output import OutputType, PrettyOutput
7
9
 
8
10
  class ReadCodeTool:
@@ -30,17 +32,18 @@ class ReadCodeTool:
30
32
 
31
33
  def _handle_single_file(self, filepath: str, start_line: int = 1, end_line: int = -1) -> Dict[str, Any]:
32
34
  """处理单个文件的读取操作
33
-
35
+
34
36
  Args:
35
37
  filepath (str): 文件路径
36
38
  start_line (int): 起始行号,默认为1
37
39
  end_line (int): 结束行号,默认为-1表示文件末尾
38
-
40
+
39
41
  Returns:
40
42
  Dict[str, Any]: 包含成功状态、输出内容和错误信息的字典
41
43
  """
42
44
  try:
43
45
  abs_path = os.path.abspath(filepath)
46
+ add_read_file_record(abs_path)
44
47
  with yaspin(text=f"正在读取文件: {abs_path}...", color="cyan") as spinner:
45
48
  # 文件存在性检查
46
49
  if not os.path.exists(abs_path):
@@ -49,7 +52,7 @@ class ReadCodeTool:
49
52
  "stdout": "",
50
53
  "stderr": f"文件不存在: {abs_path}"
51
54
  }
52
-
55
+
53
56
  # 文件大小限制检查(10MB)
54
57
  if os.path.getsize(abs_path) > 10 * 1024 * 1024:
55
58
  return {
@@ -57,21 +60,21 @@ class ReadCodeTool:
57
60
  "stdout": "",
58
61
  "stderr": "文件过大 (>10MB)"
59
62
  }
60
-
63
+
61
64
  # 读取文件内容
62
65
  with open(abs_path, 'r', encoding='utf-8', errors="ignore") as f:
63
66
  lines = f.readlines()
64
-
67
+
65
68
  total_lines = len(lines)
66
-
69
+
67
70
  # 处理特殊值-1表示文件末尾
68
71
  if end_line == -1:
69
72
  end_line = total_lines
70
73
  else:
71
74
  end_line = max(1, min(end_line, total_lines)) if end_line >= 0 else total_lines + end_line + 1
72
-
75
+
73
76
  start_line = max(1, min(start_line, total_lines)) if start_line >= 0 else total_lines + start_line + 1
74
-
77
+
75
78
  if start_line > end_line:
76
79
  spinner.fail("❌")
77
80
  return {
@@ -79,20 +82,19 @@ class ReadCodeTool:
79
82
  "stdout": "",
80
83
  "stderr": f"无效的行范围 [{start_line}-{end_line}] (总行数: {total_lines})"
81
84
  }
82
-
85
+
83
86
  # 添加行号并构建输出内容
84
87
  selected_lines = lines[start_line-1:end_line]
85
88
  numbered_content = "".join(
86
- [f"{i:4d}:{line}"
89
+ [f"{i:4d}:{line}"
87
90
  for i, line in enumerate(selected_lines, start=start_line)]
88
91
  )
89
-
92
+
90
93
  # 构建输出格式
91
94
  output = (
92
95
  f"\n🔍 文件: {abs_path}\n"
93
96
  f"📄 原始行号: {start_line}-{end_line} (共{total_lines}行) \n\n"
94
- f"{numbered_content}\n"
95
- f"{'='*80}\n"
97
+ f"{numbered_content}\n\n"
96
98
  )
97
99
  spinner.text = f"文件读取完成: {abs_path}"
98
100
  spinner.ok("✅")
@@ -104,7 +106,7 @@ class ReadCodeTool:
104
106
  "stdout": output,
105
107
  "stderr": ""
106
108
  }
107
-
109
+
108
110
  except Exception as e:
109
111
  PrettyOutput.print(str(e), OutputType.ERROR)
110
112
  return {
@@ -115,10 +117,10 @@ class ReadCodeTool:
115
117
 
116
118
  def execute(self, args: Dict) -> Dict[str, Any]:
117
119
  """执行代码读取操作
118
-
120
+
119
121
  Args:
120
122
  args (Dict): 包含文件列表的参数字典
121
-
123
+
122
124
  Returns:
123
125
  Dict[str, Any]: 包含成功状态、输出内容和错误信息的字典
124
126
  """
@@ -129,32 +131,32 @@ class ReadCodeTool:
129
131
  "stdout": "",
130
132
  "stderr": "参数中必须包含文件列表"
131
133
  }
132
-
134
+
133
135
  all_outputs = []
134
136
  overall_success = True
135
-
137
+
136
138
  for file_info in args["files"]:
137
139
  if not isinstance(file_info, dict) or "path" not in file_info:
138
140
  continue
139
-
141
+
140
142
  result = self._handle_single_file(
141
143
  file_info["path"].strip(),
142
144
  file_info.get("start_line", 1),
143
145
  file_info.get("end_line", -1)
144
146
  )
145
-
147
+
146
148
  if result["success"]:
147
149
  all_outputs.append(result["stdout"])
148
150
  else:
149
151
  all_outputs.append(f"❌ {file_info['path']}: {result['stderr']}")
150
152
  overall_success = False
151
-
153
+
152
154
  return {
153
155
  "success": overall_success,
154
156
  "stdout": "\n".join(all_outputs),
155
157
  "stderr": ""
156
158
  }
157
-
159
+
158
160
  except Exception as e:
159
161
  PrettyOutput.print(str(e), OutputType.ERROR)
160
162
  return {