jarvis-ai-assistant 0.1.3__py3-none-any.whl → 0.1.6__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 (33) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/__pycache__/__init__.cpython-313.pyc +0 -0
  3. jarvis/__pycache__/agent.cpython-313.pyc +0 -0
  4. jarvis/__pycache__/main.cpython-313.pyc +0 -0
  5. jarvis/__pycache__/models.cpython-313.pyc +0 -0
  6. jarvis/__pycache__/utils.cpython-313.pyc +0 -0
  7. jarvis/__pycache__/zte_llm.cpython-313.pyc +0 -0
  8. jarvis/agent.py +131 -36
  9. jarvis/main.py +44 -24
  10. jarvis/models.py +54 -36
  11. jarvis/tools/__init__.py +3 -9
  12. jarvis/tools/__pycache__/__init__.cpython-313.pyc +0 -0
  13. jarvis/tools/__pycache__/base.cpython-313.pyc +0 -0
  14. jarvis/tools/__pycache__/shell.cpython-313.pyc +0 -0
  15. jarvis/tools/__pycache__/sub_agent.cpython-313.pyc +0 -0
  16. jarvis/tools/__pycache__/user_input.cpython-313.pyc +0 -0
  17. jarvis/tools/base.py +57 -138
  18. jarvis/tools/shell.py +62 -48
  19. jarvis/tools/sub_agent.py +141 -0
  20. jarvis/tools/user_input.py +74 -0
  21. jarvis/utils.py +123 -64
  22. jarvis/zte_llm.py +136 -0
  23. {jarvis_ai_assistant-0.1.3.dist-info → jarvis_ai_assistant-0.1.6.dist-info}/METADATA +6 -4
  24. jarvis_ai_assistant-0.1.6.dist-info/RECORD +38 -0
  25. {jarvis_ai_assistant-0.1.3.dist-info → jarvis_ai_assistant-0.1.6.dist-info}/WHEEL +1 -1
  26. jarvis/.jarvis +0 -1
  27. jarvis/tools/python_script.py +0 -150
  28. jarvis/tools/rag.py +0 -154
  29. jarvis/tools/user_confirmation.py +0 -58
  30. jarvis/tools/user_interaction.py +0 -86
  31. jarvis_ai_assistant-0.1.3.dist-info/RECORD +0 -36
  32. {jarvis_ai_assistant-0.1.3.dist-info → jarvis_ai_assistant-0.1.6.dist-info}/entry_points.txt +0 -0
  33. {jarvis_ai_assistant-0.1.3.dist-info → jarvis_ai_assistant-0.1.6.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.3"
3
+ __version__ = "0.1.6"
Binary file
Binary file
Binary file
Binary file
Binary file
jarvis/agent.py CHANGED
@@ -2,70 +2,137 @@ import json
2
2
  import subprocess
3
3
  from typing import Dict, Any, List, Optional
4
4
  from .tools import ToolRegistry
5
- from .utils import Spinner, PrettyOutput, OutputType, get_multiline_input
6
- from .models import BaseModel, OllamaModel
5
+ from .utils import PrettyOutput, OutputType, get_multiline_input
6
+ from .models import BaseModel
7
7
  import re
8
8
  import os
9
9
  from datetime import datetime
10
10
 
11
11
  class Agent:
12
- def __init__(self, model: BaseModel, tool_registry: ToolRegistry):
12
+ def __init__(self, model: BaseModel, tool_registry: ToolRegistry, name: str = "Jarvis"):
13
+ """Initialize Agent with a model, optional tool registry and name"""
13
14
  self.model = model
14
- self.tool_registry = tool_registry
15
- # 编译正则表达式
16
- self.tool_call_pattern = re.compile(r'<tool_call>\s*({[^}]+})\s*</tool_call>')
15
+ self.tool_registry = tool_registry or ToolRegistry(model)
16
+ self.name = name
17
+
18
+ # 构建工具说明
19
+ tools_prompt = "Available Tools:\n"
20
+ for tool in self.tool_registry.get_all_tools():
21
+ tools_prompt += f"- Tool: {tool['function']['name']}\n"
22
+ tools_prompt += f" Description: {tool['function']['description']}\n"
23
+ tools_prompt += f" Arguments: {tool['function']['parameters']}\n"
24
+
17
25
  self.messages = [
18
26
  {
19
27
  "role": "system",
20
- "content": """You are a rigorous AI assistant, all data must be obtained through tools, and no fabrication or speculation is allowed. """ + "\n" + self.tool_registry.tool_help_text()
28
+ "content": f"""You are {name}, an AI assistant that follows the ReAct (Reasoning + Acting) framework to solve tasks step by step.
29
+
30
+ FRAMEWORK:
31
+ 1. Thought: Analyze the current situation and plan the next step
32
+ 2. Action: Execute ONE specific tool call
33
+ 3. Observation: Review the result
34
+ 4. Next: Plan the next step or conclude
35
+
36
+ FORMAT:
37
+ Thought: I need to [reasoning about the current situation]...
38
+ Action: I will use [tool] to [purpose]...
39
+ <START_TOOL_CALL>
40
+ name: tool_name
41
+ arguments:
42
+ param1: value1
43
+ <END_TOOL_CALL>
44
+
45
+ After receiving result:
46
+ Observation: The tool returned [analyze result]...
47
+ Next: Based on this, I will [next step]...
48
+
49
+ CORE RULES:
50
+ 1. ONE Action Per Response
51
+ - Only ONE tool call per response
52
+ - Additional tool calls will be ignored
53
+ - Complete current step before next
54
+
55
+ 2. Clear Reasoning
56
+ - Explain your thought process
57
+ - Justify tool selection
58
+ - Analyze results thoroughly
59
+
60
+ Examples:
61
+ ✓ Good Response:
62
+ Thought: I need to check the content of utils.py first to understand its structure.
63
+ Action: I will read the file content.
64
+ <START_TOOL_CALL>
65
+ name: file_operation
66
+ arguments:
67
+ operation: read
68
+ filepath: src/utils.py
69
+ <END_TOOL_CALL>
70
+
71
+ ✗ Bad Response:
72
+ Thought: Let's analyze the code.
73
+ Action: I'll read and check everything.
74
+ [Multiple or vague tool calls...]
75
+
76
+ Remember:
77
+ - Always start with "Thought:"
78
+ - Use exactly ONE tool per response
79
+ - Wait for results before next step
80
+ - Clearly explain your reasoning
81
+
82
+ {tools_prompt}"""
21
83
  }
22
84
  ]
23
- self.spinner = Spinner()
24
85
 
25
86
  def _call_model(self, messages: List[Dict], use_tools: bool = True) -> Dict:
26
87
  """调用模型获取响应"""
27
- self.spinner.start()
28
88
  try:
29
89
  return self.model.chat(
30
90
  messages=messages,
31
- tools=self.tool_registry.get_all_tools() if use_tools else None
91
+ tools=self.tool_registry.get_all_tools() if use_tools else []
32
92
  )
33
93
  except Exception as e:
34
- raise Exception(f"模型调用失败: {str(e)}")
35
- finally:
36
- self.spinner.stop()
37
-
94
+ raise Exception(f"{self.name}: 模型调用失败: {str(e)}")
38
95
 
39
- def run(self, user_input: str) :
40
- """处理用户输入并返回响应"""
41
- # 检查是否是结束命令
96
+ def run(self, user_input: str) -> str:
97
+ """处理用户输入并返回响应,返回任务总结报告"""
42
98
  self.clear_history()
99
+
100
+ # 显示任务开始
101
+ PrettyOutput.section(f"开始新任务: {self.name}", OutputType.PLANNING)
102
+
43
103
  self.messages.append({
44
104
  "role": "user",
45
105
  "content": user_input
46
106
  })
107
+
47
108
  while True:
48
109
  try:
49
- # 获取初始响应
110
+ # 显示思考状态
111
+ PrettyOutput.print("分析任务...", OutputType.PROGRESS)
50
112
  response = self._call_model(self.messages)
51
113
  current_response = response
52
114
 
53
- # 将工具执行结果添加到对话
115
+ # 流式输出已经在model中处理,这里添加换行
116
+ PrettyOutput.print_stream_end()
117
+
54
118
  self.messages.append({
55
119
  "role": "assistant",
56
120
  "content": response["message"].get("content", ""),
57
121
  "tool_calls": current_response["message"]["tool_calls"]
58
122
  })
59
123
 
60
- # 处理可能的多轮工具调用
61
124
  if len(current_response["message"]["tool_calls"]) > 0:
62
- # 添加当前助手响应到输出(如果有内容)
63
125
  if current_response["message"].get("content"):
64
126
  PrettyOutput.print(current_response["message"]["content"], OutputType.SYSTEM)
65
127
 
66
- # 使用 ToolRegistry 的 handle_tool_calls 方法处理工具调用
67
- tool_result = self.tool_registry.handle_tool_calls(current_response["message"]["tool_calls"])
68
- PrettyOutput.print(tool_result, OutputType.RESULT)
128
+ try:
129
+ # 显示工具调用
130
+ PrettyOutput.print("执行工具调用...", OutputType.PROGRESS)
131
+ tool_result = self.tool_registry.handle_tool_calls(current_response["message"]["tool_calls"])
132
+ PrettyOutput.print(tool_result, OutputType.RESULT)
133
+ except Exception as e:
134
+ PrettyOutput.print(str(e), OutputType.ERROR)
135
+ tool_result = f"Tool call failed: {str(e)}"
69
136
 
70
137
  self.messages.append({
71
138
  "role": "tool",
@@ -73,18 +140,47 @@ class Agent:
73
140
  })
74
141
  continue
75
142
 
76
- # 添加最终响应到对话历史和输出
77
- final_content = current_response["message"].get("content", "")
78
-
79
- if final_content:
80
- PrettyOutput.print(final_content, OutputType.SYSTEM)
143
+ # 获取用户输入
144
+ user_input = get_multiline_input(f"{self.name}: 您可以继续输入,或输入空行结束当前任务")
145
+ if not user_input:
146
+ PrettyOutput.print("生成任务总结...", OutputType.PROGRESS)
147
+
148
+ # 生成任务总结
149
+ summary_prompt = {
150
+ "role": "user",
151
+ "content": """The task has been completed. Based on the previous analysis and execution results, provide a task summary including:
152
+
153
+ 1. Key Information:
154
+ - Essential findings from analysis
155
+ - Important results from tool executions
156
+ - Critical data discovered
157
+
158
+ 2. Task Results:
159
+ - Final outcome
160
+ - Actual achievements
161
+ - Concrete results
162
+
163
+ Focus only on facts and actual results. Be direct and concise."""
164
+ }
81
165
 
166
+ while True:
167
+ try:
168
+ summary_response = self._call_model(self.messages + [summary_prompt], use_tools=False)
169
+ summary = summary_response["message"].get("content", "")
170
+
171
+ # 显示任务总结
172
+ PrettyOutput.section("任务总结", OutputType.SUCCESS)
173
+ PrettyOutput.print(summary, OutputType.SYSTEM)
174
+ PrettyOutput.section("任务完成", OutputType.SUCCESS)
175
+
176
+ return summary
177
+
178
+ except Exception as e:
179
+ PrettyOutput.print(str(e), OutputType.ERROR)
82
180
 
83
- # 如果没有工具调用且响应很短,可能需要继续对话
84
- user_input = get_multiline_input("您可以继续输入,或输入空行结束当前任务")
85
- if not user_input:
86
- PrettyOutput.print("===============任务结束===============", OutputType.INFO)
87
- break
181
+ if user_input == "__interrupt__":
182
+ PrettyOutput.print("任务已取消", OutputType.WARNING)
183
+ return "Task cancelled by user"
88
184
 
89
185
  self.messages.append({
90
186
  "role": "user",
@@ -92,8 +188,7 @@ class Agent:
92
188
  })
93
189
 
94
190
  except Exception as e:
95
- error_msg = f"处理响应时出错: {str(e)}"
96
- PrettyOutput.print(error_msg, OutputType.ERROR)
191
+ PrettyOutput.print(str(e), OutputType.ERROR)
97
192
 
98
193
  def clear_history(self):
99
194
  """清除对话历史,只保留系统提示"""
jarvis/main.py CHANGED
@@ -13,46 +13,60 @@ sys.path.insert(0, str(Path(__file__).parent.parent))
13
13
  from jarvis.agent import Agent
14
14
  from jarvis.tools import ToolRegistry
15
15
  from jarvis.models import DDGSModel, OllamaModel
16
- from jarvis.utils import PrettyOutput, OutputType, get_multiline_input
16
+ from jarvis.utils import PrettyOutput, OutputType, get_multiline_input, load_env_from_file
17
+ from jarvis.zte_llm import create_zte_llm
17
18
 
18
19
  # 定义支持的平台和模型
19
20
  SUPPORTED_PLATFORMS = {
20
21
  "ollama": {
21
- "models": ["llama3.2", "qwen2.5:14b"],
22
+ "models": ["qwen2.5:14b", "qwq"],
22
23
  "default": "qwen2.5:14b"
23
24
  },
24
25
  "ddgs": {
25
26
  "models": ["gpt-4o-mini", "claude-3-haiku", "llama-3.1-70b", "mixtral-8x7b"],
26
27
  "default": "gpt-4o-mini"
28
+ },
29
+ "zte": {
30
+ "models": ["NebulaBiz", "nebulacoder", "NTele-72B"],
31
+ "default": "NebulaBiz"
27
32
  }
28
33
  }
29
34
 
30
- def load_tasks() -> list:
35
+ def load_tasks() -> dict:
31
36
  """Load tasks from .jarvis file if it exists."""
32
37
  if not os.path.exists(".jarvis"):
33
- return []
38
+ return {}
34
39
 
35
40
  try:
36
41
  with open(".jarvis", "r", encoding="utf-8") as f:
37
42
  tasks = yaml.safe_load(f)
38
43
 
39
- if not isinstance(tasks, list):
40
- PrettyOutput.print("Warning: .jarvis file should contain a list of tasks", OutputType.ERROR)
41
- return []
44
+ if not isinstance(tasks, dict):
45
+ PrettyOutput.print("Warning: .jarvis file should contain a dictionary of task_name: task_description", OutputType.ERROR)
46
+ return {}
42
47
 
43
- return [str(task) for task in tasks if task] # Convert all tasks to strings and filter out empty ones
48
+ # Validate format and convert all values to strings
49
+ validated_tasks = {}
50
+ for name, desc in tasks.items():
51
+ if desc: # Ensure description is not empty
52
+ validated_tasks[str(name)] = str(desc)
53
+
54
+ return validated_tasks
44
55
  except Exception as e:
45
56
  PrettyOutput.print(f"Error loading .jarvis file: {str(e)}", OutputType.ERROR)
46
- return []
57
+ return {}
47
58
 
48
- def select_task(tasks: list) -> str:
49
- """Let user select a task from the list or skip."""
59
+ def select_task(tasks: dict) -> str:
60
+ """Let user select a task from the list or skip. Returns task description if selected."""
50
61
  if not tasks:
51
62
  return ""
52
63
 
53
- PrettyOutput.print("\nFound predefined tasks:", OutputType.INFO)
54
- for i, task in enumerate(tasks, 1):
55
- PrettyOutput.print(f"[{i}] {task}", OutputType.INFO)
64
+ # Convert tasks to list for ordered display
65
+ task_names = list(tasks.keys())
66
+
67
+ PrettyOutput.print("\nAvailable tasks:", OutputType.INFO)
68
+ for i, name in enumerate(task_names, 1):
69
+ PrettyOutput.print(f"[{i}] {name}", OutputType.INFO)
56
70
  PrettyOutput.print("[0] Skip predefined tasks", OutputType.INFO)
57
71
 
58
72
  while True:
@@ -64,8 +78,9 @@ def select_task(tasks: list) -> str:
64
78
  choice = int(choice)
65
79
  if choice == 0:
66
80
  return ""
67
- elif 1 <= choice <= len(tasks):
68
- return tasks[choice - 1]
81
+ elif 1 <= choice <= len(task_names):
82
+ selected_name = task_names[choice - 1]
83
+ return tasks[selected_name] # Return the task description
69
84
  else:
70
85
  PrettyOutput.print("Invalid choice. Please try again.", OutputType.ERROR)
71
86
  except ValueError:
@@ -73,13 +88,16 @@ def select_task(tasks: list) -> str:
73
88
 
74
89
  def main():
75
90
  """Main entry point for Jarvis."""
91
+
92
+ load_env_from_file()
93
+
76
94
  parser = argparse.ArgumentParser(description="Jarvis AI Assistant")
77
95
 
78
96
  # 添加平台选择参数
79
97
  parser.add_argument(
80
98
  "--platform",
81
99
  choices=list(SUPPORTED_PLATFORMS.keys()),
82
- default="ollama",
100
+ default=os.getenv("JARVIS_PLATFORM") or "ddgs",
83
101
  help="选择运行平台 (默认: ollama)"
84
102
  )
85
103
 
@@ -92,11 +110,13 @@ def main():
92
110
  # 添加API基础URL参数
93
111
  parser.add_argument(
94
112
  "--api-base",
95
- default="http://localhost:11434",
113
+ default=os.getenv("JARVIS_OLLAMA_API_BASE") or "http://localhost:11434",
96
114
  help="Ollama API基础URL (仅用于Ollama平台, 默认: http://localhost:11434)"
97
115
  )
98
116
 
99
117
  args = parser.parse_args()
118
+
119
+ args.model = args.model or os.getenv("JARVIS_MODEL")
100
120
 
101
121
  # 验证并设置默认模型
102
122
  if args.model:
@@ -119,11 +139,14 @@ def main():
119
139
  api_base=args.api_base
120
140
  )
