jarvis-ai-assistant 0.1.98__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 +199 -157
- jarvis/jarvis_code_agent/__init__.py +0 -0
- jarvis/jarvis_code_agent/main.py +202 -0
- jarvis/jarvis_codebase/main.py +415 -287
- jarvis/jarvis_coder/file_select.py +209 -0
- jarvis/jarvis_coder/git_utils.py +64 -2
- jarvis/jarvis_coder/main.py +13 -397
- jarvis/jarvis_coder/patch_handler.py +229 -81
- jarvis/jarvis_coder/plan_generator.py +49 -7
- jarvis/jarvis_platform/main.py +2 -2
- jarvis/jarvis_rag/main.py +11 -11
- jarvis/jarvis_smart_shell/main.py +5 -5
- jarvis/models/base.py +6 -1
- jarvis/models/kimi.py +2 -2
- jarvis/models/ollama.py +2 -2
- jarvis/models/openai.py +1 -1
- jarvis/models/registry.py +38 -18
- jarvis/tools/ask_user.py +12 -9
- jarvis/tools/chdir.py +9 -5
- jarvis/tools/create_code_sub_agent.py +56 -0
- jarvis/tools/{sub_agent.py → create_sub_agent.py} +6 -2
- jarvis/tools/execute_code_modification.py +70 -0
- jarvis/tools/{shell.py → execute_shell.py} +2 -2
- jarvis/tools/{file_ops.py → file_operation.py} +19 -15
- jarvis/tools/find_files.py +119 -0
- jarvis/tools/{generator.py → generate_tool.py} +27 -25
- jarvis/tools/methodology.py +32 -26
- jarvis/tools/rag.py +37 -33
- jarvis/tools/{webpage.py → read_webpage.py} +4 -2
- jarvis/tools/registry.py +94 -48
- jarvis/tools/search.py +19 -16
- jarvis/tools/select_code_files.py +61 -0
- jarvis/tools/thinker.py +7 -5
- jarvis/utils.py +155 -32
- {jarvis_ai_assistant-0.1.98.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_ai_assistant-0.1.98.dist-info → jarvis_ai_assistant-0.1.100.dist-info}/entry_points.txt +2 -1
- jarvis/main.py +0 -155
- jarvis/tools/codebase_qa.py +0 -74
- jarvis/tools/coder.py +0 -69
- jarvis_ai_assistant-0.1.98.dist-info/RECORD +0 -47
- {jarvis_ai_assistant-0.1.98.dist-info → jarvis_ai_assistant-0.1.100.dist-info}/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.98.dist-info → jarvis_ai_assistant-0.1.100.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.98.dist-info → jarvis_ai_assistant-0.1.100.dist-info}/top_level.txt +0 -0
|
@@ -32,16 +32,15 @@ class ToolGeneratorTool:
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
def __init__(self):
|
|
35
|
-
"""
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
self.tools_dir = Path.home() / '.jarvis_tools'
|
|
35
|
+
"""Initialize tool generator"""
|
|
36
|
+
# Set tool directory
|
|
37
|
+
self.tools_dir = Path.home() / '.jarvis/tools'
|
|
39
38
|
|
|
40
|
-
#
|
|
39
|
+
# Ensure tool directory exists
|
|
41
40
|
self.tools_dir.mkdir(parents=True, exist_ok=True)
|
|
42
41
|
|
|
43
42
|
def _generate_tool_code(self, tool_name: str, class_name: str, description: str, parameters: Dict) -> str:
|
|
44
|
-
"""
|
|
43
|
+
"""Use large model to generate tool code"""
|
|
45
44
|
model = PlatformRegistry.get_global_platform_registry().get_codegen_platform()
|
|
46
45
|
|
|
47
46
|
prompt = f"""Please generate the code for a Python tool class, with the following requirements, and do not output any content except the code:
|
|
@@ -96,36 +95,37 @@ class ExampleTool:
|
|
|
96
95
|
PrettyOutput.print(str(e), OutputType.ERROR)
|
|
97
96
|
return {{
|
|
98
97
|
"success": False,
|
|
99
|
-
"
|
|
98
|
+
"stdout": "",
|
|
99
|
+
"stderr": str(e)
|
|
100
100
|
}}
|
|
101
101
|
```"""
|
|
102
102
|
|
|
103
|
-
#
|
|
103
|
+
# Call model to generate code
|
|
104
104
|
response = model.chat_until_success(prompt)
|
|
105
105
|
|
|
106
|
-
#
|
|
106
|
+
# Extract code block
|
|
107
107
|
code_start = response.find("```python")
|
|
108
108
|
code_end = response.find("```", code_start + 9)
|
|
109
109
|
|
|
110
110
|
if code_start == -1 or code_end == -1:
|
|
111
|
-
#
|
|
111
|
+
# If code block marker not found, assume the entire response is code
|
|
112
112
|
return response
|
|
113
113
|
|
|
114
|
-
#
|
|
114
|
+
# Extract code block content (remove ```python and ``` markers)
|
|
115
115
|
code = response[code_start + 9:code_end].strip()
|
|
116
116
|
return code
|
|
117
117
|
|
|
118
118
|
def execute(self, args: Dict) -> Dict[str, Any]:
|
|
119
|
-
"""
|
|
119
|
+
"""Generate tool code"""
|
|
120
120
|
try:
|
|
121
121
|
tool_name = args["tool_name"]
|
|
122
122
|
class_name = args["class_name"]
|
|
123
123
|
description = args["description"]
|
|
124
124
|
parameters = args["parameters"]
|
|
125
125
|
|
|
126
|
-
PrettyOutput.print(f"
|
|
126
|
+
PrettyOutput.print(f"Start generating tool: {tool_name}", OutputType.INFO)
|
|
127
127
|
|
|
128
|
-
#
|
|
128
|
+
# Generate tool code
|
|
129
129
|
tool_code = self._generate_tool_code(
|
|
130
130
|
tool_name,
|
|
131
131
|
class_name,
|
|
@@ -133,34 +133,35 @@ class ExampleTool:
|
|
|
133
133
|
parameters
|
|
134
134
|
)
|
|
135
135
|
|
|
136
|
-
#
|
|
136
|
+
# Get tool file path
|
|
137
137
|
tool_file = self.tools_dir / f"{tool_name}.py"
|
|
138
138
|
|
|
139
|
-
#
|
|
139
|
+
# Write tool file
|
|
140
140
|
with open(tool_file, "w", encoding="utf-8") as f:
|
|
141
141
|
f.write(tool_code)
|
|
142
142
|
|
|
143
|
-
#
|
|
143
|
+
# Create or update __init__.py
|
|
144
144
|
init_file = self.tools_dir / "__init__.py"
|
|
145
145
|
if not init_file.exists():
|
|
146
146
|
with open(init_file, "w", encoding="utf-8") as f:
|
|
147
147
|
f.write("# Jarvis Tools\n")
|
|
148
148
|
|
|
149
|
-
#
|
|
149
|
+
# Register tool
|
|
150
150
|
success = ToolRegistry.get_global_tool_registry().register_tool_by_file(str(tool_file))
|
|
151
151
|
if not success:
|
|
152
152
|
return {
|
|
153
153
|
"success": False,
|
|
154
|
-
"
|
|
154
|
+
"stdout": "",
|
|
155
|
+
"stderr": "Tool generated successfully but registration failed"
|
|
155
156
|
}
|
|
156
157
|
|
|
157
158
|
return {
|
|
158
159
|
"success": True,
|
|
159
|
-
"stdout": f"
|
|
160
|
-
f"
|
|
161
|
-
f"
|
|
162
|
-
f"
|
|
163
|
-
f"
|
|
160
|
+
"stdout": f"Tool generated and registered to Jarvis\n"
|
|
161
|
+
f"Tool directory: {self.tools_dir}\n"
|
|
162
|
+
f"Tool name: {tool_name}\n"
|
|
163
|
+
f"Tool description: {description}\n"
|
|
164
|
+
f"Tool parameters: {parameters}",
|
|
164
165
|
"stderr": ""
|
|
165
166
|
}
|
|
166
167
|
|
|
@@ -168,5 +169,6 @@ class ExampleTool:
|
|
|
168
169
|
PrettyOutput.print(str(e), OutputType.ERROR)
|
|
169
170
|
return {
|
|
170
171
|
"success": False,
|
|
171
|
-
"
|
|
172
|
+
"stdout": "",
|
|
173
|
+
"stderr": f"Failed to generate tool: {str(e)}"
|
|
172
174
|
}
|
jarvis/tools/methodology.py
CHANGED
|
@@ -5,7 +5,7 @@ from jarvis.utils import OutputType, PrettyOutput
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class MethodologyTool:
|
|
8
|
-
"""
|
|
8
|
+
"""Experience management tool"""
|
|
9
9
|
|
|
10
10
|
name = "methodology"
|
|
11
11
|
description = "Manage problem-solving methodologies, supporting add, update, and delete operations"
|
|
@@ -31,47 +31,47 @@ class MethodologyTool:
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
def __init__(self):
|
|
34
|
-
"""
|
|
35
|
-
self.methodology_file = os.path.expanduser("~/.
|
|
34
|
+
"""Initialize the experience management tool"""
|
|
35
|
+
self.methodology_file = os.path.expanduser("~/.jarvis/methodology")
|
|
36
36
|
self._ensure_file_exists()
|
|
37
37
|
|
|
38
38
|
def _ensure_file_exists(self):
|
|
39
|
-
"""
|
|
39
|
+
"""Ensure the methodology file exists"""
|
|
40
40
|
if not os.path.exists(self.methodology_file):
|
|
41
41
|
try:
|
|
42
42
|
with open(self.methodology_file, 'w', encoding='utf-8') as f:
|
|
43
43
|
yaml.safe_dump({}, f, allow_unicode=True)
|
|
44
44
|
except Exception as e:
|
|
45
|
-
PrettyOutput.print(f"
|
|
45
|
+
PrettyOutput.print(f"Failed to create methodology file: {str(e)}", OutputType.ERROR)
|
|
46
46
|
|
|
47
47
|
def _load_methodologies(self) -> Dict:
|
|
48
|
-
"""
|
|
48
|
+
"""Load all methodologies"""
|
|
49
49
|
try:
|
|
50
50
|
with open(self.methodology_file, 'r', encoding='utf-8') as f:
|
|
51
51
|
return yaml.safe_load(f) or {}
|
|
52
52
|
except Exception as e:
|
|
53
|
-
PrettyOutput.print(f"
|
|
53
|
+
PrettyOutput.print(f"Failed to load methodologies: {str(e)}", OutputType.ERROR)
|
|
54
54
|
return {}
|
|
55
55
|
|
|
56
56
|
def _save_methodologies(self, methodologies: Dict):
|
|
57
|
-
"""
|
|
57
|
+
"""Save all methodologies"""
|
|
58
58
|
try:
|
|
59
59
|
with open(self.methodology_file, 'w', encoding='utf-8') as f:
|
|
60
60
|
yaml.safe_dump(methodologies, f, allow_unicode=True)
|
|
61
61
|
except Exception as e:
|
|
62
|
-
PrettyOutput.print(f"
|
|
62
|
+
PrettyOutput.print(f"Failed to save methodologies: {str(e)}", OutputType.ERROR)
|
|
63
63
|
|
|
64
64
|
def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
|
|
65
|
-
"""
|
|
65
|
+
"""Execute the operation of managing methodologies
|
|
66
66
|
|
|
67
67
|
Args:
|
|
68
|
-
args:
|
|
69
|
-
- operation:
|
|
70
|
-
- problem_type:
|
|
71
|
-
- content:
|
|
68
|
+
args: A dictionary containing the operation parameters
|
|
69
|
+
- operation: The operation type (delete/update/add)
|
|
70
|
+
- problem_type: The problem type
|
|
71
|
+
- content: The methodology content (required for update/add)
|
|
72
72
|
|
|
73
73
|
Returns:
|
|
74
|
-
Dict[str, Any]:
|
|
74
|
+
Dict[str, Any]: A dictionary containing the execution result
|
|
75
75
|
"""
|
|
76
76
|
operation = args.get("operation")
|
|
77
77
|
problem_type = args.get("problem_type")
|
|
@@ -80,7 +80,8 @@ class MethodologyTool:
|
|
|
80
80
|
if not operation or not problem_type:
|
|
81
81
|
return {
|
|
82
82
|
"success": False,
|
|
83
|
-
"
|
|
83
|
+
"stdout": "",
|
|
84
|
+
"stderr": "Missing required parameters: operation and problem_type"
|
|
84
85
|
}
|
|
85
86
|
|
|
86
87
|
methodologies = self._load_methodologies()
|
|
@@ -92,50 +93,55 @@ class MethodologyTool:
|
|
|
92
93
|
self._save_methodologies(methodologies)
|
|
93
94
|
return {
|
|
94
95
|
"success": True,
|
|
95
|
-
"stdout": f"
|
|
96
|
+
"stdout": f"Deleted methodology for problem type '{problem_type}'"
|
|
96
97
|
}
|
|
97
98
|
else:
|
|
98
99
|
return {
|
|
99
100
|
"success": False,
|
|
100
|
-
"
|
|
101
|
+
"stdout": "",
|
|
102
|
+
"stderr": f"Methodology for problem type '{problem_type}' not found"
|
|
101
103
|
}
|
|
102
104
|
|
|
103
105
|
elif operation in ["update", "add"]:
|
|
104
106
|
if not content:
|
|
105
107
|
return {
|
|
106
108
|
"success": False,
|
|
107
|
-
"
|
|
109
|
+
"stdout": "",
|
|
110
|
+
"stderr": "Need to provide methodology content"
|
|
108
111
|
}
|
|
109
112
|
|
|
110
113
|
methodologies[problem_type] = content
|
|
111
114
|
self._save_methodologies(methodologies)
|
|
112
115
|
|
|
113
|
-
action = "
|
|
116
|
+
action = "Update" if problem_type in methodologies else "Add"
|
|
114
117
|
return {
|
|
115
118
|
"success": True,
|
|
116
|
-
"stdout": f"
|
|
119
|
+
"stdout": f"{action} methodology for problem type '{problem_type}'",
|
|
120
|
+
"stderr": ""
|
|
117
121
|
}
|
|
118
122
|
|
|
119
123
|
else:
|
|
120
124
|
return {
|
|
121
125
|
"success": False,
|
|
122
|
-
"
|
|
126
|
+
"stdout": "",
|
|
127
|
+
"stderr": f"Unsupported operation type: {operation}"
|
|
123
128
|
}
|
|
124
129
|
|
|
125
130
|
except Exception as e:
|
|
126
131
|
return {
|
|
127
132
|
"success": False,
|
|
128
|
-
"
|
|
133
|
+
"stdout": "",
|
|
134
|
+
"stderr": f"Execution failed: {str(e)}"
|
|
129
135
|
}
|
|
130
136
|
|
|
131
137
|
def get_methodology(self, problem_type: str) -> Optional[str]:
|
|
132
|
-
"""
|
|
138
|
+
"""Get the methodology for a specific problem type
|
|
133
139
|
|
|
134
140
|
Args:
|
|
135
|
-
problem_type:
|
|
141
|
+
problem_type: The problem type
|
|
136
142
|
|
|
137
143
|
Returns:
|
|
138
|
-
Optional[str]:
|
|
144
|
+
Optional[str]: The methodology content, or None if it does not exist
|
|
139
145
|
"""
|
|
140
146
|
methodologies = self._load_methodologies()
|
|
141
147
|
return methodologies.get(problem_type)
|
jarvis/tools/rag.py
CHANGED
|
@@ -27,71 +27,74 @@ class RAGTool:
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
def __init__(self):
|
|
30
|
-
"""
|
|
31
|
-
self.rag_instances = {} #
|
|
30
|
+
"""Initialize RAG tool"""
|
|
31
|
+
self.rag_instances = {} # Cache RAG instances for different directories
|
|
32
32
|
|
|
33
33
|
def _get_rag_instance(self, dir_path: str) -> RAGCore:
|
|
34
|
-
"""
|
|
34
|
+
"""Get or create RAG instance
|
|
35
35
|
|
|
36
36
|
Args:
|
|
37
|
-
dir_path:
|
|
37
|
+
dir_path: The absolute path of the document directory
|
|
38
38
|
|
|
39
39
|
Returns:
|
|
40
|
-
RAGCore: RAG
|
|
40
|
+
RAGCore: RAG instance
|
|
41
41
|
"""
|
|
42
42
|
if dir_path not in self.rag_instances:
|
|
43
43
|
self.rag_instances[dir_path] = RAGCore(dir_path)
|
|
44
44
|
return self.rag_instances[dir_path]
|
|
45
45
|
|
|
46
46
|
def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
|
|
47
|
-
"""
|
|
47
|
+
"""Execute document question and answer
|
|
48
48
|
|
|
49
49
|
Args:
|
|
50
|
-
args:
|
|
51
|
-
- dir:
|
|
52
|
-
- question:
|
|
53
|
-
- rebuild_index:
|
|
50
|
+
args: A dictionary containing parameters
|
|
51
|
+
- dir: The document directory path
|
|
52
|
+
- question: The question to ask
|
|
53
|
+
- rebuild_index: Whether to rebuild the index
|
|
54
54
|
|
|
55
55
|
Returns:
|
|
56
|
-
Dict[str, Any]:
|
|
56
|
+
Dict[str, Any]: The execution result
|
|
57
57
|
"""
|
|
58
58
|
try:
|
|
59
|
-
#
|
|
60
|
-
dir_path = os.path.expanduser(args["dir"]) #
|
|
61
|
-
dir_path = os.path.abspath(dir_path) #
|
|
59
|
+
# Get parameters
|
|
60
|
+
dir_path = os.path.expanduser(args["dir"]) # Expand ~ paths
|
|
61
|
+
dir_path = os.path.abspath(dir_path) # Convert to absolute path
|
|
62
62
|
question = args["question"]
|
|
63
63
|
rebuild_index = args.get("rebuild_index", False)
|
|
64
64
|
|
|
65
|
-
#
|
|
65
|
+
# Check if the directory exists
|
|
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
|
|
80
82
|
rag = self._get_rag_instance(dir_path)
|
|
81
83
|
|
|
82
|
-
#
|
|
84
|
+
# If you need to rebuild the index or the index does not exist
|
|
83
85
|
if rebuild_index or not rag.is_index_built():
|
|
84
|
-
PrettyOutput.print("
|
|
86
|
+
PrettyOutput.print("Building document index...", OutputType.INFO)
|
|
85
87
|
rag.build_index(dir_path)
|
|
86
88
|
|
|
87
|
-
#
|
|
88
|
-
PrettyOutput.print(f"
|
|
89
|
+
# Execute question and answer
|
|
90
|
+
PrettyOutput.print(f"Question: {question}", OutputType.INFO)
|
|
89
91
|
response = rag.ask(question)
|
|
90
92
|
|
|
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 {
|
|
@@ -101,20 +104,21 @@ class RAGTool:
|
|
|
101
104
|
}
|
|
102
105
|
|
|
103
106
|
except Exception as e:
|
|
104
|
-
PrettyOutput.print(f"
|
|
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():
|
|
111
|
-
"""
|
|
115
|
+
"""Run the tool directly from the command line"""
|
|
112
116
|
import argparse
|
|
113
117
|
|
|
114
|
-
parser = argparse.ArgumentParser(description='
|
|
115
|
-
parser.add_argument('--dir', required=True, help='
|
|
116
|
-
parser.add_argument('--question', required=True, help='
|
|
117
|
-
parser.add_argument('--rebuild', action='store_true', help='
|
|
118
|
+
parser = argparse.ArgumentParser(description='Document question and answer tool')
|
|
119
|
+
parser.add_argument('--dir', required=True, help='Document directory path')
|
|
120
|
+
parser.add_argument('--question', required=True, help='The question to ask')
|
|
121
|
+
parser.add_argument('--rebuild', action='store_true', help='Rebuild index')
|
|
118
122
|
args = parser.parse_args()
|
|
119
123
|
|
|
120
124
|
tool = RAGTool()
|
|
@@ -125,10 +129,10 @@ def main():
|
|
|
125
129
|
})
|
|
126
130
|
|
|
127
131
|
if result["success"]:
|
|
128
|
-
PrettyOutput.print("\
|
|
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()
|
|
@@ -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
|
}
|