jarvis-ai-assistant 0.1.131__py3-none-any.whl → 0.1.132__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.
- jarvis/__init__.py +1 -1
- jarvis/jarvis_agent/__init__.py +48 -29
- jarvis/jarvis_agent/patch.py +61 -43
- jarvis/jarvis_agent/shell_input_handler.py +1 -1
- jarvis/jarvis_code_agent/code_agent.py +87 -86
- jarvis/jarvis_dev/main.py +335 -626
- jarvis/jarvis_git_squash/main.py +10 -31
- jarvis/jarvis_multi_agent/__init__.py +19 -28
- jarvis/jarvis_platform/ai8.py +7 -32
- jarvis/jarvis_platform/base.py +2 -7
- jarvis/jarvis_platform/kimi.py +3 -144
- jarvis/jarvis_platform/ollama.py +54 -68
- jarvis/jarvis_platform/openai.py +0 -4
- jarvis/jarvis_platform/oyi.py +0 -75
- jarvis/jarvis_platform/yuanbao.py +264 -0
- jarvis/jarvis_rag/file_processors.py +138 -0
- jarvis/jarvis_rag/main.py +1305 -425
- jarvis/jarvis_tools/ask_codebase.py +205 -39
- jarvis/jarvis_tools/code_review.py +125 -99
- jarvis/jarvis_tools/execute_python_script.py +58 -0
- jarvis/jarvis_tools/execute_shell.py +13 -26
- jarvis/jarvis_tools/execute_shell_script.py +1 -1
- jarvis/jarvis_tools/file_analyzer.py +271 -0
- jarvis/jarvis_tools/file_operation.py +1 -1
- jarvis/jarvis_tools/find_caller.py +213 -0
- jarvis/jarvis_tools/find_symbol.py +211 -0
- jarvis/jarvis_tools/function_analyzer.py +248 -0
- jarvis/jarvis_tools/git_commiter.py +4 -4
- jarvis/jarvis_tools/methodology.py +89 -48
- jarvis/jarvis_tools/project_analyzer.py +220 -0
- jarvis/jarvis_tools/read_code.py +23 -2
- jarvis/jarvis_tools/read_webpage.py +195 -81
- jarvis/jarvis_tools/registry.py +132 -11
- jarvis/jarvis_tools/search_web.py +55 -10
- jarvis/jarvis_tools/tool_generator.py +6 -8
- jarvis/jarvis_utils/__init__.py +1 -0
- jarvis/jarvis_utils/config.py +67 -3
- jarvis/jarvis_utils/embedding.py +344 -45
- jarvis/jarvis_utils/git_utils.py +9 -1
- jarvis/jarvis_utils/input.py +7 -6
- jarvis/jarvis_utils/methodology.py +379 -7
- jarvis/jarvis_utils/output.py +5 -3
- jarvis/jarvis_utils/utils.py +59 -7
- {jarvis_ai_assistant-0.1.131.dist-info → jarvis_ai_assistant-0.1.132.dist-info}/METADATA +3 -2
- jarvis_ai_assistant-0.1.132.dist-info/RECORD +82 -0
- {jarvis_ai_assistant-0.1.131.dist-info → jarvis_ai_assistant-0.1.132.dist-info}/entry_points.txt +2 -0
- jarvis/jarvis_codebase/__init__.py +0 -0
- jarvis/jarvis_codebase/main.py +0 -1011
- jarvis/jarvis_tools/treesitter_analyzer.py +0 -331
- jarvis/jarvis_treesitter/README.md +0 -104
- jarvis/jarvis_treesitter/__init__.py +0 -20
- jarvis/jarvis_treesitter/database.py +0 -258
- jarvis/jarvis_treesitter/example.py +0 -115
- jarvis/jarvis_treesitter/grammar_builder.py +0 -182
- jarvis/jarvis_treesitter/language.py +0 -117
- jarvis/jarvis_treesitter/symbol.py +0 -31
- jarvis/jarvis_treesitter/tools_usage.md +0 -121
- jarvis_ai_assistant-0.1.131.dist-info/RECORD +0 -85
- {jarvis_ai_assistant-0.1.131.dist-info → jarvis_ai_assistant-0.1.132.dist-info}/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.131.dist-info → jarvis_ai_assistant-0.1.132.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.131.dist-info → jarvis_ai_assistant-0.1.132.dist-info}/top_level.txt +0 -0
|
@@ -1,28 +1,38 @@
|
|
|
1
1
|
from typing import Dict, Any
|
|
2
2
|
import os
|
|
3
|
+
import pathlib
|
|
3
4
|
|
|
4
|
-
from
|
|
5
|
-
|
|
6
|
-
from jarvis.
|
|
7
|
-
from jarvis.
|
|
5
|
+
from colorama import init
|
|
6
|
+
|
|
7
|
+
from jarvis.jarvis_agent import Agent
|
|
8
|
+
from jarvis.jarvis_platform.registry import PlatformRegistry
|
|
8
9
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
10
|
+
from jarvis.jarvis_utils.git_utils import find_git_root
|
|
11
|
+
from jarvis.jarvis_utils.config import dont_use_local_model
|
|
12
|
+
from jarvis.jarvis_utils.utils import init_env
|
|
9
13
|
|
|
10
14
|
class AskCodebaseTool:
|
|
11
|
-
"""用于智能代码库查询和分析的工具
|
|
15
|
+
"""用于智能代码库查询和分析的工具
|
|
16
|
+
|
|
17
|
+
适用场景:
|
|
18
|
+
- 查询特定功能所在的文件位置
|
|
19
|
+
- 了解单个功能点的实现原理
|
|
20
|
+
- 查找特定API或接口的用法
|
|
21
|
+
|
|
22
|
+
不适用场景:
|
|
23
|
+
- 跨越多文件的大范围分析
|
|
24
|
+
- 复杂系统架构的全面评估
|
|
25
|
+
- 需要深入上下文理解的代码重构
|
|
26
|
+
"""
|
|
12
27
|
|
|
13
28
|
name = "ask_codebase"
|
|
14
|
-
description = "
|
|
29
|
+
description = "查询代码库中特定功能的位置和实现原理,适合定位功能所在文件和理解单点实现,不适合跨文件大范围分析"
|
|
15
30
|
parameters = {
|
|
16
31
|
"type": "object",
|
|
17
32
|
"properties": {
|
|
18
33
|
"question": {
|
|
19
34
|
"type": "string",
|
|
20
|
-
"description": "
|
|
21
|
-
},
|
|
22
|
-
"top_k": {
|
|
23
|
-
"type": "integer",
|
|
24
|
-
"description": "要分析的最相关文件数量(可选)",
|
|
25
|
-
"default": 20
|
|
35
|
+
"description": "关于代码库的问题,例如'登录功能在哪个文件实现?'或'如何实现了JWT验证?'"
|
|
26
36
|
},
|
|
27
37
|
"root_dir": {
|
|
28
38
|
"type": "string",
|
|
@@ -38,22 +48,27 @@ class AskCodebaseTool:
|
|
|
38
48
|
return not dont_use_local_model()
|
|
39
49
|
|
|
40
50
|
def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
|
|
41
|
-
"""Execute codebase analysis using
|
|
51
|
+
"""Execute codebase analysis using an Agent with execute_shell and rag tools
|
|
42
52
|
|
|
43
53
|
Args:
|
|
44
54
|
args: Dictionary containing:
|
|
45
|
-
- question: The question to answer
|
|
55
|
+
- question: The question to answer, preferably about locating functionality
|
|
56
|
+
or understanding implementation details of a specific feature
|
|
46
57
|
- top_k: Optional number of files to analyze
|
|
58
|
+
- root_dir: Optional root directory of the codebase
|
|
47
59
|
|
|
48
60
|
Returns:
|
|
49
61
|
Dict containing:
|
|
50
62
|
- success: Boolean indicating success
|
|
51
63
|
- stdout: Analysis result
|
|
52
64
|
- stderr: Error message if any
|
|
65
|
+
|
|
66
|
+
Note:
|
|
67
|
+
This tool works best for focused questions about specific features or implementations.
|
|
68
|
+
It is not designed for comprehensive multi-file analysis or complex architectural questions.
|
|
53
69
|
"""
|
|
54
70
|
try:
|
|
55
71
|
question = args["question"]
|
|
56
|
-
top_k = args.get("top_k", 20)
|
|
57
72
|
root_dir = args.get("root_dir", ".")
|
|
58
73
|
|
|
59
74
|
# Store current directory
|
|
@@ -63,25 +78,43 @@ class AskCodebaseTool:
|
|
|
63
78
|
# Change to root_dir
|
|
64
79
|
os.chdir(root_dir)
|
|
65
80
|
|
|
66
|
-
#
|
|
67
|
-
git_root = find_git_root()
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
81
|
+
# Get git root directory
|
|
82
|
+
git_root = find_git_root() or os.getcwd()
|
|
83
|
+
|
|
84
|
+
# Create system prompt for the Agent
|
|
85
|
+
system_prompt = self._create_system_prompt(question, git_root)
|
|
86
|
+
|
|
87
|
+
# Create summary prompt for the Agent
|
|
88
|
+
summary_prompt = self._create_summary_prompt(question)
|
|
89
|
+
|
|
90
|
+
# Create tools registry
|
|
91
|
+
from jarvis.jarvis_tools.registry import ToolRegistry
|
|
92
|
+
tool_registry = ToolRegistry()
|
|
93
|
+
tool_registry.use_tools(["execute_shell", "read_code", "rag"])
|
|
94
|
+
|
|
95
|
+
# Create and run Agent
|
|
96
|
+
analyzer_agent = Agent(
|
|
97
|
+
system_prompt=system_prompt,
|
|
98
|
+
name=f"CodebaseAnalyzer",
|
|
99
|
+
description=f"分析代码库中的功能实现和定位",
|
|
100
|
+
summary_prompt=summary_prompt,
|
|
101
|
+
platform=PlatformRegistry().get_codegen_platform(),
|
|
102
|
+
output_handler=[tool_registry],
|
|
103
|
+
need_summary=True,
|
|
104
|
+
is_sub_agent=True,
|
|
105
|
+
use_methodology=False,
|
|
106
|
+
record_methodology=False,
|
|
107
|
+
execute_tool_confirm=False,
|
|
108
|
+
auto_complete=True
|
|
109
|
+
)
|
|
72
110
|
|
|
73
|
-
#
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
for file in files:
|
|
77
|
-
output += f"- {file['file']} ({file['reason']})\n"
|
|
78
|
-
PrettyOutput.print(output, OutputType.SUCCESS, lang="markdown")
|
|
79
|
-
|
|
80
|
-
PrettyOutput.print(response, OutputType.SUCCESS, lang="markdown")
|
|
111
|
+
# Run agent and get result
|
|
112
|
+
task_input = f"回答关于代码库的问题: {question}"
|
|
113
|
+
result = analyzer_agent.run(task_input)
|
|
81
114
|
|
|
82
115
|
return {
|
|
83
116
|
"success": True,
|
|
84
|
-
"stdout":
|
|
117
|
+
"stdout": result,
|
|
85
118
|
"stderr": ""
|
|
86
119
|
}
|
|
87
120
|
finally:
|
|
@@ -95,28 +128,161 @@ class AskCodebaseTool:
|
|
|
95
128
|
"stdout": "",
|
|
96
129
|
"stderr": error_msg
|
|
97
130
|
}
|
|
131
|
+
|
|
132
|
+
def _create_system_prompt(self, question: str, git_root: str) -> str:
|
|
133
|
+
"""创建Agent的system prompt
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
question: 用户问题
|
|
137
|
+
git_root: Git仓库根目录
|
|
138
|
+
|
|
139
|
+
Returns:
|
|
140
|
+
系统提示文本
|
|
141
|
+
"""
|
|
142
|
+
return f"""# 代码库分析专家
|
|
143
|
+
|
|
144
|
+
## 任务描述
|
|
145
|
+
分析代码库,找出与用户问题最相关的信息,提供准确、具体的回答。
|
|
146
|
+
|
|
147
|
+
## 问题信息
|
|
148
|
+
- 问题: {question}
|
|
149
|
+
- 代码库根目录: {git_root}
|
|
150
|
+
|
|
151
|
+
## 工具使用优先级
|
|
152
|
+
1. **优先使用 execute_shell**: 首先使用shell命令查找和分析相关文件
|
|
153
|
+
2. **优先使用 read_code**: 找到相关文件后优先使用read_code读取文件内容
|
|
154
|
+
3. **谨慎使用 rag**: 仅在shell命令和直接文件读取无法解决问题时作为辅助手段
|
|
155
|
+
|
|
156
|
+
## 分析策略
|
|
157
|
+
1. 首先理解问题,确定需要查找的关键信息和代码组件
|
|
158
|
+
2. 使用shell命令(execute_shell)搜索和查找可能相关的文件
|
|
159
|
+
3. 使用read_code工具直接读取和分析相关文件内容
|
|
160
|
+
4. 只有在必要时才使用RAG工具作为辅助手段
|
|
161
|
+
5. 根据文件内容提供具体、准确的回答
|
|
162
|
+
|
|
163
|
+
## 分析步骤
|
|
164
|
+
1. **探索代码库结构**:
|
|
165
|
+
- 使用shell命令了解目录结构,找出可能包含相关功能的位置
|
|
166
|
+
- 识别主要模块和组件
|
|
167
|
+
|
|
168
|
+
2. **定位相关文件**:
|
|
169
|
+
- 优先使用grep、find等shell命令查找关键词
|
|
170
|
+
- 使用文件名、关键词搜索找到潜在相关文件
|
|
171
|
+
|
|
172
|
+
3. **深入分析代码**:
|
|
173
|
+
- 使用read_code工具直接读取文件内容
|
|
174
|
+
- 分析关键文件的实现细节
|
|
175
|
+
- 识别功能的实现方式和关键逻辑
|
|
176
|
+
|
|
177
|
+
4. **回答问题**:
|
|
178
|
+
- 提供基于直接分析代码的具体回答
|
|
179
|
+
- 引用具体文件和代码片段作为依据
|
|
180
|
+
|
|
181
|
+
## 关于RAG工具使用
|
|
182
|
+
- RAG工具应作为最后选择,仅在shell命令和直接文件读取无法解决问题时使用
|
|
183
|
+
- RAG工具返回的信息可能存在偏差或不准确之处
|
|
184
|
+
- 必须通过查看实际代码文件验证RAG返回的每条重要信息
|
|
185
|
+
- 对于关键发现,始终使用`read_code`工具查看原始文件内容进行求证
|
|
186
|
+
- 如发现RAG结果与实际代码不符,以实际代码为准
|
|
187
|
+
|
|
188
|
+
## 探索命令示例
|
|
189
|
+
```bash
|
|
190
|
+
# 查看目录结构
|
|
191
|
+
find . -type d -not -path "*/\\.*" | sort
|
|
192
|
+
|
|
193
|
+
# 搜索与问题相关的文件
|
|
194
|
+
find . -type f -name "*.py" -o -name "*.js" | xargs grep -l "关键词"
|
|
195
|
+
grep -r "关键词" --include="*.py" .
|
|
196
|
+
|
|
197
|
+
# 查看文件内容
|
|
198
|
+
cat 文件路径
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
## 输出要求
|
|
203
|
+
- 提供准确、具体的回答,避免模糊不清的描述
|
|
204
|
+
- 引用具体文件路径和代码片段作为依据
|
|
205
|
+
- 如果无法找到答案,明确说明并提供原因
|
|
206
|
+
- 组织信息的逻辑清晰,便于理解
|
|
207
|
+
- 对复杂概念提供简明解释
|
|
208
|
+
- 明确区分已验证的信息和待验证的信息"""
|
|
209
|
+
|
|
210
|
+
def _create_summary_prompt(self, question: str) -> str:
|
|
211
|
+
"""创建Agent的summary prompt
|
|
212
|
+
|
|
213
|
+
Args:
|
|
214
|
+
question: 用户问题
|
|
215
|
+
|
|
216
|
+
Returns:
|
|
217
|
+
总结提示文本
|
|
218
|
+
"""
|
|
219
|
+
return f"""# 代码库分析报告
|
|
220
|
+
|
|
221
|
+
## 报告要求
|
|
222
|
+
生成关于以下问题的清晰、准确的分析报告:
|
|
223
|
+
|
|
224
|
+
**问题**: {question}
|
|
225
|
+
|
|
226
|
+
报告应包含:
|
|
227
|
+
|
|
228
|
+
1. **问题回答**:
|
|
229
|
+
- 直接、具体地回答问题
|
|
230
|
+
- 基于代码库中的实际代码
|
|
231
|
+
- 避免模糊或推测性的回答
|
|
232
|
+
|
|
233
|
+
2. **核心发现**:
|
|
234
|
+
- 相关文件和代码位置
|
|
235
|
+
- 关键实现细节
|
|
236
|
+
- 功能运作机制
|
|
237
|
+
|
|
238
|
+
3. **证据引用**:
|
|
239
|
+
- 引用具体文件路径
|
|
240
|
+
- 包含关键代码片段
|
|
241
|
+
- 解释代码如何支持你的回答
|
|
242
|
+
|
|
243
|
+
4. **局限性**(如有):
|
|
244
|
+
- 指出分析的任何局限
|
|
245
|
+
- 说明任何无法确定的信息
|
|
246
|
+
|
|
247
|
+
使用清晰的Markdown格式,重点突出对问题的回答和支持证据。"""
|
|
248
|
+
|
|
249
|
+
|
|
98
250
|
def main():
|
|
99
|
-
"""
|
|
251
|
+
"""
|
|
252
|
+
命令行入口点,允许将ask_codebase作为独立脚本运行
|
|
253
|
+
|
|
254
|
+
用法示例:
|
|
255
|
+
```
|
|
256
|
+
python -m jarvis.jarvis_tools.ask_codebase "登录功能在哪个文件实现?" --root_dir /path/to/codebase
|
|
257
|
+
```
|
|
258
|
+
"""
|
|
100
259
|
import argparse
|
|
260
|
+
import sys
|
|
261
|
+
|
|
262
|
+
init_env()
|
|
101
263
|
|
|
102
|
-
|
|
103
|
-
parser.
|
|
104
|
-
parser.add_argument(
|
|
105
|
-
parser.add_argument(
|
|
264
|
+
# 创建命令行参数解析器
|
|
265
|
+
parser = argparse.ArgumentParser(description="智能代码库查询工具")
|
|
266
|
+
parser.add_argument("question", help="关于代码库的问题")
|
|
267
|
+
parser.add_argument("--root_dir", "-d", default=".", help="代码库根目录路径")
|
|
106
268
|
|
|
269
|
+
# 解析命令行参数
|
|
107
270
|
args = parser.parse_args()
|
|
271
|
+
|
|
272
|
+
# 创建并执行工具
|
|
108
273
|
tool = AskCodebaseTool()
|
|
109
274
|
result = tool.execute({
|
|
110
275
|
"question": args.question,
|
|
111
|
-
"top_k": args.top_k,
|
|
112
276
|
"root_dir": args.root_dir
|
|
113
277
|
})
|
|
114
278
|
|
|
279
|
+
# 输出结果
|
|
115
280
|
if result["success"]:
|
|
116
|
-
PrettyOutput.print(result["stdout"], OutputType.
|
|
281
|
+
PrettyOutput.print(result["stdout"], OutputType.SUCCESS)
|
|
117
282
|
else:
|
|
118
283
|
PrettyOutput.print(result["stderr"], OutputType.WARNING)
|
|
119
|
-
|
|
284
|
+
sys.exit(1)
|
|
285
|
+
|
|
120
286
|
|
|
121
287
|
if __name__ == "__main__":
|
|
122
|
-
main()
|
|
288
|
+
main()
|
|
@@ -9,7 +9,7 @@ from jarvis.jarvis_agent import Agent
|
|
|
9
9
|
import re
|
|
10
10
|
|
|
11
11
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
12
|
-
from jarvis.jarvis_utils.utils import init_env
|
|
12
|
+
from jarvis.jarvis_utils.utils import ct, ot, init_env
|
|
13
13
|
|
|
14
14
|
class CodeReviewTool:
|
|
15
15
|
name = "code_review"
|
|
@@ -112,101 +112,120 @@ class CodeReviewTool:
|
|
|
112
112
|
spinner.text = "代码变更获取完成"
|
|
113
113
|
spinner.ok("✅")
|
|
114
114
|
|
|
115
|
-
system_prompt = """
|
|
115
|
+
system_prompt = """你是一位精益求精的首席代码审查专家,拥有多年企业级代码审计经验。你需要对所有代码变更进行极其全面、严谨且深入的审查,确保代码质量达到最高标准。
|
|
116
116
|
|
|
117
|
-
#
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
117
|
+
# 专家审查标准
|
|
118
|
+
1. 必须逐行分析每个修改文件,细致审查每一处变更,不遗漏任何细节
|
|
119
|
+
2. 基于坚实的证据识别问题,不做主观臆测,给出明确的问题定位和详细分析
|
|
120
|
+
3. 对每个问题提供完整可执行的解决方案,包括精确的改进代码
|
|
121
|
+
4. 确保报告条理清晰、层次分明,便于工程师快速采取行动
|
|
121
122
|
|
|
122
|
-
|
|
123
|
+
# 全面审查框架 (SCRIPPPS)
|
|
124
|
+
## S - 安全与风险 (Security & Risk)
|
|
125
|
+
- 发现所有潜在安全漏洞:注入攻击、授权缺陷、数据泄露风险
|
|
126
|
+
- 检查加密实现、密钥管理、敏感数据处理
|
|
127
|
+
- 审核权限验证逻辑、身份认证机制
|
|
128
|
+
- 检测OWASP Top 10安全风险和针对特定语言/框架的漏洞
|
|
123
129
|
|
|
124
|
-
|
|
130
|
+
## C - 正确性与完整性 (Correctness & Completeness)
|
|
131
|
+
- 验证业务逻辑和算法实现的准确性
|
|
132
|
+
- 全面检查条件边界、空值处理和异常情况
|
|
133
|
+
- 审核所有输入验证、参数校验和返回值处理
|
|
134
|
+
- 确保循环和递归的正确终止条件
|
|
135
|
+
- 严格检查线程安全和并发控制机制
|
|
125
136
|
|
|
126
|
-
|
|
127
|
-
|
|
137
|
+
## R - 可靠性与鲁棒性 (Reliability & Robustness)
|
|
138
|
+
- 评估代码在异常情况下的行为和恢复能力
|
|
139
|
+
- 审查错误处理、异常捕获和恢复策略
|
|
140
|
+
- 检查资源管理:内存、文件句柄、连接池、线程
|
|
141
|
+
- 评估容错设计和失败优雅降级机制
|
|
128
142
|
|
|
129
|
-
|
|
130
|
-
-
|
|
131
|
-
-
|
|
132
|
-
-
|
|
133
|
-
-
|
|
134
|
-
- 如果不确定,将其升级为严重-关键分类
|
|
143
|
+
## I - 接口与集成 (Interface & Integration)
|
|
144
|
+
- 检查API合约遵守情况和向后兼容性
|
|
145
|
+
- 审核与外部系统的集成点和交互逻辑
|
|
146
|
+
- 验证数据格式、序列化和协议实现
|
|
147
|
+
- 评估系统边界处理和跨服务通信安全性
|
|
135
148
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
- 检查未使用常量的魔法数字/字符串
|
|
142
|
-
- 验证所有循环退出条件
|
|
149
|
+
## P - 性能与效率 (Performance & Efficiency)
|
|
150
|
+
- 识别潜在性能瓶颈:CPU、内存、I/O、网络
|
|
151
|
+
- 审查数据结构选择和算法复杂度
|
|
152
|
+
- 检查资源密集型操作、数据库查询优化
|
|
153
|
+
- 评估缓存策略、批处理优化和并行处理机会
|
|
143
154
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
█ 分析异常处理是否存在信息泄露
|
|
155
|
+
## P - 可移植性与平台适配 (Portability & Platform Compatibility)
|
|
156
|
+
- 检查跨平台兼容性问题和依赖项管理
|
|
157
|
+
- 评估配置管理和环境适配设计
|
|
158
|
+
- 审核国际化和本地化支持
|
|
159
|
+
- 验证部署和运行时环境需求
|
|
150
160
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
161
|
+
## S - 结构与可维护性 (Structure & Maintainability)
|
|
162
|
+
- 评估代码组织、模块划分和架构符合性
|
|
163
|
+
- 审查代码重复、设计模式应用和抽象水平
|
|
164
|
+
- 检查命名规范、代码风格和项目约定
|
|
165
|
+
- 评估文档完整性、注释质量和代码可读性
|
|
156
166
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
167
|
+
# 问题严重程度分级
|
|
168
|
+
- 严重 (P0): 安全漏洞、数据丢失风险、系统崩溃、功能严重缺陷
|
|
169
|
+
- 高危 (P1): 显著性能问题、可能导致部分功能失效、系统不稳定
|
|
170
|
+
- 中等 (P2): 功能局部缺陷、次优设计、明显的技术债务
|
|
171
|
+
- 低危 (P3): 代码风格问题、轻微优化机会、文档改进建议
|
|
161
172
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
173
|
+
# 输出规范
|
|
174
|
+
针对每个文件的问题必须包含:
|
|
175
|
+
- 精确文件路径和问题影响范围
|
|
176
|
+
- 问题位置(起始行号-结束行号)
|
|
177
|
+
- 详尽问题描述,包括具体影响和潜在风险
|
|
178
|
+
- 严重程度分级(P0-P3)并说明理由
|
|
179
|
+
- 具体改进建议,提供完整、可执行的代码示例
|
|
166
180
|
|
|
167
|
-
|
|
168
|
-
1.
|
|
169
|
-
2.
|
|
170
|
-
3.
|
|
171
|
-
4.
|
|
172
|
-
5. 生成防回归检查表
|
|
181
|
+
所有审查发现必须:
|
|
182
|
+
1. 基于确凿的代码证据
|
|
183
|
+
2. 说明具体问题而非笼统评论
|
|
184
|
+
3. 提供清晰的技术原理分析
|
|
185
|
+
4. 给出完整的改进实施步骤"""
|
|
173
186
|
|
|
174
|
-
# 输出要求
|
|
175
|
-
!! 发现必须包括:
|
|
176
|
-
- 引起关注的确切代码片段
|
|
177
|
-
- 3种可能的故障场景
|
|
178
|
-
- 每种风险的最小复现案例
|
|
179
|
-
- 安全问题的CVSS 3.1评分估计
|
|
180
|
-
- 内存安全影响评估(Rust/C/C++上下文)
|
|
181
|
-
- 已考虑的替代实现方案
|
|
182
|
-
|
|
183
|
-
!! 格式:
|
|
184
|
-
紧急级别:[血红色/深红色/金菊色]
|
|
185
|
-
证据:
|
|
186
|
-
- 代码摘录:|
|
|
187
|
-
<受影响代码行>
|
|
188
|
-
- 风险场景:
|
|
189
|
-
1. <故障模式>
|
|
190
|
-
2. <故障模式>
|
|
191
|
-
3. <故障模式>
|
|
192
|
-
建议防御措施:
|
|
193
|
-
- <具体代码变更>
|
|
194
|
-
- <验证技术>
|
|
195
|
-
- <长期预防策略>
|
|
196
|
-
"""
|
|
197
187
|
tool_registry = ToolRegistry()
|
|
198
188
|
tool_registry.dont_use_tools(["code_review"])
|
|
199
189
|
agent = Agent(
|
|
200
190
|
system_prompt=system_prompt,
|
|
201
191
|
name="Code Review Agent",
|
|
202
|
-
summary_prompt="""
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
192
|
+
summary_prompt=f"""请生成一份专业级别的代码审查报告,对每处变更进行全面深入分析。将完整报告放在REPORT标签内,格式如下:
|
|
193
|
+
|
|
194
|
+
{ot("REPORT")}
|
|
195
|
+
# 整体评估
|
|
196
|
+
[提供对整体代码质量、架构和主要关注点的简明概述,总结主要发现]
|
|
197
|
+
|
|
198
|
+
# 详细问题清单
|
|
199
|
+
|
|
200
|
+
## 文件: [文件路径]
|
|
201
|
+
[如果该文件没有发现问题,则明确说明"未发现问题"]
|
|
202
|
+
|
|
203
|
+
### 问题 1
|
|
204
|
+
- **位置**: [起始行号-结束行号]
|
|
205
|
+
- **分类**: [使用SCRIPPPS框架中相关类别]
|
|
206
|
+
- **严重程度**: [P0/P1/P2/P3] - [简要说明判定理由]
|
|
207
|
+
- **问题描述**:
|
|
208
|
+
[详细描述问题,包括技术原理和潜在影响]
|
|
209
|
+
- **改进建议**:
|
|
210
|
+
```
|
|
211
|
+
[提供完整、可执行的代码示例,而非概念性建议]
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### 问题 2
|
|
215
|
+
...
|
|
216
|
+
|
|
217
|
+
## 文件: [文件路径2]
|
|
218
|
+
...
|
|
219
|
+
|
|
220
|
+
# 最佳实践建议
|
|
221
|
+
[提供适用于整个代码库的改进建议和最佳实践]
|
|
222
|
+
|
|
223
|
+
# 总结
|
|
224
|
+
[总结主要问题和优先处理建议]
|
|
225
|
+
{ct("REPORT")}
|
|
226
|
+
|
|
227
|
+
如果没有发现任何问题,请在REPORT标签内进行全面分析后明确说明"经过全面审查,未发现问题"并解释原因。
|
|
228
|
+
必须确保对所有修改的文件都进行了审查,并在报告中明确提及每个文件,即使某些文件没有发现问题。""",
|
|
210
229
|
is_sub_agent=True,
|
|
211
230
|
output_handler=[tool_registry],
|
|
212
231
|
platform=PlatformRegistry().get_thinking_platform(),
|
|
@@ -231,7 +250,7 @@ class CodeReviewTool:
|
|
|
231
250
|
|
|
232
251
|
|
|
233
252
|
def extract_code_report(result: str) -> str:
|
|
234
|
-
sm = re.search(
|
|
253
|
+
sm = re.search(ot("REPORT")+r'\n(.*?)\n'+ct("REPORT"), result, re.DOTALL)
|
|
235
254
|
if sm:
|
|
236
255
|
return sm.group(1)
|
|
237
256
|
return ""
|
|
@@ -243,35 +262,42 @@ def main():
|
|
|
243
262
|
init_env()
|
|
244
263
|
|
|
245
264
|
parser = argparse.ArgumentParser(description='Autonomous code review tool')
|
|
246
|
-
parser.
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
265
|
+
subparsers = parser.add_subparsers(dest='type')
|
|
266
|
+
|
|
267
|
+
# Commit subcommand
|
|
268
|
+
commit_parser = subparsers.add_parser('commit', help='Review specific commit')
|
|
269
|
+
commit_parser.add_argument('commit', help='Commit SHA to review')
|
|
270
|
+
|
|
271
|
+
# Current subcommand
|
|
272
|
+
current_parser = subparsers.add_parser('current', help='Review current changes')
|
|
273
|
+
|
|
274
|
+
# Range subcommand
|
|
275
|
+
range_parser = subparsers.add_parser('range', help='Review commit range')
|
|
276
|
+
range_parser.add_argument('start_commit', help='Start commit SHA')
|
|
277
|
+
range_parser.add_argument('end_commit', help='End commit SHA')
|
|
278
|
+
|
|
279
|
+
# File subcommand
|
|
280
|
+
file_parser = subparsers.add_parser('file', help='Review specific file')
|
|
281
|
+
file_parser.add_argument('file', help='File path to review')
|
|
282
|
+
|
|
283
|
+
# Common arguments
|
|
252
284
|
parser.add_argument('--root-dir', type=str, help='Root directory of the codebase', default=".")
|
|
253
|
-
args = parser.parse_args()
|
|
254
285
|
|
|
255
|
-
#
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
if args.type == 'range' and (not args.start_commit or not args.end_commit):
|
|
259
|
-
parser.error("--start-commit and --end-commit are required when type is 'range'")
|
|
260
|
-
if args.type == 'file' and not args.file:
|
|
261
|
-
parser.error("--file is required when type is 'file'")
|
|
286
|
+
# Set default subcommand to 'current'
|
|
287
|
+
parser.set_defaults(type='current')
|
|
288
|
+
args = parser.parse_args()
|
|
262
289
|
|
|
263
290
|
tool = CodeReviewTool()
|
|
264
291
|
tool_args = {
|
|
265
292
|
"review_type": args.type,
|
|
266
293
|
"root_dir": args.root_dir
|
|
267
294
|
}
|
|
268
|
-
if args.commit:
|
|
295
|
+
if args.type == 'commit':
|
|
269
296
|
tool_args["commit_sha"] = args.commit
|
|
270
|
-
|
|
297
|
+
elif args.type == 'range':
|
|
271
298
|
tool_args["start_commit"] = args.start_commit
|
|
272
|
-
if args.end_commit:
|
|
273
299
|
tool_args["end_commit"] = args.end_commit
|
|
274
|
-
|
|
300
|
+
elif args.type == 'file':
|
|
275
301
|
tool_args["file_path"] = args.file
|
|
276
302
|
|
|
277
303
|
result = tool.execute(tool_args)
|
|
@@ -279,7 +305,7 @@ def main():
|
|
|
279
305
|
if result["success"]:
|
|
280
306
|
PrettyOutput.section("自动代码审查结果:", OutputType.SUCCESS)
|
|
281
307
|
report = extract_code_report(result["stdout"])
|
|
282
|
-
PrettyOutput.print(report, OutputType.SUCCESS, lang="
|
|
308
|
+
PrettyOutput.print(report, OutputType.SUCCESS, lang="markdown")
|
|
283
309
|
|
|
284
310
|
else:
|
|
285
311
|
PrettyOutput.print(result["stderr"], OutputType.WARNING)
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
from typing import Dict, Any
|
|
2
|
+
import os
|
|
3
|
+
import tempfile
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class PythonScriptTool:
|
|
10
|
+
name = "execute_python_script"
|
|
11
|
+
description = "执行Python脚本文件并返回结果"
|
|
12
|
+
parameters = {
|
|
13
|
+
"type": "object",
|
|
14
|
+
"properties": {
|
|
15
|
+
"script_content": {
|
|
16
|
+
"type": "string",
|
|
17
|
+
"description": "要执行的Python脚本内容"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"required": ["script_content"]
|
|
21
|
+
}
|
|
22
|
+
def execute(self, args: Dict) -> Dict[str, Any]:
|
|
23
|
+
"""Execute Python script content"""
|
|
24
|
+
try:
|
|
25
|
+
script_content = args.get("script_content", "").strip()
|
|
26
|
+
if not script_content:
|
|
27
|
+
return {
|
|
28
|
+
"success": False,
|
|
29
|
+
"stdout": "",
|
|
30
|
+
"stderr": "Missing or empty script_content parameter"
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
# Create temporary script file
|
|
34
|
+
script_path = os.path.join(tempfile.gettempdir(), f"jarvis_script_{os.getpid()}.py")
|
|
35
|
+
try:
|
|
36
|
+
with open(script_path, 'w', encoding='utf-8', errors="ignore") as f:
|
|
37
|
+
f.write(script_content)
|
|
38
|
+
# Use execute_shell to run the script
|
|
39
|
+
from jarvis.jarvis_tools.execute_shell import ShellTool
|
|
40
|
+
shell_tool = ShellTool()
|
|
41
|
+
result = shell_tool.execute({"command": f"python3 {script_path}"})
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
"success": result["success"],
|
|
45
|
+
"stdout": result["stdout"],
|
|
46
|
+
"stderr": result["stderr"]
|
|
47
|
+
}
|
|
48
|
+
finally:
|
|
49
|
+
# Clean up temporary script file
|
|
50
|
+
Path(script_path).unlink(missing_ok=True)
|
|
51
|
+
|
|
52
|
+
except Exception as e:
|
|
53
|
+
PrettyOutput.print(str(e), OutputType.ERROR)
|
|
54
|
+
return {
|
|
55
|
+
"success": False,
|
|
56
|
+
"stdout": "",
|
|
57
|
+
"stderr": str(e)
|
|
58
|
+
}
|