jarvis-ai-assistant 0.1.131__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.
Files changed (61) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/__init__.py +48 -29
  3. jarvis/jarvis_agent/patch.py +61 -43
  4. jarvis/jarvis_agent/shell_input_handler.py +1 -1
  5. jarvis/jarvis_code_agent/code_agent.py +87 -86
  6. jarvis/jarvis_dev/main.py +335 -626
  7. jarvis/jarvis_git_squash/main.py +10 -31
  8. jarvis/jarvis_multi_agent/__init__.py +19 -28
  9. jarvis/jarvis_platform/ai8.py +7 -32
  10. jarvis/jarvis_platform/base.py +2 -7
  11. jarvis/jarvis_platform/kimi.py +3 -144
  12. jarvis/jarvis_platform/ollama.py +54 -68
  13. jarvis/jarvis_platform/openai.py +0 -4
  14. jarvis/jarvis_platform/oyi.py +0 -75
  15. jarvis/jarvis_platform/yuanbao.py +264 -0
  16. jarvis/jarvis_rag/file_processors.py +138 -0
  17. jarvis/jarvis_rag/main.py +1305 -425
  18. jarvis/jarvis_tools/ask_codebase.py +205 -39
  19. jarvis/jarvis_tools/code_review.py +125 -99
  20. jarvis/jarvis_tools/execute_python_script.py +58 -0
  21. jarvis/jarvis_tools/execute_shell.py +13 -26
  22. jarvis/jarvis_tools/execute_shell_script.py +1 -1
  23. jarvis/jarvis_tools/file_analyzer.py +271 -0
  24. jarvis/jarvis_tools/file_operation.py +1 -1
  25. jarvis/jarvis_tools/find_caller.py +213 -0
  26. jarvis/jarvis_tools/find_symbol.py +211 -0
  27. jarvis/jarvis_tools/function_analyzer.py +248 -0
  28. jarvis/jarvis_tools/git_commiter.py +4 -4
  29. jarvis/jarvis_tools/methodology.py +89 -48
  30. jarvis/jarvis_tools/project_analyzer.py +220 -0
  31. jarvis/jarvis_tools/read_code.py +23 -2
  32. jarvis/jarvis_tools/read_webpage.py +195 -81
  33. jarvis/jarvis_tools/registry.py +132 -11
  34. jarvis/jarvis_tools/search_web.py +55 -10
  35. jarvis/jarvis_tools/tool_generator.py +6 -8
  36. jarvis/jarvis_utils/__init__.py +1 -0
  37. jarvis/jarvis_utils/config.py +67 -3
  38. jarvis/jarvis_utils/embedding.py +344 -45
  39. jarvis/jarvis_utils/git_utils.py +9 -1
  40. jarvis/jarvis_utils/input.py +7 -6
  41. jarvis/jarvis_utils/methodology.py +379 -7
  42. jarvis/jarvis_utils/output.py +5 -3
  43. jarvis/jarvis_utils/utils.py +59 -7
  44. {jarvis_ai_assistant-0.1.131.dist-info → jarvis_ai_assistant-0.1.132.dist-info}/METADATA +3 -2
  45. jarvis_ai_assistant-0.1.132.dist-info/RECORD +82 -0
  46. {jarvis_ai_assistant-0.1.131.dist-info → jarvis_ai_assistant-0.1.132.dist-info}/entry_points.txt +2 -0
  47. jarvis/jarvis_codebase/__init__.py +0 -0
  48. jarvis/jarvis_codebase/main.py +0 -1011
  49. jarvis/jarvis_tools/treesitter_analyzer.py +0 -331
  50. jarvis/jarvis_treesitter/README.md +0 -104
  51. jarvis/jarvis_treesitter/__init__.py +0 -20
  52. jarvis/jarvis_treesitter/database.py +0 -258
  53. jarvis/jarvis_treesitter/example.py +0 -115
  54. jarvis/jarvis_treesitter/grammar_builder.py +0 -182
  55. jarvis/jarvis_treesitter/language.py +0 -117
  56. jarvis/jarvis_treesitter/symbol.py +0 -31
  57. jarvis/jarvis_treesitter/tools_usage.md +0 -121
  58. jarvis_ai_assistant-0.1.131.dist-info/RECORD +0 -85
  59. {jarvis_ai_assistant-0.1.131.dist-info → jarvis_ai_assistant-0.1.132.dist-info}/LICENSE +0 -0
  60. {jarvis_ai_assistant-0.1.131.dist-info → jarvis_ai_assistant-0.1.132.dist-info}/WHEEL +0 -0
  61. {jarvis_ai_assistant-0.1.131.dist-info → jarvis_ai_assistant-0.1.132.dist-info}/top_level.txt +0 -0
