jarvis-ai-assistant 0.1.110__py3-none-any.whl → 0.1.112__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 (47) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/agent.py +51 -39
  3. jarvis/jarvis_code_agent/code_agent.py +89 -53
  4. jarvis/jarvis_code_agent/file_select.py +20 -20
  5. jarvis/jarvis_code_agent/patch.py +20 -11
  6. jarvis/jarvis_code_agent/relevant_files.py +68 -16
  7. jarvis/jarvis_codebase/main.py +82 -88
  8. jarvis/jarvis_lsp/cpp.py +1 -1
  9. jarvis/jarvis_lsp/go.py +1 -1
  10. jarvis/jarvis_lsp/python.py +0 -2
  11. jarvis/jarvis_lsp/registry.py +13 -13
  12. jarvis/jarvis_lsp/rust.py +1 -1
  13. jarvis/jarvis_platform/ai8.py +14 -14
  14. jarvis/jarvis_platform/base.py +1 -1
  15. jarvis/jarvis_platform/kimi.py +17 -17
  16. jarvis/jarvis_platform/ollama.py +14 -14
  17. jarvis/jarvis_platform/openai.py +8 -8
  18. jarvis/jarvis_platform/oyi.py +19 -19
  19. jarvis/jarvis_platform/registry.py +6 -6
  20. jarvis/jarvis_platform_manager/main.py +17 -17
  21. jarvis/jarvis_rag/main.py +25 -25
  22. jarvis/jarvis_smart_shell/main.py +6 -6
  23. jarvis/jarvis_tools/ask_codebase.py +4 -4
  24. jarvis/jarvis_tools/ask_user.py +2 -2
  25. jarvis/jarvis_tools/create_code_agent.py +8 -8
  26. jarvis/jarvis_tools/create_sub_agent.py +2 -2
  27. jarvis/jarvis_tools/execute_shell.py +2 -2
  28. jarvis/jarvis_tools/file_operation.py +1 -1
  29. jarvis/jarvis_tools/git_commiter.py +4 -6
  30. jarvis/jarvis_tools/methodology.py +3 -3
  31. jarvis/jarvis_tools/rag.py +3 -3
  32. jarvis/jarvis_tools/read_code.py +4 -3
  33. jarvis/jarvis_tools/read_webpage.py +19 -6
  34. jarvis/jarvis_tools/registry.py +11 -11
  35. jarvis/jarvis_tools/search.py +88 -27
  36. jarvis/jarvis_tools/select_code_files.py +1 -1
  37. jarvis/jarvis_tools/tool_generator.py +182 -0
  38. jarvis/utils/date_utils.py +19 -0
  39. jarvis/utils.py +31 -25
  40. jarvis_ai_assistant-0.1.112.dist-info/METADATA +460 -0
  41. jarvis_ai_assistant-0.1.112.dist-info/RECORD +64 -0
  42. jarvis_ai_assistant-0.1.110.dist-info/METADATA +0 -462
  43. jarvis_ai_assistant-0.1.110.dist-info/RECORD +0 -62
  44. {jarvis_ai_assistant-0.1.110.dist-info → jarvis_ai_assistant-0.1.112.dist-info}/LICENSE +0 -0
  45. {jarvis_ai_assistant-0.1.110.dist-info → jarvis_ai_assistant-0.1.112.dist-info}/WHEEL +0 -0
  46. {jarvis_ai_assistant-0.1.110.dist-info → jarvis_ai_assistant-0.1.112.dist-info}/entry_points.txt +0 -0
  47. {jarvis_ai_assistant-0.1.110.dist-info → jarvis_ai_assistant-0.1.112.dist-info}/top_level.txt +0 -0
@@ -2,7 +2,7 @@ import os
2
2
  import re
3
3
  from typing import Dict, List
4
4
  from prompt_toolkit import PromptSession
5
- from prompt_toolkit.completion import WordCompleter, Completer, Completion
5
+ from prompt_toolkit.completion import Completer, Completion
6
6
  from jarvis.utils import OutputType, PrettyOutput, get_single_line_input, user_confirm
7
7
 
8
8
 
@@ -42,7 +42,7 @@ def _parse_file_selection(input_str: str, max_index: int) -> List[int]:
42
42
  if start <= end:
43
43
  selected.update(range(start, end + 1))
44
44
  except ValueError:
45
- PrettyOutput.print(f"Ignore invalid range expression: {part}", OutputType.WARNING)
45
+ PrettyOutput.print(f"忽略无效的范围表达式: {part}", OutputType.WARNING)
46
46
  # Process single number
47
47
  else:
48
48
  try:
@@ -50,9 +50,9 @@ def _parse_file_selection(input_str: str, max_index: int) -> List[int]:
50
50
  if 0 <= index < max_index:
51
51
  selected.add(index)
