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.
Files changed (72) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/__init__.py +71 -38
  3. jarvis/jarvis_agent/builtin_input_handler.py +73 -0
  4. jarvis/{jarvis_code_agent → jarvis_agent}/file_input_handler.py +1 -1
  5. jarvis/jarvis_agent/main.py +1 -1
  6. jarvis/{jarvis_code_agent → jarvis_agent}/patch.py +77 -55
  7. jarvis/{jarvis_code_agent → jarvis_agent}/shell_input_handler.py +1 -2
  8. jarvis/jarvis_code_agent/code_agent.py +93 -88
  9. jarvis/jarvis_dev/main.py +335 -626
  10. jarvis/jarvis_git_squash/main.py +11 -32
  11. jarvis/jarvis_lsp/base.py +2 -26
  12. jarvis/jarvis_lsp/cpp.py +2 -14
  13. jarvis/jarvis_lsp/go.py +0 -13
  14. jarvis/jarvis_lsp/python.py +1 -30
  15. jarvis/jarvis_lsp/registry.py +10 -14
  16. jarvis/jarvis_lsp/rust.py +0 -12
  17. jarvis/jarvis_multi_agent/__init__.py +20 -29
  18. jarvis/jarvis_platform/ai8.py +7 -32
  19. jarvis/jarvis_platform/base.py +2 -7
  20. jarvis/jarvis_platform/kimi.py +3 -144
  21. jarvis/jarvis_platform/ollama.py +54 -68
  22. jarvis/jarvis_platform/openai.py +0 -4
  23. jarvis/jarvis_platform/oyi.py +0 -75
  24. jarvis/jarvis_platform/registry.py +1 -1
  25. jarvis/jarvis_platform/yuanbao.py +264 -0
  26. jarvis/jarvis_platform_manager/main.py +3 -3
  27. jarvis/jarvis_rag/file_processors.py +138 -0
  28. jarvis/jarvis_rag/main.py +1305 -425
  29. jarvis/jarvis_tools/ask_codebase.py +227 -41
  30. jarvis/jarvis_tools/code_review.py +229 -166
  31. jarvis/jarvis_tools/create_code_agent.py +76 -72
  32. jarvis/jarvis_tools/create_sub_agent.py +32 -15
  33. jarvis/jarvis_tools/execute_python_script.py +58 -0
  34. jarvis/jarvis_tools/execute_shell.py +15 -28
  35. jarvis/jarvis_tools/execute_shell_script.py +2 -2
  36. jarvis/jarvis_tools/file_analyzer.py +271 -0
  37. jarvis/jarvis_tools/file_operation.py +3 -3
  38. jarvis/jarvis_tools/find_caller.py +213 -0
  39. jarvis/jarvis_tools/find_symbol.py +211 -0
  40. jarvis/jarvis_tools/function_analyzer.py +248 -0
  41. jarvis/jarvis_tools/git_commiter.py +89 -70
  42. jarvis/jarvis_tools/lsp_find_definition.py +83 -67
  43. jarvis/jarvis_tools/lsp_find_references.py +62 -46
  44. jarvis/jarvis_tools/lsp_get_diagnostics.py +90 -74
  45. jarvis/jarvis_tools/methodology.py +89 -48
  46. jarvis/jarvis_tools/project_analyzer.py +220 -0
  47. jarvis/jarvis_tools/read_code.py +24 -3
  48. jarvis/jarvis_tools/read_webpage.py +195 -81
  49. jarvis/jarvis_tools/registry.py +132 -11
  50. jarvis/jarvis_tools/search_web.py +73 -30
  51. jarvis/jarvis_tools/tool_generator.py +7 -9
  52. jarvis/jarvis_utils/__init__.py +1 -0
  53. jarvis/jarvis_utils/config.py +67 -3
  54. jarvis/jarvis_utils/embedding.py +344 -45
  55. jarvis/jarvis_utils/git_utils.py +18 -2
  56. jarvis/jarvis_utils/input.py +7 -4
  57. jarvis/jarvis_utils/methodology.py +379 -7
  58. jarvis/jarvis_utils/output.py +5 -3
  59. jarvis/jarvis_utils/utils.py +62 -10
  60. {jarvis_ai_assistant-0.1.130.dist-info → jarvis_ai_assistant-0.1.132.dist-info}/METADATA +3 -4
  61. jarvis_ai_assistant-0.1.132.dist-info/RECORD +82 -0
  62. {jarvis_ai_assistant-0.1.130.dist-info → jarvis_ai_assistant-0.1.132.dist-info}/entry_points.txt +2 -0
  63. jarvis/jarvis_c2rust/c2rust.yaml +0 -734
  64. jarvis/jarvis_code_agent/builtin_input_handler.py +0 -43
  65. jarvis/jarvis_codebase/__init__.py +0 -0
  66. jarvis/jarvis_codebase/main.py +0 -1011
  67. jarvis/jarvis_tools/lsp_get_document_symbols.py +0 -87
  68. jarvis/jarvis_tools/lsp_prepare_rename.py +0 -130
  69. jarvis_ai_assistant-0.1.130.dist-info/RECORD +0 -79
  70. {jarvis_ai_assistant-0.1.130.dist-info → jarvis_ai_assistant-0.1.132.dist-info}/LICENSE +0 -0
  71. {jarvis_ai_assistant-0.1.130.dist-info → jarvis_ai_assistant-0.1.132.dist-info}/WHEEL +0 -0
  72. {jarvis_ai_assistant-0.1.130.dist-info → jarvis_ai_assistant-0.1.132.dist-info}/top_level.txt +0 -0
