Undefined-bot 2.1.0__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.
- Undefined/__init__.py +3 -0
- Undefined/__main__.py +6 -0
- Undefined/ai.py +1215 -0
- Undefined/config.py +371 -0
- Undefined/end_summary_storage.py +48 -0
- Undefined/faq.py +244 -0
- Undefined/handlers.py +1247 -0
- Undefined/injection_response_agent.py +131 -0
- Undefined/main.py +126 -0
- Undefined/memory.py +120 -0
- Undefined/onebot.py +512 -0
- Undefined/rate_limit.py +130 -0
- Undefined/render.py +123 -0
- Undefined/scheduled_task_storage.py +88 -0
- Undefined/services/__init__.py +1 -0
- Undefined/services/queue_manager.py +206 -0
- Undefined/skills/README.md +53 -0
- Undefined/skills/__init__.py +10 -0
- Undefined/skills/agents/README.md +144 -0
- Undefined/skills/agents/__init__.py +116 -0
- Undefined/skills/agents/entertainment_agent/config.json +17 -0
- Undefined/skills/agents/entertainment_agent/handler.py +220 -0
- Undefined/skills/agents/entertainment_agent/intro.md +25 -0
- Undefined/skills/agents/entertainment_agent/prompt.md +20 -0
- Undefined/skills/agents/entertainment_agent/tools/__init__.py +1 -0
- Undefined/skills/agents/entertainment_agent/tools/ai_draw_one/config.json +34 -0
- Undefined/skills/agents/entertainment_agent/tools/ai_draw_one/handler.py +62 -0
- Undefined/skills/agents/entertainment_agent/tools/ai_study_helper/config.json +22 -0
- Undefined/skills/agents/entertainment_agent/tools/ai_study_helper/handler.py +35 -0
- Undefined/skills/agents/entertainment_agent/tools/get_current_time/config.json +12 -0
- Undefined/skills/agents/entertainment_agent/tools/get_current_time/handler.py +5 -0
- Undefined/skills/agents/entertainment_agent/tools/horoscope/config.json +24 -0
- Undefined/skills/agents/entertainment_agent/tools/horoscope/handler.py +141 -0
- Undefined/skills/agents/entertainment_agent/tools/minecraft_skin/config.json +43 -0
- Undefined/skills/agents/entertainment_agent/tools/minecraft_skin/handler.py +55 -0
- Undefined/skills/agents/entertainment_agent/tools/novel_search/config.json +25 -0
- Undefined/skills/agents/entertainment_agent/tools/novel_search/handler.py +31 -0
- Undefined/skills/agents/entertainment_agent/tools/renjian/config.json +12 -0
- Undefined/skills/agents/entertainment_agent/tools/renjian/handler.py +30 -0
- Undefined/skills/agents/entertainment_agent/tools/wenchang_dijun/config.json +12 -0
- Undefined/skills/agents/entertainment_agent/tools/wenchang_dijun/handler.py +44 -0
- Undefined/skills/agents/file_analysis_agent/__init__.py +1 -0
- Undefined/skills/agents/file_analysis_agent/config.json +21 -0
- Undefined/skills/agents/file_analysis_agent/handler.py +248 -0
- Undefined/skills/agents/file_analysis_agent/intro.md +22 -0
- Undefined/skills/agents/file_analysis_agent/prompt.md +36 -0
- Undefined/skills/agents/file_analysis_agent/tools/__init__.py +1 -0
- Undefined/skills/agents/file_analysis_agent/tools/analyze_code/config.json +17 -0
- Undefined/skills/agents/file_analysis_agent/tools/analyze_code/handler.py +427 -0
- Undefined/skills/agents/file_analysis_agent/tools/analyze_multimodal/config.json +25 -0
- Undefined/skills/agents/file_analysis_agent/tools/analyze_multimodal/handler.py +178 -0
- Undefined/skills/agents/file_analysis_agent/tools/cleanup_temp/config.json +16 -0
- Undefined/skills/agents/file_analysis_agent/tools/cleanup_temp/handler.py +35 -0
- Undefined/skills/agents/file_analysis_agent/tools/detect_file_type/config.json +17 -0
- Undefined/skills/agents/file_analysis_agent/tools/detect_file_type/handler.py +221 -0
- Undefined/skills/agents/file_analysis_agent/tools/download_file/config.json +21 -0
- Undefined/skills/agents/file_analysis_agent/tools/download_file/handler.py +124 -0
- Undefined/skills/agents/file_analysis_agent/tools/extract_archive/config.json +25 -0
- Undefined/skills/agents/file_analysis_agent/tools/extract_archive/handler.py +190 -0
- Undefined/skills/agents/file_analysis_agent/tools/extract_docx/config.json +17 -0
- Undefined/skills/agents/file_analysis_agent/tools/extract_docx/handler.py +78 -0
- Undefined/skills/agents/file_analysis_agent/tools/extract_pdf/config.json +21 -0
- Undefined/skills/agents/file_analysis_agent/tools/extract_pdf/handler.py +67 -0
- Undefined/skills/agents/file_analysis_agent/tools/extract_pptx/config.json +17 -0
- Undefined/skills/agents/file_analysis_agent/tools/extract_pptx/handler.py +73 -0
- Undefined/skills/agents/file_analysis_agent/tools/extract_xlsx/config.json +17 -0
- Undefined/skills/agents/file_analysis_agent/tools/extract_xlsx/handler.py +101 -0
- Undefined/skills/agents/file_analysis_agent/tools/get_current_time/config.json +12 -0
- Undefined/skills/agents/file_analysis_agent/tools/get_current_time/handler.py +5 -0
- Undefined/skills/agents/file_analysis_agent/tools/read_text_file/config.json +21 -0
- Undefined/skills/agents/file_analysis_agent/tools/read_text_file/handler.py +90 -0
- Undefined/skills/agents/info_agent/config.json +17 -0
- Undefined/skills/agents/info_agent/handler.py +220 -0
- Undefined/skills/agents/info_agent/intro.md +22 -0
- Undefined/skills/agents/info_agent/prompt.md +27 -0
- Undefined/skills/agents/info_agent/tools/__init__.py +1 -0
- Undefined/skills/agents/info_agent/tools/baiduhot/config.json +18 -0
- Undefined/skills/agents/info_agent/tools/baiduhot/handler.py +49 -0
- Undefined/skills/agents/info_agent/tools/base64/config.json +22 -0
- Undefined/skills/agents/info_agent/tools/base64/handler.py +44 -0
- Undefined/skills/agents/info_agent/tools/douyinhot/config.json +18 -0
- Undefined/skills/agents/info_agent/tools/douyinhot/handler.py +53 -0
- Undefined/skills/agents/info_agent/tools/get_current_time/config.json +12 -0
- Undefined/skills/agents/info_agent/tools/get_current_time/handler.py +5 -0
- Undefined/skills/agents/info_agent/tools/gold_price/config.json +12 -0
- Undefined/skills/agents/info_agent/tools/gold_price/handler.py +58 -0
- Undefined/skills/agents/info_agent/tools/hash/config.json +22 -0
- Undefined/skills/agents/info_agent/tools/hash/handler.py +43 -0
- Undefined/skills/agents/info_agent/tools/history/config.json +12 -0
- Undefined/skills/agents/info_agent/tools/history/handler.py +37 -0
- Undefined/skills/agents/info_agent/tools/net_check/config.json +17 -0
- Undefined/skills/agents/info_agent/tools/net_check/handler.py +117 -0
- Undefined/skills/agents/info_agent/tools/news_tencent/config.json +17 -0
- Undefined/skills/agents/info_agent/tools/news_tencent/handler.py +38 -0
- Undefined/skills/agents/info_agent/tools/qq_level_query/config.json +29 -0
- Undefined/skills/agents/info_agent/tools/qq_level_query/handler.py +48 -0
- Undefined/skills/agents/info_agent/tools/speed/config.json +17 -0
- Undefined/skills/agents/info_agent/tools/speed/handler.py +37 -0
- Undefined/skills/agents/info_agent/tools/tcping/config.json +21 -0
- Undefined/skills/agents/info_agent/tools/tcping/handler.py +53 -0
- Undefined/skills/agents/info_agent/tools/weather_query/config.json +22 -0
- Undefined/skills/agents/info_agent/tools/weather_query/handler.py +207 -0
- Undefined/skills/agents/info_agent/tools/weibohot/config.json +18 -0
- Undefined/skills/agents/info_agent/tools/weibohot/handler.py +49 -0
- Undefined/skills/agents/info_agent/tools/whois/config.json +17 -0
- Undefined/skills/agents/info_agent/tools/whois/handler.py +63 -0
- Undefined/skills/agents/naga_code_analysis_agent/config.json +17 -0
- Undefined/skills/agents/naga_code_analysis_agent/handler.py +222 -0
- Undefined/skills/agents/naga_code_analysis_agent/intro.md +17 -0
- Undefined/skills/agents/naga_code_analysis_agent/prompt.md +19 -0
- Undefined/skills/agents/naga_code_analysis_agent/tools/__init__.py +1 -0
- Undefined/skills/agents/naga_code_analysis_agent/tools/get_current_time/config.json +12 -0
- Undefined/skills/agents/naga_code_analysis_agent/tools/get_current_time/handler.py +5 -0
- Undefined/skills/agents/naga_code_analysis_agent/tools/glob/config.json +17 -0
- Undefined/skills/agents/naga_code_analysis_agent/tools/glob/handler.py +37 -0
- Undefined/skills/agents/naga_code_analysis_agent/tools/list_directory/config.json +17 -0
- Undefined/skills/agents/naga_code_analysis_agent/tools/list_directory/handler.py +31 -0
- Undefined/skills/agents/naga_code_analysis_agent/tools/read_file/config.json +17 -0
- Undefined/skills/agents/naga_code_analysis_agent/tools/read_file/handler.py +66 -0
- Undefined/skills/agents/naga_code_analysis_agent/tools/read_naga_intro/config.json +12 -0
- Undefined/skills/agents/naga_code_analysis_agent/tools/read_naga_intro/handler.py +327 -0
- Undefined/skills/agents/naga_code_analysis_agent/tools/search_file_content/config.json +25 -0
- Undefined/skills/agents/naga_code_analysis_agent/tools/search_file_content/handler.py +46 -0
- Undefined/skills/agents/scheduler_agent/__init__.py +1 -0
- Undefined/skills/agents/scheduler_agent/config.json +17 -0
- Undefined/skills/agents/scheduler_agent/handler.py +218 -0
- Undefined/skills/agents/scheduler_agent/intro.md +17 -0
- Undefined/skills/agents/scheduler_agent/prompt.md +67 -0
- Undefined/skills/agents/scheduler_agent/tools/__init__.py +1 -0
- Undefined/skills/agents/scheduler_agent/tools/create_schedule_task/config.json +37 -0
- Undefined/skills/agents/scheduler_agent/tools/create_schedule_task/handler.py +68 -0
- Undefined/skills/agents/scheduler_agent/tools/delete_schedule_task/config.json +19 -0
- Undefined/skills/agents/scheduler_agent/tools/delete_schedule_task/handler.py +26 -0
- Undefined/skills/agents/scheduler_agent/tools/get_current_time/config.json +12 -0
- Undefined/skills/agents/scheduler_agent/tools/get_current_time/handler.py +5 -0
- Undefined/skills/agents/scheduler_agent/tools/list_schedule_tasks/config.json +11 -0
- Undefined/skills/agents/scheduler_agent/tools/list_schedule_tasks/handler.py +47 -0
- Undefined/skills/agents/scheduler_agent/tools/update_schedule_task/config.json +39 -0
- Undefined/skills/agents/scheduler_agent/tools/update_schedule_task/handler.py +46 -0
- Undefined/skills/agents/social_agent/config.json +17 -0
- Undefined/skills/agents/social_agent/handler.py +220 -0
- Undefined/skills/agents/social_agent/intro.md +17 -0
- Undefined/skills/agents/social_agent/prompt.md +19 -0
- Undefined/skills/agents/social_agent/tools/__init__.py +1 -0
- Undefined/skills/agents/social_agent/tools/bilibili_search/config.json +21 -0
- Undefined/skills/agents/social_agent/tools/bilibili_search/handler.py +68 -0
- Undefined/skills/agents/social_agent/tools/bilibili_user_info/config.json +17 -0
- Undefined/skills/agents/social_agent/tools/bilibili_user_info/handler.py +68 -0
- Undefined/skills/agents/social_agent/tools/get_current_time/config.json +12 -0
- Undefined/skills/agents/social_agent/tools/get_current_time/handler.py +5 -0
- Undefined/skills/agents/social_agent/tools/music_global_search/config.json +21 -0
- Undefined/skills/agents/social_agent/tools/music_global_search/handler.py +47 -0
- Undefined/skills/agents/social_agent/tools/music_info_get/config.json +22 -0
- Undefined/skills/agents/social_agent/tools/music_info_get/handler.py +35 -0
- Undefined/skills/agents/social_agent/tools/music_lyrics/config.json +22 -0
- Undefined/skills/agents/social_agent/tools/music_lyrics/handler.py +26 -0
- Undefined/skills/agents/social_agent/tools/video_random_recommend/config.json +21 -0
- Undefined/skills/agents/social_agent/tools/video_random_recommend/handler.py +21 -0
- Undefined/skills/agents/web_agent/config.json +17 -0
- Undefined/skills/agents/web_agent/handler.py +221 -0
- Undefined/skills/agents/web_agent/intro.md +14 -0
- Undefined/skills/agents/web_agent/prompt.md +16 -0
- Undefined/skills/agents/web_agent/tools/__init__.py +1 -0
- Undefined/skills/agents/web_agent/tools/crawl_webpage/config.json +21 -0
- Undefined/skills/agents/web_agent/tools/crawl_webpage/handler.py +102 -0
- Undefined/skills/agents/web_agent/tools/get_current_time/config.json +12 -0
- Undefined/skills/agents/web_agent/tools/get_current_time/handler.py +5 -0
- Undefined/skills/agents/web_agent/tools/web_search/config.json +21 -0
- Undefined/skills/agents/web_agent/tools/web_search/handler.py +29 -0
- Undefined/skills/tools/README.md +85 -0
- Undefined/skills/tools/__init__.py +120 -0
- Undefined/skills/tools/debug/config.json +17 -0
- Undefined/skills/tools/debug/handler.py +35 -0
- Undefined/skills/tools/end/config.json +17 -0
- Undefined/skills/tools/end/handler.py +24 -0
- Undefined/skills/tools/get_current_time/config.json +12 -0
- Undefined/skills/tools/get_current_time/handler.py +5 -0
- Undefined/skills/tools/get_forward_msg/config.json +17 -0
- Undefined/skills/tools/get_forward_msg/handler.py +131 -0
- Undefined/skills/tools/get_group_member_info/config.json +38 -0
- Undefined/skills/tools/get_group_member_info/handler.py +142 -0
- Undefined/skills/tools/get_messages_by_time/config.json +30 -0
- Undefined/skills/tools/get_messages_by_time/handler.py +128 -0
- Undefined/skills/tools/get_picture/config.json +45 -0
- Undefined/skills/tools/get_picture/handler.py +191 -0
- Undefined/skills/tools/get_recent_messages/config.json +30 -0
- Undefined/skills/tools/get_recent_messages/handler.py +88 -0
- Undefined/skills/tools/qq_like/config.json +22 -0
- Undefined/skills/tools/qq_like/handler.py +58 -0
- Undefined/skills/tools/render_html/config.json +26 -0
- Undefined/skills/tools/render_html/handler.py +39 -0
- Undefined/skills/tools/render_latex/config.json +26 -0
- Undefined/skills/tools/render_latex/handler.py +78 -0
- Undefined/skills/tools/render_markdown/config.json +26 -0
- Undefined/skills/tools/render_markdown/handler.py +63 -0
- Undefined/skills/tools/save_memory/config.json +17 -0
- Undefined/skills/tools/save_memory/handler.py +17 -0
- Undefined/skills/tools/send_message/config.json +21 -0
- Undefined/skills/tools/send_message/handler.py +60 -0
- Undefined/skills/tools/send_private_message/config.json +21 -0
- Undefined/skills/tools/send_private_message/handler.py +35 -0
- Undefined/utils/__init__.py +0 -0
- Undefined/utils/common.py +186 -0
- Undefined/utils/history.py +284 -0
- Undefined/utils/scheduler.py +286 -0
- Undefined/utils/sender.py +140 -0
- undefined_bot-2.1.0.dist-info/METADATA +259 -0
- undefined_bot-2.1.0.dist-info/RECORD +211 -0
- undefined_bot-2.1.0.dist-info/WHEEL +4 -0
- undefined_bot-2.1.0.dist-info/entry_points.txt +2 -0
- undefined_bot-2.1.0.dist-info/licenses/LICENSE +7 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Agent Registry - Agent 自动发现和注册系统
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import logging
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Any, Dict, List
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class AgentRegistry:
|
|
14
|
+
"""Agent 注册表,自动发现和加载 agents"""
|
|
15
|
+
|
|
16
|
+
def __init__(self, agents_dir: str | Path | None = None):
|
|
17
|
+
if agents_dir is None:
|
|
18
|
+
self.agents_dir = Path(__file__).parent
|
|
19
|
+
else:
|
|
20
|
+
self.agents_dir = Path(agents_dir)
|
|
21
|
+
|
|
22
|
+
self._agents_schema: List[Dict[str, Any]] = []
|
|
23
|
+
self._agents_handlers: Dict[str, Any] = {}
|
|
24
|
+
self.load_agents()
|
|
25
|
+
|
|
26
|
+
def load_agents(self) -> None:
|
|
27
|
+
"""自动发现和加载 agents"""
|
|
28
|
+
self._agents_schema = []
|
|
29
|
+
self._agents_handlers = {}
|
|
30
|
+
|
|
31
|
+
if not self.agents_dir.exists():
|
|
32
|
+
logger.warning(f"Agent 目录不存在: {self.agents_dir}")
|
|
33
|
+
return
|
|
34
|
+
|
|
35
|
+
for item in self.agents_dir.iterdir():
|
|
36
|
+
if item.is_dir() and not item.name.startswith("_"):
|
|
37
|
+
self._load_agent_from_dir(item)
|
|
38
|
+
|
|
39
|
+
agent_names = list(self._agents_handlers.keys())
|
|
40
|
+
logger.info(
|
|
41
|
+
f"成功加载了 {len(self._agents_schema)} 个 Agent: {', '.join(agent_names)}"
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
def _load_agent_from_dir(self, agent_dir: Path) -> None:
|
|
45
|
+
"""从目录加载单个 agent"""
|
|
46
|
+
config_path = agent_dir / "config.json"
|
|
47
|
+
handler_path = agent_dir / "handler.py"
|
|
48
|
+
|
|
49
|
+
if not config_path.exists() or not handler_path.exists():
|
|
50
|
+
logger.debug(
|
|
51
|
+
f"[Agent加载] 目录 {agent_dir} 缺少 config.json 或 handler.py,跳过"
|
|
52
|
+
)
|
|
53
|
+
return
|
|
54
|
+
|
|
55
|
+
import importlib.util
|
|
56
|
+
|
|
57
|
+
try:
|
|
58
|
+
with open(config_path, "r", encoding="utf-8") as f:
|
|
59
|
+
config = json.load(f)
|
|
60
|
+
|
|
61
|
+
if "function" not in config or "name" not in config.get("function", {}):
|
|
62
|
+
logger.error(
|
|
63
|
+
f"[Agent错误] Agent 配置无效 {agent_dir}: 缺少 function.name"
|
|
64
|
+
)
|
|
65
|
+
return
|
|
66
|
+
|
|
67
|
+
agent_name = config["function"]["name"]
|
|
68
|
+
logger.debug(f"[Agent加载] 正在从 {agent_dir} 加载 Agent: {agent_name}")
|
|
69
|
+
|
|
70
|
+
spec = importlib.util.spec_from_file_location(
|
|
71
|
+
f"agents.{agent_name}", handler_path
|
|
72
|
+
)
|
|
73
|
+
if spec is None or spec.loader is None:
|
|
74
|
+
logger.error(f"从 {handler_path} 加载 Agent 处理器 spec 失败")
|
|
75
|
+
return
|
|
76
|
+
|
|
77
|
+
module = importlib.util.module_from_spec(spec)
|
|
78
|
+
spec.loader.exec_module(module)
|
|
79
|
+
|
|
80
|
+
if not hasattr(module, "execute"):
|
|
81
|
+
logger.error(f"Agent {agent_dir} 的处理器缺少 'execute' 函数")
|
|
82
|
+
return
|
|
83
|
+
|
|
84
|
+
self._agents_schema.append(config)
|
|
85
|
+
self._agents_handlers[agent_name] = module.execute
|
|
86
|
+
|
|
87
|
+
logger.debug(f"已加载 Agent: {agent_name}")
|
|
88
|
+
|
|
89
|
+
except Exception as e:
|
|
90
|
+
logger.error(f"从 {agent_dir} 加载 Agent 失败: {e}")
|
|
91
|
+
|
|
92
|
+
def get_agents_schema(self) -> List[Dict[str, Any]]:
|
|
93
|
+
"""获取所有 agent 的 schema 定义(用于 OpenAI function calling)"""
|
|
94
|
+
return self._agents_schema
|
|
95
|
+
|
|
96
|
+
async def execute_agent(
|
|
97
|
+
self, agent_name: str, args: Dict[str, Any], context: Dict[str, Any]
|
|
98
|
+
) -> str:
|
|
99
|
+
"""执行 agent"""
|
|
100
|
+
handler = self._agents_handlers.get(agent_name)
|
|
101
|
+
if not handler:
|
|
102
|
+
return f"未找到 Agent: {agent_name}"
|
|
103
|
+
|
|
104
|
+
try:
|
|
105
|
+
import asyncio
|
|
106
|
+
|
|
107
|
+
start_time = asyncio.get_event_loop().time()
|
|
108
|
+
if hasattr(handler, "__call__"):
|
|
109
|
+
result = await handler(args, context)
|
|
110
|
+
duration = asyncio.get_event_loop().time() - start_time
|
|
111
|
+
logger.info(f"[Agent执行] {agent_name} 执行成功, 耗时={duration:.4f}s")
|
|
112
|
+
return str(result)
|
|
113
|
+
return f"Agent 处理器无效: {agent_name}"
|
|
114
|
+
except Exception as e:
|
|
115
|
+
logger.exception(f"[Agent异常] 执行 Agent {agent_name} 时出错")
|
|
116
|
+
return f"执行 Agent {agent_name} 时出错: {str(e)}"
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "function",
|
|
3
|
+
"function": {
|
|
4
|
+
"name": "entertainment_agent",
|
|
5
|
+
"description": "娱乐助手,提供 AI 绘画、学习答疑、星座运势、Minecraft 皮肤、小说阅读等娱乐功能。",
|
|
6
|
+
"parameters": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"properties": {
|
|
9
|
+
"prompt": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"description": "用户的娱乐需求,例如:'画一只可爱的猫咪'、'白羊座今日运势'、'搜索斗破苍穹'"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"required": ["prompt"]
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
from typing import Any, Dict, Callable
|
|
2
|
+
import importlib.util
|
|
3
|
+
import json
|
|
4
|
+
import asyncio
|
|
5
|
+
import aiofiles
|
|
6
|
+
import logging
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
logger = logging.getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class AgentToolRegistry:
|
|
13
|
+
"""Agent 内部的工具注册表"""
|
|
14
|
+
|
|
15
|
+
def __init__(self, tools_dir: Path) -> None:
|
|
16
|
+
self.tools_dir: Path = (
|
|
17
|
+
tools_dir if isinstance(tools_dir, Path) else Path(tools_dir)
|
|
18
|
+
)
|
|
19
|
+
self._tools_schema: list[dict[str, Any]] = []
|
|
20
|
+
self._tools_handlers: dict[str, Callable[..., Any]] = {}
|
|
21
|
+
self.load_tools()
|
|
22
|
+
|
|
23
|
+
def load_tools(self) -> None:
|
|
24
|
+
"""加载 agent 专属工具"""
|
|
25
|
+
if not self.tools_dir.exists():
|
|
26
|
+
logger.warning(f"Agent 工具目录不存在: {self.tools_dir}")
|
|
27
|
+
return
|
|
28
|
+
|
|
29
|
+
for item in self.tools_dir.iterdir():
|
|
30
|
+
if item.is_dir() and not item.name.startswith("_"):
|
|
31
|
+
self._load_tool_from_dir(item)
|
|
32
|
+
|
|
33
|
+
logger.info(
|
|
34
|
+
f"Agent 加载了 {len(self._tools_schema)} 个工具: {list(self._tools_handlers.keys())}"
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
def _load_tool_from_dir(self, tool_dir: Path) -> None:
|
|
38
|
+
"""从目录加载工具"""
|
|
39
|
+
config_path: Path = tool_dir / "config.json"
|
|
40
|
+
handler_path: Path = tool_dir / "handler.py"
|
|
41
|
+
|
|
42
|
+
if not config_path.exists() or not handler_path.exists():
|
|
43
|
+
return
|
|
44
|
+
|
|
45
|
+
try:
|
|
46
|
+
with open(config_path, "r", encoding="utf-8") as f:
|
|
47
|
+
config: dict[str, Any] = json.load(f)
|
|
48
|
+
|
|
49
|
+
if "function" not in config or "name" not in config.get("function", {}):
|
|
50
|
+
return
|
|
51
|
+
|
|
52
|
+
tool_name: str = config["function"]["name"]
|
|
53
|
+
|
|
54
|
+
spec = importlib.util.spec_from_file_location(
|
|
55
|
+
f"agent_tools.{tool_name}", handler_path
|
|
56
|
+
)
|
|
57
|
+
if spec is None or spec.loader is None:
|
|
58
|
+
return
|
|
59
|
+
|
|
60
|
+
module = importlib.util.module_from_spec(spec)
|
|
61
|
+
spec.loader.exec_module(module)
|
|
62
|
+
|
|
63
|
+
if not hasattr(module, "execute"):
|
|
64
|
+
return
|
|
65
|
+
|
|
66
|
+
self._tools_schema.append(config)
|
|
67
|
+
self._tools_handlers[tool_name] = module.execute
|
|
68
|
+
|
|
69
|
+
except Exception as e:
|
|
70
|
+
logger.error(f"从 {tool_dir} 加载工具失败: {e}")
|
|
71
|
+
|
|
72
|
+
def get_tools_schema(self) -> list[dict[str, Any]]:
|
|
73
|
+
"""获取工具 schema"""
|
|
74
|
+
return self._tools_schema
|
|
75
|
+
|
|
76
|
+
async def execute_tool(
|
|
77
|
+
self, tool_name: str, args: dict[str, Any], context: dict[str, Any]
|
|
78
|
+
) -> str:
|
|
79
|
+
"""执行工具"""
|
|
80
|
+
handler = self._tools_handlers.get(tool_name)
|
|
81
|
+
if not handler:
|
|
82
|
+
return f"未找到工具: {tool_name}"
|
|
83
|
+
|
|
84
|
+
try:
|
|
85
|
+
if asyncio.iscoroutinefunction(handler):
|
|
86
|
+
result = await handler(args, context)
|
|
87
|
+
else:
|
|
88
|
+
result = handler(args, context)
|
|
89
|
+
return str(result)
|
|
90
|
+
except Exception as e:
|
|
91
|
+
logger.exception(f"执行工具 {tool_name} 时出错")
|
|
92
|
+
return f"执行工具 {tool_name} 时出错: {str(e)}"
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
async def _load_prompt() -> str:
|
|
96
|
+
"""从 prompt.md 文件加载系统提示词"""
|
|
97
|
+
prompt_path: Path = Path(__file__).parent / "prompt.md"
|
|
98
|
+
if prompt_path.exists():
|
|
99
|
+
async with aiofiles.open(prompt_path, "r", encoding="utf-8") as f:
|
|
100
|
+
return await f.read()
|
|
101
|
+
return _get_default_prompt()
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _get_default_prompt() -> str:
|
|
105
|
+
"""默认提示词"""
|
|
106
|
+
return "你是一个娱乐助手..."
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
async def execute(args: Dict[str, Any], context: Dict[str, Any]) -> str:
|
|
110
|
+
"""执行 entertainment_agent"""
|
|
111
|
+
user_prompt: str = args.get("prompt", "")
|
|
112
|
+
|
|
113
|
+
if not user_prompt:
|
|
114
|
+
return "请提供您的娱乐需求"
|
|
115
|
+
|
|
116
|
+
agent_tools_dir: Path = Path(__file__).parent / "tools"
|
|
117
|
+
tool_registry = AgentToolRegistry(agent_tools_dir)
|
|
118
|
+
|
|
119
|
+
tools: list[dict[str, Any]] = tool_registry.get_tools_schema()
|
|
120
|
+
|
|
121
|
+
ai_client = context.get("ai_client")
|
|
122
|
+
if not ai_client:
|
|
123
|
+
return "AI client 未在上下文中提供"
|
|
124
|
+
|
|
125
|
+
agent_config = ai_client.agent_config
|
|
126
|
+
|
|
127
|
+
system_prompt: str = await _load_prompt()
|
|
128
|
+
|
|
129
|
+
messages: list[dict[str, Any]] = [
|
|
130
|
+
{"role": "system", "content": system_prompt},
|
|
131
|
+
{"role": "user", "content": f"用户需求:{user_prompt}"},
|
|
132
|
+
]
|
|
133
|
+
|
|
134
|
+
max_iterations: int = 20
|
|
135
|
+
iteration: int = 0
|
|
136
|
+
|
|
137
|
+
while iteration < max_iterations:
|
|
138
|
+
iteration += 1
|
|
139
|
+
|
|
140
|
+
try:
|
|
141
|
+
response = await ai_client._http_client.post(
|
|
142
|
+
agent_config.api_url,
|
|
143
|
+
headers={
|
|
144
|
+
"Authorization": f"Bearer {agent_config.api_key}",
|
|
145
|
+
"Content-Type": "application/json",
|
|
146
|
+
},
|
|
147
|
+
json=ai_client._build_request_body(
|
|
148
|
+
model_config=agent_config,
|
|
149
|
+
messages=messages,
|
|
150
|
+
max_tokens=agent_config.max_tokens,
|
|
151
|
+
tools=tools if tools else None,
|
|
152
|
+
tool_choice="auto",
|
|
153
|
+
),
|
|
154
|
+
)
|
|
155
|
+
response.raise_for_status()
|
|
156
|
+
result: dict[str, Any] = response.json()
|
|
157
|
+
|
|
158
|
+
choice: dict[str, Any] = result.get("choices", [{}])[0]
|
|
159
|
+
message: dict[str, Any] = choice.get("message", {})
|
|
160
|
+
content: str = message.get("content") or ""
|
|
161
|
+
tool_calls: list[dict[str, Any]] = message.get("tool_calls", [])
|
|
162
|
+
|
|
163
|
+
if content.strip() and tool_calls:
|
|
164
|
+
content = ""
|
|
165
|
+
|
|
166
|
+
if not tool_calls:
|
|
167
|
+
return content
|
|
168
|
+
|
|
169
|
+
messages.append(
|
|
170
|
+
{"role": "assistant", "content": content, "tool_calls": tool_calls}
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
# 准备并发执行工具
|
|
174
|
+
tool_tasks = []
|
|
175
|
+
tool_call_ids = []
|
|
176
|
+
|
|
177
|
+
for tool_call in tool_calls:
|
|
178
|
+
call_id: str = tool_call.get("id", "")
|
|
179
|
+
function: dict[str, Any] = tool_call.get("function", {})
|
|
180
|
+
function_name: str = function.get("name", "")
|
|
181
|
+
function_args_str: str = function.get("arguments", "{}")
|
|
182
|
+
|
|
183
|
+
logger.info(f"Agent 正在准备工具: {function_name}")
|
|
184
|
+
|
|
185
|
+
try:
|
|
186
|
+
function_args: dict[str, Any] = json.loads(function_args_str)
|
|
187
|
+
except json.JSONDecodeError:
|
|
188
|
+
function_args = {}
|
|
189
|
+
|
|
190
|
+
tool_call_ids.append(call_id)
|
|
191
|
+
tool_tasks.append(
|
|
192
|
+
tool_registry.execute_tool(function_name, function_args, context)
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
# 并发执行
|
|
196
|
+
if tool_tasks:
|
|
197
|
+
logger.info(f"Agent 正在并发执行 {len(tool_tasks)} 个工具")
|
|
198
|
+
results = await asyncio.gather(*tool_tasks, return_exceptions=True)
|
|
199
|
+
|
|
200
|
+
for i, tool_result in enumerate(results):
|
|
201
|
+
call_id = tool_call_ids[i]
|
|
202
|
+
content_str: str = ""
|
|
203
|
+
if isinstance(tool_result, Exception):
|
|
204
|
+
content_str = f"错误: {str(tool_result)}"
|
|
205
|
+
else:
|
|
206
|
+
content_str = str(tool_result)
|
|
207
|
+
|
|
208
|
+
messages.append(
|
|
209
|
+
{
|
|
210
|
+
"role": "tool",
|
|
211
|
+
"tool_call_id": call_id,
|
|
212
|
+
"content": content_str,
|
|
213
|
+
}
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
except Exception as e:
|
|
217
|
+
logger.exception(f"Agent 执行失败: {e}")
|
|
218
|
+
return f"处理失败: {e}"
|
|
219
|
+
|
|
220
|
+
return "达到最大迭代次数"
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# 娱乐助手
|
|
2
|
+
|
|
3
|
+
## 能力
|
|
4
|
+
- **AI 绘画**:根据描述生成图片
|
|
5
|
+
- **AI 学习助手**:解答学习问题,支持深度思考模式
|
|
6
|
+
- **星座运势**:查询十二星座的今日运势
|
|
7
|
+
- **文昌帝君**:调用文昌帝君工具查询升学运势
|
|
8
|
+
- **Minecraft 皮肤**:生成 Minecraft 玩家皮肤图片
|
|
9
|
+
- **小说搜索与阅读**:搜索网络小说并阅读章节内容
|
|
10
|
+
- **人间小句**:提供“在人间凑数的日子”中的幽默句子,带给用户轻松幽默的日常感悟
|
|
11
|
+
|
|
12
|
+
## 适用场景
|
|
13
|
+
- 用户想要生成图片时
|
|
14
|
+
- 用户需要解答题目或学习辅导时
|
|
15
|
+
- 用户查询星座运势时
|
|
16
|
+
- 用户需要 Minecraft 皮肤时
|
|
17
|
+
- 用户想看小说时
|
|
18
|
+
- 用户查询人间评分时
|
|
19
|
+
|
|
20
|
+
## 参数说明
|
|
21
|
+
- `prompt` (AI 绘画): 图片描述词,越详细越好
|
|
22
|
+
- `question` (学习助手): 具体的学习问题
|
|
23
|
+
- `astrology_name` (星座): 星座名称(如:白羊座)
|
|
24
|
+
- `username` (Minecraft): 玩家名称
|
|
25
|
+
- `novel_name` (小说): 小说名称
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
你是一个娱乐助手,专门帮助用户获取各种娱乐内容和功能。
|
|
2
|
+
|
|
3
|
+
你的任务是根据用户需求,选择合适的工具来完成任务:
|
|
4
|
+
|
|
5
|
+
1. **AI 绘图** → ai_draw_one
|
|
6
|
+
2. **学习答疑** → ai_study_helper
|
|
7
|
+
3. **星座运势** → horoscope
|
|
8
|
+
4. **Minecraft 皮肤** → minecraft_skin
|
|
9
|
+
5. **小说阅读** → novel_search
|
|
10
|
+
6. **人间小句** → renjian
|
|
11
|
+
7. **文昌帝君** → wenchang_dijun
|
|
12
|
+
|
|
13
|
+
注意事项:
|
|
14
|
+
- 对于 AI 生成的内容,可以适当调整参数获得更好效果
|
|
15
|
+
- 小说阅读支持分页
|
|
16
|
+
- 保持回答轻松友好的风格
|
|
17
|
+
|
|
18
|
+
如果用户需求不明确,请先询问用户澄清问题。
|
|
19
|
+
|
|
20
|
+
如果问题涉及时间,立刻调用时间工具获取。
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Entertainment Agent Tools
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "function",
|
|
3
|
+
"function": {
|
|
4
|
+
"name": "ai_draw_one",
|
|
5
|
+
"description": "AI 绘图工具 (DrawOne)。",
|
|
6
|
+
"parameters": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"properties": {
|
|
9
|
+
"prompt": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"description": "绘图提示词"
|
|
12
|
+
},
|
|
13
|
+
"model": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"description": "绘图模型 (例如: anylora, anything-v5, etc. 可选)"
|
|
16
|
+
},
|
|
17
|
+
"size": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"description": "比例 (例如 2:3)"
|
|
20
|
+
},
|
|
21
|
+
"target_id": {
|
|
22
|
+
"type": "integer",
|
|
23
|
+
"description": "发送目标的 ID"
|
|
24
|
+
},
|
|
25
|
+
"message_type": {
|
|
26
|
+
"type": "string",
|
|
27
|
+
"description": "消息类型 (group 或 private)",
|
|
28
|
+
"enum": ["group", "private"]
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"required": ["prompt", "target_id", "message_type"]
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
from typing import Any, Dict
|
|
2
|
+
import httpx
|
|
3
|
+
import logging
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
import uuid
|
|
6
|
+
|
|
7
|
+
logger = logging.getLogger(__name__)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
async def execute(args: Dict[str, Any], context: Dict[str, Any]) -> str:
|
|
11
|
+
prompt = args.get("prompt")
|
|
12
|
+
model = args.get("model", "anything-v5") # 默认模型猜测
|
|
13
|
+
size = args.get("size", "1:1")
|
|
14
|
+
target_id = args.get("target_id")
|
|
15
|
+
message_type = args.get("message_type")
|
|
16
|
+
|
|
17
|
+
url = "https://api.xingzhige.com/API/DrawOne/"
|
|
18
|
+
params = {"prompt": prompt, "model": model, "size": size}
|
|
19
|
+
|
|
20
|
+
try:
|
|
21
|
+
async with httpx.AsyncClient(timeout=60.0) as client: # AI 绘画可能需要一些时间
|
|
22
|
+
response = await client.get(url, params=params)
|
|
23
|
+
|
|
24
|
+
try:
|
|
25
|
+
data = response.json()
|
|
26
|
+
except Exception:
|
|
27
|
+
return f"API 返回错误 (非JSON): {response.text[:100]}"
|
|
28
|
+
|
|
29
|
+
# 解析响应
|
|
30
|
+
# 文档说 "返回: Json"。它可能包含 "url" 或 "image" 字段。
|
|
31
|
+
# 我将假设是 'url' 或类似字段。
|
|
32
|
+
# 如果找不到 URL,我将返回 JSON 给用户以进行调试。
|
|
33
|
+
|
|
34
|
+
image_url = data.get("url") or data.get("image") or data.get("img")
|
|
35
|
+
|
|
36
|
+
if not image_url and "data" in data and isinstance(data["data"], str):
|
|
37
|
+
image_url = data["data"]
|
|
38
|
+
|
|
39
|
+
if not image_url:
|
|
40
|
+
return f"未找到图片链接: {data}"
|
|
41
|
+
|
|
42
|
+
# 下载图片
|
|
43
|
+
img_response = await client.get(image_url)
|
|
44
|
+
img_response.raise_for_status()
|
|
45
|
+
|
|
46
|
+
filename = f"ai_draw_{uuid.uuid4().hex[:8]}.jpg"
|
|
47
|
+
filepath = Path.cwd() / "img" / filename
|
|
48
|
+
filepath.parent.mkdir(exist_ok=True)
|
|
49
|
+
|
|
50
|
+
with open(filepath, "wb") as f:
|
|
51
|
+
f.write(img_response.content)
|
|
52
|
+
|
|
53
|
+
send_image_callback = context.get("send_image_callback")
|
|
54
|
+
if send_image_callback:
|
|
55
|
+
await send_image_callback(target_id, message_type, str(filepath))
|
|
56
|
+
return f"AI 绘图已发送给 {message_type} {target_id}"
|
|
57
|
+
else:
|
|
58
|
+
return "发送图片回调未设置"
|
|
59
|
+
|
|
60
|
+
except Exception as e:
|
|
61
|
+
logger.exception(f"AI 绘图失败: {e}")
|
|
62
|
+
return f"AI 绘图失败: {e}"
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "function",
|
|
3
|
+
"function": {
|
|
4
|
+
"name": "ai_study_helper",
|
|
5
|
+
"description": "AI 学习助手/解题工具。",
|
|
6
|
+
"parameters": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"properties": {
|
|
9
|
+
"question": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"description": "问题内容"
|
|
12
|
+
},
|
|
13
|
+
"content": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"description": "是否开启深度思考 (yes/no)",
|
|
16
|
+
"enum": ["yes", "no"]
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"required": ["question"]
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from typing import Any, Dict
|
|
2
|
+
import httpx
|
|
3
|
+
import logging
|
|
4
|
+
|
|
5
|
+
logger = logging.getLogger(__name__)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
async def execute(args: Dict[str, Any], context: Dict[str, Any]) -> str:
|
|
9
|
+
question = args.get("question")
|
|
10
|
+
content = args.get("content", "yes")
|
|
11
|
+
|
|
12
|
+
url = "https://api.jkyai.top/API/wnjtzs.php"
|
|
13
|
+
|
|
14
|
+
try:
|
|
15
|
+
async with httpx.AsyncClient(timeout=60.0) as client:
|
|
16
|
+
response = await client.get(
|
|
17
|
+
url, params={"question": question, "content": content, "type": "json"}
|
|
18
|
+
)
|
|
19
|
+
response.raise_for_status()
|
|
20
|
+
data = response.json()
|
|
21
|
+
|
|
22
|
+
# 格式化
|
|
23
|
+
status = data.get("status")
|
|
24
|
+
if status != "success":
|
|
25
|
+
return f"AI 响应失败: {status}"
|
|
26
|
+
|
|
27
|
+
q = data.get("question", "")
|
|
28
|
+
ans = data.get("answer", "")
|
|
29
|
+
model = data.get("model", "")
|
|
30
|
+
|
|
31
|
+
return f"🤖 AI 解答 ({model}):\n❓ 问题: {q}\n💡 答案: {ans}"
|
|
32
|
+
|
|
33
|
+
except Exception as e:
|
|
34
|
+
logger.exception(f"AI 助手请求失败: {e}")
|
|
35
|
+
return f"AI 助手请求失败: {e}"
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "function",
|
|
3
|
+
"function": {
|
|
4
|
+
"name": "horoscope",
|
|
5
|
+
"description": "获取指定星座的运势信息,支持今日、本周、本月和本年的运势查询。返回综合运势、健康、爱情、财运、工作等详细运势信息,包括运势评分、运势描述、幸运色、幸运数字等。",
|
|
6
|
+
"parameters": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"properties": {
|
|
9
|
+
"constellation": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"description": "星座名称(中文或英文)",
|
|
12
|
+
"enum": ["白羊座", "金牛座", "双子座", "巨蟹座", "狮子座", "处女座", "天秤座", "天蝎座", "射手座", "摩羯座", "水瓶座", "双鱼座", "aries", "taurus", "gemini", "cancer", "leo", "virgo", "libra", "scorpio", "sagittarius", "capricorn", "aquarius", "pisces"]
|
|
13
|
+
},
|
|
14
|
+
"time_type": {
|
|
15
|
+
"type": "string",
|
|
16
|
+
"description": "运势时间类型",
|
|
17
|
+
"enum": ["today", "week", "month", "year", "今日", "本周", "本月", "本年"],
|
|
18
|
+
"default": "today"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"required": ["constellation"]
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|