jarvis-ai-assistant 0.1.99__py3-none-any.whl → 0.1.100__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 +12 -12
- jarvis/jarvis_code_agent/main.py +26 -27
- jarvis/jarvis_codebase/main.py +3 -3
- jarvis/jarvis_coder/git_utils.py +4 -4
- jarvis/jarvis_coder/main.py +2 -8
- jarvis/jarvis_coder/patch_handler.py +152 -74
- jarvis/jarvis_platform/main.py +2 -2
- jarvis/jarvis_rag/main.py +2 -2
- jarvis/jarvis_smart_shell/main.py +6 -4
- jarvis/models/kimi.py +2 -2
- jarvis/models/openai.py +1 -1
- jarvis/models/registry.py +35 -12
- jarvis/tools/ask_user.py +6 -3
- jarvis/tools/chdir.py +9 -5
- jarvis/tools/create_code_sub_agent.py +2 -1
- jarvis/tools/create_sub_agent.py +2 -1
- jarvis/tools/execute_code_modification.py +4 -6
- jarvis/tools/execute_shell.py +2 -2
- jarvis/tools/file_operation.py +10 -5
- jarvis/tools/find_files.py +119 -0
- jarvis/tools/generate_tool.py +27 -25
- jarvis/tools/methodology.py +13 -7
- jarvis/tools/rag.py +9 -5
- jarvis/tools/read_webpage.py +4 -2
- jarvis/tools/registry.py +25 -15
- jarvis/tools/search.py +18 -15
- jarvis/tools/select_code_files.py +2 -5
- jarvis/tools/thinker.py +7 -5
- jarvis/utils.py +53 -34
- {jarvis_ai_assistant-0.1.99.dist-info → jarvis_ai_assistant-0.1.100.dist-info}/METADATA +9 -8
- jarvis_ai_assistant-0.1.100.dist-info/RECORD +51 -0
- jarvis/tools/codebase_qa.py +0 -72
- jarvis/tools/find_related_files.py +0 -86
- jarvis_ai_assistant-0.1.99.dist-info/RECORD +0 -52
- {jarvis_ai_assistant-0.1.99.dist-info → jarvis_ai_assistant-0.1.100.dist-info}/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.99.dist-info → jarvis_ai_assistant-0.1.100.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.99.dist-info → jarvis_ai_assistant-0.1.100.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.1.99.dist-info → jarvis_ai_assistant-0.1.100.dist-info}/top_level.txt +0 -0
jarvis/tools/rag.py
CHANGED
|
@@ -66,14 +66,16 @@ class RAGTool:
|
|
|
66
66
|
if not os.path.exists(dir_path):
|
|
67
67
|
return {
|
|
68
68
|
"success": False,
|
|
69
|
-
"
|
|
69
|
+
"stdout": "",
|
|
70
|
+
"stderr": f"Directory does not exist: {dir_path}"
|
|
70
71
|
}
|
|
71
72
|
|
|
72
73
|
# Check if it is a directory
|
|
73
74
|
if not os.path.isdir(dir_path):
|
|
74
75
|
return {
|
|
75
76
|
"success": False,
|
|
76
|
-
"
|
|
77
|
+
"stdout": "",
|
|
78
|
+
"stderr": f"The path is not a directory: {dir_path}"
|
|
77
79
|
}
|
|
78
80
|
|
|
79
81
|
# Get RAG instance
|
|
@@ -91,7 +93,8 @@ class RAGTool:
|
|
|
91
93
|
if response is None:
|
|
92
94
|
return {
|
|
93
95
|
"success": False,
|
|
94
|
-
"
|
|
96
|
+
"stdout": "",
|
|
97
|
+
"stderr": "Failed to get answer, possibly no relevant documents found"
|
|
95
98
|
}
|
|
96
99
|
|
|
97
100
|
return {
|
|
@@ -104,7 +107,8 @@ class RAGTool:
|
|
|
104
107
|
PrettyOutput.print(f"Document question and answer failed: {str(e)}", OutputType.ERROR)
|
|
105
108
|
return {
|
|
106
109
|
"success": False,
|
|
107
|
-
"
|
|
110
|
+
"stdout": "",
|
|
111
|
+
"stderr": f"Execution failed: {str(e)}"
|
|
108
112
|
}
|
|
109
113
|
|
|
110
114
|
def main():
|
|
@@ -128,7 +132,7 @@ def main():
|
|
|
128
132
|
PrettyOutput.print("\nAnswer:", OutputType.INFO)
|
|
129
133
|
PrettyOutput.print(result["stdout"], OutputType.INFO)
|
|
130
134
|
else:
|
|
131
|
-
PrettyOutput.print(result["
|
|
135
|
+
PrettyOutput.print(result["stderr"], OutputType.ERROR)
|
|
132
136
|
|
|
133
137
|
if __name__ == "__main__":
|
|
134
138
|
main()
|
jarvis/tools/read_webpage.py
CHANGED
|
@@ -67,10 +67,12 @@ class WebpageTool:
|
|
|
67
67
|
except requests.RequestException as e:
|
|
68
68
|
return {
|
|
69
69
|
"success": False,
|
|
70
|
-
"
|
|
70
|
+
"stdout": "",
|
|
71
|
+
"stderr": f"Webpage request failed: {str(e)}"
|
|
71
72
|
}
|
|
72
73
|
except Exception as e:
|
|
73
74
|
return {
|
|
74
75
|
"success": False,
|
|
75
|
-
"
|
|
76
|
+
"stdout": "",
|
|
77
|
+
"stderr": f"Failed to parse webpage: {str(e)}"
|
|
76
78
|
}
|
jarvis/tools/registry.py
CHANGED
|
@@ -48,6 +48,16 @@ class ToolRegistry:
|
|
|
48
48
|
# Ensure max_context_length is an integer
|
|
49
49
|
self.max_context_length = int(get_max_context_length() * 0.8)
|
|
50
50
|
|
|
51
|
+
def use_tools(self, name: List[str]):
|
|
52
|
+
"""Use specified tools"""
|
|
53
|
+
missing_tools = [tool_name for tool_name in name if tool_name not in self.tools]
|
|
54
|
+
if missing_tools:
|
|
55
|
+
PrettyOutput.print(f"Tools {missing_tools} do not exist, available tools: {', '.join(self.tools.keys())}", OutputType.WARNING)
|
|
56
|
+
self.tools = {tool_name: self.tools[tool_name] for tool_name in name}
|
|
57
|
+
|
|
58
|
+
def dont_use_tools(self, names: List[str]):
|
|
59
|
+
"""Remove specified tools from the registry"""
|
|
60
|
+
self.tools = {name: tool for name, tool in self.tools.items() if name not in names}
|
|
51
61
|
@staticmethod
|
|
52
62
|
def get_global_tool_registry():
|
|
53
63
|
"""Get the global tool registry"""
|
|
@@ -68,8 +78,8 @@ class ToolRegistry:
|
|
|
68
78
|
self.register_tool_by_file(str(file_path))
|
|
69
79
|
|
|
70
80
|
def _load_external_tools(self):
|
|
71
|
-
"""Load external tools from ~/.
|
|
72
|
-
external_tools_dir = Path.home() / '.
|
|
81
|
+
"""Load external tools from ~/.jarvis/tools"""
|
|
82
|
+
external_tools_dir = Path.home() / '.jarvis/tools'
|
|
73
83
|
if not external_tools_dir.exists():
|
|
74
84
|
return
|
|
75
85
|
|
|
@@ -156,7 +166,7 @@ class ToolRegistry:
|
|
|
156
166
|
"""Execute a specified tool"""
|
|
157
167
|
tool = self.get_tool(name)
|
|
158
168
|
if tool is None:
|
|
159
|
-
return {"success": False, "
|
|
169
|
+
return {"success": False, "stderr": f"Tool {name} does not exist, available tools: {', '.join(self.tools.keys())}", "stdout": ""}
|
|
160
170
|
return tool.execute(arguments)
|
|
161
171
|
|
|
162
172
|
def handle_tool_calls(self, tool_calls: List[Dict]) -> str:
|
|
@@ -198,18 +208,20 @@ arguments:
|
|
|
198
208
|
|
|
199
209
|
# Execute tool call
|
|
200
210
|
result = self.execute_tool(name, args)
|
|
211
|
+
|
|
212
|
+
stdout = result["stdout"]
|
|
213
|
+
stderr = result.get("stderr", "")
|
|
214
|
+
output_parts = []
|
|
215
|
+
if stdout:
|
|
216
|
+
output_parts.append(f"Output:\n{stdout}")
|
|
217
|
+
if stderr:
|
|
218
|
+
output_parts.append(f"Error:\n{stderr}")
|
|
219
|
+
output = "\n\n".join(output_parts)
|
|
220
|
+
output = "no output and error" if not output else output
|
|
201
221
|
|
|
202
222
|
# Process the result
|
|
203
223
|
if result["success"]:
|
|
204
|
-
|
|
205
|
-
stderr = result.get("stderr", "")
|
|
206
|
-
output_parts = []
|
|
207
|
-
if stdout:
|
|
208
|
-
output_parts.append(f"Output:\n{stdout}")
|
|
209
|
-
if stderr:
|
|
210
|
-
output_parts.append(f"Error:\n{stderr}")
|
|
211
|
-
output = "\n\n".join(output_parts)
|
|
212
|
-
output = "Tool execution successful, no output and error" if not output else output
|
|
224
|
+
|
|
213
225
|
PrettyOutput.section("Execution successful", OutputType.SUCCESS)
|
|
214
226
|
|
|
215
227
|
# If the output exceeds 4k characters, use a large model to summarize
|
|
@@ -251,9 +263,7 @@ Please provide a summary:"""
|
|
|
251
263
|
output = f"Output is too long ({len(output)} characters), it is recommended to view the original output.\nPreview of the first 300 characters:\n{output[:300]}..."
|
|
252
264
|
|
|
253
265
|
else:
|
|
254
|
-
|
|
255
|
-
output = f"Execution failed: {error_msg}"
|
|
256
|
-
PrettyOutput.section("Execution failed", OutputType.ERROR)
|
|
266
|
+
PrettyOutput.section("Execution failed", OutputType.WARNING)
|
|
257
267
|
|
|
258
268
|
return output
|
|
259
269
|
|
jarvis/tools/search.py
CHANGED
|
@@ -8,32 +8,32 @@ from urllib.parse import quote
|
|
|
8
8
|
def bing_search(query):
|
|
9
9
|
try:
|
|
10
10
|
with sync_playwright() as p:
|
|
11
|
-
#
|
|
11
|
+
# Set parameters when starting the browser
|
|
12
12
|
browser = p.chromium.launch(
|
|
13
|
-
headless=True, #
|
|
13
|
+
headless=True, # Headless mode
|
|
14
14
|
args=['--disable-gpu', '--no-sandbox', '--disable-dev-shm-usage']
|
|
15
15
|
)
|
|
16
16
|
|
|
17
|
-
#
|
|
17
|
+
# Create a new page and set timeout
|
|
18
18
|
page = browser.new_page(
|
|
19
19
|
user_agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36',
|
|
20
20
|
viewport={'width': 1920, 'height': 1080}
|
|
21
21
|
)
|
|
22
22
|
|
|
23
|
-
#
|
|
23
|
+
# Set page timeout
|
|
24
24
|
page.set_default_timeout(60000)
|
|
25
25
|
|
|
26
|
-
#
|
|
26
|
+
# Visit search page
|
|
27
27
|
url = f"https://www.bing.com/search?q={quote(query)}&form=QBLH&sp=-1"
|
|
28
28
|
page.goto(url, wait_until="networkidle")
|
|
29
29
|
|
|
30
|
-
#
|
|
30
|
+
# Wait for search results to load
|
|
31
31
|
page.wait_for_selector("#b_results", state="visible", timeout=30000)
|
|
32
32
|
|
|
33
|
-
#
|
|
33
|
+
# Wait for a moment to ensure the results are fully loaded
|
|
34
34
|
page.wait_for_timeout(1000)
|
|
35
35
|
|
|
36
|
-
#
|
|
36
|
+
# Extract search results
|
|
37
37
|
summaries = page.evaluate("""() => {
|
|
38
38
|
const results = [];
|
|
39
39
|
const elements = document.querySelectorAll("#b_results > .b_algo");
|
|
@@ -96,7 +96,7 @@ class SearchTool:
|
|
|
96
96
|
if not results:
|
|
97
97
|
return []
|
|
98
98
|
|
|
99
|
-
#
|
|
99
|
+
# Format search results
|
|
100
100
|
formatted_results = []
|
|
101
101
|
for result in results[:max_results]:
|
|
102
102
|
formatted_results.append({
|
|
@@ -142,15 +142,16 @@ When answering, pay attention to:
|
|
|
142
142
|
PrettyOutput.print(f"Search query: {query}", OutputType.INFO)
|
|
143
143
|
PrettyOutput.print(f"Related question: {question}", OutputType.INFO)
|
|
144
144
|
|
|
145
|
-
#
|
|
145
|
+
# Get search results
|
|
146
146
|
results = self._search(query, max_results)
|
|
147
147
|
if not results:
|
|
148
148
|
return {
|
|
149
149
|
"success": False,
|
|
150
|
-
"
|
|
150
|
+
"stdout": "",
|
|
151
|
+
"stderr": "No search results found"
|
|
151
152
|
}
|
|
152
153
|
|
|
153
|
-
#
|
|
154
|
+
# Collect webpage content
|
|
154
155
|
contents = []
|
|
155
156
|
for i, result in enumerate(results, 1):
|
|
156
157
|
try:
|
|
@@ -166,7 +167,8 @@ When answering, pay attention to:
|
|
|
166
167
|
if not contents:
|
|
167
168
|
return {
|
|
168
169
|
"success": False,
|
|
169
|
-
"
|
|
170
|
+
"stdout": "",
|
|
171
|
+
"stderr": "No valid search results found"
|
|
170
172
|
}
|
|
171
173
|
|
|
172
174
|
# Extract information
|
|
@@ -182,11 +184,12 @@ When answering, pay attention to:
|
|
|
182
184
|
except Exception as e:
|
|
183
185
|
return {
|
|
184
186
|
"success": False,
|
|
185
|
-
"
|
|
187
|
+
"stdout": "",
|
|
188
|
+
"stderr": f"Search failed: {str(e)}"
|
|
186
189
|
}
|
|
187
190
|
|
|
188
191
|
def main():
|
|
189
|
-
"""
|
|
192
|
+
"""Command line directly run search tool"""
|
|
190
193
|
import argparse
|
|
191
194
|
import sys
|
|
192
195
|
|
|
@@ -49,16 +49,13 @@ class CodeFileSelecterTool:
|
|
|
49
49
|
return {
|
|
50
50
|
"success": True,
|
|
51
51
|
"stdout": output,
|
|
52
|
-
"stderr": ""
|
|
53
|
-
"selected_files": selected_files # Return the selected files for other tools to use
|
|
52
|
+
"stderr": ""
|
|
54
53
|
}
|
|
55
54
|
|
|
56
55
|
except Exception as e:
|
|
57
56
|
PrettyOutput.print(str(e), OutputType.ERROR)
|
|
58
57
|
return {
|
|
59
58
|
"success": False,
|
|
60
|
-
"error": f"Failed to select files: {str(e)}",
|
|
61
59
|
"stdout": "",
|
|
62
|
-
"stderr": str(e)
|
|
63
|
-
"selected_files": [] # Return empty list on error
|
|
60
|
+
"stderr": str(e)
|
|
64
61
|
}
|
jarvis/tools/thinker.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from typing import Dict, Any
|
|
2
|
-
from jarvis.utils import OutputType, PrettyOutput,
|
|
2
|
+
from jarvis.utils import OutputType, PrettyOutput, init_env
|
|
3
3
|
from jarvis.models.registry import PlatformRegistry
|
|
4
4
|
|
|
5
5
|
class ThinkerTool:
|
|
@@ -104,7 +104,8 @@ Related context:
|
|
|
104
104
|
if not response:
|
|
105
105
|
return {
|
|
106
106
|
"success": False,
|
|
107
|
-
"
|
|
107
|
+
"stdout": "",
|
|
108
|
+
"stderr": "Failed to obtain valid analysis results"
|
|
108
109
|
}
|
|
109
110
|
|
|
110
111
|
return {
|
|
@@ -117,14 +118,15 @@ Related context:
|
|
|
117
118
|
PrettyOutput.print(f"Thinking analysis failed: {str(e)}", OutputType.ERROR)
|
|
118
119
|
return {
|
|
119
120
|
"success": False,
|
|
120
|
-
"
|
|
121
|
+
"stdout": "",
|
|
122
|
+
"stderr": f"Execution failed: {str(e)}"
|
|
121
123
|
}
|
|
122
124
|
|
|
123
125
|
def main():
|
|
124
126
|
"""Run tool directly from command line"""
|
|
125
127
|
import argparse
|
|
126
128
|
|
|
127
|
-
|
|
129
|
+
init_env()
|
|
128
130
|
|
|
129
131
|
parser = argparse.ArgumentParser(description='Deep thinking analysis tool')
|
|
130
132
|
parser.add_argument('--question', required=True, help='The problem to analyze')
|
|
@@ -143,7 +145,7 @@ def main():
|
|
|
143
145
|
PrettyOutput.print("\nAnalysis results:", OutputType.INFO)
|
|
144
146
|
PrettyOutput.print(result["stdout"], OutputType.INFO)
|
|
145
147
|
else:
|
|
146
|
-
PrettyOutput.print(result["
|
|
148
|
+
PrettyOutput.print(result["stderr"], OutputType.ERROR)
|
|
147
149
|
|
|
148
150
|
if __name__ == "__main__":
|
|
149
151
|
main()
|
jarvis/utils.py
CHANGED
|
@@ -194,10 +194,15 @@ def get_multiline_input(tip: str) -> str:
|
|
|
194
194
|
|
|
195
195
|
return "\n".join(lines)
|
|
196
196
|
|
|
197
|
-
def
|
|
198
|
-
"""Load environment variables from ~/.
|
|
199
|
-
|
|
197
|
+
def init_env():
|
|
198
|
+
"""Load environment variables from ~/.jarvis/env"""
|
|
199
|
+
jarvis_dir = Path.home() / ".jarvis"
|
|
200
|
+
env_file = jarvis_dir / "env"
|
|
200
201
|
|
|
202
|
+
# Check if ~/.jarvis directory exists
|
|
203
|
+
if not jarvis_dir.exists():
|
|
204
|
+
jarvis_dir.mkdir(parents=True)
|
|
205
|
+
|
|
201
206
|
if env_file.exists():
|
|
202
207
|
try:
|
|
203
208
|
with open(env_file, "r", encoding="utf-8") as f:
|
|
@@ -210,7 +215,7 @@ def load_env_from_file():
|
|
|
210
215
|
except ValueError:
|
|
211
216
|
continue
|
|
212
217
|
except Exception as e:
|
|
213
|
-
PrettyOutput.print(f"Warning: Failed to read
|
|
218
|
+
PrettyOutput.print(f"Warning: Failed to read {env_file}: {e}", OutputType.WARNING)
|
|
214
219
|
|
|
215
220
|
|
|
216
221
|
def while_success(func, sleep_time: float = 0.1):
|
|
@@ -242,19 +247,24 @@ def find_git_root(dir="."):
|
|
|
242
247
|
def load_embedding_model():
|
|
243
248
|
model_name = "BAAI/bge-m3"
|
|
244
249
|
cache_dir = os.path.expanduser("~/.cache/huggingface/hub")
|
|
245
|
-
model_dir = os.path.join(cache_dir, "models--" + model_name.replace("/", "--"))
|
|
246
|
-
|
|
247
|
-
# Check if model exists
|
|
248
|
-
if not os.path.exists(model_dir):
|
|
249
|
-
PrettyOutput.print("Model not found locally, downloading using huggingface-cli...", OutputType.INFO)
|
|
250
|
-
os.system(f'huggingface-cli download --repo-type model --local-dir {cache_dir} {model_name}' + f' --token {os.getenv("HF_TOKEN")}' if os.getenv("HF_TOKEN") else "")
|
|
251
250
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
251
|
+
|
|
252
|
+
try:
|
|
253
|
+
# Load model
|
|
254
|
+
embedding_model = SentenceTransformer(
|
|
255
|
+
model_name,
|
|
256
|
+
cache_folder=cache_dir,
|
|
257
|
+
local_files_only=True
|
|
258
|
+
)
|
|
259
|
+
except Exception as e:
|
|
260
|
+
PrettyOutput.print(f"Failed to load embedding model: {str(e)}", OutputType.ERROR)
|
|
261
|
+
os.system(f'huggingface-cli download --repo-type model --local-dir {cache_dir} {model_name}')
|
|
262
|
+
# Load model
|
|
263
|
+
embedding_model = SentenceTransformer(
|
|
264
|
+
model_name,
|
|
265
|
+
cache_folder=cache_dir,
|
|
266
|
+
local_files_only=True
|
|
267
|
+
)
|
|
258
268
|
|
|
259
269
|
return embedding_model
|
|
260
270
|
|
|
@@ -262,26 +272,35 @@ def load_rerank_model():
|
|
|
262
272
|
"""Load reranking model"""
|
|
263
273
|
model_name = "BAAI/bge-reranker-v2-m3"
|
|
264
274
|
cache_dir = os.path.expanduser("~/.cache/huggingface/hub")
|
|
265
|
-
model_dir = os.path.join(cache_dir, "models--" + model_name.replace("/", "--"))
|
|
266
275
|
|
|
267
276
|
PrettyOutput.print(f"Loading reranking model: {model_name}...", OutputType.INFO)
|
|
268
277
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
278
|
+
try:
|
|
279
|
+
# Load model and tokenizer
|
|
280
|
+
tokenizer = AutoTokenizer.from_pretrained(
|
|
281
|
+
model_name,
|
|
282
|
+
cache_dir=cache_dir,
|
|
283
|
+
local_files_only=True
|
|
284
|
+
)
|
|
285
|
+
model = AutoModelForSequenceClassification.from_pretrained(
|
|
286
|
+
model_name,
|
|
287
|
+
cache_dir=cache_dir,
|
|
288
|
+
local_files_only=True
|
|
289
|
+
)
|
|
290
|
+
except Exception as e:
|
|
291
|
+
PrettyOutput.print(f"Failed to load reranking model: {str(e)}", OutputType.ERROR)
|
|
292
|
+
os.system(f'huggingface-cli download --repo-type model --local-dir {cache_dir} {model_name}')
|
|
293
|
+
# Load model and tokenizer
|
|
294
|
+
tokenizer = AutoTokenizer.from_pretrained(
|
|
295
|
+
model_name,
|
|
296
|
+
cache_dir=cache_dir,
|
|
297
|
+
local_files_only=True
|
|
298
|
+
)
|
|
299
|
+
model = AutoModelForSequenceClassification.from_pretrained(
|
|
300
|
+
model_name,
|
|
301
|
+
cache_dir=cache_dir,
|
|
302
|
+
local_files_only=True
|
|
303
|
+
)
|
|
285
304
|
|
|
286
305
|
# Use GPU if available
|
|
287
306
|
if torch.cuda.is_available():
|
|
@@ -341,7 +360,7 @@ def _create_methodology_embedding(embedding_model: Any, methodology_text: str) -
|
|
|
341
360
|
def load_methodology(user_input: str) -> str:
|
|
342
361
|
"""Load methodology and build vector index"""
|
|
343
362
|
PrettyOutput.print("Loading methodology...", OutputType.PROGRESS)
|
|
344
|
-
user_jarvis_methodology = os.path.expanduser("~/.
|
|
363
|
+
user_jarvis_methodology = os.path.expanduser("~/.jarvis/methodology")
|
|
345
364
|
if not os.path.exists(user_jarvis_methodology):
|
|
346
365
|
return ""
|
|
347
366
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: jarvis-ai-assistant
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.100
|
|
4
4
|
Summary: Jarvis: An AI assistant that uses tools to interact with the system
|
|
5
5
|
Home-page: https://github.com/skyfireitdiy/Jarvis
|
|
6
6
|
Author: skyfire
|
|
@@ -125,7 +125,7 @@ pip install jarvis-ai-assistant
|
|
|
125
125
|
|
|
126
126
|
## 🔧 Configuration
|
|
127
127
|
|
|
128
|
-
Jarvis supports configuration through environment variables that can be set in the `~/.
|
|
128
|
+
Jarvis supports configuration through environment variables that can be set in the `~/.jarvis/env` file:
|
|
129
129
|
|
|
130
130
|
| Environment Variable | Description | Default Value | Required |
|
|
131
131
|
|---------|------|--------|------|
|
|
@@ -204,7 +204,7 @@ jarvis-search "your query" --max 3
|
|
|
204
204
|
|
|
205
205
|
### Tool Locations
|
|
206
206
|
- Built-in tools: `src/jarvis/tools/`
|
|
207
|
-
- User tools: `~/.
|
|
207
|
+
- User tools: `~/.jarvis/tools/`
|
|
208
208
|
|
|
209
209
|
|
|
210
210
|
### Key Features
|
|
@@ -241,7 +241,7 @@ jarvis-search "your query" --max 3
|
|
|
241
241
|
|
|
242
242
|
### Adding New Tools
|
|
243
243
|
|
|
244
|
-
Create a new Python file in `~/.
|
|
244
|
+
Create a new Python file in `~/.jarvis/tools/` or `src/jarvis/tools/`:
|
|
245
245
|
|
|
246
246
|
```python
|
|
247
247
|
from typing import Dict, Any
|
|
@@ -273,7 +273,6 @@ class CustomTool:
|
|
|
273
273
|
"success": bool,
|
|
274
274
|
"stdout": str, # On success
|
|
275
275
|
"stderr": str, # Optional error details
|
|
276
|
-
"error": str # On failure
|
|
277
276
|
}
|
|
278
277
|
"""
|
|
279
278
|
try:
|
|
@@ -281,18 +280,20 @@ class CustomTool:
|
|
|
281
280
|
result = "Tool execution result"
|
|
282
281
|
return {
|
|
283
282
|
"success": True,
|
|
284
|
-
"stdout": result
|
|
283
|
+
"stdout": result,
|
|
284
|
+
"stderr": ""
|
|
285
285
|
}
|
|
286
286
|
except Exception as e:
|
|
287
287
|
return {
|
|
288
288
|
"success": False,
|
|
289
|
-
"
|
|
289
|
+
"stdout": "",
|
|
290
|
+
"stderr": str(e)
|
|
290
291
|
}
|
|
291
292
|
```
|
|
292
293
|
|
|
293
294
|
### Adding New Models
|
|
294
295
|
|
|
295
|
-
Create a new Python file in `~/.
|
|
296
|
+
Create a new Python file in `~/.jarvis/models/`:
|
|
296
297
|
|
|
297
298
|
```python
|
|
298
299
|
from typing import Dict, List
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
jarvis/__init__.py,sha256=CCLUaAlEVc1W7PRJT3CV9kBGq5ZA-5WXMJMM1wOz6jk,51
|
|
2
|
+
jarvis/agent.py,sha256=dneYp0w25eeJpodcm59-r8V6fu7G_4MtCntvGNCLgBI,20868
|
|
3
|
+
jarvis/utils.py,sha256=feUUqe8nA7MobPwVKH9ogMZrD1kH87-zeZxHvxWf83s,15807
|
|
4
|
+
jarvis/jarvis_code_agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
+
jarvis/jarvis_code_agent/main.py,sha256=wZkYy_VmTg1iJBmQ6fD39hv2eC8FE6CVgtx7lxIUYHo,7050
|
|
6
|
+
jarvis/jarvis_codebase/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
+
jarvis/jarvis_codebase/main.py,sha256=rnA4rSyRmtVsKQ5HkQnNc57sZnT5sCBcmQFLWdzYJv8,36854
|
|
8
|
+
jarvis/jarvis_coder/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
+
jarvis/jarvis_coder/file_select.py,sha256=BobNj5Kirr6jSwy59LOghC3o8Uff1CwTXNtlTO-idEo,8475
|
|
10
|
+
jarvis/jarvis_coder/git_utils.py,sha256=R83iDYkDHIntQCd6p9g8Nne9oR5TVNhM-frd_2qR8Jo,5021
|
|
11
|
+
jarvis/jarvis_coder/main.py,sha256=jicy9IN_94Dp8hDubOJX8t5h3vAmciAiS3v34WrvJZc,8469
|
|
12
|
+
jarvis/jarvis_coder/patch_handler.py,sha256=zTCjei1rv00-iA2zTh4UlJYEZka_AoCsgisAWA5PDug,14803
|
|
13
|
+
jarvis/jarvis_coder/plan_generator.py,sha256=x-FalwoRg79h-fvDgFQ8Cl-I8zJ7x2qcXsEUnRip9GA,6186
|
|
14
|
+
jarvis/jarvis_platform/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
|
+
jarvis/jarvis_platform/main.py,sha256=h08SaaIRBhqX8yIp_mG9vSKZYVBrBVfcC9gDK4A45RQ,4961
|
|
16
|
+
jarvis/jarvis_rag/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
|
+
jarvis/jarvis_rag/main.py,sha256=tp9skDCrassVTHRlbWJmA880CoF8OZTSFCiknoHRirU,33605
|
|
18
|
+
jarvis/jarvis_smart_shell/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
|
+
jarvis/jarvis_smart_shell/main.py,sha256=G03M39Bfwq8ieNZ8zoDbn0QeDs8Z9h2A0TxP8Hqf9GY,3951
|
|
20
|
+
jarvis/models/__init__.py,sha256=mrOt67nselz_H1gX9wdAO4y2DY5WPXzABqJbr5Des8k,63
|
|
21
|
+
jarvis/models/ai8.py,sha256=ZRNO3aRjmICRjCXl-_F9pTNQTY4j1tUd-WJoJpb9n4Y,11958
|
|
22
|
+
jarvis/models/base.py,sha256=nQ-rsJL1Z-gMev3TPoY7tYdwxhCJY8LG6_gtJ-maiW0,2181
|
|
23
|
+
jarvis/models/kimi.py,sha256=JSjSp_Hmmj_3bn0jxArE4lpG8jkQwhWx8qosjRMHdZE,16391
|
|
24
|
+
jarvis/models/ollama.py,sha256=LzEA4kbkw1KflQ1T__hkmXu4--6xUPho2NTnj_ZQe6k,5761
|
|
25
|
+
jarvis/models/openai.py,sha256=7AYKM0CKlI-tU5NtNdVaw5gobhgqSrXwGQLo5b2MJ7c,4404
|
|
26
|
+
jarvis/models/oyi.py,sha256=iA8E5vzN9VIt-rlzpT5wmbyl7umVU1_y5yo_5gz3DXc,14534
|
|
27
|
+
jarvis/models/registry.py,sha256=SM-jPu9TMommz0Fr_WrXpQE4X24QGyH39h0FwEQ-CWU,9448
|
|
28
|
+
jarvis/tools/__init__.py,sha256=7Rqyj5hBAv5cWDVr5T9ZTZASO7ssBHeQNm2_4ZARdkA,72
|
|
29
|
+
jarvis/tools/ask_user.py,sha256=cSxFn8cOZGQYHtfBtXlbdVQ7mlgC1JZCFBylparWShE,2102
|
|
30
|
+
jarvis/tools/base.py,sha256=c0DMoDDPxmsqUYJR989zgUs7nIYRY6GWBrAdusIZKjc,656
|
|
31
|
+
jarvis/tools/chdir.py,sha256=Nr16rLnrQ_eJH5E5HQ1a9o-UqAckKbWeboB3_SBVdVI,2926
|
|
32
|
+
jarvis/tools/create_code_sub_agent.py,sha256=r5Ec3Ri9TGAj1M4c0Ur10I33aZ1i8dbtGK2DqqeebkQ,1718
|
|
33
|
+
jarvis/tools/create_sub_agent.py,sha256=Nf_37sj8uQp1R1f7G1PkMRzwUFrHXj17WYLbusoDzO0,2807
|
|
34
|
+
jarvis/tools/execute_code_modification.py,sha256=_LpzTiUfK7aprKzCrTDhBuu78miDcVyx7VV1Kh682DA,2508
|
|
35
|
+
jarvis/tools/execute_shell.py,sha256=woJq-fivoXppp8rEhg46WVAImf6O89gHJnA7XOuYSM8,2568
|
|
36
|
+
jarvis/tools/file_operation.py,sha256=Aq1EJA59AHR9XomxuxNiyLNon4p8w-Gk9iionl--odU,4082
|
|
37
|
+
jarvis/tools/find_files.py,sha256=MTqijsXO6uFghb79pGaHWsa1NTgjP07p333BvUgMt5s,3696
|
|
38
|
+
jarvis/tools/generate_tool.py,sha256=qhk73UFEPtMC-QfiWBUxnMhkgZMZM-esd0TdcFhWSmc,6181
|
|
39
|
+
jarvis/tools/methodology.py,sha256=f6rF6vw-qaSIuJUrLbZdsLqzXMmAaw1aCwvJuezRX8k,5586
|
|
40
|
+
jarvis/tools/rag.py,sha256=m_G4ct6SBLKKdUXfPkokK-qVlWeFCJ2B9J5IZhHXBXQ,4879
|
|
41
|
+
jarvis/tools/read_webpage.py,sha256=AqE9Og_OzwFYIHZDTnCe_gB-szcUXbVZh-xZat4WgOU,2467
|
|
42
|
+
jarvis/tools/registry.py,sha256=O-vzSaWr9VR3lrCIPF5NPl4V-zHHmz3H3l1_9ORyKsA,11057
|
|
43
|
+
jarvis/tools/search.py,sha256=qf39Zm2Ad9-z4EyZKJrBCvZg1uqMeLuLQ9Zu8WB-TvI,9230
|
|
44
|
+
jarvis/tools/select_code_files.py,sha256=hJwfh_CnyOn4QOBuNpKh9AD7-iH92mj7FP-6EifSH0w,1875
|
|
45
|
+
jarvis/tools/thinker.py,sha256=-aWbjOjV3tGmYeIgAmyKVjd0teFs4ZK7mzPBA09R7hE,4847
|
|
46
|
+
jarvis_ai_assistant-0.1.100.dist-info/LICENSE,sha256=AGgVgQmTqFvaztRtCAXsAMryUymB18gZif7_l2e1XOg,1063
|
|
47
|
+
jarvis_ai_assistant-0.1.100.dist-info/METADATA,sha256=Q7gLFWY8g_jky5kbsJ9F1YVeBloi1hqQoTKDdF9K9AU,12783
|
|
48
|
+
jarvis_ai_assistant-0.1.100.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
49
|
+
jarvis_ai_assistant-0.1.100.dist-info/entry_points.txt,sha256=x0jA_mYRc7hBVdLuOFQBYQjpXjf8NPrAn0C54DJ9t2I,387
|
|
50
|
+
jarvis_ai_assistant-0.1.100.dist-info/top_level.txt,sha256=1BOxyWfzOP_ZXj8rVTDnNCJ92bBGB0rwq8N1PCpoMIs,7
|
|
51
|
+
jarvis_ai_assistant-0.1.100.dist-info/RECORD,,
|
jarvis/tools/codebase_qa.py
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
from typing import Any, Dict
|
|
3
|
-
from jarvis.jarvis_codebase.main import CodeBase
|
|
4
|
-
from jarvis.utils import find_git_root, PrettyOutput, OutputType
|
|
5
|
-
|
|
6
|
-
class CodebaseQATool:
|
|
7
|
-
"""Codebase QA Tool"""
|
|
8
|
-
|
|
9
|
-
name = "codebase_qa"
|
|
10
|
-
description = "Answer questions about the codebase, can query and understand code functionality, structure, and implementation details"
|
|
11
|
-
parameters = {
|
|
12
|
-
"type": "object",
|
|
13
|
-
"properties": {
|
|
14
|
-
"dir": {
|
|
15
|
-
"type": "string",
|
|
16
|
-
"description": "Project root directory"
|
|
17
|
-
},
|
|
18
|
-
"question": {
|
|
19
|
-
"type": "string",
|
|
20
|
-
"description": "Question about the codebase"
|
|
21
|
-
},
|
|
22
|
-
"top_k": {
|
|
23
|
-
"type": "integer",
|
|
24
|
-
"description": "Number of relevant files to search",
|
|
25
|
-
"default": 5
|
|
26
|
-
}
|
|
27
|
-
},
|
|
28
|
-
"required": ["question"]
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
def execute(self, params: Dict[str, Any]) -> Dict[str, Any]:
|
|
32
|
-
"""Execute codebase QA"""
|
|
33
|
-
try:
|
|
34
|
-
dir = params.get("dir")
|
|
35
|
-
question = params["question"]
|
|
36
|
-
top_k = params.get("top_k", 5)
|
|
37
|
-
|
|
38
|
-
# 初始化代码库
|
|
39
|
-
current_dir = os.getcwd()
|
|
40
|
-
root_dir = find_git_root(dir or current_dir)
|
|
41
|
-
if not root_dir:
|
|
42
|
-
return {
|
|
43
|
-
"success": False,
|
|
44
|
-
"stdout": "",
|
|
45
|
-
"stderr": "Error: Current directory is not in a Git repository",
|
|
46
|
-
"error": "NotInGitRepository"
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
os.chdir(root_dir)
|
|
50
|
-
codebase = CodeBase(root_dir)
|
|
51
|
-
# 生成索引
|
|
52
|
-
|
|
53
|
-
codebase.generate_codebase()
|
|
54
|
-
# 执行问答
|
|
55
|
-
response = codebase.ask_codebase(question, top_k)
|
|
56
|
-
os.chdir(current_dir)
|
|
57
|
-
return {
|
|
58
|
-
"success": True,
|
|
59
|
-
"stdout": response,
|
|
60
|
-
"stderr": "",
|
|
61
|
-
"error": None
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
except Exception as e:
|
|
65
|
-
PrettyOutput.print(f"Codebase QA error: {str(e)}", output_type=OutputType.ERROR)
|
|
66
|
-
return {
|
|
67
|
-
"success": False,
|
|
68
|
-
"stdout": "",
|
|
69
|
-
"stderr": f"Error executing codebase QA: {str(e)}",
|
|
70
|
-
"error": str(type(e).__name__)
|
|
71
|
-
}
|
|
72
|
-
|