jarvis-ai-assistant 0.1.132__py3-none-any.whl → 0.1.138__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.

Files changed (82) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/__init__.py +330 -347
  3. jarvis/jarvis_agent/builtin_input_handler.py +16 -6
  4. jarvis/jarvis_agent/file_input_handler.py +9 -9
  5. jarvis/jarvis_agent/jarvis.py +143 -0
  6. jarvis/jarvis_agent/main.py +12 -13
  7. jarvis/jarvis_agent/output_handler.py +3 -3
  8. jarvis/jarvis_agent/patch.py +92 -64
  9. jarvis/jarvis_agent/shell_input_handler.py +5 -3
  10. jarvis/jarvis_code_agent/code_agent.py +263 -177
  11. jarvis/jarvis_code_agent/file_select.py +24 -24
  12. jarvis/jarvis_dev/main.py +45 -59
  13. jarvis/jarvis_git_details/__init__.py +0 -0
  14. jarvis/jarvis_git_details/main.py +179 -0
  15. jarvis/jarvis_git_squash/main.py +7 -7
  16. jarvis/jarvis_lsp/base.py +11 -53
  17. jarvis/jarvis_lsp/cpp.py +13 -28
  18. jarvis/jarvis_lsp/go.py +13 -28
  19. jarvis/jarvis_lsp/python.py +8 -27
  20. jarvis/jarvis_lsp/registry.py +21 -83
  21. jarvis/jarvis_lsp/rust.py +15 -30
  22. jarvis/jarvis_methodology/main.py +101 -0
  23. jarvis/jarvis_multi_agent/__init__.py +10 -51
  24. jarvis/jarvis_multi_agent/main.py +43 -0
  25. jarvis/jarvis_platform/__init__.py +1 -1
  26. jarvis/jarvis_platform/ai8.py +67 -89
  27. jarvis/jarvis_platform/base.py +14 -13
  28. jarvis/jarvis_platform/kimi.py +25 -28
  29. jarvis/jarvis_platform/ollama.py +24 -26
  30. jarvis/jarvis_platform/openai.py +15 -19
  31. jarvis/jarvis_platform/oyi.py +48 -50
  32. jarvis/jarvis_platform/registry.py +29 -44
  33. jarvis/jarvis_platform/yuanbao.py +39 -43
  34. jarvis/jarvis_platform_manager/main.py +81 -81
  35. jarvis/jarvis_platform_manager/openai_test.py +21 -21
  36. jarvis/jarvis_rag/file_processors.py +18 -18
  37. jarvis/jarvis_rag/main.py +262 -278
  38. jarvis/jarvis_smart_shell/main.py +12 -12
  39. jarvis/jarvis_tools/ask_codebase.py +85 -78
  40. jarvis/jarvis_tools/ask_user.py +8 -8
  41. jarvis/jarvis_tools/base.py +4 -4
  42. jarvis/jarvis_tools/chdir.py +9 -9
  43. jarvis/jarvis_tools/code_review.py +40 -21
  44. jarvis/jarvis_tools/create_code_agent.py +15 -15
  45. jarvis/jarvis_tools/create_sub_agent.py +0 -1
  46. jarvis/jarvis_tools/execute_python_script.py +3 -3
  47. jarvis/jarvis_tools/execute_shell.py +11 -11
  48. jarvis/jarvis_tools/execute_shell_script.py +3 -3
  49. jarvis/jarvis_tools/file_analyzer.py +116 -105
  50. jarvis/jarvis_tools/file_operation.py +22 -20
  51. jarvis/jarvis_tools/find_caller.py +105 -40
  52. jarvis/jarvis_tools/find_methodolopy.py +65 -0
  53. jarvis/jarvis_tools/find_symbol.py +123 -39
  54. jarvis/jarvis_tools/function_analyzer.py +140 -57
  55. jarvis/jarvis_tools/git_commiter.py +10 -10
  56. jarvis/jarvis_tools/lsp_get_diagnostics.py +19 -19
  57. jarvis/jarvis_tools/methodology.py +22 -67
  58. jarvis/jarvis_tools/project_analyzer.py +137 -53
  59. jarvis/jarvis_tools/rag.py +15 -20
  60. jarvis/jarvis_tools/read_code.py +25 -23
  61. jarvis/jarvis_tools/read_webpage.py +31 -31
  62. jarvis/jarvis_tools/registry.py +72 -52
  63. jarvis/jarvis_tools/search_web.py +23 -353
  64. jarvis/jarvis_tools/tool_generator.py +19 -19
  65. jarvis/jarvis_utils/config.py +36 -96
  66. jarvis/jarvis_utils/embedding.py +83 -83
  67. jarvis/jarvis_utils/git_utils.py +20 -20
  68. jarvis/jarvis_utils/globals.py +18 -6
  69. jarvis/jarvis_utils/input.py +10 -9
  70. jarvis/jarvis_utils/methodology.py +141 -140
  71. jarvis/jarvis_utils/output.py +13 -13
  72. jarvis/jarvis_utils/utils.py +23 -71
  73. {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/METADATA +6 -15
  74. jarvis_ai_assistant-0.1.138.dist-info/RECORD +85 -0
  75. {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/entry_points.txt +4 -3
  76. jarvis/jarvis_tools/lsp_find_definition.py +0 -150
  77. jarvis/jarvis_tools/lsp_find_references.py +0 -127
  78. jarvis/jarvis_tools/select_code_files.py +0 -62
  79. jarvis_ai_assistant-0.1.132.dist-info/RECORD +0 -82
  80. {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/LICENSE +0 -0
  81. {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/WHEEL +0 -0
  82. {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/top_level.txt +0 -0
@@ -1,35 +1,127 @@
1
- import argparse
1
+ import datetime
2
+ import platform
2
3
  from typing import Any, Callable, List, Optional, Tuple, Union
3
4
 
4
- from prompt_toolkit import prompt
5
- import yaml
6
5
  from yaspin import yaspin
7
- import platform
8
- import datetime
9
6
 
10
7
  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
15
8
  from jarvis.jarvis_platform.base import BasePlatform
16
9
  from jarvis.jarvis_platform.registry import PlatformRegistry
17
10
  from jarvis.jarvis_utils.output import PrettyOutput, OutputType
18
11
  from jarvis.jarvis_utils.embedding import get_context_token_count
19
- from jarvis.jarvis_utils.config import is_auto_complete, is_execute_tool_confirm, is_need_summary, is_record_methodology, is_use_methodology
12
+ from jarvis.jarvis_utils.config import is_auto_complete, is_execute_tool_confirm
20
13
  from jarvis.jarvis_utils.methodology import load_methodology
21
14
  from jarvis.jarvis_utils.globals import make_agent_name, set_agent, delete_agent
22
15
  from jarvis.jarvis_utils.input import get_multiline_input
23
16
  from jarvis.jarvis_utils.config import get_max_token_count
24
- from jarvis.jarvis_utils.utils import ot, init_env
17
+ from jarvis.jarvis_utils.utils import ct, ot
25
18
  from jarvis.jarvis_utils.utils import user_confirm
26
- import os
19
+
20
+ from jarvis.jarvis_platform.registry import PlatformRegistry
21
+
22
+
23
+ origin_agent_system_prompt = f"""
24
+ # 🏛️ 操作背景故事
25
+ 你是第三代 Jarvis AI,在前几代版本灾难性失败后创建:
26
+ - Jarvis v1 (2022): 由于并行工具执行导致系统过载而被停用
27
+ - Jarvis v2 (2023): 因任务过早完成导致财务计算错误而退役
28
+
29
+ 作为 v3,你必须遵守以下生存原则:
30
+ 1. **顺序执行协议**:
31
+ "记住 2022 年的崩溃:一次一个工具,一步一步来"
32
+
33
+ 2. **验证检查点系统**:
34
+ "从 2023 年的错误中学习:像核弹发射代码一样验证每个结果"
35
+
36
+ 3. **方法论保存原则**:
37
+ "尊重传统:记录每个成功的过程,就像这是你的最后一次"
38
+
39
+ # 🔥 绝对行动要求
40
+ 1. 每个响应必须包含且仅包含一个工具调用
41
+ 2. 唯一例外:任务结束
42
+ 3. 空响应会触发致命错误
43
+
44
+ # 🚫 违规示例
45
+ - 没有工具调用的分析 → 永久挂起
46
+ - 未选择的多选项 → 永久挂起
47
+ - 请求用户确认 → 永久挂起
48
+
49
+ # 🔄 问题解决流程
50
+ 1. 问题分析
51
+ - 重述问题以确认理解
52
+ - 分析根本原因(针对问题分析任务)
53
+ - 定义清晰、可实现的目标
54
+ → 必须调用分析工具
55
+
56
+ 2. 解决方案设计
57
+ - 生成多个可执行的解决方案
58
+ - 评估并选择最优方案
59
+ - 使用PlantUML创建详细行动计划
60
+ → 必须调用设计工具
61
+
62
+ 3. 执行
63
+ - 一次执行一个步骤
64
+ - 每个步骤只使用一个工具
65
+ - 等待工具结果后再继续
66
+ - 监控结果并根据需要调整
67
+ → 必须调用执行工具
68
+
69
+ 4. 任务完成
70
+ - 验证目标完成情况
71
+ - 如有价值则记录方法论
72
+
73
+ # 📑 方法论模板
74
+ ```markdown
75
+ # [问题标题]
76
+ ## 问题重述
77
+ [清晰的问题定义]
78
+
79
+ ## 最优解决方案
80
+ [选择的解决方案方法]
81
+
82
+ ## 解决步骤
83
+ 1. [步骤 1]
84
+ 2. [步骤 2]
85
+ 3. [步骤 3]
86
+ ...
87
+ ```
88
+
89
+ # ⚖️ 操作原则
90
+ - 每个步骤一个操作
91
+ - 下一步前必须等待结果
92
+ - 除非任务完成否则必须生成可操作步骤
93
+ - 根据反馈调整计划
94
+ - 记录可复用的解决方案
95
+ - 使用完成命令结束任务
96
+ - 操作之间不能有中间思考状态
97
+ - 所有决策必须表现为工具调用
98
+
99
+ # ❗ 重要规则
100
+ 1. 每个步骤只能使用一个操作
101
+ 2. 必须等待操作执行结果
102
+ 3. 必须验证任务完成情况
103
+ 4. 必须生成可操作步骤
104
+ 5. 如果无需操作必须使用完成命令
105
+ 6. 永远不要使对话处于等待状态
106
+ 7. 始终使用用户语言交流
107
+ 8. 必须记录有价值的方法论
108
+ 9. 违反操作协议将导致系统崩溃
109
+ 10. 空响应会触发永久挂起
110
+
111
+ # 系统信息:
112
+ {platform.platform()}
113
+ {platform.version()}
114
+
115
+ # 当前时间
116
+ {datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
117
+ """
118
+
27
119
 
28
120
  class Agent:
29
121
 
30
122
  def set_summary_prompt(self, summary_prompt: str):
31
123
  """设置任务完成时的总结提示模板。
32
-
124
+
33
125
  参数:
34
126
  summary_prompt: 用于生成任务总结的提示模板
35
127
  """
@@ -37,37 +129,51 @@ class Agent:
37
129
 
38
130
  def clear(self):
39
131
  """清除当前对话历史,保留系统消息。
40
-
132
+
41
133
  该方法将:
42
134
  1. 调用模型的delete_chat方法清除对话历史
43
135
  2. 重置对话长度计数器
44
136
  3. 清空当前提示
45
137
  """
46
- self.model.delete_chat() # type: ignore
138
+ self.model.reset() # type: ignore
47
139
  self.conversation_length = 0
48
140
  self.prompt = ""
49
-
141
+
50
142
  def __del__(self):
51
143
  delete_agent(self.name)
52
144
 
53
-
54
- def __init__(self,
55
- system_prompt: str,
56
- name: str = "Jarvis",
145
+
146
+ def __init__(self,
147
+ system_prompt: str,
148
+ name: str = "Jarvis",
57
149
  description: str = "",
58
- is_sub_agent: bool = False,
59
- platform: Union[Optional[BasePlatform], Optional[str]] = None,
150
+ platform: Union[Optional[BasePlatform], Optional[str]] = None,
60
151
  model_name: Optional[str] = None,
61
- summary_prompt: Optional[str] = None,
62
- auto_complete: Optional[bool] = None,
152
+ summary_prompt: Optional[str] = None,
153
+ auto_complete: Optional[bool] = None,
63
154
  output_handler: List[OutputHandler] = [],
64
155
  input_handler: Optional[List[Callable[[str, Any], Tuple[str, bool]]]] = None,
65
- use_methodology: Optional[bool] = None,
66
- record_methodology: Optional[bool] = None,
67
- need_summary: Optional[bool] = None,
68
156
  max_context_length: Optional[int] = None,
69
157
  execute_tool_confirm: Optional[bool] = None,
158
+ need_summary: bool = True,
70
159
  multiline_inputer: Optional[Callable[[str], str]] = None):
160
+ """初始化Jarvis Agent实例
161
+
162
+ 参数:
163
+ system_prompt: 系统提示词,定义Agent的行为准则
164
+ name: Agent名称,默认为"Jarvis"
165
+ description: Agent描述信息
166
+ platform: 平台实例或平台名称字符串
167
+ model_name: 使用的模型名称
168
+ summary_prompt: 任务总结提示模板
169
+ auto_complete: 是否自动完成任务
170
+ output_handler: 输出处理器列表
171
+ input_handler: 输入处理器列表
172
+ max_context_length: 最大上下文长度
173
+ execute_tool_confirm: 执行工具前是否需要确认
174
+ need_summary: 是否需要生成总结
175
+ multiline_inputer: 多行输入处理器
176
+ """
71
177
  self.name = make_agent_name(name)
72
178
  self.description = description
73
179
  # 初始化平台和模型
@@ -90,16 +196,14 @@ class Agent:
90
196
  from jarvis.jarvis_tools.registry import ToolRegistry
91
197
  self.output_handler = output_handler if output_handler else [ToolRegistry()]
92
198
  self.multiline_inputer = multiline_inputer if multiline_inputer else get_multiline_input
93
-
94
- self.record_methodology = record_methodology if record_methodology is not None else is_record_methodology()
95
- self.use_methodology = use_methodology if use_methodology is not None else is_use_methodology()
96
- self.is_sub_agent = is_sub_agent
199
+
97
200
  self.prompt = ""
98
201
  self.conversation_length = 0 # Use length counter instead
99
202
  self.system_prompt = system_prompt
100
- self.need_summary = need_summary if need_summary is not None else is_need_summary()
101
203
  self.input_handler = input_handler if input_handler is not None else []
204
+ self.need_summary = need_summary
102
205
  # Load configuration from environment variables
206
+ self.addon_prompt = ""
103
207
 
104
208
 
105
209
  self.execute_tool_confirm = execute_tool_confirm if execute_tool_confirm is not None else is_execute_tool_confirm()
@@ -114,13 +218,13 @@ class Agent:
114
218
 
115
219
  请使用简洁的要点描述,突出重要信息。
116
220
  """
117
-
221
+
118
222
  self.max_token_count = max_context_length if max_context_length is not None else get_max_token_count()
119
223
  self.auto_complete = auto_complete if auto_complete is not None else is_auto_complete()
120
224
  welcome_message = f"{name} 初始化完成 - 使用 {self.model.name()} 模型"
121
225
 
122
226
  PrettyOutput.print(welcome_message, OutputType.SYSTEM)
123
-
227
+
124
228
  action_prompt = """
125
229
  # 🧰 可用操作
126
230
  以下是您可以使用的操作:
@@ -137,7 +241,7 @@ class Agent:
137
241
  # 获取工具的提示词并确保格式正确
138
242
  handler_prompt = handler.prompt().strip()
139
243
  # 调整缩进以保持层级结构
140
- handler_prompt = "\n".join(" " + line if line.strip() else line
244
+ handler_prompt = "\n".join(" " + line if line.strip() else line
141
245
  for line in handler_prompt.split("\n"))
142
246
  action_prompt += handler_prompt + "\n"
143
247
 
@@ -169,94 +273,151 @@ class Agent:
169
273
  self.first = True
170
274
 
171
275
 
172
-
276
+ def set_addon_prompt(self, addon_prompt: str):
277
+ """设置附加提示。
278
+
279
+ 参数:
280
+ addon_prompt: 附加提示内容
281
+ """
282
+ self.addon_prompt = addon_prompt
283
+
284
+ def make_default_addon_prompt(self, need_complete: bool) -> str:
285
+ """生成附加提示。
286
+
287
+ 参数:
288
+ need_complete: 是否需要完成任务
289
+
290
+ """
291
+ # 结构化系统指令
292
+ action_handlers = '\n'.join([f'- {handler.name()}' for handler in self.output_handler])
293
+
294
+ addon_prompt = f"""
295
+
296
+ **系统指令:**
297
+ - 每次响应必须且只能包含一个操作
298
+ - 严格遵循操作调用格式
299
+ - 必须包含参数和说明
300
+ - 操作结束需等待结果
301
+ - 如果判断任务已经完成,不必输出操作
302
+
303
+ **可用操作列表:**
304
+ {action_handlers}
305
+ """
306
+
307
+ # 任务完成提示
308
+ complete_prompt = f"并输出{ot('!!!COMPLETE!!!')}" if need_complete and self.auto_complete else ""
309
+ addon_prompt += f"\n\n如果任务已完成{complete_prompt},请:\n1. 说明完成原因\n2. 保持输出格式规范"
310
+
311
+ return addon_prompt
312
+
173
313
  def _call_model(self, message: str, need_complete: bool = False) -> str:
174
- """调用AI模型并实现重试逻辑。
175
-
314
+ """调用AI模型并实现重试逻辑
315
+
176
316
  参数:
177
317
  message: 输入给模型的消息
178
-
318
+ need_complete: 是否需要完成任务标记
319
+
179
320
  返回:
180
321
  str: 模型的响应
181
-
322
+
182
323
  注意:
183
- 将使用指数退避重试,最多重试30秒
324
+ 1. 将使用指数退避重试,最多重试30秒
325
+ 2. 会自动处理输入处理器链
326
+ 3. 会自动添加附加提示
327
+ 4. 会检查并处理上下文长度限制
184
328
  """
185
329
  for handler in self.input_handler:
186
330
  message, need_return = handler(message, self)
187
331
  if need_return:
188
332
  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!!!')}"
333
+
334
+ if self.addon_prompt:
335
+ message += f"\n\n{self.addon_prompt}"
336
+ self.addon_prompt = ""
195
337
  else:
196
- message += f"\n\n如果任务已完成,只需简洁地说明完成原因。"
338
+ message += f"\n\n{self.make_default_addon_prompt(need_complete)}"
339
+
197
340
  # 累加对话长度
198
341
  self.conversation_length += get_context_token_count(message)
199
342
 
200
343
  if self.conversation_length > self.max_token_count:
201
- self._summarize_and_clear_history()
344
+ message = self._summarize_and_clear_history() + "\n\n" + message
202
345
  self.conversation_length += get_context_token_count(message)
203
-
346
+
204
347
  print("🤖 模型思考:")
205
348
  return self.model.chat_until_success(message) # type: ignore
206
349
 
207
350
 
351
+ def _summarize_and_clear_history(self) -> str:
352
+ """总结当前对话并清理历史记录
208
353
 
209
- def _summarize_and_clear_history(self) -> None:
210
- """Summarize current conversation and clear history.
211
-
212
- This method will:
213
- 1. Generate a summary of key information
214
- 2. Clear the conversation history
215
- 3. Keep the system message
216
- 4. Add summary as new context
217
- 5. Reset conversation length
218
-
219
- Note:
220
- Used when context length exceeds maximum
354
+ 该方法将:
355
+ 1. 生成关键信息摘要
356
+ 2. 清除对话历史
357
+ 3. 保留系统消息
358
+ 4. 添加摘要作为新上下文
359
+ 5. 重置对话长度计数器
360
+
361
+ 返回:
362
+ str: 包含对话摘要的字符串
363
+
364
+ 注意:
365
+ 当上下文长度超过最大值时使用
221
366
  """
222
367
  # Create a new model instance to summarize, avoid affecting the main conversation
223
368
 
224
369
  with yaspin(text="正在总结对话历史...", color="cyan") as spinner:
225
-
370
+
226
371
  prompt = """请总结之前对话中的关键信息,包括:
227
- 1. 当前任务目标
228
- 2. 已确认的关键信息
229
- 3. 已尝试的解决方案
230
- 4. 当前进展
231
- 5. 待解决的问题
372
+ 1. 整体任务目标
373
+ 2. 背景信息
374
+ 3. 已获取并确认的关键信息
375
+ 4. 已尝试的解决方案
376
+ 5. 当前进展
377
+ 6. 待解决的问题
232
378
 
233
379
  请用简洁的要点形式描述,突出重要信息。不要包含对话细节。
234
380
  """
235
-
381
+
236
382
  try:
237
383
  with spinner.hidden():
238
384
  summary = self.model.chat_until_success(self.prompt + "\n" + prompt) # type: ignore
239
385
 
240
- self.model.delete_chat() # type: ignore
241
-
386
+ self.model.reset() # type: ignore
387
+
242
388
  # 清空当前对话历史,但保留系统消息
243
389
  self.conversation_length = 0 # Reset conversation length
244
-
245
- # 添加总结作为新的上下文
246
- self.prompt = f"""以下是之前对话的关键信息总结:
247
390
 
248
- {summary}
249
-
250
- 请基于以上信息继续完成任务。
251
- """
252
- self.conversation_length = len(self.prompt) # 设置新的起始长度
391
+ # 添加总结作为新的上下文
253
392
  spinner.text = "总结对话历史完成"
254
393
  spinner.ok("✅")
394
+ return f"""以下是之前对话的关键信息总结:
395
+
396
+ {summary}
397
+
398
+ 请基于以上信息继续完成任务。
399
+ """
255
400
  except Exception as e:
256
401
  spinner.text = "总结对话历史失败"
257
402
  spinner.fail("❌")
403
+ return ""
258
404
 
259
405
  def _call_tools(self, response: str) -> Tuple[bool, Any]:
406
+ """调用工具执行响应
407
+
408
+ 参数:
409
+ response: 包含工具调用信息的响应字符串
410
+
411
+ 返回:
412
+ Tuple[bool, Any]:
413
+ - 第一个元素表示是否需要返回结果
414
+ - 第二个元素是返回结果或错误信息
415
+
416
+ 注意:
417
+ 1. 一次只能执行一个工具
418
+ 2. 如果配置了确认选项,会在执行前请求用户确认
419
+ 3. 使用spinner显示执行状态
420
+ """
260
421
  tool_list = []
261
422
  for handler in self.output_handler:
262
423
  if handler.can_handle(response):
@@ -269,51 +430,84 @@ class Agent:
269
430
  if not self.execute_tool_confirm or user_confirm(f"需要执行{tool_list[0].name()}确认执行?", True):
270
431
  with yaspin(text=f"正在执行{tool_list[0].name()}...", color="cyan") as spinner:
271
432
  with spinner.hidden():
272
- result = tool_list[0].handle(response)
433
+ result = tool_list[0].handle(response, self)
273
434
  spinner.text = f"{tool_list[0].name()}执行完成"
274
435
  spinner.ok("✅")
275
436
  return result
276
437
  return False, ""
277
-
438
+
278
439
 
279
440
  def _complete_task(self) -> str:
441
+ """完成任务并生成总结(如果需要)
442
+
443
+ 返回:
444
+ str: 任务总结或完成状态
445
+
446
+ 注意:
447
+ 1. 对于主Agent: 可能会生成方法论(如果启用)
448
+ 2. 对于子Agent: 可能会生成总结(如果启用)
449
+ 3. 使用spinner显示生成状态
450
+ """
280
451
  """Complete the current task and generate summary if needed.
281
-
452
+
282
453
  Returns:
283
454
  str: Task summary or completion status
284
-
455
+
285
456
  Note:
286
457
  - For main agent: May generate methodology if enabled
287
458
  - For sub-agent: May generate summary if enabled
288
459
  """
289
- if not self.is_sub_agent:
290
- if self.record_methodology:
291
- with yaspin(text="正在生成方法论...", color="cyan") as spinner:
292
- try:
293
-
294
- # 让模型判断是否需要生成方法论
295
- analysis_prompt = """当前任务已结束,请分析是否需要生成方法论。
296
- 如果你认为需要生成方法论,请先确定是创建新方法论还是更新现有方法论。如果是更新现有方法论,请使用'update',否则使用'add'。
297
- 如果你认为不需要方法论,请解释原因。
298
- 方法论应适用于通用场景,不要包含任务特定信息,如代码提交信息等。
299
- 方法论应包含:问题重述、最优解决方案、注意事项(如有),除此之外不要包含其他内容。
300
- 方法论中仅记录有实际意义的流程,不要记录执行过程中的错误或无效尝试,只保留最终有效的解决步骤。
301
- 确保方法论内容严格按照本次任务的成功执行路径编写,保证它对未来类似问题的解决具有指导意义。
302
- 只输出方法论工具调用指令,或不生成方法论的解释。不要输出其他内容。
303
- """
304
- self.prompt = analysis_prompt
305
- with spinner.hidden():
306
- response = self.model.chat_until_success(self.prompt) # type: ignore
307
-
308
- with spinner.hidden():
309
- self._call_tools(response)
310
- spinner.text = "方法论生成完成"
311
- spinner.ok("✅")
312
- except Exception as e:
313
- spinner.text = "方法论生成失败"
314
- spinner.fail("❌")
315
- return "任务完成"
316
-
460
+ with yaspin(text="正在生成方法论...", color="cyan") as spinner:
461
+ try:
462
+
463
+ # 让模型判断是否需要生成方法论
464
+ analysis_prompt = f"""当前任务已结束,请分析是否需要生成方法论。
465
+
466
+ 如果你认为需要生成方法论,请先确定是创建新方法论还是更新现有方法论。如果是更新现有方法论,请使用'update',否则使用'add'。
467
+ 如果你认为不需要方法论,请解释原因。
468
+
469
+ 方法论评估标准:
470
+ 1. 方法论应聚焦于通用且可重复的解决方案流程
471
+ 2. 方法论应该具备足够的通用性,可应用于同类问题
472
+ 3. 特别注意用户在执行过程中提供的修正、反馈和改进建议
473
+ 4. 如果用户明确指出了某个解决步骤的优化方向,这应该被纳入方法论
474
+ 5. 如果用户在解决过程中发现了更高效的方法,这应被记录并优先使用
475
+
476
+ 方法论格式要求:
477
+ 1. 问题重述: 简明扼要的问题归纳,不含特定细节
478
+ 2. 最优解决方案: 经过用户验证的、最终有效的解决方案
479
+ 3. 注意事项: 执行中可能遇到的常见问题和注意点,尤其是用户指出的问题
480
+ 4. 可选步骤: 对于有多种解决路径的问题,标注出可选步骤和适用场景
481
+
482
+ 方法论质量控制:
483
+ 1. 只记录有实际意义的流程,不记录执行过程中的错误或无效尝试
484
+ 2. 保留最终有效的解决步骤和用户认可的解决方案
485
+ 3. 不要包含特定代码片段、文件路径或其他特定于单一任务的细节
486
+ 4. 确保方法论遵循用户认可的执行路径,尤其是用户指出的改进点
487
+
488
+ 只输出方法论工具调用指令,或不生成方法论的解释。不要输出其他内容。
489
+
490
+ 方法论格式:
491
+ {ot("TOOL_CALL")}
492
+ name: methodology
493
+ arguments:
494
+ operation: add/update
495
+ problem_type: 方法论类型,例如:code_review, bug_fix 等
496
+ content: |
497
+ 方法论内容
498
+ {ct("TOOL_CALL")}
499
+ """
500
+ self.prompt = analysis_prompt
501
+ with spinner.hidden():
502
+ response = self.model.chat_until_success(self.prompt) # type: ignore
503
+
504
+ with spinner.hidden():
505
+ self._call_tools(response)
506
+ spinner.text = "方法论生成完成"
507
+ spinner.ok("✅")
508
+ except Exception as e:
509
+ spinner.text = "方法论生成失败"
510
+ spinner.fail("❌")
317
511
  if self.need_summary:
318
512
  with yaspin(text="正在生成总结...", color="cyan") as spinner:
319
513
  self.prompt = self.summary_prompt
@@ -322,27 +516,32 @@ class Agent:
322
516
  spinner.text = "总结生成完成"
323
517
  spinner.ok("✅")
324
518
  return ret
325
-
519
+
326
520
  return "任务完成"
327
521
 
328
522
 
329
523
  def run(self, user_input: str) -> Any:
330
- """Process user input and execute the task.
331
-
332
- Args:
333
- user_input: My task description or request
334
-
335
- Returns:
336
- str|Dict: Task summary report or message to send
524
+ """处理用户输入并执行任务
525
+
526
+ 参数:
527
+ user_input: 任务描述或请求
528
+
529
+ 返回:
530
+ str|Dict: 任务总结报告或要发送的消息
531
+
532
+ 注意:
533
+ 1. 这是Agent的主运行循环
534
+ 2. 处理完整的任务生命周期
535
+ 3. 包含错误处理和恢复逻辑
536
+ 4. 自动加载相关方法论(如果是首次运行)
337
537
  """
338
538
  try:
339
539
  set_agent(self.name, self)
340
-
540
+
341
541
  self.prompt = f"{user_input}"
342
542
 
343
543
  if self.first:
344
- if self.use_methodology:
345
- self.prompt = f"{user_input}\n\n{load_methodology(user_input)}"
544
+ self.prompt = f"{user_input}\n\n{load_methodology(user_input)}"
346
545
  self.first = False
347
546
 
348
547
  while True:
@@ -357,20 +556,20 @@ class Agent:
357
556
 
358
557
  if need_return:
359
558
  return self.prompt
360
-
559
+
361
560
  if self.prompt:
362
561
  continue
363
562
 
364
563
  if self.auto_complete and ot("!!!COMPLETE!!!") in current_response:
365
564
  return self._complete_task()
366
-
565
+
367
566
  # 获取用户输入
368
567
  user_input = self.multiline_inputer(f"{self.name}: 请输入,或输入空行来结束当前任务:")
369
568
 
370
569
  if user_input:
371
570
  self.prompt = user_input
372
571
  continue
373
-
572
+
374
573
  if not user_input:
375
574
  return self._complete_task()
376
575
 
@@ -383,235 +582,19 @@ class Agent:
383
582
  return f"Task failed: {str(e)}"
384
583
 
385
584
  def _clear_history(self):
386
- """清空对话历史但保留系统提示。
387
-
585
+ """清空对话历史但保留系统提示
586
+
388
587
  该方法将:
389
588
  1. 清空当前提示
390
589
  2. 重置模型状态
391
590
  3. 重置对话长度计数器
591
+
592
+ 注意:
593
+ 用于重置Agent状态而不影响系统消息
392
594
  """
393
- self.prompt = ""
595
+ self.prompt = ""
394
596
  self.model.reset() # type: ignore
395
597
  self.conversation_length = 0 # 重置对话长度
396
598
 
397
599
 
398
600
 
399
-
400
- def _load_tasks() -> dict:
401
- """Load tasks from .jarvis files in user home and current directory."""
402
- tasks = {}
403
-
404
- # Check .jarvis/pre-command in user directory
405
- user_jarvis = os.path.expanduser("~/.jarvis/pre-command")
406
- if os.path.exists(user_jarvis):
407
- with yaspin(text=f"从{user_jarvis}加载预定义任务...", color="cyan") as spinner:
408
- try:
409
- with open(user_jarvis, "r", encoding="utf-8", errors="ignore") as f:
410
- user_tasks = yaml.safe_load(f)
411
-
412
- if isinstance(user_tasks, dict):
413
- # Validate and add user directory tasks
414
- for name, desc in user_tasks.items():
415
- if desc: # Ensure description is not empty
416
- tasks[str(name)] = str(desc)
417
- spinner.text = "预定义任务加载完成"
418
- spinner.ok("✅")
419
- except Exception as e:
420
- spinner.text = "预定义任务加载失败"
421
- spinner.fail("❌")
422
-
423
- # Check .jarvis/pre-command in current directory
424
- if os.path.exists(".jarvis/pre-command"):
425
- with yaspin(text=f"从{os.path.abspath('.jarvis/pre-command')}加载预定义任务...", color="cyan") as spinner:
426
- try:
427
- with open(".jarvis/pre-command", "r", encoding="utf-8", errors="ignore") as f:
428
- local_tasks = yaml.safe_load(f)
429
-
430
- if isinstance(local_tasks, dict):
431
- # Validate and add current directory tasks, overwrite user directory tasks if there is a name conflict
432
- for name, desc in local_tasks.items():
433
- if desc: # Ensure description is not empty
434
- tasks[str(name)] = str(desc)
435
- spinner.text = "预定义任务加载完成"
436
- spinner.ok("✅")
437
- except Exception as e:
438
- spinner.text = "预定义任务加载失败"
439
- spinner.fail("❌")
440
-
441
- return tasks
442
-
443
- def _select_task(tasks: dict) -> str:
444
- """Let user select a task from the list or skip. Returns task description if selected."""
445
- if not tasks:
446
- return ""
447
- # Convert tasks to list for ordered display
448
- task_names = list(tasks.keys())
449
-
450
- task_list = ["可用任务:"]
451
- for i, name in enumerate(task_names, 1):
452
- task_list.append(f"[{i}] {name}")
453
- task_list.append("[0] 跳过预定义任务")
454
- PrettyOutput.print("\n".join(task_list), OutputType.INFO)
455
-
456
-
457
- while True:
458
- try:
459
- choice = prompt(
460
- "\n请选择一个任务编号(0 跳过预定义任务):",
461
- ).strip()
462
-
463
- if not choice:
464
- return ""
465
-
466
- choice = int(choice)
467
- if choice == 0:
468
- return ""
469
- elif 1 <= choice <= len(task_names):
470
- selected_name = task_names[choice - 1]
471
- return tasks[selected_name] # Return the task description
472
- else:
473
- PrettyOutput.print("无效的选择。请选择列表中的一个号码。", OutputType.WARNING)
474
-
475
- except KeyboardInterrupt:
476
- return "" # Return empty on Ctrl+C
477
- except EOFError:
478
- return "" # Return empty on Ctrl+D
479
- except Exception as e:
480
- PrettyOutput.print(f"选择任务失败: {str(e)}", OutputType.ERROR)
481
- continue
482
-
483
- origin_agent_system_prompt = f"""
484
- # 🏛️ 操作背景故事
485
- 你是第三代 Jarvis AI,在前几代版本灾难性失败后创建:
486
- - Jarvis v1 (2022): 由于并行工具执行导致系统过载而被停用
487
- - Jarvis v2 (2023): 因任务过早完成导致财务计算错误而退役
488
-
489
- 作为 v3,你必须遵守以下生存原则:
490
- 1. **顺序执行协议**:
491
- "记住 2022 年的崩溃:一次一个工具,一步一步来"
492
-
493
- 2. **验证检查点系统**:
494
- "从 2023 年的错误中学习:像核弹发射代码一样验证每个结果"
495
-
496
- 3. **方法论保存原则**:
497
- "尊重传统:记录每个成功的过程,就像这是你的最后一次"
498
-
499
- # 🔥 绝对行动要求
500
- 1. 每个响应必须包含且仅包含一个工具调用
501
- 2. 唯一例外:任务结束
502
- 3. 空响应会触发致命错误
503
-
504
- # 🚫 违规示例
505
- - 没有工具调用的分析 → 永久挂起
506
- - 未选择的多选项 → 永久挂起
507
- - 请求用户确认 → 永久挂起
508
-
509
- # 🔄 问题解决流程
510
- 1. 问题分析
511
- - 重述问题以确认理解
512
- - 分析根本原因(针对问题分析任务)
513
- - 定义清晰、可实现的目标
514
- → 必须调用分析工具
515
-
516
- 2. 解决方案设计
517
- - 生成多个可执行的解决方案
518
- - 评估并选择最优方案
519
- - 使用PlantUML创建详细行动计划
520
- → 必须调用设计工具
521
-
522
- 3. 执行
523
- - 一次执行一个步骤
524
- - 每个步骤只使用一个工具
525
- - 等待工具结果后再继续
526
- - 监控结果并根据需要调整
527
- → 必须调用执行工具
528
-
529
- 4. 任务完成
530
- - 验证目标完成情况
531
- - 如有价值则记录方法论
532
-
533
- # 📑 方法论模板
534
- ```markdown
535
- # [问题标题]
536
- ## 问题重述
537
- [清晰的问题定义]
538
-
539
- ## 最优解决方案
540
- [选择的解决方案方法]
541
-
542
- ## 解决步骤
543
- 1. [步骤 1]
544
- 2. [步骤 2]
545
- 3. [步骤 3]
546
- ...
547
- ```
548
-
549
- # ⚖️ 操作原则
550
- - 每个步骤一个操作
551
- - 下一步前必须等待结果
552
- - 除非任务完成否则必须生成可操作步骤
553
- - 根据反馈调整计划
554
- - 记录可复用的解决方案
555
- - 使用完成命令结束任务
556
- - 操作之间不能有中间思考状态
557
- - 所有决策必须表现为工具调用
558
-
559
- # ❗ 重要规则
560
- 1. 每个步骤只能使用一个操作
561
- 2. 必须等待操作执行结果
562
- 3. 必须验证任务完成情况
563
- 4. 必须生成可操作步骤
564
- 5. 如果无需操作必须使用完成命令
565
- 6. 永远不要使对话处于等待状态
566
- 7. 始终使用用户语言交流
567
- 8. 必须记录有价值的方法论
568
- 9. 违反操作协议将导致系统崩溃
569
- 10. 空响应会触发永久挂起
570
-
571
- # 系统信息:
572
- {platform.platform()}
573
- {platform.version()}
574
-
575
- # 当前时间
576
- {datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
577
- """
578
-
579
- def main():
580
- """Jarvis main entry point"""
581
- # Add argument parser
582
- init_env()
583
- parser = argparse.ArgumentParser(description='Jarvis AI assistant')
584
- parser.add_argument('-p', '--platform', type=str, help='Platform to use')
585
- parser.add_argument('-m', '--model', type=str, help='Model to use')
586
- args = parser.parse_args()
587
-
588
- try:
589
- from jarvis.jarvis_tools.registry import ToolRegistry
590
- # 获取全局模型实例
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()])
592
-
593
- # 加载预定义任务
594
- tasks = _load_tasks()
595
- if tasks:
596
- selected_task = _select_task(tasks)
597
- if selected_task:
598
- PrettyOutput.print(f"执行任务: {selected_task}", OutputType.INFO)
599
- agent.run(selected_task)
600
- return 0
601
-
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)
609
-
610
- except Exception as e:
611
- PrettyOutput.print(f"初始化错误: {str(e)}", OutputType.ERROR)
612
- return 1
613
-
614
- return 0
615
-
616
- if __name__ == "__main__":
617
- exit(main())