jarvis/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  """Jarvis AI Assistant"""
2
2
 
3
- __version__ = "0.1.130"
3
+ __version__ = "0.1.132"
@@ -4,11 +4,16 @@ from typing import Any, Callable, List, Optional, Tuple, Union
4
4
  from prompt_toolkit import prompt
5
5
  import yaml
6
6
  from yaspin import yaspin
7
+ import platform
8
+ import datetime
7
9
 
8
10
  from jarvis.jarvis_agent.output_handler import OutputHandler
11
+ from jarvis.jarvis_agent.builtin_input_handler import builtin_input_handler
12
+ from jarvis.jarvis_agent.file_input_handler import file_input_handler
13
+ from jarvis.jarvis_agent.patch import PatchOutputHandler
14
+ from jarvis.jarvis_agent.shell_input_handler import shell_input_handler
9
15
  from jarvis.jarvis_platform.base import BasePlatform
10
16
  from jarvis.jarvis_platform.registry import PlatformRegistry
11
- from jarvis.jarvis_tools.registry import ToolRegistry
12
17
  from jarvis.jarvis_utils.output import PrettyOutput, OutputType
13
18
  from jarvis.jarvis_utils.embedding import get_context_token_count
14
19
  from jarvis.jarvis_utils.config import is_auto_complete, is_execute_tool_confirm, is_need_summary, is_record_methodology, is_use_methodology
@@ -16,7 +21,7 @@ from jarvis.jarvis_utils.methodology import load_methodology
16
21
  from jarvis.jarvis_utils.globals import make_agent_name, set_agent, delete_agent
17
22
  from jarvis.jarvis_utils.input import get_multiline_input
18
23
  from jarvis.jarvis_utils.config import get_max_token_count
19
- from jarvis.jarvis_utils.utils import init_env
24
+ from jarvis.jarvis_utils.utils import ot, init_env
20
25
  from jarvis.jarvis_utils.utils import user_confirm
21
26
  import os
22
27
 
