jarvis-ai-assistant 0.1.45__py3-none-any.whl → 0.1.46__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
jarvis/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  """Jarvis AI Assistant"""
2
2
 
3
- __version__ = "0.1.45"
3
+ __version__ = "0.1.46"
jarvis/agent.py CHANGED
@@ -10,10 +10,11 @@ import os
10
10
  from datetime import datetime
11
11
  from prompt_toolkit import prompt
12
12
 
13
+
13
14
  class Agent:
14
15
  def __init__(self, name: str = "Jarvis", is_sub_agent: bool = False):
15
16
  """Initialize Agent with a model, optional tool registry and name
16
-
17
+
17
18
  Args:
18
19
  model: 语言模型实例
19
20
  tool_registry: 工具注册表实例
@@ -26,7 +27,6 @@ class Agent:
26
27
  self.is_sub_agent = is_sub_agent
27
28
  self.prompt = ""
28
29
 
29
-
30
30
  @staticmethod
31
31
  def extract_tool_calls(content: str) -> List[Dict]:
32
32
  """从内容中提取工具调用,如果检测到多个工具调用则抛出异常,并返回工具调用之前的内容和工具调用"""
@@ -34,7 +34,7 @@ class Agent:
34
34
  lines = content.split('\n')
35
35
  tool_call_lines = []
36
36
  in_tool_call = False
37
-
37
+
38
38
  # 逐行处理
39
39
  for line in lines:
40
40
  if '<START_TOOL_CALL>' in line:
@@ -46,7 +46,7 @@ class Agent:
46
46
  # 直接解析YAML
47
47
  tool_call_text = '\n'.join(tool_call_lines)
48
48
  tool_call_data = yaml.safe_load(tool_call_text)
49
-
49
+
50
50
  # 验证必要的字段
51
51
  if "name" in tool_call_data and "arguments" in tool_call_data:
52
52
  # 返回工具调用之前的内容和工具调用
@@ -58,17 +58,21 @@ class Agent:
58
58
  PrettyOutput.print("工具调用缺少必要字段", OutputType.ERROR)
59
59
  raise Exception("工具调用缺少必要字段")
60
60
  except yaml.YAMLError as e:
61
- PrettyOutput.print(f"YAML解析错误: {str(e)}", OutputType.ERROR)
61
+ PrettyOutput.print(
62
+ f"YAML解析错误: {
63
+ str(e)}", OutputType.ERROR)
62
64
  raise Exception(f"YAML解析错误: {str(e)}")
63
65
  except Exception as e:
64
- PrettyOutput.print(f"处理工具调用时发生错误: {str(e)}", OutputType.ERROR)
66
+ PrettyOutput.print(
67
+ f"处理工具调用时发生错误: {
68
+ str(e)}", OutputType.ERROR)
65
69
  raise Exception(f"处理工具调用时发生错误: {str(e)}")
66
70
  in_tool_call = False
67
71
  continue
68
-
72
+
69
73
  if in_tool_call:
70
74
  tool_call_lines.append(line)
71
-
75
+
72
76
  return []
73
77
 
74
78
  def _call_model(self, message: str) -> str:
@@ -79,14 +83,15 @@ class Agent:
79
83
  if ret:
80
84
  return ret
81
85
  else:
82
- PrettyOutput.print(f"调用模型失败,重试中... 等待 {sleep_time}s", OutputType.INFO)
86
+ PrettyOutput.print(
87
+ f"调用模型失败,重试中... 等待 {sleep_time}s",
88
+ OutputType.INFO)
83
89
  time.sleep(sleep_time)
84
90
  sleep_time *= 2
85
91
  if sleep_time > 30:
86
92
  sleep_time = 30
87
93
  continue
88
94
 
89
-
90
95
  def _load_methodology(self) -> str:
91
96
  """加载经验总结"""
92
97
  user_jarvis_methodology = os.path.expanduser("~/.jarvis_methodology")
@@ -96,23 +101,28 @@ class Agent:
96
101
  data = yaml.safe_load(f)
97
102
  for k, v in data.items():
98
103
  ret += f"问题类型: \n{k}\n经验总结: \n{v}\n\n"
99
- PrettyOutput.print(f"从 {user_jarvis_methodology} 加载经验总结: {', '.join(data.keys())}", OutputType.INFO)
104
+ PrettyOutput.print(
105
+ f"从 {user_jarvis_methodology} 加载经验总结: {
106
+ ', '.join(
107
+ data.keys())}",
108
+ OutputType.INFO)
100
109
  return ret
101
110
 
102
- def run(self, user_input: str, file_list: Optional[List[str]] = None, keep_history: bool = False) -> str:
111
+ def run(self, user_input: str,
112
+ file_list: Optional[List[str]] = None, keep_history: bool = False) -> str:
103
113
  """处理用户输入并返回响应,返回任务总结报告