121
141
  platform_name = f"Ollama ({args.model})"
122
- else: # ddgs
142
+ elif args.platform == "ddgs": # ddgs
123
143
  model = DDGSModel(model_name=args.model)
124
144
  platform_name = f"DuckDuckGo Search ({args.model})"
145
+ elif args.platform == "zte": # zte
146
+ model = create_zte_llm(model_name=args.model)
147
+ platform_name = f"ZTE ({args.model})"
125
148
 
126
- tool_registry = ToolRegistry()
149
+ tool_registry = ToolRegistry(model)
127
150
  agent = Agent(model, tool_registry)
128
151
 
129
152
  # 欢迎信息
@@ -142,12 +165,9 @@ def main():
142
165
  while True:
143
166
  try:
144
167
  user_input = get_multiline_input("请输入您的任务(输入空行退出):")
145
- if not user_input:
168
+ if not user_input or user_input == "__interrupt__":
146
169
  break
147
170
  agent.run(user_input)
148
- except KeyboardInterrupt:
149
- print("\n正在退出...")
150
- break
151
171
  except Exception as e:
152
172
  PrettyOutput.print(f"错误: {str(e)}", OutputType.ERROR)
153
173
 
jarvis/models.py CHANGED
@@ -1,10 +1,10 @@
1
- import json
2
1
  import re
