jarvis-ai-assistant 0.1.97__py3-none-any.whl → 0.1.99__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 (41) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/agent.py +199 -157
  3. jarvis/jarvis_code_agent/__init__.py +0 -0
  4. jarvis/jarvis_code_agent/main.py +203 -0
  5. jarvis/jarvis_codebase/main.py +412 -284
  6. jarvis/jarvis_coder/file_select.py +209 -0
  7. jarvis/jarvis_coder/git_utils.py +81 -19
  8. jarvis/jarvis_coder/main.py +68 -446
  9. jarvis/jarvis_coder/patch_handler.py +117 -47
  10. jarvis/jarvis_coder/plan_generator.py +69 -27
  11. jarvis/jarvis_platform/main.py +38 -38
  12. jarvis/jarvis_rag/main.py +189 -189
  13. jarvis/jarvis_smart_shell/main.py +22 -24
  14. jarvis/models/base.py +6 -1
  15. jarvis/models/ollama.py +2 -2
  16. jarvis/models/registry.py +3 -6
  17. jarvis/tools/ask_user.py +6 -6
  18. jarvis/tools/codebase_qa.py +5 -7
  19. jarvis/tools/create_code_sub_agent.py +55 -0
  20. jarvis/tools/{sub_agent.py → create_sub_agent.py} +4 -1
  21. jarvis/tools/execute_code_modification.py +72 -0
  22. jarvis/tools/{file_ops.py → file_operation.py} +13 -14
  23. jarvis/tools/find_related_files.py +86 -0
  24. jarvis/tools/methodology.py +25 -25
  25. jarvis/tools/rag.py +32 -32
  26. jarvis/tools/registry.py +72 -36
  27. jarvis/tools/search.py +1 -1
  28. jarvis/tools/select_code_files.py +64 -0
  29. jarvis/utils.py +153 -49
  30. {jarvis_ai_assistant-0.1.97.dist-info → jarvis_ai_assistant-0.1.99.dist-info}/METADATA +1 -1
  31. jarvis_ai_assistant-0.1.99.dist-info/RECORD +52 -0
  32. {jarvis_ai_assistant-0.1.97.dist-info → jarvis_ai_assistant-0.1.99.dist-info}/entry_points.txt +2 -1
  33. jarvis/main.py +0 -155
  34. jarvis/tools/coder.py +0 -69
  35. jarvis_ai_assistant-0.1.97.dist-info/RECORD +0 -47
  36. /jarvis/tools/{shell.py → execute_shell.py} +0 -0
  37. /jarvis/tools/{generator.py → generate_tool.py} +0 -0
  38. /jarvis/tools/{webpage.py → read_webpage.py} +0 -0
  39. {jarvis_ai_assistant-0.1.97.dist-info → jarvis_ai_assistant-0.1.99.dist-info}/LICENSE +0 -0
  40. {jarvis_ai_assistant-0.1.97.dist-info → jarvis_ai_assistant-0.1.99.dist-info}/WHEEL +0 -0
  41. {jarvis_ai_assistant-0.1.97.dist-info → jarvis_ai_assistant-0.1.99.dist-info}/top_level.txt +0 -0
@@ -1,10 +1,13 @@
1
1
  import re
2
2
  import os
3
3
  from typing import List, Tuple, Dict
4
+ import yaml
5
+ from pathlib import Path
4
6
 
7
+ from jarvis.jarvis_coder.git_utils import generate_commit_message, init_git_repo, save_edit_record
5
8
  from jarvis.models.base import BasePlatform
6
9
  from jarvis.models.registry import PlatformRegistry
7
- from jarvis.utils import OutputType, PrettyOutput, get_multiline_input, while_success
10
+ from jarvis.utils import OutputType, PrettyOutput, get_multiline_input, get_single_line_input, while_success
8
11
 
9
12
  class Patch:
10
13
  def __init__(self, old_code: str, new_code: str):
@@ -12,16 +15,41 @@ class Patch:
12
15
  self.new_code = new_code
13
16
 
14
17
  class PatchHandler:
18
+ def __init__(self):
19
+ self.prompt_file = Path.home() / ".jarvis-coder-patch-prompt"
20
+ self.additional_info = self._load_additional_info()
21
+ self.root_dir = init_git_repo(os.getcwd())
22
+ self.record_dir = os.path.join(self.root_dir, ".jarvis-coder", "record")
23
+ if not os.path.exists(self.record_dir):
24
+ os.makedirs(self.record_dir)
25
+ def _load_additional_info(self) -> str:
26
+ """Load saved additional info from prompt file"""
27
+ if not self.prompt_file.exists():
28
+ return ""
29
+ try:
30
+ with open(self.prompt_file, 'r') as f:
31
+ data = yaml.safe_load(f)
32
+ return data.get('additional_info', '') if data else ''
33
+ except Exception as e:
34
+ PrettyOutput.print(f"Failed to load additional info: {e}", OutputType.WARNING)
35
+ return ""
15
36
 
37
+ def _save_additional_info(self, info: str):
38
+ """Save additional info to prompt file"""
39
+ try:
40
+ with open(self.prompt_file, 'w') as f:
41
+ yaml.dump({'additional_info': info}, f)
42
+ except Exception as e:
43
+ PrettyOutput.print(f"Failed to save additional info: {e}", OutputType.WARNING)
16
44
 
17
45
  def _extract_patches(self, response: str) -> List[Patch]:
18
- """从响应中提取补丁
46
+ """Extract patches from response
19
47
 
20
48
  Args:
21
- response: 模型响应内容
49
+ response: Model response content
22
50
 
23
51
  Returns:
24
- List[Tuple[str, str, str]]: 补丁列表,每个补丁是 (格式, 文件路径, 补丁内容) 的元组
52
+ List[Tuple[str, str, str]]: Patch list, each patch is a tuple of (format, file path, patch content)
25
53
  """
26
54
  # 修改后的正则表达式匹配三种补丁格式
27
55
  fmt_pattern = r'<PATCH>\n>>>>>> SEARCH\n(.*?)\n?(={5,})\n(.*?)\n?<<<<<< REPLACE\n</PATCH>'
@@ -32,21 +60,53 @@ class PatchHandler:
32
60
 
33
61
 
34
62
  def _confirm_and_apply_changes(self, file_path: str) -> bool:
35
- """确认并应用修改"""
63
+ """Confirm and apply changes"""
36
64
  os.system(f"git diff --cached {file_path}")
37
- confirm = input(f"\n是否接受 {file_path} 的修改?(y/n) [y]: ").lower() or "y"
65
+ confirm = get_single_line_input(f"Accept {file_path} changes? (y/n) [y]").lower() or "y"
38
66
  if confirm == "y":
39
67
  return True
40
68
  else:
41
- # 回退修改
69
+ # Rollback changes
42
70
  os.system(f"git reset {file_path}")
43
71
  os.system(f"git checkout -- {file_path}")
44
- PrettyOutput.print(f"已回退 {file_path} 的修改", OutputType.WARNING)
72
+ PrettyOutput.print(f"Changes to {file_path} have been rolled back", OutputType.WARNING)
45
73
  return False
74
+
75
+
76
+
77
+ def _finalize_changes(self) -> None:
78
+ """Complete changes and commit"""
79
+ PrettyOutput.print("Modification confirmed, committing...", OutputType.INFO)
80
+
81
+ # Add only modified files under git control
82
+ os.system("git add -u")
83
+
84
+ # Then get git diff
85
+ git_diff = os.popen("git diff --cached").read()
86
+
87
+ # Automatically generate commit information, pass in feature
88
+ commit_message = generate_commit_message(git_diff)
89
+
90
+ # Display and confirm commit information
91
+ PrettyOutput.print(f"Automatically generated commit information: {commit_message}", OutputType.INFO)
92
+ user_confirm = get_single_line_input("Use this commit information? (y/n) [y]").lower() or "y"
93
+
94
+ if user_confirm.lower() != "y":
95
+ commit_message = get_single_line_input("Please enter a new commit information")
96
+
97
+ # No need to git add again, it has already been added
98
+ os.system(f"git commit -m '{commit_message}'")
99
+ save_edit_record(self.record_dir, commit_message, git_diff)
100
+
101
+ def _revert_changes(self) -> None:
102
+ """Revert all changes"""
103
+ PrettyOutput.print("Modification cancelled, reverting changes", OutputType.INFO)
104
+ os.system(f"git reset --hard")
105
+ os.system(f"git clean -df")
46
106
 
47
107
 
48
108
  def apply_file_patch(self, file_path: str, patches: List[Patch]) -> bool:
49
- """应用文件补丁"""
109
+ """Apply file patch"""
50
110
  if not os.path.exists(file_path):
51
111
  base_dir = os.path.dirname(file_path)
52
112
  os.makedirs(base_dir, exist_ok=True)
@@ -54,20 +114,20 @@ class PatchHandler:
54
114
  file_content = open(file_path, "r", encoding="utf-8").read()
55
115
  for i, patch in enumerate(patches):
56
116
  if patch.old_code == "" and patch.new_code == "":
57
- PrettyOutput.print(f"应用第 {i+1}/{len(patches)} 个补丁:删除文件 {file_path}", OutputType.INFO)
117
+ PrettyOutput.print(f"Apply patch {i+1}/{len(patches)}: Delete file {file_path}", OutputType.INFO)
58
118
  file_content = ""
59
119
  os.system(f"git rm {file_path}")
60
- PrettyOutput.print(f"应用第 {i+1}/{len(patches)} 个补丁成功", OutputType.SUCCESS)
120
+ PrettyOutput.print(f"Apply patch {i+1}/{len(patches)} successfully", OutputType.SUCCESS)
61
121
  elif patch.old_code == "":
62
- PrettyOutput.print(f"应用第 {i+1}/{len(patches)} 个补丁:替换文件 {file_path} 内容:\n{patch.new_code}", OutputType.INFO)
122
+ PrettyOutput.print(f"Apply patch {i+1}/{len(patches)}: Replace file {file_path} content: \n{patch.new_code}", OutputType.INFO)
63
123
  file_content = patch.new_code
64
124
  open(file_path, "w", encoding="utf-8").write(patch.new_code)
65
125
  os.system(f"git add {file_path}")
66
- PrettyOutput.print(f"应用第 {i+1}/{len(patches)} 个补丁成功", OutputType.SUCCESS)
126
+ PrettyOutput.print(f"Apply patch {i+1}/{len(patches)} successfully", OutputType.SUCCESS)
67
127
  else:
68
- PrettyOutput.print(f"应用第 {i+1}/{len(patches)} 个补丁:文件原始内容:\n{patch.old_code}\n替换为:\n{patch.new_code}", OutputType.INFO)
128
+ PrettyOutput.print(f"Apply patch {i+1}/{len(patches)}: File original content: \n{patch.old_code}\nReplace with: \n{patch.new_code}", OutputType.INFO)
69
129
  if file_content.find(patch.old_code) == -1:
70
- PrettyOutput.print(f"文件 {file_path} 中不存在 {patch.old_code}", OutputType.WARNING)
130
+ PrettyOutput.print(f"File {file_path} does not contain {patch.old_code}", OutputType.WARNING)
71
131
  os.system(f"git reset {file_path}")
72
132
  os.system(f"git checkout -- {file_path}")
73
133
  return False
@@ -75,28 +135,36 @@ class PatchHandler:
75
135
  file_content = file_content.replace(patch.old_code, patch.new_code, 1)
76
136
  open(file_path, "w", encoding="utf-8").write(file_content)
77
137
  os.system(f"git add {file_path}")
78
- PrettyOutput.print(f"应用第 {i+1}/{len(patches)} 个补丁成功", OutputType.SUCCESS)
138
+ PrettyOutput.print(f"Apply patch {i+1}/{len(patches)} successfully", OutputType.SUCCESS)
79
139
  return True
80
140
 
81
141
 
82
- def retry_comfirm(self) -> Tuple[str, str]:# 恢复用户选择逻辑
83
- choice = input("\n请选择操作: (1) 重试 (2) 跳过 (3) 完全中止 [1]: ") or "1"
142
+ def retry_comfirm(self) -> Tuple[str, str]:
143
+ choice = get_single_line_input("\nPlease choose an action: (1) Retry (2) Skip (3) Completely stop [1]: ") or "1"
84
144
  if choice == "2":
85
145
  return "skip", ""
86
146
  if choice == "3":
87
147
  return "break", ""
88
- return "continue", get_multiline_input("请输入补充说明和要求:")
148
+
149
+ feedback = get_multiline_input("Please enter additional information and requirements:")
150
+ if feedback:
151
+ save_prompt = get_single_line_input("Would you like to save this as general feedback for future patches? (y/n) [n]: ").lower() or "n"
152
+ if save_prompt == "y":
153
+ self._save_additional_info(feedback)
154
+ PrettyOutput.print("Feedback saved for future use", OutputType.SUCCESS)
155
+
156
+ return "continue", feedback
89
157
 
90
- def apply_patch(self, feature: str, raw_plan: str, structed_plan: Dict[str, str]) -> Tuple[bool, str]:
91
- """应用补丁(主入口)"""
158
+ def apply_patch(self, feature: str, structed_plan: Dict[str, str]) -> bool:
159
+ """Apply patch (main entry)"""
92
160
  for file_path, current_plan in structed_plan.items():
93
- additional_info = ""
161
+ additional_info = self.additional_info # Initialize with saved info
94
162
  while True:
95
163
 
96
164
  if os.path.exists(file_path):
97
165
  content = open(file_path, "r", encoding="utf-8").read()
98
166
  else:
99
- content = "<文件不存在,需要创建>"
167
+ content = "<File does not exist, need to create>"
100
168
  prompt = """You are a senior software development expert who can generate code patches based on the complete modification plan, current original code file path, code content, and current file's modification plan. The output format should be as follows:
101
169
  <PATCH>
102
170
  >>>>>> SEARCH
@@ -114,16 +182,17 @@ class PatchHandler:
114
182
  2. old_code will be replaced with new_code, pay attention to context continuity
115
183
  3. Avoid breaking existing code logic when generating patches, e.g., don't insert function definitions inside existing function bodies
116
184
  4. Include sufficient context to avoid ambiguity
117
- 5. Patches will be merged using file_content.replace(patch.old_code, patch.new_code, 1), so old_code and new_code need to match exactly, including empty lines, line breaks, whitespace, tabs, and comments
185
+ 5. Patches will be merged using file_content.replace(patch.old_code, patch.new_code, 1), so old_code and new_code need to match exactly, including EMPTY LINES, LINE BREAKS, WHITESPACE, TABS, and COMMENTS
118
186
  6. Ensure generated code has correct format (syntax, indentation, line breaks)
119
187
  7. Ensure new_code's indentation and format matches old_code
120
188
  8. Ensure code is inserted in appropriate locations, e.g., code using variables should be after declarations/definitions
121
189
  9. Provide at least 3 lines of context before and after modified code for location
190
+ 10. Each patch should be no more than 20 lines of code, if it is more than 20 lines, split it into multiple patches
191
+ 11. old code's line breaks should be consistent with the original code
122
192
 
123
193
 
124
194
  """
125
195
  prompt += f"""# Original requirement: {feature}
126
- # Complete modification plan: {raw_plan}
127
196
  # Current file path: {file_path}
128
197
  # Current file content:
129
198
  <CONTENT>
@@ -135,57 +204,58 @@ class PatchHandler:
135
204
  """
136
205
 
137
206
 
138
- PrettyOutput.print(f"{file_path}生成格式化补丁...", OutputType.PROGRESS)
207
+ PrettyOutput.print(f"Generating formatted patches for {file_path}...", OutputType.PROGRESS)
139
208
  response = PlatformRegistry.get_global_platform_registry().get_codegen_platform().chat_until_success(prompt)
140
209
  patches = self._extract_patches(response)
141
210
 
142
211
  if not patches or not self.apply_file_patch(file_path, patches) or not self._confirm_and_apply_changes(file_path):
143
212
  os.system(f"git reset {file_path}")
144
213
  os.system(f"git checkout -- {file_path}")
145
- PrettyOutput.print("补丁生成失败", OutputType.WARNING)
214
+ PrettyOutput.print("Patch generation failed", OutputType.WARNING)
146
215
  act, msg = self.retry_comfirm()
147
216
  if act == "break":
148
- PrettyOutput.print("终止补丁应用", OutputType.WARNING)
149
- return False, msg
217
+ PrettyOutput.print("Terminate patch application", OutputType.WARNING)
218
+ return False
150
219
  if act == "skip":
151
- PrettyOutput.print(f"跳过文件 {file_path}", OutputType.WARNING)
220
+ PrettyOutput.print(f"Skip file {file_path}", OutputType.WARNING)
152
221
  break
153
222
  else:
154
223
  additional_info += msg + "\n"
155
224
  continue
156
225
  else:
226
+ self._finalize_changes()
157
227
  break
158
228
 
159
- return True, ""
229
+ return True
160
230
 
161
231
 
162
232
 
163
- def handle_patch_application(self, feature: str, raw_plan: str, structed_plan: Dict[str,str]) -> bool:
164
- """处理补丁应用流程
233
+ def handle_patch_application(self, feature: str, structed_plan: Dict[str,str]) -> bool:
234
+ """Process patch application process
165
235
 
166
236
  Args:
167
- related_files: 相关文件列表
168
- feature: 功能描述
169
- modification_plan: 修改方案
237
+ related_files: Related files list
238
+ feature: Feature description
239
+ modification_plan: Modification plan
170
240
 
171
241
  Returns:
172
- bool: 是否成功应用补丁
242
+ bool: Whether patch application is successful
173
243
  """
