jarvis-ai-assistant 0.1.126__py3-none-any.whl → 0.1.129__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 (42) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/__init__.py +108 -95
  3. jarvis/jarvis_agent/main.py +77 -0
  4. jarvis/jarvis_code_agent/builtin_input_handler.py +43 -0
  5. jarvis/jarvis_code_agent/code_agent.py +17 -81
  6. jarvis/jarvis_code_agent/file_input_handler.py +88 -0
  7. jarvis/jarvis_code_agent/patch.py +142 -114
  8. jarvis/jarvis_code_agent/shell_input_handler.py +8 -2
  9. jarvis/jarvis_codebase/main.py +240 -213
  10. jarvis/jarvis_dev/main.py +4 -3
  11. jarvis/jarvis_multi_agent/__init__.py +51 -40
  12. jarvis/jarvis_platform/base.py +6 -5
  13. jarvis/jarvis_platform_manager/main.py +1 -1
  14. jarvis/jarvis_rag/main.py +250 -186
  15. jarvis/jarvis_smart_shell/main.py +0 -1
  16. jarvis/jarvis_tools/ask_codebase.py +4 -3
  17. jarvis/jarvis_tools/chdir.py +22 -22
  18. jarvis/jarvis_tools/code_review.py +38 -33
  19. jarvis/jarvis_tools/execute_shell.py +0 -3
  20. jarvis/jarvis_tools/file_operation.py +56 -55
  21. jarvis/jarvis_tools/git_commiter.py +60 -50
  22. jarvis/jarvis_tools/read_code.py +143 -0
  23. jarvis/jarvis_tools/read_webpage.py +50 -30
  24. jarvis/jarvis_tools/registry.py +4 -21
  25. jarvis/jarvis_tools/search_web.py +61 -36
  26. jarvis/jarvis_tools/tool_generator.py +78 -36
  27. jarvis/jarvis_utils/__init__.py +17 -17
  28. jarvis/jarvis_utils/config.py +87 -51
  29. jarvis/jarvis_utils/embedding.py +49 -48
  30. jarvis/jarvis_utils/git_utils.py +34 -34
  31. jarvis/jarvis_utils/globals.py +26 -26
  32. jarvis/jarvis_utils/input.py +61 -45
  33. jarvis/jarvis_utils/methodology.py +94 -76
  34. jarvis/jarvis_utils/output.py +63 -62
  35. jarvis/jarvis_utils/utils.py +2 -2
  36. {jarvis_ai_assistant-0.1.126.dist-info → jarvis_ai_assistant-0.1.129.dist-info}/METADATA +1 -1
  37. jarvis_ai_assistant-0.1.129.dist-info/RECORD +78 -0
  38. {jarvis_ai_assistant-0.1.126.dist-info → jarvis_ai_assistant-0.1.129.dist-info}/entry_points.txt +2 -0
  39. jarvis_ai_assistant-0.1.126.dist-info/RECORD +0 -74
  40. {jarvis_ai_assistant-0.1.126.dist-info → jarvis_ai_assistant-0.1.129.dist-info}/LICENSE +0 -0
  41. {jarvis_ai_assistant-0.1.126.dist-info → jarvis_ai_assistant-0.1.129.dist-info}/WHEEL +0 -0
  42. {jarvis_ai_assistant-0.1.126.dist-info → jarvis_ai_assistant-0.1.129.dist-info}/top_level.txt +0 -0
@@ -2,11 +2,14 @@ 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
10
  from jarvis.jarvis_tools.execute_shell_script import ShellScriptTool
9
11
  from jarvis.jarvis_tools.file_operation import FileOperationTool
12
+ from jarvis.jarvis_tools.read_code import ReadCodeTool
10
13
  from jarvis.jarvis_utils.config import is_confirm_before_apply_patch
11
14
  from jarvis.jarvis_utils.git_utils import get_commits_between, get_latest_commit_hash
12
15
  from jarvis.jarvis_utils.input import get_multiline_input
@@ -37,7 +40,7 @@ Reason: [修改原因]
37
40
  --------------------------------
38
41
  规则:
39
42
  1. 代码片段必须包含足够的上下文(前后各3行)
40
- 2. 我可以看到完整代码,所以只需显示修改的代码部分
43
+ 2. 我可以看到完整代码,所以只需显示修改的代码部分,不需要将整个文件内容都显示出来
41
44
  3. 保留原始缩进和格式
