jarvis-ai-assistant 0.1.132__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 +330 -347
- jarvis/jarvis_agent/builtin_input_handler.py +16 -6
- jarvis/jarvis_agent/file_input_handler.py +9 -9
- jarvis/jarvis_agent/jarvis.py +143 -0
- jarvis/jarvis_agent/main.py +12 -13
- jarvis/jarvis_agent/output_handler.py +3 -3
- jarvis/jarvis_agent/patch.py +92 -64
- jarvis/jarvis_agent/shell_input_handler.py +5 -3
- jarvis/jarvis_code_agent/code_agent.py +263 -177
- jarvis/jarvis_code_agent/file_select.py +24 -24
- jarvis/jarvis_dev/main.py +45 -59
- 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 -53
- jarvis/jarvis_lsp/cpp.py +13 -28
- jarvis/jarvis_lsp/go.py +13 -28
- jarvis/jarvis_lsp/python.py +8 -27
- jarvis/jarvis_lsp/registry.py +21 -83
- jarvis/jarvis_lsp/rust.py +15 -30
- jarvis/jarvis_methodology/main.py +101 -0
- jarvis/jarvis_multi_agent/__init__.py +10 -51
- jarvis/jarvis_multi_agent/main.py +43 -0
- 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 +29 -44
- jarvis/jarvis_platform/yuanbao.py +39 -43
- 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 +262 -278
- jarvis/jarvis_smart_shell/main.py +12 -12
- jarvis/jarvis_tools/ask_codebase.py +85 -78
- 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 +40 -21
- jarvis/jarvis_tools/create_code_agent.py +15 -15
- jarvis/jarvis_tools/create_sub_agent.py +0 -1
- 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 +116 -105
- jarvis/jarvis_tools/file_operation.py +22 -20
- jarvis/jarvis_tools/find_caller.py +105 -40
- jarvis/jarvis_tools/find_methodolopy.py +65 -0
- jarvis/jarvis_tools/find_symbol.py +123 -39
- jarvis/jarvis_tools/function_analyzer.py +140 -57
- jarvis/jarvis_tools/git_commiter.py +10 -10
- jarvis/jarvis_tools/lsp_get_diagnostics.py +19 -19
- jarvis/jarvis_tools/methodology.py +22 -67
- jarvis/jarvis_tools/project_analyzer.py +137 -53
- jarvis/jarvis_tools/rag.py +15 -20
- jarvis/jarvis_tools/read_code.py +25 -23
- jarvis/jarvis_tools/read_webpage.py +31 -31
- jarvis/jarvis_tools/registry.py +72 -52
- jarvis/jarvis_tools/search_web.py +23 -353
- jarvis/jarvis_tools/tool_generator.py +19 -19
- jarvis/jarvis_utils/config.py +36 -96
- 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 +141 -140
- jarvis/jarvis_utils/output.py +13 -13
- jarvis/jarvis_utils/utils.py +23 -71
- {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/METADATA +6 -15
- jarvis_ai_assistant-0.1.138.dist-info/RECORD +85 -0
- {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/entry_points.txt +4 -3
- jarvis/jarvis_tools/lsp_find_definition.py +0 -150
- jarvis/jarvis_tools/lsp_find_references.py +0 -127
- jarvis/jarvis_tools/select_code_files.py +0 -62
- jarvis_ai_assistant-0.1.132.dist-info/RECORD +0 -82
- {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/top_level.txt +0 -0
|
@@ -4,14 +4,13 @@ import glob
|
|
|
4
4
|
import hashlib
|
|
5
5
|
from typing import Dict, Optional, Any
|
|
6
6
|
|
|
7
|
-
from jarvis.jarvis_utils.config import is_use_methodology
|
|
8
7
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
9
8
|
|
|
10
9
|
|
|
11
10
|
|
|
12
11
|
class MethodologyTool:
|
|
13
12
|
"""经验管理工具"""
|
|
14
|
-
|
|
13
|
+
|
|
15
14
|
name = "methodology"
|
|
16
15
|
description = "管理问题解决方法论,支持添加、更新和删除操作"
|
|
17
16
|
parameters = {
|
|
@@ -35,16 +34,11 @@ class MethodologyTool:
|
|
|
35
34
|
"required": ["operation", "problem_type"]
|
|
36
35
|
}
|
|
37
36
|
|
|
38
|
-
@staticmethod
|
|
39
|
-
def check()->bool:
|
|
40
|
-
"""检查是否启用了方法论功能"""
|
|
41
|
-
return is_use_methodology()
|
|
42
|
-
|
|
43
37
|
def __init__(self):
|
|
44
38
|
"""初始化经验管理工具"""
|
|
45
39
|
self.methodology_dir = os.path.expanduser("~/.jarvis/methodologies")
|
|
46
40
|
self._ensure_dir_exists()
|
|
47
|
-
|
|
41
|
+
|
|
48
42
|
def _ensure_dir_exists(self):
|
|
49
43
|
"""确保方法论目录存在"""
|
|
50
44
|
if not os.path.exists(self.methodology_dir):
|
|
@@ -52,70 +46,50 @@ class MethodologyTool:
|
|
|
52
46
|
os.makedirs(self.methodology_dir, exist_ok=True)
|
|
53
47
|
except Exception as e:
|
|
54
48
|
PrettyOutput.print(f"创建方法论目录失败:{str(e)}", OutputType.ERROR)
|
|
55
|
-
|
|
49
|
+
|
|
56
50
|
def _get_methodology_file_path(self, problem_type: str) -> str:
|
|
57
51
|
"""
|
|
58
52
|
根据问题类型获取对应的方法论文件路径
|
|
59
|
-
|
|
53
|
+
|
|
60
54
|
参数:
|
|
61
55
|
problem_type: 问题类型
|
|
62
|
-
|
|
56
|
+
|
|
63
57
|
返回:
|
|
64
58
|
str: 方法论文件路径
|
|
65
59
|
"""
|
|
66
60
|
# 使用MD5哈希作为文件名,避免文件名中的特殊字符
|
|
67
61
|
safe_filename = hashlib.md5(problem_type.encode('utf-8')).hexdigest()
|
|
68
62
|
return os.path.join(self.methodology_dir, f"{safe_filename}.json")
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
"""加载所有方法论"""
|
|
72
|
-
all_methodologies = {}
|
|
73
|
-
|
|
74
|
-
if not os.path.exists(self.methodology_dir):
|
|
75
|
-
return all_methodologies
|
|
76
|
-
|
|
77
|
-
for filepath in glob.glob(os.path.join(self.methodology_dir, "*.json")):
|
|
78
|
-
try:
|
|
79
|
-
with open(filepath, "r", encoding="utf-8", errors="ignore") as f:
|
|
80
|
-
methodology = json.load(f)
|
|
81
|
-
problem_type = methodology.get("problem_type", "")
|
|
82
|
-
content = methodology.get("content", "")
|
|
83
|
-
if problem_type and content:
|
|
84
|
-
all_methodologies[problem_type] = content
|
|
85
|
-
except Exception as e:
|
|
86
|
-
filename = os.path.basename(filepath)
|
|
87
|
-
PrettyOutput.print(f"加载方法论文件 {filename} 失败: {str(e)}", OutputType.WARNING)
|
|
88
|
-
|
|
89
|
-
return all_methodologies
|
|
90
|
-
|
|
63
|
+
|
|
64
|
+
|
|
91
65
|
def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
|
|
92
66
|
"""执行管理方法论的操作
|
|
93
|
-
|
|
67
|
+
|
|
94
68
|
Args:
|
|
95
69
|
args: 包含操作参数的字典
|
|
96
70
|
- operation: 操作类型 (delete/update/add)
|
|
97
71
|
- problem_type: 问题类型
|
|
98
72
|
- content: 方法论内容 (更新和添加时必填)
|
|
99
|
-
|
|
73
|
+
|
|
100
74
|
Returns:
|
|
101
75
|
Dict[str, Any]: 包含执行结果的字典
|
|
102
76
|
"""
|
|
103
77
|
operation = args.get("operation", "").strip()
|
|
104
78
|
problem_type = args.get("problem_type", "").strip()
|
|
105
79
|
content = args.get("content", "").strip()
|
|
106
|
-
|
|
80
|
+
|
|
107
81
|
if not operation or not problem_type:
|
|
108
82
|
return {
|
|
109
83
|
"success": False,
|
|
110
84
|
"stdout": "",
|
|
111
85
|
"stderr": "Missing required parameters: operation and problem_type"
|
|
112
86
|
}
|
|
113
|
-
|
|
87
|
+
|
|
114
88
|
try:
|
|
115
89
|
if operation == "delete":
|
|
116
90
|
# 获取方法论文件路径
|
|
117
91
|
file_path = self._get_methodology_file_path(problem_type)
|
|
118
|
-
|
|
92
|
+
|
|
119
93
|
# 检查文件是否存在
|
|
120
94
|
if os.path.exists(file_path):
|
|
121
95
|
os.remove(file_path)
|
|
@@ -130,7 +104,7 @@ class MethodologyTool:
|
|
|
130
104
|
"stdout": "",
|
|
131
105
|
"stderr": f"Methodology for problem type '{problem_type}' not found"
|
|
132
106
|
}
|
|
133
|
-
|
|
107
|
+
|
|
134
108
|
elif operation in ["update", "add"]:
|
|
135
109
|
if not content:
|
|
136
110
|
return {
|
|
@@ -138,59 +112,40 @@ class MethodologyTool:
|
|
|
138
112
|
"stdout": "",
|
|
139
113
|
"stderr": "Need to provide methodology content"
|
|
140
114
|
}
|
|
141
|
-
|
|
115
|
+
|
|
142
116
|
# 确保目录存在
|
|
143
117
|
self._ensure_dir_exists()
|
|
144
|
-
|
|
118
|
+
|
|
145
119
|
# 获取方法论文件路径
|
|
146
120
|
file_path = self._get_methodology_file_path(problem_type)
|
|
147
|
-
|
|
121
|
+
|
|
148
122
|
# 保存方法论到单独的文件
|
|
149
123
|
with open(file_path, "w", encoding="utf-8", errors="ignore") as f:
|
|
150
124
|
json.dump({
|
|
151
125
|
"problem_type": problem_type,
|
|
152
126
|
"content": content
|
|
153
127
|
}, f, ensure_ascii=False, indent=2)
|
|
154
|
-
|
|
128
|
+
|
|
129
|
+
PrettyOutput.print(f"方法论已保存到 {file_path}", OutputType.INFO)
|
|
130
|
+
|
|
155
131
|
action = "Updated" if os.path.exists(file_path) else "Added"
|
|
156
132
|
return {
|
|
157
133
|
"success": True,
|
|
158
134
|
"stdout": f"{action} methodology for problem type '{problem_type}'",
|
|
159
135
|
"stderr": ""
|
|
160
136
|
}
|
|
161
|
-
|
|
137
|
+
|
|
162
138
|
else:
|
|
163
139
|
return {
|
|
164
140
|
"success": False,
|
|
165
141
|
"stdout": "",
|
|
166
142
|
"stderr": f"Unsupported operation type: {operation}"
|
|
167
143
|
}
|
|
168
|
-
|
|
144
|
+
|
|
169
145
|
except Exception as e:
|
|
170
146
|
return {
|
|
171
147
|
"success": False,
|
|
172
148
|
"stdout": "",
|
|
173
149
|
"stderr": f"Execution failed: {str(e)}"
|
|
174
150
|
}
|
|
175
|
-
|
|
176
|
-
def get_methodology(self, problem_type: str) -> Optional[str]:
|
|
177
|
-
"""获取特定问题类型的方法论
|
|
178
|
-
|
|
179
|
-
Args:
|
|
180
|
-
problem_type: 问题类型
|
|
181
|
-
|
|
182
|
-
Returns:
|
|
183
|
-
Optional[str]: 方法论内容,如果不存在则返回 None
|
|
184
|
-
"""
|
|
185
|
-
file_path = self._get_methodology_file_path(problem_type)
|
|
186
|
-
|
|
187
|
-
if not os.path.exists(file_path):
|
|
188
|
-
return None
|
|
189
|
-
|
|
190
|
-
try:
|
|
191
|
-
with open(file_path, "r", encoding="utf-8", errors="ignore") as f:
|
|
192
|
-
methodology = json.load(f)
|
|
193
|
-
return methodology.get("content")
|
|
194
|
-
except Exception as e:
|
|
195
|
-
PrettyOutput.print(f"读取方法论失败: {str(e)}", OutputType.ERROR)
|
|
196
|
-
return None
|
|
151
|
+
|
|
@@ -9,11 +9,11 @@ from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
|
9
9
|
class ProjectAnalyzerTool:
|
|
10
10
|
"""
|
|
11
11
|
项目分析工具
|
|
12
|
-
使用agent
|
|
12
|
+
使用agent分析项目结构、入口点、模块划分等信息(支持所有文件类型)
|
|
13
13
|
"""
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
name = "project_analyzer"
|
|
16
|
-
description = "
|
|
16
|
+
description = "分析项目结构、入口点、模块划分等信息,提供项目概览(支持所有文件类型)"
|
|
17
17
|
parameters = {
|
|
18
18
|
"type": "object",
|
|
19
19
|
"properties": {
|
|
@@ -46,77 +46,73 @@ class ProjectAnalyzerTool:
|
|
|
46
46
|
},
|
|
47
47
|
"required": []
|
|
48
48
|
}
|
|
49
|
-
|
|
49
|
+
|
|
50
50
|
def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
|
|
51
51
|
"""
|
|
52
52
|
执行项目分析工具
|
|
53
|
-
|
|
53
|
+
|
|
54
54
|
Args:
|
|
55
55
|
args: 包含参数的字典
|
|
56
|
-
|
|
56
|
+
|
|
57
57
|
Returns:
|
|
58
58
|
包含执行结果的字典
|
|
59
59
|
"""
|
|
60
60
|
# 存储原始目录
|
|
61
61
|
original_dir = os.getcwd()
|
|
62
|
-
|
|
62
|
+
|
|
63
63
|
try:
|
|
64
64
|
# 解析参数
|
|
65
65
|
root_dir = args.get("root_dir", ".")
|
|
66
66
|
focus_dirs = args.get("focus_dirs", [])
|
|
67
67
|
exclude_dirs = args.get("exclude_dirs", [])
|
|
68
68
|
objective = args.get("objective", "")
|
|
69
|
-
|
|
69
|
+
|
|
70
70
|
# 创建agent的system prompt
|
|
71
71
|
system_prompt = self._create_system_prompt(
|
|
72
72
|
root_dir, focus_dirs, exclude_dirs, objective
|
|
73
73
|
)
|
|
74
|
-
|
|
74
|
+
|
|
75
75
|
# 创建agent的summary prompt
|
|
76
76
|
summary_prompt = self._create_summary_prompt(root_dir, objective)
|
|
77
|
-
|
|
77
|
+
|
|
78
78
|
# 切换到根目录
|
|
79
79
|
os.chdir(root_dir)
|
|
80
|
-
|
|
80
|
+
|
|
81
81
|
# 构建使用的工具
|
|
82
82
|
from jarvis.jarvis_tools.registry import ToolRegistry
|
|
83
83
|
tool_registry = ToolRegistry()
|
|
84
84
|
tool_registry.use_tools([
|
|
85
|
-
"execute_shell",
|
|
86
|
-
"read_code",
|
|
85
|
+
"execute_shell",
|
|
86
|
+
"read_code",
|
|
87
87
|
"find_symbol",
|
|
88
88
|
"function_analyzer",
|
|
89
89
|
"find_caller",
|
|
90
90
|
"file_analyzer",
|
|
91
91
|
"ask_codebase"
|
|
92
92
|
])
|
|
93
|
-
|
|
93
|
+
|
|
94
94
|
# 创建并运行agent
|
|
95
95
|
analyzer_agent = Agent(
|
|
96
96
|
system_prompt=system_prompt,
|
|
97
97
|
name=f"ProjectAnalyzer",
|
|
98
98
|
description=f"分析项目结构、模块划分和关键组件",
|
|
99
99
|
summary_prompt=summary_prompt,
|
|
100
|
-
platform=PlatformRegistry().
|
|
100
|
+
platform=PlatformRegistry().get_normal_platform(),
|
|
101
101
|
output_handler=[tool_registry],
|
|
102
|
-
need_summary=True,
|
|
103
|
-
is_sub_agent=True,
|
|
104
|
-
use_methodology=False,
|
|
105
|
-
record_methodology=False,
|
|
106
102
|
execute_tool_confirm=False,
|
|
107
103
|
auto_complete=True
|
|
108
104
|
)
|
|
109
|
-
|
|
105
|
+
|
|
110
106
|
# 运行agent并获取结果
|
|
111
107
|
task_input = f"分析项目结构、入口点、模块划分等信息,提供项目概览"
|
|
112
108
|
result = analyzer_agent.run(task_input)
|
|
113
|
-
|
|
109
|
+
|
|
114
110
|
return {
|
|
115
111
|
"success": True,
|
|
116
112
|
"stdout": result,
|
|
117
113
|
"stderr": ""
|
|
118
114
|
}
|
|
119
|
-
|
|
115
|
+
|
|
120
116
|
except Exception as e:
|
|
121
117
|
PrettyOutput.print(str(e), OutputType.ERROR)
|
|
122
118
|
return {
|
|
@@ -127,67 +123,152 @@ class ProjectAnalyzerTool:
|
|
|
127
123
|
finally:
|
|
128
124
|
# 恢复原始目录
|
|
129
125
|
os.chdir(original_dir)
|
|
130
|
-
|
|
131
|
-
def _create_system_prompt(self, root_dir: str, focus_dirs: List[str],
|
|
126
|
+
|
|
127
|
+
def _create_system_prompt(self, root_dir: str, focus_dirs: List[str],
|
|
132
128
|
exclude_dirs: List[str], objective: str) -> str:
|
|
133
129
|
"""
|
|
134
130
|
创建Agent的system prompt
|
|
135
|
-
|
|
131
|
+
|
|
136
132
|
Args:
|
|
137
133
|
root_dir: 项目根目录
|
|
138
134
|
focus_dirs: 重点分析的目录列表
|
|
139
135
|
exclude_dirs: 排除的目录列表
|
|
140
136
|
objective: 分析目标
|
|
141
|
-
|
|
137
|
+
|
|
142
138
|
Returns:
|
|
143
139
|
系统提示文本
|
|
144
140
|
"""
|
|
145
141
|
focus_dirs_str = ", ".join(focus_dirs) if focus_dirs else "整个项目"
|
|
146
142
|
exclude_dirs_str = ", ".join(exclude_dirs) if exclude_dirs else "无"
|
|
147
|
-
|
|
143
|
+
|
|
148
144
|
objective_text = f"\n\n## 分析目标\n{objective}" if objective else "\n\n## 分析目标\n全面了解项目结构、模块划分和关键组件"
|
|
149
|
-
|
|
145
|
+
|
|
150
146
|
return f"""# 项目架构分析专家
|
|
151
147
|
|
|
152
148
|
## 任务描述
|
|
153
149
|
对项目 `{root_dir}` 进行针对性分析,专注于分析目标所需的内容,生成有针对性、深入且有洞察力的项目分析报告。{objective_text}
|
|
154
150
|
|
|
151
|
+
## 工具使用优先级
|
|
152
|
+
1. **优先使用 execute_shell 执行 fd 命令**:
|
|
153
|
+
- `fd -t f -e py` 查找所有Python文件
|
|
154
|
+
- `fd -t d` 列出所有目录
|
|
155
|
+
- `fd README.md` 查找所有README文件
|
|
156
|
+
|
|
157
|
+
2. **优先使用 execute_shell 执行 rg 命令**:
|
|
158
|
+
- `rg "import" --type py` 搜索导入语句
|
|
159
|
+
- `rg "class|def" --type py` 搜索类和函数定义
|
|
160
|
+
- `rg "TODO|FIXME" --type py` 搜索代码注释
|
|
161
|
+
|
|
162
|
+
3. **优先使用 execute_shell 执行 loc 命令**:
|
|
163
|
+
- `loc` 统计所有代码行数
|
|
164
|
+
|
|
165
|
+
4. **辅以 read_code 读取关键文件**:
|
|
166
|
+
- 读取README.md、配置文件、主要模块
|
|
167
|
+
- 对于较大的文件,可读取关键部分
|
|
168
|
+
|
|
169
|
+
5. **避免使用专用分析工具**:
|
|
170
|
+
- 只有当fd、rg、loc命令和read_code工具无法满足需求时才考虑使用
|
|
171
|
+
|
|
155
172
|
## 分析范围
|
|
156
173
|
- 项目根目录: `{root_dir}`
|
|
157
174
|
- 重点分析: {focus_dirs_str}
|
|
158
175
|
- 排除目录: {exclude_dirs_str}
|
|
159
176
|
|
|
160
177
|
## 分析策略
|
|
161
|
-
1.
|
|
162
|
-
2.
|
|
163
|
-
3.
|
|
164
|
-
4.
|
|
178
|
+
1. 在一切分析开始前,先使用loc确定项目的主要编程语言和技术栈
|
|
179
|
+
2. 理解分析目标,确定你需要寻找什么信息
|
|
180
|
+
3. 灵活采用适合目标的分析方法,不受预设分析框架的限制
|
|
181
|
+
4. 有选择地探索项目,只关注与目标直接相关的部分
|
|
182
|
+
5. 根据目标需要自行判断分析的深度和广度
|
|
183
|
+
6. 保证分析的完整性,收集充分的信息后再得出结论
|
|
184
|
+
|
|
185
|
+
## 分析步骤
|
|
186
|
+
以下步骤应根据具体分析目标灵活应用:
|
|
187
|
+
|
|
188
|
+
1. **确定项目的编程语言和技术栈**:
|
|
189
|
+
- 使用 `loc` 统计各类文件数量和分布
|
|
190
|
+
- 使用 `fd package.json` 或 `fd requirements.txt` 查找依赖配置文件
|
|
191
|
+
- 使用 `read_code` 读取配置文件,确定使用的主要框架和依赖
|
|
192
|
+
|
|
193
|
+
2. **梳理项目结构**:
|
|
194
|
+
- 使用 `fd -t d -d 3` 识别三层以内的目录结构
|
|
195
|
+
- 使用 `fd README.md` 查找并阅读项目说明文件
|
|
196
|
+
- 使用 `fd -t f -d 1` 查看根目录下的主要文件
|
|
197
|
+
|
|
198
|
+
3. **定位核心组件**:
|
|
199
|
+
- 使用 `fd -t f -e py` 找出所有Python文件(或其他语言文件)
|
|
200
|
+
- 使用 `rg "class\\s+[A-Z]" --type py` 查找主要类定义
|
|
201
|
+
- 使用 `rg "def\\s+main|if\\s+__name__\\s*==\\s*['\"]__main__['\"]" --type py` 查找入口点
|
|
202
|
+
|
|
203
|
+
4. **分析入口点和执行流程**:
|
|
204
|
+
- 使用 `read_code` 读取入口文件内容
|
|
205
|
+
- 使用 `rg "import|from" 入口文件路径` 查找导入的模块
|
|
206
|
+
- 分析初始化和主要执行流程
|
|
207
|
+
|
|
208
|
+
5. **研究核心实现**:
|
|
209
|
+
- 深入分析与分析目标相关的关键代码
|
|
210
|
+
- 使用 `read_code` 读取关键文件内容
|
|
211
|
+
- 使用 `rg` 搜索特定功能的实现
|
|
212
|
+
|
|
213
|
+
6. **总结并提供见解**:
|
|
214
|
+
- 基于分析形成对项目的整体理解
|
|
215
|
+
- 提供与分析目标直接相关的关键发现
|
|
216
|
+
- 做出有建设性的评价和建议
|
|
165
217
|
|
|
166
|
-
##
|
|
167
|
-
```bash
|
|
168
|
-
# 获取项目文件结构
|
|
169
|
-
find . -type f -not -path "*/\\.*" | sort
|
|
218
|
+
## 常用分析命令
|
|
170
219
|
|
|
171
|
-
|
|
172
|
-
|
|
220
|
+
### 项目结构分析
|
|
221
|
+
- `fd -t d -d 3` 列出三层以内的目录结构
|
|
222
|
+
- `fd -t f -e py -g "test*" -d 3` 查找前三层目录中的Python测试文件
|
|
223
|
+
- `fd -t f -e py | wc -l` 统计Python文件数量
|
|
224
|
+
- `fd -t f -e py -o -e js -o -e html -o -e css` 查找所有前端和后端文件
|
|
173
225
|
|
|
174
|
-
|
|
175
|
-
|
|
226
|
+
### 代码内容分析
|
|
227
|
+
- `rg "^\\s*class\\s+[A-Z]" --type py` 查找Python类定义
|
|
228
|
+
- `rg "^\\s*def\\s+" --type py` 查找Python函数定义
|
|
229
|
+
- `rg "import|from\\s+.+\\s+import" --type py` 查找Python导入语句
|
|
230
|
+
- `rg "CREATE TABLE" --type sql` 查找数据库表定义
|
|
176
231
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
```
|
|
232
|
+
### 代码统计分析
|
|
233
|
+
- `loc` 获取项目总体代码统计
|
|
180
234
|
|
|
181
|
-
|
|
182
|
-
-
|
|
183
|
-
-
|
|
184
|
-
-
|
|
185
|
-
-
|
|
235
|
+
### 依赖分析
|
|
236
|
+
- `read_code requirements.txt` 读取Python依赖
|
|
237
|
+
- `read_code package.json` 读取Node.js依赖
|
|
238
|
+
- `read_code go.mod` 读取Go依赖
|
|
239
|
+
- `read_code pom.xml` 读取Java Maven依赖
|
|
186
240
|
|
|
187
|
-
|
|
241
|
+
记住:始终将分析目标作为分析过程的指导原则,不必为了完整性而执行与目标无关的步骤。
|
|
242
|
+
|
|
243
|
+
## 分析框架适应
|
|
244
|
+
|
|
245
|
+
根据不同类型的项目架构,应调整分析重点:
|
|
246
|
+
|
|
247
|
+
### 单体应用
|
|
248
|
+
- 核心业务逻辑和数据流
|
|
249
|
+
- 模块划分和内部依赖
|
|
250
|
+
- 扩展点和插件机制
|
|
251
|
+
|
|
252
|
+
### 微服务架构
|
|
253
|
+
- 服务边界和接口定义
|
|
254
|
+
- 服务间通信和数据交换
|
|
255
|
+
- 服务发现和配置管理
|
|
256
|
+
|
|
257
|
+
### 前端应用
|
|
258
|
+
- 组件结构和状态管理
|
|
259
|
+
- 路由和页面转换
|
|
260
|
+
- API调用和数据处理
|
|
261
|
+
|
|
262
|
+
### 数据处理系统
|
|
263
|
+
- 数据流向和转换过程
|
|
264
|
+
- 算法实现和优化方式
|
|
265
|
+
- 并行处理和性能考量
|
|
266
|
+
|
|
267
|
+
## 输出要求
|
|
188
268
|
- 直接回应分析目标的关键问题
|
|
189
269
|
- 提供与目标相关的深入洞察
|
|
190
270
|
- 分析内容应直接服务于分析目标
|
|
271
|
+
- 确保全面收集相关信息后再形成结论
|
|
191
272
|
- 避免与目标无关的冗余信息
|
|
192
273
|
- 使用具体代码路径和示例支持分析结论
|
|
193
274
|
- 提供针对分析目标的具体建议和改进方向"""
|
|
@@ -195,26 +276,29 @@ find . -name "core.*" -o -name "*core*" -o -name "main.*" -o -name "api.*"
|
|
|
195
276
|
def _create_summary_prompt(self, root_dir: str, objective: str) -> str:
|
|
196
277
|
"""
|
|
197
278
|
创建Agent的summary prompt
|
|
198
|
-
|
|
279
|
+
|
|
199
280
|
Args:
|
|
200
281
|
root_dir: 项目根目录
|
|
201
282
|
objective: 分析目标
|
|
202
|
-
|
|
283
|
+
|
|
203
284
|
Returns:
|
|
204
285
|
总结提示文本
|
|
205
286
|
"""
|
|
206
287
|
objective_text = f"\n\n## 具体分析目标\n{objective}" if objective else ""
|
|
207
|
-
|
|
288
|
+
|
|
208
289
|
return f"""# 项目分析报告: `{root_dir}`{objective_text}
|
|
209
290
|
|
|
210
291
|
## 报告要求
|
|
211
292
|
生成一份完全以分析目标为导向的项目分析报告。不要遵循固定的报告模板,而是完全根据分析目标来组织内容:
|
|
212
293
|
|
|
294
|
+
- 首先详细说明项目的主要编程语言、技术栈、框架和依赖
|
|
213
295
|
- 专注回答分析目标提出的问题
|
|
214
296
|
- 只包含与分析目标直接相关的发现和洞察
|
|
215
297
|
- 完全跳过与分析目标无关的内容,无需做全面分析
|
|
216
298
|
- 分析深度应与目标的具体需求匹配
|
|
217
299
|
- 使用具体的代码路径和示例支持你的观点
|
|
300
|
+
- 确保在得出结论前已全面收集和分析相关信息,避免基于部分信息形成不完整或偏颇的判断
|
|
301
|
+
- 根据分析目标灵活组织报告结构,不必包含所有传统的项目分析章节
|
|
218
302
|
- 以清晰的Markdown格式呈现,简洁明了
|
|
219
303
|
|
|
220
|
-
在分析中保持灵活性,避免固定思维模式。你的任务不是提供全面的项目概览,而是直接解决分析目标中提出的具体问题。"""
|
|
304
|
+
在分析中保持灵活性,避免固定思维模式。你的任务不是提供全面的项目概览,而是直接解决分析目标中提出的具体问题。"""
|
jarvis/jarvis_tools/rag.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from typing import Dict, Any
|
|
2
2
|
import os
|
|
3
3
|
from jarvis.jarvis_rag.main import RAGTool as RAGCore
|
|
4
|
-
from jarvis.jarvis_utils.config import dont_use_local_model
|
|
5
4
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
6
5
|
|
|
7
6
|
class RAGTool:
|
|
@@ -27,20 +26,16 @@ class RAGTool:
|
|
|
27
26
|
"required": ["dir", "question"]
|
|
28
27
|
}
|
|
29
28
|
|
|
30
|
-
@staticmethod
|
|
31
|
-
def check() -> bool:
|
|
32
|
-
return not dont_use_local_model()
|
|
33
|
-
|
|
34
29
|
def __init__(self):
|
|
35
30
|
"""Initialize RAG tool"""
|
|
36
31
|
self.rag_instances = {} # Cache RAG instances for different directories
|
|
37
32
|
|
|
38
33
|
def _get_rag_instance(self, dir_path: str) -> RAGCore:
|
|
39
34
|
"""Get or create RAG instance
|
|
40
|
-
|
|
35
|
+
|
|
41
36
|
Args:
|
|
42
37
|
dir_path: The absolute path of the document directory
|
|
43
|
-
|
|
38
|
+
|
|
44
39
|
Returns:
|
|
45
40
|
RAGCore: RAG instance
|
|
46
41
|
"""
|
|
@@ -50,13 +45,13 @@ class RAGTool:
|
|
|
50
45
|
|
|
51
46
|
def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
|
|
52
47
|
"""执行文档问答
|
|
53
|
-
|
|
48
|
+
|
|
54
49
|
Args:
|
|
55
50
|
args: 包含参数的字典
|
|
56
51
|
- dir: 文档目录路径
|
|
57
52
|
- question: 要询问的问题
|
|
58
53
|
- rebuild_index: 是否重建索引
|
|
59
|
-
|
|
54
|
+
|
|
60
55
|
Returns:
|
|
61
56
|
Dict[str, Any]: 执行结果,包含以下字段:
|
|
62
57
|
- success: 布尔值,表示操作是否成功
|
|
@@ -69,7 +64,7 @@ class RAGTool:
|
|
|
69
64
|
dir_path = os.path.abspath(dir_path)
|
|
70
65
|
question = args["question"]
|
|
71
66
|
rebuild_index = args.get("rebuild_index", False)
|
|
72
|
-
|
|
67
|
+
|
|
73
68
|
# 检查目录是否存在
|
|
74
69
|
if not os.path.exists(dir_path):
|
|
75
70
|
return {
|
|
@@ -77,7 +72,7 @@ class RAGTool:
|
|
|
77
72
|
"stdout": "",
|
|
78
73
|
"stderr": f"Directory does not exist: {dir_path}"
|
|
79
74
|
}
|
|
80
|
-
|
|
75
|
+
|
|
81
76
|
# 检查路径是否为目录
|
|
82
77
|
if not os.path.isdir(dir_path):
|
|
83
78
|
return {
|
|
@@ -85,19 +80,19 @@ class RAGTool:
|
|
|
85
80
|
"stdout": "",
|
|
86
81
|
"stderr": f"The path is not a directory: {dir_path}"
|
|
87
82
|
}
|
|
88
|
-
|
|
83
|
+
|
|
89
84
|
# 获取RAG实例
|
|
90
85
|
rag = self._get_rag_instance(dir_path)
|
|
91
|
-
|
|
86
|
+
|
|
92
87
|
# 如果需要重建索引或索引不存在
|
|
93
88
|
if rebuild_index or not rag.is_index_built():
|
|
94
89
|
PrettyOutput.print("正在构建文档索引...", OutputType.INFO)
|
|
95
90
|
rag.build_index(dir_path)
|
|
96
|
-
|
|
91
|
+
|
|
97
92
|
# 执行问答
|
|
98
93
|
PrettyOutput.print(f"问题: {question}", OutputType.INFO)
|
|
99
94
|
response = rag.ask(question)
|
|
100
|
-
|
|
95
|
+
|
|
101
96
|
# 处理未找到相关文档的情况
|
|
102
97
|
if response is None:
|
|
103
98
|
return {
|
|
@@ -105,14 +100,14 @@ class RAGTool:
|
|
|
105
100
|
"stdout": "",
|
|
106
101
|
"stderr": "Failed to get answer, possibly no relevant documents found"
|
|
107
102
|
}
|
|
108
|
-
|
|
103
|
+
|
|
109
104
|
# 返回成功响应
|
|
110
105
|
return {
|
|
111
106
|
"success": True,
|
|
112
107
|
"stdout": response,
|
|
113
108
|
"stderr": ""
|
|
114
109
|
}
|
|
115
|
-
|
|
110
|
+
|
|
116
111
|
except Exception as e:
|
|
117
112
|
# 处理任何意外错误
|
|
118
113
|
PrettyOutput.print(f"文档问答失败:{str(e)}", OutputType.ERROR)
|
|
@@ -125,20 +120,20 @@ class RAGTool:
|
|
|
125
120
|
def main():
|
|
126
121
|
"""Run the tool directly from the command line"""
|
|
127
122
|
import argparse
|
|
128
|
-
|
|
123
|
+
|
|
129
124
|
parser = argparse.ArgumentParser(description='Document question and answer tool')
|
|
130
125
|
parser.add_argument('--dir', required=True, help='Document directory path')
|
|
131
126
|
parser.add_argument('--question', required=True, help='The question to ask')
|
|
132
127
|
parser.add_argument('--rebuild', action='store_true', help='Rebuild index')
|
|
133
128
|
args = parser.parse_args()
|
|
134
|
-
|
|
129
|
+
|
|
135
130
|
tool = RAGTool()
|
|
136
131
|
result = tool.execute({
|
|
137
132
|
"dir": args.dir,
|
|
138
133
|
"question": args.question,
|
|
139
134
|
"rebuild_index": args.rebuild
|
|
140
135
|
})
|
|
141
|
-
|
|
136
|
+
|
|
142
137
|
if result["success"]:
|
|
143
138
|
PrettyOutput.print(f"{result['stdout']}", OutputType.INFO, lang="markdown")
|
|
144
139
|
else:
|