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.

Files changed (75) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/__init__.py +165 -285
  3. jarvis/jarvis_agent/jarvis.py +143 -0
  4. jarvis/jarvis_agent/main.py +0 -2
  5. jarvis/jarvis_agent/patch.py +70 -48
  6. jarvis/jarvis_agent/shell_input_handler.py +1 -1
  7. jarvis/jarvis_code_agent/code_agent.py +169 -117
  8. jarvis/jarvis_dev/main.py +327 -626
  9. jarvis/jarvis_git_squash/main.py +10 -31
  10. jarvis/jarvis_lsp/base.py +0 -42
  11. jarvis/jarvis_lsp/cpp.py +0 -15
  12. jarvis/jarvis_lsp/go.py +0 -15
  13. jarvis/jarvis_lsp/python.py +0 -19
  14. jarvis/jarvis_lsp/registry.py +0 -62
  15. jarvis/jarvis_lsp/rust.py +0 -15
  16. jarvis/jarvis_multi_agent/__init__.py +19 -69
  17. jarvis/jarvis_multi_agent/main.py +43 -0
  18. jarvis/jarvis_platform/ai8.py +7 -32
  19. jarvis/jarvis_platform/base.py +2 -7
  20. jarvis/jarvis_platform/kimi.py +3 -144
  21. jarvis/jarvis_platform/ollama.py +54 -68
  22. jarvis/jarvis_platform/openai.py +0 -4
  23. jarvis/jarvis_platform/oyi.py +0 -75
  24. jarvis/jarvis_platform/registry.py +2 -16
  25. jarvis/jarvis_platform/yuanbao.py +264 -0
  26. jarvis/jarvis_rag/file_processors.py +138 -0
  27. jarvis/jarvis_rag/main.py +1305 -425
  28. jarvis/jarvis_tools/ask_codebase.py +216 -43
  29. jarvis/jarvis_tools/code_review.py +158 -113
  30. jarvis/jarvis_tools/create_sub_agent.py +0 -1
  31. jarvis/jarvis_tools/execute_python_script.py +58 -0
  32. jarvis/jarvis_tools/execute_shell.py +13 -26
  33. jarvis/jarvis_tools/execute_shell_script.py +1 -1
  34. jarvis/jarvis_tools/file_analyzer.py +282 -0
  35. jarvis/jarvis_tools/file_operation.py +1 -1
  36. jarvis/jarvis_tools/find_caller.py +278 -0
  37. jarvis/jarvis_tools/find_symbol.py +295 -0
  38. jarvis/jarvis_tools/function_analyzer.py +331 -0
  39. jarvis/jarvis_tools/git_commiter.py +5 -5
  40. jarvis/jarvis_tools/methodology.py +88 -53
  41. jarvis/jarvis_tools/project_analyzer.py +308 -0
  42. jarvis/jarvis_tools/rag.py +0 -5
  43. jarvis/jarvis_tools/read_code.py +24 -3
  44. jarvis/jarvis_tools/read_webpage.py +195 -81
  45. jarvis/jarvis_tools/registry.py +132 -11
  46. jarvis/jarvis_tools/search_web.py +22 -307
  47. jarvis/jarvis_tools/tool_generator.py +8 -10
  48. jarvis/jarvis_utils/__init__.py +1 -0
  49. jarvis/jarvis_utils/config.py +80 -76
  50. jarvis/jarvis_utils/embedding.py +344 -45
  51. jarvis/jarvis_utils/git_utils.py +9 -1
  52. jarvis/jarvis_utils/input.py +7 -6
  53. jarvis/jarvis_utils/methodology.py +384 -15
  54. jarvis/jarvis_utils/output.py +5 -3
  55. jarvis/jarvis_utils/utils.py +60 -8
  56. {jarvis_ai_assistant-0.1.131.dist-info → jarvis_ai_assistant-0.1.134.dist-info}/METADATA +8 -16
  57. jarvis_ai_assistant-0.1.134.dist-info/RECORD +82 -0
  58. {jarvis_ai_assistant-0.1.131.dist-info → jarvis_ai_assistant-0.1.134.dist-info}/entry_points.txt +4 -3
  59. jarvis/jarvis_codebase/__init__.py +0 -0
  60. jarvis/jarvis_codebase/main.py +0 -1011
  61. jarvis/jarvis_tools/lsp_find_definition.py +0 -150
  62. jarvis/jarvis_tools/lsp_find_references.py +0 -127
  63. jarvis/jarvis_tools/treesitter_analyzer.py +0 -331
  64. jarvis/jarvis_treesitter/README.md +0 -104
  65. jarvis/jarvis_treesitter/__init__.py +0 -20
  66. jarvis/jarvis_treesitter/database.py +0 -258
  67. jarvis/jarvis_treesitter/example.py +0 -115
  68. jarvis/jarvis_treesitter/grammar_builder.py +0 -182
  69. jarvis/jarvis_treesitter/language.py +0 -117
  70. jarvis/jarvis_treesitter/symbol.py +0 -31
  71. jarvis/jarvis_treesitter/tools_usage.md +0 -121
  72. jarvis_ai_assistant-0.1.131.dist-info/RECORD +0 -85
  73. {jarvis_ai_assistant-0.1.131.dist-info → jarvis_ai_assistant-0.1.134.dist-info}/LICENSE +0 -0
  74. {jarvis_ai_assistant-0.1.131.dist-info → jarvis_ai_assistant-0.1.134.dist-info}/WHEEL +0 -0
  75. {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())
