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
jarvis/tools/registry.py CHANGED
@@ -1,6 +1,4 @@
1
- import importlib
2
1
  import json
3
- import os
4
2
  from pathlib import Path
5
3
  import sys
6
4
  from typing import Any, Callable, Dict, List, Optional
@@ -10,21 +8,7 @@ from jarvis.tools.base import Tool
10
8
  from jarvis.utils import OutputType, PrettyOutput, get_max_context_length
11
9
 
12
10
 
13
-
14
- def load_tools() -> str:
15
- """Load tools"""
16
- PrettyOutput.section("Available tools", OutputType.PLANNING)
17
- tools = ToolRegistry.get_global_tool_registry().get_all_tools()
18
- if tools:
19
- tools_prompt = "Available tools:\n"
20
- for tool in tools:
21
- PrettyOutput.print(f"{tool['name']}: {tool['description']}", OutputType.INFO)
22
- tools_prompt += f"- Name: {tool['name']}\n"
23
- tools_prompt += f" Description: {tool['description']}\n"
24
- tools_prompt += f" Parameters: {tool['parameters']}\n"
25
- tools_prompt += f" Usage Format: <TOOL_CALL>\n"
26
- tools_prompt += """
27
- Tool Usage Format:
11
+ tool_call_help = """Tool Usage Format:
28
12
 
29
13
  <TOOL_CALL>
30
14
  name: tool_name
@@ -32,13 +16,48 @@ arguments:
32
16
  param1: value1
33
17
  param2: value2
34
18
  </TOOL_CALL>
35
- ---------------------------------------------
19
+
20
+ Strict Rules:
21
+ - Execute only one tool at a time
22
+ - Tool execution must strictly follow the tool usage format
23
+ - Wait for user to provide execution results
24
+ - Don't assume or imagine results
25
+ - Don't create fake dialogues
26
+ - If current information is insufficient, you may ask the user for more information
27
+ - Not all problem-solving steps are mandatory, skip as appropriate
28
+ - Request user guidance when multiple iterations show no progress
29
+ - ALWAYS use | syntax for string parameters to prevent parsing errors
30
+ Example:
31
+ <TOOL_CALL>
32
+ name: execute_shell
33
+ arguments:
34
+ command: |
35
+ git status --porcelain
36
+ </TOOL_CALL>
37
+ <TOOL_CALL>
38
+ name: execute_shell
39
+ arguments:
40
+ command: |
41
+ git commit -m "fix bug"
42
+ </TOOL_CALL>
43
+
44
+ - If you can start executing the task, please start directly without asking the user if you can begin.
36
45
  """
37
- return tools_prompt
38
- return ""
39
46
 
40
47
  class ToolRegistry:
41
- global_tool_registry = None # type: ignore
48
+ def load_tools(self) -> str:
49
+ """Load tools"""
50
+ tools = self.get_all_tools()
51
+ if tools:
52
+ tools_prompt = "Available tools:\n"
53
+ for tool in tools:
54
+ tools_prompt += f"- Name: {tool['name']}\n"
55
+ tools_prompt += f" Description: {tool['description']}\n"
56
+ tools_prompt += f" Parameters: {tool['parameters']}\n"
57
+ tools_prompt += tool_call_help
58
+ return tools_prompt
59
+ return ""
60
+
42
61
  def __init__(self):
43
62
  """Initialize tool registry"""
44
63
  self.tools: Dict[str, Tool] = {}
@@ -58,12 +77,6 @@ class ToolRegistry:
58
77
  def dont_use_tools(self, names: List[str]):
59
78
  """Remove specified tools from the registry"""
60
79
  self.tools = {name: tool for name, tool in self.tools.items() if name not in names}
61
- @staticmethod
62
- def get_global_tool_registry():
63
- """Get the global tool registry"""
64
- if ToolRegistry.global_tool_registry is None:
65
- ToolRegistry.global_tool_registry = ToolRegistry()
66
- return ToolRegistry.global_tool_registry
67
80
 
68
81
  def _load_builtin_tools(self):
69
82
  """Load tools from the built-in tools directory"""
@@ -106,48 +119,53 @@ class ToolRegistry:
106
119
  PrettyOutput.print(f"File does not exist: {p_file_path}", OutputType.ERROR)
107
120
  return False
108
121
 
109
- # Dynamically import the module
110
- module_name = p_file_path.stem
111
- spec = importlib.util.spec_from_file_location(module_name, p_file_path) # type: ignore
112
- if not spec or not spec.loader:
113
- PrettyOutput.print(f"Failed to load module: {p_file_path}", OutputType.ERROR)
114
- return False
115
-
116
- module = importlib.util.module_from_spec(spec) # type: ignore
117
- sys.modules[module_name] = module # Add to sys.modules to support relative imports
118
- spec.loader.exec_module(module)
122
+ # Add the parent directory to sys.path temporarily
123
+ parent_dir = str(p_file_path.parent)
124
+ sys.path.insert(0, parent_dir)
119
125
 
120
- # Find the tool class in the module
121
- tool_found = False
122
- for item_name in dir(module):
123
- item = getattr(module, item_name)
124
- # Check if it is a class and has the necessary attributes
125
- if (isinstance(item, type) and
126
- hasattr(item, 'name') and
127
- hasattr(item, 'description') and
128
- hasattr(item, 'parameters')):
129
-
130
- # Instantiate the tool class, passing in the model and output processor
131
- tool_instance = item()
132
-
133
- # Register the tool
134
- self.register_tool(
135
- name=tool_instance.name,
136
- description=tool_instance.description,
137
- parameters=tool_instance.parameters,
138
- func=tool_instance.execute
139
- )
140
- tool_found = True
141
- break
126
+ try:
127
+ # Import the module using standard import mechanism
128
+ module_name = p_file_path.stem
129
+ module = __import__(module_name)
130
+
131
+ # Find the tool class in the module
132
+ tool_found = False
133
+ for item_name in dir(module):
134
+ item = getattr(module, item_name)
135
+ # Check if it is a class and has the necessary attributes
136
+ if (isinstance(item, type) and
137
+ hasattr(item, 'name') and
138
+ hasattr(item, 'description') and
139
+ hasattr(item, 'parameters')):
140
+
141
+ if hasattr(item, "check"):
142
+ if not item.check():
143
+ continue
144
+
145
+ # Instantiate the tool class
146
+ tool_instance = item()
147
+
148
+ # Register the tool
149
+ self.register_tool(
150
+ name=tool_instance.name,
151
+ description=tool_instance.description,
152
+ parameters=tool_instance.parameters,
153
+ func=tool_instance.execute
154
+ )
155
+ tool_found = True
156
+ break
157
+
158
+ if not tool_found:
159
+ return False
142
160
 
143
- if not tool_found:
144
- PrettyOutput.print(f"No valid tool class found in the file: {p_file_path}", OutputType.WARNING)
145
- return False
161
+ return True
162
+
163
+ finally:
164
+ # Remove the directory from sys.path
165
+ sys.path.remove(parent_dir)
146
166
 
147
- return True
148
-
149
167
  except Exception as e:
150
- PrettyOutput.print(f"Failed to load tool from {p_file_path.name}: {str(e)}", OutputType.ERROR)
168
+ PrettyOutput.print(f"Failed to load tool from {Path(file_path).name}: {str(e)}", OutputType.ERROR)
151
169
  return False
152
170
 
153
171
  def register_tool(self, name: str, description: str, parameters: Dict, func: Callable):
@@ -200,11 +218,14 @@ arguments:
200
218
 
201
219
  # Display tool call information
202
220
  PrettyOutput.section(f"Executing tool: {name}", OutputType.TOOL)
221
+ params = "Parameters:\n"
203
222
  if isinstance(args, dict):
204
223
  for key, value in args.items():
205
- PrettyOutput.print(f"Parameter: {key} = {value}", OutputType.DEBUG)
224
+ params += f"{key} = {value}\n"
206
225
  else:
207
- PrettyOutput.print(f"Parameter: {args}", OutputType.DEBUG)
226
+ params += f"{args}"
227
+
228
+ PrettyOutput.print(params, OutputType.INFO)
208
229
 
209
230
  # Execute tool call
210
231
  result = self.execute_tool(name, args)
@@ -264,7 +285,10 @@ Please provide a summary:"""
264
285
 
