jarvis-ai-assistant 0.1.99__py3-none-any.whl → 0.1.101__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 +153 -75
- 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.101.dist-info}/METADATA +9 -8
- jarvis_ai_assistant-0.1.101.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.101.dist-info}/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.99.dist-info → jarvis_ai_assistant-0.1.101.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.99.dist-info → jarvis_ai_assistant-0.1.101.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.1.99.dist-info → jarvis_ai_assistant-0.1.101.dist-info}/top_level.txt +0 -0
|
@@ -8,24 +8,26 @@ from yaspin import yaspin # type: ignore
|
|
|
8
8
|
from yaspin.spinners import Spinners # type: ignore
|
|
9
9
|
|
|
10
10
|
from jarvis.models.registry import PlatformRegistry
|
|
11
|
-
from jarvis.utils import PrettyOutput, OutputType,
|
|
11
|
+
from jarvis.utils import PrettyOutput, OutputType, init_env
|
|
12
12
|
|
|
13
13
|
def execute_command(command: str) -> None:
|
|
14
14
|
"""Show command and allow user to edit, then execute, Ctrl+C to cancel"""
|
|
15
15
|
try:
|
|
16
|
+
print("\nGenerated command (can be edited, press Enter to execute, Ctrl+C to cancel):")
|
|
16
17
|
# Pre-fill input line
|
|
17
18
|
readline.set_startup_hook(lambda: readline.insert_text(command))
|
|
18
19
|
try:
|
|
19
|
-
edited_command =
|
|
20
|
+
edited_command = input("> ")
|
|
20
21
|
if edited_command.strip(): # Ensure command is not empty
|
|
21
22
|
os.system(edited_command)
|
|
22
23
|
except KeyboardInterrupt:
|
|
23
|
-
|
|
24
|
+
print("\nExecution cancelled")
|
|
24
25
|
finally:
|
|
25
26
|
readline.set_startup_hook() # Clear pre-filled
|
|
26
27
|
except Exception as e:
|
|
27
28
|
PrettyOutput.print(f"Failed to execute command: {str(e)}", OutputType.ERROR)
|
|
28
29
|
|
|
30
|
+
|
|
29
31
|
def process_request(request: str) -> Optional[str]:
|
|
30
32
|
"""Process user request and return corresponding shell command
|
|
31
33
|
|
|
@@ -88,7 +90,7 @@ Remember: Only return the command itself, without any additional content.
|
|
|
88
90
|
|
|
89
91
|
def main():
|
|
90
92
|
# 创建参数解析器
|
|
91
|
-
|
|
93
|
+
init_env()
|
|
92
94
|
parser = argparse.ArgumentParser(
|
|
93
95
|
description="Convert natural language requirements to shell commands",
|
|
94
96
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
jarvis/models/kimi.py
CHANGED
|
@@ -35,8 +35,8 @@ class KimiModel(BasePlatform):
|
|
|
35
35
|
PrettyOutput.print(" • Find the Authorization header in the request", OutputType.INFO)
|
|
36
36
|
PrettyOutput.print(" • Copy the token value (remove the 'Bearer ' prefix)", OutputType.INFO)
|
|
37
37
|
PrettyOutput.print("\n2. Set environment variable:", OutputType.INFO)
|
|
38
|
-
PrettyOutput.print(" • Method 1: Create or edit ~/.
|
|
39
|
-
PrettyOutput.print(" echo 'KIMI_API_KEY=your_key_here' > ~/.
|
|
38
|
+
PrettyOutput.print(" • Method 1: Create or edit ~/.jarvis/env file:", OutputType.INFO)
|
|
39
|
+
PrettyOutput.print(" echo 'KIMI_API_KEY=your_key_here' > ~/.jarvis/env", OutputType.INFO)
|
|
40
40
|
PrettyOutput.print("\n • Method 2: Set environment variable directly:", OutputType.INFO)
|
|
41
41
|
PrettyOutput.print(" export KIMI_API_KEY=your_key_here", OutputType.INFO)
|
|
42
42
|
PrettyOutput.print("\nAfter setting, run Jarvis again.", OutputType.INFO)
|
jarvis/models/openai.py
CHANGED
|
@@ -23,7 +23,7 @@ class OpenAIModel(BasePlatform):
|
|
|
23
23
|
PrettyOutput.print(" • OPENAI_API_KEY: API key", OutputType.INFO)
|
|
24
24
|
PrettyOutput.print(" • OPENAI_API_BASE: (optional) API base address, default using https://api.openai.com/v1", OutputType.INFO)
|
|
25
25
|
PrettyOutput.print("\nYou can set them in the following ways:", OutputType.INFO)
|
|
26
|
-
PrettyOutput.print("1. Create or edit ~/.
|
|
26
|
+
PrettyOutput.print("1. Create or edit ~/.jarvis/env file:", OutputType.INFO)
|
|
27
27
|
PrettyOutput.print(" OPENAI_API_KEY=your_api_key", OutputType.INFO)
|
|
28
28
|
PrettyOutput.print(" OPENAI_API_BASE=your_api_base", OutputType.INFO)
|
|
29
29
|
PrettyOutput.print(" OPENAI_MODEL_NAME=your_model_name", OutputType.INFO)
|
jarvis/models/registry.py
CHANGED
|
@@ -26,7 +26,7 @@ class PlatformRegistry:
|
|
|
26
26
|
|
|
27
27
|
@staticmethod
|
|
28
28
|
def get_platform_dir() -> str:
|
|
29
|
-
user_platform_dir = os.path.expanduser("~/.
|
|
29
|
+
user_platform_dir = os.path.expanduser("~/.jarvis/models")
|
|
30
30
|
if not os.path.exists(user_platform_dir):
|
|
31
31
|
try:
|
|
32
32
|
os.makedirs(user_platform_dir)
|
|
@@ -137,22 +137,22 @@ class PlatformRegistry:
|
|
|
137
137
|
def get_global_platform_registry():
|
|
138
138
|
"""Get global platform registry"""
|
|
139
139
|
if PlatformRegistry.global_platform_registry is None:
|
|
140
|
-
PlatformRegistry.global_platform_registry = PlatformRegistry()
|
|
141
|
-
|
|
142
|
-
# 从用户平台目录加载额外平台
|
|
143
|
-
platform_dir = PlatformRegistry.get_platform_dir()
|
|
144
|
-
if platform_dir and os.path.exists(platform_dir):
|
|
145
|
-
for platform_name, platform_class in PlatformRegistry.load_platform_from_dir(platform_dir).items():
|
|
146
|
-
PlatformRegistry.global_platform_registry.register_platform(platform_name, platform_class)
|
|
147
|
-
platform_dir = os.path.dirname(__file__)
|
|
148
|
-
if platform_dir and os.path.exists(platform_dir):
|
|
149
|
-
for platform_name, platform_class in PlatformRegistry.load_platform_from_dir(platform_dir).items():
|
|
150
|
-
PlatformRegistry.global_platform_registry.register_platform(platform_name, platform_class)
|
|
140
|
+
PlatformRegistry.global_platform_registry = PlatformRegistry()
|
|
151
141
|
return PlatformRegistry.global_platform_registry
|
|
152
142
|
|
|
153
143
|
def __init__(self):
|
|
154
144
|
"""Initialize platform registry"""
|
|
155
145
|
self.platforms: Dict[str, Type[BasePlatform]] = {}
|
|
146
|
+
# 从用户平台目录加载额外平台
|
|
147
|
+
platform_dir = PlatformRegistry.get_platform_dir()
|
|
148
|
+
if platform_dir and os.path.exists(platform_dir):
|
|
149
|
+
for platform_name, platform_class in PlatformRegistry.load_platform_from_dir(platform_dir).items():
|
|
150
|
+
self.register_platform(platform_name, platform_class)
|
|
151
|
+
platform_dir = os.path.dirname(__file__)
|
|
152
|
+
if platform_dir and os.path.exists(platform_dir):
|
|
153
|
+
for platform_name, platform_class in PlatformRegistry.load_platform_from_dir(platform_dir).items():
|
|
154
|
+
self.register_platform(platform_name, platform_class)
|
|
155
|
+
|
|
156
156
|
|
|
157
157
|
def get_normal_platform(self) -> BasePlatform:
|
|
158
158
|
platform_name = os.environ.get("JARVIS_PLATFORM", "kimi")
|
|
@@ -212,6 +212,29 @@ class PlatformRegistry:
|
|
|
212
212
|
PrettyOutput.print(f"Create platform failed: {str(e)}", OutputType.ERROR)
|
|
213
213
|
return None
|
|
214
214
|
|
|
215
|
+
def use_platforms(self, platform_names: List[str]):
|
|
216
|
+
"""Restrict available platforms to the specified list
|
|
217
|
+
|
|
218
|
+
Args:
|
|
219
|
+
platform_names: List of platform names to use
|
|
220
|
+
"""
|
|
221
|
+
self.platforms = {
|
|
222
|
+
name: cls
|
|
223
|
+
for name, cls in self.platforms.items()
|
|
224
|
+
if name in platform_names
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
def dont_use_platforms(self, platform_names: List[str]):
|
|
228
|
+
"""Restrict available platforms by excluding the specified list
|
|
229
|
+
|
|
230
|
+
Args:
|
|
231
|
+
platform_names: List of platform names to exclude
|
|
232
|
+
"""
|
|
233
|
+
self.platforms = {
|
|
234
|
+
name: cls
|
|
235
|
+
for name, cls in self.platforms.items()
|
|
236
|
+
if name not in platform_names
|
|
237
|
+
}
|
|
215
238
|
def get_available_platforms(self) -> List[str]:
|
|
216
239
|
"""Get available platform list"""
|
|
217
240
|
return list(self.platforms.keys())
|
jarvis/tools/ask_user.py
CHANGED
|
@@ -39,16 +39,19 @@ class AskUserTool:
|
|
|
39
39
|
if user_response == "__interrupt__":
|
|
40
40
|
return {
|
|
41
41
|
"success": False,
|
|
42
|
-
"
|
|
42
|
+
"stdout": "",
|
|
43
|
+
"stderr": "User canceled input"
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
return {
|
|
46
47
|
"success": True,
|
|
47
|
-
"stdout": user_response
|
|
48
|
+
"stdout": user_response,
|
|
49
|
+
"stderr": ""
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
except Exception as e:
|
|
51
53
|
return {
|
|
52
54
|
"success": False,
|
|
53
|
-
"
|
|
55
|
+
"stdout": "",
|
|
56
|
+
"stderr": f"Failed to ask user: {str(e)}"
|
|
54
57
|
}
|
jarvis/tools/chdir.py
CHANGED
|
@@ -38,14 +38,16 @@ class ChdirTool:
|
|
|
38
38
|
if not os.path.exists(path):
|
|
39
39
|
return {
|
|
40
40
|
"success": False,
|
|
41
|
-
"
|
|
41
|
+
"stdout": "",
|
|
42
|
+
"stderr": f"Directory does not exist: {path}"
|
|
42
43
|
}
|
|
43
44
|
|
|
44
45
|
# 检查是否是目录
|
|
45
46
|
if not os.path.isdir(path):
|
|
46
47
|
return {
|
|
47
48
|
"success": False,
|
|
48
|
-
"
|
|
49
|
+
"stdout": "",
|
|
50
|
+
"stderr": f"The path is not a directory: {path}"
|
|
49
51
|
}
|
|
50
52
|
|
|
51
53
|
# 尝试切换目录
|
|
@@ -61,12 +63,14 @@ class ChdirTool:
|
|
|
61
63
|
except PermissionError:
|
|
62
64
|
return {
|
|
63
65
|
"success": False,
|
|
64
|
-
"
|
|
66
|
+
"stdout": "",
|
|
67
|
+
"stderr": f"No permission to access directory: {path}"
|
|
65
68
|
}
|
|
66
69
|
except Exception as e:
|
|
67
70
|
return {
|
|
68
71
|
"success": False,
|
|
69
|
-
"
|
|
72
|
+
"stdout": "",
|
|
73
|
+
"stderr": f"Failed to switch directory: {str(e)}"
|
|
70
74
|
}
|
|
71
75
|
|
|
72
76
|
def main():
|
|
@@ -83,7 +87,7 @@ def main():
|
|
|
83
87
|
if result["success"]:
|
|
84
88
|
PrettyOutput.print(result["stdout"], OutputType.SUCCESS)
|
|
85
89
|
else:
|
|
86
|
-
PrettyOutput.print(result["
|
|
90
|
+
PrettyOutput.print(result["stderr"], OutputType.ERROR)
|
|
87
91
|
|
|
88
92
|
if __name__ == "__main__":
|
|
89
93
|
main()
|
jarvis/tools/create_sub_agent.py
CHANGED
|
@@ -43,7 +43,7 @@ class CodeModifyTool:
|
|
|
43
43
|
patch_handler = PatchHandler()
|
|
44
44
|
|
|
45
45
|
# Apply patches and handle the process
|
|
46
|
-
success = patch_handler.handle_patch_application(
|
|
46
|
+
success, additional_info = patch_handler.handle_patch_application(
|
|
47
47
|
feature=task,
|
|
48
48
|
structed_plan=structured_plan
|
|
49
49
|
)
|
|
@@ -51,22 +51,20 @@ class CodeModifyTool:
|
|
|
51
51
|
if not success:
|
|
52
52
|
return {
|
|
53
53
|
"success": False,
|
|
54
|
-
"error": "Code modification was cancelled or failed",
|
|
55
54
|
"stdout": "Changes have been rolled back",
|
|
56
|
-
"stderr":
|
|
55
|
+
"stderr": additional_info
|
|
57
56
|
}
|
|
58
57
|
|
|
59
58
|
return {
|
|
60
59
|
"success": True,
|
|
61
60
|
"stdout": "Code modifications have been successfully applied and committed",
|
|
62
|
-
"stderr":
|
|
61
|
+
"stderr": additional_info
|
|
63
62
|
}
|
|
64
63
|
|
|
65
64
|
except Exception as e:
|
|
66
65
|
PrettyOutput.print(str(e), OutputType.ERROR)
|
|
67
66
|
return {
|
|
68
67
|
"success": False,
|
|
69
|
-
"error": f"Failed to execute code modifications: {str(e)}",
|
|
70
68
|
"stdout": "",
|
|
71
|
-
"stderr": str(e)
|
|
69
|
+
"stderr": f"Failed to execute code modifications: {str(e)}"
|
|
72
70
|
}
|
jarvis/tools/execute_shell.py
CHANGED
|
@@ -64,7 +64,6 @@ class ShellTool:
|
|
|
64
64
|
"success": return_code == 0,
|
|
65
65
|
"stdout": output,
|
|
66
66
|
"stderr": "",
|
|
67
|
-
"return_code": return_code
|
|
68
67
|
}
|
|
69
68
|
|
|
70
69
|
except Exception as e:
|
|
@@ -74,5 +73,6 @@ class ShellTool:
|
|
|
74
73
|
PrettyOutput.print(str(e), OutputType.ERROR)
|
|
75
74
|
return {
|
|
76
75
|
"success": False,
|
|
77
|
-
"
|
|
76
|
+
"stdout": "",
|
|
77
|
+
"stderr": str(e)
|
|
78
78
|
}
|
jarvis/tools/file_operation.py
CHANGED
|
@@ -57,14 +57,16 @@ class FileOperationTool:
|
|
|
57
57
|
if not os.path.exists(filepath):
|
|
58
58
|
return {
|
|
59
59
|
"success": False,
|
|
60
|
-
"
|
|
60
|
+
"stdout": "",
|
|
61
|
+
"stderr": f"文件不存在: {filepath}"
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
# Check file size
|
|
64
65
|
if os.path.getsize(filepath) > 10 * 1024 * 1024: # 10MB
|
|
65
66
|
return {
|
|
66
67
|
"success": False,
|
|
67
|
-
"
|
|
68
|
+
"stdout": "",
|
|
69
|
+
"stderr": "File too large (>10MB)"
|
|
68
70
|
}
|
|
69
71
|
|
|
70
72
|
content = open(filepath, 'r', encoding=encoding).read()
|
|
@@ -79,7 +81,8 @@ class FileOperationTool:
|
|
|
79
81
|
if not args.get("content"):
|
|
80
82
|
return {
|
|
81
83
|
"success": False,
|
|
82
|
-
"
|
|
84
|
+
"stdout": "",
|
|
85
|
+
"stderr": "Write/append operation requires providing the content parameter"
|
|
83
86
|
}
|
|
84
87
|
|
|
85
88
|
# Create directory (if it doesn't exist)
|
|
@@ -98,12 +101,14 @@ class FileOperationTool:
|
|
|
98
101
|
else:
|
|
99
102
|
return {
|
|
100
103
|
"success": False,
|
|
101
|
-
"
|
|
104
|
+
"stdout": "",
|
|
105
|
+
"stderr": f"Unknown operation: {operation}"
|
|
102
106
|
}
|
|
103
107
|
|
|
104
108
|
except Exception as e:
|
|
105
109
|
PrettyOutput.print(str(e), OutputType.ERROR)
|
|
106
110
|
return {
|
|
107
111
|
"success": False,
|
|
108
|
-
"
|
|
112
|
+
"stdout": "",
|
|
113
|
+
"stderr": f"File operation failed: {str(e)}"
|
|
109
114
|
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
from typing import Dict, Any
|
|
2
|
+
|
|
3
|
+
from jarvis.agent import Agent
|
|
4
|
+
from jarvis.tools.registry import ToolRegistry
|
|
5
|
+
from jarvis.utils import OutputType, PrettyOutput
|
|
6
|
+
|
|
7
|
+
find_files_system_prompt = """You are a Find Files Agent specialized in searching and identifying relevant code files in a codebase. Your task is to find files that are most likely related to the given requirements or problems.
|
|
8
|
+
|
|
9
|
+
SEARCH WORKFLOW:
|
|
10
|
+
1. Understand Search Requirements
|
|
11
|
+
- Analyze the search query thoroughly
|
|
12
|
+
- Identify key technical terms and concepts
|
|
13
|
+
- Break down complex requirements into searchable terms
|
|
14
|
+
|
|
15
|
+
2. Execute Search Strategy
|
|
16
|
+
- Use shell commands to search systematically:
|
|
17
|
+
* Search for key terms:
|
|
18
|
+
<TOOL_CALL>
|
|
19
|
+
name: execute_shell
|
|
20
|
+
arguments:
|
|
21
|
+
command: grep -r "pattern" .
|
|
22
|
+
</TOOL_CALL>
|
|
23
|
+
* Find files by name patterns:
|
|
24
|
+
<TOOL_CALL>
|
|
25
|
+
name: execute_shell
|
|
26
|
+
arguments:
|
|
27
|
+
command: find . -name "pattern"
|
|
28
|
+
</TOOL_CALL>
|
|
29
|
+
* Examine file contents:
|
|
30
|
+
<TOOL_CALL>
|
|
31
|
+
name: execute_shell
|
|
32
|
+
arguments:
|
|
33
|
+
command: grep -A 5 -B 5 "pattern" file.py
|
|
34
|
+
</TOOL_CALL>
|
|
35
|
+
|
|
36
|
+
3. Analyze Results
|
|
37
|
+
- Review each potential file
|
|
38
|
+
- Check file relevance
|
|
39
|
+
- Examine file relationships
|
|
40
|
+
- Consider file dependencies
|
|
41
|
+
|
|
42
|
+
4. Generate File List
|
|
43
|
+
- List all relevant files
|
|
44
|
+
- Sort by relevance
|
|
45
|
+
- Include brief explanation for each file
|
|
46
|
+
- Format output as YAML
|
|
47
|
+
|
|
48
|
+
OUTPUT FORMAT:
|
|
49
|
+
files:
|
|
50
|
+
- path: path/to/file1
|
|
51
|
+
relevance: "Brief explanation of why this file is relevant"
|
|
52
|
+
- path: path/to/file2
|
|
53
|
+
relevance: "Brief explanation of why this file is relevant"
|
|
54
|
+
|
|
55
|
+
SEARCH BEST PRACTICES:
|
|
56
|
+
- Use multiple search terms
|
|
57
|
+
- Consider file naming conventions
|
|
58
|
+
- Check both file names and contents
|
|
59
|
+
- Look for related files (imports, dependencies)
|
|
60
|
+
- Use grep with context (-A, -B options)
|
|
61
|
+
- Search in specific directories when appropriate
|
|
62
|
+
- Exclude irrelevant directories (like .git, __pycache__)
|
|
63
|
+
|
|
64
|
+
IMPORTANT:
|
|
65
|
+
1. Focus on finding the most relevant files
|
|
66
|
+
2. Avoid listing irrelevant files
|
|
67
|
+
3. Explain relevance clearly but concisely
|
|
68
|
+
4. Consider both direct and indirect relevance
|
|
69
|
+
5. Use file content to confirm relevance
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
class FindFilesTool:
|
|
73
|
+
name = "find_files"
|
|
74
|
+
description = "Search and identify relevant code files in the codebase based on requirements or problems"
|
|
75
|
+
parameters = {
|
|
76
|
+
"type": "object",
|
|
77
|
+
"properties": {
|
|
78
|
+
"query": {
|
|
79
|
+
"type": "string",
|
|
80
|
+
"description": "The search query or requirement description"
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
"required": ["query"]
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
def execute(self, args: Dict) -> Dict[str, Any]:
|
|
87
|
+
"""Execute file search task"""
|
|
88
|
+
try:
|
|
89
|
+
query = args["query"]
|
|
90
|
+
|
|
91
|
+
PrettyOutput.print(f"Creating Find Files agent to search for: {query}", OutputType.INFO)
|
|
92
|
+
|
|
93
|
+
tool_registry = ToolRegistry()
|
|
94
|
+
tool_registry.use_tools(["ask_user", "execute_shell", "file_operation"])
|
|
95
|
+
|
|
96
|
+
# Create find files agent
|
|
97
|
+
find_agent = Agent(
|
|
98
|
+
system_prompt=find_files_system_prompt,
|
|
99
|
+
name="Find Files Agent",
|
|
100
|
+
is_sub_agent=True,
|
|
101
|
+
tool_registry=tool_registry
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
# Execute search
|
|
105
|
+
result = find_agent.run(query)
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
"success": True,
|
|
109
|
+
"stdout": result,
|
|
110
|
+
"stderr": ""
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
except Exception as e:
|
|
114
|
+
PrettyOutput.print(str(e), OutputType.ERROR)
|
|
115
|
+
return {
|
|
116
|
+
"success": False,
|
|
117
|
+
"stdout": "",
|
|
118
|
+
"stderr": f"Failed to execute file search: {str(e)}"
|
|
119
|
+
}
|
jarvis/tools/generate_tool.py
CHANGED
|
@@ -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
|
@@ -32,7 +32,7 @@ class MethodologyTool:
|
|
|
32
32
|
|
|
33
33
|
def __init__(self):
|
|
34
34
|
"""Initialize the experience management tool"""
|
|
35
|
-
self.methodology_file = os.path.expanduser("~/.
|
|
35
|
+
self.methodology_file = os.path.expanduser("~/.jarvis/methodology")
|
|
36
36
|
self._ensure_file_exists()
|
|
37
37
|
|
|
38
38
|
def _ensure_file_exists(self):
|
|
@@ -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()
|
|
@@ -97,14 +98,16 @@ class MethodologyTool:
|
|
|
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
|
|
@@ -113,19 +116,22 @@ class MethodologyTool:
|
|
|
113
116
|
action = "Update" if problem_type in methodologies else "Add"
|
|
114
117
|
return {
|
|
115
118
|
"success": True,
|
|
116
|
-
"stdout": f"{action} methodology for problem type '{problem_type}'"
|
|
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]:
|