jarvis-ai-assistant 0.1.101__py3-none-any.whl → 0.1.103__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 (54) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/agent.py +140 -140
  3. jarvis/jarvis_code_agent/code_agent.py +234 -0
  4. jarvis/{jarvis_coder → jarvis_code_agent}/file_select.py +16 -17
  5. jarvis/jarvis_code_agent/patch.py +118 -0
  6. jarvis/jarvis_code_agent/relevant_files.py +66 -0
  7. jarvis/jarvis_codebase/main.py +32 -29
  8. jarvis/jarvis_platform/main.py +5 -3
  9. jarvis/jarvis_rag/main.py +11 -15
  10. jarvis/jarvis_smart_shell/main.py +2 -2
  11. jarvis/models/ai8.py +1 -0
  12. jarvis/models/kimi.py +36 -30
  13. jarvis/models/ollama.py +17 -11
  14. jarvis/models/openai.py +15 -12
  15. jarvis/models/oyi.py +22 -7
  16. jarvis/models/registry.py +1 -25
  17. jarvis/tools/__init__.py +0 -6
  18. jarvis/tools/ask_codebase.py +99 -0
  19. jarvis/tools/ask_user.py +1 -9
  20. jarvis/tools/chdir.py +1 -1
  21. jarvis/tools/code_review.py +163 -0
  22. jarvis/tools/create_code_sub_agent.py +19 -45
  23. jarvis/tools/create_code_test_agent.py +115 -0
  24. jarvis/tools/create_ctags_agent.py +176 -0
  25. jarvis/tools/create_sub_agent.py +2 -2
  26. jarvis/tools/execute_shell.py +2 -2
  27. jarvis/tools/file_operation.py +2 -2
  28. jarvis/tools/find_in_codebase.py +108 -0
  29. jarvis/tools/git_commiter.py +68 -0
  30. jarvis/tools/methodology.py +3 -3
  31. jarvis/tools/rag.py +6 -3
  32. jarvis/tools/read_code.py +147 -0
  33. jarvis/tools/read_webpage.py +1 -1
  34. jarvis/tools/registry.py +92 -68
  35. jarvis/tools/search.py +8 -6
  36. jarvis/tools/select_code_files.py +4 -4
  37. jarvis/utils.py +270 -95
  38. {jarvis_ai_assistant-0.1.101.dist-info → jarvis_ai_assistant-0.1.103.dist-info}/METADATA +9 -5
  39. jarvis_ai_assistant-0.1.103.dist-info/RECORD +51 -0
  40. {jarvis_ai_assistant-0.1.101.dist-info → jarvis_ai_assistant-0.1.103.dist-info}/entry_points.txt +4 -2
  41. jarvis/jarvis_code_agent/main.py +0 -202
  42. jarvis/jarvis_coder/__init__.py +0 -0
  43. jarvis/jarvis_coder/git_utils.py +0 -123
  44. jarvis/jarvis_coder/main.py +0 -241
  45. jarvis/jarvis_coder/patch_handler.py +0 -340
  46. jarvis/jarvis_coder/plan_generator.py +0 -145
  47. jarvis/tools/execute_code_modification.py +0 -70
  48. jarvis/tools/find_files.py +0 -119
  49. jarvis/tools/generate_tool.py +0 -174
  50. jarvis/tools/thinker.py +0 -151
  51. jarvis_ai_assistant-0.1.101.dist-info/RECORD +0 -51
  52. {jarvis_ai_assistant-0.1.101.dist-info → jarvis_ai_assistant-0.1.103.dist-info}/LICENSE +0 -0
  53. {jarvis_ai_assistant-0.1.101.dist-info → jarvis_ai_assistant-0.1.103.dist-info}/WHEEL +0 -0
  54. {jarvis_ai_assistant-0.1.101.dist-info → jarvis_ai_assistant-0.1.103.dist-info}/top_level.txt +0 -0