52
52
  else:
53
- PrettyOutput.print(f"Ignore index out of range: {part}", OutputType.WARNING)
53
+ PrettyOutput.print(f"忽略超出范围的索引: {part}", OutputType.WARNING)
54
54
  except ValueError:
55
- PrettyOutput.print(f"Ignore invalid number: {part}", OutputType.WARNING)
55
+ PrettyOutput.print(f"忽略无效的数字: {part}", OutputType.WARNING)
56
56
 
57
57
  return sorted(list(selected))
58
58
 
@@ -125,32 +125,32 @@ def _fuzzy_match_files(root_dir: str, pattern: str) -> List[str]:
125
125
 
126
126
  return sorted(matches)
127
127
 
128
- def select_files(related_files: List[str], root_dir: str) -> List[str]:
128
+ def select_files(related_files: List[Dict[str, str]], root_dir: str) -> List[Dict[str, str]]:
129
129
  """Let the user select and supplement related files"""
130
- PrettyOutput.section("Related files", OutputType.INFO)
131
-
130
+ PrettyOutput.section("相关文件", OutputType.INFO)
131
+
132
132
  output = ""
133
133
  # Display found files
134
134
  selected_files = list(related_files) # Default select all
135
135
  for i, file in enumerate(related_files, 1):
136
- output += f"[{i}] {file}\n"
136
+ output += f"[{i}] {file['file']} ({file['reason']})\n"
137
137
 
138
138
  PrettyOutput.print(output, OutputType.INFO, lang="markdown")
139
139
 
140
140
  if len(related_files) > 0:
141
141
  # Ask the user if they need to adjust the file list
142
- if user_confirm("Do you need to adjust the file list?", False):
142
+ if user_confirm("是否需要调整文件列表?", False):
143
143
  # Let the user select files
144
- numbers = get_single_line_input("Please enter the file numbers to include (support: 1,3-6 format, press Enter to keep the current selection)").strip()
144
+ numbers = get_single_line_input("请输入要包含的文件编号(支持: 1,3-6格式, 按回车保持当前选择)").strip()
145
145
  if numbers:
146
146
  selected_indices = _parse_file_selection(numbers, len(related_files))
147
147
  if selected_indices:
148
148
  selected_files = [related_files[i] for i in selected_indices]
149
149
  else:
150
- PrettyOutput.print("No valid files selected, keep the current selection", OutputType.WARNING)
150
+ PrettyOutput.print("没有有效的文件被选择, 保持当前选择", OutputType.WARNING)
151
151
 
152
152
  # Ask if they need to supplement files
153
- if user_confirm("Do you need to supplement other files?", False):
153
+ if user_confirm("是否需要补充其他文件?", False):
154
154
  # Create file completion session
155
155
  session = PromptSession(
156
156
  completer=_get_file_completer(root_dir),
@@ -158,7 +158,7 @@ def select_files(related_files: List[str], root_dir: str) -> List[str]:
158
158
  )
159
159
 
160
160
  while True:
161
- PrettyOutput.print("Please enter the file path to supplement (support Tab completion and *? wildcard, input empty line to end):", OutputType.INFO)
161
+ PrettyOutput.print("请输入要补充的文件路径(支持Tab补全和*?通配符, 输入空行结束)", OutputType.INFO)
162
162
  try:
163
163
  file_path = session.prompt(">>> ").strip()
164
164
  except KeyboardInterrupt:
@@ -171,16 +171,16 @@ def select_files(related_files: List[str], root_dir: str) -> List[str]:
171
171
  if '*' in file_path or '?' in file_path:
172
172
  matches = _fuzzy_match_files(root_dir, file_path)
173
173
  if not matches:
174
- PrettyOutput.print("No matching files found", OutputType.WARNING)
174
+ PrettyOutput.print("没有找到匹配的文件", OutputType.WARNING)
175
175
  continue
176
176
 
177
177
  # Display matching files
178
- PrettyOutput.print("Found the following matching files:", OutputType.INFO)
178
+ PrettyOutput.print("找到以下匹配的文件:", OutputType.INFO)
179
179
  for i, path in enumerate(matches, 1):
180
180
  PrettyOutput.print(f"[{i}] {path}", OutputType.INFO)
181
181
 
182
182
  # Let the user select
183
- numbers = get_single_line_input("Please select the file numbers to add (support: 1,3-6 format, press Enter to select all)").strip()
183
+ numbers = get_single_line_input("请选择要添加的文件编号(支持: 1,3-6格式, 按回车选择所有)").strip()
184
184
  if numbers:
185
185
  indices = _parse_file_selection(numbers, len(matches))
186
186
  if not indices:
@@ -195,13 +195,13 @@ def select_files(related_files: List[str], root_dir: str) -> List[str]:
195
195
  for path in paths_to_add:
196
196
  full_path = os.path.join(root_dir, path)
197
197
  if not os.path.isfile(full_path):
198
- PrettyOutput.print(f"File does not exist: {path}", OutputType.ERROR)
198
+ PrettyOutput.print(f"文件不存在: {path}", OutputType.ERROR)
199
199
  continue
200
200
 
201
201
  try:
202
- selected_files.append(path)
203
- PrettyOutput.print(f"File added: {path}", OutputType.SUCCESS)
202
+ selected_files.append({"file": path, "reason": "User Added"})
203
+ PrettyOutput.print(f"文件已添加: {path}", OutputType.SUCCESS)
204
204
  except Exception as e:
205
- PrettyOutput.print(f"Failed to read file: {str(e)}", OutputType.ERROR)
205
+ PrettyOutput.print(f"读取文件失败: {str(e)}", OutputType.ERROR)
206
206
 
207
207
  return selected_files
@@ -2,13 +2,13 @@ import re
2
2
  from typing import Dict, Any, List
3
3
  import os
4
4
  from jarvis.jarvis_tools.git_commiter import GitCommitTool
5
- from jarvis.utils import OutputType, PrettyOutput, has_uncommitted_changes, user_confirm
5
+ from jarvis.utils import OutputType, PrettyOutput, get_multiline_input, has_uncommitted_changes, user_confirm
6
6
 
7
7
 
8
8
  def _parse_patch(patch_str: str) -> Dict[str, List[Dict[str, Any]]]:
9
9
  """Parse patches from string with format:
10
10
  <PATCH>
11
- > /path/to/file start_line,end_line
11
+ > path/to/file start_line,end_line
12
12
  content_line1
13
13
  content_line2
14
14
  ...
@@ -77,12 +77,12 @@ def apply_patch(output_str: str)->str:
77
77
  # Write new file
78
78
  with open(filepath, 'w', encoding='utf-8') as f:
79
79
  f.writelines(new_content)
80
- PrettyOutput.print(f"Created new file {filepath} successfully\n", OutputType.SUCCESS)
80
+ PrettyOutput.print(f"成功创建新文件 {filepath}", OutputType.SUCCESS)
81
81
  continue
82
82
 
83
83
  # Regular patch logic for existing files
84
84
  if not os.path.exists(filepath):
85
- PrettyOutput.print(f"File not found: {filepath}", OutputType.WARNING)
85
+ PrettyOutput.print(f"文件不存在: {filepath}", OutputType.WARNING)
86
86
  continue
87
87
 
88
88
  # Read original file content
@@ -90,7 +90,7 @@ def apply_patch(output_str: str)->str:
90
90
 
91
91
  # Validate line numbers
92
92
  if start_line < 0 or end_line > len(lines) + 1 or start_line > end_line:
93
- PrettyOutput.print(f"Invalid line range [{start_line}, {end_line}) for file: {filepath}", OutputType.WARNING)
93
+ PrettyOutput.print(f"无效的行范围 [{start_line}, {end_line}) 对于文件: {filepath}", OutputType.WARNING)
94
94
  continue
95
95
 
96
96
  # Create new content
@@ -99,15 +99,21 @@ def apply_patch(output_str: str)->str:
99
99
  # Write back to file
100
100
  open(filepath, 'w', encoding='utf-8').writelines(lines)
101
101
 
102
- PrettyOutput.print(f"Applied patch to {filepath} successfully\n", OutputType.SUCCESS)
102
+ PrettyOutput.print(f"成功应用补丁到 {filepath}", OutputType.SUCCESS)
103
103
 
104
104
  except Exception as e:
105
- PrettyOutput.print(f"Error applying patch to {filepath}: {str(e)}", OutputType.ERROR)
105
+ PrettyOutput.print(f"应用补丁到 {filepath} 失败: {str(e)}", OutputType.ERROR)
106
106
  continue
107
-
107
+ ret = ""
108
108
  if has_uncommitted_changes():
109
- handle_commit_workflow()
110
- return ""
109
+ if handle_commit_workflow():
110
+ ret += "Successfully applied the patch"
111
+ else:
112
+ ret += "User rejected the patch"
113
+ user_input = get_multiline_input("你可以继续输入: ")
114
+ if user_input:
115
+ ret += user_input
116
+ return ret
111
117
 
112
118
  def handle_commit_workflow()->bool:
113
119
  """Handle the git commit workflow and return the commit details.
@@ -115,11 +121,14 @@ def handle_commit_workflow()->bool:
115
121
  Returns:
116
122
  tuple[bool, str, str]: (continue_execution, commit_id, commit_message)
