jarvis-ai-assistant 0.1.164__py3-none-any.whl → 0.1.165__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 +2 -1
- jarvis/jarvis_agent/__init__.py +1 -0
- jarvis/jarvis_agent/builtin_input_handler.py +1 -0
- jarvis/jarvis_agent/file_input_handler.py +1 -0
- jarvis/jarvis_agent/jarvis.py +1 -0
- jarvis/jarvis_agent/main.py +1 -0
- jarvis/jarvis_agent/output_handler.py +1 -0
- jarvis/jarvis_agent/shell_input_handler.py +1 -0
- jarvis/jarvis_code_agent/code_agent.py +5 -26
- jarvis/jarvis_code_analysis/checklists/__init__.py +1 -0
- jarvis/jarvis_code_analysis/checklists/c_cpp.py +1 -0
- jarvis/jarvis_code_analysis/checklists/csharp.py +1 -0
- jarvis/jarvis_code_analysis/checklists/data_format.py +1 -0
- jarvis/jarvis_code_analysis/checklists/devops.py +1 -0
- jarvis/jarvis_code_analysis/checklists/docs.py +1 -0
- jarvis/jarvis_code_analysis/checklists/go.py +1 -0
- jarvis/jarvis_code_analysis/checklists/infrastructure.py +1 -0
- jarvis/jarvis_code_analysis/checklists/java.py +1 -0
- jarvis/jarvis_code_analysis/checklists/javascript.py +1 -0
- jarvis/jarvis_code_analysis/checklists/kotlin.py +1 -0
- jarvis/jarvis_code_analysis/checklists/loader.py +1 -0
- jarvis/jarvis_code_analysis/checklists/php.py +1 -0
- jarvis/jarvis_code_analysis/checklists/python.py +1 -0
- jarvis/jarvis_code_analysis/checklists/ruby.py +1 -0
- jarvis/jarvis_code_analysis/checklists/rust.py +1 -0
- jarvis/jarvis_code_analysis/checklists/shell.py +1 -0
- jarvis/jarvis_code_analysis/checklists/sql.py +1 -0
- jarvis/jarvis_code_analysis/checklists/swift.py +1 -0
- jarvis/jarvis_code_analysis/checklists/web.py +1 -0
- jarvis/jarvis_code_analysis/code_review.py +1 -0
- jarvis/jarvis_data/huggingface.tar.gz +0 -0
- jarvis/jarvis_dev/main.py +1 -0
- jarvis/jarvis_git_details/main.py +1 -0
- jarvis/jarvis_git_squash/main.py +1 -0
- jarvis/jarvis_git_utils/git_commiter.py +55 -30
- jarvis/jarvis_lsp/base.py +1 -0
- jarvis/jarvis_lsp/cpp.py +1 -0
- jarvis/jarvis_lsp/go.py +1 -0
- jarvis/jarvis_lsp/python.py +1 -0
- jarvis/jarvis_lsp/registry.py +1 -0
- jarvis/jarvis_lsp/rust.py +1 -0
- jarvis/jarvis_mcp/__init__.py +1 -0
- jarvis/jarvis_mcp/sse_mcp_client.py +1 -0
- jarvis/jarvis_mcp/stdio_mcp_client.py +1 -0
- jarvis/jarvis_methodology/main.py +1 -0
- jarvis/jarvis_multi_agent/__init__.py +1 -0
- jarvis/jarvis_multi_agent/main.py +1 -0
- jarvis/jarvis_platform/__init__.py +1 -0
- jarvis/jarvis_platform/base.py +1 -0
- jarvis/jarvis_platform/human.py +1 -0
- jarvis/jarvis_platform/kimi.py +1 -0
- jarvis/jarvis_platform/openai.py +117 -0
- jarvis/jarvis_platform/registry.py +1 -0
- jarvis/jarvis_platform/yuanbao.py +2 -1
- jarvis/jarvis_platform_manager/main.py +1 -0
- jarvis/jarvis_smart_shell/main.py +1 -0
- jarvis/jarvis_tools/ask_codebase.py +1 -0
- jarvis/jarvis_tools/ask_user.py +1 -0
- jarvis/jarvis_tools/base.py +1 -0
- jarvis/jarvis_tools/chdir.py +1 -0
- jarvis/jarvis_tools/code_plan.py +1 -0
- jarvis/jarvis_tools/create_code_agent.py +1 -0
- jarvis/jarvis_tools/create_sub_agent.py +1 -0
- jarvis/jarvis_tools/edit_file.py +202 -130
- jarvis/jarvis_tools/execute_script.py +1 -0
- jarvis/jarvis_tools/file_analyzer.py +1 -0
- jarvis/jarvis_tools/file_operation.py +1 -0
- jarvis/jarvis_tools/find_methodology.py +1 -0
- jarvis/jarvis_tools/lsp_get_diagnostics.py +1 -0
- jarvis/jarvis_tools/methodology.py +1 -0
- jarvis/jarvis_tools/read_code.py +1 -0
- jarvis/jarvis_tools/read_webpage.py +1 -0
- jarvis/jarvis_tools/registry.py +1 -0
- jarvis/jarvis_tools/rewrite_file.py +1 -0
- jarvis/jarvis_tools/search_web.py +1 -0
- jarvis/jarvis_tools/virtual_tty.py +1 -0
- jarvis/jarvis_utils/__init__.py +1 -0
- jarvis/jarvis_utils/builtin_replace_map.py +1 -0
- jarvis/jarvis_utils/config.py +1 -0
- jarvis/jarvis_utils/embedding.py +1 -0
- jarvis/jarvis_utils/file_processors.py +1 -0
- jarvis/jarvis_utils/git_utils.py +1 -0
- jarvis/jarvis_utils/globals.py +1 -0
- jarvis/jarvis_utils/input.py +1 -0
- jarvis/jarvis_utils/methodology.py +1 -0
- jarvis/jarvis_utils/output.py +1 -0
- jarvis/jarvis_utils/tag.py +1 -0
- jarvis/jarvis_utils/utils.py +18 -0
- {jarvis_ai_assistant-0.1.164.dist-info → jarvis_ai_assistant-0.1.165.dist-info}/METADATA +2 -1
- jarvis_ai_assistant-0.1.165.dist-info/RECORD +100 -0
- jarvis_ai_assistant-0.1.164.dist-info/RECORD +0 -98
- {jarvis_ai_assistant-0.1.164.dist-info → jarvis_ai_assistant-0.1.165.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.164.dist-info → jarvis_ai_assistant-0.1.165.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.1.164.dist-info → jarvis_ai_assistant-0.1.165.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.164.dist-info → jarvis_ai_assistant-0.1.165.dist-info}/top_level.txt +0 -0
jarvis/jarvis_tools/base.py
CHANGED
jarvis/jarvis_tools/chdir.py
CHANGED
jarvis/jarvis_tools/code_plan.py
CHANGED
jarvis/jarvis_tools/edit_file.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
1
2
|
"""
|
|
2
3
|
文件搜索替换工具类
|
|
3
4
|
|
|
@@ -13,7 +14,17 @@
|
|
|
13
14
|
- 完善的错误处理和回滚机制
|
|
14
15
|
- 严格的格式保持要求
|
|
15
16
|
"""
|
|
16
|
-
|
|
17
|
+
import re
|
|
18
|
+
from typing import Any, Dict, Tuple
|
|
19
|
+
|
|
20
|
+
import yaml
|
|
21
|
+
from yaspin import yaspin
|
|
22
|
+
|
|
23
|
+
from jarvis.jarvis_platform.registry import PlatformRegistry
|
|
24
|
+
from jarvis.jarvis_tools.file_operation import FileOperationTool
|
|
25
|
+
from jarvis.jarvis_utils.git_utils import revert_file
|
|
26
|
+
from jarvis.jarvis_utils.tag import ct, ot
|
|
27
|
+
from jarvis.jarvis_utils.utils import is_context_overflow
|
|
17
28
|
|
|
18
29
|
|
|
19
30
|
class FileSearchReplaceTool:
|
|
@@ -23,43 +34,27 @@ class FileSearchReplaceTool:
|
|
|
23
34
|
# 代码编辑规范
|
|
24
35
|
|
|
25
36
|
## 重要提示
|
|
26
|
-
|
|
37
|
+
此工具可以查看和修改单个文件的代码,只需提供要修改的代码片段即可。应尽量精简内容,只包含必要的上下文和修改部分。特别注意:不要提供完整文件内容,只提供需要修改的部分及其上下文!
|
|
27
38
|
|
|
28
39
|
## 基本使用
|
|
29
40
|
1. 指定需要修改的文件路径
|
|
30
|
-
2. 提供一组或多组"
|
|
31
|
-
3.
|
|
32
|
-
4. 创建新文件时,使用空字符串("")作为搜索文本,替换文本作为完整文件内容
|
|
33
|
-
5. 所有修改要么全部成功,要么全部失败并回滚
|
|
41
|
+
2. 提供一组或多组"reason"和"patch"对
|
|
42
|
+
3. 每个patch必须包含修改后的代码和1-2行上下文用于精确定位
|
|
34
43
|
|
|
35
44
|
## 核心原则
|
|
36
|
-
1.
|
|
45
|
+
1. **精准修改**:只提供需要修改的代码部分及其上下文,不需要展示整个文件内容
|
|
37
46
|
2. **最小补丁原则**:始终生成最小范围的补丁,只包含必要的上下文和实际修改
|
|
38
|
-
3.
|
|
39
|
-
- 严格保持原始代码的缩进方式(空格或制表符)
|
|
40
|
-
- 保持原始代码的空行数量和位置
|
|
41
|
-
- 保持原始代码的行尾空格处理方式
|
|
42
|
-
- 不改变原始代码的换行风格
|
|
43
|
-
4. **新旧区分**:
|
|
44
|
-
- 对于新文件:提供完整的代码内容
|
|
45
|
-
- 对于现有文件:只提供修改部分,不要提供整个文件
|
|
46
|
-
|
|
47
|
-
## 格式兼容性要求
|
|
48
|
-
1. **缩进一致性**:
|
|
49
|
-
- 如果原代码使用4个空格缩进,替换文本也必须使用4个空格缩进
|
|
50
|
-
- 如果原代码使用制表符缩进,替换文本也必须使用制表符
|
|
51
|
-
2. **空行保留**:
|
|
52
|
-
- 如果原代码在函数之间有两个空行,替换文本也必须保留这两个空行
|
|
53
|
-
- 如果原代码在类方法之间有一个空行,替换文本也必须保留这一个空行
|
|
54
|
-
3. **行尾处理**:
|
|
55
|
-
- 不要改变原代码的行尾空格或换行符风格
|
|
56
|
-
- 保持原有的换行符类型(CR、LF或CRLF)
|
|
47
|
+
3. **上下文定位**:确保提供的上下文能唯一标识修改位置
|
|
57
48
|
|
|
58
49
|
## 最佳实践
|
|
59
50
|
1. 每个修改应专注于单一职责,避免包含过多无关代码
|
|
60
|
-
2.
|
|
61
|
-
3.
|
|
62
|
-
|
|
51
|
+
2. 不要出现未实现的代码,如:TODO
|
|
52
|
+
3. 示例格式:
|
|
53
|
+
```
|
|
54
|
+
# 原有上下文行
|
|
55
|
+
if condition: # 修改这行
|
|
56
|
+
return new_value
|
|
57
|
+
```
|
|
63
58
|
"""
|
|
64
59
|
parameters = {
|
|
65
60
|
"type": "object",
|
|
@@ -70,20 +65,20 @@ class FileSearchReplaceTool:
|
|
|
70
65
|
},
|
|
71
66
|
"changes": {
|
|
72
67
|
"type": "array",
|
|
73
|
-
"description": "
|
|
68
|
+
"description": "一组或多组修改,每个修改必须包含1-2行上下文用于精确定位",
|
|
74
69
|
"items": {
|
|
75
70
|
"type": "object",
|
|
76
71
|
"properties": {
|
|
77
|
-
"
|
|
72
|
+
"reason": {
|
|
78
73
|
"type": "string",
|
|
79
|
-
"description": "
|
|
74
|
+
"description": "修改的原因"
|
|
80
75
|
},
|
|
81
|
-
"
|
|
82
|
-
"type": "string",
|
|
83
|
-
"description": "
|
|
76
|
+
"patch": {
|
|
77
|
+
"type": "string",
|
|
78
|
+
"description": "修改后的代码片段,必须包含1-2行上下文代码用于精确定位修改位置,不需要传入完整文件内容"
|
|
84
79
|
}
|
|
85
80
|
},
|
|
86
|
-
"required": ["
|
|
81
|
+
"required": ["reason", "patch"]
|
|
87
82
|
}
|
|
88
83
|
}
|
|
89
84
|
},
|
|
@@ -95,31 +90,31 @@ class FileSearchReplaceTool:
|
|
|
95
90
|
pass
|
|
96
91
|
|
|
97
92
|
def execute(self, args: Dict) -> Dict[str, Any]:
|
|
98
|
-
"""
|
|
99
|
-
|
|
100
|
-
|
|
93
|
+
"""执行文件编辑操作,包含错误处理和回滚机制。
|
|
94
|
+
|
|
95
|
+
主要功能:
|
|
96
|
+
1. 处理文件创建或修改
|
|
97
|
+
2. 原子操作:所有修改要么全部成功,要么全部回滚
|
|
98
|
+
3. 保存修改前后的文件状态以便回滚
|
|
99
|
+
4. 提供详细的执行状态输出
|
|
101
100
|
|
|
102
101
|
参数:
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
"replace": "替换文本1"
|
|
109
|
-
},
|
|
110
|
-
{
|
|
111
|
-
"search": "搜索文本2",
|
|
112
|
-
"replace": "替换文本2"
|
|
113
|
-
}
|
|
114
|
-
]
|
|
102
|
+
args: 包含以下键的字典:
|
|
103
|
+
- file: 要修改的文件路径
|
|
104
|
+
- changes: 修改列表,每个修改包含:
|
|
105
|
+
- reason: 修改原因描述
|
|
106
|
+
- patch: 修改后的代码片段
|
|
115
107
|
|
|
116
108
|
返回:
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
109
|
+
Dict[str, Any] 包含:
|
|
110
|
+
- success: 操作是否成功
|
|
111
|
+
- stdout: 成功时的输出消息
|
|
112
|
+
- stderr: 失败时的错误消息
|
|
113
|
+
|
|
114
|
+
异常处理:
|
|
115
|
+
1. 捕获并记录文件操作异常
|
|
116
|
+
2. 失败的修改尝试回滚到原始状态
|
|
117
|
+
3. 新创建的文件在失败时会被删除
|
|
123
118
|
"""
|
|
124
119
|
import os
|
|
125
120
|
from jarvis.jarvis_utils.output import PrettyOutput, OutputType
|
|
@@ -146,49 +141,7 @@ class FileSearchReplaceTool:
|
|
|
146
141
|
content = f.read()
|
|
147
142
|
original_content = content
|
|
148
143
|
|
|
149
|
-
|
|
150
|
-
temp_content = content
|
|
151
|
-
replaced_count = 0
|
|
152
|
-
|
|
153
|
-
# 处理所有搜索替换对
|
|
154
|
-
for change in changes:
|
|
155
|
-
search_text = change["search"]
|
|
156
|
-
replace_text = change["replace"]
|
|
157
|
-
|
|
158
|
-
# 特殊处理不存在的文件或空文件
|
|
159
|
-
if not file_exists or content == "":
|
|
160
|
-
if search_text == "":
|
|
161
|
-
# 对于不存在的文件或空文件,如果搜索文本为空,则直接使用替换文本作为内容
|
|
162
|
-
temp_content = replace_text
|
|
163
|
-
replaced_count += 1
|
|
164
|
-
# 只允许有一个空字符串搜索
|
|
165
|
-
break
|
|
166
|
-
else:
|
|
167
|
-
stderr_message = f"文件 {file_path} {'不存在' if not file_exists else '为空'},但搜索文本非空: '{search_text}'"
|
|
168
|
-
stderr_messages.append(stderr_message)
|
|
169
|
-
PrettyOutput.print(stderr_message, OutputType.WARNING)
|
|
170
|
-
success = False
|
|
171
|
-
break
|
|
172
|
-
else:
|
|
173
|
-
# 正常文件处理 - 检查匹配次数
|
|
174
|
-
match_count = temp_content.count(search_text)
|
|
175
|
-
|
|
176
|
-
if match_count == 0:
|
|
177
|
-
stderr_message = f"文件 {file_path} 中未找到匹配文本: '{search_text}'"
|
|
178
|
-
stderr_messages.append(stderr_message)
|
|
179
|
-
PrettyOutput.print(stderr_message, OutputType.WARNING)
|
|
180
|
-
success = False
|
|
181
|
-
break
|
|
182
|
-
elif match_count > 1:
|
|
183
|
-
stderr_message = f"文件 {file_path} 中匹配到多个 ({match_count}) '{search_text}',搜索文本只允许一次匹配"
|
|
184
|
-
stderr_messages.append(stderr_message)
|
|
185
|
-
PrettyOutput.print(stderr_message, OutputType.WARNING)
|
|
186
|
-
success = False
|
|
187
|
-
break
|
|
188
|
-
else:
|
|
189
|
-
# 只有一个匹配,执行替换
|
|
190
|
-
temp_content = temp_content.replace(search_text, replace_text, 1)
|
|
191
|
-
replaced_count += 1
|
|
144
|
+
success, temp_content = slow_edit(file_path, yaml.safe_dump(changes))
|
|
192
145
|
|
|
193
146
|
# 只有当所有替换操作都成功时,才写回文件
|
|
194
147
|
if success and (temp_content != original_content or not file_exists):
|
|
@@ -200,14 +153,17 @@ class FileSearchReplaceTool:
|
|
|
200
153
|
|
|
201
154
|
processed = True
|
|
202
155
|
|
|
203
|
-
action = "创建并写入" if not file_exists else "
|
|
204
|
-
stdout_message = f"文件 {file_path} {action}
|
|
156
|
+
action = "创建并写入" if not file_exists else "成功修改"
|
|
157
|
+
stdout_message = f"文件 {file_path} {action} 完成"
|
|
205
158
|
stdout_messages.append(stdout_message)
|
|
206
159
|
PrettyOutput.print(stdout_message, OutputType.SUCCESS)
|
|
207
160
|
elif success:
|
|
208
161
|
stdout_message = f"文件 {file_path} 没有找到需要替换的内容"
|
|
209
162
|
stdout_messages.append(stdout_message)
|
|
210
163
|
PrettyOutput.print(stdout_message, OutputType.INFO)
|
|
164
|
+
else:
|
|
165
|
+
stdout_message = f"文件 {file_path} 修改失败"
|
|
166
|
+
stdout_messages.append(stdout_message)
|
|
211
167
|
|
|
212
168
|
except Exception as e:
|
|
213
169
|
stderr_message = f"处理文件 {file_path} 时出错: {str(e)}"
|
|
@@ -215,35 +171,10 @@ class FileSearchReplaceTool:
|
|
|
215
171
|
PrettyOutput.print(stderr_message, OutputType.WARNING)
|
|
216
172
|
success = False
|
|
217
173
|
|
|
218
|
-
# 如果操作失败,回滚已修改的文件
|
|
219
|
-
if not success and processed:
|
|
220
|
-
rollback_message = "操作失败,正在回滚修改..."
|
|
221
|
-
stderr_messages.append(rollback_message)
|
|
222
|
-
PrettyOutput.print(rollback_message, OutputType.WARNING)
|
|
223
|
-
|
|
224
|
-
try:
|
|
225
|
-
if original_content is None:
|
|
226
|
-
# 如果是新创建的文件,则删除
|
|
227
|
-
if os.path.exists(file_path):
|
|
228
|
-
os.remove(file_path)
|
|
229
|
-
rollback_file_message = f"已删除新创建的文件: {file_path}"
|
|
230
|
-
else:
|
|
231
|
-
# 如果是修改的文件,则恢复原内容
|
|
232
|
-
with open(file_path, 'w', encoding='utf-8') as f:
|
|
233
|
-
f.write(original_content)
|
|
234
|
-
rollback_file_message = f"已回滚文件: {file_path}"
|
|
235
|
-
|
|
236
|
-
stderr_messages.append(rollback_file_message)
|
|
237
|
-
PrettyOutput.print(rollback_file_message, OutputType.INFO)
|
|
238
|
-
except Exception as e:
|
|
239
|
-
rollback_error = f"回滚文件 {file_path} 失败: {str(e)}"
|
|
240
|
-
stderr_messages.append(rollback_error)
|
|
241
|
-
PrettyOutput.print(rollback_error, OutputType.WARNING)
|
|
242
|
-
|
|
243
174
|
return {
|
|
244
175
|
"success": success,
|
|
245
|
-
"stdout": "\n".join(stdout_messages),
|
|
246
|
-
"stderr": "\n".join(stderr_messages)
|
|
176
|
+
"stdout": "\n".join(stdout_messages) if success else "",
|
|
177
|
+
"stderr": "\n".join(stderr_messages) if not success else ""
|
|
247
178
|
}
|
|
248
179
|
|
|
249
180
|
except Exception as e:
|
|
@@ -276,4 +207,145 @@ class FileSearchReplaceTool:
|
|
|
276
207
|
"stderr": error_msg + "\n" + "\n".join(stderr_messages)
|
|
277
208
|
}
|
|
278
209
|
|
|
279
|
-
|
|
210
|
+
|
|
211
|
+
def slow_edit(filepath: str, patch_content: str) -> Tuple[bool, str]:
|
|
212
|
+
"""执行精确的文件编辑操作,使用AI模型生成差异补丁并应用。
|
|
213
|
+
|
|
214
|
+
功能概述:
|
|
215
|
+
1. 使用AI模型分析补丁内容并生成精确的代码差异
|
|
216
|
+
2. 应用生成的差异补丁到目标文件
|
|
217
|
+
3. 提供重试机制确保操作可靠性
|
|
218
|
+
|
|
219
|
+
参数:
|
|
220
|
+
filepath: 要编辑的文件路径
|
|
221
|
+
patch_content: YAML格式的补丁内容,包含修改原因和代码片段
|
|
222
|
+
|
|
223
|
+
返回值:
|
|
224
|
+
Tuple[bool, str]:
|
|
225
|
+
- 第一个元素表示操作是否成功
|
|
226
|
+
- 第二个元素是修改后的文件内容(成功时)或错误信息(失败时)
|
|
227
|
+
|
|
228
|
+
异常处理:
|
|
229
|
+
1. 捕获并处理文件操作异常
|
|
230
|
+
2. 失败时自动回滚文件修改
|
|
231
|
+
3. 提供详细的执行状态输出
|
|
232
|
+
"""
|
|
233
|
+
model = PlatformRegistry().get_normal_platform()
|
|
234
|
+
with yaspin(text=f"正在处理文件 {filepath}...", color="cyan") as spinner:
|
|
235
|
+
try:
|
|
236
|
+
file_content = FileOperationTool().execute({"operation":"read", "files":[{"path":filepath}]})["stdout"]
|
|
237
|
+
need_upload_file = is_context_overflow(file_content)
|
|
238
|
+
upload_success = False
|
|
239
|
+
# 读取原始文件内容
|
|
240
|
+
with spinner.hidden():
|
|
241
|
+
if need_upload_file and model.upload_files([filepath]):
|
|
242
|
+
upload_success = True
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
model.set_suppress_output(True)
|
|
246
|
+
|
|
247
|
+
main_prompt = f"""
|
|
248
|
+
# 代码补丁生成专家指南
|
|
249
|
+
|
|
250
|
+
## 任务描述
|
|
251
|
+
你是一位精确的代码补丁生成专家,需要根据补丁描述生成精确的代码差异。
|
|
252
|
+
|
|
253
|
+
### 补丁内容
|
|
254
|
+
```
|
|
255
|
+
{patch_content}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## 补丁生成要求
|
|
259
|
+
1. **精确性**:严格按照补丁的意图修改代码
|
|
260
|
+
2. **格式一致性**:严格保持原始代码的格式风格,如果补丁中缩进或者空行与原代码不一致,则需要修正补丁中的缩进或者空行
|
|
261
|
+
3. **最小化修改**:只修改必要的代码部分,保持其他部分不变
|
|
262
|
+
4. **上下文完整性**:提供足够的上下文,确保补丁能准确应用
|
|
263
|
+
|
|
264
|
+
## 输出格式规范
|
|
265
|
+
- 使用{ot("DIFF")}块包围每个需要修改的代码段
|
|
266
|
+
- 每个{ot("DIFF")}块必须包含SEARCH部分和REPLACE部分
|
|
267
|
+
- SEARCH部分是需要查找的原始代码
|
|
268
|
+
- REPLACE部分是替换后的新代码
|
|
269
|
+
- 确保SEARCH部分能在原文件中**唯一匹配**
|
|
270
|
+
- 如果修改较大,可以使用多个{ot("DIFF")}块
|
|
271
|
+
|
|
272
|
+
## 输出模板
|
|
273
|
+
{ot("DIFF")}
|
|
274
|
+
{">" * 5} SEARCH
|
|
275
|
+
[需要查找的原始代码,包含足够上下文,避免出现可匹配多处的情况]
|
|
276
|
+
{'='*5}
|
|
277
|
+
[替换后的新代码]
|
|
278
|
+
{"<" * 5} REPLACE
|
|
279
|
+
{ct("DIFF")}
|
|
280
|
+
|
|
281
|
+
{ot("DIFF")}
|
|
282
|
+
{">" * 5} SEARCH
|
|
283
|
+
[另一处需要查找的原始代码,包含足够上下文,避免出现可匹配多处的情况]
|
|
284
|
+
{'='*5}
|
|
285
|
+
[另一处替换后的新代码]
|
|
286
|
+
{"<" * 5} REPLACE
|
|
287
|
+
{ct("DIFF")}
|
|
288
|
+
"""
|
|
289
|
+
|
|
290
|
+
for _ in range(3):
|
|
291
|
+
file_prompt = ""
|
|
292
|
+
if not need_upload_file:
|
|
293
|
+
file_prompt = f"""
|
|
294
|
+
# 原始代码
|
|
295
|
+
{file_content}
|
|
296
|
+
"""
|
|
297
|
+
|
|
298
|
+
response = model.chat_until_success(main_prompt + file_prompt)
|
|
299
|
+
else:
|
|
300
|
+
if upload_success:
|
|
301
|
+
response = model.chat_until_success(main_prompt)
|
|
302
|
+
else:
|
|
303
|
+
response = model.chat_big_content(file_content, main_prompt)
|
|
304
|
+
|
|
305
|
+
# 解析差异化补丁
|
|
306
|
+
diff_blocks = re.finditer(ot("DIFF")+r'\s*>{4,} SEARCH\n?(.*?)\n?={4,}\n?(.*?)\s*<{4,} REPLACE\n?'+ct("DIFF"),
|
|
307
|
+
response, re.DOTALL)
|
|
308
|
+
|
|
309
|
+
# 读取原始文件内容
|
|
310
|
+
with open(filepath, 'r', encoding='utf-8', errors="ignore") as f:
|
|
311
|
+
file_content = f.read()
|
|
312
|
+
|
|
313
|
+
# 应用所有差异化补丁
|
|
314
|
+
modified_content = file_content
|
|
315
|
+
patch_count = 0
|
|
316
|
+
success = True
|
|
317
|
+
for match in diff_blocks:
|
|
318
|
+
search_text = match.group(1).strip()
|
|
319
|
+
replace_text = match.group(2).strip()
|
|
320
|
+
patch_count += 1
|
|
321
|
+
# 检查搜索文本是否存在于文件中
|
|
322
|
+
if search_text in modified_content:
|
|
323
|
+
# 如果有多处,报错
|
|
324
|
+
if modified_content.count(search_text) > 1:
|
|
325
|
+
spinner.write(f"❌ 补丁 #{patch_count} 应用失败:找到多个匹配的代码段")
|
|
326
|
+
success = False
|
|
327
|
+
break
|
|
328
|
+
# 应用替换
|
|
329
|
+
modified_content = modified_content.replace(
|
|
330
|
+
search_text, replace_text)
|
|
331
|
+
spinner.write(f"✅ 补丁 #{patch_count} 应用成功")
|
|
332
|
+
else:
|
|
333
|
+
spinner.write(f"❌ 补丁 #{patch_count} 应用失败:无法找到匹配的代码段")
|
|
334
|
+
success = False
|
|
335
|
+
break
|
|
336
|
+
if not success:
|
|
337
|
+
revert_file(filepath)
|
|
338
|
+
continue
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
spinner.text = f"文件 {filepath} 修改完成,应用了 {patch_count} 个补丁"
|
|
342
|
+
spinner.ok("✅")
|
|
343
|
+
return True, modified_content
|
|
344
|
+
spinner.text = f"文件 {filepath} 修改失败"
|
|
345
|
+
spinner.fail("❌")
|
|
346
|
+
return False, ""
|
|
347
|
+
|
|
348
|
+
except Exception as e:
|
|
349
|
+
spinner.text = f"文件修改失败: {str(e)}"
|
|
350
|
+
spinner.fail("❌")
|
|
351
|
+
return False, ""
|
jarvis/jarvis_tools/read_code.py
CHANGED
jarvis/jarvis_tools/registry.py
CHANGED
jarvis/jarvis_utils/__init__.py
CHANGED
jarvis/jarvis_utils/config.py
CHANGED
jarvis/jarvis_utils/embedding.py
CHANGED
jarvis/jarvis_utils/git_utils.py
CHANGED
jarvis/jarvis_utils/globals.py
CHANGED
jarvis/jarvis_utils/input.py
CHANGED
jarvis/jarvis_utils/output.py
CHANGED
jarvis/jarvis_utils/tag.py
CHANGED
jarvis/jarvis_utils/utils.py
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
from doctest import script_from_examples
|
|
1
3
|
import os
|
|
2
4
|
import time
|
|
3
5
|
import hashlib
|
|
6
|
+
import tarfile
|
|
4
7
|
from pathlib import Path
|
|
5
8
|
from typing import List, Any, Callable
|
|
6
9
|
from jarvis.jarvis_utils.config import INPUT_WINDOW_REVERSE_SIZE, get_max_input_token_count, get_data_dir
|
|
@@ -18,9 +21,24 @@ def init_env() -> None:
|
|
|
18
21
|
jarvis_dir = Path(get_data_dir())
|
|
19
22
|
env_file = jarvis_dir / "env"
|
|
20
23
|
|
|
24
|
+
script_dir = Path(os.path.dirname(os.path.dirname(__file__)))
|
|
25
|
+
hf_archive = script_dir / "jarvis_data" / "huggingface.tar.gz"
|
|
26
|
+
|
|
21
27
|
# 检查jarvis_data目录是否存在
|
|
22
28
|
if not jarvis_dir.exists():
|
|
23
29
|
jarvis_dir.mkdir(parents=True)
|
|
30
|
+
|
|
31
|
+
# 检查并解压huggingface模型
|
|
32
|
+
hf_dir = jarvis_dir / "huggingface" / "hub"
|
|
33
|
+
if not hf_dir.exists() and hf_archive.exists():
|
|
34
|
+
try:
|
|
35
|
+
PrettyOutput.print("正在解压HuggingFace模型...", OutputType.INFO)
|
|
36
|
+
with tarfile.open(hf_archive, "r:gz") as tar:
|
|
37
|
+
tar.extractall(path=jarvis_dir)
|
|
38
|
+
PrettyOutput.print("HuggingFace模型解压完成", OutputType.SUCCESS)
|
|
39
|
+
except Exception as e:
|
|
40
|
+
PrettyOutput.print(f"解压HuggingFace模型失败: {e}", OutputType.ERROR)
|
|
41
|
+
|
|
24
42
|
if env_file.exists():
|
|
25
43
|
try:
|
|
26
44
|
with open(env_file, "r", encoding="utf-8", errors="ignore") as f:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: jarvis-ai-assistant
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.165
|
|
4
4
|
Summary: Jarvis: An AI assistant that uses tools to interact with the system
|
|
5
5
|
Home-page: https://github.com/skyfireitdiy/Jarvis
|
|
6
6
|
Author: skyfire
|
|
@@ -55,6 +55,7 @@ Requires-Dist: torch==2.4.1
|
|
|
55
55
|
Requires-Dist: python-Levenshtein==0.25.1
|
|
56
56
|
Requires-Dist: sseclient==0.0.27
|
|
57
57
|
Requires-Dist: pillow==10.2.0
|
|
58
|
+
Requires-Dist: openai==1.78.1
|
|
58
59
|
Provides-Extra: dev
|
|
59
60
|
Requires-Dist: pytest; extra == "dev"
|
|
60
61
|
Requires-Dist: black; extra == "dev"
|