174
- PrettyOutput.print("\n将要应用以下修改方案:", OutputType.INFO)
244
+ PrettyOutput.print("\nThe following modification plan will be applied:", OutputType.INFO)
175
245
  for file_path, patches_code in structed_plan.items():
176
- PrettyOutput.print(f"\n文件: {file_path}", OutputType.INFO)
177
- PrettyOutput.print(f"修改方案: \n{patches_code}", OutputType.INFO)
178
- # 3. 应用补丁
179
- success, error_msg = self.apply_patch(feature, raw_plan, structed_plan)
246
+ PrettyOutput.print(f"\nFile: {file_path}", OutputType.INFO)
247
+ PrettyOutput.print(f"Modification plan: \n{patches_code}", OutputType.INFO)
248
+ # 3. Apply patches
249
+ success = self.apply_patch(feature, structed_plan)
180
250
  if not success:
181
251
  os.system("git reset --hard")
182
252
  return False
183
- # 6. 应用成功,让用户确认修改
184
- PrettyOutput.print("\n补丁已应用,请检查修改效果。", OutputType.SUCCESS)
185
- confirm = input("\n是否保留这些修改?(y/n) [y]: ").lower() or "y"
253
+ # 6. Apply successfully, let user confirm changes
254
+ PrettyOutput.print("\nPatches applied, please check the modification effect.", OutputType.SUCCESS)
255
+ confirm = get_single_line_input("\nKeep these changes? (y/n) [y]: ").lower() or "y"
186
256
  if confirm != "y":
187
- PrettyOutput.print("用户取消修改,正在回退", OutputType.WARNING)
188
- os.system("git reset --hard") # 回退所有修改
257
+ PrettyOutput.print("User cancelled changes, rolling back", OutputType.WARNING)
258
+ os.system("git reset --hard") # Rollback all changes
189
259
  return False
190
260
  else:
191
261
  return True
@@ -1,21 +1,21 @@
1
1
  import re
2
2
  from typing import Dict, List, Tuple
3
3
  from jarvis.models.registry import PlatformRegistry
4
- from jarvis.utils import PrettyOutput, OutputType, get_multiline_input
4
+ from jarvis.utils import PrettyOutput, OutputType, get_multiline_input, get_single_line_input, is_long_context
5
5
 
6
6
  class PlanGenerator:
7
- """修改方案生成器"""
7
+ """Modification plan generator"""
8
8
 
9
9
  def _build_prompt(self, feature: str, related_files: List[Dict], additional_info: str) -> str:
10
- """构建提示词
10
+ """Build prompt
11
11
 
12
12
  Args:
13
- feature: 功能描述
14
- related_files: 相关文件列表
15
- additional_info: 用户补充信息
13
+ feature: Feature description
14
+ related_files: Related files list
15
+ additional_info: User supplement information
16
16
 
17
17
  Returns:
18
- str: 完整的提示词
18
+ str: Complete prompt
19
19
  """
20
20
  prompt = "You are a code modification expert who can generate modification plans based on requirements and relevant code snippets. I need your help to analyze how to implement the following feature:\n\n"
21
21
  prompt += f"{feature}\n\n"
@@ -48,52 +48,94 @@ class PlanGenerator:
48
48
  return prompt
49
49
 
50
50
 
51
- def generate_plan(self, feature: str, related_files: List[Dict]) -> Tuple[str, Dict[str,str]]:
52
- """生成修改方案
51
+ @staticmethod
52
+ def get_key_code(files: List[str], feature: str)->List[Dict[str, List[str]]]:
53
+ """Extract relevant key code snippets from files"""
54
+ ret = []
55
+ for file in files:
56
+ PrettyOutput.print(f"Analyzing file: {file}", OutputType.INFO)
57
+ model = PlatformRegistry.get_global_platform_registry().get_codegen_platform()
58
+ model.set_suppress_output(True)
59
+ file_path = file
60
+ content = open(file_path, "r", encoding="utf-8").read()
61
+
62
+ try:
63
+ prompt = f"""You are a code analysis expert who can extract relevant snippets from code.
64
+ Please return in the following format:
65
+ <PART>
66
+ content
67
+ </PART>
68
+
69
+ Multiple snippets can be returned. If the file content is not relevant to the requirement, return empty.
70
+
71
+ Requirement: {feature}
72
+ File path: {file_path}
73
+ Code content:
74
+ {content}
75
+ """
76
+
77
+ # 调用大模型进行分析
78
+ response = model.chat_until_success(prompt)
79
+
80
+ parts = re.findall(r'<PART>\n(.*?)\n</PART>', response, re.DOTALL)
81
+ ret.append({"file_path": file, "parts": parts})
82
+ except Exception as e:
83
+ PrettyOutput.print(f"Failed to analyze file: {str(e)}", OutputType.ERROR)
84
+ return ret
85
+
86
+ def generate_plan(self, feature: str, related_files: List[str]) -> Dict[str,str]:
87
+ """Generate modification plan
53
88
 
54
89
  Args:
55
- feature: 功能描述
56
- related_files: 相关文件列表
90
+ feature: Feature description
91
+ related_files: Related files list
57
92
 
58
93
  Returns:
59
- Tuple[str, Dict[str,str]]: 修改方案,如果用户取消则返回 None
94
+ Tuple[str, Dict[str,str]]: Modification plan, return None if user cancels
60
95
  """
61
96
  additional_info = ""
97
+ file_info = []
98
+ if is_long_context(related_files):
99
+ file_info = PlanGenerator.get_key_code(related_files, feature)
100
+ else:
101
+ for file in related_files:
102
+ file_info.append({"file_path": file, "parts": [open(file, "r", encoding="utf-8").read()]})
103
+
62
104
  while True:
63
- prompt = self._build_prompt(feature, related_files, additional_info)
64
- # 构建提示词
65
- PrettyOutput.print("开始生成修改方案...", OutputType.PROGRESS)
105
+ prompt = self._build_prompt(feature, file_info, additional_info)
106
+ # Build prompt
107
+ PrettyOutput.print("Start generating modification plan...", OutputType.PROGRESS)
66
108
 
67
- # 获取修改方案
109
+ # Get modification plan
68
110
  raw_plan = PlatformRegistry.get_global_platform_registry().get_thinking_platform().chat_until_success(prompt)
69
111
  structed_plan = self._extract_code(raw_plan)
70
112
  if not structed_plan:
71
- PrettyOutput.print("修改方案生成失败,请重试", OutputType.ERROR)
72
- tmp = get_multiline_input("请输入您的补充意见或建议(直接回车取消):")
113
+ PrettyOutput.print("Modification plan generation failed, please try again", OutputType.ERROR)
114
+ tmp = get_multiline_input("Please enter your additional information or suggestions (press Enter to cancel):")
73
115
  if tmp == "__interrupt__" or prompt == "":
74
- return "", {}
116
+ return {}
75
117
  additional_info += tmp + "\n"
76
118
  continue
77
- user_input = input("\n是否同意这个修改方案?(y/n) [y]: ").strip().lower() or 'y'
119
+ user_input = get_single_line_input("Do you agree with this modification plan? (y/n) [y]").strip().lower() or 'y'
78
120
  if user_input == 'y' or user_input == '':
79
- return raw_plan, structed_plan
121
+ return structed_plan
80
122
  elif user_input == 'n':