265
286
  else:
266
287
  PrettyOutput.section("Execution failed", OutputType.WARNING)
267
-
288
+ PrettyOutput.print(result["stderr"], OutputType.WARNING)
289
+
290
+ if len(tool_calls) > 1:
291
+ output += f"\n\n--- Only one tool can be executed at a time, the following tools were not executed\n{str(tool_calls[1:])} ---"
268
292
  return output
269
293
 
270
294
  except Exception as e:
jarvis/tools/search.py CHANGED
@@ -211,17 +211,19 @@ def main():
211
211
  PrettyOutput.print(f"\nFound {len(results)} results:", OutputType.INFO)
212
212
 
213
213
  for i, result in enumerate(results[:args.max], 1):
214
- PrettyOutput.print(f"\n{'-'*50}", OutputType.INFO)
214
+ output = []
215
+ output.append(f"\n{'-'*50}")
215
216
  if args.url_only:
216
- PrettyOutput.print(f"{i}. {result['href']}", OutputType.INFO)
217
+ output.append(f"{i}. {result['href']}")
217
218
  else:
218
- PrettyOutput.print(f"{i}. {result['title']}", OutputType.INFO)
219
- PrettyOutput.print(f"Link: {result['href']}", OutputType.INFO)
219
+ output.append(f"{i}. {result['title']}")
220
+ output.append(f"Link: {result['href']}")
220
221
  if result['abstract']:
221
- PrettyOutput.print(f"Abstract: {result['abstract']}", OutputType.INFO)
222
+ output.append(f"Abstract: {result['abstract']}")
223
+ PrettyOutput.print("\n".join(output), OutputType.INFO)
222
224
 
223
225
  except KeyboardInterrupt:
224
- PrettyOutput.print("\nSearch cancelled", OutputType.WARNING)
226
+ PrettyOutput.print("Search cancelled", OutputType.WARNING)
225
227
  sys.exit(1)
226
228
  except Exception as e:
227
229
  PrettyOutput.print(f"Execution error: {str(e)}", OutputType.ERROR)
@@ -1,7 +1,7 @@
1
- from typing import Dict, Any, List
1
+ from typing import Dict, Any
2
2
 
3
3
  from jarvis.utils import OutputType, PrettyOutput
4
- from jarvis.jarvis_coder.file_select import select_files
4
+ from jarvis.jarvis_code_agent.file_select import select_files
5
5
 
6
6
 
7
7
  class CodeFileSelecterTool:
@@ -30,8 +30,8 @@ class CodeFileSelecterTool:
30
30
  def execute(self, args: Dict) -> Dict[str, Any]:
31
31
  """Execute interactive file selection"""
32
32
  try:
33
- related_files = args["related_files"]
34
- root_dir = args.get("root_dir", ".")
33
+ related_files = args.get("related_files", [])
34
+ root_dir = args.get("root_dir", ".").strip()
35
35
 
36
36
  PrettyOutput.print("Starting interactive file selection...", OutputType.INFO)
37
37