42
45
  4. 对于新文件,提供完整代码
43
46
  5. 修改现有文件时,保留周围未更改的代码
@@ -73,55 +76,63 @@ def _parse_patch(patch_str: str) -> Dict[str, str]:
73
76
 
74
77
  def apply_patch(output_str: str) -> str:
75
78
  """Apply patches to files"""
76
- try:
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():
79
+ with yaspin(text="正在应用补丁...", color="cyan") as spinner:
87
80
  try:
88
- handle_code_operation(filepath, patch_content)
89
- PrettyOutput.print(f"文件 {filepath} 处理完成", OutputType.SUCCESS)
81
+ patches = _parse_patch(output_str)
90
82
  except Exception as e:
91
- revert_file(filepath) # 回滚单个文件
92
- PrettyOutput.print(f"文件 {filepath} 处理失败: {str(e)}", OutputType.ERROR)
93
-
94
- final_ret = ""
95
- diff = get_diff()
96
- if diff:
97
- PrettyOutput.print(diff, OutputType.CODE, lang="diff")
98
- if handle_commit_workflow():
99
- # 获取提交信息
100
- end_hash = get_latest_commit_hash()
101
- commits = get_commits_between(start_hash, end_hash)
102
-
103
- # 添加提交信息到final_ret
104
- if commits:
105
- final_ret += "✅ 补丁已应用\n"
106
- final_ret += "提交信息:\n"
107
- for commit_hash, commit_message in commits:
108
- final_ret += f"- {commit_hash[:7]}: {commit_message}\n"
83
+ PrettyOutput.print(f"解析补丁失败: {str(e)}", OutputType.ERROR)
84
+ return ""
85
+
86
+ # 获取当前提交hash作为起始点
87
+ spinner.text= "开始获取当前提交hash..."
88
+ start_hash = get_latest_commit_hash()
89
+ spinner.write("✅ 当前提交hash获取完成")
90
+
91
+ # 按文件逐个处理
92
+ for filepath, patch_content in patches.items():
93
+ try:
94
+ spinner.text = f"正在处理文件: {filepath}"
95
+ with spinner.hidden():
96
+ handle_code_operation(filepath, patch_content)
97
+ spinner.write(f"✅ 文件 {filepath} 处理完成")
98
+ except Exception as e:
99
+ spinner.text = f"文件 {filepath} 处理失败: {str(e)}, 回滚文件"
100
+ revert_file(filepath) # 回滚单个文件
101
+ spinner.write(f"✅ 文件 {filepath} 回滚完成")
102
+
103
+ final_ret = ""
104
+ diff = get_diff()
105
+ if diff:
106
+ PrettyOutput.print(diff, OutputType.CODE, lang="diff")
107
+ with spinner.hidden():
108
+ commited = handle_commit_workflow()
109
+ if commited:
110
+ # 获取提交信息
111
+ end_hash = get_latest_commit_hash()
112
+ commits = get_commits_between(start_hash, end_hash)
109
113
 
110
- final_ret += f"应用补丁后的代码:\n{diff}"
111
-
114
+ # 添加提交信息到final_ret
115
+ if commits:
116
+ final_ret += "✅ 补丁已应用\n"
117
+ final_ret += "提交信息:\n"
118
+ for commit_hash, commit_message in commits:
119
+ final_ret += f"- {commit_hash[:7]}: {commit_message}\n"
120
+
121
+ final_ret += f"应用补丁:\n{diff}"
122
+
123
+ else:
124
+ final_ret += "✅ 补丁已应用(没有新的提交)"
112
125
  else:
113
- final_ret += " 补丁已应用(没有新的提交)"
126
+ final_ret += " 我不想提交代码\n"
127
+ final_ret += "补丁预览:\n"
128
+ final_ret += diff
114
129
  else:
