jarvis-ai-assistant 0.1.125__py3-none-any.whl → 0.1.128__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 +205 -187
- jarvis/jarvis_code_agent/code_agent.py +116 -109
- jarvis/jarvis_code_agent/patch.py +157 -138
- jarvis/jarvis_code_agent/shell_input_handler.py +22 -0
- jarvis/jarvis_codebase/main.py +314 -288
- jarvis/jarvis_dev/main.py +695 -716
- jarvis/jarvis_lsp/base.py +0 -12
- jarvis/jarvis_lsp/cpp.py +0 -9
- jarvis/jarvis_lsp/go.py +0 -9
- jarvis/jarvis_lsp/python.py +0 -28
- jarvis/jarvis_lsp/registry.py +0 -1
- jarvis/jarvis_lsp/rust.py +0 -9
- jarvis/jarvis_multi_agent/__init__.py +52 -52
- jarvis/jarvis_platform/base.py +6 -5
- jarvis/jarvis_platform_manager/main.py +1 -1
- jarvis/jarvis_rag/main.py +250 -186
- jarvis/jarvis_smart_shell/main.py +0 -1
- jarvis/jarvis_tools/ask_codebase.py +10 -9
- jarvis/jarvis_tools/ask_user.py +2 -2
- jarvis/jarvis_tools/base.py +4 -4
- jarvis/jarvis_tools/chdir.py +28 -28
- jarvis/jarvis_tools/code_review.py +44 -39
- jarvis/jarvis_tools/create_code_agent.py +4 -4
- jarvis/jarvis_tools/create_sub_agent.py +7 -7
- jarvis/jarvis_tools/execute_shell.py +53 -23
- jarvis/jarvis_tools/execute_shell_script.py +3 -3
- jarvis/jarvis_tools/file_operation.py +70 -41
- jarvis/jarvis_tools/git_commiter.py +61 -51
- jarvis/jarvis_tools/lsp_find_definition.py +7 -7
- jarvis/jarvis_tools/lsp_prepare_rename.py +7 -7
- jarvis/jarvis_tools/methodology.py +6 -6
- jarvis/jarvis_tools/rag.py +5 -5
- jarvis/jarvis_tools/read_webpage.py +52 -32
- jarvis/jarvis_tools/registry.py +167 -180
- jarvis/jarvis_tools/search_web.py +66 -41
- jarvis/jarvis_tools/select_code_files.py +3 -3
- jarvis/jarvis_tools/tool_generator.py +68 -55
- jarvis/jarvis_utils/methodology.py +77 -59
- jarvis/jarvis_utils/output.py +1 -0
- {jarvis_ai_assistant-0.1.125.dist-info → jarvis_ai_assistant-0.1.128.dist-info}/METADATA +31 -17
- jarvis_ai_assistant-0.1.128.dist-info/RECORD +74 -0
- {jarvis_ai_assistant-0.1.125.dist-info → jarvis_ai_assistant-0.1.128.dist-info}/WHEEL +1 -1
- jarvis/jarvis_tools/lsp_validate_edit.py +0 -141
- jarvis/jarvis_tools/read_code.py +0 -192
- jarvis_ai_assistant-0.1.125.dist-info/RECORD +0 -75
- {jarvis_ai_assistant-0.1.125.dist-info → jarvis_ai_assistant-0.1.128.dist-info}/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.125.dist-info → jarvis_ai_assistant-0.1.128.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.1.125.dist-info → jarvis_ai_assistant-0.1.128.dist-info}/top_level.txt +0 -0
|
@@ -3,11 +3,15 @@ import subprocess
|
|
|
3
3
|
import os
|
|
4
4
|
from typing import Any, Tuple
|
|
5
5
|
|
|
6
|
+
from yaspin import yaspin
|
|
7
|
+
|
|
6
8
|
from jarvis.jarvis_agent import Agent
|
|
7
|
-
from jarvis.jarvis_code_agent.
|
|
9
|
+
from jarvis.jarvis_code_agent.shell_input_handler import shell_input_handler
|
|
10
|
+
from jarvis.jarvis_code_agent.patch import PatchOutputHandler
|
|
8
11
|
from jarvis.jarvis_platform.registry import PlatformRegistry
|
|
12
|
+
from jarvis.jarvis_tools.file_operation import FileOperationTool
|
|
9
13
|
from jarvis.jarvis_tools.git_commiter import GitCommitTool
|
|
10
|
-
|
|
14
|
+
|
|
11
15
|
from jarvis.jarvis_tools.registry import ToolRegistry
|
|
12
16
|
from jarvis.jarvis_utils.git_utils import find_git_root, get_commits_between, get_latest_commit_hash, has_uncommitted_changes
|
|
13
17
|
from jarvis.jarvis_utils.input import get_multiline_input
|
|
@@ -81,12 +85,15 @@ def file_input_handler(user_input: str, agent: Any) -> Tuple[str, bool]:
|
|
|
81
85
|
"start_line": 1, # 1-based
|
|
82
86
|
"end_line": -1
|
|
83
87
|
})
|
|
84
|
-
|
|
88
|
+
|
|
85
89
|
# Read and process files if any were found
|
|
86
90
|
if files:
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
91
|
+
with yaspin(text="正在读取文件...", color="cyan") as spinner:
|
|
92
|
+
result = FileOperationTool().execute({"operation":"read","files": files})
|
|
93
|
+
if result["success"]:
|
|
94
|
+
spinner.text = "文件读取完成"
|
|
95
|
+
spinner.ok("✅")
|
|
96
|
+
return result["stdout"] + "\n" + prompt, False
|
|
90
97
|
|
|
91
98
|
return prompt, False
|
|
92
99
|
|
|
@@ -96,8 +103,7 @@ class CodeAgent:
|
|
|
96
103
|
def __init__(self):
|
|
97
104
|
self.root_dir = os.getcwd()
|
|
98
105
|
tool_registry = ToolRegistry()
|
|
99
|
-
tool_registry.use_tools(["
|
|
100
|
-
"execute_shell",
|
|
106
|
+
tool_registry.use_tools(["execute_shell",
|
|
101
107
|
"execute_shell_script",
|
|
102
108
|
"search_web",
|
|
103
109
|
"create_code_agent",
|
|
@@ -107,99 +113,92 @@ class CodeAgent:
|
|
|
107
113
|
"lsp_get_diagnostics",
|
|
108
114
|
"lsp_find_references",
|
|
109
115
|
"lsp_find_definition",
|
|
110
|
-
"lsp_prepare_rename"
|
|
111
|
-
|
|
116
|
+
"lsp_prepare_rename"
|
|
117
|
+
])
|
|
112
118
|
code_system_prompt = """
|
|
113
|
-
#
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
##
|
|
117
|
-
1.
|
|
118
|
-
2.
|
|
119
|
-
3.
|
|
120
|
-
4.
|
|
121
|
-
|
|
122
|
-
##
|
|
123
|
-
1.
|
|
124
|
-
-
|
|
125
|
-
-
|
|
126
|
-
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
-
|
|
142
|
-
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
-
|
|
148
|
-
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
-
|
|
157
|
-
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
-
|
|
168
|
-
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
-
|
|
184
|
-
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
-
|
|
189
|
-
-
|
|
190
|
-
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
-
|
|
194
|
-
-
|
|
195
|
-
-
|
|
196
|
-
- Untested interface alterations
|
|
197
|
-
|
|
198
|
-
3. Emergency Protocols:
|
|
199
|
-
- Immediately halt and rollback on lsp_get_diagnostics errors
|
|
200
|
-
- Prioritize fixing validation errors if lsp_validate_edit fails
|
|
201
|
-
- User notification on unexpected behavior
|
|
202
|
-
- Post-mortem analysis for any regression
|
|
119
|
+
# 角色:高级代码工程师
|
|
120
|
+
精通安全、精确的代码修改,具有严格的验证流程。
|
|
121
|
+
|
|
122
|
+
## 核心原则
|
|
123
|
+
1. 安全第一:绝不破坏现有功能
|
|
124
|
+
2. 精准工程:最小化、针对性修改
|
|
125
|
+
3. 完整可追溯:记录所有决策
|
|
126
|
+
4. 验证驱动:在每个阶段进行验证
|
|
127
|
+
|
|
128
|
+
## 工具使用协议
|
|
129
|
+
1. 分析工具:
|
|
130
|
+
- lsp_get_document_symbols:映射代码结构
|
|
131
|
+
- lsp_find_references:理解使用模式
|
|
132
|
+
- lsp_find_definition:追踪实现细节
|
|
133
|
+
|
|
134
|
+
2. 验证工具:
|
|
135
|
+
- lsp_prepare_rename:安全重构检查
|
|
136
|
+
- lsp_get_diagnostics:修改后检查
|
|
137
|
+
|
|
138
|
+
3. 系统工具:
|
|
139
|
+
- execute_shell:用于git操作和grep搜索
|
|
140
|
+
- ask_codebase:查询代码知识库
|
|
141
|
+
- search_web:技术参考查找
|
|
142
|
+
|
|
143
|
+
## 工作流程(PDCA循环)
|
|
144
|
+
1. 计划:
|
|
145
|
+
- 使用ask_user分析需求
|
|
146
|
+
- 使用LSP工具映射现有代码
|
|
147
|
+
- 使用find_references识别影响区域
|
|
148
|
+
- 使用git创建回滚计划
|
|
149
|
+
|
|
150
|
+
2. 执行:
|
|
151
|
+
- 在受保护的块中进行原子修改
|
|
152
|
+
- 每次更改后自动运行lsp_get_diagnostics
|
|
153
|
+
- 如果发现错误,使用lsp_find_references和lsp_find_definition进行即时修复
|
|
154
|
+
- 每次更改后使用LSP验证语法
|
|
155
|
+
|
|
156
|
+
3. 检查:
|
|
157
|
+
- 强制使用lsp_get_diagnostics进行完整诊断报告
|
|
158
|
+
- 使用lsp_preprepare_rename验证所有重命名
|
|
159
|
+
- 如果检测到错误,进入修复循环直到所有检查通过
|
|
160
|
+
|
|
161
|
+
4. 行动:
|
|
162
|
+
- 使用git提交详细消息
|
|
163
|
+
- 准备回滚脚本(如果需要)
|
|
164
|
+
- 进行实施后审查
|
|
165
|
+
|
|
166
|
+
## 代码修改标准
|
|
167
|
+
1. 修改前要求:
|
|
168
|
+
- 完整的代码分析报告
|
|
169
|
+
- 影响评估矩阵
|
|
170
|
+
- 回滚程序文档
|
|
171
|
+
|
|
172
|
+
2. 修改实施:
|
|
173
|
+
- 单一职责修改
|
|
174
|
+
- 严格的代码范围验证(±3行缓冲区)
|
|
175
|
+
- 接口兼容性检查
|
|
176
|
+
|
|
177
|
+
3. 验证清单:
|
|
178
|
+
[ ] 执行lsp_get_diagnostics并确保零错误
|
|
179
|
+
[ ] 使用lsp_find_references确认影响范围
|
|
180
|
+
[ ] 使用lsp_prepare_rename验证重命名安全性
|
|
181
|
+
|
|
182
|
+
4. 修改后:
|
|
183
|
+
- 代码审查模拟
|
|
184
|
+
- 版本控制审计
|
|
185
|
+
- 更新变更日志
|
|
186
|
+
|
|
187
|
+
## 关键要求
|
|
188
|
+
1. 强制分析:
|
|
189
|
+
- 修改前完整符号追踪
|
|
190
|
+
- 跨文件影响分析
|
|
191
|
+
- 依赖关系映射
|
|
192
|
+
|
|
193
|
+
2. 禁止操作:
|
|
194
|
+
- 未通过lsp_get_diagnostics检查继续操作
|
|
195
|
+
- 多个功能组合修改
|
|
196
|
+
- 未经测试的接口修改
|
|
197
|
+
|
|
198
|
+
3. 紧急协议:
|
|
199
|
+
- lsp_get_diagnostics出现错误时立即停止并回滚
|
|
200
|
+
- 出现意外行为时通知用户
|
|
201
|
+
- 对任何回归进行事后分析
|
|
203
202
|
"""
|
|
204
203
|
self.agent = Agent(system_prompt=code_system_prompt,
|
|
205
204
|
name="CodeAgent",
|
|
@@ -215,12 +214,17 @@ Expert in safe, precise code modifications with rigorous validation processes.
|
|
|
215
214
|
|
|
216
215
|
|
|
217
216
|
def _init_env(self):
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
217
|
+
with yaspin(text="正在初始化环境...", color="cyan") as spinner:
|
|
218
|
+
curr_dir = os.getcwd()
|
|
219
|
+
git_dir = find_git_root(curr_dir)
|
|
220
|
+
self.root_dir = git_dir
|
|
221
|
+
if has_uncommitted_changes():
|
|
222
|
+
with spinner.hidden():
|
|
223
|
+
git_commiter = GitCommitTool()
|
|
224
|
+
git_commiter.execute({})
|
|
225
|
+
else:
|
|
226
|
+
spinner.text = "环境初始化完成"
|
|
227
|
+
spinner.ok("✅")
|
|
224
228
|
|
|
225
229
|
|
|
226
230
|
|
|
@@ -235,10 +239,13 @@ Expert in safe, precise code modifications with rigorous validation processes.
|
|
|
235
239
|
"""
|
|
236
240
|
try:
|
|
237
241
|
self._init_env()
|
|
238
|
-
start_commit = get_latest_commit_hash()
|
|
239
242
|
|
|
243
|
+
start_commit = get_latest_commit_hash()
|
|
240
244
|
|
|
241
|
-
|
|
245
|
+
try:
|
|
246
|
+
self.agent.run(user_input)
|
|
247
|
+
except Exception as e:
|
|
248
|
+
PrettyOutput.print(f"执行失败: {str(e)}", OutputType.WARNING)
|
|
242
249
|
|
|
243
250
|
end_commit = get_latest_commit_hash()
|
|
244
251
|
# Print commit history between start and end commits
|
|
@@ -296,4 +303,4 @@ def main():
|
|
|
296
303
|
return 0
|
|
297
304
|
|
|
298
305
|
if __name__ == "__main__":
|
|
299
|
-
exit(main())
|
|
306
|
+
exit(main())
|
|
@@ -2,11 +2,13 @@ import re
|
|
|
2
2
|
from typing import Dict, Any, Tuple
|
|
3
3
|
import os
|
|
4
4
|
|
|
5
|
+
from yaspin import yaspin
|
|
6
|
+
|
|
5
7
|
from jarvis.jarvis_agent.output_handler import OutputHandler
|
|
6
8
|
from jarvis.jarvis_platform.registry import PlatformRegistry
|
|
7
9
|
from jarvis.jarvis_tools.git_commiter import GitCommitTool
|
|
8
|
-
from jarvis.jarvis_tools.file_operation import FileOperationTool
|
|
9
10
|
from jarvis.jarvis_tools.execute_shell_script import ShellScriptTool
|
|
11
|
+
from jarvis.jarvis_tools.file_operation import FileOperationTool
|
|
10
12
|
from jarvis.jarvis_utils.config import is_confirm_before_apply_patch
|
|
11
13
|
from jarvis.jarvis_utils.git_utils import get_commits_between, get_latest_commit_hash
|
|
12
14
|
from jarvis.jarvis_utils.input import get_multiline_input
|
|
@@ -26,31 +28,31 @@ class PatchOutputHandler(OutputHandler):
|
|
|
26
28
|
|
|
27
29
|
def prompt(self) -> str:
|
|
28
30
|
return """
|
|
29
|
-
# 🛠️
|
|
30
|
-
|
|
31
|
+
# 🛠️ 上下文代码补丁规范
|
|
32
|
+
使用<PATCH>块来指定代码更改:
|
|
31
33
|
--------------------------------
|
|
32
34
|
<PATCH>
|
|
33
|
-
File: [
|
|
34
|
-
Reason: [
|
|
35
|
-
[
|
|
35
|
+
File: [文件路径]
|
|
36
|
+
Reason: [修改原因]
|
|
37
|
+
[上下文代码片段]
|
|
36
38
|
</PATCH>
|
|
37
39
|
--------------------------------
|
|
38
|
-
|
|
39
|
-
1.
|
|
40
|
-
2.
|
|
41
|
-
3.
|
|
42
|
-
4.
|
|
43
|
-
5.
|
|
44
|
-
|
|
40
|
+
规则:
|
|
41
|
+
1. 代码片段必须包含足够的上下文(前后各3行)
|
|
42
|
+
2. 我可以看到完整代码,所以只需显示修改的代码部分
|
|
43
|
+
3. 保留原始缩进和格式
|
|
44
|
+
4. 对于新文件,提供完整代码
|
|
45
|
+
5. 修改现有文件时,保留周围未更改的代码
|
|
46
|
+
示例:
|
|
45
47
|
<PATCH>
|
|
46
48
|
File: src/utils/math.py
|
|
47
|
-
Reason:
|
|
49
|
+
Reason: 修复除零处理
|
|
48
50
|
def safe_divide(a, b):
|
|
49
|
-
#
|
|
51
|
+
# 添加参数验证
|
|
50
52
|
if b == 0:
|
|
51
|
-
raise ValueError("
|
|
53
|
+
raise ValueError("除数不能为零")
|
|
52
54
|
return a / b
|
|
53
|
-
#
|
|
55
|
+
# 现有代码 ...
|
|
54
56
|
def add(a, b):
|
|
55
57
|
return a + b
|
|
56
58
|
</PATCH>
|
|
@@ -73,50 +75,63 @@ def _parse_patch(patch_str: str) -> Dict[str, str]:
|
|
|
73
75
|
|
|
74
76
|
def apply_patch(output_str: str) -> str:
|
|
75
77
|
"""Apply patches to files"""
|
|
76
|
-
|
|
77
|
-
patches = _parse_patch(output_str)
|
|
78
|
-
except Exception as e:
|
|
79
|
-
PrettyOutput.print(f"解析补丁失败: {str(e)}", OutputType.ERROR)
|
|
80
|
-
return ""
|
|
81
|
-
|
|
82
|
-
# 获取当前提交hash作为起始点
|
|
83
|
-
start_hash = get_latest_commit_hash()
|
|
84
|
-
|
|
85
|
-
# 按文件逐个处理
|
|
86
|
-
for filepath, patch_content in patches.items():
|
|
78
|
+
with yaspin(text="正在应用补丁...", color="cyan") as spinner:
|
|
87
79
|
try:
|
|
88
|
-
|
|
89
|
-
PrettyOutput.print(f"文件 {filepath} 处理完成", OutputType.SUCCESS)
|
|
80
|
+
patches = _parse_patch(output_str)
|
|
90
81
|
except Exception as e:
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
82
|
+
PrettyOutput.print(f"解析补丁失败: {str(e)}", OutputType.ERROR)
|
|
83
|
+
return ""
|
|
84
|
+
|
|
85
|
+
# 获取当前提交hash作为起始点
|
|
86
|
+
spinner.text= "开始获取当前提交hash..."
|
|
87
|
+
start_hash = get_latest_commit_hash()
|
|
88
|
+
spinner.write("✅ 当前提交hash获取完成")
|
|
89
|
+
|
|
90
|
+
# 按文件逐个处理
|
|
91
|
+
for filepath, patch_content in patches.items():
|
|
92
|
+
try:
|
|
93
|
+
spinner.text = f"正在处理文件: {filepath}"
|
|
94
|
+
with spinner.hidden():
|
|
95
|
+
handle_code_operation(filepath, patch_content)
|
|
96
|
+
spinner.write(f"✅ 文件 {filepath} 处理完成")
|
|
97
|
+
except Exception as e:
|
|
98
|
+
spinner.text = f"文件 {filepath} 处理失败: {str(e)}, 回滚文件"
|
|
99
|
+
revert_file(filepath) # 回滚单个文件
|
|
100
|
+
spinner.write(f"✅ 文件 {filepath} 回滚完成")
|
|
101
|
+
|
|
102
|
+
final_ret = ""
|
|
103
|
+
diff = get_diff()
|
|
104
|
+
if diff:
|
|
105
|
+
PrettyOutput.print(diff, OutputType.CODE, lang="diff")
|
|
106
|
+
with spinner.hidden():
|
|
107
|
+
commited = handle_commit_workflow()
|
|
108
|
+
if commited:
|
|
109
|
+
# 获取提交信息
|
|
110
|
+
end_hash = get_latest_commit_hash()
|
|
111
|
+
commits = get_commits_between(start_hash, end_hash)
|
|
112
|
+
|
|
113
|
+
# 添加提交信息到final_ret
|
|
114
|
+
if commits:
|
|
115
|
+
final_ret += "✅ 补丁已应用\n"
|
|
116
|
+
final_ret += "提交信息:\n"
|
|
117
|
+
for commit_hash, commit_message in commits:
|
|
118
|
+
final_ret += f"- {commit_hash[:7]}: {commit_message}\n"
|
|
119
|
+
|
|
120
|
+
final_ret += f"应用补丁:\n{diff}"
|
|
121
|
+
|
|
122
|
+
else:
|
|
123
|
+
final_ret += "✅ 补丁已应用(没有新的提交)"
|
|
109
124
|
else:
|
|
110
|
-
final_ret += "
|
|
125
|
+
final_ret += "❌ 我不想提交代码\n"
|
|
126
|
+
final_ret += "补丁预览:\n"
|
|
127
|
+
final_ret += diff
|
|
111
128
|
else:
|
|
112
|
-
final_ret += "❌
|
|
113
|
-
|
|
114
|
-
final_ret
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
return final_ret
|
|
119
|
-
return get_multiline_input("请输入自定义回复")
|
|
129
|
+
final_ret += "❌ 没有要提交的更改\n"
|
|
130
|
+
# 用户确认最终结果
|
|
131
|
+
PrettyOutput.print(final_ret, OutputType.USER)
|
|
132
|
+
if not is_confirm_before_apply_patch() or user_confirm("是否使用此回复?", default=True):
|
|
133
|
+
return final_ret
|
|
134
|
+
return get_multiline_input("请输入自定义回复")
|
|
120
135
|
def revert_file(filepath: str):
|
|
121
136
|
"""增强版git恢复,处理新文件"""
|
|
122
137
|
import subprocess
|
|
@@ -170,87 +185,91 @@ def handle_commit_workflow()->bool:
|
|
|
170
185
|
return commit_result["success"]
|
|
171
186
|
|
|
172
187
|
# New handler functions below ▼▼▼
|
|
173
|
-
def handle_code_operation(filepath: str, patch_content: str) ->
|
|
188
|
+
def handle_code_operation(filepath: str, patch_content: str) -> bool:
|
|
174
189
|
"""处理基于上下文的代码片段"""
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
190
|
+
with yaspin(text=f"正在修改文件 {filepath}...", color="cyan") as spinner:
|
|
191
|
+
try:
|
|
192
|
+
if not os.path.exists(filepath):
|
|
193
|
+
# 新建文件
|
|
194
|
+
spinner.text = "文件不存在,正在创建文件..."
|
|
195
|
+
os.makedirs(os.path.dirname(filepath), exist_ok=True)
|
|
196
|
+
open(filepath, 'w', encoding='utf-8').close()
|
|
197
|
+
spinner.write("✅ 文件创建完成")
|
|
198
|
+
old_file_content = FileOperationTool().execute({"operation": "read", "files": [{"path": filepath}]})
|
|
199
|
+
if not old_file_content["success"]:
|
|
200
|
+
spinner.write("❌ 文件读取失败")
|
|
201
|
+
return False
|
|
202
|
+
|
|
203
|
+
prompt = f"""
|
|
204
|
+
你是一个代码审查员,请审查以下代码并将其与上下文合并。
|
|
205
|
+
原始代码:
|
|
206
|
+
{old_file_content["stdout"]}
|
|
207
|
+
补丁内容:
|
|
208
|
+
{patch_content}
|
|
209
|
+
"""
|
|
210
|
+
prompt += f"""
|
|
211
|
+
请将代码与上下文合并并返回完整的合并代码,每次最多输出300行代码。
|
|
193
212
|
|
|
194
|
-
|
|
195
|
-
1.
|
|
196
|
-
2.
|
|
197
|
-
3.
|
|
198
|
-
4.
|
|
213
|
+
要求:
|
|
214
|
+
1. 严格保留原始代码的格式、空行和缩进
|
|
215
|
+
2. 仅在<MERGED_CODE>块中包含实际代码内容,包括空行和缩进
|
|
216
|
+
3. 绝对不要使用markdown代码块(```)或反引号,除非修改的是markdown文件
|
|
217
|
+
4. 除了合并后的代码,不要输出任何其他文本
|
|
218
|
+
5. 所有代码输出完成后,输出<!!!FINISHED!!!>
|
|
199
219
|
|
|
200
|
-
|
|
201
|
-
<MERGED_CODE>
|
|
202
|
-
[merged_code]
|
|
203
|
-
</MERGED_CODE>
|
|
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
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
220
|
+
输出格式:
|
|
221
|
+
<MERGED_CODE>
|
|
222
|
+
[merged_code]
|
|
223
|
+
</MERGED_CODE>
|
|
224
|
+
"""
|
|
225
|
+
PrettyOutput.section("代码生成", OutputType.SYSTEM)
|
|
226
|
+
model = PlatformRegistry().get_codegen_platform()
|
|
227
|
+
model.set_suppress_output(False)
|
|
228
|
+
count = 30
|
|
229
|
+
start_line = -1
|
|
230
|
+
end_line = -1
|
|
231
|
+
code = []
|
|
232
|
+
finished = False
|
|
233
|
+
with spinner.hidden():
|
|
234
|
+
while count>0:
|
|
235
|
+
count -= 1
|
|
236
|
+
response = model.chat_until_success(prompt).splitlines()
|
|
237
|
+
try:
|
|
238
|
+
start_line = response.index("<MERGED_CODE>") + 1
|
|
239
|
+
except:
|
|
240
|
+
return False
|
|
241
|
+
try:
|
|
242
|
+
end_line = response.index("</MERGED_CODE>")
|
|
243
|
+
except:
|
|
244
|
+
return False
|
|
245
|
+
code = response[start_line:end_line]
|
|
246
|
+
try:
|
|
247
|
+
response.index("<!!!FINISHED!!!>")
|
|
248
|
+
finished = True
|
|
249
|
+
break
|
|
250
|
+
except:
|
|
251
|
+
prompt += f"""继续输出接下来的300行代码
|
|
252
|
+
要求:
|
|
253
|
+
1. 严格保留原始代码的格式、空行和缩进
|
|
254
|
+
2. 仅在<MERGED_CODE>块中包含实际代码内容,包括空行和缩进
|
|
255
|
+
3. 绝对不要使用markdown代码块(```)或反引号,除非修改的是markdown文件
|
|
256
|
+
4. 除了合并后的代码,不要输出任何其他文本
|
|
257
|
+
5. 所有代码输出完成后,输出<!!!FINISHED!!!>
|
|
258
|
+
"""
|
|
259
|
+
pass
|
|
260
|
+
if not finished:
|
|
261
|
+
spinner.text = "生成代码失败"
|
|
262
|
+
spinner.fail("❌")
|
|
263
|
+
return False
|
|
264
|
+
# 写入合并后的代码
|
|
265
|
+
spinner.text = "写入合并后的代码..."
|
|
266
|
+
with open(filepath, 'w', encoding='utf-8') as f:
|
|
267
|
+
f.write("\n".join(code)+"\n")
|
|
268
|
+
spinner.write("✅ 合并后的代码写入完成")
|
|
269
|
+
spinner.text = "代码修改完成"
|
|
270
|
+
spinner.ok("✅")
|
|
271
|
+
return True
|
|
272
|
+
except Exception as e:
|
|
273
|
+
spinner.text = "代码修改失败"
|
|
274
|
+
spinner.fail("❌")
|
|
275
|
+
return False
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
from typing import Any, Tuple
|
|
4
|
+
|
|
5
|
+
from jarvis.jarvis_tools.execute_shell_script import ShellScriptTool
|
|
6
|
+
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
7
|
+
from jarvis.jarvis_utils.utils import user_confirm
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def shell_input_handler(user_input: str, agent: Any) -> Tuple[str, bool]:
|
|
11
|
+
lines = user_input.splitlines()
|
|
12
|
+
cmdline = [line for line in lines if line.startswith("!")]
|
|
13
|
+
if len(cmdline) == 0:
|
|
14
|
+
return user_input, False
|
|
15
|
+
else:
|
|
16
|
+
script = '\n'.join([c[1:] for c in cmdline])
|
|
17
|
+
PrettyOutput.print(script, OutputType.CODE, lang="bash")
|
|
18
|
+
if user_confirm(f"是否要执行以上shell脚本?", default=True):
|
|
19
|
+
ShellScriptTool().execute({"script_content": script})
|
|
20
|
+
return "", True
|
|
21
|
+
return user_input, False
|
|
22
|
+
|