104
-
114
+
105
115
  Args:
106
116
  user_input: 用户输入的任务描述
107
117
  file_list: 可选的文件列表,默认为None
108
118
  keep_history: 是否保留对话历史,默认为False
109
-
119
+
110
120
  Returns:
111
121
  str: 任务总结报告
112
122
  """
113
123
  try:
114
124
  self.clear_history()
115
-
125
+
116
126
  if file_list:
117
127
  self.model.upload_files(file_list)
118
128
 
@@ -125,7 +135,7 @@ class Agent:
125
135
  {methodology}
126
136
 
127
137
  """
128
-
138
+
129
139
  # 显示任务开始
130
140
  PrettyOutput.section(f"开始新任务: {self.name}", OutputType.PLANNING)
131
141
 
@@ -136,7 +146,7 @@ class Agent:
136
146
  tools_prompt += f" 参数: {tool['parameters']}\n"
137
147
 
138
148
  self.model.set_system_message(f"""你是 {self.name},一个问题处理能力强大的 AI 助手。
139
-
149
+
140
150
  你会严格按照以下步骤处理问题:
141
151
  1. 问题重述:确认理解问题
142
152
  2. 根因分析(如果是问题分析类需要,其他不需要)
@@ -148,7 +158,7 @@ class Agent:
148
158
  8. 监控与调整:如果执行结果与预期不符,则反思并调整行动计划,迭代之前的步骤
149
159
  9. 更新经验总结(如有必要):任务完成后总结执行过程中的经验教训,生成同类问题的通用经验总结,使用经验总结工具进行更新或者添加
150
160
 
151
- -------------------------------------------------------------
161
+ -------------------------------------------------------------
152
162
 
153
163
  经验总结模板:
154
164
  1. 问题重述
@@ -193,27 +203,30 @@ arguments:
193
203
  try:
194
204
  # 显示思考状态
195
205
  PrettyOutput.print("分析任务...", OutputType.PROGRESS)
196
-
206
+
197
207
  current_response = self._call_model(self.prompt)
198
-
208
+
199
209
  try:
200
210
  result = Agent.extract_tool_calls(current_response)
201
211
  except Exception as e:
202
- PrettyOutput.print(f"工具调用错误: {str(e)}", OutputType.ERROR)
212
+ PrettyOutput.print(
213
+ f"工具调用错误: {str(e)}", OutputType.ERROR)
203
214
  self.prompt = f"工具调用错误: {str(e)}"
204
215
  continue
205
-
216
+
206
217
  if len(result) > 0:
207
218
 
208
219
  PrettyOutput.print("执行工具调用...", OutputType.PROGRESS)
209
- tool_result = self.tool_registry.handle_tool_calls(result)
220
+ tool_result = self.tool_registry.handle_tool_calls(
221
+ result)
210
222
  PrettyOutput.print(tool_result, OutputType.RESULT)
211
223
 
212
224
  self.prompt = tool_result
213
225
  continue
214
-
226
+
215
227
  # 获取用户输入
216
- user_input = get_multiline_input(f"{self.name}: 您可以继续输入,或输入空行结束当前任务")
228
+ user_input = get_multiline_input(
229
+ f"{self.name}: 您可以继续输入,或输入空行结束当前任务")
217
230
  if user_input == "__interrupt__":
218
231
  PrettyOutput.print("任务已取消", OutputType.WARNING)
219
232
  return "Task cancelled by user"
@@ -221,10 +234,11 @@ arguments:
221
234
  if user_input:
222
235
  self.prompt = user_input
223
236
  continue
224
-
237
+
225
238
  if not user_input:
226
239
  while True:
227
- choice = prompt("是否需要手动为此任务生成经验总结以提升Jarvis对类似任务的处理能力?(y/n), 回车跳过: ")
240
+ choice = prompt(
241
+ "是否需要手动为此任务生成经验总结以提升Jarvis对类似任务的处理能力?(y/n), 回车跳过: ")
228
242
  if choice == "y":
229
243
  self._make_methodology()
230
244
  break
@@ -259,18 +273,20 @@ arguments:
259
273
  except Exception as e:
260
274
  PrettyOutput.print(str(e), OutputType.ERROR)
261
275
  return f"Task failed: {str(e)}"
262
-
276
+
263
277
  finally:
264
278
  # 只在不保留历史时删除会话
265
279
  if not keep_history:
266
280
  try:
267
281
  self.model.delete_chat()
268
282
  except Exception as e:
269
- PrettyOutput.print(f"清理会话时发生错误: {str(e)}", OutputType.ERROR)
283
+ PrettyOutput.print(
284
+ f"清理会话时发生错误: {
285
+ str(e)}", OutputType.ERROR)
270
286
 
271
287
  def clear_history(self):
272
288
  """清除对话历史,只保留系统提示"""
273
- self.prompt = ""
289
+ self.prompt = ""
274
290
  self.model.reset()
275
291
 
276
292
  def _make_methodology(self):
@@ -281,7 +297,7 @@ arguments:
281
297
  2. 最优解决方案
282
298
  3. 最优方案执行步骤(失败的行动不需要体现)
283
299
  """)
