jarvis-ai-assistant 0.1.130__py3-none-any.whl → 0.1.132__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- jarvis/__init__.py +1 -1
- jarvis/jarvis_agent/__init__.py +71 -38
- jarvis/jarvis_agent/builtin_input_handler.py +73 -0
- jarvis/{jarvis_code_agent → jarvis_agent}/file_input_handler.py +1 -1
- jarvis/jarvis_agent/main.py +1 -1
- jarvis/{jarvis_code_agent → jarvis_agent}/patch.py +77 -55
- jarvis/{jarvis_code_agent → jarvis_agent}/shell_input_handler.py +1 -2
- jarvis/jarvis_code_agent/code_agent.py +93 -88
- jarvis/jarvis_dev/main.py +335 -626
- jarvis/jarvis_git_squash/main.py +11 -32
- jarvis/jarvis_lsp/base.py +2 -26
- jarvis/jarvis_lsp/cpp.py +2 -14
- jarvis/jarvis_lsp/go.py +0 -13
- jarvis/jarvis_lsp/python.py +1 -30
- jarvis/jarvis_lsp/registry.py +10 -14
- jarvis/jarvis_lsp/rust.py +0 -12
- jarvis/jarvis_multi_agent/__init__.py +20 -29
- jarvis/jarvis_platform/ai8.py +7 -32
- jarvis/jarvis_platform/base.py +2 -7
- jarvis/jarvis_platform/kimi.py +3 -144
- jarvis/jarvis_platform/ollama.py +54 -68
- jarvis/jarvis_platform/openai.py +0 -4
- jarvis/jarvis_platform/oyi.py +0 -75
- jarvis/jarvis_platform/registry.py +1 -1
- jarvis/jarvis_platform/yuanbao.py +264 -0
- jarvis/jarvis_platform_manager/main.py +3 -3
- jarvis/jarvis_rag/file_processors.py +138 -0
- jarvis/jarvis_rag/main.py +1305 -425
- jarvis/jarvis_tools/ask_codebase.py +227 -41
- jarvis/jarvis_tools/code_review.py +229 -166
- jarvis/jarvis_tools/create_code_agent.py +76 -72
- jarvis/jarvis_tools/create_sub_agent.py +32 -15
- jarvis/jarvis_tools/execute_python_script.py +58 -0
- jarvis/jarvis_tools/execute_shell.py +15 -28
- jarvis/jarvis_tools/execute_shell_script.py +2 -2
- jarvis/jarvis_tools/file_analyzer.py +271 -0
- jarvis/jarvis_tools/file_operation.py +3 -3
- jarvis/jarvis_tools/find_caller.py +213 -0
- jarvis/jarvis_tools/find_symbol.py +211 -0
- jarvis/jarvis_tools/function_analyzer.py +248 -0
- jarvis/jarvis_tools/git_commiter.py +89 -70
- jarvis/jarvis_tools/lsp_find_definition.py +83 -67
- jarvis/jarvis_tools/lsp_find_references.py +62 -46
- jarvis/jarvis_tools/lsp_get_diagnostics.py +90 -74
- jarvis/jarvis_tools/methodology.py +89 -48
- jarvis/jarvis_tools/project_analyzer.py +220 -0
- jarvis/jarvis_tools/read_code.py +24 -3
- jarvis/jarvis_tools/read_webpage.py +195 -81
- jarvis/jarvis_tools/registry.py +132 -11
- jarvis/jarvis_tools/search_web.py +73 -30
- jarvis/jarvis_tools/tool_generator.py +7 -9
- jarvis/jarvis_utils/__init__.py +1 -0
- jarvis/jarvis_utils/config.py +67 -3
- jarvis/jarvis_utils/embedding.py +344 -45
- jarvis/jarvis_utils/git_utils.py +18 -2
- jarvis/jarvis_utils/input.py +7 -4
- jarvis/jarvis_utils/methodology.py +379 -7
- jarvis/jarvis_utils/output.py +5 -3
- jarvis/jarvis_utils/utils.py +62 -10
- {jarvis_ai_assistant-0.1.130.dist-info → jarvis_ai_assistant-0.1.132.dist-info}/METADATA +3 -4
- jarvis_ai_assistant-0.1.132.dist-info/RECORD +82 -0
- {jarvis_ai_assistant-0.1.130.dist-info → jarvis_ai_assistant-0.1.132.dist-info}/entry_points.txt +2 -0
- jarvis/jarvis_c2rust/c2rust.yaml +0 -734
- jarvis/jarvis_code_agent/builtin_input_handler.py +0 -43
- jarvis/jarvis_codebase/__init__.py +0 -0
- jarvis/jarvis_codebase/main.py +0 -1011
- jarvis/jarvis_tools/lsp_get_document_symbols.py +0 -87
- jarvis/jarvis_tools/lsp_prepare_rename.py +0 -130
- jarvis_ai_assistant-0.1.130.dist-info/RECORD +0 -79
- {jarvis_ai_assistant-0.1.130.dist-info → jarvis_ai_assistant-0.1.132.dist-info}/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.130.dist-info → jarvis_ai_assistant-0.1.132.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.130.dist-info → jarvis_ai_assistant-0.1.132.dist-info}/top_level.txt +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from typing import Dict, Any, List
|
|
2
|
-
|
|
2
|
+
import concurrent.futures
|
|
3
3
|
from regex import W
|
|
4
4
|
from yaspin import yaspin
|
|
5
5
|
from jarvis.jarvis_platform.registry import PlatformRegistry
|
|
@@ -7,7 +7,7 @@ from jarvis.jarvis_tools.read_webpage import WebpageTool
|
|
|
7
7
|
from playwright.sync_api import sync_playwright
|
|
8
8
|
from urllib.parse import quote
|
|
9
9
|
|
|
10
|
-
from jarvis.jarvis_utils.config import get_max_token_count
|
|
10
|
+
from jarvis.jarvis_utils.config import get_max_token_count, get_thread_count
|
|
11
11
|
from jarvis.jarvis_utils.embedding import get_context_token_count
|
|
12
12
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
13
13
|
|
|
@@ -104,7 +104,7 @@ class SearchTool:
|
|
|
104
104
|
"max_results": {
|
|
105
105
|
"type": "integer",
|
|
106
106
|
"description": "最大搜索结果数量",
|
|
107
|
-
"default":
|
|
107
|
+
"default": 10
|
|
108
108
|
}
|
|
109
109
|
},
|
|
110
110
|
"required": ["query", "question"]
|
|
@@ -168,22 +168,20 @@ class SearchTool:
|
|
|
168
168
|
# Process each batch
|
|
169
169
|
batch_results = []
|
|
170
170
|
for i, batch in enumerate(batches, 1):
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
prompt = f"""Please analyze these search results to answer the question: {question}
|
|
171
|
+
prompt = f"""请根据以下搜索结果回答以下问题:{question}
|
|
174
172
|
|
|
175
|
-
|
|
173
|
+
搜索结果内容 (第 {i} 批/{len(batches)}):
|
|
176
174
|
{'-' * 40}
|
|
177
175
|
{''.join(batch)}
|
|
178
176
|
{'-' * 40}
|
|
179
177
|
|
|
180
|
-
|
|
181
|
-
1.
|
|
182
|
-
2.
|
|
183
|
-
3.
|
|
184
|
-
4.
|
|
178
|
+
请提取与问题相关的关键信息。重点关注:
|
|
179
|
+
1. 相关事实和细节
|
|
180
|
+
2. 保持客观性
|
|
181
|
+
3. 在适当的时候引用来源
|
|
182
|
+
4. 注明任何不确定性
|
|
185
183
|
|
|
186
|
-
|
|
184
|
+
请将您的回答格式化为对本批次搜索结果的清晰总结。"""
|
|
187
185
|
|
|
188
186
|
response = self.model.chat_until_success(prompt)
|
|
189
187
|
batch_results.append(response)
|
|
@@ -196,27 +194,27 @@ Format your response as a clear summary of findings from this batch."""
|
|
|
196
194
|
batch_findings = '\n\n'.join(f'Batch {i+1}:\n{result}' for i, result in enumerate(batch_results))
|
|
197
195
|
separator = '-' * 40
|
|
198
196
|
|
|
199
|
-
synthesis_prompt = f"""
|
|
197
|
+
synthesis_prompt = f"""请通过综合多个批次的搜索结果,为原始问题提供一个全面的回答。
|
|
200
198
|
|
|
201
|
-
|
|
199
|
+
原始问题: {question}
|
|
202
200
|
|
|
203
|
-
|
|
201
|
+
各批次的发现:
|
|
204
202
|
{separator}
|
|
205
203
|
{batch_findings}
|
|
206
204
|
{separator}
|
|
207
205
|
|
|
208
|
-
|
|
209
|
-
1.
|
|
210
|
-
2.
|
|
211
|
-
3.
|
|
212
|
-
4.
|
|
213
|
-
5.
|
|
206
|
+
请综合出一个最终答案,要求:
|
|
207
|
+
1. 整合所有批次的关键见解
|
|
208
|
+
2. 解决不同来源之间的矛盾
|
|
209
|
+
3. 保持清晰的来源归属
|
|
210
|
+
4. 承认任何剩余的不确定性
|
|
211
|
+
5. 提供对原始问题的连贯完整的回答"""
|
|
214
212
|
|
|
215
213
|
final_response = self.model.chat_until_success(synthesis_prompt)
|
|
216
214
|
return final_response
|
|
217
215
|
|
|
218
216
|
except Exception as e:
|
|
219
|
-
return f"
|
|
217
|
+
return f"信息提取失败:{str(e)}"
|
|
220
218
|
|
|
221
219
|
def execute(self, args: Dict) -> Dict[str, Any]:
|
|
222
220
|
"""Execute search and extract information"""
|
|
@@ -238,18 +236,60 @@ Please synthesize a final answer that:
|
|
|
238
236
|
"stderr": "No search results found"
|
|
239
237
|
}
|
|
240
238
|
|
|
239
|
+
# Read webpages in parallel using ThreadPoolExecutor
|
|
241
240
|
contents = []
|
|
242
|
-
|
|
241
|
+
|
|
242
|
+
# Print starting message
|
|
243
|
+
PrettyOutput.print(f"开始并行读取 {len(results)} 个网页结果...", OutputType.INFO)
|
|
244
|
+
|
|
245
|
+
def fetch_webpage(result_info):
|
|
246
|
+
"""Function to fetch a single webpage in a separate thread"""
|
|
247
|
+
idx, result = result_info
|
|
243
248
|
try:
|
|
244
|
-
|
|
249
|
+
# Removed progress print here to avoid mixed output
|
|
245
250
|
webpage_result = self.webpage_tool.execute({"url": result["href"]})
|
|
246
251
|
if webpage_result["success"]:
|
|
247
|
-
|
|
248
|
-
|
|
252
|
+
return idx, result, webpage_result["stdout"], True
|
|
253
|
+
return idx, result, None, False
|
|
249
254
|
except Exception as e:
|
|
250
|
-
|
|
251
|
-
|
|
255
|
+
return idx, result, str(e), False
|
|
256
|
+
|
|
257
|
+
# Use ThreadPoolExecutor for parallel processing
|
|
258
|
+
processed_results = []
|
|
259
|
+
with yaspin(text="正在并行读取网页内容...", color="cyan") as spinner:
|
|
260
|
+
with concurrent.futures.ThreadPoolExecutor(max_workers=get_thread_count()) as executor:
|
|
261
|
+
# Submit all webpage fetch tasks
|
|
262
|
+
future_to_result = {
|
|
263
|
+
executor.submit(fetch_webpage, (i, result)): i
|
|
264
|
+
for i, result in enumerate(results)
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
# Collect results as they complete
|
|
268
|
+
for future in concurrent.futures.as_completed(future_to_result):
|
|
269
|
+
processed_results.append(future.result())
|
|
270
|
+
# Update spinner with current progress
|
|
271
|
+
spinner.text = f"正在并行读取网页内容... ({len(processed_results)}/{len(results)})"
|
|
272
|
+
|
|
273
|
+
spinner.text = "网页内容读取完成"
|
|
274
|
+
spinner.ok("✅")
|
|
252
275
|
|
|
276
|
+
# Sort results by original index to maintain ordering
|
|
277
|
+
processed_results.sort(key=lambda x: x[0])
|
|
278
|
+
|
|
279
|
+
# Print results in order and add to contents
|
|
280
|
+
PrettyOutput.section("搜索结果概览", OutputType.INFO)
|
|
281
|
+
|
|
282
|
+
output = []
|
|
283
|
+
for idx, result, content, success in processed_results:
|
|
284
|
+
if success:
|
|
285
|
+
output.append(f"✅ 读取结果 {idx+1}/{len(results)} 完成: {result['title']} - {result['href']}")
|
|
286
|
+
contents.append(f"\nSource {idx+1}: {result['href']}\n")
|
|
287
|
+
contents.append(content)
|
|
288
|
+
else:
|
|
289
|
+
output.append(f"❌ 读取结果 {idx+1}/{len(results)} 失败: {result['title']} - {result['href']}")
|
|
290
|
+
|
|
291
|
+
PrettyOutput.print("\n".join(output), OutputType.INFO)
|
|
292
|
+
|
|
253
293
|
if not contents:
|
|
254
294
|
return {
|
|
255
295
|
"success": False,
|
|
@@ -262,10 +302,13 @@ Please synthesize a final answer that:
|
|
|
262
302
|
analysis = self._extract_info(contents, question)
|
|
263
303
|
spinner.text = "信息提取完成"
|
|
264
304
|
spinner.ok("✅")
|
|
305
|
+
|
|
306
|
+
output = f"分析结果:\n\n{analysis}"
|
|
307
|
+
PrettyOutput.print(output, OutputType.SUCCESS)
|
|
265
308
|
|
|
266
309
|
return {
|
|
267
310
|
"success": True,
|
|
268
|
-
"stdout":
|
|
311
|
+
"stdout": output,
|
|
269
312
|
"stderr": ""
|
|
270
313
|
}
|
|
271
314
|
|
|
@@ -7,6 +7,7 @@ from typing import Dict, Any
|
|
|
7
7
|
|
|
8
8
|
from yaspin import yaspin
|
|
9
9
|
from jarvis.jarvis_platform.registry import PlatformRegistry
|
|
10
|
+
from jarvis.jarvis_utils.utils import ct, ot
|
|
10
11
|
|
|
11
12
|
class ToolGenerator:
|
|
12
13
|
"""工具生成器类,用于自动创建与Jarvis系统集成的新工具"""
|
|
@@ -84,7 +85,7 @@ class ToolGenerator:
|
|
|
84
85
|
tools_dir.mkdir(parents=True, exist_ok=True)
|
|
85
86
|
tool_file = tools_dir / f"{tool_name}.py"
|
|
86
87
|
|
|
87
|
-
with open(tool_file, "w") as f:
|
|
88
|
+
with open(tool_file, "w", errors="ignore") as f:
|
|
88
89
|
f.write(implementation)
|
|
89
90
|
spinner.text = "工具保存完成"
|
|
90
91
|
spinner.ok("✅")
|
|
@@ -112,8 +113,7 @@ class ToolGenerator:
|
|
|
112
113
|
Returns:
|
|
113
114
|
格式化后的提示字符串
|
|
114
115
|
"""
|
|
115
|
-
example_code = '''
|
|
116
|
-
<TOOL>
|
|
116
|
+
example_code = ot("TOOL")+'''
|
|
117
117
|
from typing import Dict, Any
|
|
118
118
|
from jarvis.utils import OutputType, PrettyOutput
|
|
119
119
|
from jarvis.jarvis_platform.registry import PlatformRegistry
|
|
@@ -163,8 +163,7 @@ class CustomTool:
|
|
|
163
163
|
"stdout": "",
|
|
164
164
|
"stderr": str(e)
|
|
165
165
|
}
|
|
166
|
-
|
|
167
|
-
'''
|
|
166
|
+
''' + ct("TOOL")
|
|
168
167
|
|
|
169
168
|
return f'''创建一个与Jarvis系统集成的Python工具类。请遵循以下要求:
|
|
170
169
|
1. 类名: {tool_name.capitalize()}Tool
|
|
@@ -183,9 +182,9 @@ class CustomTool:
|
|
|
183
182
|
8. 仅返回Python实现代码
|
|
184
183
|
9. 代码应该是完整且可直接使用的
|
|
185
184
|
10. 按照以下格式输出代码:
|
|
186
|
-
|
|
185
|
+
{ot("TOOL")}
|
|
187
186
|
{example_code}
|
|
188
|
-
|
|
187
|
+
{ct("TOOL")}
|
|
189
188
|
|
|
190
189
|
示例:
|
|
191
190
|
{example_code}
|
|
@@ -199,8 +198,7 @@ class CustomTool:
|
|
|
199
198
|
Returns:
|
|
200
199
|
提取到的Python代码字符串
|
|
201
200
|
"""
|
|
202
|
-
|
|
203
|
-
sm = re.search(r'<TOOL>(.*?)</TOOL>', response, re.DOTALL)
|
|
201
|
+
sm = re.search(ot("TOOL")+r'(.*?)'+ct("TOOL"), response, re.DOTALL)
|
|
204
202
|
if sm:
|
|
205
203
|
return sm.group(1)
|
|
206
204
|
return ""
|
jarvis/jarvis_utils/__init__.py
CHANGED
jarvis/jarvis_utils/config.py
CHANGED
|
@@ -11,10 +11,10 @@ import os
|
|
|
11
11
|
"""
|
|
12
12
|
def get_max_token_count() -> int:
|
|
13
13
|
"""
|
|
14
|
-
|
|
14
|
+
获取模型允许的最大token数量。
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
int:
|
|
16
|
+
返回:
|
|
17
|
+
int: 模型能处理的最大token数量。
|
|
18
18
|
"""
|
|
19
19
|
return int(os.getenv('JARVIS_MAX_TOKEN_COUNT', '131072')) # 默认128k
|
|
20
20
|
|
|
@@ -172,3 +172,67 @@ def is_confirm_before_apply_patch() -> bool:
|
|
|
172
172
|
bool: 如果需要确认则返回True,默认为False
|
|
173
173
|
"""
|
|
174
174
|
return os.getenv('JARVIS_CONFIRM_BEFORE_APPLY_PATCH', 'false') == 'true'
|
|
175
|
+
|
|
176
|
+
def get_rag_ignored_paths() -> list:
|
|
177
|
+
"""
|
|
178
|
+
获取RAG索引时需要忽略的路径列表。
|
|
179
|
+
|
|
180
|
+
首先尝试从.jarvis/rag_ignore.txt文件中读取,
|
|
181
|
+
如果该文件不存在,则返回默认忽略列表。
|
|
182
|
+
|
|
183
|
+
返回:
|
|
184
|
+
list: 忽略路径的列表,默认包含常见忽略路径
|
|
185
|
+
"""
|
|
186
|
+
# 默认忽略路径
|
|
187
|
+
default_ignored = [
|
|
188
|
+
'.git',
|
|
189
|
+
'__pycache__',
|
|
190
|
+
'node_modules',
|
|
191
|
+
'.jarvis',
|
|
192
|
+
'.jarvis-*',
|
|
193
|
+
'target',
|
|
194
|
+
'venv',
|
|
195
|
+
'env',
|
|
196
|
+
'.env',
|
|
197
|
+
'.venv',
|
|
198
|
+
'.idea',
|
|
199
|
+
'.vscode',
|
|
200
|
+
'dist',
|
|
201
|
+
'build',
|
|
202
|
+
'*.pyc',
|
|
203
|
+
'*.pyo',
|
|
204
|
+
'*.so',
|
|
205
|
+
'*.o',
|
|
206
|
+
'*.a',
|
|
207
|
+
'*.pyd',
|
|
208
|
+
'*.dll',
|
|
209
|
+
'*.exe',
|
|
210
|
+
'*.bin',
|
|
211
|
+
'*.obj',
|
|
212
|
+
'*.out',
|
|
213
|
+
'*.jpg',
|
|
214
|
+
'*.jpeg',
|
|
215
|
+
'*.png',
|
|
216
|
+
'*.gif',
|
|
217
|
+
'*.tiff',
|
|
218
|
+
'*.pdf',
|
|
219
|
+
'*.zip',
|
|
220
|
+
'*.tar',
|
|
221
|
+
'*.tar.gz',
|
|
222
|
+
'*.gz',
|
|
223
|
+
'*.bz2',
|
|
224
|
+
'*.xz',
|
|
225
|
+
'*.rar'
|
|
226
|
+
]
|
|
227
|
+
|
|
228
|
+
# 尝试从配置文件中读取
|
|
229
|
+
try:
|
|
230
|
+
config_path = os.path.join('.jarvis', 'rag_ignore.txt')
|
|
231
|
+
if os.path.exists(config_path):
|
|
232
|
+
with open(config_path, 'r') as f:
|
|
233
|
+
custom_ignored = [line.strip() for line in f if line.strip() and not line.startswith('#')]
|
|
234
|
+
return custom_ignored
|
|
235
|
+
except Exception:
|
|
236
|
+
pass
|
|
237
|
+
|
|
238
|
+
return default_ignored
|