jarvis-ai-assistant 0.1.131__py3-none-any.whl → 0.1.134__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 +165 -285
- jarvis/jarvis_agent/jarvis.py +143 -0
- jarvis/jarvis_agent/main.py +0 -2
- jarvis/jarvis_agent/patch.py +70 -48
- jarvis/jarvis_agent/shell_input_handler.py +1 -1
- jarvis/jarvis_code_agent/code_agent.py +169 -117
- jarvis/jarvis_dev/main.py +327 -626
- jarvis/jarvis_git_squash/main.py +10 -31
- jarvis/jarvis_lsp/base.py +0 -42
- jarvis/jarvis_lsp/cpp.py +0 -15
- jarvis/jarvis_lsp/go.py +0 -15
- jarvis/jarvis_lsp/python.py +0 -19
- jarvis/jarvis_lsp/registry.py +0 -62
- jarvis/jarvis_lsp/rust.py +0 -15
- jarvis/jarvis_multi_agent/__init__.py +19 -69
- jarvis/jarvis_multi_agent/main.py +43 -0
- jarvis/jarvis_platform/ai8.py +7 -32
- jarvis/jarvis_platform/base.py +2 -7
- jarvis/jarvis_platform/kimi.py +3 -144
- jarvis/jarvis_platform/ollama.py +54 -68
- jarvis/jarvis_platform/openai.py +0 -4
- jarvis/jarvis_platform/oyi.py +0 -75
- jarvis/jarvis_platform/registry.py +2 -16
- jarvis/jarvis_platform/yuanbao.py +264 -0
- jarvis/jarvis_rag/file_processors.py +138 -0
- jarvis/jarvis_rag/main.py +1305 -425
- jarvis/jarvis_tools/ask_codebase.py +216 -43
- jarvis/jarvis_tools/code_review.py +158 -113
- jarvis/jarvis_tools/create_sub_agent.py +0 -1
- jarvis/jarvis_tools/execute_python_script.py +58 -0
- jarvis/jarvis_tools/execute_shell.py +13 -26
- jarvis/jarvis_tools/execute_shell_script.py +1 -1
- jarvis/jarvis_tools/file_analyzer.py +282 -0
- jarvis/jarvis_tools/file_operation.py +1 -1
- jarvis/jarvis_tools/find_caller.py +278 -0
- jarvis/jarvis_tools/find_symbol.py +295 -0
- jarvis/jarvis_tools/function_analyzer.py +331 -0
- jarvis/jarvis_tools/git_commiter.py +5 -5
- jarvis/jarvis_tools/methodology.py +88 -53
- jarvis/jarvis_tools/project_analyzer.py +308 -0
- jarvis/jarvis_tools/rag.py +0 -5
- jarvis/jarvis_tools/read_code.py +24 -3
- jarvis/jarvis_tools/read_webpage.py +195 -81
- jarvis/jarvis_tools/registry.py +132 -11
- jarvis/jarvis_tools/search_web.py +22 -307
- jarvis/jarvis_tools/tool_generator.py +8 -10
- jarvis/jarvis_utils/__init__.py +1 -0
- jarvis/jarvis_utils/config.py +80 -76
- jarvis/jarvis_utils/embedding.py +344 -45
- jarvis/jarvis_utils/git_utils.py +9 -1
- jarvis/jarvis_utils/input.py +7 -6
- jarvis/jarvis_utils/methodology.py +384 -15
- jarvis/jarvis_utils/output.py +5 -3
- jarvis/jarvis_utils/utils.py +60 -8
- {jarvis_ai_assistant-0.1.131.dist-info → jarvis_ai_assistant-0.1.134.dist-info}/METADATA +8 -16
- jarvis_ai_assistant-0.1.134.dist-info/RECORD +82 -0
- {jarvis_ai_assistant-0.1.131.dist-info → jarvis_ai_assistant-0.1.134.dist-info}/entry_points.txt +4 -3
- jarvis/jarvis_codebase/__init__.py +0 -0
- jarvis/jarvis_codebase/main.py +0 -1011
- jarvis/jarvis_tools/lsp_find_definition.py +0 -150
- jarvis/jarvis_tools/lsp_find_references.py +0 -127
- jarvis/jarvis_tools/treesitter_analyzer.py +0 -331
- jarvis/jarvis_treesitter/README.md +0 -104
- jarvis/jarvis_treesitter/__init__.py +0 -20
- jarvis/jarvis_treesitter/database.py +0 -258
- jarvis/jarvis_treesitter/example.py +0 -115
- jarvis/jarvis_treesitter/grammar_builder.py +0 -182
- jarvis/jarvis_treesitter/language.py +0 -117
- jarvis/jarvis_treesitter/symbol.py +0 -31
- jarvis/jarvis_treesitter/tools_usage.md +0 -121
- jarvis_ai_assistant-0.1.131.dist-info/RECORD +0 -85
- {jarvis_ai_assistant-0.1.131.dist-info → jarvis_ai_assistant-0.1.134.dist-info}/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.131.dist-info → jarvis_ai_assistant-0.1.134.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.131.dist-info → jarvis_ai_assistant-0.1.134.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
from prompt_toolkit import prompt
|
|
5
|
+
import yaml
|
|
6
|
+
from yaspin import yaspin
|
|
7
|
+
from jarvis.jarvis_agent import (
|
|
8
|
+
PrettyOutput, OutputType,
|
|
9
|
+
get_multiline_input,
|
|
10
|
+
Agent, # 显式导入关键组件
|
|
11
|
+
origin_agent_system_prompt
|
|
12
|
+
)
|
|
13
|
+
from jarvis.jarvis_agent.patch import PatchOutputHandler
|
|
14
|
+
from jarvis.jarvis_tools.registry import ToolRegistry
|
|
15
|
+
from jarvis.jarvis_utils.utils import init_env
|
|
16
|
+
from jarvis.jarvis_agent.file_input_handler import file_input_handler
|
|
17
|
+
from jarvis.jarvis_agent.shell_input_handler import shell_input_handler
|
|
18
|
+
from jarvis.jarvis_agent.builtin_input_handler import builtin_input_handler
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _load_tasks() -> dict:
|
|
22
|
+
"""Load tasks from .jarvis files in user home and current directory."""
|
|
23
|
+
tasks = {}
|
|
24
|
+
|
|
25
|
+
# Check .jarvis/pre-command in user directory
|
|
26
|
+
user_jarvis = os.path.expanduser("~/.jarvis/pre-command")
|
|
27
|
+
if os.path.exists(user_jarvis):
|
|
28
|
+
with yaspin(text=f"从{user_jarvis}加载预定义任务...", color="cyan") as spinner:
|
|
29
|
+
try:
|
|
30
|
+
with open(user_jarvis, "r", encoding="utf-8", errors="ignore") as f:
|
|
31
|
+
user_tasks = yaml.safe_load(f)
|
|
32
|
+
|
|
33
|
+
if isinstance(user_tasks, dict):
|
|
34
|
+
# Validate and add user directory tasks
|
|
35
|
+
for name, desc in user_tasks.items():
|
|
36
|
+
if desc: # Ensure description is not empty
|
|
37
|
+
tasks[str(name)] = str(desc)
|
|
38
|
+
spinner.text = "预定义任务加载完成"
|
|
39
|
+
spinner.ok("✅")
|
|
40
|
+
except Exception as e:
|
|
41
|
+
spinner.text = "预定义任务加载失败"
|
|
42
|
+
spinner.fail("❌")
|
|
43
|
+
|
|
44
|
+
# Check .jarvis/pre-command in current directory
|
|
45
|
+
if os.path.exists(".jarvis/pre-command"):
|
|
46
|
+
with yaspin(text=f"从{os.path.abspath('.jarvis/pre-command')}加载预定义任务...", color="cyan") as spinner:
|
|
47
|
+
try:
|
|
48
|
+
with open(".jarvis/pre-command", "r", encoding="utf-8", errors="ignore") as f:
|
|
49
|
+
local_tasks = yaml.safe_load(f)
|
|
50
|
+
|
|
51
|
+
if isinstance(local_tasks, dict):
|
|
52
|
+
# Validate and add current directory tasks, overwrite user directory tasks if there is a name conflict
|
|
53
|
+
for name, desc in local_tasks.items():
|
|
54
|
+
if desc: # Ensure description is not empty
|
|
55
|
+
tasks[str(name)] = str(desc)
|
|
56
|
+
spinner.text = "预定义任务加载完成"
|
|
57
|
+
spinner.ok("✅")
|
|
58
|
+
except Exception as e:
|
|
59
|
+
spinner.text = "预定义任务加载失败"
|
|
60
|
+
spinner.fail("❌")
|
|
61
|
+
|
|
62
|
+
return tasks
|
|
63
|
+
|
|
64
|
+
def _select_task(tasks: dict) -> str:
|
|
65
|
+
"""Let user select a task from the list or skip. Returns task description if selected."""
|
|
66
|
+
if not tasks:
|
|
67
|
+
return ""
|
|
68
|
+
# Convert tasks to list for ordered display
|
|
69
|
+
task_names = list(tasks.keys())
|
|
70
|
+
|
|
71
|
+
task_list = ["可用任务:"]
|
|
72
|
+
for i, name in enumerate(task_names, 1):
|
|
73
|
+
task_list.append(f"[{i}] {name}")
|
|
74
|
+
task_list.append("[0] 跳过预定义任务")
|
|
75
|
+
PrettyOutput.print("\n".join(task_list), OutputType.INFO)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
while True:
|
|
79
|
+
try:
|
|
80
|
+
choice = prompt(
|
|
81
|
+
"\n请选择一个任务编号(0 跳过预定义任务):",
|
|
82
|
+
).strip()
|
|
83
|
+
|
|
84
|
+
if not choice:
|
|
85
|
+
return ""
|
|
86
|
+
|
|
87
|
+
choice = int(choice)
|
|
88
|
+
if choice == 0:
|
|
89
|
+
return ""
|
|
90
|
+
elif 1 <= choice <= len(task_names):
|
|
91
|
+
selected_name = task_names[choice - 1]
|
|
92
|
+
return tasks[selected_name] # Return the task description
|
|
93
|
+
else:
|
|
94
|
+
PrettyOutput.print("无效的选择。请选择列表中的一个号码。", OutputType.WARNING)
|
|
95
|
+
|
|
96
|
+
except KeyboardInterrupt:
|
|
97
|
+
return "" # Return empty on Ctrl+C
|
|
98
|
+
except EOFError:
|
|
99
|
+
return "" # Return empty on Ctrl+D
|
|
100
|
+
except Exception as e:
|
|
101
|
+
PrettyOutput.print(f"选择任务失败: {str(e)}", OutputType.ERROR)
|
|
102
|
+
continue
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def main() -> int:
|
|
108
|
+
"""Jarvis main entry point"""
|
|
109
|
+
init_env()
|
|
110
|
+
parser = argparse.ArgumentParser(description='Jarvis AI assistant')
|
|
111
|
+
parser.add_argument('-p', '--platform', type=str, help='Platform to use')
|
|
112
|
+
parser.add_argument('-m', '--model', type=str, help='Model to use')
|
|
113
|
+
args = parser.parse_args()
|
|
114
|
+
|
|
115
|
+
try:
|
|
116
|
+
agent = Agent(
|
|
117
|
+
system_prompt=origin_agent_system_prompt,
|
|
118
|
+
platform=args.platform,
|
|
119
|
+
model_name=args.model,
|
|
120
|
+
input_handler=[file_input_handler, shell_input_handler, builtin_input_handler], # type: ignore
|
|
121
|
+
output_handler=[ToolRegistry(), PatchOutputHandler()],
|
|
122
|
+
need_summary=False
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
tasks = _load_tasks()
|
|
126
|
+
if tasks:
|
|
127
|
+
selected_task = _select_task(tasks)
|
|
128
|
+
if selected_task:
|
|
129
|
+
PrettyOutput.print(f"执行任务: {selected_task}", OutputType.INFO)
|
|
130
|
+
agent.run(selected_task)
|
|
131
|
+
return 0
|
|
132
|
+
|
|
133
|
+
user_input = get_multiline_input("请输入你的任务(输入空行退出):")
|
|
134
|
+
if user_input:
|
|
135
|
+
agent.run(user_input)
|
|
136
|
+
return 0
|
|
137
|
+
|
|
138
|
+
except Exception as e:
|
|
139
|
+
PrettyOutput.print(f"初始化错误: {str(e)}", OutputType.ERROR)
|
|
140
|
+
return 1
|
|
141
|
+
|
|
142
|
+
if __name__ == "__main__":
|
|
143
|
+
exit(main())
|
jarvis/jarvis_agent/main.py
CHANGED
|
@@ -7,8 +7,6 @@ from jarvis.jarvis_utils.input import get_multiline_input
|
|
|
7
7
|
from jarvis.jarvis_utils.output import PrettyOutput, OutputType
|
|
8
8
|
from jarvis.jarvis_utils.utils import init_env
|
|
9
9
|
|
|
10
|
-
# 从__init__.py导入系统提示
|
|
11
|
-
from jarvis.jarvis_agent import origin_agent_system_prompt
|
|
12
10
|
|
|
13
11
|
def load_config(config_path: str) -> dict:
|
|
14
12
|
"""Load configuration from YAML file
|
jarvis/jarvis_agent/patch.py
CHANGED
|
@@ -5,6 +5,7 @@ import os
|
|
|
5
5
|
from yaspin import yaspin
|
|
6
6
|
|
|
7
7
|
from jarvis.jarvis_agent.output_handler import OutputHandler
|
|
8
|
+
from jarvis.jarvis_platform.base import BasePlatform
|
|
8
9
|
from jarvis.jarvis_platform.registry import PlatformRegistry
|
|
9
10
|
from jarvis.jarvis_tools.git_commiter import GitCommitTool
|
|
10
11
|
from jarvis.jarvis_tools.file_operation import FileOperationTool
|
|
@@ -12,7 +13,7 @@ from jarvis.jarvis_utils.config import is_confirm_before_apply_patch
|
|
|
12
13
|
from jarvis.jarvis_utils.git_utils import get_commits_between, get_latest_commit_hash
|
|
13
14
|
from jarvis.jarvis_utils.input import get_multiline_input
|
|
14
15
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
15
|
-
from jarvis.jarvis_utils.utils import get_file_line_count, user_confirm
|
|
16
|
+
from jarvis.jarvis_utils.utils import ct, ot, get_file_line_count, user_confirm
|
|
16
17
|
|
|
17
18
|
class PatchOutputHandler(OutputHandler):
|
|
18
19
|
def name(self) -> str:
|
|
@@ -26,31 +27,35 @@ class PatchOutputHandler(OutputHandler):
|
|
|
26
27
|
return False
|
|
27
28
|
|
|
28
29
|
def prompt(self) -> str:
|
|
29
|
-
return """
|
|
30
|
+
return f"""
|
|
30
31
|
# 代码补丁规范
|
|
31
32
|
|
|
33
|
+
## 重要提示
|
|
34
|
+
我可以看到完整的代码,所以不需要生成完整的代码,只需要提供修改的代码片段即可。请尽量精简补丁内容,只包含必要的上下文和修改部分。
|
|
35
|
+
|
|
32
36
|
## 补丁格式定义
|
|
33
|
-
|
|
37
|
+
使用{ot("PATCH")}块来精确指定代码更改:
|
|
34
38
|
```
|
|
35
|
-
|
|
39
|
+
{ot("PATCH")}
|
|
36
40
|
File: [文件路径]
|
|
37
41
|
Reason: [修改原因]
|
|
38
42
|
[上下文代码片段]
|
|
39
|
-
|
|
43
|
+
{ct("PATCH")}
|
|
40
44
|
```
|
|
41
45
|
|
|
42
46
|
## 核心原则
|
|
43
47
|
1. **上下文完整性**:代码片段必须包含足够的上下文(修改前后各3行)
|
|
44
48
|
2. **精准修改**:只显示需要修改的代码部分,不需要展示整个文件内容
|
|
45
|
-
3.
|
|
49
|
+
3. **最小补丁原则**:始终生成最小范围的补丁,只包含必要的上下文和实际修改
|
|
50
|
+
4. **格式严格保持**:
|
|
46
51
|
- 严格保持原始代码的缩进方式(空格或制表符)
|
|
47
52
|
- 保持原始代码的空行数量和位置
|
|
48
53
|
- 保持原始代码的行尾空格处理方式
|
|
49
54
|
- 不改变原始代码的换行风格
|
|
50
|
-
|
|
55
|
+
5. **新旧区分**:
|
|
51
56
|
- 对于新文件:提供完整的代码内容
|
|
52
|
-
-
|
|
53
|
-
|
|
57
|
+
- 对于现有文件:只提供修改部分及必要上下文,不要提供整个文件
|
|
58
|
+
6. **理由说明**:每个补丁必须包含清晰的修改理由,解释为什么需要此更改
|
|
54
59
|
|
|
55
60
|
## 格式兼容性要求
|
|
56
61
|
1. **缩进一致性**:
|
|
@@ -65,7 +70,7 @@ Reason: [修改原因]
|
|
|
65
70
|
|
|
66
71
|
## 补丁示例
|
|
67
72
|
```
|
|
68
|
-
|
|
73
|
+
{ot("PATCH")}
|
|
69
74
|
File: src/utils/math.py
|
|
70
75
|
Reason: 修复除零错误,增加参数验证以提高函数健壮性
|
|
71
76
|
def safe_divide(a, b):
|
|
@@ -76,7 +81,7 @@ def safe_divide(a, b):
|
|
|
76
81
|
# 现有代码 ...
|
|
77
82
|
def add(a, b):
|
|
78
83
|
return a + b
|
|
79
|
-
|
|
84
|
+
{ct("PATCH")}
|
|
80
85
|
```
|
|
81
86
|
|
|
82
87
|
## 最佳实践
|
|
@@ -85,12 +90,13 @@ def add(a, b):
|
|
|
85
90
|
- 确保修改理由清晰明确,便于理解变更目的
|
|
86
91
|
- 保持代码风格一致性,遵循项目现有的编码规范
|
|
87
92
|
- 在修改前仔细分析原代码的格式风格,确保补丁与之完全兼容
|
|
93
|
+
- 绝不提供完整文件内容,除非是新建文件
|
|
88
94
|
"""
|
|
89
95
|
|
|
90
96
|
def _parse_patch(patch_str: str) -> Dict[str, str]:
|
|
91
97
|
"""解析新的上下文补丁格式"""
|
|
92
98
|
result = {}
|
|
93
|
-
patches = re.findall(r'
|
|
99
|
+
patches = re.findall(ot("PATCH")+r'\n?(.*?)\n?'+ct("PATCH"), patch_str, re.DOTALL)
|
|
94
100
|
if patches:
|
|
95
101
|
for patch in patches:
|
|
96
102
|
first_line = patch.splitlines()[0]
|
|
@@ -155,27 +161,46 @@ def apply_patch(output_str: str) -> str:
|
|
|
155
161
|
# 添加提交信息到final_ret
|
|
156
162
|
if commits:
|
|
157
163
|
final_ret += "✅ 补丁已应用\n"
|
|
158
|
-
final_ret += "提交信息:\n"
|
|
164
|
+
final_ret += "# 提交信息:\n"
|
|
159
165
|
for commit_hash, commit_message in commits:
|
|
160
166
|
final_ret += f"- {commit_hash[:7]}: {commit_message}\n"
|
|
161
167
|
|
|
162
|
-
final_ret += f"应用补丁:\n{diff}"
|
|
168
|
+
final_ret += f"# 应用补丁:\n```diff\n{diff}\n```"
|
|
169
|
+
|
|
170
|
+
# 增加代码变更分析和错误提示
|
|
171
|
+
final_ret += "\n\n# 代码变更分析:\n"
|
|
172
|
+
final_ret += "1. 请使用静态检查工具(如有)检查以上变更是否引入了潜在错误\n"
|
|
173
|
+
final_ret += "2. 如果发现代码错误,请立即提出修复方案\n"
|
|
174
|
+
final_ret += "3. 修复代码错误的优先级高于继续实现功能\n"
|
|
175
|
+
final_ret += "4. 确保修改后代码的一致性和完整性\n"
|
|
176
|
+
final_ret += "5. 请确认所有相关点是否已修改完成,包括但不限于:\n"
|
|
177
|
+
final_ret += " - 所有需要修改的文件\n"
|
|
178
|
+
final_ret += " - 所有需要更新的函数\n"
|
|
179
|
+
final_ret += " - 所有需要调整的依赖关系\n"
|
|
180
|
+
final_ret += " - 所有需要同步的文档\n"
|
|
181
|
+
final_ret += "\n\n"
|
|
182
|
+
final_ret += "如果没有问题,请继续进行下一步修改,如果所有修改都已经完成,请终止"
|
|
163
183
|
|
|
164
184
|
else:
|
|
165
185
|
final_ret += "✅ 补丁已应用(没有新的提交)"
|
|
166
186
|
else:
|
|
167
|
-
final_ret += "❌
|
|
168
|
-
final_ret += "补丁预览:\n"
|
|
169
|
-
final_ret += diff
|
|
187
|
+
final_ret += "❌ 补丁应用被拒绝\n"
|
|
188
|
+
final_ret += f"# 补丁预览:\n```diff\n{diff}\n```"
|
|
170
189
|
else:
|
|
190
|
+
commited = False
|
|
171
191
|
final_ret += "❌ 没有要提交的更改\n"
|
|
172
192
|
# 用户确认最终结果
|
|
173
193
|
with spinner.hidden():
|
|
174
|
-
|
|
194
|
+
if commited:
|
|
195
|
+
return final_ret
|
|
196
|
+
PrettyOutput.print(final_ret, OutputType.USER, lang="markdown")
|
|
175
197
|
if not is_confirm_before_apply_patch() or user_confirm("是否使用此回复?", default=True):
|
|
176
198
|
return final_ret
|
|
177
|
-
|
|
178
|
-
|
|
199
|
+
custom_reply = get_multiline_input("请输入自定义回复")
|
|
200
|
+
if not custom_reply.strip(): # 如果自定义回复为空,返回空字符串
|
|
201
|
+
return ""
|
|
202
|
+
return final_ret + "\n\n" + custom_reply
|
|
203
|
+
|
|
179
204
|
def revert_file(filepath: str):
|
|
180
205
|
"""增强版git恢复,处理新文件"""
|
|
181
206
|
import subprocess
|
|
@@ -235,10 +260,10 @@ def handle_code_operation(filepath: str, patch_content: str) -> bool:
|
|
|
235
260
|
if get_file_line_count(filepath) < 100:
|
|
236
261
|
return handle_small_code_operation(filepath, patch_content)
|
|
237
262
|
else:
|
|
238
|
-
retry_count =
|
|
263
|
+
retry_count = 5
|
|
239
264
|
while retry_count > 0:
|
|
240
265
|
retry_count -= 1
|
|
241
|
-
if handle_large_code_operation(filepath, patch_content):
|
|
266
|
+
if handle_large_code_operation(filepath, patch_content, PlatformRegistry().get_normal_platform() if retry_count > 2 else PlatformRegistry().get_thinking_platform()):
|
|
242
267
|
return True
|
|
243
268
|
return handle_small_code_operation(filepath, patch_content)
|
|
244
269
|
|
|
@@ -277,19 +302,19 @@ def handle_small_code_operation(filepath: str, patch_content: str) -> bool:
|
|
|
277
302
|
4. **上下文保留**:保持未修改部分的代码完全不变
|
|
278
303
|
|
|
279
304
|
## 输出格式规范
|
|
280
|
-
-
|
|
305
|
+
- 仅在{ot("MERGED_CODE")}标签内输出合并后的完整代码
|
|
281
306
|
- 每次最多输出300行代码
|
|
282
307
|
- 不要使用markdown代码块(```)或反引号,除非修改的是markdown文件
|
|
283
308
|
- 除了合并后的代码,不要输出任何其他文本
|
|
284
|
-
-
|
|
309
|
+
- 所有代码输出完成后,输出{ot("!!!FINISHED!!!")}标记
|
|
285
310
|
|
|
286
311
|
## 输出模板
|
|
287
|
-
|
|
312
|
+
{ot("MERGED_CODE")}
|
|
288
313
|
[合并后的完整代码,包括所有空行和缩进]
|
|
289
|
-
|
|
314
|
+
{ct("MERGED_CODE")}
|
|
290
315
|
"""
|
|
291
|
-
model = PlatformRegistry().
|
|
292
|
-
model.set_suppress_output(
|
|
316
|
+
model = PlatformRegistry().get_normal_platform()
|
|
317
|
+
model.set_suppress_output(True)
|
|
293
318
|
count = 30
|
|
294
319
|
start_line = -1
|
|
295
320
|
end_line = -1
|
|
@@ -297,12 +322,11 @@ def handle_small_code_operation(filepath: str, patch_content: str) -> bool:
|
|
|
297
322
|
finished = False
|
|
298
323
|
while count>0:
|
|
299
324
|
count -= 1
|
|
300
|
-
|
|
301
|
-
response = model.chat_until_success(prompt).splitlines()
|
|
325
|
+
response = model.chat_until_success(prompt).splitlines()
|
|
302
326
|
try:
|
|
303
|
-
start_line = response.index("
|
|
327
|
+
start_line = response.index(ot("MERGED_CODE")) + 1
|
|
304
328
|
try:
|
|
305
|
-
end_line = response.index("
|
|
329
|
+
end_line = response.index(ct("MERGED_CODE"))
|
|
306
330
|
code = response[start_line:end_line]
|
|
307
331
|
except:
|
|
308
332
|
pass
|
|
@@ -310,7 +334,7 @@ def handle_small_code_operation(filepath: str, patch_content: str) -> bool:
|
|
|
310
334
|
pass
|
|
311
335
|
|
|
312
336
|
try:
|
|
313
|
-
response.index("
|
|
337
|
+
response.index(ot("!!!FINISHED!!!"))
|
|
314
338
|
finished = True
|
|
315
339
|
break
|
|
316
340
|
except:
|
|
@@ -322,10 +346,10 @@ def handle_small_code_operation(filepath: str, patch_content: str) -> bool:
|
|
|
322
346
|
|
|
323
347
|
## 要求
|
|
324
348
|
- 严格保留原始代码的格式、空行和缩进
|
|
325
|
-
-
|
|
349
|
+
- 仅在{ot("MERGED_CODE")}块中包含实际代码内容
|
|
326
350
|
- 不要使用markdown代码块(```)或反引号
|
|
327
351
|
- 除了合并后的代码,不要输出任何其他文本
|
|
328
|
-
-
|
|
352
|
+
- 所有代码输出完成后,输出{ot("!!!FINISHED!!!")}标记
|
|
329
353
|
"""
|
|
330
354
|
pass
|
|
331
355
|
if not finished:
|
|
@@ -346,7 +370,7 @@ def handle_small_code_operation(filepath: str, patch_content: str) -> bool:
|
|
|
346
370
|
return False
|
|
347
371
|
|
|
348
372
|
|
|
349
|
-
def handle_large_code_operation(filepath: str, patch_content: str) -> bool:
|
|
373
|
+
def handle_large_code_operation(filepath: str, patch_content: str, model: BasePlatform) -> bool:
|
|
350
374
|
"""处理大型代码文件的补丁操作,使用差异化补丁格式"""
|
|
351
375
|
with yaspin(text=f"正在处理文件 {filepath}...", color="cyan") as spinner:
|
|
352
376
|
try:
|
|
@@ -357,8 +381,7 @@ def handle_large_code_operation(filepath: str, patch_content: str) -> bool:
|
|
|
357
381
|
spinner.fail("❌")
|
|
358
382
|
return False
|
|
359
383
|
|
|
360
|
-
model
|
|
361
|
-
model.set_suppress_output(False)
|
|
384
|
+
model.set_suppress_output(True)
|
|
362
385
|
|
|
363
386
|
prompt = f"""
|
|
364
387
|
# 代码补丁生成专家指南
|
|
@@ -387,36 +410,35 @@ def handle_large_code_operation(filepath: str, patch_content: str) -> bool:
|
|
|
387
410
|
4. **上下文完整性**:提供足够的上下文,确保补丁能准确应用
|
|
388
411
|
|
|
389
412
|
## 输出格式规范
|
|
390
|
-
-
|
|
391
|
-
-
|
|
413
|
+
- 使用{ot("DIFF")}块包围每个需要修改的代码段
|
|
414
|
+
- 每个{ot("DIFF")}块必须包含SEARCH部分和REPLACE部分
|
|
392
415
|
- SEARCH部分是需要查找的原始代码
|
|
393
416
|
- REPLACE部分是替换后的新代码
|
|
394
417
|
- 确保SEARCH部分能在原文件中唯一匹配
|
|
395
|
-
-
|
|
418
|
+
- 如果修改较大,可以使用多个{ot("DIFF")}块
|
|
396
419
|
|
|
397
420
|
## 输出模板
|
|
398
|
-
|
|
421
|
+
{ot("DIFF")}
|
|
399
422
|
>>>>>> SEARCH
|
|
400
423
|
[需要查找的原始代码,包含足够上下文]
|
|
401
424
|
======
|
|
402
425
|
[替换后的新代码]
|
|
403
426
|
<<<<<< REPLACE
|
|
404
|
-
|
|
427
|
+
{ct("DIFF")}
|
|
405
428
|
|
|
406
|
-
|
|
429
|
+
{ot("DIFF")}
|
|
407
430
|
>>>>>> SEARCH
|
|
408
431
|
[另一处需要查找的原始代码]
|
|
409
432
|
======
|
|
410
433
|
[另一处替换后的新代码]
|
|
411
434
|
<<<<<< REPLACE
|
|
412
|
-
|
|
435
|
+
{ct("DIFF")}
|
|
413
436
|
"""
|
|
414
437
|
# 获取补丁内容
|
|
415
|
-
|
|
416
|
-
response = model.chat_until_success(prompt)
|
|
438
|
+
response = model.chat_until_success(prompt)
|
|
417
439
|
|
|
418
440
|
# 解析差异化补丁
|
|
419
|
-
diff_blocks = re.finditer(r'
|
|
441
|
+
diff_blocks = re.finditer(ot("DIFF")+r'\s*>{4,} SEARCH\n?(.*?)\n?={4,}\n?(.*?)\s*<{4,} REPLACE\n?'+ct("DIFF"),
|
|
420
442
|
response, re.DOTALL)
|
|
421
443
|
|
|
422
444
|
# 读取原始文件内容
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
from typing import Any, Tuple
|
|
4
4
|
|
|
5
|
-
from jarvis.jarvis_tools.registry import ToolRegistry
|
|
6
5
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
7
6
|
from jarvis.jarvis_utils.utils import user_confirm
|
|
8
7
|
|
|
@@ -16,6 +15,7 @@ def shell_input_handler(user_input: str, agent: Any) -> Tuple[str, bool]:
|
|
|
16
15
|
script = '\n'.join([c[1:] for c in cmdline])
|
|
17
16
|
PrettyOutput.print(script, OutputType.CODE, lang="bash")
|
|
18
17
|
if user_confirm(f"是否要执行以上shell脚本?", default=True):
|
|
18
|
+
from jarvis.jarvis_tools.registry import ToolRegistry
|
|
19
19
|
output = ToolRegistry().handle_tool_calls({
|
|
20
20
|
"name": "execute_shell_script",
|
|
21
21
|
"arguments": {
|