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.
- {jarvis_ai_assistant-0.1.3/src/jarvis_ai_assistant.egg-info → jarvis_ai_assistant-0.1.5}/PKG-INFO +6 -4
- {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/pyproject.toml +3 -9
- {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/setup.py +2 -3
- {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/__init__.py +1 -1
- jarvis_ai_assistant-0.1.5/src/jarvis/__pycache__/__init__.cpython-313.pyc +0 -0
- jarvis_ai_assistant-0.1.5/src/jarvis/__pycache__/agent.cpython-313.pyc +0 -0
- jarvis_ai_assistant-0.1.5/src/jarvis/__pycache__/main.cpython-313.pyc +0 -0
- jarvis_ai_assistant-0.1.5/src/jarvis/__pycache__/utils.cpython-313.pyc +0 -0
- jarvis_ai_assistant-0.1.5/src/jarvis/__pycache__/zte_llm.cpython-313.pyc +0 -0
- jarvis_ai_assistant-0.1.5/src/jarvis/agent.py +133 -0
- {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/main.py +38 -18
- {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/models.py +15 -17
- {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/tools/__init__.py +0 -6
- jarvis_ai_assistant-0.1.5/src/jarvis/tools/__pycache__/__init__.cpython-313.pyc +0 -0
- jarvis_ai_assistant-0.1.5/src/jarvis/tools/__pycache__/base.cpython-313.pyc +0 -0
- {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/tools/__pycache__/shell.cpython-313.pyc +0 -0
- jarvis_ai_assistant-0.1.5/src/jarvis/tools/__pycache__/sub_agent.cpython-313.pyc +0 -0
- {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/tools/base.py +70 -83
- jarvis_ai_assistant-0.1.5/src/jarvis/tools/sub_agent.py +79 -0
- {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/utils.py +25 -2
- jarvis_ai_assistant-0.1.5/src/jarvis/zte_llm.py +132 -0
- {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5/src/jarvis_ai_assistant.egg-info}/PKG-INFO +6 -4
- {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis_ai_assistant.egg-info/SOURCES.txt +5 -3
- {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis_ai_assistant.egg-info/requires.txt +1 -2
- jarvis_ai_assistant-0.1.3/src/jarvis/__pycache__/__init__.cpython-313.pyc +0 -0
- jarvis_ai_assistant-0.1.3/src/jarvis/__pycache__/agent.cpython-313.pyc +0 -0
- jarvis_ai_assistant-0.1.3/src/jarvis/__pycache__/utils.cpython-313.pyc +0 -0
- jarvis_ai_assistant-0.1.3/src/jarvis/agent.py +0 -100
- jarvis_ai_assistant-0.1.3/src/jarvis/tools/__pycache__/__init__.cpython-313.pyc +0 -0
- jarvis_ai_assistant-0.1.3/src/jarvis/tools/__pycache__/base.cpython-313.pyc +0 -0
- jarvis_ai_assistant-0.1.3/src/jarvis/tools/rag.py +0 -154
- jarvis_ai_assistant-0.1.3/src/jarvis/tools/user_confirmation.py +0 -58
- jarvis_ai_assistant-0.1.3/src/jarvis/tools/user_interaction.py +0 -86
- {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/MANIFEST.in +0 -0
- {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/README.md +0 -0
- {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/setup.cfg +0 -0
- {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/.jarvis +0 -0
- {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/__pycache__/models.cpython-313.pyc +0 -0
- {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/__pycache__/tools.cpython-313.pyc +0 -0
- {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/tools/__pycache__/file_ops.cpython-313.pyc +0 -0
- {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/tools/__pycache__/python_script.cpython-313.pyc +0 -0
- {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/tools/__pycache__/rag.cpython-313.pyc +0 -0
- {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/tools/__pycache__/search.cpython-313.pyc +0 -0
- {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/tools/__pycache__/user_confirmation.cpython-313.pyc +0 -0
- {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/tools/__pycache__/user_interaction.cpython-313.pyc +0 -0
- {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/tools/__pycache__/webpage.cpython-313.pyc +0 -0
- {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/tools/file_ops.py +0 -0
- {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/tools/python_script.py +0 -0
- {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/tools/search.py +0 -0
- {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/tools/shell.py +0 -0
- {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis/tools/webpage.py +0 -0
- {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis_ai_assistant.egg-info/dependency_links.txt +0 -0
- {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis_ai_assistant.egg-info/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.1.3 → jarvis_ai_assistant-0.1.5}/src/jarvis_ai_assistant.egg-info/top_level.txt +0 -0
{jarvis_ai_assistant-0.1.3/src/jarvis_ai_assistant.egg-info → jarvis_ai_assistant-0.1.5}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: jarvis-ai-assistant
|
|
3
|
-
Version: 0.1.
|
|
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:
|
|
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.
|
|
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
|
-
"
|
|
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.
|
|
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
|
-
"
|
|
22
|
-
"chromadb>=0.4.24",
|
|
21
|
+
"colorama>=0.4.6",
|
|
23
22
|
],
|
|
24
23
|
entry_points={
|
|
25
24
|
"console_scripts": [
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -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() ->
|
|
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,
|
|
40
|
-
PrettyOutput.print("Warning: .jarvis file should contain a
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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(
|
|
68
|
-
|
|
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="
|
|
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
|
-
|
|
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
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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":
|
|
38
|
-
"arguments":
|
|
37
|
+
"name": tool_call_data["name"],
|
|
38
|
+
"arguments": tool_call_data["arguments"]
|
|
39
39
|
}
|
|
40
40
|
})
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
except
|
|
44
|
-
|
|
45
|
-
|
|
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
|
]
|
|
Binary file
|
|
@@ -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.
|
|
126
|
-
6.
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
-
|
|
133
|
-
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
-
|
|
138
|
-
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
-
|
|
153
|
-
|
|
154
|
-
|
|
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
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
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.
|
|
208
|
-
2.
|
|
209
|
-
3.
|
|
210
|
-
4.
|
|
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"""
|