@@ -13,20 +13,21 @@ from jarvis.jarvis_tools.base import Tool
13
13
  from jarvis.jarvis_utils.config import get_max_token_count
14
14
  from jarvis.jarvis_utils.embedding import get_context_token_count
15
15
  from jarvis.jarvis_utils.output import OutputType, PrettyOutput
16
+ from jarvis.jarvis_utils.utils import ct, ot, init_env
16
17
 
17
18
 
18
19
 
19
- tool_call_help = """
20
+ tool_call_help = f"""
20
21
  # 🛠️ 工具使用系统
21
22
  您正在使用一个需要精确格式和严格规则的工具执行系统。
22
23
 
23
24
  # 📋 工具调用格式
24
- <TOOL_CALL>
25
+ {ot("TOOL_CALL")}
25
26
  name: 工具名称
26
27
  arguments:
27
28
  param1: 值1
28
29
  param2: 值2
29
- </TOOL_CALL>
30
+ {ct("TOOL_CALL")}
30
31
 
31
32
  # ❗ 关键规则
32
33
  1. 每次只使用一个工具
@@ -53,12 +54,12 @@ arguments:
53
54
  # 📝 字符串参数格式
54
55
  始终使用 | 语法表示字符串参数:
55
56
 
56
- <TOOL_CALL>
57
+ {ot("TOOL_CALL")}
57
58
  name: execute_shell
58
59
  arguments:
59
60
  command: |
60
61
  git status --porcelain
61
- </TOOL_CALL>
62
+ {ct("TOOL_CALL")}
62
63
 
63
64
  # 💡 最佳实践
64
65
  - 准备好后立即开始执行
@@ -233,7 +234,7 @@ class ToolRegistry(OutputHandler):
233
234
  Exception: 如果工具调用缺少必要字段
