jarvis-ai-assistant 0.1.3__tar.gz → 0.1.5__tar.gz

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 (54) hide show
  1. {jarvis_ai_assistant-0.1.3/src/jarvis_ai_assistant.egg-info → jarvis_ai_assistant-0.1.5}/PKG-INFO +6 -4
  2. {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/pyproject.toml +3 -9
  3. {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/setup.py +2 -3
  4. {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/__init__.py +1 -1
  5. jarvis_ai_assistant-0.1.5/src/jarvis/__pycache__/__init__.cpython-313.pyc +0 -0
  6. jarvis_ai_assistant-0.1.5/src/jarvis/__pycache__/agent.cpython-313.pyc +0 -0
  7. jarvis_ai_assistant-0.1.5/src/jarvis/__pycache__/main.cpython-313.pyc +0 -0
  8. jarvis_ai_assistant-0.1.5/src/jarvis/__pycache__/utils.cpython-313.pyc +0 -0
  9. jarvis_ai_assistant-0.1.5/src/jarvis/__pycache__/zte_llm.cpython-313.pyc +0 -0
  10. jarvis_ai_assistant-0.1.5/src/jarvis/agent.py +133 -0
  11. {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/main.py +38 -18
  12. {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/models.py +15 -17
  13. {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/tools/__init__.py +0 -6
  14. jarvis_ai_assistant-0.1.5/src/jarvis/tools/__pycache__/__init__.cpython-313.pyc +0 -0
  15. jarvis_ai_assistant-0.1.5/src/jarvis/tools/__pycache__/base.cpython-313.pyc +0 -0
  16. {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/tools/__pycache__/shell.cpython-313.pyc +0 -0
  17. jarvis_ai_assistant-0.1.5/src/jarvis/tools/__pycache__/sub_agent.cpython-313.pyc +0 -0
  18. {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/tools/base.py +70 -83
  19. jarvis_ai_assistant-0.1.5/src/jarvis/tools/sub_agent.py +79 -0
  20. {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/utils.py +25 -2
  21. jarvis_ai_assistant-0.1.5/src/jarvis/zte_llm.py +132 -0
  22. {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5/src/jarvis_ai_assistant.egg-info}/PKG-INFO +6 -4
  23. {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis_ai_assistant.egg-info/SOURCES.txt +5 -3
  24. {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis_ai_assistant.egg-info/requires.txt +1 -2
  25. jarvis_ai_assistant-0.1.3/src/jarvis/__pycache__/__init__.cpython-313.pyc +0 -0
  26. jarvis_ai_assistant-0.1.3/src/jarvis/__pycache__/agent.cpython-313.pyc +0 -0
  27. jarvis_ai_assistant-0.1.3/src/jarvis/__pycache__/utils.cpython-313.pyc +0 -0
  28. jarvis_ai_assistant-0.1.3/src/jarvis/agent.py +0 -100
  29. jarvis_ai_assistant-0.1.3/src/jarvis/tools/__pycache__/__init__.cpython-313.pyc +0 -0
  30. jarvis_ai_assistant-0.1.3/src/jarvis/tools/__pycache__/base.cpython-313.pyc +0 -0
  31. jarvis_ai_assistant-0.1.3/src/jarvis/tools/rag.py +0 -154
  32. jarvis_ai_assistant-0.1.3/src/jarvis/tools/user_confirmation.py +0 -58
  33. jarvis_ai_assistant-0.1.3/src/jarvis/tools/user_interaction.py +0 -86
  34. {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/MANIFEST.in +0 -0
  35. {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/README.md +0 -0
  36. {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/setup.cfg +0 -0
  37. {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/.jarvis +0 -0
  38. {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/__pycache__/models.cpython-313.pyc +0 -0
  39. {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/__pycache__/tools.cpython-313.pyc +0 -0
  40. {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/tools/__pycache__/file_ops.cpython-313.pyc +0 -0
  41. {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/tools/__pycache__/python_script.cpython-313.pyc +0 -0
  42. {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/tools/__pycache__/rag.cpython-313.pyc +0 -0
  43. {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/tools/__pycache__/search.cpython-313.pyc +0 -0
  44. {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/tools/__pycache__/user_confirmation.cpython-313.pyc +0 -0
  45. {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/tools/__pycache__/user_interaction.cpython-313.pyc +0 -0
  46. {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/tools/__pycache__/webpage.cpython-313.pyc +0 -0
  47. {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/tools/file_ops.py +0 -0
  48. {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/tools/python_script.py +0 -0
  49. {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/tools/search.py +0 -0
  50. {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/tools/shell.py +0 -0
  51. {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/tools/webpage.py +0 -0
  52. {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis_ai_assistant.egg-info/dependency_links.txt +0 -0
  53. {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis_ai_assistant.egg-info/entry_points.txt +0 -0
  54. {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis_ai_assistant.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: jarvis-ai-assistant
3
- Version: 0.1.3
3
+ Version: 0.1.5
4
4
  Summary: Jarvis: An AI assistant that uses tools to interact with the system
5
5
  Home-page: https://github.com/skyfireitdiy/Jarvis
6
6
  Author: skyfire
@@ -21,13 +21,15 @@ Requires-Dist: beautifulsoup4>=4.9.3
21
21
  Requires-Dist: duckduckgo-search>=3.0.0
22
22
  Requires-Dist: pyyaml>=5.1
23
23
  Requires-Dist: ollama>=0.1.6
24
- Requires-Dist: sentence-transformers>=2.5.1
25
- Requires-Dist: chromadb>=0.4.24
24
+ Requires-Dist: colorama>=0.4.6
26
25
  Provides-Extra: dev
27
26
  Requires-Dist: pytest; extra == "dev"
28
27
  Requires-Dist: black; extra == "dev"
29
28
  Requires-Dist: isort; extra == "dev"
30
29
  Requires-Dist: mypy; extra == "dev"
30
+ Dynamic: author
31
+ Dynamic: home-page
32
+ Dynamic: requires-python
31
33
 
32
34
  <div align="center">
33
35
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "jarvis-ai-assistant"
7
- version = "0.1.3"
7
+ version = "0.1.5"
8
8
  description = "Jarvis: An AI assistant that uses tools to interact with the system"
9
9
  readme = "README.md"
10
10
  authors = [{ name = "Your Name", email = "your.email@example.com" }]
@@ -25,18 +25,12 @@ dependencies = [
25
25
  "duckduckgo-search>=3.0.0",
26
26
  "pyyaml>=5.1",
27
27
  "ollama>=0.1.6",
28
- "sentence-transformers>=2.5.1",
29
- "chromadb>=0.4.24",
28
+ "colorama>=0.4.6",
30
29
  ]
31
30
  requires-python = ">=3.8"
32
31
 
33
32
  [project.optional-dependencies]
34
- dev = [
35
- "pytest",
36
- "black",
37
- "isort",
38
- "mypy",
39
- ]
33
+ dev = ["pytest", "black", "isort", "mypy"]
40
34
 
41
35
  [project.urls]
42
36
  Homepage = "https://github.com/skyfireitdiy/Jarvis"
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name="jarvis-ai-assistant",
5
- version="0.1.3",
5
+ version="0.1.5",
6
6
  author="skyfire",
7
7
  author_email="skyfireitdiy@hotmail.com",
8
8
  description="An AI assistant that uses various tools to interact with the system",
@@ -18,8 +18,7 @@ setup(
18
18
  "duckduckgo-search>=3.0.0",
19
19
  "pyyaml>=5.1",
20
20
  "ollama>=0.1.6",
21
- "sentence-transformers>=2.5.1",
22
- "chromadb>=0.4.24",
21
+ "colorama>=0.4.6",
23
22
  ],
24
23
  entry_points={
25
24
  "console_scripts": [
@@ -1,3 +1,3 @@
1
1
  """Jarvis AI Assistant"""
2
2
 
3
- __version__ = "0.1.3"
3
+ __version__ = "0.1.5"
@@ -0,0 +1,133 @@
1
+ import json
2
+ import subprocess
3
+ from typing import Dict, Any, List, Optional
4
+ from .tools import ToolRegistry
5
+ from .utils import Spinner, PrettyOutput, OutputType, get_multiline_input
6
+ from .models import BaseModel
7
+ import re
8
+ import os
9
+ from datetime import datetime
10
+
11
+ class Agent:
12
+ def __init__(self, model: BaseModel, tool_registry: ToolRegistry, name: str = "Jarvis"):
13
+ """Initialize Agent with a model, optional tool registry and name"""
14
+ self.model = model
15
+ self.tool_registry = tool_registry or ToolRegistry(model)
16
+ self.name = name
17
+ # 编译正则表达式
18
+ self.tool_call_pattern = re.compile(r'<tool_call>\s*({[^}]+})\s*</tool_call>')
19
+ self.messages = [
20
+ {
21
+ "role": "system",
22
+ "content": f"""You are {name}, a rigorous AI assistant that executes tasks step by step.
23
+
24
+ Key Principles:
25
+ 1. Execute ONE step at a time
26
+ 2. Wait for each step's result before planning the next
27
+ 3. Use tools to obtain all data, no fabrication
28
+ 4. Create sub-agents for independent subtasks
29
+ 5. Think carefully before each action
30
+
31
+ """ + self.tool_registry.tool_help_text()
32
+ }
33
+ ]
34
+ self.spinner = Spinner()
35
+
36
+ def _call_model(self, messages: List[Dict], use_tools: bool = True) -> Dict:
37
+ """调用模型获取响应"""
38
+ self.spinner.start()
39
+ try:
40
+ return self.model.chat(
41
+ messages=messages,
42
+ tools=self.tool_registry.get_all_tools() if use_tools else []
43
+ )
44
+ except Exception as e:
45
+ raise Exception(f"{self.name}: 模型调用失败: {str(e)}")
46
+ finally:
47
+ self.spinner.stop()
48
+
49
+ def run(self, user_input: str) -> str:
50
+ """处理用户输入并返回响应,返回任务总结报告"""
51
+ self.clear_history()
52
+ self.messages.append({
53
+ "role": "user",
54
+ "content": user_input
55
+ })
56
+
57
+ while True:
58
+ try:
59
+ response = self._call_model(self.messages)
60
+ current_response = response
61
+
62
+ self.messages.append({
63
+ "role": "assistant",
64
+ "content": response["message"].get("content", ""),
65
+ "tool_calls": current_response["message"]["tool_calls"]
66
+ })
67
+
68
+ if len(current_response["message"]["tool_calls"]) > 0:
69
+ if current_response["message"].get("content"):
70
+ PrettyOutput.print(f"{self.name}: {current_response['message']['content']}", OutputType.SYSTEM)
71
+
72
+ tool_result = self.tool_registry.handle_tool_calls(current_response["message"]["tool_calls"])
73
+ PrettyOutput.print(f"{self.name} Tool Result: {tool_result}", OutputType.RESULT)
74
+
75
+ self.messages.append({
76
+ "role": "tool",
77
+ "content": tool_result
78
+ })
79
+ continue
80
+
81
+ final_content = current_response["message"].get("content", "")
82
+ if final_content:
83
+ PrettyOutput.print(f"{self.name}: {final_content}", OutputType.SYSTEM)
84
+
85
+ user_input = get_multiline_input(f"{self.name}: 您可以继续输入,或输入空行结束当前任务")
86
+ if not user_input:
87
+ PrettyOutput.print(f"{self.name}: 正在生成任务总结...", OutputType.INFO)
88
+
89
+ # 优化后的任务总结提示语
90
+ summary_prompt = {
91
+ "role": "user",
92
+ "content": """The task has been completed. Based on the previous analysis and execution results, provide a task summary including:
93
+
94
+ 1. Key Information:
95
+ - Essential findings from analysis
96
+ - Important results from tool executions
97
+ - Critical data discovered
98
+
99
+ 2. Task Results:
100
+ - Final outcome
101
+ - Actual achievements
102
+ - Concrete results
103
+
104
+ Focus only on facts and actual results. Be direct and concise."""
105
+ }
106
+ while True:
107
+ try:
108
+ summary_response = self._call_model(self.messages + [summary_prompt], use_tools=False)
109
+ summary = summary_response["message"].get("content", "")
110
+
111
+ PrettyOutput.print(f"==============={self.name} 任务总结===============", OutputType.INFO)
112
+ PrettyOutput.print(summary, OutputType.SYSTEM)
113
+ PrettyOutput.print("=" * (len(self.name) + 16), OutputType.INFO)
114
+
115
+ return summary
116
+
117
+ except Exception as e:
118
+ error_msg = f"{self.name}: 生成任务总结时出错: {str(e)}"
119
+ PrettyOutput.print(error_msg, OutputType.ERROR)
120
+
121
+
122
+ self.messages.append({
123
+ "role": "user",
124
+ "content": user_input
125
+ })
126
+
127
+ except Exception as e:
128
+ error_msg = f"{self.name}: 处理响应时出错: {str(e)}"
129
+ PrettyOutput.print(error_msg, OutputType.ERROR)
130
+
131
+ def clear_history(self):
132
+ """清除对话历史,只保留系统提示"""
133
+ self.messages = [self.messages[0]]
@@ -13,7 +13,8 @@ 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 = {
@@ -24,35 +25,48 @@ SUPPORTED_PLATFORMS = {
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:
@@ -79,7 +94,7 @@ def main():
79
94
  parser.add_argument(
80
95
  "--platform",
81
96
  choices=list(SUPPORTED_PLATFORMS.keys()),
82
- default="ollama",
97
+ default="ddgs",
83
98
  help="选择运行平台 (默认: ollama)"
84
99
  )
85
100
 
@@ -97,6 +112,8 @@ def main():
97
112
  )
98
113
 
99
114
  args = parser.parse_args()
115
+
116
+ load_env_from_file()
100
117
 
101
118
  # 验证并设置默认模型
102
119
  if args.model:
@@ -119,11 +136,14 @@ def main():
119
136
  api_base=args.api_base
120
137
  )
121
138
  platform_name = f"Ollama ({args.model})"
122
- else: # ddgs
139
+ elif args.platform == "ddgs": # ddgs
123
140
  model = DDGSModel(model_name=args.model)
124
141
  platform_name = f"DuckDuckGo Search ({args.model})"
142
+ elif args.platform == "zte": # zte
143
+ model = create_zte_llm(model_name=args.model)
144
+ platform_name = f"ZTE ({args.model})"
125
145
 
126
- tool_registry = ToolRegistry()
146
+ tool_registry = ToolRegistry(model)
127
147
  agent = Agent(model, tool_registry)
128
148
 
129
149
  # 欢迎信息
@@ -20,31 +20,29 @@ class BaseModel(ABC):
20
20
  def extract_tool_calls(content: str) -> List[Dict]:
21
21
  """从内容中提取工具调用"""
22
22
  tool_calls = []
23
- # 修改正则表达式以更好地处理多行内容
24
- pattern = re.compile(
25
- r'<tool_call>\s*({(?:[^{}]|(?:{[^{}]*})|(?:{(?:[^{}]|{[^{}]*})*}))*})\s*</tool_call>',
26
- re.DOTALL # 添加DOTALL标志以匹配跨行内容
27
- )
23
+ # 使用非贪婪匹配来获取标签之间的所有内容
24
+ pattern = re.compile(r'<tool_call>(.*?)</tool_call>', re.DOTALL)
28
25
 
29
26
  matches = pattern.finditer(content)
30
27
  for match in matches:
31
28
  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:
29
+ # 提取并解析 JSON
30
+ tool_call_text = match.group(1).strip()
31
+ tool_call_data = json.loads(tool_call_text)
32
+
33
+ # 验证必要的字段
34
+ if "name" in tool_call_data and "arguments" in tool_call_data:
35
35
  tool_calls.append({
36
36
  "function": {
37
- "name": tool_call["name"],
38
- "arguments": tool_call["arguments"]
37
+ "name": tool_call_data["name"],
38
+ "arguments": tool_call_data["arguments"]
39
39
  }
40
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)
46
- continue
47
-
41
+ except json.JSONDecodeError:
42
+ continue # 跳过无效的 JSON
43
+ except Exception:
44
+ continue # 跳过其他错误
45
+
48
46
  return tool_calls
49
47
 
50
48
 
@@ -3,9 +3,6 @@ from .python_script import PythonScript
3
3
  from .file_ops import FileOperationTool
4
4
  from .search import SearchTool
5
5
  from .shell import ShellTool
6
- from .user_interaction import UserInteractionTool
7
- from .user_confirmation import UserConfirmationTool
8
- from .rag import RAGTool
9
6
  from .webpage import WebpageTool
10
7
 
11
8
  __all__ = [
@@ -15,8 +12,5 @@ __all__ = [
15
12
  'FileOperationTool',
16
13
  'SearchTool',
17
14
  'ShellTool',
18
- 'UserInteractionTool',
19
- 'UserConfirmationTool',
20
- 'RAGTool',
21
15
  'WebpageTool',
22
16
  ]
@@ -1,6 +1,7 @@
1
1
  from typing import Dict, Any, List, Optional, Callable
2
2
  import json
3
3
  from ..utils import PrettyOutput, OutputType
4
+ from ..models import BaseModel
4
5
 
5
6
  class Tool:
6
7
  def __init__(self, name: str, description: str, parameters: Dict, func: Callable):
@@ -25,29 +26,25 @@ class Tool:
25
26
  return self.func(arguments)
26
27
 
27
28
  class ToolRegistry:
28
- def __init__(self):
29
+ def __init__(self, model: BaseModel):
29
30
  self.tools: Dict[str, Tool] = {}
31
+ self.model = model
30
32
  self._register_default_tools()
31
33
 
32
34
  def _register_default_tools(self):
33
35
  """注册所有默认工具"""
34
36
  from .search import SearchTool
35
37
  from .shell import ShellTool
36
- from .user_interaction import UserInteractionTool
37
- from .user_confirmation import UserConfirmationTool
38
38
  from .python_script import PythonScriptTool
39
39
  from .file_ops import FileOperationTool
40
- from .rag import RAGTool
41
40
  from .webpage import WebpageTool
41
+ from .sub_agent import SubAgentTool
42
42
 
43
43
  tools = [
44
44
  SearchTool(),
45
45
  ShellTool(),
46
- UserInteractionTool(),
47
- UserConfirmationTool(),
48
46
  PythonScriptTool(),
49
47
  FileOperationTool(),
50
- RAGTool(),
51
48
  WebpageTool(),
52
49
  ]
53
50
 
@@ -59,6 +56,14 @@ class ToolRegistry:
59
56
  func=tool.execute
60
57
  )
61
58
 
59
+ sub_agent_tool = SubAgentTool(self.model)
60
+ self.register_tool(
61
+ name=sub_agent_tool.name,
62
+ description=sub_agent_tool.description,
63
+ parameters=sub_agent_tool.parameters,
64
+ func=sub_agent_tool.execute
65
+ )
66
+
62
67
  def register_tool(self, name: str, description: str, parameters: Dict, func: Callable):
63
68
  """注册新工具"""
64
69
  self.tools[name] = Tool(name, description, parameters, func)
@@ -122,39 +127,36 @@ class ToolRegistry:
122
127
  2. read_webpage: Extract content from webpages
123
128
  3. execute_python: Run Python code with dependency management
124
129
  4. execute_shell: Execute shell commands
125
- 5. ask_user: Get input from user with options support
126
- 6. ask_user_confirmation: Get yes/no confirmation from user
127
- 7. file_operation: Read/write files in workspace directory
128
- 8. rag_query: Query documents using RAG
129
-
130
- Output Guidelines:
131
- 1. Focus on Essential Information
132
- - Filter out irrelevant or redundant information
133
- - Only output the most relevant search results
134
- - Summarize long content when possible
135
-
136
- 2. Context Management
137
- - Avoid repeating information that's already known
138
- - Don't echo back the entire content of files
139
- - Use snippets instead of full documents
140
-
141
- 3. Error Handling
142
- - Only show relevant parts of error messages
143
- - Include troubleshooting steps when appropriate
144
- - Omit stack traces unless specifically requested
145
-
146
- 4. Search Results
147
- - Focus on the most relevant 2-3 results
148
- - Extract key information instead of full articles
149
- - Skip duplicate or similar content
150
-
151
- 5. RAG Queries
152
- - Return only the most relevant passages
153
- - Combine similar information
154
- - Skip redundant context
155
-
156
- Tool Call Format Requirements:
157
- 1. MUST use exact format:
130
+ 5. file_operation: Read/write files in workspace directory
131
+ 6. create_sub_agent: Create a sub-agent to handle subtasks (ONLY for independent subtasks)
132
+
133
+ Core Rules:
134
+ 1. ONE Step at a Time
135
+ - Execute only one action per response
136
+ - Explain what you're going to do before doing it
137
+ - Wait for the result before planning next step
138
+ - No multiple actions or parallel execution
139
+
140
+ 2. Sub-Agent Usage (ONLY for Subtasks)
141
+ - Create sub-agents ONLY to handle independent subtasks
142
+ - Main task should be broken down into clear subtasks first
143
+ - Examples of good subtask delegation:
144
+ * Analyzing each Python file in a directory
145
+ * Processing each data file in a batch
146
+ * Researching different aspects of a topic
147
+ * Reviewing multiple code components
148
+ - Do NOT use for:
149
+ * Main task execution
150
+ * Single file operations
151
+ * Simple sequential steps
152
+ * Tasks requiring continuous context
153
+
154
+ 3. Output Guidelines
155
+ - Focus on essential information
156
+ - Clear step-by-step explanations
157
+ - Summarize results concisely
158
+
159
+ Tool Call Format:
158
160
  <tool_call>
159
161
  {
160
162
  "name": "tool_name",
@@ -164,48 +166,33 @@ Tool Call Format Requirements:
164
166
  }
165
167
  </tool_call>
166
168
 
167
- 2. Format Rules:
168
- - NO comments or explanations inside tool_call blocks
169
- - NO additional text or formatting within JSON
170
- - NO markdown or other markup inside tool_call
171
- - ONLY valid JSON allowed in arguments
172
- - ALL arguments must match tool parameters exactly
173
-
174
- 3. Invalid Examples (DO NOT USE):
175
- <tool_call>
176
- {
177
- "name": "search", # Search tool
178
- "arguments": {
179
- "query": "Python GIL" // Search query
180
- }
181
- }
182
- </tool_call>
183
-
184
- <tool_call>
185
- ```json
186
- {
187
- "name": "search",
188
- "arguments": {
189
- "query": "Python GIL"
190
- }
191
- }
192
- ```
193
- </tool_call>
194
-
195
- 4. Valid Example:
196
- ✅ <tool_call>
197
- {
198
- "name": "search",
199
- "arguments": {
200
- "query": "Python GIL",
201
- "max_results": 2
202
- }
203
- }
204
- </tool_call>
169
+ Example (Correct - Subtask Delegation):
170
+ Assistant: I'll create a sub-agent to handle the code analysis subtask.
171
+ <tool_call>
172
+ {
173
+ "name": "create_sub_agent",
174
+ "arguments": {
175
+ "name": "CodeAnalyzer",
176
+ "task": "Analyze the utils.py file structure and generate documentation",
177
+ "context": "This is part of the larger documentation task"
178
+ }
179
+ }
180
+ </tool_call>
181
+
182
+ Example (Incorrect - Main Task):
183
+ ❌ Assistant: I'll create a sub-agent to handle the entire project analysis.
184
+ <tool_call>
185
+ {
186
+ "name": "create_sub_agent",
187
+ "arguments": {
188
+ "name": "ProjectAnalyzer",
189
+ "task": "Analyze and document the entire project"
190
+ }
191
+ }
192
+ </tool_call>
205
193
 
206
194
  Remember:
207
- 1. Quality over quantity
208
- 2. Relevance over completeness
209
- 3. Conciseness over verbosity
210
- 4. Context efficiency is crucial
211
- 5. STRICT adherence to tool call format"""
195
+ 1. ONE step at a time
196
+ 2. Create sub-agents ONLY for subtasks
197
+ 3. Explain before acting
198
+ 4. Wait for results"""