3
2
  import time
4
3
  from typing import Dict, List, Optional
5
4
  from duckduckgo_search import DDGS
6
5
  import ollama
7
6
  from abc import ABC, abstractmethod
7
+ import yaml
8
8
 
9
9
  from .utils import OutputType, PrettyOutput
10
10
 
@@ -18,34 +18,46 @@ class BaseModel(ABC):
18
18
 
19
19
  @staticmethod
20
20
  def extract_tool_calls(content: str) -> List[Dict]:
21
- """从内容中提取工具调用"""
22
- tool_calls = []
23
- # 修改正则表达式以更好地处理多行内容
24
- pattern = re.compile(
25
- r'<tool_call>\s*({(?:[^{}]|(?:{[^{}]*})|(?:{(?:[^{}]|{[^{}]*})*}))*})\s*</tool_call>',
26
- re.DOTALL # 添加DOTALL标志以匹配跨行内容
27
- )
21
+ """从内容中提取工具调用,只返回第一个有效的工具调用"""
22
+ # 分割内容为行
23
+ lines = content.split('\n')
24
+ tool_call_lines = []
25
+ in_tool_call = False
28
26
 
29
- matches = pattern.finditer(content)
30
- for match in matches:
31
- try:
32
- tool_call_str = match.group(1).strip()
33
- tool_call = json.loads(tool_call_str)
34
- if isinstance(tool_call, dict) and "name" in tool_call and "arguments" in tool_call:
35
- tool_calls.append({
36
- "function": {
37
- "name": tool_call["name"],
38
- "arguments": tool_call["arguments"]
39
- }
40
- })
41
- else:
42
- PrettyOutput.print(f"无效的工具调用格式: {tool_call_str}", OutputType.ERROR)
43
- except json.JSONDecodeError as e:
44
- PrettyOutput.print(f"JSON解析错误: {str(e)}", OutputType.ERROR)
45
- PrettyOutput.print(f"解析内容: {tool_call_str}", OutputType.ERROR)
27
+ # 逐行处理
28
+ for line in lines:
29
+ if not line:
46
30
  continue