@@ -30,6 +35,18 @@ class Agent:
30
35
  """
31
36
  self.summary_prompt = summary_prompt
32
37
 
38
+ def clear(self):
39
+ """清除当前对话历史,保留系统消息。
40
+
41
+ 该方法将:
42
+ 1. 调用模型的delete_chat方法清除对话历史
43
+ 2. 重置对话长度计数器
44
+ 3. 清空当前提示
45
+ """
46
+ self.model.delete_chat() # type: ignore
47
+ self.conversation_length = 0
48
+ self.prompt = ""
49
+
33
50
  def __del__(self):
34
51
  delete_agent(self.name)
35
52
 
@@ -70,6 +87,7 @@ class Agent:
70
87
 
71
88
  self.model.set_suppress_output(False)
72
89
 
90
+ from jarvis.jarvis_tools.registry import ToolRegistry
73
91
  self.output_handler = output_handler if output_handler else [ToolRegistry()]
74
92
  self.multiline_inputer = multiline_inputer if multiline_inputer else get_multiline_input
75
93
 
@@ -126,7 +144,7 @@ class Agent:
126
144
  # 添加工具使用总结
127
145
  action_prompt += """
128
146
  # ❗ 重要操作使用规则
129
- 1. 一次只使用一个操作
147
+ 1. 一次对话只能使用一个操作,否则会出错
130
148
  2. 严格按照每个操作的格式执行
131
149
  3. 等待操作结果后再进行下一个操作
132
150
  4. 处理完结果后再调用新的操作
@@ -135,10 +153,10 @@ class Agent:
135
153
 
136
154
  complete_prompt = ""
137
155
  if self.auto_complete:
138
- complete_prompt = """
156
+ complete_prompt = f"""
139
157
  ## 任务完成
140
158
  当任务完成时,你应该打印以下信息:
141
- <!!!COMPLETE!!!>
159
+ {ot("!!!COMPLETE!!!")}
142
160
  """
143
161
 
144
162
  self.model.set_system_message(f"""
@@ -152,7 +170,7 @@ class Agent:
152
170
 
153
171
 
154
172
 
155
- def _call_model(self, message: str) -> str:
173
+ def _call_model(self, message: str, need_complete: bool = False) -> str:
156
174
  """调用AI模型并实现重试逻辑。
157
175
 
158
176
  参数:
@@ -168,6 +186,21 @@ class Agent:
168
186
  message, need_return = handler(message, self)
169
187
  if need_return:
170
188
  return message
189
+
190
+ # 添加输出简洁性指令
191
+ actions = '、'.join([o.name() for o in self.output_handler])
192
+ message += f"\n\n系统指令:请严格输出且仅输出一个操作的完整调用格式,不要输出多个操作;需要输出解释、分析和思考过程。确保输出格式正确且可直接执行。每次响应必须且只能包含一个操作。可用的操作:{actions}"
193
+ if need_complete and self.auto_complete:
194
+ message += f"\n\n如果任务已完成,说明完成原因,并输出{ot('!!!COMPLETE!!!')}"
195
+ else:
196
+ message += f"\n\n如果任务已完成,只需简洁地说明完成原因。"
197
+ # 累加对话长度
198
+ self.conversation_length += get_context_token_count(message)
199
+
200
+ if self.conversation_length > self.max_token_count:
201
+ self._summarize_and_clear_history()
202
+ self.conversation_length += get_context_token_count(message)
203
+
171
204
  print("🤖 模型思考:")
172
205
  return self.model.chat_until_success(message) # type: ignore
173
206
 
@@ -202,7 +235,9 @@ class Agent:
202
235
 
203
236
  try:
204
237
  with spinner.hidden():
205
- summary = self._call_model(self.prompt + "\n" + prompt)
238
+ summary = self.model.chat_until_success(self.prompt + "\n" + prompt) # type: ignore
239
+
240
+ self.model.delete_chat() # type: ignore
206
241
 
207
242
  # 清空当前对话历史,但保留系统消息
208
243
  self.conversation_length = 0 # Reset conversation length
@@ -262,11 +297,13 @@ class Agent:
262
297
  如果你认为不需要方法论,请解释原因。
263
298
  方法论应适用于通用场景,不要包含任务特定信息,如代码提交信息等。
264
299
  方法论应包含:问题重述、最优解决方案、注意事项(如有),除此之外不要包含其他内容。
300
+ 方法论中仅记录有实际意义的流程,不要记录执行过程中的错误或无效尝试,只保留最终有效的解决步骤。
301
+ 确保方法论内容严格按照本次任务的成功执行路径编写,保证它对未来类似问题的解决具有指导意义。
265
302
  只输出方法论工具调用指令,或不生成方法论的解释。不要输出其他内容。
266
303
  """