@@ -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
@@ -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
- 使用<PATCH>块来精确指定代码更改:
37
+ 使用{ot("PATCH")}块来精确指定代码更改:
34
38
  ```
35
- <PATCH>
39
+ {ot("PATCH")}
36
40
  File: [文件路径]
37
41
  Reason: [修改原因]
38
42
  [上下文代码片段]
39
- </PATCH>
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
- 4. **新旧区分**:
55
+ 5. **新旧区分**:
51
56
  - 对于新文件:提供完整的代码内容
52
- - 对于现有文件:保留周围未更改的代码,突出显示变更部分
53
- 5. **理由说明**:每个补丁必须包含清晰的修改理由,解释为什么需要此更改
57
+ - 对于现有文件:只提供修改部分及必要上下文,不要提供整个文件
58
+ 6. **理由说明**:每个补丁必须包含清晰的修改理由,解释为什么需要此更改
54
59
 
55
60
  ## 格式兼容性要求
56
61
  1. **缩进一致性**:
@@ -65,7 +70,7 @@ Reason: [修改原因]
65
70
 
66
71
  ## 补丁示例
67
72
  ```
68
- <PATCH>
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
- </PATCH>
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'<PATCH>\n?(.*?)\n?</PATCH>', patch_str, re.DOTALL)
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 += "❌ 我拒绝应用此补丁\n"
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
- PrettyOutput.print(final_ret, OutputType.USER)
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
- return get_multiline_input("请输入自定义回复")
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 = 3
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
- - 仅在<MERGED_CODE>标签内输出合并后的完整代码
305
+ - 仅在{ot("MERGED_CODE")}标签内输出合并后的完整代码
281
306
  - 每次最多输出300行代码
282
307
  - 不要使用markdown代码块(```)或反引号,除非修改的是markdown文件
283
308
  - 除了合并后的代码,不要输出任何其他文本
284
- - 所有代码输出完成后,输出<!!!FINISHED!!!>标记
309
+ - 所有代码输出完成后,输出{ot("!!!FINISHED!!!")}标记
285
310
 
286
311
  ## 输出模板
287
- <MERGED_CODE>
312
+ {ot("MERGED_CODE")}
288
313
  [合并后的完整代码,包括所有空行和缩进]
289
- </MERGED_CODE>
314
+ {ct("MERGED_CODE")}
290
315
  """
291
- model = PlatformRegistry().get_codegen_platform()
292
- model.set_suppress_output(False)
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
- with spinner.hidden():
301
- response = model.chat_until_success(prompt).splitlines()
325
+ response = model.chat_until_success(prompt).splitlines()
302
326
  try:
303
- start_line = response.index("<MERGED_CODE>") + 1
327
+ start_line = response.index(ot("MERGED_CODE")) + 1
304
328
  try:
305
- end_line = response.index("</MERGED_CODE>")
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("<!!!FINISHED!!!>")
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
- - 仅在<MERGED_CODE>块中包含实际代码内容
349
+ - 仅在{ot("MERGED_CODE")}块中包含实际代码内容
326
350
  - 不要使用markdown代码块(```)或反引号
327
351
  - 除了合并后的代码,不要输出任何其他文本
328
- - 所有代码输出完成后,输出<!!!FINISHED!!!>标记
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 = PlatformRegistry().get_codegen_platform()
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
- - 使用<DIFF>块包围每个需要修改的代码段
391
- - 每个<DIFF>块必须包含SEARCH部分和REPLACE部分
413
+ - 使用{ot("DIFF")}块包围每个需要修改的代码段
414
+ - 每个{ot("DIFF")}块必须包含SEARCH部分和REPLACE部分
392
415
  - SEARCH部分是需要查找的原始代码
393
416
  - REPLACE部分是替换后的新代码
394
417
  - 确保SEARCH部分能在原文件中唯一匹配
395
- - 如果修改较大,可以使用多个<DIFF>块
418
+ - 如果修改较大,可以使用多个{ot("DIFF")}块
396
419
 
397
420
  ## 输出模板
398
- <DIFF>
421
+ {ot("DIFF")}
399
422
  >>>>>> SEARCH
400
423
  [需要查找的原始代码,包含足够上下文]
401
424
  ======
402
425
  [替换后的新代码]
403
426
  <<<<<< REPLACE
404
- </DIFF>
427
+ {ct("DIFF")}
405
428
 
406
- <DIFF>
429
+ {ot("DIFF")}
407
430
  >>>>>> SEARCH
408
431
  [另一处需要查找的原始代码]
409
432
  ======
410
433
  [另一处替换后的新代码]
411
434
  <<<<<< REPLACE
412
- </DIFF>
435
+ {ct("DIFF")}
413
436
  """
414
437
  # 获取补丁内容
415
- with spinner.hidden():
416
- response = model.chat_until_success(prompt)
438
+ response = model.chat_until_success(prompt)
417
439
 
418
440
  # 解析差异化补丁
419
- diff_blocks = re.finditer(r'<DIFF>\s*>{4,} SEARCH\n?(.*?)\n?={4,}\n?(.*?)\s*<{4,} REPLACE\n?</DIFF>',
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": {