31
+
32
+ if line == '<START_TOOL_CALL>':
33
+ tool_call_lines = []
34
+ in_tool_call = True
35
+ continue
36
+ elif line == '<END_TOOL_CALL>':
37
+ if in_tool_call and tool_call_lines:
38
+ try:
39
+ # 解析工具调用内容
40
+ tool_call_text = '\n'.join(tool_call_lines)
41
+ tool_call_data = yaml.safe_load(tool_call_text)
42
+
43
+ # 验证必要的字段
44
+ if "name" in tool_call_data and "arguments" in tool_call_data:
45
+ # 只返回第一个有效的工具调用
46
+ return [{
47
+ "function": {
48
+ "name": tool_call_data["name"],
49
+ "arguments": tool_call_data["arguments"]
50
+ }
51
+ }]
52
+ except yaml.YAMLError:
53
+ pass # 跳过无效的YAML
54
+ except Exception:
55
+ pass # 跳过其他错误
56
+ in_tool_call = False
57
+ elif in_tool_call:
58
+ tool_call_lines.append(line)
47
59
 
48
- return tool_calls
60
+ return [] # 如果没有找到有效的工具调用,返回空列表
49
61
 
50
62
 
51
63
  class DDGSModel(BaseModel):
@@ -59,11 +71,7 @@ class DDGSModel(BaseModel):
59
71
  self.model_name = model_name