115
- final_ret += "❌ 我不想提交代码\n"
116
- final_ret += "之前的代码:\n"
117
- final_ret += diff
118
- else:
119
- final_ret += "❌ 没有要提交的更改\n"
120
- # 用户确认最终结果
121
- PrettyOutput.print(final_ret, OutputType.USER)
122
- if not is_confirm_before_apply_patch() or user_confirm("是否使用此回复?", default=True):
123
- return final_ret
124
- return get_multiline_input("请输入自定义回复")
130
+ final_ret += "❌ 没有要提交的更改\n"
131
+ # 用户确认最终结果
132
+ PrettyOutput.print(final_ret, OutputType.USER)
133
+ if not is_confirm_before_apply_patch() or user_confirm("是否使用此回复?", default=True):
134
+ return final_ret
135
+ return get_multiline_input("请输入自定义回复")
125
136
  def revert_file(filepath: str):
126
137
  """增强版git恢复,处理新文件"""
127
138
  import subprocess
@@ -174,75 +185,92 @@ def handle_commit_workflow()->bool:
174
185
  commit_result = git_commiter.execute({})
175
186
  return commit_result["success"]
176
187
 
177
- # New handler functions below ▼▼▼
178
- def handle_code_operation(filepath: str, patch_content: str) -> str:
188
+
189
+ def handle_code_operation(filepath: str, patch_content: str) -> bool:
179
190
  """处理基于上下文的代码片段"""
180
- try:
181
- if not os.path.exists(filepath):
182
- # 新建文件
183
- os.makedirs(os.path.dirname(filepath), exist_ok=True)
184
- open(filepath, 'w', encoding='utf-8').close()
185
- old_file_content = FileOperationTool().execute({"operation": "read", "files": [{"path": filepath}]})
186
- if not old_file_content["success"]:
187
- return f"文件读取失败: {old_file_content['stderr']}"
188
-
189
- prompt = f"""
190
- 你是一个代码审查员,请审查以下代码并将其与上下文合并。
191
- 原始代码:
192
- {old_file_content["stdout"]}
193
- 补丁内容:
194
- {patch_content}
195
- """
196
- prompt += f"""
197
- 请将代码与上下文合并并返回完整的合并代码。
191
+ with yaspin(text=f"正在修改文件 {filepath}...", color="cyan") as spinner:
192
+ try:
193
+ if not os.path.exists(filepath):
194
+ # 新建文件
195
+ spinner.text = "文件不存在,正在创建文件..."
196
+ os.makedirs(os.path.dirname(filepath), exist_ok=True)
197
+ open(filepath, 'w', encoding='utf-8').close()
198
+ spinner.write(" 文件创建完成")
199
+ with spinner.hidden():
200
+ old_file_content = FileOperationTool().execute({"operation": "read", "files": [{"path": filepath}]})
201
+ if not old_file_content["success"]:
202
+ spinner.write("❌ 文件读取失败")
203
+ return False
204
+
205
+ prompt = f"""
206
+ 你是一个代码审查员,请审查以下代码并将其与上下文合并。
207
+ 原始代码:
208
+ {old_file_content["stdout"]}
209
+ 补丁内容:
210
+ {patch_content}
211
+ """
212
+ prompt += f"""
213
+ 请将代码与上下文合并并返回完整的合并代码,每次最多输出300行代码。
198
214
 
199
- 要求:
200
- 1. 严格保留原始代码的格式、空行和缩进
201
- 2. 仅在<MERGED_CODE>块中包含实际代码内容,包括空行和缩进
202
- 3. 绝对不要使用markdown代码块(```)或反引号,除非修改的是markdown文件
203
- 4. 除了合并后的代码,不要输出任何其他文本
215
+ 要求:
216
+ 1. 严格保留原始代码的格式、空行和缩进
217
+ 2. 仅在<MERGED_CODE>块中包含实际代码内容,包括空行和缩进
218
+ 3. 绝对不要使用markdown代码块(```)或反引号,除非修改的是markdown文件
219
+ 4. 除了合并后的代码,不要输出任何其他文本
220
+ 5. 所有代码输出完成后,输出<!!!FINISHED!!!>
204
221
 
