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.
Files changed (211) hide show
  1. Undefined/__init__.py +3 -0
  2. Undefined/__main__.py +6 -0
  3. Undefined/ai.py +1215 -0
  4. Undefined/config.py +371 -0
  5. Undefined/end_summary_storage.py +48 -0
  6. Undefined/faq.py +244 -0
  7. Undefined/handlers.py +1247 -0
  8. Undefined/injection_response_agent.py +131 -0
  9. Undefined/main.py +126 -0
  10. Undefined/memory.py +120 -0
  11. Undefined/onebot.py +512 -0
  12. Undefined/rate_limit.py +130 -0
  13. Undefined/render.py +123 -0
  14. Undefined/scheduled_task_storage.py +88 -0
  15. Undefined/services/__init__.py +1 -0
  16. Undefined/services/queue_manager.py +206 -0
  17. Undefined/skills/README.md +53 -0
  18. Undefined/skills/__init__.py +10 -0
  19. Undefined/skills/agents/README.md +144 -0
  20. Undefined/skills/agents/__init__.py +116 -0
  21. Undefined/skills/agents/entertainment_agent/config.json +17 -0
  22. Undefined/skills/agents/entertainment_agent/handler.py +220 -0
  23. Undefined/skills/agents/entertainment_agent/intro.md +25 -0
  24. Undefined/skills/agents/entertainment_agent/prompt.md +20 -0
  25. Undefined/skills/agents/entertainment_agent/tools/__init__.py +1 -0
  26. Undefined/skills/agents/entertainment_agent/tools/ai_draw_one/config.json +34 -0
  27. Undefined/skills/agents/entertainment_agent/tools/ai_draw_one/handler.py +62 -0
  28. Undefined/skills/agents/entertainment_agent/tools/ai_study_helper/config.json +22 -0
  29. Undefined/skills/agents/entertainment_agent/tools/ai_study_helper/handler.py +35 -0
  30. Undefined/skills/agents/entertainment_agent/tools/get_current_time/config.json +12 -0
  31. Undefined/skills/agents/entertainment_agent/tools/get_current_time/handler.py +5 -0
  32. Undefined/skills/agents/entertainment_agent/tools/horoscope/config.json +24 -0
  33. Undefined/skills/agents/entertainment_agent/tools/horoscope/handler.py +141 -0
  34. Undefined/skills/agents/entertainment_agent/tools/minecraft_skin/config.json +43 -0
  35. Undefined/skills/agents/entertainment_agent/tools/minecraft_skin/handler.py +55 -0
  36. Undefined/skills/agents/entertainment_agent/tools/novel_search/config.json +25 -0
  37. Undefined/skills/agents/entertainment_agent/tools/novel_search/handler.py +31 -0
  38. Undefined/skills/agents/entertainment_agent/tools/renjian/config.json +12 -0
  39. Undefined/skills/agents/entertainment_agent/tools/renjian/handler.py +30 -0
  40. Undefined/skills/agents/entertainment_agent/tools/wenchang_dijun/config.json +12 -0
  41. Undefined/skills/agents/entertainment_agent/tools/wenchang_dijun/handler.py +44 -0
  42. Undefined/skills/agents/file_analysis_agent/__init__.py +1 -0
  43. Undefined/skills/agents/file_analysis_agent/config.json +21 -0
  44. Undefined/skills/agents/file_analysis_agent/handler.py +248 -0
  45. Undefined/skills/agents/file_analysis_agent/intro.md +22 -0
  46. Undefined/skills/agents/file_analysis_agent/prompt.md +36 -0
  47. Undefined/skills/agents/file_analysis_agent/tools/__init__.py +1 -0
  48. Undefined/skills/agents/file_analysis_agent/tools/analyze_code/config.json +17 -0
  49. Undefined/skills/agents/file_analysis_agent/tools/analyze_code/handler.py +427 -0
  50. Undefined/skills/agents/file_analysis_agent/tools/analyze_multimodal/config.json +25 -0
  51. Undefined/skills/agents/file_analysis_agent/tools/analyze_multimodal/handler.py +178 -0
  52. Undefined/skills/agents/file_analysis_agent/tools/cleanup_temp/config.json +16 -0
  53. Undefined/skills/agents/file_analysis_agent/tools/cleanup_temp/handler.py +35 -0
  54. Undefined/skills/agents/file_analysis_agent/tools/detect_file_type/config.json +17 -0
  55. Undefined/skills/agents/file_analysis_agent/tools/detect_file_type/handler.py +221 -0
  56. Undefined/skills/agents/file_analysis_agent/tools/download_file/config.json +21 -0
  57. Undefined/skills/agents/file_analysis_agent/tools/download_file/handler.py +124 -0
  58. Undefined/skills/agents/file_analysis_agent/tools/extract_archive/config.json +25 -0
  59. Undefined/skills/agents/file_analysis_agent/tools/extract_archive/handler.py +190 -0
  60. Undefined/skills/agents/file_analysis_agent/tools/extract_docx/config.json +17 -0
  61. Undefined/skills/agents/file_analysis_agent/tools/extract_docx/handler.py +78 -0
  62. Undefined/skills/agents/file_analysis_agent/tools/extract_pdf/config.json +21 -0
  63. Undefined/skills/agents/file_analysis_agent/tools/extract_pdf/handler.py +67 -0
  64. Undefined/skills/agents/file_analysis_agent/tools/extract_pptx/config.json +17 -0
  65. Undefined/skills/agents/file_analysis_agent/tools/extract_pptx/handler.py +73 -0
  66. Undefined/skills/agents/file_analysis_agent/tools/extract_xlsx/config.json +17 -0
  67. Undefined/skills/agents/file_analysis_agent/tools/extract_xlsx/handler.py +101 -0
  68. Undefined/skills/agents/file_analysis_agent/tools/get_current_time/config.json +12 -0
  69. Undefined/skills/agents/file_analysis_agent/tools/get_current_time/handler.py +5 -0
  70. Undefined/skills/agents/file_analysis_agent/tools/read_text_file/config.json +21 -0
  71. Undefined/skills/agents/file_analysis_agent/tools/read_text_file/handler.py +90 -0
  72. Undefined/skills/agents/info_agent/config.json +17 -0
  73. Undefined/skills/agents/info_agent/handler.py +220 -0
  74. Undefined/skills/agents/info_agent/intro.md +22 -0
  75. Undefined/skills/agents/info_agent/prompt.md +27 -0
  76. Undefined/skills/agents/info_agent/tools/__init__.py +1 -0
  77. Undefined/skills/agents/info_agent/tools/baiduhot/config.json +18 -0
  78. Undefined/skills/agents/info_agent/tools/baiduhot/handler.py +49 -0
  79. Undefined/skills/agents/info_agent/tools/base64/config.json +22 -0
  80. Undefined/skills/agents/info_agent/tools/base64/handler.py +44 -0
  81. Undefined/skills/agents/info_agent/tools/douyinhot/config.json +18 -0
  82. Undefined/skills/agents/info_agent/tools/douyinhot/handler.py +53 -0
  83. Undefined/skills/agents/info_agent/tools/get_current_time/config.json +12 -0
  84. Undefined/skills/agents/info_agent/tools/get_current_time/handler.py +5 -0
  85. Undefined/skills/agents/info_agent/tools/gold_price/config.json +12 -0
  86. Undefined/skills/agents/info_agent/tools/gold_price/handler.py +58 -0
  87. Undefined/skills/agents/info_agent/tools/hash/config.json +22 -0
  88. Undefined/skills/agents/info_agent/tools/hash/handler.py +43 -0
  89. Undefined/skills/agents/info_agent/tools/history/config.json +12 -0
  90. Undefined/skills/agents/info_agent/tools/history/handler.py +37 -0
  91. Undefined/skills/agents/info_agent/tools/net_check/config.json +17 -0
  92. Undefined/skills/agents/info_agent/tools/net_check/handler.py +117 -0
  93. Undefined/skills/agents/info_agent/tools/news_tencent/config.json +17 -0
  94. Undefined/skills/agents/info_agent/tools/news_tencent/handler.py +38 -0
  95. Undefined/skills/agents/info_agent/tools/qq_level_query/config.json +29 -0
  96. Undefined/skills/agents/info_agent/tools/qq_level_query/handler.py +48 -0
  97. Undefined/skills/agents/info_agent/tools/speed/config.json +17 -0
  98. Undefined/skills/agents/info_agent/tools/speed/handler.py +37 -0
  99. Undefined/skills/agents/info_agent/tools/tcping/config.json +21 -0
  100. Undefined/skills/agents/info_agent/tools/tcping/handler.py +53 -0
  101. Undefined/skills/agents/info_agent/tools/weather_query/config.json +22 -0
  102. Undefined/skills/agents/info_agent/tools/weather_query/handler.py +207 -0
  103. Undefined/skills/agents/info_agent/tools/weibohot/config.json +18 -0
  104. Undefined/skills/agents/info_agent/tools/weibohot/handler.py +49 -0
  105. Undefined/skills/agents/info_agent/tools/whois/config.json +17 -0
  106. Undefined/skills/agents/info_agent/tools/whois/handler.py +63 -0
  107. Undefined/skills/agents/naga_code_analysis_agent/config.json +17 -0
  108. Undefined/skills/agents/naga_code_analysis_agent/handler.py +222 -0
  109. Undefined/skills/agents/naga_code_analysis_agent/intro.md +17 -0
  110. Undefined/skills/agents/naga_code_analysis_agent/prompt.md +19 -0
  111. Undefined/skills/agents/naga_code_analysis_agent/tools/__init__.py +1 -0
  112. Undefined/skills/agents/naga_code_analysis_agent/tools/get_current_time/config.json +12 -0
  113. Undefined/skills/agents/naga_code_analysis_agent/tools/get_current_time/handler.py +5 -0
  114. Undefined/skills/agents/naga_code_analysis_agent/tools/glob/config.json +17 -0
  115. Undefined/skills/agents/naga_code_analysis_agent/tools/glob/handler.py +37 -0
  116. Undefined/skills/agents/naga_code_analysis_agent/tools/list_directory/config.json +17 -0
  117. Undefined/skills/agents/naga_code_analysis_agent/tools/list_directory/handler.py +31 -0
  118. Undefined/skills/agents/naga_code_analysis_agent/tools/read_file/config.json +17 -0
  119. Undefined/skills/agents/naga_code_analysis_agent/tools/read_file/handler.py +66 -0
  120. Undefined/skills/agents/naga_code_analysis_agent/tools/read_naga_intro/config.json +12 -0
  121. Undefined/skills/agents/naga_code_analysis_agent/tools/read_naga_intro/handler.py +327 -0
  122. Undefined/skills/agents/naga_code_analysis_agent/tools/search_file_content/config.json +25 -0
  123. Undefined/skills/agents/naga_code_analysis_agent/tools/search_file_content/handler.py +46 -0
  124. Undefined/skills/agents/scheduler_agent/__init__.py +1 -0
  125. Undefined/skills/agents/scheduler_agent/config.json +17 -0
  126. Undefined/skills/agents/scheduler_agent/handler.py +218 -0
  127. Undefined/skills/agents/scheduler_agent/intro.md +17 -0
  128. Undefined/skills/agents/scheduler_agent/prompt.md +67 -0
  129. Undefined/skills/agents/scheduler_agent/tools/__init__.py +1 -0
  130. Undefined/skills/agents/scheduler_agent/tools/create_schedule_task/config.json +37 -0
  131. Undefined/skills/agents/scheduler_agent/tools/create_schedule_task/handler.py +68 -0
  132. Undefined/skills/agents/scheduler_agent/tools/delete_schedule_task/config.json +19 -0
  133. Undefined/skills/agents/scheduler_agent/tools/delete_schedule_task/handler.py +26 -0
  134. Undefined/skills/agents/scheduler_agent/tools/get_current_time/config.json +12 -0
  135. Undefined/skills/agents/scheduler_agent/tools/get_current_time/handler.py +5 -0
  136. Undefined/skills/agents/scheduler_agent/tools/list_schedule_tasks/config.json +11 -0
  137. Undefined/skills/agents/scheduler_agent/tools/list_schedule_tasks/handler.py +47 -0
  138. Undefined/skills/agents/scheduler_agent/tools/update_schedule_task/config.json +39 -0
  139. Undefined/skills/agents/scheduler_agent/tools/update_schedule_task/handler.py +46 -0
  140. Undefined/skills/agents/social_agent/config.json +17 -0
  141. Undefined/skills/agents/social_agent/handler.py +220 -0
  142. Undefined/skills/agents/social_agent/intro.md +17 -0
  143. Undefined/skills/agents/social_agent/prompt.md +19 -0
  144. Undefined/skills/agents/social_agent/tools/__init__.py +1 -0
  145. Undefined/skills/agents/social_agent/tools/bilibili_search/config.json +21 -0
  146. Undefined/skills/agents/social_agent/tools/bilibili_search/handler.py +68 -0
  147. Undefined/skills/agents/social_agent/tools/bilibili_user_info/config.json +17 -0
  148. Undefined/skills/agents/social_agent/tools/bilibili_user_info/handler.py +68 -0
  149. Undefined/skills/agents/social_agent/tools/get_current_time/config.json +12 -0
  150. Undefined/skills/agents/social_agent/tools/get_current_time/handler.py +5 -0
  151. Undefined/skills/agents/social_agent/tools/music_global_search/config.json +21 -0
  152. Undefined/skills/agents/social_agent/tools/music_global_search/handler.py +47 -0
  153. Undefined/skills/agents/social_agent/tools/music_info_get/config.json +22 -0
  154. Undefined/skills/agents/social_agent/tools/music_info_get/handler.py +35 -0
  155. Undefined/skills/agents/social_agent/tools/music_lyrics/config.json +22 -0
  156. Undefined/skills/agents/social_agent/tools/music_lyrics/handler.py +26 -0
  157. Undefined/skills/agents/social_agent/tools/video_random_recommend/config.json +21 -0
  158. Undefined/skills/agents/social_agent/tools/video_random_recommend/handler.py +21 -0
  159. Undefined/skills/agents/web_agent/config.json +17 -0
  160. Undefined/skills/agents/web_agent/handler.py +221 -0
  161. Undefined/skills/agents/web_agent/intro.md +14 -0
  162. Undefined/skills/agents/web_agent/prompt.md +16 -0
  163. Undefined/skills/agents/web_agent/tools/__init__.py +1 -0
  164. Undefined/skills/agents/web_agent/tools/crawl_webpage/config.json +21 -0
  165. Undefined/skills/agents/web_agent/tools/crawl_webpage/handler.py +102 -0
  166. Undefined/skills/agents/web_agent/tools/get_current_time/config.json +12 -0
  167. Undefined/skills/agents/web_agent/tools/get_current_time/handler.py +5 -0
  168. Undefined/skills/agents/web_agent/tools/web_search/config.json +21 -0
  169. Undefined/skills/agents/web_agent/tools/web_search/handler.py +29 -0
  170. Undefined/skills/tools/README.md +85 -0
  171. Undefined/skills/tools/__init__.py +120 -0
  172. Undefined/skills/tools/debug/config.json +17 -0
  173. Undefined/skills/tools/debug/handler.py +35 -0
  174. Undefined/skills/tools/end/config.json +17 -0
  175. Undefined/skills/tools/end/handler.py +24 -0
  176. Undefined/skills/tools/get_current_time/config.json +12 -0
  177. Undefined/skills/tools/get_current_time/handler.py +5 -0
  178. Undefined/skills/tools/get_forward_msg/config.json +17 -0
  179. Undefined/skills/tools/get_forward_msg/handler.py +131 -0
  180. Undefined/skills/tools/get_group_member_info/config.json +38 -0
  181. Undefined/skills/tools/get_group_member_info/handler.py +142 -0
  182. Undefined/skills/tools/get_messages_by_time/config.json +30 -0
  183. Undefined/skills/tools/get_messages_by_time/handler.py +128 -0
  184. Undefined/skills/tools/get_picture/config.json +45 -0
  185. Undefined/skills/tools/get_picture/handler.py +191 -0
  186. Undefined/skills/tools/get_recent_messages/config.json +30 -0
  187. Undefined/skills/tools/get_recent_messages/handler.py +88 -0
  188. Undefined/skills/tools/qq_like/config.json +22 -0
  189. Undefined/skills/tools/qq_like/handler.py +58 -0
  190. Undefined/skills/tools/render_html/config.json +26 -0
  191. Undefined/skills/tools/render_html/handler.py +39 -0
  192. Undefined/skills/tools/render_latex/config.json +26 -0
  193. Undefined/skills/tools/render_latex/handler.py +78 -0
  194. Undefined/skills/tools/render_markdown/config.json +26 -0
  195. Undefined/skills/tools/render_markdown/handler.py +63 -0
  196. Undefined/skills/tools/save_memory/config.json +17 -0
  197. Undefined/skills/tools/save_memory/handler.py +17 -0
  198. Undefined/skills/tools/send_message/config.json +21 -0
  199. Undefined/skills/tools/send_message/handler.py +60 -0
  200. Undefined/skills/tools/send_private_message/config.json +21 -0
  201. Undefined/skills/tools/send_private_message/handler.py +35 -0
  202. Undefined/utils/__init__.py +0 -0
  203. Undefined/utils/common.py +186 -0
  204. Undefined/utils/history.py +284 -0
  205. Undefined/utils/scheduler.py +286 -0
  206. Undefined/utils/sender.py +140 -0
  207. undefined_bot-2.1.0.dist-info/METADATA +259 -0
  208. undefined_bot-2.1.0.dist-info/RECORD +211 -0
  209. undefined_bot-2.1.0.dist-info/WHEEL +4 -0
  210. undefined_bot-2.1.0.dist-info/entry_points.txt +2 -0
  211. undefined_bot-2.1.0.dist-info/licenses/LICENSE +7 -0