60
72
 
61
73
  def __make_prompt(self, messages: List[Dict], tools: Optional[List[Dict]] = None) -> str:
62
- prompt = "You are an AI Agent skilled in utilizing tools and planning tasks. Based on the task input by the user and the list of available tools, you output the tool invocation methods in a specified format. The user will provide feedback on the results of the tool execution, allowing you to continue analyzing and ultimately complete the user's designated task. Below is the list of tools and their usage methods. Let's use them step by step to accomplish the user's task.\n"
63
- for tool in tools:
64
- prompt += f"- Tool: {tool['function']['name']}\n"
65
- prompt += f" Description: {tool['function']['description']}\n"
66
- prompt += f" Arguments: {tool['function']['parameters']}\n"
74
+ prompt = ""
67
75
  for message in messages:
68
76
  prompt += f"[{message['role']}]: {message['content']}\n"
69
77
  return prompt
@@ -72,6 +80,7 @@ class DDGSModel(BaseModel):
72
80
  ddgs = DDGS()
73
81
  prompt = self.__make_prompt(messages, tools)
74
82
  content = ddgs.chat(prompt)
83
+ PrettyOutput.print_stream(content, OutputType.SYSTEM)
75
84
  tool_calls = BaseModel.extract_tool_calls(content)
76
85
  return {
77
86
  "message": {
@@ -92,16 +101,25 @@ class OllamaModel(BaseModel):
92
101
  def chat(self, messages: List[Dict], tools: Optional[List[Dict]] = None) -> Dict:
93
102
  """调用Ollama API获取响应"""
94
103
  try:
95
- response = self.client.chat(
104
+ # 使用流式调用
105
+ stream = self.client.chat(
96
106
  model=self.model_name,
97
107
  messages=messages,
98
- tools=tools
108
+ stream=True
99
109
  )
100
110
 
101
- content = response.message.content
102
- tool_calls = response.message.tool_calls or BaseModel.extract_tool_calls(content)
111
+ # 收集完整响应
112
+ content_parts = []
113
+ for chunk in stream:
114
+ if chunk.message.content:
115
+ content_parts.append(chunk.message.content)
116
+ # 实时打印内容
117
+ PrettyOutput.print_stream(chunk.message.content, OutputType.SYSTEM)
118
+
119
+ # 合并完整内容
120
+ content = "".join(content_parts)
121
+ tool_calls = BaseModel.extract_tool_calls(content)
103
122
 
104
- # 转换响应格式
105
123
  return {
106
124
  "message": {
107
125
  "content": content,
jarvis/tools/__init__.py CHANGED
@@ -1,22 +1,16 @@
1
1
  from .base import Tool, ToolRegistry
2
- from .python_script import PythonScript
3
2
  from .file_ops import FileOperationTool
4
3
  from .search import SearchTool
5
4
  from .shell import ShellTool
6
- from .user_interaction import UserInteractionTool
7
- from .user_confirmation import UserConfirmationTool
8
- from .rag import RAGTool
9
5
  from .webpage import WebpageTool
6
+ from .user_input import UserInputTool
10
7
 
11
8
  __all__ = [
12
9
  'Tool',
13
10
  'ToolRegistry',
14
- 'PythonScript',
15
11
  'FileOperationTool',
16
12
  'SearchTool',
17
13
  'ShellTool',
18
- 'UserInteractionTool',
19
- 'UserConfirmationTool',
20
- 'RAGTool',
21
14
  'WebpageTool',
22
- ]
15
+ 'UserInputTool',
16
+ ]