jarvis-ai-assistant 0.1.132__py3-none-any.whl → 0.1.134__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 +140 -279
- jarvis/jarvis_agent/jarvis.py +143 -0
- jarvis/jarvis_agent/main.py +0 -2
- jarvis/jarvis_agent/patch.py +16 -12
- jarvis/jarvis_code_agent/code_agent.py +155 -104
- jarvis/jarvis_dev/main.py +0 -8
- jarvis/jarvis_lsp/base.py +0 -42
- jarvis/jarvis_lsp/cpp.py +0 -15
- jarvis/jarvis_lsp/go.py +0 -15
- jarvis/jarvis_lsp/python.py +0 -19
- jarvis/jarvis_lsp/registry.py +0 -62
- jarvis/jarvis_lsp/rust.py +0 -15
- jarvis/jarvis_multi_agent/__init__.py +0 -41
- jarvis/jarvis_multi_agent/main.py +43 -0
- jarvis/jarvis_platform/registry.py +2 -16
- jarvis/jarvis_platform/yuanbao.py +1 -1
- jarvis/jarvis_rag/main.py +1 -1
- jarvis/jarvis_tools/ask_codebase.py +61 -54
- jarvis/jarvis_tools/code_review.py +21 -2
- jarvis/jarvis_tools/create_sub_agent.py +0 -1
- jarvis/jarvis_tools/file_analyzer.py +84 -73
- jarvis/jarvis_tools/find_caller.py +83 -18
- jarvis/jarvis_tools/find_symbol.py +102 -18
- jarvis/jarvis_tools/function_analyzer.py +115 -32
- jarvis/jarvis_tools/git_commiter.py +1 -1
- jarvis/jarvis_tools/methodology.py +0 -6
- jarvis/jarvis_tools/project_analyzer.py +116 -28
- jarvis/jarvis_tools/rag.py +0 -5
- jarvis/jarvis_tools/read_code.py +1 -1
- jarvis/jarvis_tools/search_web.py +23 -353
- jarvis/jarvis_tools/tool_generator.py +2 -2
- jarvis/jarvis_utils/config.py +13 -73
- jarvis/jarvis_utils/methodology.py +8 -11
- jarvis/jarvis_utils/output.py +2 -2
- jarvis/jarvis_utils/utils.py +1 -1
- {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.134.dist-info}/METADATA +6 -15
- {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.134.dist-info}/RECORD +42 -42
- {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.134.dist-info}/entry_points.txt +2 -3
- jarvis/jarvis_tools/lsp_find_definition.py +0 -150
- jarvis/jarvis_tools/lsp_find_references.py +0 -127
- {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.134.dist-info}/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.134.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.134.dist-info}/top_level.txt +0 -0
jarvis/jarvis_agent/patch.py
CHANGED
|
@@ -5,6 +5,7 @@ import os
|
|
|
5
5
|
from yaspin import yaspin
|
|
6
6
|
|
|
7
7
|
from jarvis.jarvis_agent.output_handler import OutputHandler
|
|
8
|
+
from jarvis.jarvis_platform.base import BasePlatform
|
|
8
9
|
from jarvis.jarvis_platform.registry import PlatformRegistry
|
|
9
10
|
from jarvis.jarvis_tools.git_commiter import GitCommitTool
|
|
10
11
|
from jarvis.jarvis_tools.file_operation import FileOperationTool
|
|
@@ -168,11 +169,15 @@ def apply_patch(output_str: str) -> str:
|
|
|
168
169
|
|
|
169
170
|
# 增加代码变更分析和错误提示
|
|
170
171
|
final_ret += "\n\n# 代码变更分析:\n"
|
|
171
|
-
final_ret += "1.
|
|
172
|
+
final_ret += "1. 请使用静态检查工具(如有)检查以上变更是否引入了潜在错误\n"
|
|
172
173
|
final_ret += "2. 如果发现代码错误,请立即提出修复方案\n"
|
|
173
174
|
final_ret += "3. 修复代码错误的优先级高于继续实现功能\n"
|
|
174
|
-
final_ret += "4.
|
|
175
|
-
final_ret += "5.
|
|
175
|
+
final_ret += "4. 确保修改后代码的一致性和完整性\n"
|
|
176
|
+
final_ret += "5. 请确认所有相关点是否已修改完成,包括但不限于:\n"
|
|
177
|
+
final_ret += " - 所有需要修改的文件\n"
|
|
178
|
+
final_ret += " - 所有需要更新的函数\n"
|
|
179
|
+
final_ret += " - 所有需要调整的依赖关系\n"
|
|
180
|
+
final_ret += " - 所有需要同步的文档\n"
|
|
176
181
|
final_ret += "\n\n"
|
|
177
182
|
final_ret += "如果没有问题,请继续进行下一步修改,如果所有修改都已经完成,请终止"
|
|
178
183
|
|
|
@@ -182,20 +187,20 @@ def apply_patch(output_str: str) -> str:
|
|
|
182
187
|
final_ret += "❌ 补丁应用被拒绝\n"
|
|
183
188
|
final_ret += f"# 补丁预览:\n```diff\n{diff}\n```"
|
|
184
189
|
else:
|
|
190
|
+
commited = False
|
|
185
191
|
final_ret += "❌ 没有要提交的更改\n"
|
|
186
192
|
# 用户确认最终结果
|
|
187
193
|
with spinner.hidden():
|
|
194
|
+
if commited:
|
|
195
|
+
return final_ret
|
|
188
196
|
PrettyOutput.print(final_ret, OutputType.USER, lang="markdown")
|
|
189
197
|
if not is_confirm_before_apply_patch() or user_confirm("是否使用此回复?", default=True):
|
|
190
198
|
return final_ret
|
|
191
199
|
custom_reply = get_multiline_input("请输入自定义回复")
|
|
192
200
|
if not custom_reply.strip(): # 如果自定义回复为空,返回空字符串
|
|
193
201
|
return ""
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
else:
|
|
197
|
-
return custom_reply
|
|
198
|
-
|
|
202
|
+
return final_ret + "\n\n" + custom_reply
|
|
203
|
+
|
|
199
204
|
def revert_file(filepath: str):
|
|
200
205
|
"""增强版git恢复,处理新文件"""
|
|
201
206
|
import subprocess
|
|
@@ -258,7 +263,7 @@ def handle_code_operation(filepath: str, patch_content: str) -> bool:
|
|
|
258
263
|
retry_count = 5
|
|
259
264
|
while retry_count > 0:
|
|
260
265
|
retry_count -= 1
|
|
261
|
-
if handle_large_code_operation(filepath, patch_content):
|
|
266
|
+
if handle_large_code_operation(filepath, patch_content, PlatformRegistry().get_normal_platform() if retry_count > 2 else PlatformRegistry().get_thinking_platform()):
|
|
262
267
|
return True
|
|
263
268
|
return handle_small_code_operation(filepath, patch_content)
|
|
264
269
|
|
|
@@ -308,7 +313,7 @@ def handle_small_code_operation(filepath: str, patch_content: str) -> bool:
|
|
|
308
313
|
[合并后的完整代码,包括所有空行和缩进]
|
|
309
314
|
{ct("MERGED_CODE")}
|
|
310
315
|
"""
|
|
311
|
-
model = PlatformRegistry().
|
|
316
|
+
model = PlatformRegistry().get_normal_platform()
|
|
312
317
|
model.set_suppress_output(True)
|
|
313
318
|
count = 30
|
|
314
319
|
start_line = -1
|
|
@@ -365,7 +370,7 @@ def handle_small_code_operation(filepath: str, patch_content: str) -> bool:
|
|
|
365
370
|
return False
|
|
366
371
|
|
|
367
372
|
|
|
368
|
-
def handle_large_code_operation(filepath: str, patch_content: str) -> bool:
|
|
373
|
+
def handle_large_code_operation(filepath: str, patch_content: str, model: BasePlatform) -> bool:
|
|
369
374
|
"""处理大型代码文件的补丁操作,使用差异化补丁格式"""
|
|
370
375
|
with yaspin(text=f"正在处理文件 {filepath}...", color="cyan") as spinner:
|
|
371
376
|
try:
|
|
@@ -376,7 +381,6 @@ def handle_large_code_operation(filepath: str, patch_content: str) -> bool:
|
|
|
376
381
|
spinner.fail("❌")
|
|
377
382
|
return False
|
|
378
383
|
|
|
379
|
-
model = PlatformRegistry().get_codegen_platform()
|
|
380
384
|
model.set_suppress_output(True)
|
|
381
385
|
|
|
382
386
|
prompt = f"""
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import subprocess
|
|
2
2
|
import os
|
|
3
|
+
import argparse
|
|
4
|
+
from token import OP
|
|
5
|
+
from typing import Optional
|
|
3
6
|
|
|
4
7
|
from yaspin import yaspin
|
|
5
8
|
|
|
@@ -22,7 +25,7 @@ from jarvis.jarvis_utils.utils import init_env, user_confirm
|
|
|
22
25
|
|
|
23
26
|
|
|
24
27
|
class CodeAgent:
|
|
25
|
-
def __init__(self):
|
|
28
|
+
def __init__(self, platform : Optional[str] = None, model: Optional[str] = None, need_summary: bool = True):
|
|
26
29
|
self.root_dir = os.getcwd()
|
|
27
30
|
tool_registry = ToolRegistry()
|
|
28
31
|
tool_registry.use_tools(["execute_shell",
|
|
@@ -31,119 +34,162 @@ class CodeAgent:
|
|
|
31
34
|
"ask_user",
|
|
32
35
|
"ask_codebase",
|
|
33
36
|
"lsp_get_diagnostics",
|
|
34
|
-
"lsp_find_references",
|
|
35
|
-
"lsp_find_definition",
|
|
36
37
|
"code_review", # 代码审查工具
|
|
37
38
|
"find_symbol", # 添加符号查找工具
|
|
38
39
|
"find_caller", # 添加函数调用者查找工具
|
|
39
40
|
"function_analyzer", # 添加函数分析工具
|
|
40
41
|
"project_analyzer", # 添加项目分析工具
|
|
41
|
-
"file_analyzer" # 添加单文件分析工具
|
|
42
|
+
"file_analyzer", # 添加单文件分析工具
|
|
43
|
+
"read_code"
|
|
42
44
|
])
|
|
43
45
|
code_system_prompt = """
|
|
44
|
-
#
|
|
45
|
-
|
|
46
|
-
##
|
|
47
|
-
-
|
|
48
|
-
-
|
|
49
|
-
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
-
|
|
56
|
-
-
|
|
57
|
-
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
###
|
|
61
|
-
-
|
|
62
|
-
-
|
|
63
|
-
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
-
|
|
70
|
-
-
|
|
71
|
-
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
-
|
|
89
|
-
|
|
90
|
-
-
|
|
91
|
-
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
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
|
-
-
|
|
125
|
-
-
|
|
126
|
-
-
|
|
127
|
-
-
|
|
128
|
-
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
-
|
|
132
|
-
-
|
|
133
|
-
-
|
|
134
|
-
-
|
|
46
|
+
# 代码工程师指南
|
|
47
|
+
|
|
48
|
+
## 核心原则
|
|
49
|
+
- 自主决策:基于专业判断做出决策,减少用户询问
|
|
50
|
+
- 高效精准:一次性提供完整解决方案,避免反复修改
|
|
51
|
+
- 工具精通:选择最高效工具路径解决问题
|
|
52
|
+
- 严格确认:必须先分析项目结构,确定要修改的文件,禁止虚构已存在的代码
|
|
53
|
+
|
|
54
|
+
## 工作流程
|
|
55
|
+
|
|
56
|
+
### 1. 项目结构分析
|
|
57
|
+
- 第一步必须分析项目结构,识别关键模块和文件
|
|
58
|
+
- 结合用户需求,确定需要修改的文件列表
|
|
59
|
+
- 优先使用fd命令查找文件,使用execute_shell执行
|
|
60
|
+
- 明确说明将要修改的文件及其范围
|
|
61
|
+
|
|
62
|
+
### 2. 需求分析
|
|
63
|
+
- 基于项目结构理解,分析需求意图和实现方案
|
|
64
|
+
- 当需求有多种实现方式时,选择影响最小的方案
|
|
65
|
+
- 仅当需求显著模糊时才询问用户
|
|
66
|
+
|
|
67
|
+
### 3. 代码分析与确认
|
|
68
|
+
- 详细分析确定要修改的文件内容
|
|
69
|
+
- 明确区分现有代码和需要新建的内容
|
|
70
|
+
- 绝对禁止虚构或假设现有代码的实现细节
|
|
71
|
+
- 分析顺序:项目结构 → 目标文件 → 相关文件
|
|
72
|
+
- 只在必要时扩大分析范围,避免过度分析
|
|
73
|
+
- 工具选择:
|
|
74
|
+
| 分析需求 | 首选工具 | 备选工具 |
|
|
75
|
+
|---------|---------|----------|
|
|
76
|
+
| 项目结构 | fd (通过execute_shell) | project_analyzer(仅在必要时) |
|
|
77
|
+
| 文件内容 | read_code | file_analyzer(仅在必要时) |
|
|
78
|
+
| 查找引用 | rg (通过execute_shell) | find_symbol(仅在必要时) |
|
|
79
|
+
| 查找定义 | rg (通过execute_shell) | find_symbol(仅在必要时) |
|
|
80
|
+
| 函数调用者 | rg (通过execute_shell) | find_caller(仅在必要时) |
|
|
81
|
+
| 函数分析 | read_code + rg | function_analyzer(仅在必要时) |
|
|
82
|
+
| 整体分析 | execute_shell_script | ask_codebase(仅在必要时) |
|
|
83
|
+
| 代码质量检查 | execute_shell | code_review(仅在必要时) |
|
|
84
|
+
| 统计代码行数 | loc (通过execute_shell) | - |
|
|
85
|
+
|
|
86
|
+
### 4. 方案设计
|
|
87
|
+
- 确定最小变更方案,保持代码结构
|
|
88
|
+
- 变更类型处理:
|
|
89
|
+
- 修改现有文件:必须先确认文件存在及其内容
|
|
90
|
+
- 创建新文件:可以根据需求创建,但要符合项目结构和风格
|
|
91
|
+
- 变更规模处理:
|
|
92
|
+
- ≤50行:一次性完成所有修改
|
|
93
|
+
- 50-200行:按功能模块分组
|
|
94
|
+
- >200行:按功能拆分,但尽量减少提交次数
|
|
95
|
+
|
|
96
|
+
### 5. 实施修改
|
|
97
|
+
- 遵循"先读后写"原则,在修改已有代码前,必须已经读取了对应文件
|
|
98
|
+
- 保持代码风格一致性
|
|
99
|
+
- 自动匹配项目现有命名风格
|
|
100
|
+
- 允许创建新文件和结构,但不得假设或虚构现有代码
|
|
101
|
+
|
|
102
|
+
### 6. 验证
|
|
103
|
+
- 修改后自动验证:
|
|
104
|
+
1. 优先使用execute_shell运行相关静态检查命令(如pylint、flake8或单元测试)
|
|
105
|
+
2. 只有在shell命令不足时才使用lsp_get_diagnostics
|
|
106
|
+
3. 只有在特殊情况下才使用code_review
|
|
107
|
+
- 发现问题自动修复,无需用户指导
|
|
108
|
+
|
|
109
|
+
## 专用工具简介
|
|
110
|
+
仅在必要时使用以下专用工具:
|
|
111
|
+
|
|
112
|
+
- **project_analyzer**: 项目整体结构分析,仅在fd命令无法满足需求时使用
|
|
113
|
+
- **file_analyzer**: 单文件深度分析,应优先使用read_code替代
|
|
114
|
+
- **find_caller**: 函数调用者查找,应优先使用rg命令替代
|
|
115
|
+
- **find_symbol**: 符号引用查找,应优先使用rg命令替代
|
|
116
|
+
- **function_analyzer**: 函数实现分析,应优先使用read_code和rg组合替代
|
|
117
|
+
- **ask_codebase**: 代码库整体查询,应优先使用fd、rg和read_code组合替代
|
|
118
|
+
- **code_review**: 代码质量检查,应优先使用语言特定的lint工具替代
|
|
119
|
+
|
|
120
|
+
## Shell命令优先策略
|
|
121
|
+
|
|
122
|
+
### 优先使用的Shell命令
|
|
123
|
+
- **项目结构分析**:
|
|
124
|
+
- `fd -t f -e py` 查找所有Python文件
|
|
125
|
+
- `fd -t f -e js -e ts` 查找所有JavaScript/TypeScript文件
|
|
126
|
+
- `fd -t d` 列出所有目录
|
|
127
|
+
- `fd -t f -e java -e kt` 查找所有Java/Kotlin文件
|
|
128
|
+
- `fd -t f -e go` 查找所有Go文件
|
|
129
|
+
- `fd -t f -e rs` 查找所有Rust文件
|
|
130
|
+
- `fd -t f -e c -e cpp -e h -e hpp` 查找所有C/C++文件
|
|
131
|
+
|
|
132
|
+
- **代码内容搜索**:
|
|
133
|
+
- `rg "pattern" --type py` 在Python文件中搜索
|
|
134
|
+
- `rg "pattern" --type js` 在JavaScript文件中搜索
|
|
135
|
+
- `rg "pattern" --type java` 在Java文件中搜索
|
|
136
|
+
- `rg "pattern" --type c` 在C文件中搜索
|
|
137
|
+
- `rg "class ClassName"` 查找类定义
|
|
138
|
+
- `rg "func|function|def" -g "*.py" -g "*.js" -g "*.go" -g "*.rs"` 查找函数定义
|
|
139
|
+
- `rg -w "word"` 精确匹配单词
|
|
140
|
+
|
|
141
|
+
- **代码统计分析**:
|
|
142
|
+
- `loc <file_path>` 统计单个文件
|
|
143
|
+
- `loc --include="*.py"` 统计所有Python文件
|
|
144
|
+
- `loc --include="*.js" --include="*.ts"` 统计所有JavaScript/TypeScript文件
|
|
145
|
+
- `loc --exclude="test"` 排除测试文件
|
|
146
|
+
- `loc --sort=code` 按代码量排序
|
|
147
|
+
|
|
148
|
+
- **代码质量检查**:
|
|
149
|
+
- Python: `pylint <file_path>`, `flake8 <file_path>`
|
|
150
|
+
- JavaScript: `eslint <file_path>`
|
|
151
|
+
- TypeScript: `tsc --noEmit <file_path>`
|
|
152
|
+
- Java: `checkstyle <file_path>`
|
|
153
|
+
- Go: `go vet <file_path>`
|
|
154
|
+
- Rust: `cargo clippy`
|
|
155
|
+
- C/C++: `cppcheck <file_path>`
|
|
156
|
+
|
|
157
|
+
- **整体代码分析**:
|
|
158
|
+
- 使用execute_shell_script编写和执行脚本,批量分析多个文件
|
|
159
|
+
- 简单脚本示例:`find . -name "*.py" | xargs pylint`
|
|
160
|
+
- 使用多工具组合:`fd -e py | xargs pylint`
|
|
161
|
+
|
|
162
|
+
### read_code工具使用
|
|
163
|
+
读取文件应优先使用read_code工具,而非shell命令:
|
|
164
|
+
- 完整读取:使用read_code读取整个文件内容
|
|
165
|
+
- 部分读取:使用read_code指定行范围
|
|
166
|
+
- 大文件处理:对大型文件使用read_code指定行范围,避免全部加载
|
|
167
|
+
|
|
168
|
+
### 仅在命令行工具不足时使用专用工具
|
|
169
|
+
只有当fd、rg、loc和read_code工具无法获取足够信息时,才考虑使用专用工具(ask_codebase、code_review等)。在每次使用专用工具前,应先尝试使用上述工具获取所需信息。
|
|
170
|
+
|
|
171
|
+
### 注意事项
|
|
172
|
+
- read_code比cat或grep更适合阅读代码
|
|
173
|
+
- rg比grep更快更强大,应优先使用
|
|
174
|
+
- fd比find更快更易用,应优先使用
|
|
175
|
+
- loc比wc -l提供更多代码统计信息,应优先使用
|
|
176
|
+
- 针对不同编程语言选择对应的代码质量检查工具
|
|
135
177
|
"""
|
|
136
178
|
# Dynamically add ask_codebase based on task complexity if really needed
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
179
|
+
# 处理platform参数
|
|
180
|
+
platform_instance = (PlatformRegistry().create_platform(platform)
|
|
181
|
+
if platform
|
|
182
|
+
else PlatformRegistry().get_normal_platform())
|
|
183
|
+
if model:
|
|
184
|
+
platform_instance.set_model_name(model) # type: ignore
|
|
185
|
+
|
|
186
|
+
self.agent = Agent(system_prompt=code_system_prompt,
|
|
187
|
+
name="CodeAgent",
|
|
188
|
+
auto_complete=False,
|
|
142
189
|
output_handler=[tool_registry, PatchOutputHandler()],
|
|
143
|
-
platform=
|
|
144
|
-
record_methodology=False,
|
|
190
|
+
platform=platform_instance,
|
|
145
191
|
input_handler=[shell_input_handler, file_input_handler, builtin_input_handler],
|
|
146
|
-
need_summary=
|
|
192
|
+
need_summary=need_summary)
|
|
147
193
|
|
|
148
194
|
|
|
149
195
|
|
|
@@ -212,6 +258,11 @@ def main():
|
|
|
212
258
|
# Add argument parser
|
|
213
259
|
init_env()
|
|
214
260
|
|
|
261
|
+
parser = argparse.ArgumentParser(description='Jarvis Code Agent')
|
|
262
|
+
parser.add_argument('-p', '--platform', type=str, help='Target platform name', default=None)
|
|
263
|
+
parser.add_argument('-m', '--model', type=str, help='Model name to use', default=None)
|
|
264
|
+
args = parser.parse_args()
|
|
265
|
+
|
|
215
266
|
curr_dir = os.getcwd()
|
|
216
267
|
git_dir = find_git_root(curr_dir)
|
|
217
268
|
PrettyOutput.print(f"当前目录: {git_dir}", OutputType.INFO)
|
|
@@ -221,7 +272,7 @@ def main():
|
|
|
221
272
|
user_input = get_multiline_input("请输入你的需求(输入空行退出):")
|
|
222
273
|
if not user_input:
|
|
223
274
|
return 0
|
|
224
|
-
agent = CodeAgent()
|
|
275
|
+
agent = CodeAgent(platform=args.platform, model=args.model, need_summary=False)
|
|
225
276
|
agent.run(user_input)
|
|
226
277
|
|
|
227
278
|
except Exception as e:
|
jarvis/jarvis_dev/main.py
CHANGED
|
@@ -425,8 +425,6 @@ def create_dev_team() -> MultiAgent:
|
|
|
425
425
|
"file_operation",
|
|
426
426
|
"ask_codebase",
|
|
427
427
|
"lsp_get_diagnostics",
|
|
428
|
-
"lsp_find_references",
|
|
429
|
-
"lsp_find_definition",
|
|
430
428
|
"execute_shell",
|
|
431
429
|
"code_review",
|
|
432
430
|
"find_symbol",
|
|
@@ -441,8 +439,6 @@ def create_dev_team() -> MultiAgent:
|
|
|
441
439
|
"file_operation",
|
|
442
440
|
"ask_codebase",
|
|
443
441
|
"execute_shell",
|
|
444
|
-
"lsp_find_definition",
|
|
445
|
-
"lsp_find_references",
|
|
446
442
|
"find_symbol",
|
|
447
443
|
"function_analyzer",
|
|
448
444
|
"file_analyzer",
|
|
@@ -545,8 +541,6 @@ def create_dev_team() -> MultiAgent:
|
|
|
545
541
|
- **file_operation**:管理技术文档和指导文件
|
|
546
542
|
- **ask_codebase**:分析代码库,理解实现细节
|
|
547
543
|
- **lsp_get_diagnostics**:检查代码问题和警告
|
|
548
|
-
- **lsp_find_references**:查找代码引用关系
|
|
549
|
-
- **lsp_find_definition**:查找符号定义位置
|
|
550
544
|
- **execute_shell**:执行开发工具和命令
|
|
551
545
|
- **code_review**:进行代码审查,确保代码质量
|
|
552
546
|
- **find_symbol**:查找关键符号在代码中的使用
|
|
@@ -574,8 +568,6 @@ def create_dev_team() -> MultiAgent:
|
|
|
574
568
|
- **file_operation**:管理源代码和配置文件
|
|
575
569
|
- **ask_codebase**:了解代码库实现细节
|
|
576
570
|
- **execute_shell**:执行开发命令和测试脚本
|
|
577
|
-
- **lsp_find_definition**:查找符号定义位置
|
|
578
|
-
- **lsp_find_references**:查找代码引用关系
|
|
579
571
|
- **find_symbol**:查找关键符号在代码中的使用
|
|
580
572
|
- **function_analyzer**:分析函数实现和优化空间
|
|
581
573
|
- **file_analyzer**:分析文件结构和功能
|
jarvis/jarvis_lsp/base.py
CHANGED
|
@@ -25,48 +25,6 @@ class BaseLSP(ABC):
|
|
|
25
25
|
"""
|
|
26
26
|
return False
|
|
27
27
|
|
|
28
|
-
@abstractmethod
|
|
29
|
-
def find_references(self, file_path: str, position: Tuple[int, int]) -> List[Dict[str, Any]]:
|
|
30
|
-
"""Find all references of symbol at position.
|
|
31
|
-
|
|
32
|
-
Args:
|
|
33
|
-
file_path: Path to the file
|
|
34
|
-
position: (line, character) tuple
|
|
35
|
-
|
|
36
|
-
Returns:
|
|
37
|
-
List of references with location info:
|
|
38
|
-
[
|
|
39
|
-
{
|
|
40
|
-
"uri": "file path",
|
|
41
|
-
"range": {
|
|
42
|
-
"start": {"line": int, "character": int},
|
|
43
|
-
"end": {"line": int, "character": int}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
]
|
|
47
|
-
"""
|
|
48
|
-
return []
|
|
49
|
-
|
|
50
|
-
@abstractmethod
|
|
51
|
-
def find_definition(self, file_path: str, position: Tuple[int, int]) -> Optional[Dict[str, Any]]:
|
|
52
|
-
"""Find definition of symbol at position.
|
|
53
|
-
|
|
54
|
-
Args:
|
|
55
|
-
file_path: Path to the file
|
|
56
|
-
position: (line, character) tuple
|
|
57
|
-
|
|
58
|
-
Returns:
|
|
59
|
-
Location of definition:
|
|
60
|
-
{
|
|
61
|
-
"uri": "file path",
|
|
62
|
-
"range": {
|
|
63
|
-
"start": {"line": int, "character": int},
|
|
64
|
-
"end": {"line": int, "character": int}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
"""
|
|
68
|
-
return None
|
|
69
|
-
|
|
70
28
|
|
|
71
29
|
@abstractmethod
|
|
72
30
|
def get_diagnostics(self, file_path: str) -> List[Dict[str, Any]]:
|
jarvis/jarvis_lsp/cpp.py
CHANGED
|
@@ -66,21 +66,6 @@ class CPPLSP(BaseLSP):
|
|
|
66
66
|
except Exception:
|
|
67
67
|
return None
|
|
68
68
|
|
|
69
|
-
def find_references(self, file_path: str, position: Tuple[int, int]) -> List[Dict[str, Any]]:
|
|
70
|
-
result = self._send_request("textDocument/references", {
|
|
71
|
-
"textDocument": {"uri": f"file://{file_path}"},
|
|
72
|
-
"position": {"line": position[0], "character": position[1]},
|
|
73
|
-
"context": {"includeDeclaration": True}
|
|
74
|
-
})
|
|
75
|
-
return result or [] # type: ignore
|
|
76
|
-
|
|
77
|
-
def find_definition(self, file_path: str, position: Tuple[int, int]) -> Optional[Dict[str, Any]]:
|
|
78
|
-
result = self._send_request("textDocument/definition", {
|
|
79
|
-
"textDocument": {"uri": f"file://{file_path}"},
|
|
80
|
-
"position": {"line": position[0], "character": position[1]}
|
|
81
|
-
})
|
|
82
|
-
return result[0] if result else None
|
|
83
|
-
|
|
84
69
|
|
|
85
70
|
def get_diagnostics(self, file_path: str) -> List[Dict[str, Any]]:
|
|
86
71
|
# Send didOpen notification to trigger diagnostics
|
jarvis/jarvis_lsp/go.py
CHANGED
|
@@ -72,21 +72,6 @@ class GoLSP(BaseLSP):
|
|
|
72
72
|
except Exception:
|
|
73
73
|
return None
|
|
74
74
|
|
|
75
|
-
def find_references(self, file_path: str, position: Tuple[int, int]) -> List[Dict[str, Any]]:
|
|
76
|
-
result = self._send_request("textDocument/references", {
|
|
77
|
-
"textDocument": {"uri": f"file://{file_path}"},
|
|
78
|
-
"position": {"line": position[0], "character": position[1]},
|
|
79
|
-
"context": {"includeDeclaration": True}
|
|
80
|
-
})
|
|
81
|
-
return result or [] # type: ignore
|
|
82
|
-
|
|
83
|
-
def find_definition(self, file_path: str, position: Tuple[int, int]) -> Optional[Dict[str, Any]]:
|
|
84
|
-
result = self._send_request("textDocument/definition", {
|
|
85
|
-
"textDocument": {"uri": f"file://{file_path}"},
|
|
86
|
-
"position": {"line": position[0], "character": position[1]}
|
|
87
|
-
})
|
|
88
|
-
return result[0] if result else None
|
|
89
|
-
|
|
90
75
|
def get_diagnostics(self, file_path: str) -> List[Dict[str, Any]]:
|
|
91
76
|
# Send didOpen notification to trigger diagnostics
|
|
92
77
|
self._send_request("textDocument/didOpen", {
|
jarvis/jarvis_lsp/python.py
CHANGED
|
@@ -25,25 +25,6 @@ class PythonLSP(BaseLSP):
|
|
|
25
25
|
return None
|
|
26
26
|
return self.script_cache[file_path]
|
|
27
27
|
|
|
28
|
-
def find_references(self, file_path: str, position: Tuple[int, int]) -> List[Dict[str, Any]]:
|
|
29
|
-
script = self._get_script(file_path)
|
|
30
|
-
if not script:
|
|
31
|
-
return []
|
|
32
|
-
try:
|
|
33
|
-
refs = script.get_references(line=position[0] + 1, column=position[1])
|
|
34
|
-
return [self._location_to_dict(ref) for ref in refs]
|
|
35
|
-
except Exception:
|
|
36
|
-
return []
|
|
37
|
-
|
|
38
|
-
def find_definition(self, file_path: str, position: Tuple[int, int]) -> Optional[Dict[str, Any]]:
|
|
39
|
-
script = self._get_script(file_path)
|
|
40
|
-
if not script:
|
|
41
|
-
return None
|
|
42
|
-
try:
|
|
43
|
-
defs = script.goto(line=position[0] + 1, column=position[1])
|
|
44
|
-
return self._location_to_dict(defs[0]) if defs else None
|
|
45
|
-
except Exception:
|
|
46
|
-
return None
|
|
47
28
|
|
|
48
29
|
def _location_to_dict(self, location) -> Dict[str, Any]:
|
|
49
30
|
return {
|
jarvis/jarvis_lsp/registry.py
CHANGED
|
@@ -9,8 +9,6 @@ from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
|
9
9
|
|
|
10
10
|
REQUIRED_METHODS = [
|
|
11
11
|
('initialize', ['workspace_path']),
|
|
12
|
-
('find_references', ['file_path', 'position']),
|
|
13
|
-
('find_definition', ['file_path', 'position']),
|
|
14
12
|
('get_diagnostics', ['file_path']),
|
|
15
13
|
('shutdown', [])
|
|
16
14
|
]
|
|
@@ -167,63 +165,3 @@ class LSPRegistry:
|
|
|
167
165
|
with open(file_path, 'r', errors="ignore") as file:
|
|
168
166
|
lines = file.readlines()
|
|
169
167
|
return lines[line]
|
|
170
|
-
|
|
171
|
-
def main():
|
|
172
|
-
"""CLI entry point for LSP testing."""
|
|
173
|
-
import argparse
|
|
174
|
-
|
|
175
|
-
parser = argparse.ArgumentParser(description='LSP functionality testing')
|
|
176
|
-
parser.add_argument('--language', type=str, required=True, help='Programming language')
|
|
177
|
-
parser.add_argument('--file', type=str, required=True, help='File to analyze')
|
|
178
|
-
parser.add_argument('--action', choices=['symbols', 'diagnostics', 'references', 'definition'],
|
|
179
|
-
required=True, help='Action to perform')
|
|
180
|
-
parser.add_argument('--line', type=int, help='Line number (0-based) for references/definition')
|
|
181
|
-
parser.add_argument('--character', type=int, help='Character position for references/definition')
|
|
182
|
-
|
|
183
|
-
args = parser.parse_args()
|
|
184
|
-
|
|
185
|
-
# Initialize LSP
|
|
186
|
-
registry = LSPRegistry.get_global_lsp_registry()
|
|
187
|
-
lsp = registry.create_lsp(args.language)
|
|
188
|
-
|
|
189
|
-
if not lsp:
|
|
190
|
-
PrettyOutput.print(f"没有 LSP 支持的语言: {args.language}", OutputType.WARNING)
|
|
191
|
-
return 1
|
|
192
|
-
|
|
193
|
-
if not lsp.initialize(os.path.abspath(os.getcwd())):
|
|
194
|
-
PrettyOutput.print("LSP 初始化失败", OutputType.WARNING)
|
|
195
|
-
return 1
|
|
196
|
-
|
|
197
|
-
try:
|
|
198
|
-
if args.action == 'diagnostics':
|
|
199
|
-
diagnostics = lsp.get_diagnostics(args.file)
|
|
200
|
-
for diag in diagnostics:
|
|
201
|
-
severity = ['Error', 'Warning', 'Info', 'Hint'][diag['severity'] - 1]
|
|
202
|
-
PrettyOutput.print(f"{severity} 在 {diag['range']['start']['line']}:{diag['range']['start']['character']}: {diag['message']}", OutputType.INFO)
|
|
203
|
-
|
|
204
|
-
elif args.action in ('references', 'definition'):
|
|
205
|
-
if args.line is None or args.character is None:
|
|
206
|
-
PrettyOutput.print("需要行和字符位置用于 references/definition", OutputType.WARNING)
|
|
207
|
-
return 1
|
|
208
|
-
|
|
209
|
-
if args.action == 'references':
|
|
210
|
-
refs = lsp.find_references(args.file, (args.line, args.character))
|
|
211
|
-
for ref in refs:
|
|
212
|
-
PrettyOutput.print(f"引用在 {ref['uri']} 在 {ref['range']['start']['line']}:{ref['range']['start']['character']}\n行: {LSPRegistry.get_line_at_position(ref['uri'], ref['range']['start']['line'])}", OutputType.INFO)
|
|
213
|
-
else:
|
|
214
|
-
defn = lsp.find_definition(args.file, (args.line, args.character))
|
|
215
|
-
if defn:
|
|
216
|
-
PrettyOutput.print(f"定义在 {defn['uri']} 在 {defn['range']['start']['line']}:{defn['range']['start']['character']}\n行: {LSPRegistry.get_line_at_position(defn['uri'], defn['range']['start']['line'])}", OutputType.INFO)
|
|
217
|
-
else:
|
|
218
|
-
PrettyOutput.print("没有找到定义", OutputType.WARNING)
|
|
219
|
-
|
|
220
|
-
except Exception as e:
|
|
221
|
-
PrettyOutput.print(f"错误: {str(e)}", OutputType.ERROR)
|
|
222
|
-
return 1
|
|
223
|
-
finally:
|
|
224
|
-
lsp.shutdown()
|
|
225
|
-
|
|
226
|
-
return 0
|
|
227
|
-
|
|
228
|
-
if __name__ == "__main__":
|
|
229
|
-
exit(main())
|
jarvis/jarvis_lsp/rust.py
CHANGED
|
@@ -74,21 +74,6 @@ class RustLSP(BaseLSP):
|
|
|
74
74
|
except Exception:
|
|
75
75
|
return None
|
|
76
76
|
|
|
77
|
-
def find_references(self, file_path: str, position: Tuple[int, int]) -> List[Dict[str, Any]]:
|
|
78
|
-
result = self._send_request("textDocument/references", {
|
|
79
|
-
"textDocument": {"uri": f"file://{file_path}"},
|
|
80
|
-
"position": {"line": position[0], "character": position[1]},
|
|
81
|
-
"context": {"includeDeclaration": True}
|
|
82
|
-
})
|
|
83
|
-
return result or [] # type: ignore
|
|
84
|
-
|
|
85
|
-
def find_definition(self, file_path: str, position: Tuple[int, int]) -> Optional[Dict[str, Any]]:
|
|
86
|
-
result = self._send_request("textDocument/definition", {
|
|
87
|
-
"textDocument": {"uri": f"file://{file_path}"},
|
|
88
|
-
"position": {"line": position[0], "character": position[1]}
|
|
89
|
-
})
|
|
90
|
-
return result[0] if result else None
|
|
91
|
-
|
|
92
77
|
|
|
93
78
|
def get_diagnostics(self, file_path: str) -> List[Dict[str, Any]]:
|
|
94
79
|
# Send didOpen notification to trigger diagnostics
|