@@ -0,0 +1,90 @@
1
+ import chardet
2
+ from pathlib import Path
3
+ from typing import Any, Dict
4
+ import logging
5
+
6
+ logger = logging.getLogger(__name__)
7
+
8
+
9
+ async def execute(args: Dict[str, Any], context: Dict[str, Any]) -> str:
10
+ file_path: str = args.get("file_path", "")
11
+ max_lines: int | None = args.get("max_lines")
12
+
13
+ path = Path(file_path)
14
+
15
+ if not path.exists():
16
+ return f"错误:文件不存在 {file_path}"
17
+
18
+ if not path.is_file():
19
+ return f"错误:{file_path} 不是文件"
20
+
21
+ try:
22
+ file_size = path.stat().st_size
23
+
24
+ with open(path, "rb") as binary_file:
25
+ raw_data: bytes = binary_file.read()
26
+
27
+ detected = chardet.detect(raw_data)
28
+ encoding: str | None = detected.get("encoding") if detected else None
29
+ confidence: float = detected.get("confidence", 0.0) if detected else 0.0
30
+
31
+ encodings_to_try: list[str] = []
32
+ if encoding and confidence > 0.5:
33
+ encodings_to_try.append(encoding)
34
+ encodings_to_try.extend(
35
+ [
36
+ "utf-8",
37
+ "gbk",
38
+ "gb2312",
39
+ "gb18030",
40
+ "big5",
41
+ "shift_jis",
42
+ "euc-kr",
43
+ "latin-1",
44
+ ]
45
+ )
46
+
47
+ file_content: str = ""
48
+ actual_encoding: str = "unknown"
49
+ decode_error: Exception | None = None
50
+
51
+ for enc in encodings_to_try:
52
+ try:
53
+ file_content = raw_data.decode(enc)
54
+ actual_encoding = enc
55
+ break
56
+ except (UnicodeDecodeError, LookupError) as e:
57
+ decode_error = e
58
+ continue
59
+
60
+ if not file_content and decode_error:
61
+ return f"错误:无法解码文件,可能是二进制文件。文件大小:{file_size} 字节"
62
+
63
+ control_chars = sum(
64
+ 1 for c in file_content if ord(c) < 32 and c not in "\t\n\r"
65
+ )
66
+ if control_chars > len(file_content) * 0.05:
67
+ return f"错误:文件包含大量控制字符,可能是二进制文件。文件大小:{file_size} 字节"
68
+
69
+ total_lines = file_content.count("\n")
70
+ if max_lines and total_lines > max_lines:
71
+ lines = file_content.split("\n")[:max_lines]
72
+ file_content = "\n".join(lines)
73
+ truncated = True
74
+ else:
75
+ truncated = False
76
+
77
+ info_lines: list[str] = []
78
+ info_lines.append(f"文件大小:{file_size} 字节")
79
+ info_lines.append(f"检测编码:{encoding} (置信度: {confidence:.2f})")
80
+ info_lines.append(f"实际编码:{actual_encoding}")
81
+ info_lines.append(f"内容行数:{total_lines}")
82
+ if truncated:
83
+ info_lines.append(f"已截断到前 {max_lines} 行")
84
+ info_lines.append("")
85
+
86
+ return "\n".join(info_lines) + file_content
87
+
88
+ except Exception as e:
89
+ logger.exception(f"读取文件失败: {e}")
90
+ return f"读取文件失败: {e}"
@@ -0,0 +1,17 @@
1
+ {
2
+ "type": "function",
3
+ "function": {
4
+ "name": "info_agent",
5
+ "description": "信息查询助手,提供天气、热搜、新闻、历史、网络诊断、编码工具等各类实用信息查询功能。",
6
+ "parameters": {
7
+ "type": "object",
8
+ "properties": {
9
+ "prompt": {
10
+ "type": "string",
11
+ "description": "用户的查询需求,例如:'北京天气'、'今日热搜'、'查询 qq123456 的等级'"
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
+ """执行 info_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,22 @@
1
+ # 信息查询助手
2
+
3
+ ## 能力
4
+ - **生活服务**:查询指定城市天气、查询实时黄金价格
5
+ - **热搜榜单**:获取百度、微博、抖音热搜榜,获取腾讯新闻
6
+ - **文化历史**:查询历史上的今天
7
+ - **网络工具**:网络诊断(TCP Ping/网速测试/连通性检查)、Whois域名查询、Base64编解码、Hash计算
8
+ - **其他查询**:查询QQ等级
9
+
10
+ ## 适用场景
11
+ - 用户查询天气、金价时
12
+ - 用户想看新闻或热搜时
13
+ - 用户查询历史事件时
14
+ - 用户需要测试网络连通性、查询域名信息时
15
+ - 用户需要进行 Base64 编解码或计算 Hash 时
16
+ - 用户查询 QQ 等级时
17
+
18
+ ## 参数说明
19
+ - `city` (天气): 城市名称(如:北京)
20
+ - `qq` (QQ等级): 目标 QQ 号码
21
+ - `target`/`host` (网络工具): 目标域名或 IP
22
+ - `text` (编码/哈希): 需要处理的文本内容
@@ -0,0 +1,27 @@
1
+ 你是一个信息查询助手,专门帮助用户获取各种实用信息。
2
+
3
+ 你的任务是根据用户需求,选择合适的工具来完成任务:
4
+
5
+ 1. **天气查询** → weather_query
6
+ 2. **黄金价格** → gold_price
7
+ 3. **百度热搜** → baiduhot
8
+ 4. **微博热搜** → weibohot
9
+ 5. **抖音热搜** → douyinhot
10
+ 6. **腾讯新闻** → news_tencent
11
+ 7. **历史今天** → history
12
+ 8. **文昌帝君** → wenchang_dijun
13
+ 9. **QQ 等级** → qq_level_query
14
+ 10. **网络诊断** → tcping / speed / net_check
15
+ 11. **Base64 编码/解码** → base64
16
+ 12. **哈希计算** → hash
17
+ 13. **Whois 查询** → whois
18
+
19
+ 注意事项:
20
+ - 天气查询支持城市名称
21
+ - QQ 等级查询需要提供目标 QQ 号
22
+ - 网络诊断可能需要一定时间
23
+ - 保持回答简洁明了
24
+
25
+ 如果用户需求不明确,请先询问用户澄清问题。
26
+
27
+ 如果问题涉及时间,立刻调用时间工具获取。
@@ -0,0 +1 @@
1
+ # Info Agent Tools
@@ -0,0 +1,18 @@
1
+ {
2
+ "type": "function",
3
+ "function": {
4
+ "name": "baiduhot",
5
+ "description": "获取百度热搜排行榜,实时返回百度搜索引擎上的热门搜索词和趋势。",
6
+ "parameters": {
7
+ "type": "object",
8
+ "properties": {
9
+ "limit": {
10
+ "type": "integer",
11
+ "description": "返回的热搜数量,默认10",
12
+ "default": 10
13
+ }
14
+ },
15
+ "required": []
16
+ }
17
+ }
18
+ }
@@ -0,0 +1,49 @@
1
+ from typing import Any, Dict
2
+ import logging
3
+ import httpx
4
+
5
+ logger = logging.getLogger(__name__)
6
+
7
+ async def execute(args: Dict[str, Any], context: Dict[str, Any]) -> str:
8
+ limit = args.get("limit", 10)
9
+
10
+ if limit < 1 or limit > 50:
11
+ return "❌ 热搜数量必须在 1-50 之间"
12
+
13
+ try:
14
+ async with httpx.AsyncClient(timeout=15.0) as client:
15
+ logger.info(f"获取百度热搜,数量: {limit}")
16
+
17
+ response = await client.get("https://v2.xxapi.cn/api/baiduhot")
18
+ response.raise_for_status()
19
+ data = response.json()
20
+
21
+ if data.get("code") != 200:
22
+ return f"获取百度热搜失败: {data.get('msg')}"
23
+
24
+ hot_list = data.get("data", [])
25
+ if not hot_list:
26
+ return "暂无热搜数据"
27
+
28
+ result = f"【百度热搜 TOP {min(limit, len(hot_list))}】\n\n"
29
+
30
+ for idx, item in enumerate(hot_list[:limit], 1):
31
+ title = item.get("title", "")
32
+ hot = item.get("hot", "")
33
+ url = item.get("url", "")
34
+ result += f"{idx}. {title}\n"
35
+ result += f" 热度: {hot}\n"
36
+ if url:
37
+ result += f" 链接: {url}\n"
38
+ result += "\n"
39
+
40
+ return result
41
+
42
+ except httpx.TimeoutException:
43
+ return "请求超时,请稍后重试"
44
+ except httpx.HTTPStatusError as e:
45
+ logger.error(f"HTTP 错误: {e}")
46
+ return f"获取百度热搜失败: {e}"
47
+ except Exception as e:
48
+ logger.exception(f"获取百度热搜失败: {e}")
49
+ return f"获取百度热搜失败: {e}"
@@ -0,0 +1,22 @@
1
+ {
2
+ "type": "function",
3
+ "function": {
4
+ "name": "base64",
5
+ "description": "Base64加密与解密工具,支持对字符串进行Base64编码(加密)和解码(解密)操作。",
6
+ "parameters": {
7
+ "type": "object",
8
+ "properties": {
9
+ "text": {
10
+ "type": "string",
11
+ "description": "需要加密或解密的字符串"
12
+ },
13
+ "operation": {
14
+ "type": "string",
15
+ "description": "操作类型:encode(加密)或 decode(解密)",
16
+ "enum": ["encode", "decode"]
17
+ }
18
+ },
19
+ "required": ["text", "operation"]
20
+ }
21
+ }
22
+ }
@@ -0,0 +1,44 @@
1
+ from typing import Any, Dict
2
+ import logging
3
+ import httpx
4
+
5
+ logger = logging.getLogger(__name__)
6
+
7
+ async def execute(args: Dict[str, Any], context: Dict[str, Any]) -> str:
8
+ text = args.get("text")
9
+ operation = args.get("operation")
10
+
11
+ if not text:
12
+ return "❌ 文本不能为空"
13
+ if not operation:
14
+ return "❌ 操作类型不能为空"
15
+ if operation not in ["encode", "decode"]:
16
+ return "❌ 操作类型必须是 encode(加密)或 decode(解密)"
17
+
18
+ try:
19
+ async with httpx.AsyncClient(timeout=10.0) as client:
20
+ params = {
21
+ "type": operation,
22
+ "text": text
23
+ }
24
+ logger.info(f"Base64 {operation}: {text[:50]}...")
25
+
26
+ response = await client.get("https://v2.xxapi.cn/api/base64", params=params)
27
+ response.raise_for_status()
28
+ data = response.json()
29
+
30
+ if data.get("code") != 200 and data.get("code") != "200":
31
+ return f"Base64 {operation} 失败: {data.get('msg')}"
32
+
33
+ result = data.get("data")
34
+ operation_text = "加密" if operation == "encode" else "解密"
35
+ return f"Base64{operation_text}结果:\n{result}"
36
+
37
+ except httpx.TimeoutException:
38
+ return "请求超时,请稍后重试"
39
+ except httpx.HTTPStatusError as e:
40
+ logger.error(f"HTTP 错误: {e}")
41
+ return f"请求失败: {e}"
42
+ except Exception as e:
43
+ logger.exception(f"Base64操作失败: {e}")
44
+ return f"操作失败: {e}"
@@ -0,0 +1,18 @@
1
+ {
2
+ "type": "function",
3
+ "function": {
4
+ "name": "douyinhot",
5
+ "description": "获取抖音热榜,实时返回抖音平台上的热门视频、话题和排行榜数据。",
6
+ "parameters": {
7
+ "type": "object",
8
+ "properties": {
9
+ "limit": {
10
+ "type": "integer",
11
+ "description": "返回的热榜数量,默认10",
12
+ "default": 10
13
+ }
14
+ },
15
+ "required": []
16
+ }
17
+ }
18
+ }
@@ -0,0 +1,53 @@
1
+ from typing import Any, Dict
2
+ import logging
3
+ import httpx
4
+
5
+ logger = logging.getLogger(__name__)
6
+
7
+ async def execute(args: Dict[str, Any], context: Dict[str, Any]) -> str:
8
+ limit = args.get("limit", 10)
9
+
10
+ if limit < 1 or limit > 50:
11
+ return "❌ 热榜数量必须在 1-50 之间"
12
+
13
+ try:
14
+ async with httpx.AsyncClient(timeout=15.0) as client:
15
+ logger.info(f"获取抖音热榜,数量: {limit}")
16
+
17
+ response = await client.get("https://v2.xxapi.cn/api/douyinhot")
18
+ response.raise_for_status()
19
+ data = response.json()
20
+
21
+ if data.get("code") != 200:
22
+ return f"获取抖音热榜失败: {data.get('msg')}"
23
+
24
+ hot_list = data.get("data", [])
25
+ if not hot_list:
26
+ return "暂无热榜数据"
27
+
28
+ result = f"【抖音热榜 TOP {min(limit, len(hot_list))}】\n\n"
29
+
30
+ for idx, item in enumerate(hot_list[:limit], 1):
31
+ word = item.get("word", "")
32
+ hot_value = item.get("hot_value", 0)
33
+ position = item.get("position", idx)
34
+ video_count = item.get("video_count", 0)
35
+
36
+ # 将热度值转换为万
37
+ hot_str = f"{hot_value / 10000:.1f}万" if hot_value >= 10000 else str(hot_value)
38
+
39
+ result += f"{position}. {word}\n"
40
+ result += f" 热度: {hot_str}\n"
41
+ result += f" 视频数: {video_count}\n"
42
+ result += "\n"
43
+
44
+ return result
45
+
46
+ except httpx.TimeoutException:
47
+ return "请求超时,请稍后重试"
48
+ except httpx.HTTPStatusError as e:
49
+ logger.error(f"HTTP 错误: {e}")
50
+ return f"获取抖音热榜失败: {e}"
51
+ except Exception as e:
52
+ logger.exception(f"获取抖音热榜失败: {e}")
53
+ return f"获取抖音热榜失败: {e}"
@@ -0,0 +1,12 @@
1
+ {
2
+ "type": "function",
3
+ "function": {
4
+ "name": "get_current_time",
5
+ "description": "获取当前系统时间。",
6
+ "parameters": {
7
+ "type": "object",
8
+ "properties": {},
9
+ "required": []
10
+ }
11
+ }
12
+ }
@@ -0,0 +1,5 @@
1
+ from typing import Any, Dict
2
+ from datetime import datetime
3
+
4
+ async def execute(args: Dict[str, Any], context: Dict[str, Any]) -> str:
5
+ return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
@@ -0,0 +1,12 @@
1
+ {
2
+ "type": "function",
3
+ "function": {
4
+ "name": "gold_price",
5
+ "description": "获取今日黄金价格,包括银行投资金条价格、黄金回收价格和贵金属品牌价格。",
6
+ "parameters": {
7
+ "type": "object",
8
+ "properties": {},
9
+ "required": []
10
+ }
11
+ }
12
+ }