81
- # 获取用户反馈
82
- tmp = get_multiline_input("请输入您的补充意见或建议(直接回车取消):")
123
+ # Get user feedback
124
+ tmp = get_multiline_input("Please enter your additional information or suggestions (press Enter to cancel):")
83
125
  if prompt == "__interrupt__" or prompt == "":
84
- return "", {}
126
+ return {}
85
127
  additional_info += tmp + "\n"
86
128
  continue
87
129
 
88
130
 
89
131
  def _extract_code(self, response: str) -> Dict[str, str]:
90
- """从响应中提取代码
132
+ """Extract code from response
91
133
 
92
134
  Args:
93
- response: 模型响应内容
135
+ response: Model response content
94
136
 
95
137
  Returns:
96
- Dict[str, List[str]]: 代码字典,key为文件路径,value为代码片段列表
138
+ Dict[str, List[str]]: Code dictionary, key is file path, value is code snippet list
97
139
  """
98
140
  code_dict = {}
99
141
  for match in re.finditer(r'<PLAN>\n> (.+?)\n(.*?)\n</PLAN>', response, re.DOTALL):
@@ -2,26 +2,26 @@ from jarvis.models.registry import PlatformRegistry
2
2
  from jarvis.utils import PrettyOutput, OutputType, load_env_from_file, get_multiline_input
3
3
 
4
4
  def list_platforms():
5
- """列出所有支持的平台和模型"""
5
+ """List all supported platforms and models"""
6
6
  registry = PlatformRegistry.get_global_platform_registry()
7
7
  platforms = registry.get_available_platforms()
8
8
 
9
- PrettyOutput.section("支持的平台和模型", OutputType.SUCCESS)
9
+ PrettyOutput.section("Supported platforms and models", OutputType.SUCCESS)
10
10
 
11
11
  for platform_name in platforms:
12
- # 创建平台实例
12
+ # Create platform instance
13
13
  platform = registry.create_platform(platform_name)
14
14
  if not platform:
15
15
  continue
16
16
 
17
- # 获取平台支持的模型列表
17
+ # Get the list of models supported by the platform
18
18
  try:
19
19
  models = platform.get_model_list()
20
20
 
21
- # 打印平台名称
21
+ # Print platform name
22
22
  PrettyOutput.section(f"{platform_name}", OutputType.SUCCESS)
23
23
 
24
- # 打印模型列表
24
+ # Print model list
25
25
  if models:
26
26
  for model_name, description in models:
27
27
  if description:
@@ -29,95 +29,95 @@ def list_platforms():
29
29
  else:
30
30
  PrettyOutput.print(f" • {model_name}", OutputType.SUCCESS)
31
31
  else:
32
- PrettyOutput.print(" 没有可用的模型信息", OutputType.WARNING)
32
+ PrettyOutput.print(" • No available model information", OutputType.WARNING)
33
33
 
34
34
  except Exception as e:
35
- PrettyOutput.print(f"获取 {platform_name} 平台模型列表失败: {str(e)}", OutputType.WARNING)
35
+ PrettyOutput.print(f"Failed to get model list for {platform_name}: {str(e)}", OutputType.WARNING)
36
36
 
37
37
  def chat_with_model(platform_name: str, model_name: str):
38
- """与指定平台和模型进行对话"""
38
+ """Chat with specified platform and model"""
39
39
  registry = PlatformRegistry.get_global_platform_registry()
40
40
 
41
- # 创建平台实例
41
+ # Create platform instance
42
42
  platform = registry.create_platform(platform_name)
43
43
  if not platform:
44
- PrettyOutput.print(f"创建平台 {platform_name} 失败", OutputType.ERROR)
44
+ PrettyOutput.print(f"Failed to create platform {platform_name}", OutputType.ERROR)
45
45
  return
46
46
 
47
47
  try:
48
- # 设置模型
48
+ # Set model
49
49
  platform.set_model_name(model_name)
50
- PrettyOutput.print(f"已连接到 {platform_name} 平台的 {model_name} 模型", OutputType.SUCCESS)
50
+ PrettyOutput.print(f"Connected to {platform_name} platform {model_name} model", OutputType.SUCCESS)
51
51
 
52
- # 开始对话循环
52
+ # Start conversation loop
53
53
  while True:
54
- # 获取用户输入
54
+ # Get user input
55
55
  user_input = get_multiline_input("")
56
56
 
57
- # 检查是否取消输入
57
+ # Check if input is cancelled
58
58
  if user_input == "__interrupt__" or user_input.strip() == "/bye":
59
- PrettyOutput.print("再见!", OutputType.SUCCESS)
59
+ PrettyOutput.print("Bye!", OutputType.SUCCESS)
60
60
  break
61
61
 
62
- # 检查是否为空输入
62
+ # Check if input is empty
63
63
  if not user_input.strip():
64
64
  continue
65
65
 
66
- # 检查是否为清除会话命令
66
+ # Check if it is a clear session command
67
67
  if user_input.strip() == "/clear":
68
68
  try:
69
69
  platform.delete_chat()
70
- platform.set_model_name(model_name) # 重新初始化会话
71
- PrettyOutput.print("会话已清除", OutputType.SUCCESS)
70
+ platform.set_model_name(model_name) # Reinitialize session
71
+ PrettyOutput.print("Session cleared", OutputType.SUCCESS)
72
72
  except Exception as e:
73
- PrettyOutput.print(f"清除会话失败: {str(e)}", OutputType.ERROR)
73
+ PrettyOutput.print(f"Failed to clear session: {str(e)}", OutputType.ERROR)
74
74
  continue
75
75
 
76
76
  try:
77
- # 发送到模型并获取回复
77
+ # Send to model and get reply
78
78
  response = platform.chat_until_success(user_input)
79
79
  if not response:
80
- PrettyOutput.print("未获得有效回复", OutputType.WARNING)
80
+ PrettyOutput.print("No valid reply", OutputType.WARNING)
81
81
 
82
82
  except Exception as e:
83
- PrettyOutput.print(f"对话失败: {str(e)}", OutputType.ERROR)
83
+ PrettyOutput.print(f"Failed to chat: {str(e)}", OutputType.ERROR)
84
84
 
85
85
  except Exception as e:
86
- PrettyOutput.print(f"初始化对话失败: {str(e)}", OutputType.ERROR)
86
+ PrettyOutput.print(f"Failed to initialize conversation: {str(e)}", OutputType.ERROR)
87
87
  finally:
88
- # 清理资源
88
+ # Clean up resources
89
89
  try:
90
90
  platform.delete_chat()
91
91
  except:
92
92
  pass
93
93
 
94
94
  def info_command(args):
95
- """处理 info 子命令"""
95
+ """Process info subcommand"""
96
96
  list_platforms()
97
97
 
98
98
  def chat_command(args):
99
- """处理 chat 子命令"""
99
+ """Process chat subcommand"""
100
100
  if not args.platform or not args.model:
101
- PrettyOutput.print("请指定平台和模型。使用 'jarvis info' 查看可用的平台和模型。", OutputType.ERROR)
101
+ PrettyOutput.print("Please specify platform and model. Use 'jarvis info' to view available platforms and models.", OutputType.ERROR)
102
102
  return
103
103
  chat_with_model(args.platform, args.model)
104
104
 
105
105
  def main():
106
- """主函数"""
106
+ """Main function"""
107
107
  import argparse
108
108
 
109
109
  load_env_from_file()
110
110
 
111
111
  parser = argparse.ArgumentParser(description='Jarvis AI Platform')
112
- subparsers = parser.add_subparsers(dest='command', help='可用的子命令')
112
+ subparsers = parser.add_subparsers(dest='command', help='Available subcommands')
113
113
 
114
- # info 子命令
115
- info_parser = subparsers.add_parser('info', help='显示支持的平台和模型信息')
114
+ # info subcommand
115
+ info_parser = subparsers.add_parser('info', help='Display supported platforms and models information')
116
116
 
117
- # chat 子命令
118
- chat_parser = subparsers.add_parser('chat', help='与指定的平台和模型进行对话')
119
- chat_parser.add_argument('--platform', '-p', help='指定要使用的平台')
120
- chat_parser.add_argument('--model', '-m', help='指定要使用的模型')
117
+ # chat subcommand
118
+ chat_parser = subparsers.add_parser('chat', help='Chat with specified platform and model')
119
+ chat_parser.add_argument('--platform', '-p', help='Specify the platform to use')
120
+ chat_parser.add_argument('--model', '-m', help='Specify the model to use')
121
121
 
122
122
  args = parser.parse_args()
123
123