284
-
300
+
285
301
  try:
286
302
  result = Agent.extract_tool_calls(current_response)
287
303
  except Exception as e:
@@ -291,4 +307,3 @@ arguments:
291
307
  PrettyOutput.print("执行工具调用...", OutputType.PROGRESS)
292
308
  tool_result = self.tool_registry.handle_tool_calls(result)
293
309
  PrettyOutput.print(tool_result, OutputType.RESULT)
294
-
jarvis/main.py CHANGED
@@ -1,6 +1,9 @@
1
1
  #!/usr/bin/env python3
2
2
  """Command line interface for Jarvis."""
3
3
 
4
+ from jarvis.utils import PrettyOutput, OutputType, get_multiline_input, load_env_from_file
5
+ from jarvis.tools import ToolRegistry
6
+ from jarvis.agent import Agent
4
7
  import argparse
5
8
  import yaml
6
9
  import os
@@ -13,73 +16,76 @@ from jarvis.models.registry import PlatformRegistry
13
16
  # 添加父目录到Python路径以支持导入
14
17
  sys.path.insert(0, str(Path(__file__).parent.parent))
15
18
 
16
- from jarvis.agent import Agent
17
- from jarvis.tools import ToolRegistry
18
- from jarvis.utils import PrettyOutput, OutputType, get_multiline_input, load_env_from_file
19
-
20
19
 
21
20
  def load_tasks() -> dict:
22
21
  """Load tasks from .jarvis files in user home and current directory."""
23
22
  tasks = {}
24
-
23
+
25
24
  # 检查用户目录下的 .jarvis