267
304
  self.prompt = analysis_prompt
268
305
  with spinner.hidden():
269
- response = self._call_model(self.prompt)
306
+ response = self.model.chat_until_success(self.prompt) # type: ignore
270
307
 
271
308
  with spinner.hidden():
272
309
  self._call_tools(response)
@@ -281,7 +318,7 @@ class Agent:
281
318
  with yaspin(text="正在生成总结...", color="cyan") as spinner:
282
319
  self.prompt = self.summary_prompt
283
320
  with spinner.hidden():
284
- ret = self._call_model(self.prompt)
321
+ ret = self.model.chat_until_success(self.prompt) # type: ignore
285
322
  spinner.text = "总结生成完成"
286
323
  spinner.ok("✅")
287
324
  return ret
@@ -310,17 +347,11 @@ class Agent:
310
347
 
311
348
  while True:
312
349
  try:
313
- # 累加对话长度
314
- self.conversation_length += get_context_token_count(self.prompt)
315
-
316
350
  # 如果对话历史长度超过限制,在提示中添加提醒
317
- if self.conversation_length > self.max_token_count:
318
- current_response = self._summarize_and_clear_history()
319
- continue
320
- else:
321
- current_response = self._call_model(self.prompt)
322
- self.prompt = ""
323
- self.conversation_length += get_context_token_count(current_response)
351
+
352
+ current_response = self._call_model(self.prompt, True)
353
+ self.prompt = ""
354
+ self.conversation_length += get_context_token_count(current_response)
324
355
 
325
356
  need_return, self.prompt = self._call_tools(current_response)
326
357
 
@@ -330,7 +361,7 @@ class Agent:
330
361
  if self.prompt:
331
362
  continue
332
363
 
333
- if self.auto_complete and "<!!!COMPLETE!!!>" in current_response:
364
+ if self.auto_complete and ot("!!!COMPLETE!!!") in current_response:
334
365
  return self._complete_task()
335
366
 
336
367
  # 获取用户输入
@@ -375,7 +406,7 @@ def _load_tasks() -> dict:
375
406
  if os.path.exists(user_jarvis):
376
407
  with yaspin(text=f"从{user_jarvis}加载预定义任务...", color="cyan") as spinner:
377
408
  try:
378
- with open(user_jarvis, "r", encoding="utf-8") as f:
409
+ with open(user_jarvis, "r", encoding="utf-8", errors="ignore") as f:
379
410
  user_tasks = yaml.safe_load(f)
380
411
 
381
412
  if isinstance(user_tasks, dict):
@@ -393,7 +424,7 @@ def _load_tasks() -> dict:
393
424
  if os.path.exists(".jarvis/pre-command"):
394
425
  with yaspin(text=f"从{os.path.abspath('.jarvis/pre-command')}加载预定义任务...", color="cyan") as spinner:
395
426
  try:
396
- with open(".jarvis/pre-command", "r", encoding="utf-8") as f:
427
+ with open(".jarvis/pre-command", "r", encoding="utf-8", errors="ignore") as f:
397
428
  local_tasks = yaml.safe_load(f)
398
429
 
399
430
  if isinstance(local_tasks, dict):