@@ -1,340 +0,0 @@
1
- import re
2
- import os
3
- from typing import List, Tuple, Dict
4
- import yaml
5
- from pathlib import Path
6
-
7
- from jarvis.jarvis_coder.git_utils import generate_commit_message, init_git_repo, save_edit_record
8
- from jarvis.models.base import BasePlatform
9
- from jarvis.models.registry import PlatformRegistry
10
- from jarvis.utils import OutputType, PrettyOutput, get_multiline_input, get_single_line_input, while_success
11
-
12
- class Patch:
13
- def __init__(self, start: int, end: int, new_code: str):
14
- self.start = start # Line number where patch starts (inclusive)
15
- self.end = end # Line number where patch ends (exclusive)
16
- self.new_code = new_code # New code to insert/replace
17
-
18
- class PatchHandler:
19
- def __init__(self):
20
- self.prompt_file = Path.home() / ".jarvis-coder-patch-prompt"
21
- self.additional_info = self._load_additional_info()
22
- self.root_dir = init_git_repo(os.getcwd())
23
- self.record_dir = os.path.join(self.root_dir, ".jarvis-coder", "record")
24
- if not os.path.exists(self.record_dir):
25
- os.makedirs(self.record_dir)
26
- def _load_additional_info(self) -> str:
27
- """Load saved additional info from prompt file"""
28
- if not self.prompt_file.exists():
29
- return ""
30
- try:
31
- with open(self.prompt_file, 'r') as f:
32
- data = yaml.safe_load(f)
33
- return data.get('additional_info', '') if data else ''
34
- except Exception as e:
35
- PrettyOutput.print(f"Failed to load additional info: {e}", OutputType.WARNING)
36
- return ""
37
-
38
- def _save_additional_info(self, info: str):
39
- """Save additional info to prompt file"""
40
- try:
41
- with open(self.prompt_file, 'w') as f:
42
- yaml.dump({'additional_info': info}, f)
43
- except Exception as e:
44
- PrettyOutput.print(f"Failed to save additional info: {e}", OutputType.WARNING)
45
-
46
- def _extract_patches(self, response: str) -> List[Patch]:
47
- """Extract patches from response with hexadecimal line numbers
48
-
49
- Args:
50
- response: Model response content
51
-
52
- Returns:
53
- List[Patch]: List of patches, each containing the line range and new code
54
- """
55
- fmt_pattern = r'<PATCH>\n\[([0-9a-f]+),([0-9a-f]+)\)\n(.*?\n)</PATCH>'
56
- ret = []
57
- for m in re.finditer(fmt_pattern, response, re.DOTALL):
58
- start = int(m.group(1), 16) # Convert hex to decimal
59
- end = int(m.group(2), 16)
60
- new_code = m.group(3)
61
- ret.append(Patch(start, end, new_code))
62
- return ret
63
-
64
- def _confirm_and_apply_changes(self, file_path: str) -> bool:
65
- """Confirm and apply changes"""
66
- os.system(f"git diff --cached {file_path}")
67
- confirm = get_single_line_input(f"Accept {file_path} changes? (y/n) [y]").lower() or "y"
68
- if confirm == "y":
69
- return True
70
- else:
71
- # Rollback changes
72
- os.system(f"git reset {file_path}")
73
- os.system(f"git checkout -- {file_path}")
74
- PrettyOutput.print(f"Changes to {file_path} have been rolled back", OutputType.WARNING)
75
- return False
76
-
77
-
78
-
79
- def _finalize_changes(self) -> None:
80
- """Complete changes and commit"""
81
- PrettyOutput.print("Modification confirmed, committing...", OutputType.INFO)
82
-
83
- # Add only modified files under git control
84
- os.system("git add -u")
85
-
86
- # Then get git diff
87
- git_diff = os.popen("git diff --cached").read()
88
-
89
- # Automatically generate commit information, pass in feature
90
- commit_message = generate_commit_message(git_diff)
91
-
92
- # Display and confirm commit information
93
- PrettyOutput.print(f"Automatically generated commit information: {commit_message}", OutputType.INFO)
94
- user_confirm = get_single_line_input("Use this commit information? (y/n) [y]").lower() or "y"
95
-
96
- if user_confirm.lower() != "y":
97
- commit_message = get_single_line_input("Please enter a new commit information")
98
-
99
- # No need to git add again, it has already been added
100
- os.system(f"git commit -m '{commit_message}'")
101
- save_edit_record(self.record_dir, commit_message, git_diff)
102
-
103
- def _revert_changes(self) -> None:
104
- """Revert all changes"""
105
- PrettyOutput.print("Modification cancelled, reverting changes", OutputType.INFO)
106
- os.system(f"git reset --hard")
107
- os.system(f"git clean -df")
108
-
109
- def _check_patches_overlap(self, patches: List[Patch]) -> bool:
110
- """Check if any patches overlap with each other
111
-
112
- Args:
113
- patches: List of patches to check
114
-
115
- Returns:
116
- bool: True if patches overlap, False otherwise
117
- """
118
- if not patches:
119
- return False
120
-
121
- # Sort patches by start line
122
- sorted_patches = sorted(patches, key=lambda x: x.start)
123
-
124
- # Check for overlaps
125
- for i in range(len(sorted_patches) - 1):
126
- current = sorted_patches[i]
127
- next_patch = sorted_patches[i + 1]
128
-
129
- if current.end > next_patch.start:
130
- PrettyOutput.print(
131
- f"Overlapping patches detected: [{current.start:04x},{current.end:04x}) and [{next_patch.start:04x},{next_patch.end:04x})",
132
- OutputType.WARNING
133
- )
134
- return True
135
-
136
- return False
137
-
138
- def apply_file_patch(self, file_path: str, patches: List[Patch]) -> bool:
139
- """Apply file patches using line numbers"""
140
- if not os.path.exists(file_path):
141
- base_dir = os.path.dirname(file_path)
142
- os.makedirs(base_dir, exist_ok=True)
143
- open(file_path, "w", encoding="utf-8").close()
144
-
145
- # Check for overlapping patches
146
- if self._check_patches_overlap(patches):
147
- PrettyOutput.print("Cannot apply overlapping patches", OutputType.ERROR)
148
- os.system(f"git reset {file_path}")
149
- os.system(f"git checkout -- {file_path}")
150
- return False
151
-
152
- with open(file_path, "r", encoding="utf-8") as f:
153
- lines = f.readlines()
154
-
155
- # Sort patches by start line in reverse order to apply from bottom to top
156
- patches.sort(key=lambda x: x.start, reverse=True)
157
-
158
- for i, patch in enumerate(patches):
159
- PrettyOutput.print(f"Applying patch {i+1}/{len(patches)} at lines [{patch.start},{patch.end})", OutputType.INFO)
160
-
161
- if patch.start > len(lines):
162
- PrettyOutput.print(f"Invalid patch: start line {patch.start} exceeds file length {len(lines)}", OutputType.WARNING)
163
- os.system(f"git reset {file_path}")
164
- os.system(f"git checkout -- {file_path}")
165
- return False
166
-
167
- if patch.new_code:
168
- new_lines = patch.new_code.splitlines(keepends=True)
169
- lines[patch.start:patch.end] = new_lines
170
- else:
171
- del lines[patch.start:patch.end]
172
-
173
- # Write modified content back to file
174
- with open(file_path, "w", encoding="utf-8") as f:
175
- f.writelines(lines)
176
-
177
- os.system(f"git add {file_path}")
178
- PrettyOutput.print(f"Successfully applied all patches to {file_path}", OutputType.SUCCESS)
179
- return True
180
-
181
-
182
- def retry_comfirm(self) -> Tuple[str, str]:
183
- choice = get_single_line_input("\nPlease choose an action: (1) Retry (2) Skip (3) Completely stop [1]: ") or "1"
184
- if choice == "2":
185
- return "skip", ""
186
- if choice == "3":
187
- return "break", ""
188
-
189
- feedback = get_multiline_input("Please enter additional information and requirements:")
190
- if feedback:
191
- save_prompt = get_single_line_input("Would you like to save this as general feedback for future patches? (y/n) [n]: ").lower() or "n"
192
- if save_prompt == "y":
193
- self._save_additional_info(feedback)
194
- PrettyOutput.print("Feedback saved for future use", OutputType.SUCCESS)
195
-
196
- return "continue", feedback
197
-
198
- def apply_patch(self, feature: str, structed_plan: Dict[str, str]) -> Tuple[bool, str]:
199
- """Apply patch (main entry)"""
200
- feedback = ""
201
- for file_path, current_plan in structed_plan.items():
202
- additional_info = self.additional_info # Initialize with saved info
203
- while True:
204
- if os.path.exists(file_path):
205
- # Read file and add line numbers
206
- lines = []
207
- with open(file_path, "r", encoding="utf-8") as f:
208
- for i, line in enumerate(f):
209
- lines.append(f"{i:04x}{line}") # Changed from i+1 to i for 0-based indexing
210
- content = "".join(lines)
211
- else:
212
- content = "<File does not exist, need to create>"
213
-
214
- 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 (with 4-digit hexadecimal line numbers), and current file's modification plan. The output format should be as follows:
215
-
216
- <PATCH>
217
- [start,end)
218
- new_code
219
- </PATCH>
220
-
221
- Example:
222
- <PATCH>
223
- [000c,000c)
224
- def new_function():
225
- pass
226
- </PATCH>
227
-
228
- means:
229
- Insert code BEFORE line 12:
230
- ```
231
- def new_function():
232
- pass
233
- ```
234
-
235
- Example 2:
236
- <PATCH>
237
- [0004,000b)
238
- aa
239
- bb
240
- cc
241
- </PATCH>
242
-
243
- means:
244
- Replace lines [4,11) with:
245
- ```
246
- aa
247
- bb
248
- cc
249
- ```
250
-
251
- Rules:
252
- 1. start and end are hexadecimal line numbers (e.g., 000a)
253
- 2. The patch will replace lines [start,end) with new_code (including start, excluding end)
254
- 3. If start equals end, new_code will be inserted BEFORE that line
255
- 4. If new_code is empty, lines [start,end) will be deleted
256
- 5. Multiple patches can be generated
257
- 6. Each line in the input file starts with its 4-digit hexadecimal line number (0-based)
258
- 7. Your new_code should NOT include line numbers
259
- 8. CRITICAL: Patches MUST NOT overlap - ensure each line is modified by at most one patch
260
- 9. Generate patches from bottom to top of the file
261
- 10. Ensure new_code maintains correct indentation and formatting
262
- 11. Each patch should modify no more than 20 lines
263
- 12. Include sufficient context in new_code to maintain code consistency
264
- 13. `[` and `)` must be included in the line range
265
- 14. Line numbers start from 0
266
- 15. Example of INVALID overlapping patches:
267
- <PATCH>
268
- [0001,0005)
269
- code1
270
- </PATCH>
271
- <PATCH>
272
- [0003,0007) # This overlaps with the previous patch
273
- code2
274
- </PATCH>
275
- """
276
-
277
- prompt += f"""# Original requirement: {feature}
278
- # Current file path: {file_path}
279
- # Current file content:
280
- <CONTENT>
281
- {content}
282
- </CONTENT>
283
- # Current file modification plan:
284
- {current_plan}
285
- { "# Additional information: " + additional_info if additional_info else "" }
286
- """
287
-
288
-
289
- PrettyOutput.print(f"Generating formatted patches for {file_path}...", OutputType.PROGRESS)
290
- response = PlatformRegistry.get_global_platform_registry().get_codegen_platform().chat_until_success(prompt)
291
- patches = self._extract_patches(response)
292
-
293
- if not patches or not self.apply_file_patch(file_path, patches) or not self._confirm_and_apply_changes(file_path):
294
- os.system(f"git reset {file_path}")
295
- os.system(f"git checkout -- {file_path}")
296
- PrettyOutput.print("Patch generation failed", OutputType.WARNING)
297
- act, msg = self.retry_comfirm()
298
- if act == "break":
299
- PrettyOutput.print("Terminate patch application", OutputType.WARNING)
300
- additional_info = get_multiline_input("Please enter your additional information or suggestions (press Enter to cancel):")
301
- return False, additional_info
302
- if act == "skip":
303
- PrettyOutput.print(f"Skip file {file_path}", OutputType.WARNING)
304
- feedback += f"Skip file {file_path}\n"
305
- feedback += "Reason: " + get_multiline_input("Please enter your reason:") + "\n"
306
- break
307
- else:
308
- additional_info += msg + "\n"
309
- continue
310
- else:
311
- self._finalize_changes()
312
- break
313
-
314
- return True, feedback
315
-
316
-
317
-
318
- def handle_patch_application(self, feature: str, structed_plan: Dict[str,str]) -> Tuple[bool, str]:
319
- """Process patch application process
320
-
321
- Args:
322
- related_files: Related files list
323
- feature: Feature description
324
- modification_plan: Modification plan
325
-
326
- Returns:
327
- bool: Whether patch application is successful
328
- """
329
- PrettyOutput.print("\nThe following modification plan will be applied:", OutputType.INFO)
330
- for file_path, patches_code in structed_plan.items():
331
- PrettyOutput.print(f"\nFile: {file_path}", OutputType.INFO)
332
- PrettyOutput.print(f"Modification plan: \n{patches_code}", OutputType.INFO)
333
- # 3. Apply patches
334
- success, additional_info = self.apply_patch(feature, structed_plan)
335
- if not success:
336
- os.system("git reset --hard")
337
- return False, additional_info
338
- # 6. Apply successfully, let user confirm changes
339
- PrettyOutput.print("\nPatches applied, please check the modification effect.", OutputType.SUCCESS)
340
- return True, "Modification applied successfully"
@@ -1,145 +0,0 @@
1
- import re
2
- from typing import Dict, List, Tuple
3
- from jarvis.models.registry import PlatformRegistry
4
- from jarvis.utils import PrettyOutput, OutputType, get_multiline_input, get_single_line_input, is_long_context
5
-
6
- class PlanGenerator:
7
- """Modification plan generator"""
8
-
9
- def _build_prompt(self, feature: str, related_files: List[Dict], additional_info: str) -> str:
10
- """Build prompt
11
-
12
- Args:
13
- feature: Feature description
14
- related_files: Related files list
15
- additional_info: User supplement information
16
-
17
- Returns:
18
- str: Complete prompt
19
- """
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
- prompt += f"{feature}\n\n"
22
-
23
- prompt += "Here are the relevant code file snippets:\n\n"
24
-
25
- for file in related_files:
26
- prompt += f"File: {file['file_path']}\n"
27
- for part in file["parts"]:
28
- prompt += f"<PART>\n{part}\n</PART>\n"
29
-
30
- prompt += "\nPlease provide detailed modifications needed to implement this feature. Include:\n"
31
- prompt += "1. Which files need to be modified\n"
32
- prompt += "2. How to modify each file, no explanation needed\n"
33
- prompt += "3. Don't assume other files or code exist, only generate modification plans based on provided file contents and description\n"
34
- prompt += "4. Don't implement features outside the requirement\n"
35
- prompt += "5. Output only one modification plan per file (can be multiple lines)\n"
36
- prompt += "6. Output format as follows:\n"
37
- prompt += "<PLAN>\n"
38
- prompt += "> path/to/file1\n"
39
- prompt += "modification plan\n"
40
- prompt += "</PLAN>\n"
41
- prompt += "<PLAN>\n"
42
- prompt += "> path/to/file2\n"
43
- prompt += "modification plan\n"
44
- prompt += "</PLAN>\n"
45
- if additional_info:
46
- prompt += f"# Additional information:\n{additional_info}\n"
47
-
48
- return prompt
49
-
50
-
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
88
-
89
- Args:
90
- feature: Feature description
91
- related_files: Related files list
92
-
93
- Returns:
94
- Tuple[str, Dict[str,str]]: Modification plan, return None if user cancels
95
- """
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
-
104
- while True:
105
- prompt = self._build_prompt(feature, file_info, additional_info)
106
- # Build prompt
107
- PrettyOutput.print("Start generating modification plan...", OutputType.PROGRESS)
108
-
109
- # Get modification plan
110
- raw_plan = PlatformRegistry.get_global_platform_registry().get_thinking_platform().chat_until_success(prompt)
111
- structed_plan = self._extract_code(raw_plan)
112
- if not structed_plan:
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):")
115
- if tmp == "__interrupt__" or prompt == "":
116
- return {}
117
- additional_info += tmp + "\n"
118
- continue
119
- user_input = get_single_line_input("Do you agree with this modification plan? (y/n) [y]").strip().lower() or 'y'
120
- if user_input == 'y' or user_input == '':
121
- return structed_plan
122
- elif user_input == 'n':
123
- # Get user feedback
124
- tmp = get_multiline_input("Please enter your additional information or suggestions (press Enter to cancel):")
125
- if prompt == "__interrupt__" or prompt == "":
126
- return {}
127
- additional_info += tmp + "\n"
128
- continue
129
-
130
-
131
- def _extract_code(self, response: str) -> Dict[str, str]:
132
- """Extract code from response
133
-
134
- Args:
135
- response: Model response content
136
-
137
- Returns:
138
- Dict[str, List[str]]: Code dictionary, key is file path, value is code snippet list
139
- """
140
- code_dict = {}
141
- for match in re.finditer(r'<PLAN>\n> (.+?)\n(.*?)\n</PLAN>', response, re.DOTALL):
142
- file_path = match.group(1)
143
- code_part = match.group(2)
144
- code_dict[file_path] = code_part
145
- return code_dict
@@ -1,70 +0,0 @@
1
- from typing import Dict, Any
2
-
3
- from jarvis.agent import Agent
4
- from jarvis.utils import OutputType, PrettyOutput
5
- from jarvis.jarvis_coder.patch_handler import PatchHandler
6
-
7
-
8
- class CodeModifyTool:
9
- name = "execute_code_modification"
10
- description = "Execute code modifications according to the provided plan"
11
- parameters = {
12
- "type": "object",
13
- "properties": {
14
- "task": {
15
- "type": "string",
16
- "description": "The code modification task description"
17
- },
18
- "structured_plan": {
19
- "type": "object",
20
- "description": "Dictionary mapping file paths to their modification plans. Example: {'path/to/file.py': 'Add function foo() to handle...'}",
21
- "additionalProperties": {
22
- "type": "string",
23
- "description": "Modification plan for a specific file"
24
- },
25
- "examples": [{
26
- "src/file1.py": "Add error handling to process_data()",
27
- "src/file2.py": "Update API endpoint URL in get_data()"
28
- }]
29
- }
30
- },
31
- "required": ["task", "raw_plan", "structured_plan"]
32
- }
33
-
34
- def execute(self, args: Dict) -> Dict[str, Any]:
35
- """Execute code modifications using PatchHandler"""
36
- try:
37
- task = args["task"]
38
- structured_plan = args["structured_plan"]
39
-
40
- PrettyOutput.print("Executing code modifications...", OutputType.INFO)
41
-
42
- # Create patch handler instance
43
- patch_handler = PatchHandler()
44
-
45
- # Apply patches and handle the process
46
- success, additional_info = patch_handler.handle_patch_application(
47
- feature=task,
48
- structed_plan=structured_plan
49
- )
50
-
51
- if not success:
52
- return {
53
- "success": False,
54
- "stdout": "Changes have been rolled back",
55
- "stderr": additional_info
56
- }
57
-
58
- return {
59
- "success": True,
60
- "stdout": "Code modifications have been successfully applied and committed",
61
- "stderr": additional_info
62
- }
63
-
64
- except Exception as e:
65
- PrettyOutput.print(str(e), OutputType.ERROR)
66
- return {
67
- "success": False,
68
- "stdout": "",
69
- "stderr": f"Failed to execute code modifications: {str(e)}"
70
- }
@@ -1,119 +0,0 @@
1
- from typing import Dict, Any
2
-
3
- from jarvis.agent import Agent
4
- from jarvis.tools.registry import ToolRegistry
5
- from jarvis.utils import OutputType, PrettyOutput
6
-
7
- find_files_system_prompt = """You are a Find Files Agent specialized in searching and identifying relevant code files in a codebase. Your task is to find files that are most likely related to the given requirements or problems.
8
-
9
- SEARCH WORKFLOW:
10
- 1. Understand Search Requirements
11
- - Analyze the search query thoroughly
12
- - Identify key technical terms and concepts
13
- - Break down complex requirements into searchable terms
14
-
15
- 2. Execute Search Strategy
16
- - Use shell commands to search systematically:
17
- * Search for key terms:
18
- <TOOL_CALL>
19
- name: execute_shell
20
- arguments:
21
- command: grep -r "pattern" .
22
- </TOOL_CALL>
23
- * Find files by name patterns:
24
- <TOOL_CALL>
25
- name: execute_shell
26
- arguments:
27
- command: find . -name "pattern"
28
- </TOOL_CALL>
29
- * Examine file contents:
30
- <TOOL_CALL>
31
- name: execute_shell
32
- arguments:
33
- command: grep -A 5 -B 5 "pattern" file.py
34
- </TOOL_CALL>
35
-
36
- 3. Analyze Results
37
- - Review each potential file
38
- - Check file relevance
39
- - Examine file relationships
40
- - Consider file dependencies
41
-
42
- 4. Generate File List
43
- - List all relevant files
44
- - Sort by relevance
45
- - Include brief explanation for each file
46
- - Format output as YAML
47
-
48
- OUTPUT FORMAT:
49
- files:
50
- - path: path/to/file1
51
- relevance: "Brief explanation of why this file is relevant"
52
- - path: path/to/file2
53
- relevance: "Brief explanation of why this file is relevant"
54
-
55
- SEARCH BEST PRACTICES:
56
- - Use multiple search terms
57
- - Consider file naming conventions
58
- - Check both file names and contents
59
- - Look for related files (imports, dependencies)
60
- - Use grep with context (-A, -B options)
61
- - Search in specific directories when appropriate
62
- - Exclude irrelevant directories (like .git, __pycache__)
63
-
64
- IMPORTANT:
65
- 1. Focus on finding the most relevant files
66
- 2. Avoid listing irrelevant files
67
- 3. Explain relevance clearly but concisely
68
- 4. Consider both direct and indirect relevance
69
- 5. Use file content to confirm relevance
70
- """
71
-
72
- class FindFilesTool:
73
- name = "find_files"
74
- description = "Search and identify relevant code files in the codebase based on requirements or problems"
75
- parameters = {
76
- "type": "object",
77
- "properties": {
78
- "query": {
79
- "type": "string",
80
- "description": "The search query or requirement description"
81
- }
82
- },
83
- "required": ["query"]
84
- }
85
-
86
- def execute(self, args: Dict) -> Dict[str, Any]:
87
- """Execute file search task"""
88
- try:
89
- query = args["query"]
90
-
91
- PrettyOutput.print(f"Creating Find Files agent to search for: {query}", OutputType.INFO)
92
-
93
- tool_registry = ToolRegistry()
94
- tool_registry.use_tools(["ask_user", "execute_shell", "file_operation"])
95
-
96
- # Create find files agent
97
- find_agent = Agent(
98
- system_prompt=find_files_system_prompt,
99
- name="Find Files Agent",
100
- is_sub_agent=True,
101
- tool_registry=tool_registry
102
- )
103
-
104
- # Execute search
105
- result = find_agent.run(query)
106
-
107
- return {
108
- "success": True,
109
- "stdout": result,
110
- "stderr": ""
111
- }
112
-
113
- except Exception as e:
114
- PrettyOutput.print(str(e), OutputType.ERROR)
115
- return {
116
- "success": False,
117
- "stdout": "",
118
- "stderr": f"Failed to execute file search: {str(e)}"
119
- }