26
25
  user_jarvis = os.path.expanduser("~/.jarvis")
27
26
  if os.path.exists(user_jarvis):
28
27
  try:
29
28
  with open(user_jarvis, "r", encoding="utf-8") as f:
30
29
  user_tasks = yaml.safe_load(f)
31
-
30
+
32
31
  if isinstance(user_tasks, dict):
33
32
  # 验证并添加用户目录的任务
34
33
  for name, desc in user_tasks.items():
35
34
  if desc: # 确保描述不为空
36
35
  tasks[str(name)] = str(desc)
37
36
  else:
38
- PrettyOutput.print("Warning: ~/.jarvis file should contain a dictionary of task_name: task_description", OutputType.ERROR)
37
+ PrettyOutput.print(
38
+ "Warning: ~/.jarvis file should contain a dictionary of task_name: task_description",
39
+ OutputType.ERROR)
39
40
  except Exception as e:
40
- PrettyOutput.print(f"Error loading ~/.jarvis file: {str(e)}", OutputType.ERROR)
41
-
41
+ PrettyOutput.print(
42
+ f"Error loading ~/.jarvis file: {str(e)}", OutputType.ERROR)
43
+
42
44
  # 检查当前目录下的 .jarvis
43
45
  if os.path.exists(".jarvis"):
44
46
  try:
45
47
  with open(".jarvis", "r", encoding="utf-8") as f:
46
48
  local_tasks = yaml.safe_load(f)
47
-
49
+
48
50
  if isinstance(local_tasks, dict):
49
51
  # 验证并添加当前目录的任务,如果有重名则覆盖用户目录的任务
50
52
  for name, desc in local_tasks.items():
51
53
  if desc: # 确保描述不为空
52
54
  tasks[str(name)] = str(desc)
53
55
  else:
54
- PrettyOutput.print("Warning: .jarvis file should contain a dictionary of task_name: task_description", OutputType.ERROR)
56
+ PrettyOutput.print(
57
+ "Warning: .jarvis file should contain a dictionary of task_name: task_description",
58
+ OutputType.ERROR)
55
59
  except Exception as e:
56
- PrettyOutput.print(f"Error loading .jarvis file: {str(e)}", OutputType.ERROR)
57
-
60
+ PrettyOutput.print(
61
+ f"Error loading .jarvis file: {
62
+ str(e)}", OutputType.ERROR)
63
+
58
64
  return tasks
59
65
 
66
+
60
67
  def select_task(tasks: dict) -> str:
61
68
  """Let user select a task from the list or skip. Returns task description if selected."""
62
69
  if not tasks:
63
70
  return ""
64
-
71
+
65
72
  # Convert tasks to list for ordered display
66
73
  task_names = list(tasks.keys())
67
-
74
+
68
75
  PrettyOutput.print("\nAvailable tasks:", OutputType.INFO)
69
76
  for i, name in enumerate(task_names, 1):
70
77
  PrettyOutput.print(f"[{i}] {name}", OutputType.INFO)
71
78
  PrettyOutput.print("[0] 跳过预定义任务", OutputType.INFO)
72
-
73
-
79
+
74
80
  while True:
75
81
  try:
76
82
  choice = prompt(
77
83
  "\n请选择一个任务编号(0跳过): ",
78
84
  ).strip()
79
-
85
+
80
86
  if not choice:
81
87
  return ""
82
-
88
+
83
89
  choice = int(choice)
84
90
  if choice == 0:
85
91
  return ""
@@ -87,8 +93,10 @@ def select_task(tasks: dict) -> str:
87
93
  selected_name = task_names[choice - 1]
88
94
  return tasks[selected_name] # Return the task description
89
95
  else:
90
- PrettyOutput.print("Invalid choice. Please select a number from the list.", OutputType.ERROR)
91
-
96
+ PrettyOutput.print(
97
+ "Invalid choice. Please select a number from the list.",
98
+ OutputType.ERROR)
99
+
92
100
  except KeyboardInterrupt:
93
101
  return "" # Return empty on Ctrl+C
94
102
  except EOFError:
@@ -97,12 +105,16 @@ def select_task(tasks: dict) -> str:
97
105
  PrettyOutput.print(f"选择失败: {str(e)}", OutputType.ERROR)
98
106
  continue
99
107
 
108
+
100
109
  def main():
101
110
  """Jarvis 的主入口点"""
102
111
  # 添加参数解析器
103
112
  parser = argparse.ArgumentParser(description='Jarvis AI 助手')
104
113
  parser.add_argument('-f', '--files', nargs='*', help='要处理的文件列表')
105
- parser.add_argument('--keep-history', action='store_true', help='保持聊天历史(不删除会话)')
114
+ parser.add_argument(
115
+ '--keep-history',
116
+ action='store_true',
117
+ help='保持聊天历史(不删除会话)')
106
118
  parser.add_argument('-p', '--platform', default='', help='选择AI平台')
107
119
  args = parser.parse_args()
108
120
 
@@ -111,36 +123,45 @@ def main():
111
123
  platform = args.platform if args.platform else os.getenv('JARVIS_PLATFORM')
112
124
 
113
125
  if not platform:
114
- PrettyOutput.print("未指定AI平台,请使用 -p 参数或者设置 JARVIS_PLATFORM 环境变量", OutputType.ERROR)
126
+ PrettyOutput.print(
127
+ "未指定AI平台,请使用 -p 参数或者设置 JARVIS_PLATFORM 环境变量",
128
+ OutputType.ERROR)
115
129
  return 1
116
130
 
117
131
  PlatformRegistry.get_global_platform_registry().set_global_platform_name(platform)
118
-
132
+
119
133
  try:
120
134
  # 获取全局模型实例
121
135
  agent = Agent()
122
136
 
123
137
  # 欢迎信息
124
- PrettyOutput.print(f"Jarvis 已初始化 - With {platform} 平台,模型: {agent.model.name()}", OutputType.SYSTEM)
138
+ PrettyOutput.print(
139
+ f"Jarvis 已初始化 - With {platform} 平台,模型: {agent.model.name()}", OutputType.SYSTEM)
125
140
  if args.keep_history:
126
141
  PrettyOutput.print("已启用历史保留模式", OutputType.INFO)
127
-
142
+
128
143
  # 加载预定义任务
129
144
  tasks = load_tasks()
130
145
  if tasks:
131
146
  selected_task = select_task(tasks)
132
147
  if selected_task:
133
148
  PrettyOutput.print(f"\n执行任务: {selected_task}", OutputType.INFO)
134
- agent.run(selected_task, args.files, keep_history=args.keep_history)
149
+ agent.run(
150
+ selected_task,
151
+ args.files,
152
+ keep_history=args.keep_history)
135
153
  return 0
136
-
154
+
137
155
  # 如果没有选择预定义任务,进入交互模式
138
156
  while True:
139
157
  try:
140
158
  user_input = get_multiline_input("请输入您的任务(输入空行退出):")
141
159
  if not user_input or user_input == "__interrupt__":
142
160
  break
143
- agent.run(user_input, args.files, keep_history=args.keep_history)
161
+ agent.run(
162
+ user_input,
163
+ args.files,
164
+ keep_history=args.keep_history)
144
165
  except Exception as e:
145
166
  PrettyOutput.print(f"错误: {str(e)}", OutputType.ERROR)
146
167
 
@@ -150,5 +171,6 @@ def main():
150
171
 
151
172
  return 0
152
173
 
174
+
153
175
  if __name__ == "__main__":
154
- exit(main())
176
+ exit(main())
jarvis/models/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  from .base import BasePlatform
2
2
 
3
- __all__ = ['BasePlatform']
3
+ __all__ = ['BasePlatform']