jarvis-ai-assistant 0.1.134__py3-none-any.whl → 0.1.138__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/jarvis_agent/__init__.py +201 -79
- jarvis/jarvis_agent/builtin_input_handler.py +16 -6
- jarvis/jarvis_agent/file_input_handler.py +9 -9
- jarvis/jarvis_agent/jarvis.py +10 -10
- jarvis/jarvis_agent/main.py +12 -11
- jarvis/jarvis_agent/output_handler.py +3 -3
- jarvis/jarvis_agent/patch.py +86 -62
- jarvis/jarvis_agent/shell_input_handler.py +5 -3
- jarvis/jarvis_code_agent/code_agent.py +134 -99
- jarvis/jarvis_code_agent/file_select.py +24 -24
- jarvis/jarvis_dev/main.py +45 -51
- jarvis/jarvis_git_details/__init__.py +0 -0
- jarvis/jarvis_git_details/main.py +179 -0
- jarvis/jarvis_git_squash/main.py +7 -7
- jarvis/jarvis_lsp/base.py +11 -11
- jarvis/jarvis_lsp/cpp.py +14 -14
- jarvis/jarvis_lsp/go.py +13 -13
- jarvis/jarvis_lsp/python.py +8 -8
- jarvis/jarvis_lsp/registry.py +21 -21
- jarvis/jarvis_lsp/rust.py +15 -15
- jarvis/jarvis_methodology/main.py +101 -0
- jarvis/jarvis_multi_agent/__init__.py +11 -11
- jarvis/jarvis_multi_agent/main.py +6 -6
- jarvis/jarvis_platform/__init__.py +1 -1
- jarvis/jarvis_platform/ai8.py +67 -89
- jarvis/jarvis_platform/base.py +14 -13
- jarvis/jarvis_platform/kimi.py +25 -28
- jarvis/jarvis_platform/ollama.py +24 -26
- jarvis/jarvis_platform/openai.py +15 -19
- jarvis/jarvis_platform/oyi.py +48 -50
- jarvis/jarvis_platform/registry.py +27 -28
- jarvis/jarvis_platform/yuanbao.py +38 -42
- jarvis/jarvis_platform_manager/main.py +81 -81
- jarvis/jarvis_platform_manager/openai_test.py +21 -21
- jarvis/jarvis_rag/file_processors.py +18 -18
- jarvis/jarvis_rag/main.py +261 -277
- jarvis/jarvis_smart_shell/main.py +12 -12
- jarvis/jarvis_tools/ask_codebase.py +28 -28
- jarvis/jarvis_tools/ask_user.py +8 -8
- jarvis/jarvis_tools/base.py +4 -4
- jarvis/jarvis_tools/chdir.py +9 -9
- jarvis/jarvis_tools/code_review.py +19 -19
- jarvis/jarvis_tools/create_code_agent.py +15 -15
- jarvis/jarvis_tools/execute_python_script.py +3 -3
- jarvis/jarvis_tools/execute_shell.py +11 -11
- jarvis/jarvis_tools/execute_shell_script.py +3 -3
- jarvis/jarvis_tools/file_analyzer.py +29 -29
- jarvis/jarvis_tools/file_operation.py +22 -20
- jarvis/jarvis_tools/find_caller.py +25 -25
- jarvis/jarvis_tools/find_methodolopy.py +65 -0
- jarvis/jarvis_tools/find_symbol.py +24 -24
- jarvis/jarvis_tools/function_analyzer.py +27 -27
- jarvis/jarvis_tools/git_commiter.py +9 -9
- jarvis/jarvis_tools/lsp_get_diagnostics.py +19 -19
- jarvis/jarvis_tools/methodology.py +23 -62
- jarvis/jarvis_tools/project_analyzer.py +29 -33
- jarvis/jarvis_tools/rag.py +15 -15
- jarvis/jarvis_tools/read_code.py +24 -22
- jarvis/jarvis_tools/read_webpage.py +31 -31
- jarvis/jarvis_tools/registry.py +72 -52
- jarvis/jarvis_tools/tool_generator.py +18 -18
- jarvis/jarvis_utils/config.py +23 -23
- jarvis/jarvis_utils/embedding.py +83 -83
- jarvis/jarvis_utils/git_utils.py +20 -20
- jarvis/jarvis_utils/globals.py +18 -6
- jarvis/jarvis_utils/input.py +10 -9
- jarvis/jarvis_utils/methodology.py +140 -136
- jarvis/jarvis_utils/output.py +11 -11
- jarvis/jarvis_utils/utils.py +22 -70
- {jarvis_ai_assistant-0.1.134.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/METADATA +1 -1
- jarvis_ai_assistant-0.1.138.dist-info/RECORD +85 -0
- {jarvis_ai_assistant-0.1.134.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/entry_points.txt +2 -0
- jarvis/jarvis_tools/select_code_files.py +0 -62
- jarvis_ai_assistant-0.1.134.dist-info/RECORD +0 -82
- {jarvis_ai_assistant-0.1.134.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.134.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.134.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/top_level.txt +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# Shell command execution module
|
|
2
|
-
#
|
|
2
|
+
#
|
|
3
3
|
# Provides functionality to execute shell commands safely with:
|
|
4
4
|
# - Command escaping
|
|
5
5
|
# - Output capturing
|
|
@@ -12,7 +12,7 @@ from pathlib import Path
|
|
|
12
12
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
13
13
|
class ShellTool:
|
|
14
14
|
"""Shell command execution tool
|
|
15
|
-
|
|
15
|
+
|
|
16
16
|
Attributes:
|
|
17
17
|
name: Tool identifier used in API
|
|
18
18
|
description: Tool description for API documentation
|
|
@@ -32,10 +32,10 @@ class ShellTool:
|
|
|
32
32
|
}
|
|
33
33
|
def _escape_command(self, cmd: str) -> str:
|
|
34
34
|
"""Escape special characters in command to prevent shell injection
|
|
35
|
-
|
|
35
|
+
|
|
36
36
|
Args:
|
|
37
37
|
cmd: Raw command string
|
|
38
|
-
|
|
38
|
+
|
|
39
39
|
Returns:
|
|
40
40
|
Escaped command string with single quotes properly handled
|
|
41
41
|
"""
|
|
@@ -44,21 +44,21 @@ class ShellTool:
|
|
|
44
44
|
try:
|
|
45
45
|
# Get and clean command input
|
|
46
46
|
command = args["command"].strip()
|
|
47
|
-
|
|
47
|
+
|
|
48
48
|
# Generate temporary file name using process ID for uniqueness
|
|
49
49
|
script_file = os.path.join(tempfile.gettempdir(), f"jarvis_shell_{os.getpid()}.sh")
|
|
50
50
|
output_file = os.path.join(tempfile.gettempdir(), f"jarvis_shell_{os.getpid()}.log")
|
|
51
|
-
|
|
51
|
+
|
|
52
52
|
# Write command to script file
|
|
53
53
|
with open(script_file, 'w', encoding='utf-8') as f:
|
|
54
54
|
f.write(f"#!/bin/bash\n{command}")
|
|
55
|
-
|
|
55
|
+
|
|
56
56
|
# Use script command to capture both stdout and stderr
|
|
57
57
|
tee_command = f"script -q -c 'bash {script_file}' {output_file}"
|
|
58
|
-
|
|
58
|
+
|
|
59
59
|
# Execute command and capture return code
|
|
60
60
|
os.system(tee_command)
|
|
61
|
-
|
|
61
|
+
|
|
62
62
|
# Read and process output file
|
|
63
63
|
try:
|
|
64
64
|
with open(output_file, 'r', encoding='utf-8', errors='ignore') as f:
|
|
@@ -74,14 +74,14 @@ class ShellTool:
|
|
|
74
74
|
# Clean up temporary files
|
|
75
75
|
Path(script_file).unlink(missing_ok=True)
|
|
76
76
|
Path(output_file).unlink(missing_ok=True)
|
|
77
|
-
|
|
77
|
+
|
|
78
78
|
# Return successful result
|
|
79
79
|
return {
|
|
80
80
|
"success": True,
|
|
81
81
|
"stdout": output,
|
|
82
82
|
"stderr": "",
|
|
83
83
|
}
|
|
84
|
-
|
|
84
|
+
|
|
85
85
|
except Exception as e:
|
|
86
86
|
# Ensure temporary files are cleaned up even if error occurs
|
|
87
87
|
if 'script_file' in locals():
|
|
@@ -29,7 +29,7 @@ class ShellScriptTool:
|
|
|
29
29
|
"stdout": "",
|
|
30
30
|
"stderr": "Missing or empty script_content parameter"
|
|
31
31
|
}
|
|
32
|
-
|
|
32
|
+
|
|
33
33
|
# Create temporary script file
|
|
34
34
|
script_path = os.path.join(tempfile.gettempdir(), f"jarvis_shell_script_{os.getpid()}.sh")
|
|
35
35
|
try:
|
|
@@ -39,7 +39,7 @@ class ShellScriptTool:
|
|
|
39
39
|
from jarvis.jarvis_tools.execute_shell import ShellTool
|
|
40
40
|
shell_tool = ShellTool()
|
|
41
41
|
result = shell_tool.execute({"command": f"bash {script_path}"})
|
|
42
|
-
|
|
42
|
+
|
|
43
43
|
return {
|
|
44
44
|
"success": result["success"],
|
|
45
45
|
"stdout": result["stdout"],
|
|
@@ -48,7 +48,7 @@ class ShellScriptTool:
|
|
|
48
48
|
finally:
|
|
49
49
|
# Clean up temporary script file
|
|
50
50
|
Path(script_path).unlink(missing_ok=True)
|
|
51
|
-
|
|
51
|
+
|
|
52
52
|
except Exception as e:
|
|
53
53
|
PrettyOutput.print(str(e), OutputType.ERROR)
|
|
54
54
|
return {
|
|
@@ -12,7 +12,7 @@ class FileAnalyzerTool:
|
|
|
12
12
|
单文件分析工具
|
|
13
13
|
使用agent深入分析单个文件的结构、实现细节和代码质量
|
|
14
14
|
"""
|
|
15
|
-
|
|
15
|
+
|
|
16
16
|
name = "file_analyzer"
|
|
17
17
|
description = "深入分析单个文件的结构、实现细节和代码质量"
|
|
18
18
|
parameters = {
|
|
@@ -35,26 +35,26 @@ class FileAnalyzerTool:
|
|
|
35
35
|
},
|
|
36
36
|
"required": ["file_path"]
|
|
37
37
|
}
|
|
38
|
-
|
|
38
|
+
|
|
39
39
|
def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
|
|
40
40
|
"""
|
|
41
41
|
执行单文件分析工具
|
|
42
|
-
|
|
42
|
+
|
|
43
43
|
Args:
|
|
44
44
|
args: 包含参数的字典
|
|
45
|
-
|
|
45
|
+
|
|
46
46
|
Returns:
|
|
47
47
|
包含执行结果的字典
|
|
48
48
|
"""
|
|
49
49
|
# 存储原始目录
|
|
50
50
|
original_dir = os.getcwd()
|
|
51
|
-
|
|
51
|
+
|
|
52
52
|
try:
|
|
53
53
|
# 解析参数
|
|
54
54
|
file_path = args.get("file_path", "")
|
|
55
55
|
root_dir = args.get("root_dir", ".")
|
|
56
56
|
objective = args.get("objective", "")
|
|
57
|
-
|
|
57
|
+
|
|
58
58
|
# 验证参数
|
|
59
59
|
if not file_path:
|
|
60
60
|
return {
|
|
@@ -62,31 +62,31 @@ class FileAnalyzerTool:
|
|
|
62
62
|
"stdout": "",
|
|
63
63
|
"stderr": "必须提供文件路径"
|
|
64
64
|
}
|
|
65
|
-
|
|
65
|
+
|
|
66
66
|
# 确保文件路径是相对于root_dir的,如果是绝对路径则转换为相对路径
|
|
67
67
|
abs_file_path = os.path.abspath(file_path)
|
|
68
68
|
abs_root_dir = os.path.abspath(root_dir)
|
|
69
|
-
|
|
69
|
+
|
|
70
70
|
if abs_file_path.startswith(abs_root_dir):
|
|
71
71
|
rel_file_path = os.path.relpath(abs_file_path, abs_root_dir)
|
|
72
72
|
else:
|
|
73
73
|
rel_file_path = file_path
|
|
74
|
-
|
|
74
|
+
|
|
75
75
|
# 获取文件扩展名和文件名
|
|
76
76
|
file_ext = pathlib.Path(file_path).suffix
|
|
77
77
|
file_name = os.path.basename(file_path)
|
|
78
|
-
|
|
78
|
+
|
|
79
79
|
# 创建agent的system prompt
|
|
80
80
|
system_prompt = self._create_system_prompt(
|
|
81
81
|
rel_file_path, file_name, file_ext, root_dir, objective
|
|
82
82
|
)
|
|
83
|
-
|
|
83
|
+
|
|
84
84
|
# 创建agent的summary prompt
|
|
85
85
|
summary_prompt = self._create_summary_prompt(rel_file_path, file_name)
|
|
86
|
-
|
|
86
|
+
|
|
87
87
|
# 切换到根目录
|
|
88
88
|
os.chdir(root_dir)
|
|
89
|
-
|
|
89
|
+
|
|
90
90
|
# 检查文件是否存在
|
|
91
91
|
if not os.path.isfile(rel_file_path):
|
|
92
92
|
return {
|
|
@@ -94,18 +94,18 @@ class FileAnalyzerTool:
|
|
|
94
94
|
"stdout": "",
|
|
95
95
|
"stderr": f"文件不存在: {rel_file_path}"
|
|
96
96
|
}
|
|
97
|
-
|
|
97
|
+
|
|
98
98
|
# 构建使用的工具
|
|
99
99
|
from jarvis.jarvis_tools.registry import ToolRegistry
|
|
100
100
|
tool_registry = ToolRegistry()
|
|
101
101
|
tool_registry.use_tools([
|
|
102
|
-
"execute_shell",
|
|
103
|
-
"read_code",
|
|
102
|
+
"execute_shell",
|
|
103
|
+
"read_code",
|
|
104
104
|
"find_symbol",
|
|
105
|
-
"function_analyzer",
|
|
105
|
+
"function_analyzer",
|
|
106
106
|
"find_caller"
|
|
107
107
|
])
|
|
108
|
-
|
|
108
|
+
|
|
109
109
|
# 创建并运行agent
|
|
110
110
|
analyzer_agent = Agent(
|
|
111
111
|
system_prompt=system_prompt,
|
|
@@ -117,17 +117,17 @@ class FileAnalyzerTool:
|
|
|
117
117
|
execute_tool_confirm=False,
|
|
118
118
|
auto_complete=True
|
|
119
119
|
)
|
|
120
|
-
|
|
120
|
+
|
|
121
121
|
# 运行agent并获取结果
|
|
122
122
|
task_input = f"深入分析文件 {rel_file_path} 的结构、实现细节和代码质量"
|
|
123
123
|
result = analyzer_agent.run(task_input)
|
|
124
|
-
|
|
124
|
+
|
|
125
125
|
return {
|
|
126
126
|
"success": True,
|
|
127
127
|
"stdout": result,
|
|
128
128
|
"stderr": ""
|
|
129
129
|
}
|
|
130
|
-
|
|
130
|
+
|
|
131
131
|
except Exception as e:
|
|
132
132
|
PrettyOutput.print(str(e), OutputType.ERROR)
|
|
133
133
|
return {
|
|
@@ -138,24 +138,24 @@ class FileAnalyzerTool:
|
|
|
138
138
|
finally:
|
|
139
139
|
# 恢复原始目录
|
|
140
140
|
os.chdir(original_dir)
|
|
141
|
-
|
|
141
|
+
|
|
142
142
|
def _create_system_prompt(self, file_path: str, file_name: str, file_ext: str,
|
|
143
143
|
root_dir: str, objective: str) -> str:
|
|
144
144
|
"""
|
|
145
145
|
创建Agent的system prompt
|
|
146
|
-
|
|
146
|
+
|
|
147
147
|
Args:
|
|
148
148
|
file_path: 文件路径
|
|
149
149
|
file_name: 文件名
|
|
150
150
|
file_ext: 文件扩展名
|
|
151
151
|
root_dir: 代码库根目录
|
|
152
152
|
objective: 分析目标
|
|
153
|
-
|
|
153
|
+
|
|
154
154
|
Returns:
|
|
155
155
|
系统提示文本
|
|
156
156
|
"""
|
|
157
157
|
objective_text = f"\n\n## 分析目标\n{objective}" if objective else ""
|
|
158
|
-
|
|
158
|
+
|
|
159
159
|
return f"""# 文件分析专家
|
|
160
160
|
|
|
161
161
|
## 任务描述
|
|
@@ -164,7 +164,7 @@ class FileAnalyzerTool:
|
|
|
164
164
|
## 工具使用优先级
|
|
165
165
|
1. **优先使用 read_code**: 直接读取文件内容是分析文件的首选方式
|
|
166
166
|
2. **优先使用 execute_shell**:
|
|
167
|
-
- 使用 rg 搜索文件内容: `rg "pattern" {file_path}`
|
|
167
|
+
- 使用 rg 搜索文件内容: `rg "pattern" {file_path}`
|
|
168
168
|
- 使用 loc 统计代码: `loc {file_path}`
|
|
169
169
|
3. **仅在必要时使用其他分析工具**
|
|
170
170
|
|
|
@@ -259,11 +259,11 @@ class FileAnalyzerTool:
|
|
|
259
259
|
def _create_summary_prompt(self, file_path: str, file_name: str) -> str:
|
|
260
260
|
"""
|
|
261
261
|
创建Agent的summary prompt
|
|
262
|
-
|
|
262
|
+
|
|
263
263
|
Args:
|
|
264
264
|
file_path: 文件路径
|
|
265
265
|
file_name: 文件名
|
|
266
|
-
|
|
266
|
+
|
|
267
267
|
Returns:
|
|
268
268
|
总结提示文本
|
|
269
269
|
"""
|
|
@@ -279,4 +279,4 @@ class FileAnalyzerTool:
|
|
|
279
279
|
- 使用具体的代码片段和实例支持你的观点
|
|
280
280
|
- 以清晰的Markdown格式呈现,简洁明了
|
|
281
281
|
|
|
282
|
-
在分析中保持灵活性,避免固定思维模式。你的任务不是提供全面的文件概览,而是直接解决分析目标中提出的具体问题。"""
|
|
282
|
+
在分析中保持灵活性,避免固定思维模式。你的任务不是提供全面的文件概览,而是直接解决分析目标中提出的具体问题。"""
|
|
@@ -3,6 +3,7 @@ import os
|
|
|
3
3
|
|
|
4
4
|
from yaspin import yaspin
|
|
5
5
|
|
|
6
|
+
from jarvis.jarvis_utils.globals import add_read_file_record
|
|
6
7
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
7
8
|
|
|
8
9
|
|
|
@@ -34,11 +35,12 @@ class FileOperationTool:
|
|
|
34
35
|
"required": ["operation", "files"]
|
|
35
36
|
}
|
|
36
37
|
|
|
37
|
-
def _handle_single_file(self, operation: str, filepath: str, content: str = "",
|
|
38
|
+
def _handle_single_file(self, operation: str, filepath: str, content: str = "",
|
|
38
39
|
start_line: int = 1, end_line: int = -1) -> Dict[str, Any]:
|
|
39
40
|
"""Handle operations for a single file"""
|
|
40
41
|
try:
|
|
41
42
|
abs_path = os.path.abspath(filepath)
|
|
43
|
+
add_read_file_record(abs_path)
|
|
42
44
|
if operation == "read":
|
|
43
45
|
with yaspin(text=f"正在读取文件: {abs_path}...", color="cyan") as spinner:
|
|
44
46
|
if not os.path.exists(abs_path):
|
|
@@ -47,18 +49,18 @@ class FileOperationTool:
|
|
|
47
49
|
"stdout": "",
|
|
48
50
|
"stderr": f"文件不存在: {abs_path}"
|
|
49
51
|
}
|
|
50
|
-
|
|
52
|
+
|
|
51
53
|
if os.path.getsize(abs_path) > 10 * 1024 * 1024: # 10MB
|
|
52
54
|
return {
|
|
53
55
|
"success": False,
|
|
54
56
|
"stdout": "",
|
|
55
57
|
"stderr": "File too large (>10MB)"
|
|
56
58
|
}
|
|
57
|
-
|
|
59
|
+
|
|
58
60
|
with open(abs_path, 'r', encoding='utf-8', errors="ignore") as f:
|
|
59
61
|
lines = f.readlines()
|
|
60
|
-
|
|
61
|
-
|
|
62
|
+
|
|
63
|
+
|
|
62
64
|
total_lines = len(lines)
|
|
63
65
|
start_line = start_line if start_line >= 0 else total_lines + start_line + 1
|
|
64
66
|
end_line = end_line if end_line >= 0 else total_lines + end_line + 1
|
|
@@ -66,7 +68,7 @@ class FileOperationTool:
|
|
|
66
68
|
end_line = max(1, min(end_line, total_lines))
|
|
67
69
|
if end_line == -1:
|
|
68
70
|
end_line = total_lines
|
|
69
|
-
|
|
71
|
+
|
|
70
72
|
if start_line > end_line:
|
|
71
73
|
spinner.text = "无效的行范围"
|
|
72
74
|
spinner.fail("❌")
|
|
@@ -76,10 +78,10 @@ class FileOperationTool:
|
|
|
76
78
|
"stdout": "",
|
|
77
79
|
"stderr": error_msg
|
|
78
80
|
}
|
|
79
|
-
|
|
81
|
+
|
|
80
82
|
content = "".join(lines[start_line - 1:end_line])
|
|
81
|
-
output = f"\n文件: {abs_path}\n行: [{start_line}-{end_line}]\n{content}" + "\n\n"
|
|
82
|
-
|
|
83
|
+
output = f"\n文件: {abs_path}\n行: [{start_line}-{end_line}]\n{content}" + "\n\n"
|
|
84
|
+
|
|
83
85
|
spinner.text = f"文件读取完成: {abs_path}"
|
|
84
86
|
spinner.ok("✅")
|
|
85
87
|
return {
|
|
@@ -104,7 +106,7 @@ class FileOperationTool:
|
|
|
104
106
|
"stdout": "",
|
|
105
107
|
"stderr": f"Unknown operation: {operation}"
|
|
106
108
|
}
|
|
107
|
-
|
|
109
|
+
|
|
108
110
|
except Exception as e:
|
|
109
111
|
PrettyOutput.print(str(e), OutputType.ERROR)
|
|
110
112
|
return {
|
|
@@ -115,10 +117,10 @@ class FileOperationTool:
|
|
|
115
117
|
|
|
116
118
|
def execute(self, args: Dict) -> Dict[str, Any]:
|
|
117
119
|
"""Execute file operations for multiple files
|
|
118
|
-
|
|
120
|
+
|
|
119
121
|
Args:
|
|
120
122
|
args: Dictionary containing operation and files list
|
|
121
|
-
|
|
123
|
+
|
|
122
124
|
Returns:
|
|
123
125
|
Dict containing:
|
|
124
126
|
- success: Boolean indicating overall success
|
|
@@ -127,21 +129,21 @@ class FileOperationTool:
|
|
|
127
129
|
"""
|
|
128
130
|
try:
|
|
129
131
|
operation = args["operation"].strip()
|
|
130
|
-
|
|
132
|
+
|
|
131
133
|
if "files" not in args or not isinstance(args["files"], list):
|
|
132
134
|
return {
|
|
133
135
|
"success": False,
|
|
134
136
|
"stdout": "",
|
|
135
137
|
"stderr": "files parameter is required and must be a list"
|
|
136
138
|
}
|
|
137
|
-
|
|
139
|
+
|
|
138
140
|
all_outputs = []
|
|
139
141
|
success = True
|
|
140
|
-
|
|
142
|
+
|
|
141
143
|
for file_info in args["files"]:
|
|
142
144
|
if not isinstance(file_info, dict) or "path" not in file_info:
|
|
143
145
|
continue
|
|
144
|
-
|
|
146
|
+
|
|
145
147
|
content = file_info.get("content", "") if operation == "write" else ""
|
|
146
148
|
result = self._handle_single_file(
|
|
147
149
|
operation,
|
|
@@ -150,22 +152,22 @@ class FileOperationTool:
|
|
|
150
152
|
file_info.get("start_line", 1),
|
|
151
153
|
file_info.get("end_line", -1)
|
|
152
154
|
)
|
|
153
|
-
|
|
155
|
+
|
|
154
156
|
if result["success"]:
|
|
155
157
|
all_outputs.append(result["stdout"])
|
|
156
158
|
else:
|
|
157
159
|
all_outputs.append(f"Error with {file_info['path']}: {result['stderr']}")
|
|
158
160
|
success = success and result["success"]
|
|
159
|
-
|
|
161
|
+
|
|
160
162
|
# Combine all outputs with separators
|
|
161
163
|
combined_output = "\n\n" + "="*80 + "\n\n".join(all_outputs)
|
|
162
|
-
|
|
164
|
+
|
|
163
165
|
return {
|
|
164
166
|
"success": success,
|
|
165
167
|
"stdout": combined_output,
|
|
166
168
|
"stderr": ""
|
|
167
169
|
}
|
|
168
|
-
|
|
170
|
+
|
|
169
171
|
except Exception as e:
|
|
170
172
|
PrettyOutput.print(str(e), OutputType.ERROR)
|
|
171
173
|
return {
|
|
@@ -11,7 +11,7 @@ class FindCallerTool:
|
|
|
11
11
|
函数调用者查找工具
|
|
12
12
|
使用agent查找代码库中所有调用指定函数的位置
|
|
13
13
|
"""
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
name = "find_caller"
|
|
16
16
|
description = "查找所有调用指定函数的代码位置"
|
|
17
17
|
parameters = {
|
|
@@ -50,20 +50,20 @@ class FindCallerTool:
|
|
|
50
50
|
},
|
|
51
51
|
"required": ["function_name"]
|
|
52
52
|
}
|
|
53
|
-
|
|
53
|
+
|
|
54
54
|
def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
|
|
55
55
|
"""
|
|
56
56
|
执行调用者查找工具
|
|
57
|
-
|
|
57
|
+
|
|
58
58
|
Args:
|
|
59
59
|
args: 包含参数的字典
|
|
60
|
-
|
|
60
|
+
|
|
61
61
|
Returns:
|
|
62
62
|
包含执行结果的字典
|
|
63
63
|
"""
|
|
64
64
|
# 存储原始目录
|
|
65
65
|
original_dir = os.getcwd()
|
|
66
|
-
|
|
66
|
+
|
|
67
67
|
try:
|
|
68
68
|
# 解析参数
|
|
69
69
|
function_name = args.get("function_name", "")
|
|
@@ -71,7 +71,7 @@ class FindCallerTool:
|
|
|
71
71
|
file_extensions = args.get("file_extensions", [])
|
|
72
72
|
exclude_dirs = args.get("exclude_dirs", [])
|
|
73
73
|
objective = args.get("objective", "")
|
|
74
|
-
|
|
74
|
+
|
|
75
75
|
# 验证参数
|
|
76
76
|
if not function_name:
|
|
77
77
|
return {
|
|
@@ -79,23 +79,23 @@ class FindCallerTool:
|
|
|
79
79
|
"stdout": "",
|
|
80
80
|
"stderr": "必须提供函数名称"
|
|
81
81
|
}
|
|
82
|
-
|
|
82
|
+
|
|
83
83
|
# 创建agent的system prompt
|
|
84
84
|
system_prompt = self._create_system_prompt(
|
|
85
85
|
function_name, root_dir, file_extensions, exclude_dirs, objective
|
|
86
86
|
)
|
|
87
|
-
|
|
87
|
+
|
|
88
88
|
# 创建agent的summary prompt
|
|
89
89
|
summary_prompt = self._create_summary_prompt(function_name)
|
|
90
|
-
|
|
90
|
+
|
|
91
91
|
# 切换到根目录
|
|
92
92
|
os.chdir(root_dir)
|
|
93
|
-
|
|
93
|
+
|
|
94
94
|
# 构建使用的工具
|
|
95
95
|
from jarvis.jarvis_tools.registry import ToolRegistry
|
|
96
96
|
tool_registry = ToolRegistry()
|
|
97
97
|
tool_registry.use_tools(["execute_shell", "read_code"])
|
|
98
|
-
|
|
98
|
+
|
|
99
99
|
# 创建并运行agent
|
|
100
100
|
caller_agent = Agent(
|
|
101
101
|
system_prompt=system_prompt,
|
|
@@ -107,17 +107,17 @@ class FindCallerTool:
|
|
|
107
107
|
execute_tool_confirm=False,
|
|
108
108
|
auto_complete=True
|
|
109
109
|
)
|
|
110
|
-
|
|
110
|
+
|
|
111
111
|
# 运行agent并获取结果
|
|
112
112
|
task_input = f"查找所有调用 '{function_name}' 函数的代码位置"
|
|
113
113
|
result = caller_agent.run(task_input)
|
|
114
|
-
|
|
114
|
+
|
|
115
115
|
return {
|
|
116
116
|
"success": True,
|
|
117
117
|
"stdout": result,
|
|
118
118
|
"stderr": ""
|
|
119
119
|
}
|
|
120
|
-
|
|
120
|
+
|
|
121
121
|
except Exception as e:
|
|
122
122
|
PrettyOutput.print(str(e), OutputType.ERROR)
|
|
123
123
|
return {
|
|
@@ -128,41 +128,41 @@ class FindCallerTool:
|
|
|
128
128
|
finally:
|
|
129
129
|
# 恢复原始目录
|
|
130
130
|
os.chdir(original_dir)
|
|
131
|
-
|
|
132
|
-
def _create_system_prompt(self, function_name: str, root_dir: str,
|
|
131
|
+
|
|
132
|
+
def _create_system_prompt(self, function_name: str, root_dir: str,
|
|
133
133
|
file_extensions: List[str], exclude_dirs: List[str],
|
|
134
134
|
objective: str) -> str:
|
|
135
135
|
"""
|
|
136
136
|
创建Agent的system prompt
|
|
137
|
-
|
|
137
|
+
|
|
138
138
|
Args:
|
|
139
139
|
function_name: 函数名称
|
|
140
140
|
root_dir: 代码库根目录
|
|
141
141
|
file_extensions: 文件扩展名列表
|
|
142
142
|
exclude_dirs: 排除目录列表
|
|
143
143
|
objective: 分析目标
|
|
144
|
-
|
|
144
|
+
|
|
145
145
|
Returns:
|
|
146
146
|
系统提示文本
|
|
147
147
|
"""
|
|
148
148
|
file_ext_str = " ".join([f"*{ext}" for ext in file_extensions]) if file_extensions else ""
|
|
149
149
|
exclude_str = " ".join([f"--glob '!{excl}'" for excl in exclude_dirs]) if exclude_dirs else ""
|
|
150
150
|
objective_text = f"\n\n## 分析目标\n{objective}" if objective else ""
|
|
151
|
-
|
|
151
|
+
|
|
152
152
|
search_pattern = f"\\b{function_name}\\s*\\("
|
|
153
|
-
|
|
153
|
+
|
|
154
154
|
return f"""# 函数调用分析专家
|
|
155
155
|
|
|
156
156
|
## 任务描述
|
|
157
157
|
查找所有调用 `{function_name}` 函数的代码位置,专注于分析目标所需的信息,生成有针对性的调用分析报告。{objective_text}
|
|
158
158
|
|
|
159
159
|
## 工具使用优先级
|
|
160
|
-
1. **优先使用 execute_shell 执行 rg 命令**:
|
|
160
|
+
1. **优先使用 execute_shell 执行 rg 命令**:
|
|
161
161
|
- `rg "\\b{function_name}\\s*\\(" --type py` 查找Python文件中的调用
|
|
162
162
|
- `rg "\\b{function_name}\\s*\\(" --type js` 查找JavaScript文件中的调用
|
|
163
163
|
- `rg -w "{function_name}" -A 2 -B 2` 查看调用上下文
|
|
164
164
|
|
|
165
|
-
2. **辅以 read_code**:
|
|
165
|
+
2. **辅以 read_code**:
|
|
166
166
|
- 找到调用位置后使用read_code阅读上下文
|
|
167
167
|
- 读取关键调用者的完整实现
|
|
168
168
|
|
|
@@ -185,7 +185,7 @@ class FindCallerTool:
|
|
|
185
185
|
## 调用者查找工具指南
|
|
186
186
|
|
|
187
187
|
### execute_shell 搜索命令
|
|
188
|
-
- **基本搜索**:
|
|
188
|
+
- **基本搜索**:
|
|
189
189
|
- `rg "\\b{function_name}\\s*\\(" --type=文件类型`
|
|
190
190
|
- 示例: `rg "\\b{function_name}\\s*\\(" --type py` 搜索Python文件中的调用
|
|
191
191
|
|
|
@@ -255,10 +255,10 @@ class FindCallerTool:
|
|
|
255
255
|
def _create_summary_prompt(self, function_name: str) -> str:
|
|
256
256
|
"""
|
|
257
257
|
创建Agent的summary prompt
|
|
258
|
-
|
|
258
|
+
|
|
259
259
|
Args:
|
|
260
260
|
function_name: 函数名称
|
|
261
|
-
|
|
261
|
+
|
|
262
262
|
Returns:
|
|
263
263
|
总结提示文本
|
|
264
264
|
"""
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
from typing import Dict, Any
|
|
2
|
+
from yaspin import yaspin
|
|
3
|
+
|
|
4
|
+
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
5
|
+
from jarvis.jarvis_utils.methodology import load_methodology
|
|
6
|
+
|
|
7
|
+
class FindMethodologyTool:
|
|
8
|
+
name = "find_methodology"
|
|
9
|
+
description = "方法论查找工具,用于在执行过程中查看历史方法论辅助决策"
|
|
10
|
+
parameters = {
|
|
11
|
+
"type": "object",
|
|
12
|
+
"properties": {
|
|
13
|
+
"query": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"description": "要搜索的查询文本"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"required": ["query"]
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
def execute(self, args: Dict) -> Dict[str, Any]:
|
|
22
|
+
"""执行方法论查找操作
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
args (Dict): 包含查询文本的参数字典
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
Dict[str, Any]: 包含成功状态、输出内容和错误信息的字典
|
|
29
|
+
"""
|
|
30
|
+
try:
|
|
31
|
+
if "query" not in args:
|
|
32
|
+
return {
|
|
33
|
+
"success": False,
|
|
34
|
+
"stdout": "",
|
|
35
|
+
"stderr": "参数中必须包含查询文本"
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
with yaspin(text="搜索相关方法论...", color="cyan") as spinner:
|
|
39
|
+
methodology_prompt = load_methodology(args["query"])
|
|
40
|
+
|
|
41
|
+
if methodology_prompt:
|
|
42
|
+
spinner.text = "找到相关方法论"
|
|
43
|
+
spinner.ok("✅")
|
|
44
|
+
PrettyOutput.print(methodology_prompt, OutputType.INFO)
|
|
45
|
+
return {
|
|
46
|
+
"success": True,
|
|
47
|
+
"stdout": methodology_prompt,
|
|
48
|
+
"stderr": ""
|
|
49
|
+
}
|
|
50
|
+
else:
|
|
51
|
+
spinner.text = "未找到相关方法论"
|
|
52
|
+
spinner.fail("❌")
|
|
53
|
+
return {
|
|
54
|
+
"success": True,
|
|
55
|
+
"stdout": "未找到相关的方法论",
|
|
56
|
+
"stderr": ""
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
except Exception as e:
|
|
60
|
+
PrettyOutput.print(str(e), OutputType.ERROR)
|
|
61
|
+
return {
|
|
62
|
+
"success": False,
|
|
63
|
+
"stdout": "",
|
|
64
|
+
"stderr": f"方法论查找失败: {str(e)}"
|
|
65
|
+
}
|