jarvis-ai-assistant 0.1.138__py3-none-any.whl → 0.1.141__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 +62 -14
- jarvis/jarvis_agent/builtin_input_handler.py +4 -14
- jarvis/jarvis_agent/main.py +1 -1
- jarvis/jarvis_agent/patch.py +37 -40
- jarvis/jarvis_agent/shell_input_handler.py +2 -3
- jarvis/jarvis_code_agent/code_agent.py +23 -30
- jarvis/jarvis_code_analysis/checklists/__init__.py +3 -0
- jarvis/jarvis_code_analysis/checklists/c_cpp.py +50 -0
- jarvis/jarvis_code_analysis/checklists/csharp.py +75 -0
- jarvis/jarvis_code_analysis/checklists/data_format.py +82 -0
- jarvis/jarvis_code_analysis/checklists/devops.py +107 -0
- jarvis/jarvis_code_analysis/checklists/docs.py +87 -0
- jarvis/jarvis_code_analysis/checklists/go.py +52 -0
- jarvis/jarvis_code_analysis/checklists/infrastructure.py +98 -0
- jarvis/jarvis_code_analysis/checklists/java.py +66 -0
- jarvis/jarvis_code_analysis/checklists/javascript.py +73 -0
- jarvis/jarvis_code_analysis/checklists/kotlin.py +107 -0
- jarvis/jarvis_code_analysis/checklists/loader.py +76 -0
- jarvis/jarvis_code_analysis/checklists/php.py +77 -0
- jarvis/jarvis_code_analysis/checklists/python.py +56 -0
- jarvis/jarvis_code_analysis/checklists/ruby.py +107 -0
- jarvis/jarvis_code_analysis/checklists/rust.py +58 -0
- jarvis/jarvis_code_analysis/checklists/shell.py +75 -0
- jarvis/jarvis_code_analysis/checklists/sql.py +72 -0
- jarvis/jarvis_code_analysis/checklists/swift.py +77 -0
- jarvis/jarvis_code_analysis/checklists/web.py +97 -0
- jarvis/jarvis_code_analysis/code_review.py +660 -0
- jarvis/jarvis_dev/main.py +61 -88
- jarvis/jarvis_git_squash/main.py +3 -3
- jarvis/jarvis_git_utils/git_commiter.py +242 -0
- jarvis/jarvis_init/main.py +62 -0
- jarvis/jarvis_platform/base.py +4 -0
- jarvis/jarvis_platform/kimi.py +173 -5
- jarvis/jarvis_platform/openai.py +3 -0
- jarvis/jarvis_platform/registry.py +1 -0
- jarvis/jarvis_platform/yuanbao.py +275 -5
- jarvis/jarvis_tools/ask_codebase.py +6 -9
- jarvis/jarvis_tools/ask_user.py +17 -5
- jarvis/jarvis_tools/base.py +3 -1
- jarvis/jarvis_tools/chdir.py +1 -0
- jarvis/jarvis_tools/create_code_agent.py +4 -3
- jarvis/jarvis_tools/create_sub_agent.py +1 -0
- jarvis/jarvis_tools/execute_script.py +170 -0
- jarvis/jarvis_tools/file_analyzer.py +90 -239
- jarvis/jarvis_tools/file_operation.py +99 -31
- jarvis/jarvis_tools/{find_methodolopy.py → find_methodology.py} +2 -1
- jarvis/jarvis_tools/lsp_get_diagnostics.py +2 -0
- jarvis/jarvis_tools/methodology.py +11 -11
- jarvis/jarvis_tools/read_code.py +2 -0
- jarvis/jarvis_tools/read_webpage.py +33 -196
- jarvis/jarvis_tools/registry.py +68 -131
- jarvis/jarvis_tools/search_web.py +14 -6
- jarvis/jarvis_tools/virtual_tty.py +399 -0
- jarvis/jarvis_utils/config.py +29 -3
- jarvis/jarvis_utils/embedding.py +0 -317
- jarvis/jarvis_utils/file_processors.py +343 -0
- jarvis/jarvis_utils/input.py +0 -1
- jarvis/jarvis_utils/methodology.py +94 -435
- jarvis/jarvis_utils/utils.py +207 -9
- {jarvis_ai_assistant-0.1.138.dist-info → jarvis_ai_assistant-0.1.141.dist-info}/METADATA +4 -4
- jarvis_ai_assistant-0.1.141.dist-info/RECORD +94 -0
- {jarvis_ai_assistant-0.1.138.dist-info → jarvis_ai_assistant-0.1.141.dist-info}/entry_points.txt +4 -4
- jarvis/jarvis_code_agent/file_select.py +0 -202
- jarvis/jarvis_platform/ai8.py +0 -268
- jarvis/jarvis_platform/ollama.py +0 -137
- jarvis/jarvis_platform/oyi.py +0 -307
- jarvis/jarvis_rag/file_processors.py +0 -138
- jarvis/jarvis_rag/main.py +0 -1734
- jarvis/jarvis_tools/code_review.py +0 -333
- jarvis/jarvis_tools/execute_python_script.py +0 -58
- jarvis/jarvis_tools/execute_shell.py +0 -97
- jarvis/jarvis_tools/execute_shell_script.py +0 -58
- jarvis/jarvis_tools/find_caller.py +0 -278
- jarvis/jarvis_tools/find_symbol.py +0 -295
- jarvis/jarvis_tools/function_analyzer.py +0 -331
- jarvis/jarvis_tools/git_commiter.py +0 -167
- jarvis/jarvis_tools/project_analyzer.py +0 -304
- jarvis/jarvis_tools/rag.py +0 -143
- jarvis/jarvis_tools/tool_generator.py +0 -221
- jarvis_ai_assistant-0.1.138.dist-info/RECORD +0 -85
- /jarvis/{jarvis_rag → jarvis_init}/__init__.py +0 -0
- {jarvis_ai_assistant-0.1.138.dist-info → jarvis_ai_assistant-0.1.141.dist-info}/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.138.dist-info → jarvis_ai_assistant-0.1.141.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.138.dist-info → jarvis_ai_assistant-0.1.141.dist-info}/top_level.txt +0 -0
jarvis/jarvis_tools/ask_user.py
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
|
+
# 导入所需的类型注解模块
|
|
1
2
|
from typing import Dict, Any
|
|
2
3
|
|
|
4
|
+
# 导入多行输入工具和输出工具
|
|
3
5
|
from jarvis.jarvis_utils.input import get_multiline_input
|
|
4
6
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
5
7
|
|
|
8
|
+
# 定义AskUserTool类,用于向用户提问
|
|
6
9
|
class AskUserTool:
|
|
7
10
|
name="ask_user"
|
|
8
11
|
description="""当完成任务所需的信息缺失或关键决策信息不足时,向用户提问。用户可以输入多行文本,以空行结束。使用场景:1. 需要用户提供更多信息以完成任务;2. 需要用户做出关键决策;3. 需要用户确认重要操作;4. 需要用户提供额外信息"""
|
|
12
|
+
labels=['user', 'interaction', 'input'] # 工具标签
|
|
13
|
+
# 定义参数结构,指定必须包含的问题字段
|
|
9
14
|
parameters={
|
|
10
15
|
"type": "object",
|
|
11
16
|
"properties": {
|
|
@@ -19,23 +24,29 @@ class AskUserTool:
|
|
|
19
24
|
|
|
20
25
|
|
|
21
26
|
def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
|
|
22
|
-
"""
|
|
27
|
+
"""执行向用户提问的操作
|
|
23
28
|
|
|
24
29
|
Args:
|
|
25
|
-
args:
|
|
30
|
+
args: 一个包含问题的字典
|
|
26
31
|
|
|
27
32
|
Returns:
|
|
28
|
-
Dict:
|
|
33
|
+
Dict: 一个包含用户响应的字典
|
|
29
34
|
"""
|
|
30
35
|
try:
|
|
36
|
+
# 从参数中获取问题
|
|
31
37
|
question = args["question"]
|
|
32
38
|
|
|
33
|
-
#
|
|
39
|
+
# 获取agent对象并重置工具调用计数
|
|
40
|
+
agent = args["agent"]
|
|
41
|
+
agent.reset_tool_call_count()
|
|
42
|
+
|
|
43
|
+
# 显示问题给用户
|
|
34
44
|
PrettyOutput.print(f"问题: {question}", OutputType.SYSTEM)
|
|
35
45
|
|
|
36
|
-
#
|
|
46
|
+
# 获取用户输入
|
|
37
47
|
user_response = get_multiline_input("请输入您的答案 (输入空行结束)")
|
|
38
48
|
|
|
49
|
+
# 返回成功响应,包含用户输入的内容
|
|
39
50
|
return {
|
|
40
51
|
"success": True,
|
|
41
52
|
"stdout": user_response,
|
|
@@ -43,6 +54,7 @@ class AskUserTool:
|
|
|
43
54
|
}
|
|
44
55
|
|
|
45
56
|
except Exception as e:
|
|
57
|
+
# 如果发生异常,返回失败响应,包含错误信息
|
|
46
58
|
return {
|
|
47
59
|
"success": False,
|
|
48
60
|
"stdout": "",
|
jarvis/jarvis_tools/base.py
CHANGED
|
@@ -17,12 +17,14 @@ class Tool:
|
|
|
17
17
|
self.description = description
|
|
18
18
|
self.parameters = parameters
|
|
19
19
|
self.func = func
|
|
20
|
+
self.labels = [] # 默认空标签列表
|
|
20
21
|
def to_dict(self) -> Dict:
|
|
21
22
|
"""将工具对象转换为字典格式,主要用于序列化"""
|
|
22
23
|
return {
|
|
23
24
|
"name": self.name,
|
|
24
25
|
"description": self.description,
|
|
25
|
-
"parameters": json.dumps(self.parameters, ensure_ascii=False)
|
|
26
|
+
"parameters": json.dumps(self.parameters, ensure_ascii=False),
|
|
27
|
+
"labels": self.labels
|
|
26
28
|
}
|
|
27
29
|
def execute(self, arguments: Dict) -> Dict[str, Any]:
|
|
28
30
|
"""
|
jarvis/jarvis_tools/chdir.py
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
from typing import Dict, Any
|
|
2
2
|
import os
|
|
3
3
|
from jarvis.jarvis_code_agent.code_agent import CodeAgent
|
|
4
|
-
from jarvis.
|
|
5
|
-
from jarvis.
|
|
4
|
+
from jarvis.jarvis_git_utils.git_commiter import GitCommitTool
|
|
5
|
+
from jarvis.jarvis_code_analysis.code_review import CodeReviewTool, extract_code_report
|
|
6
6
|
from jarvis.jarvis_utils.git_utils import get_latest_commit_hash, has_uncommitted_changes
|
|
7
7
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
8
8
|
|
|
@@ -10,7 +10,8 @@ class CreateCodeAgentTool:
|
|
|
10
10
|
"""用于管理代码开发工作流的工具"""
|
|
11
11
|
|
|
12
12
|
name = "create_code_agent"
|
|
13
|
-
description = "
|
|
13
|
+
description = "技术代码实现和开发过程管理工具,当需要修改代码时使用,如果只是简单文件修改,使用文件操作或者脚本即可"
|
|
14
|
+
labels = ['code', 'development', 'automation']
|
|
14
15
|
parameters = {
|
|
15
16
|
"requirement": """代码实现的技术规范,必须包含以下完整信息:
|
|
16
17
|
1. 项目代码目录 - 项目根目录的绝对路径
|
|
@@ -10,6 +10,7 @@ from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
|
10
10
|
class SubAgentTool:
|
|
11
11
|
name = "create_sub_agent"
|
|
12
12
|
description = "创建子代理以处理特定任务,子代理将生成任务总结报告"
|
|
13
|
+
labels = ['agent', 'automation', 'task']
|
|
13
14
|
parameters = {
|
|
14
15
|
"type": "object",
|
|
15
16
|
"properties": {
|
|
@@ -0,0 +1,170 @@
|
|
|
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 ScriptTool:
|
|
10
|
+
"""Combined script execution tool
|
|
11
|
+
|
|
12
|
+
Executes scripts with any interpreter with a unified interface.
|
|
13
|
+
"""
|
|
14
|
+
name = "execute_script"
|
|
15
|
+
description = "执行脚本并返回结果,支持任意解释器。注意:由于模型上下文长度限制,请避免在脚本中输出大量信息,应该使用rg过滤输出"
|
|
16
|
+
labels = ['system', 'shell', 'python', 'execution', 'script']
|
|
17
|
+
parameters = {
|
|
18
|
+
"type": "object",
|
|
19
|
+
"properties": {
|
|
20
|
+
"interpreter": {
|
|
21
|
+
"type": "string",
|
|
22
|
+
"description": "脚本解释器: 如bash, python3, expect, perl, ruby等任意解释器。如需直接执行shell命令, 可使用bash作为解释器"
|
|
23
|
+
},
|
|
24
|
+
"script_type": {
|
|
25
|
+
"type": "string",
|
|
26
|
+
"enum": ["shell_command", "shell_script", "python_script"],
|
|
27
|
+
"description": "已废弃,请使用interpreter参数。脚本类型: shell_command (Shell命令), shell_script (Shell脚本), python_script (Python脚本)"
|
|
28
|
+
},
|
|
29
|
+
"script_content": {
|
|
30
|
+
"type": "string",
|
|
31
|
+
"description": "要执行的脚本内容"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"required": ["script_content"]
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
# Map of common file extensions for interpreters (can be extended as needed)
|
|
38
|
+
INTERPRETER_EXTENSIONS = {
|
|
39
|
+
"bash": "sh",
|
|
40
|
+
"sh": "sh",
|
|
41
|
+
"python": "py",
|
|
42
|
+
"python2": "py",
|
|
43
|
+
"python3": "py",
|
|
44
|
+
"perl": "pl",
|
|
45
|
+
"ruby": "rb",
|
|
46
|
+
"node": "js",
|
|
47
|
+
"nodejs": "js",
|
|
48
|
+
"php": "php",
|
|
49
|
+
"powershell": "ps1",
|
|
50
|
+
"pwsh": "ps1",
|
|
51
|
+
"R": "r",
|
|
52
|
+
"Rscript": "r",
|
|
53
|
+
"julia": "jl",
|
|
54
|
+
"lua": "lua",
|
|
55
|
+
"go": "go",
|
|
56
|
+
"awk": "awk",
|
|
57
|
+
"kotlin": "kt",
|
|
58
|
+
"java": "java",
|
|
59
|
+
"javac": "java",
|
|
60
|
+
"scala": "scala",
|
|
61
|
+
"swift": "swift",
|
|
62
|
+
"gcc": "c",
|
|
63
|
+
"g++": "cpp",
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
def _execute_script_with_interpreter(self, interpreter: str, script_content: str) -> Dict[str, Any]:
|
|
67
|
+
"""Execute a script with the specified interpreter
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
interpreter: The interpreter to use (any valid interpreter command)
|
|
71
|
+
script_content: Content of the script
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
Dictionary with execution results
|
|
75
|
+
"""
|
|
76
|
+
try:
|
|
77
|
+
# Get file extension for the interpreter
|
|
78
|
+
extension = self.INTERPRETER_EXTENSIONS.get(interpreter, "script")
|
|
79
|
+
|
|
80
|
+
# Create temporary script file
|
|
81
|
+
script_path = os.path.join(tempfile.gettempdir(), f"jarvis_{interpreter.replace('/', '_')}_{os.getpid()}.{extension}")
|
|
82
|
+
output_file = os.path.join(tempfile.gettempdir(), f"jarvis_output_{os.getpid()}.log")
|
|
83
|
+
try:
|
|
84
|
+
with open(script_path, 'w', encoding='utf-8', errors="ignore") as f:
|
|
85
|
+
f.write(script_content)
|
|
86
|
+
|
|
87
|
+
# Use script command to capture both stdout and stderr
|
|
88
|
+
tee_command = f"script -q -c '{interpreter} {script_path}' {output_file}"
|
|
89
|
+
|
|
90
|
+
# Execute command and capture return code
|
|
91
|
+
os.system(tee_command)
|
|
92
|
+
|
|
93
|
+
# Read and process output file
|
|
94
|
+
try:
|
|
95
|
+
with open(output_file, 'r', encoding='utf-8', errors='ignore') as f:
|
|
96
|
+
output = f.read()
|
|
97
|
+
# Remove header and footer added by script command (if any)
|
|
98
|
+
if output:
|
|
99
|
+
lines = output.splitlines()
|
|
100
|
+
if len(lines) > 2:
|
|
101
|
+
output = "\n".join(lines[1:-1])
|
|
102
|
+
except Exception as e:
|
|
103
|
+
output = f"读取输出文件失败: {str(e)}"
|
|
104
|
+
|
|
105
|
+
# Return successful result
|
|
106
|
+
return {
|
|
107
|
+
"success": True,
|
|
108
|
+
"stdout": output,
|
|
109
|
+
"stderr": "",
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
finally:
|
|
113
|
+
# Clean up temporary files
|
|
114
|
+
Path(script_path).unlink(missing_ok=True)
|
|
115
|
+
Path(output_file).unlink(missing_ok=True)
|
|
116
|
+
|
|
117
|
+
except Exception as e:
|
|
118
|
+
PrettyOutput.print(str(e), OutputType.ERROR)
|
|
119
|
+
return {
|
|
120
|
+
"success": False,
|
|
121
|
+
"stdout": "",
|
|
122
|
+
"stderr": str(e)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
def execute(self, args: Dict) -> Dict[str, Any]:
|
|
126
|
+
"""Execute script based on interpreter and content
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
args: Dictionary containing interpreter (or script_type) and script_content
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
Dictionary with execution results
|
|
133
|
+
"""
|
|
134
|
+
try:
|
|
135
|
+
script_content = args.get("script_content", "").strip()
|
|
136
|
+
if not script_content:
|
|
137
|
+
return {
|
|
138
|
+
"success": False,
|
|
139
|
+
"stdout": "",
|
|
140
|
+
"stderr": "Missing or empty script_content parameter"
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
# Get interpreter, with fallback to script_type for backward compatibility
|
|
144
|
+
interpreter = args.get("interpreter")
|
|
145
|
+
script_type = args.get("script_type")
|
|
146
|
+
|
|
147
|
+
# Handle backward compatibility
|
|
148
|
+
if interpreter is None and script_type is not None:
|
|
149
|
+
if script_type == "shell_command":
|
|
150
|
+
# For direct shell commands, use bash -c
|
|
151
|
+
return self._execute_script_with_interpreter("bash -c", script_content)
|
|
152
|
+
elif script_type == "shell_script":
|
|
153
|
+
interpreter = "bash"
|
|
154
|
+
elif script_type == "python_script":
|
|
155
|
+
interpreter = "python"
|
|
156
|
+
|
|
157
|
+
# Default to bash if nothing specified
|
|
158
|
+
if interpreter is None:
|
|
159
|
+
interpreter = "bash"
|
|
160
|
+
|
|
161
|
+
# Execute the script with the specified interpreter
|
|
162
|
+
return self._execute_script_with_interpreter(interpreter, script_content)
|
|
163
|
+
|
|
164
|
+
except Exception as e:
|
|
165
|
+
PrettyOutput.print(str(e), OutputType.ERROR)
|
|
166
|
+
return {
|
|
167
|
+
"success": False,
|
|
168
|
+
"stdout": "",
|
|
169
|
+
"stderr": str(e)
|
|
170
|
+
}
|
|
@@ -1,282 +1,133 @@
|
|
|
1
|
-
from typing import Dict, Any
|
|
1
|
+
from typing import Dict, Any, List
|
|
2
2
|
import os
|
|
3
|
-
import pathlib
|
|
4
3
|
|
|
5
|
-
from jarvis.jarvis_agent import Agent
|
|
6
4
|
from jarvis.jarvis_platform.registry import PlatformRegistry
|
|
7
5
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
8
|
-
|
|
6
|
+
from yaspin import yaspin
|
|
7
|
+
from yaspin.spinners import Spinners
|
|
9
8
|
|
|
10
9
|
class FileAnalyzerTool:
|
|
11
|
-
"""
|
|
12
|
-
单文件分析工具
|
|
13
|
-
使用agent深入分析单个文件的结构、实现细节和代码质量
|
|
14
|
-
"""
|
|
15
|
-
|
|
16
10
|
name = "file_analyzer"
|
|
17
|
-
description = "
|
|
11
|
+
description = """分析文件内容并提取关键信息。支持的文件:文本文件、word文档、pdf文件、图片"""
|
|
12
|
+
labels = ['file', 'analysis', 'code']
|
|
18
13
|
parameters = {
|
|
19
14
|
"type": "object",
|
|
20
15
|
"properties": {
|
|
21
|
-
"
|
|
22
|
-
"type": "
|
|
23
|
-
"
|
|
16
|
+
"file_paths": {
|
|
17
|
+
"type": "array",
|
|
18
|
+
"items": {
|
|
19
|
+
"type": "string"
|
|
20
|
+
},
|
|
21
|
+
"description": "要分析的文件路径列表"
|
|
24
22
|
},
|
|
25
|
-
"
|
|
23
|
+
"prompt": {
|
|
26
24
|
"type": "string",
|
|
27
|
-
"description": "
|
|
28
|
-
"default": "."
|
|
29
|
-
},
|
|
30
|
-
"objective": {
|
|
31
|
-
"type": "string",
|
|
32
|
-
"description": "描述本次文件分析的目标和用途,例如'准备重构该文件'或'理解该文件在项目中的作用'",
|
|
33
|
-
"default": ""
|
|
25
|
+
"description": "分析文件的提示词,指导模型提取什么样的信息"
|
|
34
26
|
}
|
|
35
27
|
},
|
|
36
|
-
"required": ["
|
|
28
|
+
"required": ["file_paths", "prompt"]
|
|
37
29
|
}
|
|
38
30
|
|
|
39
31
|
def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
|
|
40
|
-
"""
|
|
41
|
-
执行单文件分析工具
|
|
32
|
+
"""执行文件分析操作
|
|
42
33
|
|
|
43
34
|
Args:
|
|
44
|
-
args:
|
|
35
|
+
args: 包含文件路径列表和提示词的字典
|
|
45
36
|
|
|
46
37
|
Returns:
|
|
47
|
-
|
|
38
|
+
Dict: 包含分析结果的字典
|
|
48
39
|
"""
|
|
49
|
-
# 存储原始目录
|
|
50
|
-
original_dir = os.getcwd()
|
|
51
|
-
|
|
52
40
|
try:
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
41
|
+
file_paths = args["file_paths"]
|
|
42
|
+
prompt = args["prompt"]
|
|
43
|
+
|
|
44
|
+
agent = args["agent"]
|
|
45
|
+
agent.reset_tool_call_count()
|
|
46
|
+
|
|
47
|
+
# 验证文件路径
|
|
48
|
+
valid_files = []
|
|
49
|
+
for file_path in file_paths:
|
|
50
|
+
if os.path.exists(file_path):
|
|
51
|
+
valid_files.append(file_path)
|
|
52
|
+
else:
|
|
53
|
+
PrettyOutput.print(f"文件不存在: {file_path}", OutputType.WARNING)
|
|
54
|
+
|
|
55
|
+
if not valid_files:
|
|
60
56
|
return {
|
|
61
57
|
"success": False,
|
|
62
58
|
"stdout": "",
|
|
63
|
-
"stderr": "
|
|
59
|
+
"stderr": "没有找到有效的文件"
|
|
64
60
|
}
|
|
65
61
|
|
|
66
|
-
#
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if
|
|
71
|
-
rel_file_path = os.path.relpath(abs_file_path, abs_root_dir)
|
|
72
|
-
else:
|
|
73
|
-
rel_file_path = file_path
|
|
74
|
-
|
|
75
|
-
# 获取文件扩展名和文件名
|
|
76
|
-
file_ext = pathlib.Path(file_path).suffix
|
|
77
|
-
file_name = os.path.basename(file_path)
|
|
78
|
-
|
|
79
|
-
# 创建agent的system prompt
|
|
80
|
-
system_prompt = self._create_system_prompt(
|
|
81
|
-
rel_file_path, file_name, file_ext, root_dir, objective
|
|
82
|
-
)
|
|
83
|
-
|
|
84
|
-
# 创建agent的summary prompt
|
|
85
|
-
summary_prompt = self._create_summary_prompt(rel_file_path, file_name)
|
|
86
|
-
|
|
87
|
-
# 切换到根目录
|
|
88
|
-
os.chdir(root_dir)
|
|
89
|
-
|
|
90
|
-
# 检查文件是否存在
|
|
91
|
-
if not os.path.isfile(rel_file_path):
|
|
62
|
+
# 创建thinking平台实例
|
|
63
|
+
platform_registry = PlatformRegistry.get_global_platform_registry()
|
|
64
|
+
platform = platform_registry.get_thinking_platform()
|
|
65
|
+
|
|
66
|
+
if not platform:
|
|
92
67
|
return {
|
|
93
68
|
"success": False,
|
|
94
69
|
"stdout": "",
|
|
95
|
-
"stderr":
|
|
70
|
+
"stderr": "无法创建thinking平台实例"
|
|
96
71
|
}
|
|
97
|
-
|
|
98
|
-
#
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
72
|
+
|
|
73
|
+
# 设置系统消息
|
|
74
|
+
system_message = """你是一个文件分析助手。你的任务是分析提供的文件内容,并根据用户的提示提取关键信息。
|
|
75
|
+
请保持客观,只关注文件中实际存在的内容。如果无法确定某些信息,请明确指出。
|
|
76
|
+
请以结构化的方式组织你的回答,使用标题、列表和代码块等格式来提高可读性。"""
|
|
77
|
+
platform.set_system_message(system_message)
|
|
78
|
+
|
|
79
|
+
# 上传文件
|
|
80
|
+
with yaspin(Spinners.dots, text="正在上传文件...") as spinner:
|
|
81
|
+
try:
|
|
82
|
+
upload_result = platform.upload_files(valid_files)
|
|
83
|
+
if not upload_result:
|
|
84
|
+
spinner.text = "文件上传失败"
|
|
85
|
+
spinner.fail("❌")
|
|
86
|
+
return {
|
|
87
|
+
"success": False,
|
|
88
|
+
"stdout": "",
|
|
89
|
+
"stderr": "文件上传失败"
|
|
90
|
+
}
|
|
91
|
+
spinner.ok("✅")
|
|
92
|
+
except Exception as e:
|
|
93
|
+
spinner.text = "文件上传失败"
|
|
94
|
+
spinner.fail("❌")
|
|
95
|
+
return {
|
|
96
|
+
"success": False,
|
|
97
|
+
"stdout": "",
|
|
98
|
+
"stderr": f"文件上传失败: {str(e)}"
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
prompt = f"""我上传了文件,收到请回复“已接收到文件”"""
|
|
102
|
+
platform.chat_until_success(prompt)
|
|
103
|
+
|
|
104
|
+
platform.set_suppress_output(False)
|
|
105
|
+
|
|
106
|
+
# 构建分析请求
|
|
107
|
+
analysis_request = f"""
|
|
108
|
+
请根据以下提示分析这些文件。
|
|
109
|
+
{prompt}
|
|
110
|
+
|
|
111
|
+
请提供详细的分析结果和理由。"""
|
|
112
|
+
|
|
113
|
+
# 发送请求并获取分析结果
|
|
114
|
+
with yaspin(Spinners.dots, text="正在分析文件...") as spinner:
|
|
115
|
+
analysis_result = platform.chat_until_success(analysis_request)
|
|
116
|
+
spinner.text = "分析完成"
|
|
117
|
+
spinner.ok("✅")
|
|
118
|
+
|
|
119
|
+
# 清理会话
|
|
120
|
+
platform.delete_chat()
|
|
121
|
+
|
|
125
122
|
return {
|
|
126
123
|
"success": True,
|
|
127
|
-
"stdout":
|
|
124
|
+
"stdout": analysis_result,
|
|
128
125
|
"stderr": ""
|
|
129
126
|
}
|
|
130
127
|
|
|
131
128
|
except Exception as e:
|
|
132
|
-
PrettyOutput.print(str(e), OutputType.ERROR)
|
|
133
129
|
return {
|
|
134
130
|
"success": False,
|
|
135
131
|
"stdout": "",
|
|
136
132
|
"stderr": f"文件分析失败: {str(e)}"
|
|
137
133
|
}
|
|
138
|
-
finally:
|
|
139
|
-
# 恢复原始目录
|
|
140
|
-
os.chdir(original_dir)
|
|
141
|
-
|
|
142
|
-
def _create_system_prompt(self, file_path: str, file_name: str, file_ext: str,
|
|
143
|
-
root_dir: str, objective: str) -> str:
|
|
144
|
-
"""
|
|
145
|
-
创建Agent的system prompt
|
|
146
|
-
|
|
147
|
-
Args:
|
|
148
|
-
file_path: 文件路径
|
|
149
|
-
file_name: 文件名
|
|
150
|
-
file_ext: 文件扩展名
|
|
151
|
-
root_dir: 代码库根目录
|
|
152
|
-
objective: 分析目标
|
|
153
|
-
|
|
154
|
-
Returns:
|
|
155
|
-
系统提示文本
|
|
156
|
-
"""
|
|
157
|
-
objective_text = f"\n\n## 分析目标\n{objective}" if objective else ""
|
|
158
|
-
|
|
159
|
-
return f"""# 文件分析专家
|
|
160
|
-
|
|
161
|
-
## 任务描述
|
|
162
|
-
分析文件 `{file_path}` 的结构、实现细节和代码质量,专注于分析目标所需的内容,生成有针对性、深入且有洞察力的文件分析报告。{objective_text}
|
|
163
|
-
|
|
164
|
-
## 工具使用优先级
|
|
165
|
-
1. **优先使用 read_code**: 直接读取文件内容是分析文件的首选方式
|
|
166
|
-
2. **优先使用 execute_shell**:
|
|
167
|
-
- 使用 rg 搜索文件内容: `rg "pattern" {file_path}`
|
|
168
|
-
- 使用 loc 统计代码: `loc {file_path}`
|
|
169
|
-
3. **仅在必要时使用其他分析工具**
|
|
170
|
-
|
|
171
|
-
## 文件信息
|
|
172
|
-
- 文件路径: `{file_path}`
|
|
173
|
-
- 文件名称: `{file_name}`
|
|
174
|
-
- 文件类型: `{file_ext}`
|
|
175
|
-
- 项目根目录: `{root_dir}`
|
|
176
|
-
|
|
177
|
-
## 分析策略
|
|
178
|
-
1. 首先使用read_code直接读取整个文件内容或分段读取
|
|
179
|
-
2. 使用rg命令搜索文件中的特定模式和结构
|
|
180
|
-
3. 使用loc命令获取文件统计信息
|
|
181
|
-
4. 根据文件类型和分析目标确定重点关注的方面
|
|
182
|
-
5. 保证分析的完整性,收集充分的信息后再得出结论
|
|
183
|
-
|
|
184
|
-
## 分析步骤
|
|
185
|
-
以下步骤应根据具体分析目标灵活应用:
|
|
186
|
-
|
|
187
|
-
1. **文件基本信息分析**:
|
|
188
|
-
- 使用 `loc {file_path}` 获取代码统计
|
|
189
|
-
- 使用 read_code 读取文件头部注释和文档
|
|
190
|
-
- 确定文件的编程语言和主要功能
|
|
191
|
-
|
|
192
|
-
2. **结构分析**:
|
|
193
|
-
- 使用 read_code 阅读完整文件
|
|
194
|
-
- 对于大文件,可分段读取主要部分
|
|
195
|
-
- 识别文件的主要组成部分:
|
|
196
|
-
- 类定义: `rg "class\\s+" {file_path}`
|
|
197
|
-
- 函数定义: `rg "def\\s+|function\\s+" {file_path}`
|
|
198
|
-
- 重要变量: `rg "const\\s+|var\\s+|let\\s+" {file_path}`
|
|
199
|
-
|
|
200
|
-
3. **核心组件分析**:
|
|
201
|
-
- 识别文件中的关键接口、类和函数
|
|
202
|
-
- 使用 rg 搜索重要的代码模式
|
|
203
|
-
- 分析组件间的交互和依赖关系
|
|
204
|
-
|
|
205
|
-
4. **实现细节分析**:
|
|
206
|
-
- 读取并分析关键函数的实现
|
|
207
|
-
- 关注异常处理: `rg "try|catch|except" {file_path}`
|
|
208
|
-
- 检查资源管理: `rg "open|close|with" {file_path}`
|
|
209
|
-
|
|
210
|
-
5. **引用分析**:
|
|
211
|
-
- 找出引用的外部依赖: `rg "import|require|include" {file_path}`
|
|
212
|
-
- 分析与其他模块的交互
|
|
213
|
-
|
|
214
|
-
## 分析工具使用指南
|
|
215
|
-
|
|
216
|
-
### read_code
|
|
217
|
-
- **首选工具**: 用于读取和分析文件内容
|
|
218
|
-
- **用法指南**:
|
|
219
|
-
- 读取整个文件: 直接指定文件路径
|
|
220
|
-
- 读取部分内容: 指定文件路径和行范围
|
|
221
|
-
- 读取头部或关键部分: 根据目的选择合适的行范围
|
|
222
|
-
|
|
223
|
-
### execute_shell
|
|
224
|
-
- **用途**: 执行辅助命令进行分析
|
|
225
|
-
- **推荐命令**:
|
|
226
|
-
- `rg "pattern" {file_path}`: 在文件中搜索模式
|
|
227
|
-
- `loc {file_path}`: 获取文件代码统计
|
|
228
|
-
- `rg -n "class|def|function" {file_path}`: 查找结构元素
|
|
229
|
-
|
|
230
|
-
### 其他专业工具
|
|
231
|
-
- **使用时机**: 仅当read_code和execute_shell不足以完成分析时
|
|
232
|
-
- **使用前提**: 必须先尝试使用基本工具解决问题
|
|
233
|
-
- **选择原则**: 根据实际需要选择最简洁有效的工具
|
|
234
|
-
|
|
235
|
-
## 分析框架适应
|
|
236
|
-
根据文件类型和编程范式调整分析重点:
|
|
237
|
-
|
|
238
|
-
### 不同编程范式
|
|
239
|
-
- 面向对象: 类层次、继承、封装、接口实现
|
|
240
|
-
- 函数式: 函数组合、不可变性、纯函数
|
|
241
|
-
- 过程式: 流程控制、状态管理、数据处理
|
|
242
|
-
- 声明式: 规则定义、约束表达、模式匹配
|
|
243
|
-
|
|
244
|
-
### 不同文件类型
|
|
245
|
-
- 源代码文件: 实现逻辑、算法、接口设计
|
|
246
|
-
- 配置文件: 参数设置、环境变量、系统选项
|
|
247
|
-
- 模板文件: 渲染逻辑、变量占位符、条件分支
|
|
248
|
-
- 数据文件: 结构组织、关系定义、索引设计
|
|
249
|
-
|
|
250
|
-
## 输出要求
|
|
251
|
-
- 直接回应分析目标的关键问题
|
|
252
|
-
- 提供与目标相关的深入洞察
|
|
253
|
-
- 分析内容应直接服务于分析目标
|
|
254
|
-
- 避免与目标无关的冗余信息
|
|
255
|
-
- 使用具体代码片段支持分析结论
|
|
256
|
-
- 提供针对分析目标的具体建议
|
|
257
|
-
- 保证全面分析相关信息后再得出结论"""
|
|
258
|
-
|
|
259
|
-
def _create_summary_prompt(self, file_path: str, file_name: str) -> str:
|
|
260
|
-
"""
|
|
261
|
-
创建Agent的summary prompt
|
|
262
|
-
|
|
263
|
-
Args:
|
|
264
|
-
file_path: 文件路径
|
|
265
|
-
file_name: 文件名
|
|
266
|
-
|
|
267
|
-
Returns:
|
|
268
|
-
总结提示文本
|
|
269
|
-
"""
|
|
270
|
-
return f"""# 文件分析报告: `{file_name}`
|
|
271
|
-
|
|
272
|
-
## 报告要求
|
|
273
|
-
生成一份完全以分析目标为导向的文件分析报告。不要遵循固定的报告模板,而是完全根据分析目标来组织内容:
|
|
274
|
-
|
|
275
|
-
- 专注回答分析目标提出的问题
|
|
276
|
-
- 只包含与分析目标直接相关的发现和洞察
|
|
277
|
-
- 完全跳过与分析目标无关的内容,无需做全面分析
|
|
278
|
-
- 分析深度应与目标的具体需求匹配
|
|
279
|
-
- 使用具体的代码片段和实例支持你的观点
|
|
280
|
-
- 以清晰的Markdown格式呈现,简洁明了
|
|
281
|
-
|
|
282
|
-
在分析中保持灵活性,避免固定思维模式。你的任务不是提供全面的文件概览,而是直接解决分析目标中提出的具体问题。"""
|