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.
- jarvis/__init__.py +1 -1
- jarvis/agent.py +140 -140
- jarvis/jarvis_code_agent/code_agent.py +234 -0
- jarvis/{jarvis_coder → jarvis_code_agent}/file_select.py +16 -17
- jarvis/jarvis_code_agent/patch.py +118 -0
- jarvis/jarvis_code_agent/relevant_files.py +66 -0
- jarvis/jarvis_codebase/main.py +32 -29
- jarvis/jarvis_platform/main.py +5 -3
- jarvis/jarvis_rag/main.py +11 -15
- jarvis/jarvis_smart_shell/main.py +2 -2
- jarvis/models/ai8.py +1 -0
- jarvis/models/kimi.py +36 -30
- jarvis/models/ollama.py +17 -11
- jarvis/models/openai.py +15 -12
- jarvis/models/oyi.py +22 -7
- jarvis/models/registry.py +1 -25
- jarvis/tools/__init__.py +0 -6
- jarvis/tools/ask_codebase.py +99 -0
- jarvis/tools/ask_user.py +1 -9
- jarvis/tools/chdir.py +1 -1
- jarvis/tools/code_review.py +163 -0
- jarvis/tools/create_code_sub_agent.py +19 -45
- jarvis/tools/create_code_test_agent.py +115 -0
- jarvis/tools/create_ctags_agent.py +176 -0
- jarvis/tools/create_sub_agent.py +2 -2
- jarvis/tools/execute_shell.py +2 -2
- jarvis/tools/file_operation.py +2 -2
- jarvis/tools/find_in_codebase.py +108 -0
- jarvis/tools/git_commiter.py +68 -0
- jarvis/tools/methodology.py +3 -3
- jarvis/tools/rag.py +6 -3
- jarvis/tools/read_code.py +147 -0
- jarvis/tools/read_webpage.py +1 -1
- jarvis/tools/registry.py +92 -68
- jarvis/tools/search.py +8 -6
- jarvis/tools/select_code_files.py +4 -4
- jarvis/utils.py +270 -95
- {jarvis_ai_assistant-0.1.101.dist-info → jarvis_ai_assistant-0.1.103.dist-info}/METADATA +9 -5
- jarvis_ai_assistant-0.1.103.dist-info/RECORD +51 -0
- {jarvis_ai_assistant-0.1.101.dist-info → jarvis_ai_assistant-0.1.103.dist-info}/entry_points.txt +4 -2
- jarvis/jarvis_code_agent/main.py +0 -202
- jarvis/jarvis_coder/__init__.py +0 -0
- jarvis/jarvis_coder/git_utils.py +0 -123
- jarvis/jarvis_coder/main.py +0 -241
- jarvis/jarvis_coder/patch_handler.py +0 -340
- jarvis/jarvis_coder/plan_generator.py +0 -145
- jarvis/tools/execute_code_modification.py +0 -70
- jarvis/tools/find_files.py +0 -119
- jarvis/tools/generate_tool.py +0 -174
- jarvis/tools/thinker.py +0 -151
- jarvis_ai_assistant-0.1.101.dist-info/RECORD +0 -51
- {jarvis_ai_assistant-0.1.101.dist-info → jarvis_ai_assistant-0.1.103.dist-info}/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.101.dist-info → jarvis_ai_assistant-0.1.103.dist-info}/WHEEL +0 -0
- {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
|
-
|
|
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
|
-
#
|
|
110
|
-
|
|
111
|
-
|
|
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
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
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
|
-
|
|
144
|
-
|
|
145
|
-
|
|
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 {
|
|
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
|
-
|
|
224
|
+
params += f"{key} = {value}\n"
|
|
206
225
|
else:
|
|
207
|
-
|
|
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
|
-
|
|
214
|
+
output = []
|
|
215
|
+
output.append(f"\n{'-'*50}")
|
|
215
216
|
if args.url_only:
|
|
216
|
-
|
|
217
|
+
output.append(f"{i}. {result['href']}")
|
|
217
218
|
else:
|
|
218
|
-
|
|
219
|
-
|
|
219
|
+
output.append(f"{i}. {result['title']}")
|
|
220
|
+
output.append(f"Link: {result['href']}")
|
|
220
221
|
if result['abstract']:
|
|
221
|
-
|
|
222
|
+
output.append(f"Abstract: {result['abstract']}")
|
|
223
|
+
PrettyOutput.print("\n".join(output), OutputType.INFO)
|
|
222
224
|
|
|
223
225
|
except KeyboardInterrupt:
|
|
224
|
-
PrettyOutput.print("
|
|
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
|
|
1
|
+
from typing import Dict, Any
|
|
2
2
|
|
|
3
3
|
from jarvis.utils import OutputType, PrettyOutput
|
|
4
|
-
from jarvis.
|
|
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
|
|
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
|
|