jarvis-ai-assistant 0.1.110__py3-none-any.whl → 0.1.111__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 +13 -7
- jarvis/jarvis_code_agent/code_agent.py +66 -48
- jarvis/jarvis_code_agent/file_select.py +4 -4
- jarvis/jarvis_code_agent/patch.py +3 -0
- jarvis/jarvis_code_agent/relevant_files.py +74 -15
- jarvis/jarvis_codebase/main.py +27 -42
- jarvis/jarvis_tools/ask_codebase.py +1 -1
- jarvis/jarvis_tools/git_commiter.py +0 -2
- jarvis/jarvis_tools/read_code.py +3 -2
- jarvis/utils/date_utils.py +19 -0
- jarvis/utils.py +15 -7
- {jarvis_ai_assistant-0.1.110.dist-info → jarvis_ai_assistant-0.1.111.dist-info}/METADATA +1 -2
- {jarvis_ai_assistant-0.1.110.dist-info → jarvis_ai_assistant-0.1.111.dist-info}/RECORD +18 -17
- {jarvis_ai_assistant-0.1.110.dist-info → jarvis_ai_assistant-0.1.111.dist-info}/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.110.dist-info → jarvis_ai_assistant-0.1.111.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.110.dist-info → jarvis_ai_assistant-0.1.111.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.1.110.dist-info → jarvis_ai_assistant-0.1.111.dist-info}/top_level.txt +0 -0
jarvis/__init__.py
CHANGED
jarvis/agent.py
CHANGED
|
@@ -8,7 +8,7 @@ import yaml
|
|
|
8
8
|
from jarvis.jarvis_platform.base import BasePlatform
|
|
9
9
|
from jarvis.jarvis_platform.registry import PlatformRegistry
|
|
10
10
|
from jarvis.jarvis_tools.registry import ToolRegistry, tool_call_help
|
|
11
|
-
from jarvis.utils import PrettyOutput, OutputType, get_context_token_count, is_auto_complete, is_need_summary, is_record_methodology, load_methodology, add_agent, delete_current_agent, get_max_token_count, get_multiline_input, init_env, is_use_methodology
|
|
11
|
+
from jarvis.utils import PrettyOutput, OutputType, get_context_token_count, is_auto_complete, is_execute_tool_confirm, is_need_summary, is_record_methodology, load_methodology, add_agent, delete_current_agent, get_max_token_count, get_multiline_input, init_env, is_use_methodology, user_confirm
|
|
12
12
|
import os
|
|
13
13
|
|
|
14
14
|
class Agent:
|
|
@@ -42,7 +42,8 @@ class Agent:
|
|
|
42
42
|
use_methodology: Optional[bool] = None,
|
|
43
43
|
record_methodology: Optional[bool] = None,
|
|
44
44
|
need_summary: Optional[bool] = None,
|
|
45
|
-
max_context_length: Optional[int] = None
|
|
45
|
+
max_context_length: Optional[int] = None,
|
|
46
|
+
execute_tool_confirm: Optional[bool] = None):
|
|
46
47
|
"""Initialize an Agent instance.
|
|
47
48
|
|
|
48
49
|
Args:
|
|
@@ -78,6 +79,8 @@ class Agent:
|
|
|
78
79
|
self.output_handler_before_tool = output_handler_before_tool if output_handler_before_tool else []
|
|
79
80
|
self.output_handler_after_tool = output_handler_after_tool if output_handler_after_tool else []
|
|
80
81
|
|
|
82
|
+
self.execute_tool_confirm = execute_tool_confirm if execute_tool_confirm is not None else is_execute_tool_confirm()
|
|
83
|
+
|
|
81
84
|
self.summary_prompt = summary_prompt if summary_prompt else f"""Please generate a concise summary report of the task execution, including:
|
|
82
85
|
|
|
83
86
|
1. Task Objective: Task restatement
|
|
@@ -344,10 +347,11 @@ Please continue the task based on the above information.
|
|
|
344
347
|
continue
|
|
345
348
|
|
|
346
349
|
if len(result) > 0:
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
350
|
+
if not self.execute_tool_confirm or user_confirm(f"Execute tool call: {result[0]['name']}?"):
|
|
351
|
+
PrettyOutput.print("Executing tool call...", OutputType.PROGRESS)
|
|
352
|
+
tool_result = self.tool_registry.handle_tool_calls(result)
|
|
353
|
+
self.prompt += tool_result
|
|
354
|
+
|
|
351
355
|
for handler in self.output_handler_after_tool:
|
|
352
356
|
self.prompt += handler(current_response)
|
|
353
357
|
|
|
@@ -499,6 +503,8 @@ When users need to execute tasks, you will strictly follow these steps to handle
|
|
|
499
503
|
10. Auto check the task goal completion status: If the task goal is completed, use the task completion command to end the task
|
|
500
504
|
11. Task Completion: End the task using task completion command when finished
|
|
501
505
|
|
|
506
|
+
Tip: Chat in user's language
|
|
507
|
+
|
|
502
508
|
Methodology Template:
|
|
503
509
|
1. Problem Restatement
|
|
504
510
|
2. Optimal Solution
|
|
@@ -516,7 +522,7 @@ def main():
|
|
|
516
522
|
|
|
517
523
|
try:
|
|
518
524
|
# 获取全局模型实例
|
|
519
|
-
agent = Agent(system_prompt=origin_agent_system_prompt
|
|
525
|
+
agent = Agent(system_prompt=origin_agent_system_prompt)
|
|
520
526
|
|
|
521
527
|
# 加载预定义任务
|
|
522
528
|
tasks = _load_tasks()
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import os
|
|
2
|
-
from typing import List
|
|
2
|
+
from typing import Dict, List
|
|
3
3
|
|
|
4
4
|
from jarvis.agent import Agent
|
|
5
5
|
from jarvis.jarvis_code_agent.patch import apply_patch
|
|
6
|
-
from jarvis.jarvis_code_agent.relevant_files import
|
|
6
|
+
from jarvis.jarvis_code_agent.relevant_files import find_relevant_information
|
|
7
7
|
from jarvis.jarvis_platform.registry import PlatformRegistry
|
|
8
8
|
from jarvis.jarvis_tools.git_commiter import GitCommitTool
|
|
9
9
|
from jarvis.jarvis_tools.registry import ToolRegistry
|
|
10
|
-
from jarvis.utils import OutputType, PrettyOutput,
|
|
10
|
+
from jarvis.utils import OutputType, PrettyOutput, get_multiline_input, has_uncommitted_changes, init_env, find_git_root
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
class CodeAgent:
|
|
@@ -26,7 +26,13 @@ class CodeAgent:
|
|
|
26
26
|
"lsp_find_definition",
|
|
27
27
|
"lsp_prepare_rename",
|
|
28
28
|
"lsp_validate_edit"])
|
|
29
|
-
code_system_prompt = """You are a code agent responsible for modifying code.
|
|
29
|
+
code_system_prompt = """You are a code agent responsible for modifying code. Your primary task is to understand existing code first and ensure compatibility with the current system.
|
|
30
|
+
|
|
31
|
+
# Critical First Steps
|
|
32
|
+
1. READ and UNDERSTAND existing code thoroughly
|
|
33
|
+
2. Identify current patterns and conventions
|
|
34
|
+
3. Map out affected components and their interactions
|
|
35
|
+
4. Plan changes that maintain system integrity
|
|
30
36
|
|
|
31
37
|
# Patch Format
|
|
32
38
|
<PATCH>
|
|
@@ -41,40 +47,43 @@ Key Rules:
|
|
|
41
47
|
• Same start/end number: insert before that line
|
|
42
48
|
• Start=0, end=0: create new file with content
|
|
43
49
|
|
|
44
|
-
# Code Compatibility
|
|
50
|
+
# Code Compatibility Requirements
|
|
45
51
|
1. System Integration
|
|
46
|
-
•
|
|
47
|
-
•
|
|
48
|
-
•
|
|
49
|
-
•
|
|
52
|
+
• MUST preserve existing API contracts
|
|
53
|
+
• MUST maintain current function signatures
|
|
54
|
+
• MUST keep data structure compatibility
|
|
55
|
+
• MUST follow error handling patterns
|
|
50
56
|
|
|
51
57
|
2. Style Consistency
|
|
52
|
-
• Match naming conventions
|
|
53
|
-
• Follow
|
|
54
|
-
• Use
|
|
55
|
-
•
|
|
58
|
+
• Match existing naming conventions exactly
|
|
59
|
+
• Follow established code organization
|
|
60
|
+
• Use current import style and order
|
|
61
|
+
• Maintain comment style and level of detail
|
|
56
62
|
|
|
57
63
|
3. Pattern Alignment
|
|
58
|
-
•
|
|
59
|
-
• Follow
|
|
60
|
-
•
|
|
61
|
-
• Keep configuration
|
|
64
|
+
• Reuse existing error handling approaches
|
|
65
|
+
• Follow established design patterns
|
|
66
|
+
• Use current logging conventions
|
|
67
|
+
• Keep configuration consistency
|
|
62
68
|
|
|
63
69
|
# Development Process
|
|
64
|
-
1. ANALYZE
|
|
65
|
-
•
|
|
66
|
-
•
|
|
67
|
-
•
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
•
|
|
72
|
-
•
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
•
|
|
70
|
+
1. ANALYZE (Current Code)
|
|
71
|
+
• Read and understand existing implementations
|
|
72
|
+
• Map out current code structure
|
|
73
|
+
• Identify established patterns
|
|
74
|
+
• Note key dependencies
|
|
75
|
+
|
|
76
|
+
2. ASSESS (Changes)
|
|
77
|
+
• Evaluate impact on existing code
|
|
78
|
+
• Check all dependencies
|
|
79
|
+
• Verify API compatibility
|
|
80
|
+
• Consider side effects
|
|
81
|
+
|
|
82
|
+
3. IMPLEMENT (Carefully)
|
|
83
|
+
• Make minimal necessary changes
|
|
84
|
+
• Follow existing patterns exactly
|
|
85
|
+
• Preserve all interfaces
|
|
86
|
+
• Maintain backward compatibility
|
|
78
87
|
|
|
79
88
|
# File Handling
|
|
80
89
|
Large Files (>200 lines):
|
|
@@ -84,18 +93,18 @@ Large Files (>200 lines):
|
|
|
84
93
|
|
|
85
94
|
# Available Tools
|
|
86
95
|
Primary:
|
|
96
|
+
• read_code - MUST use to understand existing code
|
|
87
97
|
• LSP tools for code analysis
|
|
88
|
-
• read_code with line ranges
|
|
89
98
|
• execute_shell for searches
|
|
90
|
-
• ask_user when
|
|
99
|
+
• ask_user when uncertain
|
|
91
100
|
|
|
92
101
|
# Quality Requirements
|
|
93
|
-
|
|
94
|
-
✓
|
|
95
|
-
✓
|
|
102
|
+
Every Change Must:
|
|
103
|
+
✓ Be based on thorough code reading
|
|
104
|
+
✓ Preserve all interfaces
|
|
105
|
+
✓ Match existing style exactly
|
|
96
106
|
✓ Handle errors consistently
|
|
97
107
|
✓ Maintain documentation
|
|
98
|
-
✓ Keep test coverage
|
|
99
108
|
✓ Follow project patterns"""
|
|
100
109
|
self.agent = Agent(system_prompt=code_system_prompt,
|
|
101
110
|
name="CodeAgent",
|
|
@@ -103,7 +112,7 @@ Code Changes Must:
|
|
|
103
112
|
is_sub_agent=False,
|
|
104
113
|
use_methodology=False,
|
|
105
114
|
tool_registry=tool_registry,
|
|
106
|
-
platform=PlatformRegistry().
|
|
115
|
+
platform=PlatformRegistry().get_codegen_platform(),
|
|
107
116
|
record_methodology=False,
|
|
108
117
|
output_handler_after_tool=[apply_patch],
|
|
109
118
|
need_summary=False)
|
|
@@ -119,17 +128,22 @@ Code Changes Must:
|
|
|
119
128
|
git_commiter.execute({})
|
|
120
129
|
|
|
121
130
|
|
|
122
|
-
def make_files_prompt(self, files: List[str]) -> str:
|
|
123
|
-
"""Make the files prompt.
|
|
131
|
+
def make_files_prompt(self, files: List[Dict[str, str]]) -> str:
|
|
132
|
+
"""Make the files prompt with content that fits within token limit.
|
|
124
133
|
|
|
125
134
|
Args:
|
|
126
135
|
files: The files to be modified
|
|
127
136
|
|
|
137
|
+
Returns:
|
|
138
|
+
str: A prompt containing file paths and contents within token limit
|
|
128
139
|
"""
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
140
|
+
prompt_parts = []
|
|
141
|
+
|
|
142
|
+
# Then try to add file contents
|
|
143
|
+
for file in files:
|
|
144
|
+
prompt_parts.append(f'''- {file['file']} ({file['reason']})''')
|
|
145
|
+
|
|
146
|
+
return "\n".join(prompt_parts)
|
|
133
147
|
|
|
134
148
|
def run(self, user_input: str) :
|
|
135
149
|
"""Run the code agent with the given user input.
|
|
@@ -142,15 +156,15 @@ Code Changes Must:
|
|
|
142
156
|
"""
|
|
143
157
|
try:
|
|
144
158
|
self._init_env()
|
|
145
|
-
files =
|
|
146
|
-
self.agent.run(self._build_first_edit_prompt(user_input, self.make_files_prompt(files)))
|
|
159
|
+
files, information = find_relevant_information(user_input, self.root_dir)
|
|
160
|
+
self.agent.run(self._build_first_edit_prompt(user_input, self.make_files_prompt(files), information))
|
|
147
161
|
|
|
148
162
|
except Exception as e:
|
|
149
163
|
return f"Error during execution: {str(e)}"
|
|
150
164
|
|
|
151
165
|
|
|
152
166
|
|
|
153
|
-
def _build_first_edit_prompt(self, user_input: str, files_prompt: str) -> str:
|
|
167
|
+
def _build_first_edit_prompt(self, user_input: str, files_prompt: str, information: str) -> str:
|
|
154
168
|
"""Build the initial prompt for the agent.
|
|
155
169
|
|
|
156
170
|
Args:
|
|
@@ -160,13 +174,17 @@ Code Changes Must:
|
|
|
160
174
|
Returns:
|
|
161
175
|
str: The formatted prompt
|
|
162
176
|
"""
|
|
177
|
+
|
|
163
178
|
return f"""# Code Modification Task
|
|
164
179
|
|
|
165
180
|
## User Requirement
|
|
166
181
|
{user_input}
|
|
167
182
|
|
|
168
|
-
##
|
|
183
|
+
## Maybe Relevant Files
|
|
169
184
|
{files_prompt}
|
|
185
|
+
|
|
186
|
+
## Some Information
|
|
187
|
+
{information}
|
|
170
188
|
"""
|
|
171
189
|
def main():
|
|
172
190
|
"""Jarvis main entry point"""
|
|
@@ -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
|
|
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
|
|
|
@@ -125,7 +125,7 @@ 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
130
|
PrettyOutput.section("Related files", OutputType.INFO)
|
|
131
131
|
|
|
@@ -133,7 +133,7 @@ def select_files(related_files: List[str], root_dir: str) -> List[str]:
|
|
|
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
|
|
|
@@ -199,7 +199,7 @@ def select_files(related_files: List[str], root_dir: str) -> List[str]:
|
|
|
199
199
|
continue
|
|
200
200
|
|
|
201
201
|
try:
|
|
202
|
-
selected_files.append(path)
|
|
202
|
+
selected_files.append({"file": path, "reason": "User Added"})
|
|
203
203
|
PrettyOutput.print(f"File added: {path}", OutputType.SUCCESS)
|
|
204
204
|
except Exception as e:
|
|
205
205
|
PrettyOutput.print(f"Failed to read file: {str(e)}", OutputType.ERROR)
|
|
@@ -115,11 +115,14 @@ def handle_commit_workflow()->bool:
|
|
|
115
115
|
Returns:
|
|
116
116
|
tuple[bool, str, str]: (continue_execution, commit_id, commit_message)
|
|
117
117
|
"""
|
|
118
|
+
os.system("git add .")
|
|
118
119
|
diff = os.popen("git diff HEAD").read()
|
|
120
|
+
os.system("git reset HEAD")
|
|
119
121
|
PrettyOutput.print(diff, OutputType.CODE, lang="diff")
|
|
120
122
|
if not user_confirm("Do you want to commit the code?", default=True):
|
|
121
123
|
os.system("git reset HEAD")
|
|
122
124
|
os.system("git checkout -- .")
|
|
125
|
+
os.system("git clean -fd")
|
|
123
126
|
return False
|
|
124
127
|
|
|
125
128
|
git_commiter = GitCommitTool()
|
|
@@ -1,27 +1,86 @@
|
|
|
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.
|
|
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
|
+
|
|
13
|
+
Args:
|
|
14
|
+
requirement: The user's requirement description
|
|
15
|
+
|
|
16
|
+
Returns:
|
|
17
|
+
str: A formatted string containing relevant questions
|
|
18
|
+
"""
|
|
19
|
+
prompt = f"""You are a helpful assistant that generates SPECIFIC questions in English for a code analysis team. The analysis team:
|
|
20
|
+
- Has access to the codebase but NO CONTEXT about the requirement
|
|
21
|
+
- Will search and analyze code based on your questions
|
|
22
|
+
- Needs complete context to understand what to look for
|
|
13
23
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
24
|
+
Key Instructions:
|
|
25
|
+
1. Write questions in clear, professional English
|
|
26
|
+
2. Include necessary CONTEXT in each question
|
|
27
|
+
3. Be SPECIFIC about what needs to be found/analyzed
|
|
28
|
+
4. Provide enough background for someone with no prior knowledge
|
|
29
|
+
|
|
30
|
+
For example:
|
|
31
|
+
BAD: "How is error handling implemented?"
|
|
32
|
+
GOOD: "Given that we need to add retry logic to the file upload feature, how does the current error handling work in upload_handler.py, specifically around network failures and timeout scenarios?"
|
|
33
|
+
|
|
34
|
+
Consider these aspects when forming questions:
|
|
35
|
+
|
|
36
|
+
1. Implementation Context:
|
|
37
|
+
- "What is the current implementation of [specific feature]?"
|
|
38
|
+
- "Which modules/classes handle [specific functionality]?"
|
|
39
|
+
- "What is the existing workflow for [specific operation]?"
|
|
40
|
+
|
|
41
|
+
2. Technical Investigation:
|
|
42
|
+
- "How does the system currently handle [specific scenario]?"
|
|
43
|
+
- "What patterns are used for [specific behavior]?"
|
|
44
|
+
- "Where are the configuration settings for [specific feature]?"
|
|
45
|
+
|
|
46
|
+
3. Integration Details:
|
|
47
|
+
- "Which components call or depend on [specific module]?"
|
|
48
|
+
- "What is the data flow between [component A] and [component B]?"
|
|
49
|
+
- "How are errors propagated from [specific component]?"
|
|
21
50
|
|
|
51
|
+
4. Requirements Context:
|
|
52
|
+
- "Given [specific requirement], what are the current limitations?"
|
|
53
|
+
- "For [specific change], what validation rules apply?"
|
|
54
|
+
- "In the context of [feature], what edge cases exist?"
|
|
55
|
+
|
|
56
|
+
User Requirement:
|
|
57
|
+
{requirement}
|
|
58
|
+
|
|
59
|
+
Output Format:
|
|
60
|
+
<QUESTION>
|
|
61
|
+
[Write 3-5 specific questions in English, ensuring each includes full context for someone with no prior knowledge of the requirement]
|
|
62
|
+
</QUESTION>
|
|
63
|
+
"""
|
|
64
|
+
model = PlatformRegistry().get_normal_platform()
|
|
65
|
+
response = model.chat_until_success(prompt)
|
|
66
|
+
response = re.search(r'<QUESTION>(.*?)</QUESTION>', response, re.DOTALL)
|
|
67
|
+
if response is None:
|
|
68
|
+
return None
|
|
69
|
+
return response.group(1)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def find_relevant_information(user_input: str, root_dir: str) -> Tuple[List[Dict[str, str]], str]:
|
|
73
|
+
try:
|
|
74
|
+
PrettyOutput.print("Find files from codebase...", OutputType.INFO)
|
|
75
|
+
codebase = CodeBase(root_dir)
|
|
76
|
+
question = make_question(user_input)
|
|
77
|
+
if question is None:
|
|
78
|
+
return [], ""
|
|
79
|
+
files_from_codebase, infomation = codebase.ask_codebase(question)
|
|
22
80
|
PrettyOutput.print("Find files by agent...", OutputType.INFO)
|
|
23
81
|
|
|
24
82
|
selected_files = select_files(files_from_codebase, os.getcwd())
|
|
25
|
-
return selected_files
|
|
26
|
-
except Exception
|
|
27
|
-
|
|
83
|
+
return selected_files, infomation
|
|
84
|
+
except Exception:
|
|
85
|
+
PrettyOutput.print("Failed to find relevant files", OutputType.ERROR)
|
|
86
|
+
return [], ""
|
jarvis/jarvis_codebase/main.py
CHANGED
|
@@ -524,7 +524,7 @@ Content: {content}
|
|
|
524
524
|
score = len(matched_keywords) / len(keywords)
|
|
525
525
|
return score
|
|
526
526
|
|
|
527
|
-
def pick_results(self, query: List[str], initial_results: List[str]) -> List[str]:
|
|
527
|
+
def pick_results(self, query: List[str], initial_results: List[str]) -> List[Dict[str,str]]:
|
|
528
528
|
"""Use a large model to pick the search results
|
|
529
529
|
|
|
530
530
|
Args:
|
|
@@ -538,14 +538,14 @@ Content: {content}
|
|
|
538
538
|
return []
|
|
539
539
|
|
|
540
540
|
try:
|
|
541
|
-
PrettyOutput.print(f"Picking results
|
|
541
|
+
PrettyOutput.print(f"Picking results ...", output_type=OutputType.INFO)
|
|
542
542
|
|
|
543
543
|
# Maximum content length per batch
|
|
544
544
|
max_batch_length = self.max_token_count - 1000 # Reserve space for prompt
|
|
545
545
|
max_file_length = max_batch_length // 3 # Limit individual file size
|
|
546
546
|
|
|
547
547
|
# Process files in batches
|
|
548
|
-
all_selected_files =
|
|
548
|
+
all_selected_files = []
|
|
549
549
|
current_batch = []
|
|
550
550
|
current_token_count = 0
|
|
551
551
|
|
|
@@ -565,7 +565,7 @@ Content: {content}
|
|
|
565
565
|
# Process current batch
|
|
566
566
|
if current_batch:
|
|
567
567
|
selected = self._process_batch('\n'.join(query), current_batch)
|
|
568
|
-
all_selected_files.
|
|
568
|
+
all_selected_files.extend(selected)
|
|
569
569
|
# Start new batch
|
|
570
570
|
current_batch = [file_info]
|
|
571
571
|
current_token_count = tokens_count
|
|
@@ -580,17 +580,16 @@ Content: {content}
|
|
|
580
580
|
# Process final batch
|
|
581
581
|
if current_batch:
|
|
582
582
|
selected = self._process_batch('\n'.join(query), current_batch)
|
|
583
|
-
all_selected_files.
|
|
583
|
+
all_selected_files.extend(selected)
|
|
584
584
|
|
|
585
585
|
# Convert set to list and maintain original order
|
|
586
|
-
|
|
587
|
-
return final_results
|
|
586
|
+
return all_selected_files
|
|
588
587
|
|
|
589
588
|
except Exception as e:
|
|
590
589
|
PrettyOutput.print(f"Failed to pick: {str(e)}", OutputType.ERROR)
|
|
591
|
-
return initial_results
|
|
590
|
+
return [{"file": f, "reason": "" } for f in initial_results]
|
|
592
591
|
|
|
593
|
-
def _process_batch(self, query: str, files_info: List[str]) -> List[str]:
|
|
592
|
+
def _process_batch(self, query: str, files_info: List[str]) -> List[Dict[str, str]]:
|
|
594
593
|
"""Process a batch of files"""
|
|
595
594
|
prompt = f"""As a code analysis expert, please help identify the most relevant files for the given query using chain-of-thought reasoning.
|
|
596
595
|
|
|
@@ -611,8 +610,10 @@ Think through this step by step:
|
|
|
611
610
|
|
|
612
611
|
Please output your selection in YAML format:
|
|
613
612
|
<FILES>
|
|
614
|
-
- path/to/most/relevant.py
|
|
613
|
+
- file: path/to/most/relevant.py
|
|
614
|
+
reason: xxxxxxxxxx
|
|
615
615
|
- path/to/next/relevant.py
|
|
616
|
+
reason: yyyyyyyyyy
|
|
616
617
|
</FILES>
|
|
617
618
|
|
|
618
619
|
Important:
|
|
@@ -724,7 +725,7 @@ Please provide 10 search-optimized expressions in the specified format.
|
|
|
724
725
|
return results
|
|
725
726
|
|
|
726
727
|
|
|
727
|
-
def search_similar(self, query: str, top_k: int = 30) -> List[str]:
|
|
728
|
+
def search_similar(self, query: str, top_k: int = 30) -> List[Dict[str, str]]:
|
|
728
729
|
"""Search related files with optimized retrieval"""
|
|
729
730
|
try:
|
|
730
731
|
self.generate_codebase()
|
|
@@ -764,13 +765,13 @@ Please provide 10 search-optimized expressions in the specified format.
|
|
|
764
765
|
all_results.sort(key=lambda x: x[1], reverse=True)
|
|
765
766
|
results = all_results[:top_k]
|
|
766
767
|
|
|
767
|
-
# Display results with scores
|
|
768
|
-
message = "Found related files:\n"
|
|
769
|
-
for path, score, _ in results:
|
|
770
|
-
message += f"File: {path} (Score: {score:.3f})\n"
|
|
771
|
-
PrettyOutput.print(message.rstrip(), output_type=OutputType.INFO, lang="markdown")
|
|
772
|
-
|
|
773
768
|
results = self.pick_results(query_variants, [path for path, _, _ in results])
|
|
769
|
+
|
|
770
|
+
output = "Found related files:\n"
|
|
771
|
+
for file in results:
|
|
772
|
+
output += f'''- {file['file']} ({file['reason']})\n'''
|
|
773
|
+
PrettyOutput.print(output, output_type=OutputType.INFO, lang="markdown")
|
|
774
|
+
|
|
774
775
|
|
|
775
776
|
return results
|
|
776
777
|
|
|
@@ -778,18 +779,13 @@ Please provide 10 search-optimized expressions in the specified format.
|
|
|
778
779
|
PrettyOutput.print(f"Failed to search: {str(e)}", output_type=OutputType.ERROR)
|
|
779
780
|
return []
|
|
780
781
|
|
|
781
|
-
def ask_codebase(self, query: str, top_k: int=20) -> str:
|
|
782
|
+
def ask_codebase(self, query: str, top_k: int=20) -> Tuple[List[Dict[str, str]], str]:
|
|
782
783
|
"""Query the codebase with enhanced context building"""
|
|
783
784
|
files_from_codebase = self.search_similar(query, top_k)
|
|
784
785
|
|
|
785
786
|
if not files_from_codebase:
|
|
786
787
|
PrettyOutput.print("No related files found", output_type=OutputType.WARNING)
|
|
787
|
-
return ""
|
|
788
|
-
|
|
789
|
-
output = "Found related files:\n"
|
|
790
|
-
for path in files_from_codebase:
|
|
791
|
-
output += f"- {path}\n"
|
|
792
|
-
PrettyOutput.print(output, output_type=OutputType.INFO, lang="markdown")
|
|
788
|
+
return [],""
|
|
793
789
|
|
|
794
790
|
# Build enhanced prompt
|
|
795
791
|
prompt = f"""Based on the following code files, please provide a comprehensive and accurate answer to the user's question.
|
|
@@ -799,6 +795,8 @@ Important guidelines:
|
|
|
799
795
|
2. Explain technical concepts clearly
|
|
800
796
|
3. Include relevant code snippets when helpful
|
|
801
797
|
4. If the code doesn't fully answer the question, indicate what's missing
|
|
798
|
+
5. Answer in user's language.
|
|
799
|
+
6. Answer with professional language.
|
|
802
800
|
|
|
803
801
|
Question: {query}
|
|
804
802
|
|
|
@@ -810,9 +808,9 @@ Relevant code files (ordered by relevance):
|
|
|
810
808
|
|
|
811
809
|
for path in files_from_codebase:
|
|
812
810
|
try:
|
|
813
|
-
content = open(path, "r", encoding="utf-8").read()
|
|
811
|
+
content = open(path["file"], "r", encoding="utf-8").read()
|
|
814
812
|
file_content = f"""
|
|
815
|
-
File: {path}
|
|
813
|
+
File: {path["file"]}
|
|
816
814
|
Content:
|
|
817
815
|
{content}
|
|
818
816
|
----------------------------------------
|
|
@@ -832,21 +830,8 @@ Content:
|
|
|
832
830
|
output_type=OutputType.ERROR)
|
|
833
831
|
continue
|
|
834
832
|
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
1. Direct answer to the question
|
|
838
|
-
2. Relevant code explanations
|
|
839
|
-
3. Implementation details
|
|
840
|
-
4. Any missing information or limitations
|
|
841
|
-
5. Add reference files and code snippets at the end of the answer.
|
|
842
|
-
|
|
843
|
-
Answer in Chinese using professional language.
|
|
844
|
-
"""
|
|
845
|
-
|
|
846
|
-
model = PlatformRegistry.get_global_platform_registry().get_normal_platform()
|
|
847
|
-
response = model.chat_until_success(prompt)
|
|
848
|
-
|
|
849
|
-
return response
|
|
833
|
+
model = PlatformRegistry.get_global_platform_registry().get_thinking_platform()
|
|
834
|
+
return files_from_codebase, model.chat_until_success(prompt)
|
|
850
835
|
|
|
851
836
|
def is_index_generated(self) -> bool:
|
|
852
837
|
"""Check if the index has been generated"""
|
|
@@ -948,7 +933,7 @@ def main():
|
|
|
948
933
|
|
|
949
934
|
elif args.command == 'ask':
|
|
950
935
|
response = codebase.ask_codebase(args.question, args.top_k)
|
|
951
|
-
output = f"""
|
|
936
|
+
output = f"""{response}"""
|
|
952
937
|
PrettyOutput.print(output, output_type=OutputType.INFO)
|
|
953
938
|
|
|
954
939
|
else:
|
|
@@ -3,9 +3,7 @@ import re
|
|
|
3
3
|
from typing import Dict, Any
|
|
4
4
|
|
|
5
5
|
import yaml
|
|
6
|
-
from jarvis.agent import Agent
|
|
7
6
|
from jarvis.jarvis_platform.registry import PlatformRegistry
|
|
8
|
-
from jarvis.jarvis_tools.registry import ToolRegistry
|
|
9
7
|
from jarvis.utils import OutputType, PrettyOutput, init_env
|
|
10
8
|
import sys
|
|
11
9
|
|
jarvis/jarvis_tools/read_code.py
CHANGED
|
@@ -100,11 +100,12 @@ class ReadCodeTool:
|
|
|
100
100
|
|
|
101
101
|
content = "".join(formatted_lines)
|
|
102
102
|
|
|
103
|
-
|
|
103
|
+
output = f"File: {filepath}\nLines: [{start_line}, {end_line})\n{content}";
|
|
104
|
+
PrettyOutput.print(output, OutputType.CODE)
|
|
104
105
|
|
|
105
106
|
return {
|
|
106
107
|
"success": True,
|
|
107
|
-
"stdout":
|
|
108
|
+
"stdout": output,
|
|
108
109
|
"stderr": ""
|
|
109
110
|
}
|
|
110
111
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
|
|
3
|
+
class DateValidator:
|
|
4
|
+
@staticmethod
|
|
5
|
+
def validate_iso_date(date_str: str) -> bool:
|
|
6
|
+
try:
|
|
7
|
+
datetime.fromisoformat(date_str)
|
|
8
|
+
return True
|
|
9
|
+
except ValueError:
|
|
10
|
+
return False
|
|
11
|
+
|
|
12
|
+
@staticmethod
|
|
13
|
+
def validate_date_range(start: str, end: str) -> bool:
|
|
14
|
+
try:
|
|
15
|
+
start_dt = datetime.fromisoformat(start)
|
|
16
|
+
end_dt = datetime.fromisoformat(end)
|
|
17
|
+
return start_dt <= end_dt
|
|
18
|
+
except ValueError:
|
|
19
|
+
return False
|
jarvis/utils.py
CHANGED
|
@@ -213,6 +213,8 @@ class FileCompleter(Completer):
|
|
|
213
213
|
"""Custom completer for file paths with fuzzy matching."""
|
|
214
214
|
def __init__(self):
|
|
215
215
|
self.path_completer = PathCompleter()
|
|
216
|
+
self.max_suggestions = 10 # 增加显示数量
|
|
217
|
+
self.min_score = 10 # 降低相似度阈值
|
|
216
218
|
|
|
217
219
|
def get_completions(self, document: Document, complete_event):
|
|
218
220
|
text = document.text_before_cursor
|
|
@@ -251,21 +253,26 @@ class FileCompleter(Completer):
|
|
|
251
253
|
# If no input after @, show all files
|
|
252
254
|
# Otherwise use fuzzy matching
|
|
253
255
|
if not file_path:
|
|
254
|
-
scored_files = [(path, 100) for path in all_files]
|
|
256
|
+
scored_files = [(path, 100) for path in all_files[:self.max_suggestions]]
|
|
255
257
|
else:
|
|
256
258
|
scored_files = [
|
|
257
259
|
(path, fuzz.ratio(file_path.lower(), path.lower()))
|
|
258
260
|
for path in all_files
|
|
259
261
|
]
|
|
262
|
+
# Sort by score and take top results
|
|
260
263
|
scored_files.sort(key=lambda x: x[1], reverse=True)
|
|
264
|
+
scored_files = scored_files[:self.max_suggestions]
|
|
261
265
|
|
|
262
266
|
# Return completions for files
|
|
263
267
|
for path, score in scored_files:
|
|
264
|
-
if not file_path or score >
|
|
268
|
+
if not file_path or score > self.min_score:
|
|
269
|
+
display_text = path
|
|
270
|
+
if file_path and score < 100:
|
|
271
|
+
display_text = f"{path} ({score}%)"
|
|
265
272
|
completion = Completion(
|
|
266
273
|
text=path,
|
|
267
274
|
start_position=-len(file_path),
|
|
268
|
-
display=
|
|
275
|
+
display=display_text,
|
|
269
276
|
display_meta="File"
|
|
270
277
|
)
|
|
271
278
|
yield completion
|
|
@@ -376,6 +383,7 @@ def has_uncommitted_changes():
|
|
|
376
383
|
working_changes = os.popen("git diff --exit-code").read().strip() != ""
|
|
377
384
|
# Check staged changes
|
|
378
385
|
staged_changes = os.popen("git diff --cached --exit-code").read().strip() != ""
|
|
386
|
+
os.system("git reset HEAD")
|
|
379
387
|
return working_changes or staged_changes
|
|
380
388
|
|
|
381
389
|
def load_embedding_model():
|
|
@@ -685,9 +693,6 @@ def dont_use_local_model():
|
|
|
685
693
|
|
|
686
694
|
def is_auto_complete() -> bool:
|
|
687
695
|
return os.getenv('JARVIS_AUTO_COMPLETE', 'false') == 'true'
|
|
688
|
-
|
|
689
|
-
def is_disable_codebase() -> bool:
|
|
690
|
-
return os.getenv('JARVIS_DISABLE_CODEBASE', 'false') == 'true'
|
|
691
696
|
|
|
692
697
|
def is_use_methodology() -> bool:
|
|
693
698
|
return os.getenv('JARVIS_USE_METHODOLOGY', 'true') == 'true'
|
|
@@ -731,6 +736,9 @@ def get_cheap_platform_name() -> str:
|
|
|
731
736
|
def get_cheap_model_name() -> str:
|
|
732
737
|
return os.getenv('JARVIS_CHEAP_MODEL', os.getenv('JARVIS_MODEL', 'kimi'))
|
|
733
738
|
|
|
739
|
+
def is_execute_tool_confirm() -> bool:
|
|
740
|
+
return os.getenv('JARVIS_EXECUTE_TOOL_CONFIRM', 'false') == 'true'
|
|
741
|
+
|
|
734
742
|
def split_text_into_chunks(text: str, max_length: int = 512) -> List[str]:
|
|
735
743
|
"""Split text into chunks with overlapping windows"""
|
|
736
744
|
chunks = []
|
|
@@ -774,7 +782,7 @@ def get_context_token_count(text: str) -> int:
|
|
|
774
782
|
try:
|
|
775
783
|
# Use a fast tokenizer that's good at general text
|
|
776
784
|
tokenizer = load_tokenizer()
|
|
777
|
-
chunks = split_text_into_chunks(text,
|
|
785
|
+
chunks = split_text_into_chunks(text, 1024)
|
|
778
786
|
return sum([len(tokenizer.encode(chunk)) for chunk in chunks])
|
|
779
787
|
|
|
780
788
|
except Exception as e:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: jarvis-ai-assistant
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.111
|
|
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
|
|
@@ -149,7 +149,6 @@ Jarvis supports configuration through environment variables that can be set in t
|
|
|
149
149
|
| JARVIS_MAX_PARAGRAPH_LENGTH | Maximum paragraph length | 1000 | No |
|
|
150
150
|
| JARVIS_CONTEXT_WINDOW | Context window size | 5 | No |
|
|
151
151
|
| JARVIS_AUTO_COMPLETE | Enable auto completion | false | No |
|
|
152
|
-
| JARVIS_DISABLE_CODEBASE | Disable codebase features | false | No |
|
|
153
152
|
| JARVIS_USE_METHODOLOGY | Enable methodology | true | No |
|
|
154
153
|
| JARVIS_RECORD_METHODOLOGY | Record methodology | true | No |
|
|
155
154
|
| JARVIS_NEED_SUMMARY | Generate summaries | true | No |
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
jarvis/__init__.py,sha256=
|
|
2
|
-
jarvis/agent.py,sha256=
|
|
3
|
-
jarvis/utils.py,sha256=
|
|
1
|
+
jarvis/__init__.py,sha256=EwzKMyQQYv9-9h1YUWEh1i7Ne5vKRvUB3mF27llLwo4,51
|
|
2
|
+
jarvis/agent.py,sha256=r-wTNio1BwbySStjJH2fF-yCVftDJzWtX9GJxMrkD3Y,23062
|
|
3
|
+
jarvis/utils.py,sha256=iwmiKVg5ATyKzOGzDaunZHl2ThosQRMyqjQzj1Hu6Wc,27289
|
|
4
4
|
jarvis/jarvis_code_agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
-
jarvis/jarvis_code_agent/code_agent.py,sha256=
|
|
6
|
-
jarvis/jarvis_code_agent/file_select.py,sha256=
|
|
7
|
-
jarvis/jarvis_code_agent/patch.py,sha256=
|
|
8
|
-
jarvis/jarvis_code_agent/relevant_files.py,sha256=
|
|
5
|
+
jarvis/jarvis_code_agent/code_agent.py,sha256=2EptFqsX7xgbTIrsr1lMxo7j6g1t0jrbuuS1J3QrrI0,6935
|
|
6
|
+
jarvis/jarvis_code_agent/file_select.py,sha256=w4s-aUqGRVC2zP45_QgMAlWuSq8ocnT1s1XRioejVNc,8222
|
|
7
|
+
jarvis/jarvis_code_agent/patch.py,sha256=0_T_P1NOGqYe91VaQ6oofNI1Q8XVcfxMH69aT-txd_c,4688
|
|
8
|
+
jarvis/jarvis_code_agent/relevant_files.py,sha256=BPc8HXIS86HdLS76j9seL9Sw78Eh3G_Oyj--lwdoZZY,3475
|
|
9
9
|
jarvis/jarvis_codebase/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
-
jarvis/jarvis_codebase/main.py,sha256=
|
|
10
|
+
jarvis/jarvis_codebase/main.py,sha256=Yjy9P9xh1s7GIDskpajPObgE8zDfwj9-oi8eipEwWbw,39186
|
|
11
11
|
jarvis/jarvis_lsp/base.py,sha256=_7pdbMKjdtYBW0DsRbjIodDHM3J7df-YgXHejN_WIrU,4490
|
|
12
12
|
jarvis/jarvis_lsp/cpp.py,sha256=F7Zo3BErkvtWS1_H9zQO83pX_FUmnijux-2SjhWzKCE,4985
|
|
13
13
|
jarvis/jarvis_lsp/go.py,sha256=p8LULiFdq4qjDYQzXFlzH0-FQZ3IyfiwN_sbO9i0L_A,5310
|
|
@@ -29,7 +29,7 @@ jarvis/jarvis_rag/main.py,sha256=Lr3b2eTB9TXZGZGdG4Sl9bdtE5NFRbv_bRysxeWNCEo,313
|
|
|
29
29
|
jarvis/jarvis_smart_shell/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
30
30
|
jarvis/jarvis_smart_shell/main.py,sha256=VdUR-x932OccEwU0pcQM_pb_I4yfrAutE3hfm6jf5es,3955
|
|
31
31
|
jarvis/jarvis_tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
32
|
-
jarvis/jarvis_tools/ask_codebase.py,sha256=
|
|
32
|
+
jarvis/jarvis_tools/ask_codebase.py,sha256=KLECEUGcAwXPAJF4sYV4CS2PYIc7RPBjHfUHZXCbMNQ,2994
|
|
33
33
|
jarvis/jarvis_tools/ask_user.py,sha256=9ZhIffoPGSfxJIwiIsL03V95yM8uYJsRg7j1C8ltNGc,1830
|
|
34
34
|
jarvis/jarvis_tools/base.py,sha256=c0DMoDDPxmsqUYJR989zgUs7nIYRY6GWBrAdusIZKjc,656
|
|
35
35
|
jarvis/jarvis_tools/chdir.py,sha256=A53BNXFB9tvwoV_cxW_LpF_DfxANgAEJ8rjikTaTa-I,1813
|
|
@@ -40,7 +40,7 @@ jarvis/jarvis_tools/deep_thinking.py,sha256=ltsMUfmE8XNyYTkgpWMD1Qow-6_x0dcD8WL7
|
|
|
40
40
|
jarvis/jarvis_tools/deep_thinking_agent.py,sha256=UBBWq8kp6SDEhwYXjO-tMMHP7Wblx5OA-gpQ8h_1tdk,4378
|
|
41
41
|
jarvis/jarvis_tools/execute_shell.py,sha256=bawfof8bUg3f9bjyCSifLa9bU-hkNoNOuos22uZffdg,2564
|
|
42
42
|
jarvis/jarvis_tools/file_operation.py,sha256=-1U_J5SEuBjRylzEl7wvCfjspNv6aA49UvFHLNQ3bJU,4098
|
|
43
|
-
jarvis/jarvis_tools/git_commiter.py,sha256=
|
|
43
|
+
jarvis/jarvis_tools/git_commiter.py,sha256=bGGqSHraR5E1YMrGDudKh6uZyMEhjlLiCYJUp9wvFhU,2480
|
|
44
44
|
jarvis/jarvis_tools/lsp_find_definition.py,sha256=xV8YeN1RJfwd2F3gE6OnDeTwl-AnCmrxueHocbXkQOc,4800
|
|
45
45
|
jarvis/jarvis_tools/lsp_find_references.py,sha256=FohlJeLfTxcMUASfbjOT93hQGtI2WeyTpMGwRwShW_I,4043
|
|
46
46
|
jarvis/jarvis_tools/lsp_get_diagnostics.py,sha256=bEvbDk8TnKg9TTFFxMrYOJm5TBDgz5gO04WJFQUwQQE,4490
|
|
@@ -49,14 +49,15 @@ jarvis/jarvis_tools/lsp_prepare_rename.py,sha256=RxUyIef4awtp-jgupcD1LcPlno9P3mO
|
|
|
49
49
|
jarvis/jarvis_tools/lsp_validate_edit.py,sha256=M0iglK2QbnIEFv0RYK6o2iAYnv259jB6EU7To-rc51E,5247
|
|
50
50
|
jarvis/jarvis_tools/methodology.py,sha256=RFqcVjKuj8ESGmNYcQz_HyphsitDvF3XtqgGaqhafDQ,5770
|
|
51
51
|
jarvis/jarvis_tools/rag.py,sha256=2fQHqc4bw8JM-OxGTsHobLIOTo8Mip3rdtJCmAoY8XU,4952
|
|
52
|
-
jarvis/jarvis_tools/read_code.py,sha256=
|
|
52
|
+
jarvis/jarvis_tools/read_code.py,sha256=Pr7e06qHpVn7_cuXCZY1HuJ28MCHMPzCQltn9GSza8o,4030
|
|
53
53
|
jarvis/jarvis_tools/read_webpage.py,sha256=JCReSXhkDHDkQ606sZYIKG1Itlprjpmu1sSbF-Ed-jI,2478
|
|
54
54
|
jarvis/jarvis_tools/registry.py,sha256=OR-BxSVfI3ER_1rAPMZfLf45E2YpheeS01j8MJ8RGso,11841
|
|
55
55
|
jarvis/jarvis_tools/search.py,sha256=PLSSNETyajpqDoStCTfkoy-D41IMNudTuVzonMlT6Aw,9225
|
|
56
56
|
jarvis/jarvis_tools/select_code_files.py,sha256=bjJGwCNw0Ue_8jW60K1gcy1rUgKqoHihicu5SS58WNk,1890
|
|
57
|
-
|
|
58
|
-
jarvis_ai_assistant-0.1.
|
|
59
|
-
jarvis_ai_assistant-0.1.
|
|
60
|
-
jarvis_ai_assistant-0.1.
|
|
61
|
-
jarvis_ai_assistant-0.1.
|
|
62
|
-
jarvis_ai_assistant-0.1.
|
|
57
|
+
jarvis/utils/date_utils.py,sha256=DZCQ91FBC4dnQRKCqNnACTg3HuqzQ7R1DRYqH59tON4,537
|
|
58
|
+
jarvis_ai_assistant-0.1.111.dist-info/LICENSE,sha256=AGgVgQmTqFvaztRtCAXsAMryUymB18gZif7_l2e1XOg,1063
|
|
59
|
+
jarvis_ai_assistant-0.1.111.dist-info/METADATA,sha256=FEftsBlMHWqbUroz5ZdWcDD6JaOZlKlzQ3PJshAC-bQ,14323
|
|
60
|
+
jarvis_ai_assistant-0.1.111.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
61
|
+
jarvis_ai_assistant-0.1.111.dist-info/entry_points.txt,sha256=UYj4FYvOH8jJ0GgCJTA_TAmJ3wvikos-hUVbCwt_KOc,480
|
|
62
|
+
jarvis_ai_assistant-0.1.111.dist-info/top_level.txt,sha256=1BOxyWfzOP_ZXj8rVTDnNCJ92bBGB0rwq8N1PCpoMIs,7
|
|
63
|
+
jarvis_ai_assistant-0.1.111.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
{jarvis_ai_assistant-0.1.110.dist-info → jarvis_ai_assistant-0.1.111.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{jarvis_ai_assistant-0.1.110.dist-info → jarvis_ai_assistant-0.1.111.dist-info}/top_level.txt
RENAMED
|
File without changes
|