mirror of
https://github.com/AstrBotDevs/AstrBot
synced 2026-07-19 02:12:46 +08:00
Merge remote-tracking branch 'origin/master' into feat/astrbot-agent-mode
This commit is contained in:
@@ -6,26 +6,7 @@ from astrbot.core.star.star import star_map
|
||||
from astrbot.core.star.filter.command import CommandFilter
|
||||
from astrbot.core.star.filter.command_group import CommandGroupFilter
|
||||
from astrbot.core.star.filter.permission import PermissionTypeFilter
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class RstScene(Enum):
|
||||
GROUP_UNIQUE_ON = ("group_unique_on", "群聊+会话隔离开启")
|
||||
GROUP_UNIQUE_OFF = ("group_unique_off", "群聊+会话隔离关闭")
|
||||
PRIVATE = ("private", "私聊")
|
||||
|
||||
@property
|
||||
def key(self) -> str:
|
||||
return self.value[0]
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
return self.value[1]
|
||||
|
||||
@classmethod
|
||||
def from_index(cls, index: int) -> "RstScene":
|
||||
mapping = {1: cls.GROUP_UNIQUE_ON, 2: cls.GROUP_UNIQUE_OFF, 3: cls.PRIVATE}
|
||||
return mapping[index]
|
||||
from .utils.rst_scene import RstScene
|
||||
|
||||
|
||||
class AlterCmdCommands(CommandParserMixin):
|
||||
@@ -58,8 +39,9 @@ class AlterCmdCommands(CommandParserMixin):
|
||||
)
|
||||
return
|
||||
|
||||
cmd_name = " ".join(token.tokens[1:-1])
|
||||
cmd_type = token.get(-1)
|
||||
# 兼容 reset scene 的专门配置
|
||||
cmd_name = token.get(1)
|
||||
cmd_type = token.get(2)
|
||||
|
||||
if cmd_name == "reset" and cmd_type == "config":
|
||||
from astrbot.api import sp
|
||||
@@ -123,6 +105,8 @@ class AlterCmdCommands(CommandParserMixin):
|
||||
return
|
||||
|
||||
# 查找指令
|
||||
cmd_name = " ".join(token.tokens[1:-1])
|
||||
cmd_type = token.get(-1)
|
||||
found_command = None
|
||||
cmd_group = False
|
||||
for handler in star_handlers_registry:
|
||||
|
||||
@@ -6,40 +6,27 @@ from astrbot.core.platform.message_type import MessageType
|
||||
from astrbot.core.provider.sources.dify_source import ProviderDify
|
||||
from astrbot.core.provider.sources.coze_source import ProviderCoze
|
||||
from astrbot.api import sp, logger
|
||||
from ..long_term_memory import LongTermMemory
|
||||
from .utils.rst_scene import RstScene
|
||||
from typing import Union
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class RstScene(Enum):
|
||||
GROUP_UNIQUE_ON = ("group_unique_on", "群聊+会话隔离开启")
|
||||
GROUP_UNIQUE_OFF = ("group_unique_off", "群聊+会话隔离关闭")
|
||||
PRIVATE = ("private", "私聊")
|
||||
|
||||
@property
|
||||
def key(self) -> str:
|
||||
return self.value[0]
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
return self.value[1]
|
||||
|
||||
@classmethod
|
||||
def from_index(cls, index: int) -> "RstScene":
|
||||
mapping = {1: cls.GROUP_UNIQUE_ON, 2: cls.GROUP_UNIQUE_OFF, 3: cls.PRIVATE}
|
||||
return mapping[index]
|
||||
|
||||
@classmethod
|
||||
def get_scene(cls, is_group: bool, is_unique_session: bool) -> "RstScene":
|
||||
if is_group:
|
||||
return cls.GROUP_UNIQUE_ON if is_unique_session else cls.GROUP_UNIQUE_OFF
|
||||
return cls.PRIVATE
|
||||
|
||||
|
||||
class ConversationCommands:
|
||||
def __init__(self, context: star.Context, ltm=None):
|
||||
def __init__(self, context: star.Context, ltm: LongTermMemory | None = None):
|
||||
self.context = context
|
||||
self.ltm = ltm
|
||||
|
||||
async def _get_current_persona_id(self, session_id):
|
||||
curr = await self.context.conversation_manager.get_curr_conversation_id(
|
||||
session_id
|
||||
)
|
||||
if not curr:
|
||||
return None
|
||||
conv = await self.context.conversation_manager.get_conversation(
|
||||
session_id, curr
|
||||
)
|
||||
return conv.persona_id
|
||||
|
||||
def ltm_enabled(self, event: AstrMessageEvent):
|
||||
if not self.ltm:
|
||||
return False
|
||||
@@ -254,8 +241,9 @@ class ConversationCommands:
|
||||
)
|
||||
return
|
||||
|
||||
cpersona = await self._get_current_persona_id(message.unified_msg_origin)
|
||||
cid = await self.context.conversation_manager.new_conversation(
|
||||
message.unified_msg_origin, message.get_platform_id()
|
||||
message.unified_msg_origin, message.get_platform_id(), persona_id=cpersona
|
||||
)
|
||||
|
||||
# 长期记忆
|
||||
@@ -289,8 +277,10 @@ class ConversationCommands:
|
||||
session_id=sid,
|
||||
)
|
||||
)
|
||||
|
||||
cpersona = await self._get_current_persona_id(session)
|
||||
cid = await self.context.conversation_manager.new_conversation(
|
||||
session, message.get_platform_id()
|
||||
session, message.get_platform_id(), persona_id=cpersona
|
||||
)
|
||||
message.set_result(
|
||||
MessageEventResult().message(
|
||||
@@ -433,8 +423,9 @@ class ConversationCommands:
|
||||
await self.context.conversation_manager.delete_conversation(
|
||||
message.unified_msg_origin, session_curr_cid
|
||||
)
|
||||
message.set_result(
|
||||
MessageEventResult().message(
|
||||
"删除当前对话成功。不再处于对话状态,使用 /switch 序号 切换到其他对话或 /new 创建。"
|
||||
)
|
||||
)
|
||||
|
||||
ret = "删除当前对话成功。不再处于对话状态,使用 /switch 序号 切换到其他对话或 /new 创建。"
|
||||
if self.ltm and self.ltm_enabled(message):
|
||||
cnt = await self.ltm.remove_session(event=message)
|
||||
ret += f"\n聊天增强: 已清除 {cnt} 条聊天记录。"
|
||||
message.set_result(MessageEventResult().message(ret))
|
||||
|
||||
@@ -129,7 +129,7 @@ class ProviderCommands:
|
||||
)
|
||||
return
|
||||
i = 1
|
||||
ret = "下面列出了此服务提供商可用模型:"
|
||||
ret = "下面列出了此模型提供商可用模型:"
|
||||
for model in models:
|
||||
ret += f"\n{i}. {model}"
|
||||
i += 1
|
||||
@@ -159,7 +159,11 @@ class ProviderCommands:
|
||||
message.set_result(
|
||||
MessageEventResult().message("切换模型未知错误: " + str(e))
|
||||
)
|
||||
message.set_result(MessageEventResult().message("切换模型成功。"))
|
||||
message.set_result(
|
||||
MessageEventResult().message(
|
||||
f"切换模型成功。当前提供商: [{prov.meta().id}] 当前模型: [{prov.get_model()}]"
|
||||
)
|
||||
)
|
||||
else:
|
||||
prov.set_model(idx_or_name)
|
||||
message.set_result(
|
||||
|
||||
@@ -11,19 +11,26 @@ class SIDCommand:
|
||||
self.context = context
|
||||
|
||||
async def sid(self, event: AstrMessageEvent):
|
||||
"""获取会话 ID 和 管理员 ID"""
|
||||
"""获取消息来源信息"""
|
||||
sid = event.unified_msg_origin
|
||||
user_id = str(event.get_sender_id())
|
||||
ret = f"""SID: {sid} 此 ID 可用于设置会话白名单。
|
||||
/wl <SID> 添加白名单, /dwl <SID> 删除白名单。
|
||||
|
||||
UID: {user_id} 此 ID 可用于设置管理员。
|
||||
/op <UID> 授权管理员, /deop <UID> 取消管理员。"""
|
||||
umo_platform = event.session.platform_id
|
||||
umo_msg_type = event.session.message_type.value
|
||||
umo_session_id = event.session.session_id
|
||||
ret = (
|
||||
f"UMO: 「{sid}」 此值可用于设置白名单。\n"
|
||||
f"UID: 「{user_id}」 此值可用于设置管理员。\n"
|
||||
f"消息会话来源信息:\n"
|
||||
f" 机器人 ID: 「{umo_platform}」\n"
|
||||
f" 消息类型: 「{umo_msg_type}」\n"
|
||||
f" 会话 ID: 「{umo_session_id}」\n"
|
||||
f"消息来源可用于配置机器人的配置文件路由。"
|
||||
)
|
||||
|
||||
if (
|
||||
self.context.get_config()["platform_settings"]["unique_session"]
|
||||
and event.get_group_id()
|
||||
):
|
||||
ret += f"\n\n当前处于独立会话模式, 此群 ID: {event.get_group_id()}, 也可将此 ID 加入白名单来放行整个群聊。"
|
||||
ret += f"\n\n当前处于独立会话模式, 此群 ID: 「{event.get_group_id()}」, 也可将此 ID 加入白名单来放行整个群聊。"
|
||||
|
||||
event.set_result(MessageEventResult().message(ret).use_t2i(False))
|
||||
|
||||
26
packages/astrbot/commands/utils/rst_scene.py
Normal file
26
packages/astrbot/commands/utils/rst_scene.py
Normal file
@@ -0,0 +1,26 @@
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class RstScene(Enum):
|
||||
GROUP_UNIQUE_ON = ("group_unique_on", "群聊+会话隔离开启")
|
||||
GROUP_UNIQUE_OFF = ("group_unique_off", "群聊+会话隔离关闭")
|
||||
PRIVATE = ("private", "私聊")
|
||||
|
||||
@property
|
||||
def key(self) -> str:
|
||||
return self.value[0]
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
return self.value[1]
|
||||
|
||||
@classmethod
|
||||
def from_index(cls, index: int) -> "RstScene":
|
||||
mapping = {1: cls.GROUP_UNIQUE_ON, 2: cls.GROUP_UNIQUE_OFF, 3: cls.PRIVATE}
|
||||
return mapping[index]
|
||||
|
||||
@classmethod
|
||||
def get_scene(cls, is_group: bool, is_unique_session: bool) -> "RstScene":
|
||||
if is_group:
|
||||
return cls.GROUP_UNIQUE_ON if is_unique_session else cls.GROUP_UNIQUE_OFF
|
||||
return cls.PRIVATE
|
||||
@@ -4,7 +4,7 @@ import random
|
||||
import astrbot.api.star as star
|
||||
from astrbot.api.event import AstrMessageEvent
|
||||
from astrbot.api.platform import MessageType
|
||||
from astrbot.api.provider import ProviderRequest
|
||||
from astrbot.api.provider import ProviderRequest, Provider
|
||||
from astrbot.api.message_components import Plain, Image
|
||||
from astrbot import logger
|
||||
from collections import defaultdict
|
||||
@@ -32,6 +32,7 @@ class LongTermMemory:
|
||||
image_caption = (
|
||||
True
|
||||
if cfg["provider_settings"]["default_image_caption_provider_id"]
|
||||
and cfg["provider_ltm_settings"]["image_caption"]
|
||||
else False
|
||||
)
|
||||
image_caption_prompt = cfg["provider_settings"]["image_caption_prompt"]
|
||||
@@ -73,6 +74,8 @@ class LongTermMemory:
|
||||
provider = self.context.get_provider_by_id(image_caption_provider_id)
|
||||
if not provider:
|
||||
raise Exception(f"没有找到 ID 为 {image_caption_provider_id} 的提供商")
|
||||
if not isinstance(provider, Provider):
|
||||
raise Exception(f"提供商类型错误({type(provider)}),无法获取图片描述")
|
||||
response = await provider.text_chat(
|
||||
prompt=image_caption_prompt,
|
||||
session_id=uuid.uuid4().hex,
|
||||
@@ -122,8 +125,11 @@ class LongTermMemory:
|
||||
elif isinstance(comp, Image):
|
||||
if cfg["image_caption"]:
|
||||
try:
|
||||
url = comp.url if comp.url else comp.file
|
||||
if not url:
|
||||
raise Exception("图片 URL 为空")
|
||||
caption = await self.get_image_caption(
|
||||
comp.url if comp.url else comp.file,
|
||||
url,
|
||||
cfg["image_caption_provider_id"],
|
||||
cfg["image_caption_prompt"],
|
||||
)
|
||||
|
||||
@@ -41,7 +41,7 @@ class Main(star.Star):
|
||||
self.tool_c = ToolCommands(self.context)
|
||||
self.plugin_c = PluginCommands(self.context)
|
||||
self.admin_c = AdminCommands(self.context)
|
||||
self.conversation_c = ConversationCommands(self.context)
|
||||
self.conversation_c = ConversationCommands(self.context, self.ltm)
|
||||
self.provider_c = ProviderCommands(self.context)
|
||||
self.persona_c = PersonaCommands(self.context)
|
||||
self.alter_cmd_c = AlterCmdCommands(self.context)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import copy
|
||||
import astrbot.api.star as star
|
||||
import builtins
|
||||
import datetime
|
||||
@@ -41,7 +42,7 @@ class ProcessLLMRequest:
|
||||
if persona:
|
||||
if prompt := persona["prompt"]:
|
||||
req.system_prompt += prompt
|
||||
if begin_dialogs := persona["_begin_dialogs_processed"]:
|
||||
if begin_dialogs := copy.deepcopy(persona["_begin_dialogs_processed"]):
|
||||
req.contexts[:0] = begin_dialogs
|
||||
|
||||
# tools select
|
||||
|
||||
@@ -1,9 +1,19 @@
|
||||
import re
|
||||
import json
|
||||
import logging
|
||||
from typing import Any, Tuple
|
||||
|
||||
from astrbot.api.event import filter, AstrMessageEvent
|
||||
from astrbot.api.star import Context, Star
|
||||
from astrbot.api.provider import LLMResponse
|
||||
from openai.types.chat.chat_completion import ChatCompletion
|
||||
|
||||
try:
|
||||
# 谨慎引入,避免在未安装 google-genai 的环境下报错
|
||||
from google.genai.types import GenerateContentResponse
|
||||
except Exception: # pragma: no cover - 兼容无此依赖的运行环境
|
||||
GenerateContentResponse = None # type: ignore
|
||||
|
||||
|
||||
class R1Filter(Star):
|
||||
def __init__(self, context: Context):
|
||||
@@ -14,7 +24,36 @@ class R1Filter(Star):
|
||||
cfg = self.context.get_config(umo=event.unified_msg_origin).get(
|
||||
"provider_settings", {}
|
||||
)
|
||||
if cfg.get("display_reasoning_text", False):
|
||||
show_reasoning = cfg.get("display_reasoning_text", False)
|
||||
|
||||
# --- Gemini: 过滤/展示 thought:true 片段 ---
|
||||
# Gemini 可能在 parts 中注入 {"thought": true, "text": "..."}
|
||||
# 官方 SDK 默认不会返回此字段。
|
||||
if GenerateContentResponse is not None and isinstance(
|
||||
response.raw_completion, GenerateContentResponse
|
||||
):
|
||||
thought_text, answer_text = self._extract_gemini_texts(
|
||||
response.raw_completion
|
||||
)
|
||||
|
||||
if thought_text or answer_text:
|
||||
# 有明确的思考/正文分离信号,则按配置处理
|
||||
if show_reasoning:
|
||||
merged = (
|
||||
(f"🤔思考:{thought_text}\n\n" if thought_text else "")
|
||||
+ (answer_text or "")
|
||||
).strip()
|
||||
if merged:
|
||||
response.completion_text = merged
|
||||
return
|
||||
else:
|
||||
# 默认隐藏思考内容,仅保留正文
|
||||
if answer_text:
|
||||
response.completion_text = answer_text
|
||||
return
|
||||
|
||||
# --- 非 Gemini 或无明确 thought:true 情况 ---
|
||||
if show_reasoning:
|
||||
# 显示推理内容的处理逻辑
|
||||
if (
|
||||
response
|
||||
@@ -60,3 +99,105 @@ class R1Filter(Star):
|
||||
)
|
||||
|
||||
response.completion_text = completion_text
|
||||
|
||||
# ------------------------
|
||||
# helpers
|
||||
# ------------------------
|
||||
def _get_part_dict(self, p: Any) -> dict:
|
||||
"""优先使用 SDK 标准序列化方法获取字典,失败则逐级回退。
|
||||
|
||||
顺序: model_dump → model_dump_json → json → to_dict → dict → __dict__。
|
||||
"""
|
||||
for getter in ("model_dump", "model_dump_json", "json", "to_dict", "dict"):
|
||||
fn = getattr(p, getter, None)
|
||||
if callable(fn):
|
||||
try:
|
||||
result = fn()
|
||||
if isinstance(result, (str, bytes)):
|
||||
try:
|
||||
if isinstance(result, bytes):
|
||||
result = result.decode("utf-8", "ignore")
|
||||
return json.loads(result) or {}
|
||||
except json.JSONDecodeError:
|
||||
continue
|
||||
if isinstance(result, dict):
|
||||
return result
|
||||
except (AttributeError, TypeError):
|
||||
continue
|
||||
except Exception as e:
|
||||
logging.exception(
|
||||
f"Unexpected error when calling {getter} on {type(p).__name__}: {e}"
|
||||
)
|
||||
continue
|
||||
try:
|
||||
d = getattr(p, "__dict__", None)
|
||||
if isinstance(d, dict):
|
||||
return d
|
||||
except (AttributeError, TypeError):
|
||||
pass
|
||||
except Exception as e:
|
||||
logging.exception(
|
||||
f"Unexpected error when accessing __dict__ on {type(p).__name__}: {e}"
|
||||
)
|
||||
return {}
|
||||
|
||||
def _is_thought_part(self, p: Any) -> bool:
|
||||
"""判断是否为思考片段。
|
||||
|
||||
规则:
|
||||
1) 直接 thought 属性
|
||||
2) 字典字段 thought 或 metadata.thought
|
||||
3) data/raw/extra/_raw 中嵌入的 JSON 串包含 thought: true
|
||||
"""
|
||||
try:
|
||||
if getattr(p, "thought", False):
|
||||
return True
|
||||
except Exception:
|
||||
# best-effort
|
||||
pass
|
||||
|
||||
d = self._get_part_dict(p)
|
||||
if d.get("thought") is True:
|
||||
return True
|
||||
meta = d.get("metadata")
|
||||
if isinstance(meta, dict) and meta.get("thought") is True:
|
||||
return True
|
||||
for k in ("data", "raw", "extra", "_raw"):
|
||||
v = d.get(k)
|
||||
if isinstance(v, (str, bytes)):
|
||||
try:
|
||||
if isinstance(v, bytes):
|
||||
v = v.decode("utf-8", "ignore")
|
||||
parsed = json.loads(v)
|
||||
if isinstance(parsed, dict) and parsed.get("thought") is True:
|
||||
return True
|
||||
except json.JSONDecodeError:
|
||||
continue
|
||||
return False
|
||||
|
||||
def _extract_gemini_texts(self, resp: Any) -> Tuple[str, str]:
|
||||
"""从 GenerateContentResponse 中提取 (思考文本, 正文文本)。"""
|
||||
try:
|
||||
cand0 = next(iter(getattr(resp, "candidates", []) or []), None)
|
||||
if not cand0:
|
||||
return "", ""
|
||||
content = getattr(cand0, "content", None)
|
||||
parts = getattr(content, "parts", None) or []
|
||||
except (AttributeError, TypeError, ValueError):
|
||||
return "", ""
|
||||
|
||||
thought_buf: list[str] = []
|
||||
answer_buf: list[str] = []
|
||||
for p in parts:
|
||||
txt = getattr(p, "text", None)
|
||||
if txt is None:
|
||||
continue
|
||||
txt_str = str(txt).strip()
|
||||
if not txt_str:
|
||||
continue
|
||||
if self._is_thought_part(p):
|
||||
thought_buf.append(txt_str)
|
||||
else:
|
||||
answer_buf.append(txt_str)
|
||||
|
||||
return "\n".join(thought_buf).strip(), "\n".join(answer_buf).strip()
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
import os
|
||||
from googlesearch import search
|
||||
|
||||
from . import SearchEngine, SearchResult
|
||||
|
||||
from typing import List
|
||||
|
||||
|
||||
class Google(SearchEngine):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.proxy = os.environ.get("https_proxy")
|
||||
|
||||
async def search(self, query: str, num_results: int) -> List[SearchResult]:
|
||||
results = []
|
||||
try:
|
||||
ls = search(
|
||||
query,
|
||||
advanced=True,
|
||||
num_results=num_results,
|
||||
timeout=3,
|
||||
proxy=self.proxy,
|
||||
)
|
||||
for i in ls:
|
||||
results.append(
|
||||
SearchResult(title=i.title, url=i.url, snippet=i.description)
|
||||
)
|
||||
except Exception as e:
|
||||
raise e
|
||||
return results
|
||||
@@ -10,7 +10,6 @@ from astrbot.core.provider.func_tool_manager import FunctionToolManager
|
||||
from .engines import SearchResult
|
||||
from .engines.bing import Bing
|
||||
from .engines.sogo import Sogo
|
||||
from .engines.google import Google
|
||||
from readability import Document
|
||||
from bs4 import BeautifulSoup
|
||||
from .engines import HEADERS, USER_AGENTS
|
||||
@@ -46,7 +45,7 @@ class Main(star.Star):
|
||||
|
||||
self.bing_search = Bing()
|
||||
self.sogo_search = Sogo()
|
||||
self.google = Google()
|
||||
self.baidu_initialized = False
|
||||
|
||||
async def _tidy_text(self, text: str) -> str:
|
||||
"""清理文本,去除空格、换行符等"""
|
||||
@@ -90,15 +89,9 @@ class Main(star.Star):
|
||||
) -> list[SearchResult]:
|
||||
results = []
|
||||
try:
|
||||
results = await self.google.search(query, num_results)
|
||||
results = await self.bing_search.search(query, num_results)
|
||||
except Exception as e:
|
||||
logger.error(f"google search error: {e}, try the next one...")
|
||||
if len(results) == 0:
|
||||
logger.debug("search google failed")
|
||||
try:
|
||||
results = await self.bing_search.search(query, num_results)
|
||||
except Exception as e:
|
||||
logger.error(f"bing search error: {e}, try the next one...")
|
||||
logger.error(f"bing search error: {e}, try the next one...")
|
||||
if len(results) == 0:
|
||||
logger.debug("search bing failed")
|
||||
try:
|
||||
@@ -220,6 +213,30 @@ class Main(star.Star):
|
||||
|
||||
return ret
|
||||
|
||||
async def ensure_baidu_ai_search_mcp(self, umo: str | None = None):
|
||||
if self.baidu_initialized:
|
||||
return
|
||||
cfg = self.context.get_config(umo=umo)
|
||||
key = cfg.get("provider_settings", {}).get(
|
||||
"websearch_baidu_app_builder_key", ""
|
||||
)
|
||||
if not key:
|
||||
raise ValueError(
|
||||
"Error: Baidu AI Search API key is not configured in AstrBot."
|
||||
)
|
||||
func_tool_mgr = self.context.get_llm_tool_manager()
|
||||
await func_tool_mgr.enable_mcp_server(
|
||||
"baidu_ai_search",
|
||||
config={
|
||||
"transport": "sse",
|
||||
"url": f"http://appbuilder.baidu.com/v2/ai_search/mcp/sse?api_key={key}",
|
||||
"headers": {},
|
||||
"timeout": 30,
|
||||
},
|
||||
)
|
||||
self.baidu_initialized = True
|
||||
logger.info("Successfully initialized Baidu AI Search MCP server.")
|
||||
|
||||
@llm_tool(name="fetch_url")
|
||||
async def fetch_website_content(self, event: AstrMessageEvent, url: str) -> str:
|
||||
"""fetch the content of a website with the given web url
|
||||
@@ -366,6 +383,7 @@ class Main(star.Star):
|
||||
tool_set.add_tool(fetch_url_t)
|
||||
tool_set.remove_tool("web_search_tavily")
|
||||
tool_set.remove_tool("tavily_extract_web_page")
|
||||
tool_set.remove_tool("AIsearch")
|
||||
elif provider == "tavily":
|
||||
web_search_tavily = func_tool_mgr.get_func("web_search_tavily")
|
||||
tavily_extract_web_page = func_tool_mgr.get_func("tavily_extract_web_page")
|
||||
@@ -375,3 +393,17 @@ class Main(star.Star):
|
||||
tool_set.add_tool(tavily_extract_web_page)
|
||||
tool_set.remove_tool("web_search")
|
||||
tool_set.remove_tool("fetch_url")
|
||||
tool_set.remove_tool("AIsearch")
|
||||
elif provider == "baidu_ai_search":
|
||||
try:
|
||||
await self.ensure_baidu_ai_search_mcp(event.unified_msg_origin)
|
||||
aisearch_tool = func_tool_mgr.get_func("AIsearch")
|
||||
if not aisearch_tool:
|
||||
raise ValueError("Cannot get Baidu AI Search MCP tool.")
|
||||
tool_set.add_tool(aisearch_tool)
|
||||
tool_set.remove_tool("web_search")
|
||||
tool_set.remove_tool("fetch_url")
|
||||
tool_set.remove_tool("web_search_tavily")
|
||||
tool_set.remove_tool("tavily_extract_web_page")
|
||||
except Exception as e:
|
||||
logger.error(f"Cannot Initialize Baidu AI Search MCP Server: {e}")
|
||||
|
||||
Reference in New Issue
Block a user