117
123
  """
124
+ os.system("git add .")
118
125
  diff = os.popen("git diff HEAD").read()
126
+ os.system("git reset HEAD")
119
127
  PrettyOutput.print(diff, OutputType.CODE, lang="diff")
120
- if not user_confirm("Do you want to commit the code?", default=True):
128
+ if not user_confirm("是否要提交代码?", default=True):
121
129
  os.system("git reset HEAD")
122
130
  os.system("git checkout -- .")
131
+ os.system("git clean -fd")
123
132
  return False
124
133
 
125
134
  git_commiter = GitCommitTool()
@@ -1,27 +1,79 @@
1
1
  import os
2
2
  import re
3
- from typing import List
3
+ from typing import Dict, List, Optional, Tuple
4
4
 
5
- import yaml
6
- from jarvis.agent import Agent
7
5
  from jarvis.jarvis_code_agent.file_select import select_files
8
6
  from jarvis.jarvis_codebase.main import CodeBase
9
7
  from jarvis.jarvis_platform.registry import PlatformRegistry
10
- from jarvis.jarvis_tools.registry import ToolRegistry
11
- from jarvis.utils import OutputType, PrettyOutput, is_disable_codebase
8
+ from jarvis.utils import OutputType, PrettyOutput
12
9
 
10
+ def make_question(requirement: str) -> Optional[str]:
11
+ """Generate structured questions to gather necessary information for the requirement."""
12
+ prompt = f"""You are a code analysis expert who helps developers understand existing system implementations. Generate specific questions to investigate:
13
+ - Current system implementations
14
+ - Existing interfaces and integration points
15
+ - Extension mechanisms and patterns
16
+ - Related components and their interactions
13
17
 
14
- def find_relevant_files(user_input: str, root_dir: str) -> List[str]:
15
- try:
16
- files_from_codebase = []
17
- if not is_disable_codebase():
18
- PrettyOutput.print("Find files from codebase...", OutputType.INFO)
19
- codebase = CodeBase(root_dir)
20
- files_from_codebase = codebase.search_similar(user_input)
18
+ Key Instructions:
19
+ 1. Focus on understanding the EXISTING system
20
+ 2. Ask about interfaces, hooks, and extension points
21
+ 3. Investigate integration patterns and dependencies
22
+ 4. Explore current implementation details
23
+
24
+ For example:
25
+ BAD: "How should we implement the new feature?"
26
+ GOOD: "What are the existing extension points in the authentication system that we can use to add the new OAuth provider? Specifically, how does AuthProvider interface work and where is it currently used?"
27
+
28
+ Consider these investigation aspects:
29
+
30
+ 1. System Architecture:
31
+ - "What are the existing interfaces/classes that handle [functionality]?"
32
+ - "How is [feature] currently integrated with other components?"
33
+ - "Where are the extension points for [system component]?"
34
+
35
+ 2. Implementation Details:
36
+ - "What is the current workflow for [operation] in the system?"
37
+ - "How does the system expose hooks/callbacks for [functionality]?"
38
+ - "Which interfaces/abstract classes are used for [feature] extensibility?"
39
+
40
+ 3. Integration Patterns:
41
+ - "How do existing components integrate with [system part]?"
42
+ - "What are the current integration points for [feature]?"
43
+ - "How does the system handle extensions to [component]?"
21
44
 
22
- PrettyOutput.print("Find files by agent...", OutputType.INFO)
45
+ 4. Extension Mechanisms:
46
+ - "What patterns are used for extending [functionality]?"
47
+ - "How do existing plugins/extensions connect to [system]?"
48
+ - "Where are the configuration points for [feature] customization?"
49
+
50
+ User Requirement:
51
+ {requirement}
52
+
53
+ Output Format:
54
+ <QUESTION>
55
+ [Write 3-5 specific questions focusing on existing implementations and extension points. Each question should help understand how to integrate with or extend the current system]
56
+ </QUESTION>
57
+ """
58
+ model = PlatformRegistry().get_thinking_platform()
59
+ response = model.chat_until_success(prompt)
60
+ response = re.search(r'<QUESTION>(.*?)</QUESTION>', response, re.DOTALL)
61
+ if response is None:
62
+ return None
63
+ return response.group(1)
64
+
65
+
66
+ def find_relevant_information(user_input: str, root_dir: str) -> Tuple[List[Dict[str, str]], str]:
67
+ try:
68
+ PrettyOutput.print("从代码库中查找文件...", OutputType.INFO)
69
+ codebase = CodeBase(root_dir)
70
+ question = make_question(user_input)
71
+ if question is None:
72
+ return [], ""
73
+ files_from_codebase, infomation = codebase.ask_codebase(question)
23
74
 
24
75
  selected_files = select_files(files_from_codebase, os.getcwd())
25
- return selected_files
26
- except Exception as e:
27
- return []
76
+ return selected_files, infomation
77
+ except Exception:
78
+ PrettyOutput.print("查找相关文件失败", OutputType.ERROR)
79
+ return [], ""