234
235
  """
235
236
  # 将内容拆分为行
236
- data = re.findall(r'<TOOL_CALL>(.*?)</TOOL_CALL>', content, re.DOTALL)
237
+ data = re.findall(ot("TOOL_CALL")+r'(.*?)'+ct("TOOL_CALL"), content, re.DOTALL)
237
238
  ret = []
238
239
  for item in data:
239
240
  try:
@@ -270,18 +271,18 @@ class ToolRegistry(OutputHandler):
270
271
  name = tool_call["name"]
271
272
  args = tool_call["arguments"]
272
273
 
273
- tool_call_help = """
274
+ tool_call_help = f"""
274
275
  # 🛠️ 工具使用系统
275
276
  您正在使用一个需要精确格式和严格规则的工具执行系统。
276
277
 
277
278
  # 📋 工具调用格式
278
279
 
279
- <TOOL_CALL>
280
+ {ot("TOOL_CALL")}
280
281
  name: 工具名称
281
282
  arguments:
282
283
  param1: 值1
283
284
  param2: 值2
284
- </TOOL_CALL>
285
+ {ct("TOOL_CALL")}
285
286
 
286
287
  # ❗ 关键规则
287
288
  1. 每次只使用一个工具
@@ -308,12 +309,12 @@ arguments:
308
309
  # 📝 字符串参数格式
309
310
  始终使用 | 语法表示字符串参数:
310
311
 
311
- <TOOL_CALL>
312
+ {ot("TOOL_CALL")}
312
313
  name: execute_shell
313
314
  arguments:
314
315
  command: |
315
316
  git status --porcelain
316
- </TOOL_CALL>
317
+ {ct("TOOL_CALL")}
317
318
 
318
319
  # 💡 最佳实践
319
320
  - 准备好后立即开始执行
@@ -394,3 +395,123 @@ arguments:
394
395
  except Exception as e:
395
396
  PrettyOutput.print(f"工具执行失败:{str(e)}", OutputType.ERROR)
396
397
  return f"工具调用失败: {str(e)}"
398
+
399
+
400
+ def main():
401
+ """命令行工具入口,提供工具列表查看和工具调用功能"""
402
+ import argparse
403
+ import json
404
+
405
+ init_env()
406
+
407
+ parser = argparse.ArgumentParser(description='Jarvis 工具系统命令行界面')
408
+ subparsers = parser.add_subparsers(dest='command', help='命令')
409
+
410
+ # 列出工具子命令
411
+ list_parser = subparsers.add_parser('list', help='列出所有可用工具')
412
+ list_parser.add_argument('--json', action='store_true', help='以JSON格式输出')
413
+ list_parser.add_argument('--detailed', action='store_true', help='显示详细信息')
414
+
415
+ # 调用工具子命令
416
+ call_parser = subparsers.add_parser('call', help='调用指定工具')
417
+ call_parser.add_argument('tool_name', help='要调用的工具名称')
418
+ call_parser.add_argument('--args', type=str, help='工具参数 (JSON格式)')
419
+ call_parser.add_argument('--args-file', type=str, help='从文件加载工具参数 (JSON格式)')
420
+
421
+ args = parser.parse_args()
422
+
423
+ # 初始化工具注册表
424
+ registry = ToolRegistry()
425
+
426
+ if args.command == 'list':
427
+ tools = registry.get_all_tools()
428
+
429
+ if args.json:
430
+ if args.detailed:
431
+ print(json.dumps(tools, indent=2, ensure_ascii=False))
432
+ else:
433
+ simple_tools = [{"name": t["name"], "description": t["description"]} for t in tools]
434
+ print(json.dumps(simple_tools, indent=2, ensure_ascii=False))
435
+ else:
436
+ PrettyOutput.section("可用工具列表", OutputType.SYSTEM)
437
+ for tool in tools:
438
+ print(f"\n✅ {tool['name']}")
439
+ print(f" 描述: {tool['description']}")
440
+ if args.detailed:
441
+ print(f" 参数:")
442
+ params = tool['parameters'].get('properties', {})
443
+ required = tool['parameters'].get('required', [])
444
+ for param_name, param_info in params.items():
445
+ req_mark = "*" if param_name in required else ""
446
+ desc = param_info.get('description', '无描述')
447
+ print(f" - {param_name}{req_mark}: {desc}")
448
+
449
+ elif args.command == 'call':
450
+ tool_name = args.tool_name
451
+ tool = registry.get_tool(tool_name)
452
+
453
+ if not tool:
454
+ PrettyOutput.print(f"错误: 工具 '{tool_name}' 不存在", OutputType.ERROR)
455
+ available_tools = ", ".join([t["name"] for t in registry.get_all_tools()])
456
+ print(f"可用工具: {available_tools}")
457
+ return 1
458
+
459
+ # 获取参数
460
+ tool_args = {}
461
+ if args.args:
462
+ try:
463
+ tool_args = json.loads(args.args)
464
+ except json.JSONDecodeError:
465
+ PrettyOutput.print("错误: 参数必须是有效的JSON格式", OutputType.ERROR)
466
+ return 1
467
+
468
+ elif args.args_file:
469
+ try:
470
+ with open(args.args_file, 'r', encoding='utf-8') as f:
471
+ tool_args = json.load(f)
472
+ except (json.JSONDecodeError, FileNotFoundError) as e:
473
+ PrettyOutput.print(f"错误: 无法从文件加载参数: {str(e)}", OutputType.ERROR)
474
+ return 1
475
+
476
+ # 检查必需参数
477
+ required_params = tool.parameters.get('required', [])
478
+ missing_params = [p for p in required_params if p not in tool_args]
479
+
480
+ if missing_params:
481
+ PrettyOutput.print(f"错误: 缺少必需参数: {', '.join(missing_params)}", OutputType.ERROR)
482
+ print("\n参数说明:")
483
+ params = tool.parameters.get('properties', {})
484
+ for param_name in required_params:
485
+ param_info = params.get(param_name, {})
486
+ desc = param_info.get('description', '无描述')
487
+ print(f" - {param_name}: {desc}")
488
+ return 1
489
+
490
+ # 执行工具
491
+ with yaspin(text=f"正在执行工具 {tool_name}...").dots12:
492
+ result = registry.execute_tool(tool_name, tool_args)
493
+
494
+ # 显示结果
495
+ if result["success"]:
496
+ PrettyOutput.section(f"工具 {tool_name} 执行成功", OutputType.SUCCESS)
497
+ else:
498
+ PrettyOutput.section(f"工具 {tool_name} 执行失败", OutputType.ERROR)
499
+
500
+ if result.get("stdout"):
501
+ print("\n输出:")
502
+ print(result["stdout"])
503
+
504
+ if result.get("stderr"):
505
+ PrettyOutput.print("\n错误:", OutputType.ERROR)
506
+ print(result["stderr"])
507
+
508
+ return 0 if result["success"] else 1
509
+
510
+ else:
511
+ parser.print_help()
512
+
513
+ return 0
514
+
515
+
516
+ if __name__ == "__main__":
517
+ sys.exit(main())
@@ -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": 3
107
+ "default": 10
108
108
  }
109
109
  },
110
110
  "required": ["query", "question"]
@@ -236,18 +236,60 @@ class SearchTool:
236
236
  "stderr": "No search results found"
237
237
  }
238
238
 
239
+ # Read webpages in parallel using ThreadPoolExecutor
239
240
  contents = []
240
- for i, result in enumerate(results, 1):
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
241
248
  try:
242
- PrettyOutput.print(f"正在读取结果 {i}/{len(results)}... {result['title']} - {result['href']}", OutputType.PROGRESS)
249
+ # Removed progress print here to avoid mixed output
243
250
  webpage_result = self.webpage_tool.execute({"url": result["href"]})
244
251
  if webpage_result["success"]:
245
- contents.append(f"\nSource {i}: {result['href']}\n")
246
- contents.append(webpage_result["stdout"])
252
+ return idx, result, webpage_result["stdout"], True
253
+ return idx, result, None, False
247
254
  except Exception as e:
248
- PrettyOutput.print(f"读取结果失败 {i}: {str(e)}", OutputType.WARNING)
249
- continue
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("✅")
250
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
+
251
293
  if not contents:
252
294
  return {
253
295
  "success": False,
@@ -260,10 +302,13 @@ class SearchTool:
260
302
  analysis = self._extract_info(contents, question)
261
303
  spinner.text = "信息提取完成"
262
304
  spinner.ok("✅")
305
+
306
+ output = f"分析结果:\n\n{analysis}"
307
+ PrettyOutput.print(output, OutputType.SUCCESS)
263
308
 
264
309
  return {
265
310
  "success": True,
266
- "stdout": f"Search analysis results:\n\n{analysis}",
311
+ "stdout": output,
267
312
  "stderr": ""
268
313
  }
269
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系统集成的新工具"""
@@ -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
- </TOOL>
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
- <TOOL>
185
+ {ot("TOOL")}
187
186
  {example_code}
188
- </TOOL>
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
- # 查找第一个<TOOL>和</TOOL>标签之间的内容
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 ""
@@ -22,3 +22,4 @@ colorama.init()
22
22
  os.environ["TOKENIZERS_PARALLELISM"] = "false"
23
23
  # 安装rich traceback处理器以获得更好的错误信息
24
24
  install_rich_traceback()
25
+
@@ -11,10 +11,10 @@ import os
11
11
  """
12
12
  def get_max_token_count() -> int:
13
13
  """
14
- 获取API请求的最大token数量。
14
+ 获取模型允许的最大token数量。
15
15
 
16
- 返回:
17
- int: 最大token数量,默认为131072(128k)
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