jarvis-ai-assistant 0.1.132__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.
- jarvis/__init__.py +1 -1
- jarvis/jarvis_agent/__init__.py +330 -347
- jarvis/jarvis_agent/builtin_input_handler.py +16 -6
- jarvis/jarvis_agent/file_input_handler.py +9 -9
- jarvis/jarvis_agent/jarvis.py +143 -0
- jarvis/jarvis_agent/main.py +12 -13
- jarvis/jarvis_agent/output_handler.py +3 -3
- jarvis/jarvis_agent/patch.py +92 -64
- jarvis/jarvis_agent/shell_input_handler.py +5 -3
- jarvis/jarvis_code_agent/code_agent.py +263 -177
- jarvis/jarvis_code_agent/file_select.py +24 -24
- jarvis/jarvis_dev/main.py +45 -59
- jarvis/jarvis_git_details/__init__.py +0 -0
- jarvis/jarvis_git_details/main.py +179 -0
- jarvis/jarvis_git_squash/main.py +7 -7
- jarvis/jarvis_lsp/base.py +11 -53
- jarvis/jarvis_lsp/cpp.py +13 -28
- jarvis/jarvis_lsp/go.py +13 -28
- jarvis/jarvis_lsp/python.py +8 -27
- jarvis/jarvis_lsp/registry.py +21 -83
- jarvis/jarvis_lsp/rust.py +15 -30
- jarvis/jarvis_methodology/main.py +101 -0
- jarvis/jarvis_multi_agent/__init__.py +10 -51
- jarvis/jarvis_multi_agent/main.py +43 -0
- jarvis/jarvis_platform/__init__.py +1 -1
- jarvis/jarvis_platform/ai8.py +67 -89
- jarvis/jarvis_platform/base.py +14 -13
- jarvis/jarvis_platform/kimi.py +25 -28
- jarvis/jarvis_platform/ollama.py +24 -26
- jarvis/jarvis_platform/openai.py +15 -19
- jarvis/jarvis_platform/oyi.py +48 -50
- jarvis/jarvis_platform/registry.py +29 -44
- jarvis/jarvis_platform/yuanbao.py +39 -43
- jarvis/jarvis_platform_manager/main.py +81 -81
- jarvis/jarvis_platform_manager/openai_test.py +21 -21
- jarvis/jarvis_rag/file_processors.py +18 -18
- jarvis/jarvis_rag/main.py +262 -278
- jarvis/jarvis_smart_shell/main.py +12 -12
- jarvis/jarvis_tools/ask_codebase.py +85 -78
- jarvis/jarvis_tools/ask_user.py +8 -8
- jarvis/jarvis_tools/base.py +4 -4
- jarvis/jarvis_tools/chdir.py +9 -9
- jarvis/jarvis_tools/code_review.py +40 -21
- jarvis/jarvis_tools/create_code_agent.py +15 -15
- jarvis/jarvis_tools/create_sub_agent.py +0 -1
- jarvis/jarvis_tools/execute_python_script.py +3 -3
- jarvis/jarvis_tools/execute_shell.py +11 -11
- jarvis/jarvis_tools/execute_shell_script.py +3 -3
- jarvis/jarvis_tools/file_analyzer.py +116 -105
- jarvis/jarvis_tools/file_operation.py +22 -20
- jarvis/jarvis_tools/find_caller.py +105 -40
- jarvis/jarvis_tools/find_methodolopy.py +65 -0
- jarvis/jarvis_tools/find_symbol.py +123 -39
- jarvis/jarvis_tools/function_analyzer.py +140 -57
- jarvis/jarvis_tools/git_commiter.py +10 -10
- jarvis/jarvis_tools/lsp_get_diagnostics.py +19 -19
- jarvis/jarvis_tools/methodology.py +22 -67
- jarvis/jarvis_tools/project_analyzer.py +137 -53
- jarvis/jarvis_tools/rag.py +15 -20
- jarvis/jarvis_tools/read_code.py +25 -23
- jarvis/jarvis_tools/read_webpage.py +31 -31
- jarvis/jarvis_tools/registry.py +72 -52
- jarvis/jarvis_tools/search_web.py +23 -353
- jarvis/jarvis_tools/tool_generator.py +19 -19
- jarvis/jarvis_utils/config.py +36 -96
- jarvis/jarvis_utils/embedding.py +83 -83
- jarvis/jarvis_utils/git_utils.py +20 -20
- jarvis/jarvis_utils/globals.py +18 -6
- jarvis/jarvis_utils/input.py +10 -9
- jarvis/jarvis_utils/methodology.py +141 -140
- jarvis/jarvis_utils/output.py +13 -13
- jarvis/jarvis_utils/utils.py +23 -71
- {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/METADATA +6 -15
- jarvis_ai_assistant-0.1.138.dist-info/RECORD +85 -0
- {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/entry_points.txt +4 -3
- jarvis/jarvis_tools/lsp_find_definition.py +0 -150
- jarvis/jarvis_tools/lsp_find_references.py +0 -127
- jarvis/jarvis_tools/select_code_files.py +0 -62
- jarvis_ai_assistant-0.1.132.dist-info/RECORD +0 -82
- {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/top_level.txt +0 -0
|
@@ -12,7 +12,7 @@ class FileAnalyzerTool:
|
|
|
12
12
|
单文件分析工具
|
|
13
13
|
使用agent深入分析单个文件的结构、实现细节和代码质量
|
|
14
14
|
"""
|
|
15
|
-
|
|
15
|
+
|
|
16
16
|
name = "file_analyzer"
|
|
17
17
|
description = "深入分析单个文件的结构、实现细节和代码质量"
|
|
18
18
|
parameters = {
|
|
@@ -35,26 +35,26 @@ class FileAnalyzerTool:
|
|
|
35
35
|
},
|
|
36
36
|
"required": ["file_path"]
|
|
37
37
|
}
|
|
38
|
-
|
|
38
|
+
|
|
39
39
|
def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
|
|
40
40
|
"""
|
|
41
41
|
执行单文件分析工具
|
|
42
|
-
|
|
42
|
+
|
|
43
43
|
Args:
|
|
44
44
|
args: 包含参数的字典
|
|
45
|
-
|
|
45
|
+
|
|
46
46
|
Returns:
|
|
47
47
|
包含执行结果的字典
|
|
48
48
|
"""
|
|
49
49
|
# 存储原始目录
|
|
50
50
|
original_dir = os.getcwd()
|
|
51
|
-
|
|
51
|
+
|
|
52
52
|
try:
|
|
53
53
|
# 解析参数
|
|
54
54
|
file_path = args.get("file_path", "")
|
|
55
55
|
root_dir = args.get("root_dir", ".")
|
|
56
56
|
objective = args.get("objective", "")
|
|
57
|
-
|
|
57
|
+
|
|
58
58
|
# 验证参数
|
|
59
59
|
if not file_path:
|
|
60
60
|
return {
|
|
@@ -62,31 +62,31 @@ class FileAnalyzerTool:
|
|
|
62
62
|
"stdout": "",
|
|
63
63
|
"stderr": "必须提供文件路径"
|
|
64
64
|
}
|
|
65
|
-
|
|
65
|
+
|
|
66
66
|
# 确保文件路径是相对于root_dir的,如果是绝对路径则转换为相对路径
|
|
67
67
|
abs_file_path = os.path.abspath(file_path)
|
|
68
68
|
abs_root_dir = os.path.abspath(root_dir)
|
|
69
|
-
|
|
69
|
+
|
|
70
70
|
if abs_file_path.startswith(abs_root_dir):
|
|
71
71
|
rel_file_path = os.path.relpath(abs_file_path, abs_root_dir)
|
|
72
72
|
else:
|
|
73
73
|
rel_file_path = file_path
|
|
74
|
-
|
|
74
|
+
|
|
75
75
|
# 获取文件扩展名和文件名
|
|
76
76
|
file_ext = pathlib.Path(file_path).suffix
|
|
77
77
|
file_name = os.path.basename(file_path)
|
|
78
|
-
|
|
78
|
+
|
|
79
79
|
# 创建agent的system prompt
|
|
80
80
|
system_prompt = self._create_system_prompt(
|
|
81
81
|
rel_file_path, file_name, file_ext, root_dir, objective
|
|
82
82
|
)
|
|
83
|
-
|
|
83
|
+
|
|
84
84
|
# 创建agent的summary prompt
|
|
85
85
|
summary_prompt = self._create_summary_prompt(rel_file_path, file_name)
|
|
86
|
-
|
|
86
|
+
|
|
87
87
|
# 切换到根目录
|
|
88
88
|
os.chdir(root_dir)
|
|
89
|
-
|
|
89
|
+
|
|
90
90
|
# 检查文件是否存在
|
|
91
91
|
if not os.path.isfile(rel_file_path):
|
|
92
92
|
return {
|
|
@@ -94,44 +94,40 @@ class FileAnalyzerTool:
|
|
|
94
94
|
"stdout": "",
|
|
95
95
|
"stderr": f"文件不存在: {rel_file_path}"
|
|
96
96
|
}
|
|
97
|
-
|
|
97
|
+
|
|
98
98
|
# 构建使用的工具
|
|
99
99
|
from jarvis.jarvis_tools.registry import ToolRegistry
|
|
100
100
|
tool_registry = ToolRegistry()
|
|
101
101
|
tool_registry.use_tools([
|
|
102
|
-
"execute_shell",
|
|
103
|
-
"read_code",
|
|
102
|
+
"execute_shell",
|
|
103
|
+
"read_code",
|
|
104
104
|
"find_symbol",
|
|
105
|
-
"function_analyzer",
|
|
105
|
+
"function_analyzer",
|
|
106
106
|
"find_caller"
|
|
107
107
|
])
|
|
108
|
-
|
|
108
|
+
|
|
109
109
|
# 创建并运行agent
|
|
110
110
|
analyzer_agent = Agent(
|
|
111
111
|
system_prompt=system_prompt,
|
|
112
112
|
name=f"FileAnalyzer-{file_name}",
|
|
113
113
|
description=f"分析 {file_name} 文件的结构和实现",
|
|
114
114
|
summary_prompt=summary_prompt,
|
|
115
|
-
platform=PlatformRegistry().
|
|
115
|
+
platform=PlatformRegistry().get_normal_platform(),
|
|
116
116
|
output_handler=[tool_registry],
|
|
117
|
-
need_summary=True,
|
|
118
|
-
is_sub_agent=True,
|
|
119
|
-
use_methodology=False,
|
|
120
|
-
record_methodology=False,
|
|
121
117
|
execute_tool_confirm=False,
|
|
122
118
|
auto_complete=True
|
|
123
119
|
)
|
|
124
|
-
|
|
120
|
+
|
|
125
121
|
# 运行agent并获取结果
|
|
126
122
|
task_input = f"深入分析文件 {rel_file_path} 的结构、实现细节和代码质量"
|
|
127
123
|
result = analyzer_agent.run(task_input)
|
|
128
|
-
|
|
124
|
+
|
|
129
125
|
return {
|
|
130
126
|
"success": True,
|
|
131
127
|
"stdout": result,
|
|
132
128
|
"stderr": ""
|
|
133
129
|
}
|
|
134
|
-
|
|
130
|
+
|
|
135
131
|
except Exception as e:
|
|
136
132
|
PrettyOutput.print(str(e), OutputType.ERROR)
|
|
137
133
|
return {
|
|
@@ -142,117 +138,132 @@ class FileAnalyzerTool:
|
|
|
142
138
|
finally:
|
|
143
139
|
# 恢复原始目录
|
|
144
140
|
os.chdir(original_dir)
|
|
145
|
-
|
|
141
|
+
|
|
146
142
|
def _create_system_prompt(self, file_path: str, file_name: str, file_ext: str,
|
|
147
143
|
root_dir: str, objective: str) -> str:
|
|
148
144
|
"""
|
|
149
145
|
创建Agent的system prompt
|
|
150
|
-
|
|
146
|
+
|
|
151
147
|
Args:
|
|
152
|
-
file_path:
|
|
148
|
+
file_path: 文件路径
|
|
153
149
|
file_name: 文件名
|
|
154
150
|
file_ext: 文件扩展名
|
|
155
|
-
root_dir:
|
|
151
|
+
root_dir: 代码库根目录
|
|
156
152
|
objective: 分析目标
|
|
157
|
-
|
|
153
|
+
|
|
158
154
|
Returns:
|
|
159
155
|
系统提示文本
|
|
160
156
|
"""
|
|
161
|
-
# 根据文件扩展名确定语言
|
|
162
|
-
language_map = {
|
|
163
|
-
'.py': 'Python',
|
|
164
|
-
'.js': 'JavaScript',
|
|
165
|
-
'.ts': 'TypeScript',
|
|
166
|
-
'.java': 'Java',
|
|
167
|
-
'.c': 'C',
|
|
168
|
-
'.cpp': 'C++',
|
|
169
|
-
'.cs': 'C#',
|
|
170
|
-
'.go': 'Go',
|
|
171
|
-
'.rs': 'Rust',
|
|
172
|
-
'.php': 'PHP',
|
|
173
|
-
'.rb': 'Ruby',
|
|
174
|
-
'.swift': 'Swift',
|
|
175
|
-
'.kt': 'Kotlin',
|
|
176
|
-
'.sh': 'Shell',
|
|
177
|
-
'.html': 'HTML',
|
|
178
|
-
'.css': 'CSS',
|
|
179
|
-
'.scss': 'SCSS',
|
|
180
|
-
'.json': 'JSON',
|
|
181
|
-
'.xml': 'XML',
|
|
182
|
-
'.yaml': 'YAML',
|
|
183
|
-
'.md': 'Markdown'
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
language = language_map.get(file_ext, '未知')
|
|
187
157
|
objective_text = f"\n\n## 分析目标\n{objective}" if objective else ""
|
|
188
|
-
|
|
189
|
-
return f"""#
|
|
158
|
+
|
|
159
|
+
return f"""# 文件分析专家
|
|
190
160
|
|
|
191
161
|
## 任务描述
|
|
192
|
-
分析文件 `{file_path}`
|
|
162
|
+
分析文件 `{file_path}` 的结构、实现细节和代码质量,专注于分析目标所需的内容,生成有针对性、深入且有洞察力的文件分析报告。{objective_text}
|
|
163
|
+
|
|
164
|
+
## 工具使用优先级
|
|
165
|
+
1. **优先使用 read_code**: 直接读取文件内容是分析文件的首选方式
|
|
166
|
+
2. **优先使用 execute_shell**:
|
|
167
|
+
- 使用 rg 搜索文件内容: `rg "pattern" {file_path}`
|
|
168
|
+
- 使用 loc 统计代码: `loc {file_path}`
|
|
169
|
+
3. **仅在必要时使用其他分析工具**
|
|
193
170
|
|
|
194
171
|
## 文件信息
|
|
195
172
|
- 文件路径: `{file_path}`
|
|
196
|
-
-
|
|
173
|
+
- 文件名称: `{file_name}`
|
|
174
|
+
- 文件类型: `{file_ext}`
|
|
197
175
|
- 项目根目录: `{root_dir}`
|
|
198
176
|
|
|
199
177
|
## 分析策略
|
|
200
|
-
1.
|
|
201
|
-
2.
|
|
202
|
-
3.
|
|
203
|
-
4.
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
178
|
+
1. 首先使用read_code直接读取整个文件内容或分段读取
|
|
179
|
+
2. 使用rg命令搜索文件中的特定模式和结构
|
|
180
|
+
3. 使用loc命令获取文件统计信息
|
|
181
|
+
4. 根据文件类型和分析目标确定重点关注的方面
|
|
182
|
+
5. 保证分析的完整性,收集充分的信息后再得出结论
|
|
183
|
+
|
|
184
|
+
## 分析步骤
|
|
185
|
+
以下步骤应根据具体分析目标灵活应用:
|
|
186
|
+
|
|
187
|
+
1. **文件基本信息分析**:
|
|
188
|
+
- 使用 `loc {file_path}` 获取代码统计
|
|
189
|
+
- 使用 read_code 读取文件头部注释和文档
|
|
190
|
+
- 确定文件的编程语言和主要功能
|
|
191
|
+
|
|
192
|
+
2. **结构分析**:
|
|
193
|
+
- 使用 read_code 阅读完整文件
|
|
194
|
+
- 对于大文件,可分段读取主要部分
|
|
195
|
+
- 识别文件的主要组成部分:
|
|
196
|
+
- 类定义: `rg "class\\s+" {file_path}`
|
|
197
|
+
- 函数定义: `rg "def\\s+|function\\s+" {file_path}`
|
|
198
|
+
- 重要变量: `rg "const\\s+|var\\s+|let\\s+" {file_path}`
|
|
199
|
+
|
|
200
|
+
3. **核心组件分析**:
|
|
201
|
+
- 识别文件中的关键接口、类和函数
|
|
202
|
+
- 使用 rg 搜索重要的代码模式
|
|
203
|
+
- 分析组件间的交互和依赖关系
|
|
204
|
+
|
|
205
|
+
4. **实现细节分析**:
|
|
206
|
+
- 读取并分析关键函数的实现
|
|
207
|
+
- 关注异常处理: `rg "try|catch|except" {file_path}`
|
|
208
|
+
- 检查资源管理: `rg "open|close|with" {file_path}`
|
|
209
|
+
|
|
210
|
+
5. **引用分析**:
|
|
211
|
+
- 找出引用的外部依赖: `rg "import|require|include" {file_path}`
|
|
212
|
+
- 分析与其他模块的交互
|
|
213
|
+
|
|
214
|
+
## 分析工具使用指南
|
|
215
|
+
|
|
216
|
+
### read_code
|
|
217
|
+
- **首选工具**: 用于读取和分析文件内容
|
|
218
|
+
- **用法指南**:
|
|
219
|
+
- 读取整个文件: 直接指定文件路径
|
|
220
|
+
- 读取部分内容: 指定文件路径和行范围
|
|
221
|
+
- 读取头部或关键部分: 根据目的选择合适的行范围
|
|
222
|
+
|
|
223
|
+
### execute_shell
|
|
224
|
+
- **用途**: 执行辅助命令进行分析
|
|
225
|
+
- **推荐命令**:
|
|
226
|
+
- `rg "pattern" {file_path}`: 在文件中搜索模式
|
|
227
|
+
- `loc {file_path}`: 获取文件代码统计
|
|
228
|
+
- `rg -n "class|def|function" {file_path}`: 查找结构元素
|
|
229
|
+
|
|
230
|
+
### 其他专业工具
|
|
231
|
+
- **使用时机**: 仅当read_code和execute_shell不足以完成分析时
|
|
232
|
+
- **使用前提**: 必须先尝试使用基本工具解决问题
|
|
233
|
+
- **选择原则**: 根据实际需要选择最简洁有效的工具
|
|
234
|
+
|
|
235
|
+
## 分析框架适应
|
|
236
|
+
根据文件类型和编程范式调整分析重点:
|
|
237
|
+
|
|
238
|
+
### 不同编程范式
|
|
239
|
+
- 面向对象: 类层次、继承、封装、接口实现
|
|
240
|
+
- 函数式: 函数组合、不可变性、纯函数
|
|
241
|
+
- 过程式: 流程控制、状态管理、数据处理
|
|
242
|
+
- 声明式: 规则定义、约束表达、模式匹配
|
|
243
|
+
|
|
244
|
+
### 不同文件类型
|
|
245
|
+
- 源代码文件: 实现逻辑、算法、接口设计
|
|
246
|
+
- 配置文件: 参数设置、环境变量、系统选项
|
|
247
|
+
- 模板文件: 渲染逻辑、变量占位符、条件分支
|
|
248
|
+
- 数据文件: 结构组织、关系定义、索引设计
|
|
239
249
|
|
|
240
250
|
## 输出要求
|
|
241
251
|
- 直接回应分析目标的关键问题
|
|
242
252
|
- 提供与目标相关的深入洞察
|
|
243
253
|
- 分析内容应直接服务于分析目标
|
|
244
254
|
- 避免与目标无关的冗余信息
|
|
245
|
-
-
|
|
246
|
-
-
|
|
255
|
+
- 使用具体代码片段支持分析结论
|
|
256
|
+
- 提供针对分析目标的具体建议
|
|
257
|
+
- 保证全面分析相关信息后再得出结论"""
|
|
247
258
|
|
|
248
259
|
def _create_summary_prompt(self, file_path: str, file_name: str) -> str:
|
|
249
260
|
"""
|
|
250
261
|
创建Agent的summary prompt
|
|
251
|
-
|
|
262
|
+
|
|
252
263
|
Args:
|
|
253
264
|
file_path: 文件路径
|
|
254
265
|
file_name: 文件名
|
|
255
|
-
|
|
266
|
+
|
|
256
267
|
Returns:
|
|
257
268
|
总结提示文本
|
|
258
269
|
"""
|
|
@@ -268,4 +279,4 @@ class FileAnalyzerTool:
|
|
|
268
279
|
- 使用具体的代码片段和实例支持你的观点
|
|
269
280
|
- 以清晰的Markdown格式呈现,简洁明了
|
|
270
281
|
|
|
271
|
-
在分析中保持灵活性,避免固定思维模式。你的任务不是提供全面的文件概览,而是直接解决分析目标中提出的具体问题。"""
|
|
282
|
+
在分析中保持灵活性,避免固定思维模式。你的任务不是提供全面的文件概览,而是直接解决分析目标中提出的具体问题。"""
|
|
@@ -3,6 +3,7 @@ import os
|
|
|
3
3
|
|
|
4
4
|
from yaspin import yaspin
|
|
5
5
|
|
|
6
|
+
from jarvis.jarvis_utils.globals import add_read_file_record
|
|
6
7
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
7
8
|
|
|
8
9
|
|
|
@@ -34,11 +35,12 @@ class FileOperationTool:
|
|
|
34
35
|
"required": ["operation", "files"]
|
|
35
36
|
}
|
|
36
37
|
|
|
37
|
-
def _handle_single_file(self, operation: str, filepath: str, content: str = "",
|
|
38
|
+
def _handle_single_file(self, operation: str, filepath: str, content: str = "",
|
|
38
39
|
start_line: int = 1, end_line: int = -1) -> Dict[str, Any]:
|
|
39
40
|
"""Handle operations for a single file"""
|
|
40
41
|
try:
|
|
41
42
|
abs_path = os.path.abspath(filepath)
|
|
43
|
+
add_read_file_record(abs_path)
|
|
42
44
|
if operation == "read":
|
|
43
45
|
with yaspin(text=f"正在读取文件: {abs_path}...", color="cyan") as spinner:
|
|
44
46
|
if not os.path.exists(abs_path):
|
|
@@ -47,18 +49,18 @@ class FileOperationTool:
|
|
|
47
49
|
"stdout": "",
|
|
48
50
|
"stderr": f"文件不存在: {abs_path}"
|
|
49
51
|
}
|
|
50
|
-
|
|
52
|
+
|
|
51
53
|
if os.path.getsize(abs_path) > 10 * 1024 * 1024: # 10MB
|
|
52
54
|
return {
|
|
53
55
|
"success": False,
|
|
54
56
|
"stdout": "",
|
|
55
57
|
"stderr": "File too large (>10MB)"
|
|
56
58
|
}
|
|
57
|
-
|
|
59
|
+
|
|
58
60
|
with open(abs_path, 'r', encoding='utf-8', errors="ignore") as f:
|
|
59
61
|
lines = f.readlines()
|
|
60
|
-
|
|
61
|
-
|
|
62
|
+
|
|
63
|
+
|
|
62
64
|
total_lines = len(lines)
|
|
63
65
|
start_line = start_line if start_line >= 0 else total_lines + start_line + 1
|
|
64
66
|
end_line = end_line if end_line >= 0 else total_lines + end_line + 1
|
|
@@ -66,7 +68,7 @@ class FileOperationTool:
|
|
|
66
68
|
end_line = max(1, min(end_line, total_lines))
|
|
67
69
|
if end_line == -1:
|
|
68
70
|
end_line = total_lines
|
|
69
|
-
|
|
71
|
+
|
|
70
72
|
if start_line > end_line:
|
|
71
73
|
spinner.text = "无效的行范围"
|
|
72
74
|
spinner.fail("❌")
|
|
@@ -76,10 +78,10 @@ class FileOperationTool:
|
|
|
76
78
|
"stdout": "",
|
|
77
79
|
"stderr": error_msg
|
|
78
80
|
}
|
|
79
|
-
|
|
81
|
+
|
|
80
82
|
content = "".join(lines[start_line - 1:end_line])
|
|
81
|
-
output = f"\n文件: {abs_path}\n行: [{start_line}-{end_line}]\n{content}" + "\n\n"
|
|
82
|
-
|
|
83
|
+
output = f"\n文件: {abs_path}\n行: [{start_line}-{end_line}]\n{content}" + "\n\n"
|
|
84
|
+
|
|
83
85
|
spinner.text = f"文件读取完成: {abs_path}"
|
|
84
86
|
spinner.ok("✅")
|
|
85
87
|
return {
|
|
@@ -104,7 +106,7 @@ class FileOperationTool:
|
|
|
104
106
|
"stdout": "",
|
|
105
107
|
"stderr": f"Unknown operation: {operation}"
|
|
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 FileOperationTool:
|
|
|
115
117
|
|
|
116
118
|
def execute(self, args: Dict) -> Dict[str, Any]:
|
|
117
119
|
"""Execute file operations for multiple files
|
|
118
|
-
|
|
120
|
+
|
|
119
121
|
Args:
|
|
120
122
|
args: Dictionary containing operation and files list
|
|
121
|
-
|
|
123
|
+
|
|
122
124
|
Returns:
|
|
123
125
|
Dict containing:
|
|
124
126
|
- success: Boolean indicating overall success
|
|
@@ -127,21 +129,21 @@ class FileOperationTool:
|
|
|
127
129
|
"""
|
|
128
130
|
try:
|
|
129
131
|
operation = args["operation"].strip()
|
|
130
|
-
|
|
132
|
+
|
|
131
133
|
if "files" not in args or not isinstance(args["files"], list):
|
|
132
134
|
return {
|
|
133
135
|
"success": False,
|
|
134
136
|
"stdout": "",
|
|
135
137
|
"stderr": "files parameter is required and must be a list"
|
|
136
138
|
}
|
|
137
|
-
|
|
139
|
+
|
|
138
140
|
all_outputs = []
|
|
139
141
|
success = True
|
|
140
|
-
|
|
142
|
+
|
|
141
143
|
for file_info in args["files"]:
|
|
142
144
|
if not isinstance(file_info, dict) or "path" not in file_info:
|
|
143
145
|
continue
|
|
144
|
-
|
|
146
|
+
|
|
145
147
|
content = file_info.get("content", "") if operation == "write" else ""
|
|
146
148
|
result = self._handle_single_file(
|
|
147
149
|
operation,
|
|
@@ -150,22 +152,22 @@ class FileOperationTool:
|
|
|
150
152
|
file_info.get("start_line", 1),
|
|
151
153
|
file_info.get("end_line", -1)
|
|
152
154
|
)
|
|
153
|
-
|
|
155
|
+
|
|
154
156
|
if result["success"]:
|
|
155
157
|
all_outputs.append(result["stdout"])
|
|
156
158
|
else:
|
|
157
159
|
all_outputs.append(f"Error with {file_info['path']}: {result['stderr']}")
|
|
158
160
|
success = success and result["success"]
|
|
159
|
-
|
|
161
|
+
|
|
160
162
|
# Combine all outputs with separators
|
|
161
163
|
combined_output = "\n\n" + "="*80 + "\n\n".join(all_outputs)
|
|
162
|
-
|
|
164
|
+
|
|
163
165
|
return {
|
|
164
166
|
"success": success,
|
|
165
167
|
"stdout": combined_output,
|
|
166
168
|
"stderr": ""
|
|
167
169
|
}
|
|
168
|
-
|
|
170
|
+
|
|
169
171
|
except Exception as e:
|
|
170
172
|
PrettyOutput.print(str(e), OutputType.ERROR)
|
|
171
173
|
return {
|