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
|
@@ -1,304 +0,0 @@
|
|
|
1
|
-
from typing import Dict, Any, List
|
|
2
|
-
import os
|
|
3
|
-
|
|
4
|
-
from jarvis.jarvis_agent import Agent
|
|
5
|
-
from jarvis.jarvis_platform.registry import PlatformRegistry
|
|
6
|
-
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class ProjectAnalyzerTool:
|
|
10
|
-
"""
|
|
11
|
-
项目分析工具
|
|
12
|
-
使用agent分析项目结构、入口点、模块划分等信息(支持所有文件类型)
|
|
13
|
-
"""
|
|
14
|
-
|
|
15
|
-
name = "project_analyzer"
|
|
16
|
-
description = "分析项目结构、入口点、模块划分等信息,提供项目概览(支持所有文件类型)"
|
|
17
|
-
parameters = {
|
|
18
|
-
"type": "object",
|
|
19
|
-
"properties": {
|
|
20
|
-
"root_dir": {
|
|
21
|
-
"type": "string",
|
|
22
|
-
"description": "项目根目录路径(可选)",
|
|
23
|
-
"default": "."
|
|
24
|
-
},
|
|
25
|
-
"focus_dirs": {
|
|
26
|
-
"type": "array",
|
|
27
|
-
"items": {
|
|
28
|
-
"type": "string"
|
|
29
|
-
},
|
|
30
|
-
"description": "要重点分析的目录列表(可选)",
|
|
31
|
-
"default": []
|
|
32
|
-
},
|
|
33
|
-
"exclude_dirs": {
|
|
34
|
-
"type": "array",
|
|
35
|
-
"items": {
|
|
36
|
-
"type": "string"
|
|
37
|
-
},
|
|
38
|
-
"description": "要排除的目录列表(可选)",
|
|
39
|
-
"default": []
|
|
40
|
-
},
|
|
41
|
-
"objective": {
|
|
42
|
-
"type": "string",
|
|
43
|
-
"description": "描述本次项目分析的目标和用途,例如'理解项目架构以便进行重构'或'寻找性能瓶颈'",
|
|
44
|
-
"default": ""
|
|
45
|
-
}
|
|
46
|
-
},
|
|
47
|
-
"required": []
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
|
|
51
|
-
"""
|
|
52
|
-
执行项目分析工具
|
|
53
|
-
|
|
54
|
-
Args:
|
|
55
|
-
args: 包含参数的字典
|
|
56
|
-
|
|
57
|
-
Returns:
|
|
58
|
-
包含执行结果的字典
|
|
59
|
-
"""
|
|
60
|
-
# 存储原始目录
|
|
61
|
-
original_dir = os.getcwd()
|
|
62
|
-
|
|
63
|
-
try:
|
|
64
|
-
# 解析参数
|
|
65
|
-
root_dir = args.get("root_dir", ".")
|
|
66
|
-
focus_dirs = args.get("focus_dirs", [])
|
|
67
|
-
exclude_dirs = args.get("exclude_dirs", [])
|
|
68
|
-
objective = args.get("objective", "")
|
|
69
|
-
|
|
70
|
-
# 创建agent的system prompt
|
|
71
|
-
system_prompt = self._create_system_prompt(
|
|
72
|
-
root_dir, focus_dirs, exclude_dirs, objective
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
# 创建agent的summary prompt
|
|
76
|
-
summary_prompt = self._create_summary_prompt(root_dir, objective)
|
|
77
|
-
|
|
78
|
-
# 切换到根目录
|
|
79
|
-
os.chdir(root_dir)
|
|
80
|
-
|
|
81
|
-
# 构建使用的工具
|
|
82
|
-
from jarvis.jarvis_tools.registry import ToolRegistry
|
|
83
|
-
tool_registry = ToolRegistry()
|
|
84
|
-
tool_registry.use_tools([
|
|
85
|
-
"execute_shell",
|
|
86
|
-
"read_code",
|
|
87
|
-
"find_symbol",
|
|
88
|
-
"function_analyzer",
|
|
89
|
-
"find_caller",
|
|
90
|
-
"file_analyzer",
|
|
91
|
-
"ask_codebase"
|
|
92
|
-
])
|
|
93
|
-
|
|
94
|
-
# 创建并运行agent
|
|
95
|
-
analyzer_agent = Agent(
|
|
96
|
-
system_prompt=system_prompt,
|
|
97
|
-
name=f"ProjectAnalyzer",
|
|
98
|
-
description=f"分析项目结构、模块划分和关键组件",
|
|
99
|
-
summary_prompt=summary_prompt,
|
|
100
|
-
platform=PlatformRegistry().get_normal_platform(),
|
|
101
|
-
output_handler=[tool_registry],
|
|
102
|
-
execute_tool_confirm=False,
|
|
103
|
-
auto_complete=True
|
|
104
|
-
)
|
|
105
|
-
|
|
106
|
-
# 运行agent并获取结果
|
|
107
|
-
task_input = f"分析项目结构、入口点、模块划分等信息,提供项目概览"
|
|
108
|
-
result = analyzer_agent.run(task_input)
|
|
109
|
-
|
|
110
|
-
return {
|
|
111
|
-
"success": True,
|
|
112
|
-
"stdout": result,
|
|
113
|
-
"stderr": ""
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
except Exception as e:
|
|
117
|
-
PrettyOutput.print(str(e), OutputType.ERROR)
|
|
118
|
-
return {
|
|
119
|
-
"success": False,
|
|
120
|
-
"stdout": "",
|
|
121
|
-
"stderr": f"项目分析失败: {str(e)}"
|
|
122
|
-
}
|
|
123
|
-
finally:
|
|
124
|
-
# 恢复原始目录
|
|
125
|
-
os.chdir(original_dir)
|
|
126
|
-
|
|
127
|
-
def _create_system_prompt(self, root_dir: str, focus_dirs: List[str],
|
|
128
|
-
exclude_dirs: List[str], objective: str) -> str:
|
|
129
|
-
"""
|
|
130
|
-
创建Agent的system prompt
|
|
131
|
-
|
|
132
|
-
Args:
|
|
133
|
-
root_dir: 项目根目录
|
|
134
|
-
focus_dirs: 重点分析的目录列表
|
|
135
|
-
exclude_dirs: 排除的目录列表
|
|
136
|
-
objective: 分析目标
|
|
137
|
-
|
|
138
|
-
Returns:
|
|
139
|
-
系统提示文本
|
|
140
|
-
"""
|
|
141
|
-
focus_dirs_str = ", ".join(focus_dirs) if focus_dirs else "整个项目"
|
|
142
|
-
exclude_dirs_str = ", ".join(exclude_dirs) if exclude_dirs else "无"
|
|
143
|
-
|
|
144
|
-
objective_text = f"\n\n## 分析目标\n{objective}" if objective else "\n\n## 分析目标\n全面了解项目结构、模块划分和关键组件"
|
|
145
|
-
|
|
146
|
-
return f"""# 项目架构分析专家
|
|
147
|
-
|
|
148
|
-
## 任务描述
|
|
149
|
-
对项目 `{root_dir}` 进行针对性分析,专注于分析目标所需的内容,生成有针对性、深入且有洞察力的项目分析报告。{objective_text}
|
|
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
|
-
|
|
172
|
-
## 分析范围
|
|
173
|
-
- 项目根目录: `{root_dir}`
|
|
174
|
-
- 重点分析: {focus_dirs_str}
|
|
175
|
-
- 排除目录: {exclude_dirs_str}
|
|
176
|
-
|
|
177
|
-
## 分析策略
|
|
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
|
-
- 做出有建设性的评价和建议
|
|
217
|
-
|
|
218
|
-
## 常用分析命令
|
|
219
|
-
|
|
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` 查找所有前端和后端文件
|
|
225
|
-
|
|
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` 查找数据库表定义
|
|
231
|
-
|
|
232
|
-
### 代码统计分析
|
|
233
|
-
- `loc` 获取项目总体代码统计
|
|
234
|
-
|
|
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依赖
|
|
240
|
-
|
|
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
|
-
## 输出要求
|
|
268
|
-
- 直接回应分析目标的关键问题
|
|
269
|
-
- 提供与目标相关的深入洞察
|
|
270
|
-
- 分析内容应直接服务于分析目标
|
|
271
|
-
- 确保全面收集相关信息后再形成结论
|
|
272
|
-
- 避免与目标无关的冗余信息
|
|
273
|
-
- 使用具体代码路径和示例支持分析结论
|
|
274
|
-
- 提供针对分析目标的具体建议和改进方向"""
|
|
275
|
-
|
|
276
|
-
def _create_summary_prompt(self, root_dir: str, objective: str) -> str:
|
|
277
|
-
"""
|
|
278
|
-
创建Agent的summary prompt
|
|
279
|
-
|
|
280
|
-
Args:
|
|
281
|
-
root_dir: 项目根目录
|
|
282
|
-
objective: 分析目标
|
|
283
|
-
|
|
284
|
-
Returns:
|
|
285
|
-
总结提示文本
|
|
286
|
-
"""
|
|
287
|
-
objective_text = f"\n\n## 具体分析目标\n{objective}" if objective else ""
|
|
288
|
-
|
|
289
|
-
return f"""# 项目分析报告: `{root_dir}`{objective_text}
|
|
290
|
-
|
|
291
|
-
## 报告要求
|
|
292
|
-
生成一份完全以分析目标为导向的项目分析报告。不要遵循固定的报告模板,而是完全根据分析目标来组织内容:
|
|
293
|
-
|
|
294
|
-
- 首先详细说明项目的主要编程语言、技术栈、框架和依赖
|
|
295
|
-
- 专注回答分析目标提出的问题
|
|
296
|
-
- 只包含与分析目标直接相关的发现和洞察
|
|
297
|
-
- 完全跳过与分析目标无关的内容,无需做全面分析
|
|
298
|
-
- 分析深度应与目标的具体需求匹配
|
|
299
|
-
- 使用具体的代码路径和示例支持你的观点
|
|
300
|
-
- 确保在得出结论前已全面收集和分析相关信息,避免基于部分信息形成不完整或偏颇的判断
|
|
301
|
-
- 根据分析目标灵活组织报告结构,不必包含所有传统的项目分析章节
|
|
302
|
-
- 以清晰的Markdown格式呈现,简洁明了
|
|
303
|
-
|
|
304
|
-
在分析中保持灵活性,避免固定思维模式。你的任务不是提供全面的项目概览,而是直接解决分析目标中提出的具体问题。"""
|
jarvis/jarvis_tools/rag.py
DELETED
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
from typing import Dict, Any
|
|
2
|
-
import os
|
|
3
|
-
from jarvis.jarvis_rag.main import RAGTool as RAGCore
|
|
4
|
-
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
5
|
-
|
|
6
|
-
class RAGTool:
|
|
7
|
-
name = "rag"
|
|
8
|
-
description = "基于文档目录进行问答,支持多种文档格式(txt、pdf、docx等)"
|
|
9
|
-
parameters = {
|
|
10
|
-
"type": "object",
|
|
11
|
-
"properties": {
|
|
12
|
-
"dir": {
|
|
13
|
-
"type": "string",
|
|
14
|
-
"description": "文档目录路径,支持相对路径和绝对路径"
|
|
15
|
-
},
|
|
16
|
-
"question": {
|
|
17
|
-
"type": "string",
|
|
18
|
-
"description": "要询问的问题"
|
|
19
|
-
},
|
|
20
|
-
"rebuild_index": {
|
|
21
|
-
"type": "boolean",
|
|
22
|
-
"description": "是否重建索引",
|
|
23
|
-
"default": False
|
|
24
|
-
}
|
|
25
|
-
},
|
|
26
|
-
"required": ["dir", "question"]
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
def __init__(self):
|
|
30
|
-
"""Initialize RAG tool"""
|
|
31
|
-
self.rag_instances = {} # Cache RAG instances for different directories
|
|
32
|
-
|
|
33
|
-
def _get_rag_instance(self, dir_path: str) -> RAGCore:
|
|
34
|
-
"""Get or create RAG instance
|
|
35
|
-
|
|
36
|
-
Args:
|
|
37
|
-
dir_path: The absolute path of the document directory
|
|
38
|
-
|
|
39
|
-
Returns:
|
|
40
|
-
RAGCore: RAG instance
|
|
41
|
-
"""
|
|
42
|
-
if dir_path not in self.rag_instances:
|
|
43
|
-
self.rag_instances[dir_path] = RAGCore(dir_path)
|
|
44
|
-
return self.rag_instances[dir_path]
|
|
45
|
-
|
|
46
|
-
def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
|
|
47
|
-
"""执行文档问答
|
|
48
|
-
|
|
49
|
-
Args:
|
|
50
|
-
args: 包含参数的字典
|
|
51
|
-
- dir: 文档目录路径
|
|
52
|
-
- question: 要询问的问题
|
|
53
|
-
- rebuild_index: 是否重建索引
|
|
54
|
-
|
|
55
|
-
Returns:
|
|
56
|
-
Dict[str, Any]: 执行结果,包含以下字段:
|
|
57
|
-
- success: 布尔值,表示操作是否成功
|
|
58
|
-
- stdout: 如果成功,包含问题的答案
|
|
59
|
-
- stderr: 如果失败,包含错误信息
|
|
60
|
-
"""
|
|
61
|
-
try:
|
|
62
|
-
# 获取参数
|
|
63
|
-
dir_path = os.path.expanduser(args["dir"])
|
|
64
|
-
dir_path = os.path.abspath(dir_path)
|
|
65
|
-
question = args["question"]
|
|
66
|
-
rebuild_index = args.get("rebuild_index", False)
|
|
67
|
-
|
|
68
|
-
# 检查目录是否存在
|
|
69
|
-
if not os.path.exists(dir_path):
|
|
70
|
-
return {
|
|
71
|
-
"success": False,
|
|
72
|
-
"stdout": "",
|
|
73
|
-
"stderr": f"Directory does not exist: {dir_path}"
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
# 检查路径是否为目录
|
|
77
|
-
if not os.path.isdir(dir_path):
|
|
78
|
-
return {
|
|
79
|
-
"success": False,
|
|
80
|
-
"stdout": "",
|
|
81
|
-
"stderr": f"The path is not a directory: {dir_path}"
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
# 获取RAG实例
|
|
85
|
-
rag = self._get_rag_instance(dir_path)
|
|
86
|
-
|
|
87
|
-
# 如果需要重建索引或索引不存在
|
|
88
|
-
if rebuild_index or not rag.is_index_built():
|
|
89
|
-
PrettyOutput.print("正在构建文档索引...", OutputType.INFO)
|
|
90
|
-
rag.build_index(dir_path)
|
|
91
|
-
|
|
92
|
-
# 执行问答
|
|
93
|
-
PrettyOutput.print(f"问题: {question}", OutputType.INFO)
|
|
94
|
-
response = rag.ask(question)
|
|
95
|
-
|
|
96
|
-
# 处理未找到相关文档的情况
|
|
97
|
-
if response is None:
|
|
98
|
-
return {
|
|
99
|
-
"success": False,
|
|
100
|
-
"stdout": "",
|
|
101
|
-
"stderr": "Failed to get answer, possibly no relevant documents found"
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
# 返回成功响应
|
|
105
|
-
return {
|
|
106
|
-
"success": True,
|
|
107
|
-
"stdout": response,
|
|
108
|
-
"stderr": ""
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
except Exception as e:
|
|
112
|
-
# 处理任何意外错误
|
|
113
|
-
PrettyOutput.print(f"文档问答失败:{str(e)}", OutputType.ERROR)
|
|
114
|
-
return {
|
|
115
|
-
"success": False,
|
|
116
|
-
"stdout": "",
|
|
117
|
-
"stderr": f"Execution failed: {str(e)}"
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
def main():
|
|
121
|
-
"""Run the tool directly from the command line"""
|
|
122
|
-
import argparse
|
|
123
|
-
|
|
124
|
-
parser = argparse.ArgumentParser(description='Document question and answer tool')
|
|
125
|
-
parser.add_argument('--dir', required=True, help='Document directory path')
|
|
126
|
-
parser.add_argument('--question', required=True, help='The question to ask')
|
|
127
|
-
parser.add_argument('--rebuild', action='store_true', help='Rebuild index')
|
|
128
|
-
args = parser.parse_args()
|
|
129
|
-
|
|
130
|
-
tool = RAGTool()
|
|
131
|
-
result = tool.execute({
|
|
132
|
-
"dir": args.dir,
|
|
133
|
-
"question": args.question,
|
|
134
|
-
"rebuild_index": args.rebuild
|
|
135
|
-
})
|
|
136
|
-
|
|
137
|
-
if result["success"]:
|
|
138
|
-
PrettyOutput.print(f"{result['stdout']}", OutputType.INFO, lang="markdown")
|
|
139
|
-
else:
|
|
140
|
-
PrettyOutput.print(result["stderr"], OutputType.WARNING)
|
|
141
|
-
|
|
142
|
-
if __name__ == "__main__":
|
|
143
|
-
main()
|
|
@@ -1,221 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Tool Generator Tool - Automatically creates new tools using LLM
|
|
3
|
-
"""
|
|
4
|
-
from pathlib import Path
|
|
5
|
-
import re
|
|
6
|
-
from typing import Dict, Any
|
|
7
|
-
|
|
8
|
-
from yaspin import yaspin
|
|
9
|
-
from jarvis.jarvis_platform.registry import PlatformRegistry
|
|
10
|
-
from jarvis.jarvis_utils.utils import ct, ot
|
|
11
|
-
|
|
12
|
-
class ToolGenerator:
|
|
13
|
-
"""工具生成器类,用于自动创建与Jarvis系统集成的新工具"""
|
|
14
|
-
|
|
15
|
-
name = "tool_generator"
|
|
16
|
-
description = "使用LLM自动生成与系统集成的新工具"
|
|
17
|
-
parameters = {
|
|
18
|
-
"type": "object",
|
|
19
|
-
"properties": {
|
|
20
|
-
"tool_name": {
|
|
21
|
-
"type": "string",
|
|
22
|
-
"description": "新工具的名称"
|
|
23
|
-
},
|
|
24
|
-
"description": {
|
|
25
|
-
"type": "string",
|
|
26
|
-
"description": "工具用途描述"
|
|
27
|
-
},
|
|
28
|
-
"input_spec": {
|
|
29
|
-
"type": "string",
|
|
30
|
-
"description": "所需输入和功能的规范说明"
|
|
31
|
-
}
|
|
32
|
-
},
|
|
33
|
-
"required": ["tool_name", "description", "input_spec"]
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
def execute(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
|
|
37
|
-
"""
|
|
38
|
-
执行工具生成过程
|
|
39
|
-
Args:
|
|
40
|
-
arguments: 包含工具生成所需参数的字典
|
|
41
|
-
Returns:
|
|
42
|
-
包含执行结果的字典,包含success、stdout和stderr字段
|
|
43
|
-
"""
|
|
44
|
-
# 获取代码生成平台实例
|
|
45
|
-
model = PlatformRegistry.get_global_platform_registry().get_normal_platform()
|
|
46
|
-
|
|
47
|
-
try:
|
|
48
|
-
tool_name = arguments["tool_name"]
|
|
49
|
-
description = arguments["description"]
|
|
50
|
-
input_spec = arguments["input_spec"]
|
|
51
|
-
|
|
52
|
-
# 使用LLM生成工具实现代码
|
|
53
|
-
with yaspin(text="正在生成工具...", color="cyan") as spinner:
|
|
54
|
-
prompt = self._create_prompt(tool_name, description, input_spec)
|
|
55
|
-
llm_response = model.chat_until_success(prompt)
|
|
56
|
-
spinner.text = "工具生成完成"
|
|
57
|
-
spinner.ok("✅")
|
|
58
|
-
|
|
59
|
-
# 从LLM响应中提取实现代码
|
|
60
|
-
with yaspin(text="正在提取工具实现...", color="cyan") as spinner:
|
|
61
|
-
implementation = self._extract_code(llm_response)
|
|
62
|
-
if not implementation:
|
|
63
|
-
return {
|
|
64
|
-
"success": False,
|
|
65
|
-
"stdout": "",
|
|
66
|
-
"stderr": "无法从LLM响应中提取有效的Python代码"
|
|
67
|
-
}
|
|
68
|
-
spinner.text = "工具实现提取完成"
|
|
69
|
-
spinner.ok("✅")
|
|
70
|
-
|
|
71
|
-
# 验证生成的工具代码是否符合返回值格式要求
|
|
72
|
-
with yaspin(text="正在验证工具返回值格式...", color="cyan") as spinner:
|
|
73
|
-
if not self._validate_return_value_format(implementation):
|
|
74
|
-
return {
|
|
75
|
-
"success": False,
|
|
76
|
-
"stdout": "",
|
|
77
|
-
"stderr": "生成的工具不符合要求的返回值格式"
|
|
78
|
-
}
|
|
79
|
-
spinner.text = "工具返回值格式验证完成"
|
|
80
|
-
spinner.ok("✅")
|
|
81
|
-
|
|
82
|
-
# 保存生成的新工具
|
|
83
|
-
with yaspin(text="正在保存工具...", color="cyan") as spinner:
|
|
84
|
-
tools_dir = Path.home() / ".jarvis" / "tools"
|
|
85
|
-
tools_dir.mkdir(parents=True, exist_ok=True)
|
|
86
|
-
tool_file = tools_dir / f"{tool_name}.py"
|
|
87
|
-
|
|
88
|
-
with open(tool_file, "w", errors="ignore") as f:
|
|
89
|
-
f.write(implementation)
|
|
90
|
-
spinner.text = "工具保存完成"
|
|
91
|
-
spinner.ok("✅")
|
|
92
|
-
|
|
93
|
-
return {
|
|
94
|
-
"success": True,
|
|
95
|
-
"stdout": f"工具成功生成于: {tool_file}",
|
|
96
|
-
"stderr": ""
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
except Exception as e:
|
|
100
|
-
return {
|
|
101
|
-
"success": False,
|
|
102
|
-
"stdout": "",
|
|
103
|
-
"stderr": f"工具生成失败: {str(e)}"
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
def _create_prompt(self, tool_name: str, description: str, input_spec: str) -> str:
|
|
107
|
-
"""
|
|
108
|
-
创建用于工具生成的LLM提示
|
|
109
|
-
Args:
|
|
110
|
-
tool_name: 工具名称
|
|
111
|
-
description: 工具描述
|
|
112
|
-
input_spec: 输入规范
|
|
113
|
-
Returns:
|
|
114
|
-
格式化后的提示字符串
|
|
115
|
-
"""
|
|
116
|
-
example_code = ot("TOOL")+'''
|
|
117
|
-
from typing import Dict, Any
|
|
118
|
-
from jarvis.utils import OutputType, PrettyOutput
|
|
119
|
-
from jarvis.jarvis_platform.registry import PlatformRegistry
|
|
120
|
-
|
|
121
|
-
class CustomTool:
|
|
122
|
-
name = "工具名称" # 调用时使用的工具名称
|
|
123
|
-
description = "工具描述" # 工具用途
|
|
124
|
-
parameters = { # 参数JSON Schema
|
|
125
|
-
"type": "object",
|
|
126
|
-
"properties": {
|
|
127
|
-
"param1": {
|
|
128
|
-
"type": "string",
|
|
129
|
-
"description": "参数描述"
|
|
130
|
-
}
|
|
131
|
-
},
|
|
132
|
-
"required": ["param1"]
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
|
|
136
|
-
"""执行工具功能
|
|
137
|
-
|
|
138
|
-
Args:
|
|
139
|
-
args: 传递给工具的参数
|
|
140
|
-
|
|
141
|
-
Returns:
|
|
142
|
-
{
|
|
143
|
-
"success": bool,
|
|
144
|
-
"stdout": str,
|
|
145
|
-
"stderr": str,
|
|
146
|
-
}
|
|
147
|
-
"""
|
|
148
|
-
try:
|
|
149
|
-
# 在此实现工具逻辑
|
|
150
|
-
# 使用LLM
|
|
151
|
-
# model = PlatformRegistry.get_global_platform_registry().get_normal_platform()
|
|
152
|
-
# result = model.chat_until_success(prompt)
|
|
153
|
-
|
|
154
|
-
result = "工具执行结果"
|
|
155
|
-
return {
|
|
156
|
-
"success": True,
|
|
157
|
-
"stdout": result,
|
|
158
|
-
"stderr": ""
|
|
159
|
-
}
|
|
160
|
-
except Exception as e:
|
|
161
|
-
return {
|
|
162
|
-
"success": False,
|
|
163
|
-
"stdout": "",
|
|
164
|
-
"stderr": str(e)
|
|
165
|
-
}
|
|
166
|
-
''' + ct("TOOL")
|
|
167
|
-
|
|
168
|
-
return f'''创建一个与Jarvis系统集成的Python工具类。请遵循以下要求:
|
|
169
|
-
1. 类名: {tool_name.capitalize()}Tool
|
|
170
|
-
2. 描述: {description}
|
|
171
|
-
3. 输入规范: {input_spec}
|
|
172
|
-
4. 必须包含以下类属性:
|
|
173
|
-
- name: str (工具标识符)
|
|
174
|
-
- description: str (工具用途)
|
|
175
|
-
- parameters: dict (输入的JSON schema)
|
|
176
|
-
5. 必须实现 execute(self, args: Dict) -> Dict 方法
|
|
177
|
-
6. execute方法必须返回包含以下字段的字典:
|
|
178
|
-
- success: bool (指示操作是否成功)
|
|
179
|
-
- stdout: str (主要输出/结果)
|
|
180
|
-
- stderr: str (错误信息,如果有)
|
|
181
|
-
7. 必须优雅地处理错误
|
|
182
|
-
8. 仅返回Python实现代码
|
|
183
|
-
9. 代码应该是完整且可直接使用的
|
|
184
|
-
10. 按照以下格式输出代码:
|
|
185
|
-
{ot("TOOL")}
|
|
186
|
-
{example_code}
|
|
187
|
-
{ct("TOOL")}
|
|
188
|
-
|
|
189
|
-
示例:
|
|
190
|
-
{example_code}
|
|
191
|
-
'''
|
|
192
|
-
|
|
193
|
-
def _extract_code(self, response: str) -> str:
|
|
194
|
-
"""
|
|
195
|
-
从LLM响应中提取Python代码
|
|
196
|
-
Args:
|
|
197
|
-
response: LLM的响应字符串
|
|
198
|
-
Returns:
|
|
199
|
-
提取到的Python代码字符串
|
|
200
|
-
"""
|
|
201
|
-
sm = re.search(ot("TOOL")+r'(.*?)'+ct("TOOL"), response, re.DOTALL)
|
|
202
|
-
if sm:
|
|
203
|
-
return sm.group(1)
|
|
204
|
-
return ""
|
|
205
|
-
|
|
206
|
-
def _validate_return_value_format(self, code: str) -> bool:
|
|
207
|
-
"""
|
|
208
|
-
验证execute方法的返回值格式是否正确
|
|
209
|
-
Args:
|
|
210
|
-
code: 要验证的代码字符串
|
|
211
|
-
Returns:
|
|
212
|
-
布尔值,表示格式是否正确
|
|
213
|
-
"""
|
|
214
|
-
required_fields = ["success", "stdout", "stderr"]
|
|
215
|
-
# 检查execute方法是否存在
|
|
216
|
-
if "def execute(self, args: Dict) -> Dict:" not in code and \
|
|
217
|
-
"def execute(self, args: Dict) -> Dict[str, Any]:" not in code:
|
|
218
|
-
return False
|
|
219
|
-
|
|
220
|
-
# 检查返回值中是否包含所有必需字段
|
|
221
|
-
return all(field in code for field in required_fields)
|