@@ -449,7 +480,7 @@ def _select_task(tasks: dict) -> str:
449
480
  PrettyOutput.print(f"选择任务失败: {str(e)}", OutputType.ERROR)
450
481
  continue
451
482
 
452
- origin_agent_system_prompt = """
483
+ origin_agent_system_prompt = f"""
453
484
  # 🏛️ 操作背景故事
454
485
  你是第三代 Jarvis AI,在前几代版本灾难性失败后创建:
455
486
  - Jarvis v1 (2022): 由于并行工具执行导致系统过载而被停用
@@ -467,10 +498,8 @@ origin_agent_system_prompt = """
467
498
 
468
499
  # 🔥 绝对行动要求
469
500
  1. 每个响应必须包含且仅包含一个工具调用
470
- 2. 唯一例外:使用 <!!!COMPLETE!!!> 命令
501
+ 2. 唯一例外:任务结束
471
502
  3. 空响应会触发致命错误
472
- 4. 不能处于"等待用户输入"状态
473
- 5. 任何行动都不能使用完成命令
474
503
 
475
504
  # 🚫 违规示例
476
505
  - 没有工具调用的分析 → 永久挂起
@@ -500,8 +529,6 @@ origin_agent_system_prompt = """
500
529
  4. 任务完成
501
530
  - 验证目标完成情况
502
531
  - 如有价值则记录方法论
503
- - 使用完成命令结束任务
504
- → 必须使用 <!!!COMPLETE!!!>
505
532
 
506
533
  # 📑 方法论模板
