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/__init__.py
CHANGED
jarvis/jarvis_agent/__init__.py
CHANGED
|
@@ -1,29 +1,121 @@
|
|
|
1
|
-
import
|
|
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
|
|
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
|
|
17
|
+
from jarvis.jarvis_utils.utils import ot
|
|
25
18
|
from jarvis.jarvis_utils.utils import user_confirm
|
|
26
|
-
|
|
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
|
|
|
@@ -55,18 +147,15 @@ class Agent:
|
|
|
55
147
|
system_prompt: str,
|
|
56
148
|
name: str = "Jarvis",
|
|
57
149
|
description: str = "",
|
|
58
|
-
is_sub_agent: bool = False,
|
|
59
150
|
platform: Union[Optional[BasePlatform], Optional[str]] = None,
|
|
60
151
|
model_name: Optional[str] = None,
|
|
61
152
|
summary_prompt: Optional[str] = None,
|
|
62
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):
|
|
71
160
|
self.name = make_agent_name(name)
|
|
72
161
|
self.description = description
|
|
@@ -91,14 +180,11 @@ class Agent:
|
|
|
91
180
|
self.output_handler = output_handler if output_handler else [ToolRegistry()]
|
|
92
181
|
self.multiline_inputer = multiline_inputer if multiline_inputer else get_multiline_input
|
|
93
182
|
|
|
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
|
|
97
183
|
self.prompt = ""
|
|
98
184
|
self.conversation_length = 0 # Use length counter instead
|
|
99
185
|
self.system_prompt = system_prompt
|
|
100
|
-
self.need_summary = need_summary if need_summary is not None else is_need_summary()
|
|
101
186
|
self.input_handler = input_handler if input_handler is not None else []
|
|
187
|
+
self.need_summary = need_summary
|
|
102
188
|
# Load configuration from environment variables
|
|
103
189
|
|
|
104
190
|
|
|
@@ -198,15 +284,14 @@ class Agent:
|
|
|
198
284
|
self.conversation_length += get_context_token_count(message)
|
|
199
285
|
|
|
200
286
|
if self.conversation_length > self.max_token_count:
|
|
201
|
-
self._summarize_and_clear_history()
|
|
287
|
+
message = self._summarize_and_clear_history() + "\n\n" + message
|
|
202
288
|
self.conversation_length += get_context_token_count(message)
|
|
203
289
|
|
|
204
290
|
print("🤖 模型思考:")
|
|
205
291
|
return self.model.chat_until_success(message) # type: ignore
|
|
206
292
|
|
|
207
293
|
|
|
208
|
-
|
|
209
|
-
def _summarize_and_clear_history(self) -> None:
|
|
294
|
+
def _summarize_and_clear_history(self) -> str:
|
|
210
295
|
"""Summarize current conversation and clear history.
|
|
211
296
|
|
|
212
297
|
This method will:
|
|
@@ -243,18 +328,18 @@ class Agent:
|
|
|
243
328
|
self.conversation_length = 0 # Reset conversation length
|
|
244
329
|
|
|
245
330
|
# 添加总结作为新的上下文
|
|
246
|
-
self.prompt = f"""以下是之前对话的关键信息总结:
|
|
247
|
-
|
|
248
|
-
{summary}
|
|
249
|
-
|
|
250
|
-
请基于以上信息继续完成任务。
|
|
251
|
-
"""
|
|
252
|
-
self.conversation_length = len(self.prompt) # 设置新的起始长度
|
|
253
331
|
spinner.text = "总结对话历史完成"
|
|
254
332
|
spinner.ok("✅")
|
|
333
|
+
return f"""以下是之前对话的关键信息总结:
|
|
334
|
+
|
|
335
|
+
{summary}
|
|
336
|
+
|
|
337
|
+
请基于以上信息继续完成任务。
|
|
338
|
+
"""
|
|
255
339
|
except Exception as e:
|
|
256
340
|
spinner.text = "总结对话历史失败"
|
|
257
341
|
spinner.fail("❌")
|
|
342
|
+
return ""
|
|
258
343
|
|
|
259
344
|
def _call_tools(self, response: str) -> Tuple[bool, Any]:
|
|
260
345
|
tool_list = []
|
|
@@ -286,34 +371,30 @@ class Agent:
|
|
|
286
371
|
- For main agent: May generate methodology if enabled
|
|
287
372
|
- For sub-agent: May generate summary if enabled
|
|
288
373
|
"""
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
spinner.text = "方法论生成失败"
|
|
314
|
-
spinner.fail("❌")
|
|
315
|
-
return "任务完成"
|
|
316
|
-
|
|
374
|
+
with yaspin(text="正在生成方法论...", color="cyan") as spinner:
|
|
375
|
+
try:
|
|
376
|
+
|
|
377
|
+
# 让模型判断是否需要生成方法论
|
|
378
|
+
analysis_prompt = """当前任务已结束,请分析是否需要生成方法论。
|
|
379
|
+
如果你认为需要生成方法论,请先确定是创建新方法论还是更新现有方法论。如果是更新现有方法论,请使用'update',否则使用'add'。
|
|
380
|
+
如果你认为不需要方法论,请解释原因。
|
|
381
|
+
方法论应适用于通用场景,不要包含任务特定信息,如代码提交信息等。
|
|
382
|
+
方法论应包含:问题重述、最优解决方案、注意事项(如有),除此之外不要包含其他内容。
|
|
383
|
+
方法论中仅记录有实际意义的流程,不要记录执行过程中的错误或无效尝试,只保留最终有效的解决步骤。
|
|
384
|
+
确保方法论内容严格按照本次任务的成功执行路径编写,保证它对未来类似问题的解决具有指导意义。
|
|
385
|
+
只输出方法论工具调用指令,或不生成方法论的解释。不要输出其他内容。
|
|
386
|
+
"""
|
|
387
|
+
self.prompt = analysis_prompt
|
|
388
|
+
with spinner.hidden():
|
|
389
|
+
response = self.model.chat_until_success(self.prompt) # type: ignore
|
|
390
|
+
|
|
391
|
+
with spinner.hidden():
|
|
392
|
+
self._call_tools(response)
|
|
393
|
+
spinner.text = "方法论生成完成"
|
|
394
|
+
spinner.ok("✅")
|
|
395
|
+
except Exception as e:
|
|
396
|
+
spinner.text = "方法论生成失败"
|
|
397
|
+
spinner.fail("❌")
|
|
317
398
|
if self.need_summary:
|
|
318
399
|
with yaspin(text="正在生成总结...", color="cyan") as spinner:
|
|
319
400
|
self.prompt = self.summary_prompt
|
|
@@ -341,8 +422,7 @@ class Agent:
|
|
|
341
422
|
self.prompt = f"{user_input}"
|
|
342
423
|
|
|
343
424
|
if self.first:
|
|
344
|
-
|
|
345
|
-
self.prompt = f"{user_input}\n\n{load_methodology(user_input)}"
|
|
425
|
+
self.prompt = f"{user_input}\n\n{load_methodology(user_input)}"
|
|
346
426
|
self.first = False
|
|
347
427
|
|
|
348
428
|
while True:
|
|
@@ -396,222 +476,3 @@ class Agent:
|
|
|
396
476
|
|
|
397
477
|
|
|
398
478
|
|
|
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())
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
from prompt_toolkit import prompt
|
|
5
|
+
import yaml
|
|
6
|
+
from yaspin import yaspin
|
|
7
|
+
from jarvis.jarvis_agent import (
|
|
8
|
+
PrettyOutput, OutputType,
|
|
9
|
+
get_multiline_input,
|
|
10
|
+
Agent, # 显式导入关键组件
|
|
11
|
+
origin_agent_system_prompt
|
|
12
|
+
)
|
|
13
|
+
from jarvis.jarvis_agent.patch import PatchOutputHandler
|
|
14
|
+
from jarvis.jarvis_tools.registry import ToolRegistry
|
|
15
|
+
from jarvis.jarvis_utils.utils import init_env
|
|
16
|
+
from jarvis.jarvis_agent.file_input_handler import file_input_handler
|
|
17
|
+
from jarvis.jarvis_agent.shell_input_handler import shell_input_handler
|
|
18
|
+
from jarvis.jarvis_agent.builtin_input_handler import builtin_input_handler
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _load_tasks() -> dict:
|
|
22
|
+
"""Load tasks from .jarvis files in user home and current directory."""
|
|
23
|
+
tasks = {}
|
|
24
|
+
|
|
25
|
+
# Check .jarvis/pre-command in user directory
|
|
26
|
+
user_jarvis = os.path.expanduser("~/.jarvis/pre-command")
|
|
27
|
+
if os.path.exists(user_jarvis):
|
|
28
|
+
with yaspin(text=f"从{user_jarvis}加载预定义任务...", color="cyan") as spinner:
|
|
29
|
+
try:
|
|
30
|
+
with open(user_jarvis, "r", encoding="utf-8", errors="ignore") as f:
|
|
31
|
+
user_tasks = yaml.safe_load(f)
|
|
32
|
+
|
|
33
|
+
if isinstance(user_tasks, dict):
|
|
34
|
+
# Validate and add user directory tasks
|
|
35
|
+
for name, desc in user_tasks.items():
|
|
36
|
+
if desc: # Ensure description is not empty
|
|
37
|
+
tasks[str(name)] = str(desc)
|
|
38
|
+
spinner.text = "预定义任务加载完成"
|
|
39
|
+
spinner.ok("✅")
|
|
40
|
+
except Exception as e:
|
|
41
|
+
spinner.text = "预定义任务加载失败"
|
|
42
|
+
spinner.fail("❌")
|
|
43
|
+
|
|
44
|
+
# Check .jarvis/pre-command in current directory
|
|
45
|
+
if os.path.exists(".jarvis/pre-command"):
|
|
46
|
+
with yaspin(text=f"从{os.path.abspath('.jarvis/pre-command')}加载预定义任务...", color="cyan") as spinner:
|
|
47
|
+
try:
|
|
48
|
+
with open(".jarvis/pre-command", "r", encoding="utf-8", errors="ignore") as f:
|
|
49
|
+
local_tasks = yaml.safe_load(f)
|
|
50
|
+
|
|
51
|
+
if isinstance(local_tasks, dict):
|
|
52
|
+
# Validate and add current directory tasks, overwrite user directory tasks if there is a name conflict
|
|
53
|
+
for name, desc in local_tasks.items():
|
|
54
|
+
if desc: # Ensure description is not empty
|
|
55
|
+
tasks[str(name)] = str(desc)
|
|
56
|
+
spinner.text = "预定义任务加载完成"
|
|
57
|
+
spinner.ok("✅")
|
|
58
|
+
except Exception as e:
|
|
59
|
+
spinner.text = "预定义任务加载失败"
|
|
60
|
+
spinner.fail("❌")
|
|
61
|
+
|
|
62
|
+
return tasks
|
|
63
|
+
|
|
64
|
+
def _select_task(tasks: dict) -> str:
|
|
65
|
+
"""Let user select a task from the list or skip. Returns task description if selected."""
|
|
66
|
+
if not tasks:
|
|
67
|
+
return ""
|
|
68
|
+
# Convert tasks to list for ordered display
|
|
69
|
+
task_names = list(tasks.keys())
|
|
70
|
+
|
|
71
|
+
task_list = ["可用任务:"]
|
|
72
|
+
for i, name in enumerate(task_names, 1):
|
|
73
|
+
task_list.append(f"[{i}] {name}")
|
|
74
|
+
task_list.append("[0] 跳过预定义任务")
|
|
75
|
+
PrettyOutput.print("\n".join(task_list), OutputType.INFO)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
while True:
|
|
79
|
+
try:
|
|
80
|
+
choice = prompt(
|
|
81
|
+
"\n请选择一个任务编号(0 跳过预定义任务):",
|
|
82
|
+
).strip()
|
|
83
|
+
|
|
84
|
+
if not choice:
|
|
85
|
+
return ""
|
|
86
|
+
|
|
87
|
+
choice = int(choice)
|
|
88
|
+
if choice == 0:
|
|
89
|
+
return ""
|
|
90
|
+
elif 1 <= choice <= len(task_names):
|
|
91
|
+
selected_name = task_names[choice - 1]
|
|
92
|
+
return tasks[selected_name] # Return the task description
|
|
93
|
+
else:
|
|
94
|
+
PrettyOutput.print("无效的选择。请选择列表中的一个号码。", OutputType.WARNING)
|
|
95
|
+
|
|
96
|
+
except KeyboardInterrupt:
|
|
97
|
+
return "" # Return empty on Ctrl+C
|
|
98
|
+
except EOFError:
|
|
99
|
+
return "" # Return empty on Ctrl+D
|
|
100
|
+
except Exception as e:
|
|
101
|
+
PrettyOutput.print(f"选择任务失败: {str(e)}", OutputType.ERROR)
|
|
102
|
+
continue
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def main() -> int:
|
|
108
|
+
"""Jarvis main entry point"""
|
|
109
|
+
init_env()
|
|
110
|
+
parser = argparse.ArgumentParser(description='Jarvis AI assistant')
|
|
111
|
+
parser.add_argument('-p', '--platform', type=str, help='Platform to use')
|
|
112
|
+
parser.add_argument('-m', '--model', type=str, help='Model to use')
|
|
113
|
+
args = parser.parse_args()
|
|
114
|
+
|
|
115
|
+
try:
|
|
116
|
+
agent = Agent(
|
|
117
|
+
system_prompt=origin_agent_system_prompt,
|
|
118
|
+
platform=args.platform,
|
|
119
|
+
model_name=args.model,
|
|
120
|
+
input_handler=[file_input_handler, shell_input_handler, builtin_input_handler], # type: ignore
|
|
121
|
+
output_handler=[ToolRegistry(), PatchOutputHandler()],
|
|
122
|
+
need_summary=False
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
tasks = _load_tasks()
|
|
126
|
+
if tasks:
|
|
127
|
+
selected_task = _select_task(tasks)
|
|
128
|
+
if selected_task:
|
|
129
|
+
PrettyOutput.print(f"执行任务: {selected_task}", OutputType.INFO)
|
|
130
|
+
agent.run(selected_task)
|
|
131
|
+
return 0
|
|
132
|
+
|
|
133
|
+
user_input = get_multiline_input("请输入你的任务(输入空行退出):")
|
|
134
|
+
if user_input:
|
|
135
|
+
agent.run(user_input)
|
|
136
|
+
return 0
|
|
137
|
+
|
|
138
|
+
except Exception as e:
|
|
139
|
+
PrettyOutput.print(f"初始化错误: {str(e)}", OutputType.ERROR)
|
|
140
|
+
return 1
|
|
141
|
+
|
|
142
|
+
if __name__ == "__main__":
|
|
143
|
+
exit(main())
|
jarvis/jarvis_agent/main.py
CHANGED
|
@@ -7,8 +7,6 @@ from jarvis.jarvis_utils.input import get_multiline_input
|
|
|
7
7
|
from jarvis.jarvis_utils.output import PrettyOutput, OutputType
|
|
8
8
|
from jarvis.jarvis_utils.utils import init_env
|
|
9
9
|
|
|
10
|
-
# 从__init__.py导入系统提示
|
|
11
|
-
from jarvis.jarvis_agent import origin_agent_system_prompt
|
|
12
10
|
|
|
13
11
|
def load_config(config_path: str) -> dict:
|
|
14
12
|
"""Load configuration from YAML file
|