205
- 输出格式:
206
- <MERGED_CODE>
207
- [merged_code]
208
- </MERGED_CODE>
209
- """
210
- model = PlatformRegistry().get_codegen_platform()
211
- model.set_suppress_output(False)
212
- count = 5
213
- start_line = -1
214
- end_line = -1
215
- response = []
216
- while count > 0:
217
- count -= 1
218
- response.extend(model.chat_until_success(prompt).splitlines())
219
- try:
220
- start_line = response.index("<MERGED_CODE>") + 1
221
- except:
222
- pass
223
- try:
224
- end_line = response.index("</MERGED_CODE>")
225
- except:
226
- pass
227
- if start_line == -1:
228
- PrettyOutput.print(f"❌ 为文件 {filepath} 应用补丁失败", OutputType.WARNING)
229
- return f"代码合并失败"
230
- if end_line == -1:
231
- last_line = response[-1]
232
- prompt = f"""
233
- 继续从最后一行开始(不要包含<MERGED_CODE>标签,完成后输出</MERGED_CODE>标签):
234
- {last_line}
235
- """
236
- response.pop() # 删除最后一行
237
- continue
238
- if end_line < start_line:
239
- PrettyOutput.print(f"❌ 为文件 {filepath} 应用补丁失败", OutputType.WARNING)
240
- return f"代码合并失败"
241
- break
242
- # 写入合并后的代码
243
- with open(filepath, 'w', encoding='utf-8') as f:
244
- f.write("\n".join(response[start_line:end_line])+"\n")
245
- PrettyOutput.print(f"✅ 为文件 {filepath} 应用补丁成功", OutputType.SUCCESS)
246
- return ""
247
- except Exception as e:
248
- return f"文件操作失败: {str(e)}"
222
+ 输出格式:
223
+ <MERGED_CODE>
224
+ [merged_code]
225
+ </MERGED_CODE>
226
+ """
227
+ model = PlatformRegistry().get_codegen_platform()
228
+ model.set_suppress_output(True)
229
+ count = 30
230
+ start_line = -1
231
+ end_line = -1
232
+ code = []
233
+ finished = False
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
+ try:
240
+ end_line = response.index("</MERGED_CODE>")
241
+ code = response[start_line:end_line]
242
+ except:
243
+ pass
244
+ except:
245
+ pass
246
+
247
+ try:
248
+ response.index("<!!!FINISHED!!!>")
249
+ finished = True
250
+ break
251
+ except:
252
+ prompt += f"""继续输出接下来的300行代码
253
+ 要求:
254
+ 1. 严格保留原始代码的格式、空行和缩进
255
+ 2. 仅在<MERGED_CODE>块中包含实际代码内容,包括空行和缩进
256
+ 3. 绝对不要使用markdown代码块(```)或反引号,除非修改的是markdown文件
257
+ 4. 除了合并后的代码,不要输出任何其他文本
258
+ 5. 所有代码输出完成后,输出<!!!FINISHED!!!>
259
+ """
260
+ pass
261
+ if not finished:
262
+ spinner.text = "生成代码失败"
263
+ spinner.fail("")
264
+ return False
265
+ # 写入合并后的代码
266
+ spinner.text = "写入合并后的代码..."
267
+ with open(filepath, 'w', encoding='utf-8') as f:
268
+ f.write("\n".join(code)+"\n")
269
+ spinner.write("✅ 合并后的代码写入完成")
270
+ spinner.text = "代码修改完成"
271
+ spinner.ok("✅")
272
+ return True
273
+ except Exception as e:
274
+ spinner.text = "代码修改失败"
275
+ spinner.fail("❌")
276
+ return False
@@ -3,6 +3,7 @@
3
3
  from typing import Any, Tuple
4
4
 
5
5
  from jarvis.jarvis_tools.execute_shell_script import ShellScriptTool
6
+ from jarvis.jarvis_tools.registry import ToolRegistry
6
7
  from jarvis.jarvis_utils.output import OutputType, PrettyOutput
7
8
  from jarvis.jarvis_utils.utils import user_confirm
8
9
 
@@ -16,7 +17,12 @@ def shell_input_handler(user_input: str, agent: Any) -> Tuple[str, bool]:
16
17
  script = '\n'.join([c[1:] for c in cmdline])
17
18
  PrettyOutput.print(script, OutputType.CODE, lang="bash")
18
19
  if user_confirm(f"是否要执行以上shell脚本?", default=True):
19
- ShellScriptTool().execute({"script_content": script})
20
- return "", True
20
+ output = ToolRegistry().handle_tool_calls({
21
+ "name": "execute_shell_script",
22
+ "arguments": {
23
+ "script_content": script
24
+ }
25
+ })
26
+ return f"{user_input}\n\n用户执行以下脚本:\n{script}\n\n执行结果:\n{output}", False
21
27
  return user_input, False
22
28