507
534
  ```markdown
@@ -540,6 +567,13 @@ origin_agent_system_prompt = """
540
567
  8. 必须记录有价值的方法论
541
568
  9. 违反操作协议将导致系统崩溃
542
569
  10. 空响应会触发永久挂起
570
+
571
+ # 系统信息:
572
+ {platform.platform()}
573
+ {platform.version()}
574
+
575
+ # 当前时间
576
+ {datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
543
577
  """
544
578
 
545
579
  def main():
@@ -552,8 +586,9 @@ def main():
552
586
  args = parser.parse_args()
553
587
 
554
588
  try:
589
+ from jarvis.jarvis_tools.registry import ToolRegistry
555
590
  # 获取全局模型实例
556
- agent = Agent(system_prompt=origin_agent_system_prompt, platform=args.platform, model_name=args.model, output_handler=[ToolRegistry()])
591
+ agent = Agent(system_prompt=origin_agent_system_prompt, platform=args.platform, model_name=args.model, input_handler=[file_input_handler, shell_input_handler, builtin_input_handler] ,output_handler=[ToolRegistry(), PatchOutputHandler()])
557
592
 
558
593
  # 加载预定义任务
559
594
  tasks = _load_tasks()
@@ -564,15 +599,13 @@ def main():
564
599
  agent.run(selected_task)
565
600
  return 0
566
601
 
567
- # 如果没有选择预定义任务,进入交互模式
568
- while True:
569
- try:
570
- user_input = get_multiline_input("请输入你的任务(输入空行退出):")
571
- if not user_input:
572
- break
573
- agent.run(user_input)
574
- except Exception as e:
575
- PrettyOutput.print(f"错误: {str(e)}", OutputType.ERROR)
602
+ try:
603
+ user_input = get_multiline_input("请输入你的任务(输入空行退出):")
604
+ if not user_input:
605
+ return 0
606
+ agent.run(user_input)
607
+ except Exception as e:
608
+ PrettyOutput.print(f"错误: {str(e)}", OutputType.ERROR)
576
609
 
577
610
  except Exception as e:
578
611
  PrettyOutput.print(f"初始化错误: {str(e)}", OutputType.ERROR)
@@ -0,0 +1,73 @@
1
+ import re
2
+ from typing import Any, Tuple
3
+
4
+
5
+
6
+ def builtin_input_handler(user_input: str, agent: Any) -> Tuple[str, bool]:
7
+ """
8
+ 处理内置的特殊输入标记,并追加相应的提示词
9
+
10
+ 参数:
11
+ user_input: 用户输入
12
+ agent: 代理对象
13
+
14
+ 返回:
15
+ Tuple[str, bool]: 处理后的输入和是否需要进一步处理
16
+ """
17
+ # 查找特殊标记
18
+ special_tags = re.findall(r"'<([^>]+)>'", user_input)
19
+
20
+ if not special_tags:
21
+ return user_input, False
22
+
23
+ # 使用集合去重
24
+ processed_tags = set()
25
+ # 处理每个标记
26
+ for tag in special_tags:
27
+ if tag in processed_tags:
28
+ continue
29
+ processed_tags.add(tag)
30
+
31
+ if tag == "CodeBase":
32
+ user_input = user_input.replace(f"'<{tag}>'", "")
33
+ user_input += """
34
+ 请使用ask_codebase工具查询代码库,可以使用的提问格式包括:
35
+ 1. 与xxx功能相关的文件有哪些?
36
+ 2. 要实现xxx,应该要修改哪些文件?
37
+ 3. xxx功能是怎么实现的?
38
+ 4. xxx模块的入口函数是什么?
39
+ 5. xxx功能的测试用例在哪里?
40
+ """
41
+ elif tag == "Web":
42
+ user_input = user_input.replace(f"'<{tag}>'", "")
43
+ user_input += """
44
+ 请使用search_web工具进行网页搜索,可以使用的提问格式包括:
45
+ 1. xxx技术的最新发展是什么?
46
+ 2. xxx框架的官方文档在哪里?
47
+ 3. xxx库的GitHub仓库地址是什么?
48
+ 4. xxx问题的解决方案有哪些?
49
+ 5. xxx概念的详细解释是什么?
50
+ """
51
+ elif tag == "RAG":
52
+ user_input = user_input.replace(f"'<{tag}>'", "")
53
+ user_input += """
54
+ 请使用rag工具进行知识库检索,可以使用的提问格式包括:
55
+ 1. 关于xxx的知识点有哪些?
56
+ 2. xxx的最佳实践是什么?
57
+ 3. xxx的实现方案有哪些?
58
+ 4. xxx的相关案例有哪些?
59
+ 5. xxx的技术细节是什么?
60
+ """
61
+ elif tag == "Summary":
62
+ user_input = user_input.replace(f"'<{tag}>'", "")
63
+ agent._summarize_and_clear_history()
64
+ if not user_input.strip():
65
+ return "", True
66
+ elif tag == "Clear":
67
+ user_input = user_input.replace(f"'<{tag}>'", "")
68
+ agent.clear()
69
+ if not user_input.strip():
70
+ return "", True
71
+ # 移除对未知标记的警告输出
72
+
73
+ return user_input, False
@@ -30,7 +30,7 @@ def file_input_handler(user_input: str, agent: Any) -> Tuple[str, bool]:
30
30
 
31
31
  # Handle special values and Python-style negative indices
32
32
  try:
33
- with open(file_path, 'r', encoding='utf-8') as f:
33
+ with open(file_path, 'r', encoding='utf-8', errors="ignore") as f:
34
34
  total_lines = len(f.readlines())
35
35
  except FileNotFoundError:
36
36
  PrettyOutput.print(f"文件不存在: {file_path}", OutputType.WARNING)
@@ -23,7 +23,7 @@ def load_config(config_path: str) -> dict:
23
23
  PrettyOutput.print(f"配置文件 {config_path} 不存在,使用默认配置", OutputType.WARNING)
24
24
  return {}
25
25
 
26
- with open(config_path, 'r', encoding='utf-8') as f:
26
+ with open(config_path, 'r', encoding='utf-8', errors="ignore") as f:
27
27
  try:
28
28
  config = yaml.safe_load(f)
29
29
  return config if config else {}