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/utils.py
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
from ast import List, Str
|
|
2
1
|
import hashlib
|
|
3
2
|
from pathlib import Path
|
|
4
|
-
import sys
|
|
5
3
|
import time
|
|
6
4
|
import os
|
|
7
5
|
from enum import Enum
|
|
@@ -18,20 +16,53 @@ from transformers import AutoModelForSequenceClassification, AutoTokenizer
|
|
|
18
16
|
import torch
|
|
19
17
|
import yaml
|
|
20
18
|
import faiss
|
|
19
|
+
from pygments.lexers import guess_lexer
|
|
20
|
+
from pygments.util import ClassNotFound
|
|
21
|
+
|
|
22
|
+
from rich.console import Console
|
|
23
|
+
from rich.theme import Theme
|
|
24
|
+
from rich.panel import Panel
|
|
25
|
+
from rich.text import Text
|
|
26
|
+
from rich.traceback import install as install_rich_traceback
|
|
27
|
+
from rich.syntax import Syntax
|
|
28
|
+
|
|
29
|
+
from prompt_toolkit.completion import Completer, Completion, PathCompleter
|
|
30
|
+
from prompt_toolkit.document import Document
|
|
31
|
+
from fuzzywuzzy import fuzz
|
|
21
32
|
|
|
22
33
|
# 初始化colorama
|
|
23
34
|
colorama.init()
|
|
24
35
|
|
|
25
36
|
os.environ["TOKENIZERS_PARALLELISM"] = "false"
|
|
26
|
-
os.environ["HF_ENDPOINT"] = "https://hf-mirror.com"
|
|
27
37
|
|
|
28
38
|
current_agent = []
|
|
29
39
|
|
|
40
|
+
# Install rich traceback handler
|
|
41
|
+
install_rich_traceback()
|
|
42
|
+
|
|
43
|
+
# Create console with custom theme
|
|
44
|
+
custom_theme = Theme({
|
|
45
|
+
"info": "yellow",
|
|
46
|
+
"warning": "yellow",
|
|
47
|
+
"error": "red",
|
|
48
|
+
"success": "green",
|
|
49
|
+
"system": "cyan",
|
|
50
|
+
"code": "green",
|
|
51
|
+
"result": "blue",
|
|
52
|
+
"planning": "magenta",
|
|
53
|
+
"progress": "white",
|
|
54
|
+
"debug": "blue",
|
|
55
|
+
"user": "green",
|
|
56
|
+
"tool": "yellow",
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
console = Console(theme=custom_theme)
|
|
60
|
+
|
|
30
61
|
def add_agent(agent_name: str):
|
|
31
62
|
current_agent.append(agent_name)
|
|
32
63
|
|
|
33
|
-
def
|
|
34
|
-
return current_agent
|
|
64
|
+
def get_agent_list():
|
|
65
|
+
return ']['.join(current_agent) if current_agent else "No Agent"
|
|
35
66
|
|
|
36
67
|
def delete_current_agent():
|
|
37
68
|
current_agent.pop()
|
|
@@ -51,25 +82,9 @@ class OutputType(Enum):
|
|
|
51
82
|
TOOL = "tool" # Tool call
|
|
52
83
|
|
|
53
84
|
class PrettyOutput:
|
|
54
|
-
"""
|
|
55
|
-
|
|
56
|
-
# 颜色方案 - 只使用前景色
|
|
57
|
-
COLORS = {
|
|
58
|
-
OutputType.SYSTEM: Fore.CYAN, # Cyan - AI assistant
|
|
59
|
-
OutputType.CODE: Fore.GREEN, # Green - Code
|
|
60
|
-
OutputType.RESULT: Fore.BLUE, # Blue - Result
|
|
61
|
-
OutputType.ERROR: Fore.RED, # Red - Error
|
|
62
|
-
OutputType.INFO: Fore.YELLOW, # Yellow - Prompt
|
|
63
|
-
OutputType.PLANNING: Fore.MAGENTA, # Magenta - Planning
|
|
64
|
-
OutputType.PROGRESS: Fore.WHITE, # White - Progress
|
|
65
|
-
OutputType.SUCCESS: Fore.GREEN, # Green - Success
|
|
66
|
-
OutputType.WARNING: Fore.YELLOW, # Yellow - Warning
|
|
67
|
-
OutputType.DEBUG: Fore.BLUE, # Blue - Debug
|
|
68
|
-
OutputType.USER: Fore.GREEN, # Green - User
|
|
69
|
-
OutputType.TOOL: Fore.YELLOW, # Yellow - Tool
|
|
70
|
-
}
|
|
85
|
+
"""Pretty output using rich"""
|
|
71
86
|
|
|
72
|
-
#
|
|
87
|
+
# Icons for different output types
|
|
73
88
|
ICONS = {
|
|
74
89
|
OutputType.SYSTEM: "🤖", # Robot - AI assistant
|
|
75
90
|
OutputType.CODE: "📝", # Notebook - Code
|
|
@@ -84,67 +99,106 @@ class PrettyOutput:
|
|
|
84
99
|
OutputType.USER: "👤", # User - User
|
|
85
100
|
OutputType.TOOL: "🔧", # Wrench - Tool
|
|
86
101
|
}
|
|
87
|
-
|
|
88
|
-
#
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
+
|
|
103
|
+
# Common language mapping dictionary
|
|
104
|
+
_lang_map = {
|
|
105
|
+
'Python': 'python',
|
|
106
|
+
'JavaScript': 'javascript',
|
|
107
|
+
'TypeScript': 'typescript',
|
|
108
|
+
'Java': 'java',
|
|
109
|
+
'C++': 'cpp',
|
|
110
|
+
'C#': 'csharp',
|
|
111
|
+
'Ruby': 'ruby',
|
|
112
|
+
'PHP': 'php',
|
|
113
|
+
'Go': 'go',
|
|
114
|
+
'Rust': 'rust',
|
|
115
|
+
'Bash': 'bash',
|
|
116
|
+
'HTML': 'html',
|
|
117
|
+
'CSS': 'css',
|
|
118
|
+
'SQL': 'sql',
|
|
119
|
+
'R': 'r',
|
|
120
|
+
'Kotlin': 'kotlin',
|
|
121
|
+
'Swift': 'swift',
|
|
122
|
+
'Scala': 'scala',
|
|
123
|
+
'Perl': 'perl',
|
|
124
|
+
'Lua': 'lua',
|
|
125
|
+
'YAML': 'yaml',
|
|
126
|
+
'JSON': 'json',
|
|
127
|
+
'XML': 'xml',
|
|
128
|
+
'Markdown': 'markdown',
|
|
129
|
+
'Text': 'text',
|
|
130
|
+
'Shell': 'bash',
|
|
131
|
+
'Dockerfile': 'dockerfile',
|
|
132
|
+
'Makefile': 'makefile',
|
|
133
|
+
'INI': 'ini',
|
|
134
|
+
'TOML': 'toml',
|
|
102
135
|
}
|
|
103
136
|
|
|
104
137
|
@staticmethod
|
|
105
|
-
def
|
|
106
|
-
"""
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
138
|
+
def _detect_language(text: str, default_lang: str = 'markdown') -> str:
|
|
139
|
+
"""Helper method to detect language and map it to syntax highlighting name"""
|
|
140
|
+
try:
|
|
141
|
+
lexer = guess_lexer(text)
|
|
142
|
+
detected_lang = lexer.name
|
|
143
|
+
return PrettyOutput._lang_map.get(detected_lang, default_lang)
|
|
144
|
+
except ClassNotFound:
|
|
145
|
+
return default_lang
|
|
146
|
+
except Exception:
|
|
147
|
+
return default_lang
|
|
148
|
+
|
|
149
|
+
@staticmethod
|
|
150
|
+
def format(text: str, output_type: OutputType, timestamp: bool = True) -> Text:
|
|
151
|
+
"""Format output text using rich Text"""
|
|
152
|
+
# Create rich Text object
|
|
153
|
+
formatted = Text()
|
|
113
154
|
|
|
114
|
-
#
|
|
115
|
-
|
|
155
|
+
# Add timestamp and agent info
|
|
156
|
+
if timestamp:
|
|
157
|
+
formatted.append(f"[{datetime.now().strftime('%H:%M:%S')}] ", style="white")
|
|
158
|
+
formatted.append(f"[{get_agent_list()}]", style="blue")
|
|
159
|
+
# Add icon
|
|
160
|
+
icon = PrettyOutput.ICONS.get(output_type, "")
|
|
161
|
+
formatted.append(f"{icon} ", style=output_type.value)
|
|
116
162
|
|
|
117
|
-
return
|
|
163
|
+
return formatted
|
|
118
164
|
|
|
119
165
|
@staticmethod
|
|
120
166
|
def print(text: str, output_type: OutputType, timestamp: bool = True):
|
|
121
|
-
"""Print formatted output"""
|
|
122
|
-
|
|
167
|
+
"""Print formatted output using rich console"""
|
|
168
|
+
# Get formatted header
|
|
169
|
+
lang = PrettyOutput._detect_language(text, default_lang='markdown')
|
|
170
|
+
header = PrettyOutput.format("", output_type, timestamp)
|
|
171
|
+
|
|
172
|
+
content = Syntax(text, lang, theme="monokai")
|
|
173
|
+
|
|
174
|
+
# Print panel with appropriate border style
|
|
175
|
+
border_style = "red" if output_type == OutputType.ERROR else output_type.value
|
|
176
|
+
console.print(Panel(content, border_style=border_style, title=header, title_align="left", highlight=True))
|
|
177
|
+
|
|
178
|
+
# Print stack trace for errors
|
|
123
179
|
if output_type == OutputType.ERROR:
|
|
124
|
-
|
|
125
|
-
PrettyOutput.print(f"Error trace: {traceback.format_exc()}", OutputType.INFO)
|
|
180
|
+
console.print_exception()
|
|
126
181
|
|
|
127
182
|
@staticmethod
|
|
128
183
|
def section(title: str, output_type: OutputType = OutputType.INFO):
|
|
129
|
-
"""Print
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
print(
|
|
184
|
+
"""Print section title in a panel"""
|
|
185
|
+
panel = Panel(
|
|
186
|
+
Text(title, style=output_type.value, justify="center"),
|
|
187
|
+
border_style=output_type.value
|
|
188
|
+
)
|
|
189
|
+
console.print()
|
|
190
|
+
console.print(panel)
|
|
191
|
+
console.print()
|
|
135
192
|
|
|
136
193
|
@staticmethod
|
|
137
194
|
def print_stream(text: str):
|
|
138
|
-
"""Print stream output
|
|
139
|
-
|
|
140
|
-
sys.stdout.write(f"{color}{text}{ColoramaStyle.RESET_ALL}")
|
|
141
|
-
sys.stdout.flush()
|
|
195
|
+
"""Print stream output without line break"""
|
|
196
|
+
console.print(text, style="system", end="")
|
|
142
197
|
|
|
143
198
|
@staticmethod
|
|
144
199
|
def print_stream_end():
|
|
145
|
-
"""
|
|
146
|
-
|
|
147
|
-
sys.stdout.flush()
|
|
200
|
+
"""End stream output with line break"""
|
|
201
|
+
console.print()
|
|
148
202
|
|
|
149
203
|
def get_single_line_input(tip: str) -> str:
|
|
150
204
|
"""Get single line input, support direction key, history function, etc."""
|
|
@@ -154,14 +208,87 @@ def get_single_line_input(tip: str) -> str:
|
|
|
154
208
|
})
|
|
155
209
|
return session.prompt(f"{tip}", style=style)
|
|
156
210
|
|
|
211
|
+
def make_choice_input(tip: str, choices: list) -> str:
|
|
212
|
+
"""Get choice input, support direction key, history function, etc."""
|
|
213
|
+
session = PromptSession(history=None)
|
|
214
|
+
style = PromptStyle.from_dict({
|
|
215
|
+
'prompt': 'ansicyan',
|
|
216
|
+
})
|
|
217
|
+
return session.prompt(f"{tip}", style=style)
|
|
218
|
+
|
|
219
|
+
class FileCompleter(Completer):
|
|
220
|
+
"""Custom completer for file paths with fuzzy matching."""
|
|
221
|
+
def __init__(self):
|
|
222
|
+
self.path_completer = PathCompleter()
|
|
223
|
+
|
|
224
|
+
def get_completions(self, document: Document, complete_event):
|
|
225
|
+
text = document.text_before_cursor
|
|
226
|
+
cursor_pos = document.cursor_position
|
|
227
|
+
|
|
228
|
+
# Find all @ positions in text
|
|
229
|
+
at_positions = [i for i, char in enumerate(text) if char == '@']
|
|
230
|
+
|
|
231
|
+
if not at_positions:
|
|
232
|
+
return
|
|
233
|
+
|
|
234
|
+
# Get the last @ position
|
|
235
|
+
current_at_pos = at_positions[-1]
|
|
236
|
+
|
|
237
|
+
# If cursor is not after the last @, don't complete
|
|
238
|
+
if cursor_pos <= current_at_pos:
|
|
239
|
+
return
|
|
240
|
+
|
|
241
|
+
# Check if there's a space after @
|
|
242
|
+
text_after_at = text[current_at_pos + 1:cursor_pos]
|
|
243
|
+
if ' ' in text_after_at:
|
|
244
|
+
return
|
|
245
|
+
|
|
246
|
+
# Get the text after the current @
|
|
247
|
+
file_path = text_after_at.strip()
|
|
248
|
+
|
|
249
|
+
# Get all possible files from current directory
|
|
250
|
+
all_files = []
|
|
251
|
+
for root, _, files in os.walk('.'):
|
|
252
|
+
for f in files:
|
|
253
|
+
path = os.path.join(root, f)
|
|
254
|
+
# Remove ./ from the beginning
|
|
255
|
+
path = path[2:] if path.startswith('./') else path
|
|
256
|
+
all_files.append(path)
|
|
257
|
+
|
|
258
|
+
# If no input after @, show all files
|
|
259
|
+
# Otherwise use fuzzy matching
|
|
260
|
+
if not file_path:
|
|
261
|
+
scored_files = [(path, 100) for path in all_files]
|
|
262
|
+
else:
|
|
263
|
+
scored_files = [
|
|
264
|
+
(path, fuzz.ratio(file_path.lower(), path.lower()))
|
|
265
|
+
for path in all_files
|
|
266
|
+
]
|
|
267
|
+
scored_files.sort(key=lambda x: x[1], reverse=True)
|
|
268
|
+
|
|
269
|
+
# Return completions for files
|
|
270
|
+
for path, score in scored_files:
|
|
271
|
+
if not file_path or score > 30: # Show all if no input, otherwise filter by score
|
|
272
|
+
completion = Completion(
|
|
273
|
+
text=path,
|
|
274
|
+
start_position=-len(file_path),
|
|
275
|
+
display=f"{path}" if not file_path else f"{path} ({score}%)",
|
|
276
|
+
display_meta="File"
|
|
277
|
+
)
|
|
278
|
+
yield completion
|
|
279
|
+
|
|
157
280
|
def get_multiline_input(tip: str) -> str:
|
|
158
|
-
"""Get multi-line input, support direction key, history function,
|
|
159
|
-
print(f"{Fore.GREEN}{tip}{ColoramaStyle.RESET_ALL}")
|
|
281
|
+
"""Get multi-line input, support direction key, history function, and file completion.
|
|
160
282
|
|
|
161
|
-
|
|
162
|
-
|
|
283
|
+
Args:
|
|
284
|
+
tip: The prompt tip to display
|
|
285
|
+
|
|
286
|
+
Returns:
|
|
287
|
+
str: The entered text
|
|
288
|
+
"""
|
|
289
|
+
print(f"{Fore.GREEN}{tip}{ColoramaStyle.RESET_ALL}")
|
|
163
290
|
|
|
164
|
-
#
|
|
291
|
+
# Define prompt style
|
|
165
292
|
style = PromptStyle.from_dict({
|
|
166
293
|
'prompt': 'ansicyan',
|
|
167
294
|
})
|
|
@@ -169,28 +296,34 @@ def get_multiline_input(tip: str) -> str:
|
|
|
169
296
|
lines = []
|
|
170
297
|
try:
|
|
171
298
|
while True:
|
|
172
|
-
#
|
|
299
|
+
# Set prompt
|
|
173
300
|
prompt = FormattedText([
|
|
174
301
|
('class:prompt', '... ' if lines else '>>> ')
|
|
175
302
|
])
|
|
176
303
|
|
|
177
|
-
#
|
|
304
|
+
# Create new session with new completer for each line
|
|
305
|
+
session = PromptSession(
|
|
306
|
+
history=None, # Use default history
|
|
307
|
+
completer=FileCompleter() # New completer instance for each line
|
|
308
|
+
)
|
|
309
|
+
|
|
310
|
+
# Get input with completion support
|
|
178
311
|
line = session.prompt(
|
|
179
312
|
prompt,
|
|
180
313
|
style=style,
|
|
181
314
|
).strip()
|
|
182
315
|
|
|
183
|
-
#
|
|
316
|
+
# Handle empty line
|
|
184
317
|
if not line:
|
|
185
|
-
if not lines: #
|
|
318
|
+
if not lines: # First line is empty
|
|
186
319
|
return ""
|
|
187
|
-
break #
|
|
320
|
+
break # End multi-line input
|
|
188
321
|
|
|
189
322
|
lines.append(line)
|
|
190
323
|
|
|
191
324
|
except KeyboardInterrupt:
|
|
192
|
-
PrettyOutput.print("
|
|
193
|
-
return "
|
|
325
|
+
PrettyOutput.print("Input cancelled", OutputType.INFO)
|
|
326
|
+
return ""
|
|
194
327
|
|
|
195
328
|
return "\n".join(lines)
|
|
196
329
|
|
|
@@ -244,6 +377,13 @@ def find_git_root(dir="."):
|
|
|
244
377
|
os.chdir(curr_dir)
|
|
245
378
|
return ret
|
|
246
379
|
|
|
380
|
+
def has_uncommitted_changes():
|
|
381
|
+
# Check working directory changes
|
|
382
|
+
working_changes = os.popen("git diff --exit-code").read().strip() != ""
|
|
383
|
+
# Check staged changes
|
|
384
|
+
staged_changes = os.popen("git diff --cached --exit-code").read().strip() != ""
|
|
385
|
+
return working_changes or staged_changes
|
|
386
|
+
|
|
247
387
|
def load_embedding_model():
|
|
248
388
|
model_name = "BAAI/bge-m3"
|
|
249
389
|
cache_dir = os.path.expanduser("~/.cache/huggingface/hub")
|
|
@@ -257,13 +397,11 @@ def load_embedding_model():
|
|
|
257
397
|
local_files_only=True
|
|
258
398
|
)
|
|
259
399
|
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
400
|
# Load model
|
|
263
401
|
embedding_model = SentenceTransformer(
|
|
264
402
|
model_name,
|
|
265
403
|
cache_folder=cache_dir,
|
|
266
|
-
local_files_only=
|
|
404
|
+
local_files_only=False
|
|
267
405
|
)
|
|
268
406
|
|
|
269
407
|
return embedding_model
|
|
@@ -288,18 +426,16 @@ def load_rerank_model():
|
|
|
288
426
|
local_files_only=True
|
|
289
427
|
)
|
|
290
428
|
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
429
|
# Load model and tokenizer
|
|
294
430
|
tokenizer = AutoTokenizer.from_pretrained(
|
|
295
431
|
model_name,
|
|
296
432
|
cache_dir=cache_dir,
|
|
297
|
-
local_files_only=
|
|
433
|
+
local_files_only=False
|
|
298
434
|
)
|
|
299
435
|
model = AutoModelForSequenceClassification.from_pretrained(
|
|
300
436
|
model_name,
|
|
301
437
|
cache_dir=cache_dir,
|
|
302
|
-
local_files_only=
|
|
438
|
+
local_files_only=False
|
|
303
439
|
)
|
|
304
440
|
|
|
305
441
|
# Use GPU if available
|
|
@@ -339,6 +475,10 @@ def get_file_md5(filepath: str)->str:
|
|
|
339
475
|
return hashlib.md5(open(filepath, "rb").read(100*1024*1024)).hexdigest()
|
|
340
476
|
|
|
341
477
|
|
|
478
|
+
def dont_use_local_model():
|
|
479
|
+
return os.getenv('JARVIS_DONT_USE_LOCAL_MODEL', 'false') == 'true'
|
|
480
|
+
|
|
481
|
+
|
|
342
482
|
def _create_methodology_embedding(embedding_model: Any, methodology_text: str) -> np.ndarray:
|
|
343
483
|
"""Create embedding vector for methodology text"""
|
|
344
484
|
try:
|
|
@@ -363,11 +503,20 @@ def load_methodology(user_input: str) -> str:
|
|
|
363
503
|
user_jarvis_methodology = os.path.expanduser("~/.jarvis/methodology")
|
|
364
504
|
if not os.path.exists(user_jarvis_methodology):
|
|
365
505
|
return ""
|
|
506
|
+
|
|
507
|
+
def make_methodology_prompt(data: Dict) -> str:
|
|
508
|
+
ret = """This is the standard methodology for handling previous problems, if the current task is similar, you can refer to it, if not,just ignore it:\n"""
|
|
509
|
+
for key, value in data.items():
|
|
510
|
+
ret += f"Problem: {key}\nMethodology: {value}\n"
|
|
511
|
+
return ret
|
|
366
512
|
|
|
367
513
|
try:
|
|
368
514
|
with open(user_jarvis_methodology, "r", encoding="utf-8") as f:
|
|
369
515
|
data = yaml.safe_load(f)
|
|
370
516
|
|
|
517
|
+
if dont_use_local_model():
|
|
518
|
+
return make_methodology_prompt(data)
|
|
519
|
+
|
|
371
520
|
# Reset data structure
|
|
372
521
|
methodology_data = []
|
|
373
522
|
vectors = []
|
|
@@ -382,7 +531,6 @@ def load_methodology(user_input: str) -> str:
|
|
|
382
531
|
|
|
383
532
|
# Create embedding vector for each methodology
|
|
384
533
|
for i, (key, value) in enumerate(data.items()):
|
|
385
|
-
PrettyOutput.print(f"Vectorizing methodology: {key} ...", OutputType.INFO)
|
|
386
534
|
methodology_text = f"{key}\n{value}"
|
|
387
535
|
embedding = _create_methodology_embedding(embedding_model, methodology_text)
|
|
388
536
|
vectors.append(embedding)
|
|
@@ -398,32 +546,59 @@ def load_methodology(user_input: str) -> str:
|
|
|
398
546
|
methodology_index = faiss.IndexIDMap(hnsw_index)
|
|
399
547
|
methodology_index.add_with_ids(vectors_array, np.array(ids)) # type: ignore
|
|
400
548
|
query_embedding = _create_methodology_embedding(embedding_model, user_input)
|
|
401
|
-
k = min(
|
|
549
|
+
k = min(3, len(methodology_data))
|
|
402
550
|
PrettyOutput.print(f"Retrieving methodology...", OutputType.INFO)
|
|
403
551
|
distances, indices = methodology_index.search(
|
|
404
552
|
query_embedding.reshape(1, -1), k
|
|
405
553
|
) # type: ignore
|
|
406
554
|
|
|
407
555
|
relevant_methodologies = {}
|
|
556
|
+
output_lines = []
|
|
408
557
|
for dist, idx in zip(distances[0], indices[0]):
|
|
409
558
|
if idx >= 0:
|
|
410
559
|
similarity = 1.0 / (1.0 + float(dist))
|
|
411
560
|
methodology = methodology_data[idx]
|
|
412
|
-
|
|
413
|
-
f"Methodology '{methodology['key']}' similarity: {similarity:.3f}"
|
|
414
|
-
OutputType.INFO
|
|
561
|
+
output_lines.append(
|
|
562
|
+
f"Methodology '{methodology['key']}' similarity: {similarity:.3f}"
|
|
415
563
|
)
|
|
416
564
|
if similarity >= 0.5:
|
|
417
565
|
relevant_methodologies[methodology["key"]] = methodology["value"]
|
|
566
|
+
|
|
567
|
+
if output_lines:
|
|
568
|
+
PrettyOutput.print("\n".join(output_lines), OutputType.INFO)
|
|
418
569
|
|
|
419
570
|
if relevant_methodologies:
|
|
420
|
-
return
|
|
421
|
-
|
|
422
|
-
"""
|
|
423
|
-
return ""
|
|
571
|
+
return make_methodology_prompt(relevant_methodologies)
|
|
572
|
+
return make_methodology_prompt(data)
|
|
424
573
|
|
|
425
574
|
except Exception as e:
|
|
426
575
|
PrettyOutput.print(f"Error loading methodology: {str(e)}", OutputType.ERROR)
|
|
427
576
|
import traceback
|
|
428
577
|
PrettyOutput.print(f"Error trace: {traceback.format_exc()}", OutputType.INFO)
|
|
429
|
-
return ""
|
|
578
|
+
return ""
|
|
579
|
+
|
|
580
|
+
def is_auto_complete() -> bool:
|
|
581
|
+
return os.getenv('JARVIS_AUTO_COMPLETE', 'false') == 'true'
|
|
582
|
+
|
|
583
|
+
def is_disable_codebase() -> bool:
|
|
584
|
+
return os.getenv('JARVIS_DISABLE_CODEBASE', 'false') == 'true'
|
|
585
|
+
|
|
586
|
+
def user_confirm(tip: str, default: bool = True) -> bool:
|
|
587
|
+
"""Prompt the user for confirmation.
|
|
588
|
+
|
|
589
|
+
Args:
|
|
590
|
+
tip: The message to show to the user
|
|
591
|
+
default: The default response if user hits enter
|
|
592
|
+
|
|
593
|
+
Returns:
|
|
594
|
+
bool: True if user confirmed, False otherwise
|
|
595
|
+
"""
|
|
596
|
+
suffix = "[Y/n]" if default else "[y/N]"
|
|
597
|
+
ret = get_single_line_input(f"{tip} {suffix}: ")
|
|
598
|
+
return default if ret == "" else ret.lower() == "y"
|
|
599
|
+
|
|
600
|
+
def get_file_line_count(filename: str) -> int:
|
|
601
|
+
try:
|
|
602
|
+
return len(open(filename, "r", encoding="utf-8").readlines())
|
|
603
|
+
except Exception as e:
|
|
604
|
+
return 0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: jarvis-ai-assistant
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.103
|
|
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
|
|
@@ -45,7 +45,7 @@ Requires-Dist: colorama>=0.4.6
|
|
|
45
45
|
Requires-Dist: prompt_toolkit>=3.0.0
|
|
46
46
|
Requires-Dist: openai>=1.20.0
|
|
47
47
|
Requires-Dist: playwright>=1.41.1
|
|
48
|
-
Requires-Dist: numpy>=1.
|
|
48
|
+
Requires-Dist: numpy>=1.17.4
|
|
49
49
|
Requires-Dist: faiss-cpu>=1.8.0
|
|
50
50
|
Requires-Dist: sentence-transformers>=2.2.2
|
|
51
51
|
Requires-Dist: bs4>=0.0.1
|
|
@@ -55,6 +55,10 @@ Requires-Dist: tiktoken>=0.3.0
|
|
|
55
55
|
Requires-Dist: tqdm>=4.65.0
|
|
56
56
|
Requires-Dist: docx>=0.2.4
|
|
57
57
|
Requires-Dist: yaspin>=2.5.0
|
|
58
|
+
Requires-Dist: rich>=13.3.1
|
|
59
|
+
Requires-Dist: pygments>=2.15.0
|
|
60
|
+
Requires-Dist: fuzzywuzzy>=0.18.0
|
|
61
|
+
Requires-Dist: python-Levenshtein>=0.26.1
|
|
58
62
|
Provides-Extra: dev
|
|
59
63
|
Requires-Dist: pytest; extra == "dev"
|
|
60
64
|
Requires-Dist: black; extra == "dev"
|
|
@@ -157,13 +161,13 @@ jarvis
|
|
|
157
161
|
### Codebase Search
|
|
158
162
|
```bash
|
|
159
163
|
# Generate codebase index
|
|
160
|
-
jarvis-codebase
|
|
164
|
+
jarvis-codebase generate
|
|
161
165
|
|
|
162
166
|
# Search similar code
|
|
163
|
-
jarvis-codebase
|
|
167
|
+
jarvis-codebase search "your search query"
|
|
164
168
|
|
|
165
169
|
# Ask questions about codebase
|
|
166
|
-
jarvis-codebase
|
|
170
|
+
jarvis-codebase ask "your question"
|
|
167
171
|
```
|
|
168
172
|
|
|
169
173
|
### Document Analysis (RAG)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
jarvis/__init__.py,sha256=A2vW7Ac_EmnSRhUOBJFq0qUWC2iJ1qwVxHAT5sJhxnk,51
|
|
2
|
+
jarvis/agent.py,sha256=6r5_pv3sumUrUCd2ntWVGg7yp1KTA3JCzz2IKH582k0,20010
|
|
3
|
+
jarvis/utils.py,sha256=FiWpRM0RjSJyDRimhvU2xa5SIUI70rxWq4ItSeMOCfw,20715
|
|
4
|
+
jarvis/jarvis_code_agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
+
jarvis/jarvis_code_agent/code_agent.py,sha256=8dIiFPZiWOEyIBDWUrqAdtn9g7eFrvvcCGPx5S56Ngc,6757
|
|
6
|
+
jarvis/jarvis_code_agent/file_select.py,sha256=59s_w1E0ihY1RxBZ1kyXNyQVTHjmjO8L9mg2FtjrsyQ,8192
|
|
7
|
+
jarvis/jarvis_code_agent/patch.py,sha256=du06gKWwmKcDPEtZmQJCOZbotNMKVtS-bz-8MYT78b0,4044
|
|
8
|
+
jarvis/jarvis_code_agent/relevant_files.py,sha256=8rL-hfdelJhWSt6MJKaxmQmFXf-WY-O8L18Ntw9dpnE,2686
|
|
9
|
+
jarvis/jarvis_codebase/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
+
jarvis/jarvis_codebase/main.py,sha256=Q_kVOjtL_AgSVkVUUYBNNKqA386GVxpnx0FXj1omUOc,36739
|
|
11
|
+
jarvis/jarvis_platform/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
|
+
jarvis/jarvis_platform/main.py,sha256=waLMHQmdecph_mZuPXWjpkmqibJFYHnCHroL9gL0nh0,4959
|
|
13
|
+
jarvis/jarvis_rag/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
|
+
jarvis/jarvis_rag/main.py,sha256=4St9VkaqK9zOq7AgurLB02nEj1_SvZAiFWhS3i_FcBY,33167
|
|
15
|
+
jarvis/jarvis_smart_shell/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
|
+
jarvis/jarvis_smart_shell/main.py,sha256=yWsD9Td81sr8I1pkimlDxucDPaLWb95NuCo4LCGnT7M,3947
|
|
17
|
+
jarvis/models/__init__.py,sha256=mrOt67nselz_H1gX9wdAO4y2DY5WPXzABqJbr5Des8k,63
|
|
18
|
+
jarvis/models/ai8.py,sha256=QwpcdvOAixFC4BOI2AsWC9290WqcrLj6lQOiT0A3Id4,11994
|
|
19
|
+
jarvis/models/base.py,sha256=nQ-rsJL1Z-gMev3TPoY7tYdwxhCJY8LG6_gtJ-maiW0,2181
|
|
20
|
+
jarvis/models/kimi.py,sha256=2x60DVjX0ph2fJjKj_NICeb0q4qVBihuc_laCpH94eo,15759
|
|
21
|
+
jarvis/models/ollama.py,sha256=WiUYkstaqFjiawXfuJs2GQUa3l3Y2ZWqhnKDBcF7rUQ,5672
|
|
22
|
+
jarvis/models/openai.py,sha256=SAbVIvFO4q6bRl8zlDaH5bKbrP0T_zd1WzlbkPCvkwg,4121
|
|
23
|
+
jarvis/models/oyi.py,sha256=nNBe-A0cOZ6vuGrnrUjeuC3N3oYRQeFazTUpFrAmx2w,15080
|
|
24
|
+
jarvis/models/registry.py,sha256=nDYyGzT2uGSxbEbqp1JhuXa7bXeiMaX4hPAFAg74eyA,8683
|
|
25
|
+
jarvis/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
26
|
+
jarvis/tools/ask_codebase.py,sha256=cYMQd2Ba0Ka_Kpt9dAJrbcPhaXvfY_-A8S6i0UxtY3w,2975
|
|
27
|
+
jarvis/tools/ask_user.py,sha256=k0PcMqvCkf_W9kMWnFsgcFefVf1A5DhpM6WVXFMdhdQ,1823
|
|
28
|
+
jarvis/tools/base.py,sha256=c0DMoDDPxmsqUYJR989zgUs7nIYRY6GWBrAdusIZKjc,656
|
|
29
|
+
jarvis/tools/chdir.py,sha256=3aGvpvWO6Fj9RdjWXanjeNBDZ7kz3TO8_Zo8DurENDk,2934
|
|
30
|
+
jarvis/tools/code_review.py,sha256=Reck765EIfhx8mteaJPw9IRnBkEzGS8INcQ0vVoKUw8,4939
|
|
31
|
+
jarvis/tools/create_code_sub_agent.py,sha256=_G2HUWyik5FFCV1JU8JqF_mutcW6n6WWCvkhb5LGrL0,765
|
|
32
|
+
jarvis/tools/create_code_test_agent.py,sha256=SqdIpymoDUX7L6hh5vqnZLyeVwW-QmLfytU-xkG7Gag,3462
|
|
33
|
+
jarvis/tools/create_ctags_agent.py,sha256=P-vqqUxh33R6kuMy8b5s3bANh1cVmkHpvz0vV5DNbXE,5184
|
|
34
|
+
jarvis/tools/create_sub_agent.py,sha256=0lZDtYRFjr9C9xtBKV-sxWfhK0TX-cxAHj3Zez76A4s,2853
|
|
35
|
+
jarvis/tools/execute_shell.py,sha256=bawfof8bUg3f9bjyCSifLa9bU-hkNoNOuos22uZffdg,2564
|
|
36
|
+
jarvis/tools/file_operation.py,sha256=-1U_J5SEuBjRylzEl7wvCfjspNv6aA49UvFHLNQ3bJU,4098
|
|
37
|
+
jarvis/tools/find_in_codebase.py,sha256=u-T6mEWv6JyE74fYZBjVlxXsqUnkf0BtgwVUy-SX4XI,3321
|
|
38
|
+
jarvis/tools/git_commiter.py,sha256=BcapUhKymAV5Ofi-Cjg4nvYiAj4u5yBaOfsIr0iEp0c,2536
|
|
39
|
+
jarvis/tools/methodology.py,sha256=yZldtjPZpNq8eGJ6IbhwHB0v3cFUtfPd14r7LDCo5IU,5622
|
|
40
|
+
jarvis/tools/rag.py,sha256=m8s-7dCPFhUrdTHvKj3HulNSsoOssBN7kqqn9n1l3Zw,4943
|
|
41
|
+
jarvis/tools/read_code.py,sha256=_ObjMWirIYOdZi-D9KSRTd_4tg-5WwKLOn5ilrTF77I,4834
|
|
42
|
+
jarvis/tools/read_webpage.py,sha256=JCReSXhkDHDkQ606sZYIKG1Itlprjpmu1sSbF-Ed-jI,2478
|
|
43
|
+
jarvis/tools/registry.py,sha256=81Q_x9BJV6SIfPWURq4uzXxP2JCiFeaGbGM1IO5FSy4,11658
|
|
44
|
+
jarvis/tools/search.py,sha256=IciWpdKoa03Kl5J1SdblI2VhkUBoIRuLHHM2X4KlMWE,9209
|
|
45
|
+
jarvis/tools/select_code_files.py,sha256=bjJGwCNw0Ue_8jW60K1gcy1rUgKqoHihicu5SS58WNk,1890
|
|
46
|
+
jarvis_ai_assistant-0.1.103.dist-info/LICENSE,sha256=AGgVgQmTqFvaztRtCAXsAMryUymB18gZif7_l2e1XOg,1063
|
|
47
|
+
jarvis_ai_assistant-0.1.103.dist-info/METADATA,sha256=Tr5iXpTFgFd9Z-iSNzIi1B0nB4HA6NfY2l5k4QRKgs8,12913
|
|
48
|
+
jarvis_ai_assistant-0.1.103.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
49
|
+
jarvis_ai_assistant-0.1.103.dist-info/entry_points.txt,sha256=jHc8XiYoVNlzKcvV5mA-uYvlDRUTO_74_glpb5vvvUg,494
|
|
50
|
+
jarvis_ai_assistant-0.1.103.dist-info/top_level.txt,sha256=1BOxyWfzOP_ZXj8rVTDnNCJ92bBGB0rwq8N1PCpoMIs,7
|
|
51
|
+
jarvis_ai_assistant-0.1.103.dist-info/RECORD,,
|
{jarvis_ai_assistant-0.1.101.dist-info → jarvis_ai_assistant-0.1.103.dist-info}/entry_points.txt
RENAMED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
[console_scripts]
|
|
2
2
|
jarvis = jarvis.agent:main
|
|
3
|
-
jarvis-code-agent = jarvis.jarvis_code_agent.
|
|
3
|
+
jarvis-code-agent = jarvis.jarvis_code_agent.code_agent:main
|
|
4
4
|
jarvis-codebase = jarvis.jarvis_codebase.main:main
|
|
5
|
-
jarvis-
|
|
5
|
+
jarvis-ctags = jarvis.tools.create_ctags_agent:main
|
|
6
|
+
jarvis-gh = jarvis.jarvis_github.main:main
|
|
7
|
+
jarvis-git-commit = jarvis.tools.git_commiter:main
|
|
6
8
|
jarvis-platform = jarvis.jarvis_platform.main:main
|
|
7
9
|
jarvis-rag = jarvis.jarvis_rag.main:main
|
|
8
10
|
jarvis-smart-shell = jarvis.jarvis_smart_shell.main:main
|