feat:修复门控多重result问题,新增at动作,插件现在运行chat_id指定或chat_type指定
This commit is contained in:
@@ -1,12 +1,16 @@
|
||||
"""Maisaka 内置工具聚合入口。"""
|
||||
|
||||
from collections.abc import Awaitable, Callable
|
||||
from typing import Dict, List, Optional
|
||||
from copy import deepcopy
|
||||
from dataclasses import dataclass
|
||||
from typing import Dict, List, Literal, Optional
|
||||
|
||||
from src.config.config import global_config
|
||||
from src.core.tooling import ToolExecutionContext, ToolExecutionResult, ToolInvocation, ToolSpec
|
||||
from src.core.tooling import ToolAvailabilityContext, ToolExecutionContext, ToolExecutionResult, ToolInvocation, ToolSpec
|
||||
from src.llm_models.payload_content.tool_option import ToolDefinitionInput
|
||||
|
||||
from .at import get_tool_spec as get_at_tool_spec
|
||||
from .at import handle_tool as handle_at_tool
|
||||
from .context import BuiltinToolRuntimeContext
|
||||
from .continue_tool import get_tool_spec as get_continue_tool_spec
|
||||
from .continue_tool import handle_tool as handle_continue_tool
|
||||
@@ -32,93 +36,152 @@ from .wait import get_tool_spec as get_wait_tool_spec
|
||||
from .wait import handle_tool as handle_wait_tool
|
||||
|
||||
BuiltinToolHandler = Callable[[ToolInvocation, Optional[ToolExecutionContext]], Awaitable[ToolExecutionResult]]
|
||||
BuiltinToolRawHandler = Callable[
|
||||
[BuiltinToolRuntimeContext, ToolInvocation, Optional[ToolExecutionContext]],
|
||||
Awaitable[ToolExecutionResult],
|
||||
]
|
||||
BuiltinToolStage = Literal["timing", "action"]
|
||||
BuiltinToolVisibility = Literal["visible", "deferred", "hidden"]
|
||||
BuiltinToolChatScope = Literal["all", "group", "private"]
|
||||
|
||||
|
||||
def get_timing_tool_specs() -> List[ToolSpec]:
|
||||
"""获取 Timing Gate 阶段可用的内置工具声明。"""
|
||||
@dataclass(frozen=True)
|
||||
class BuiltinToolEntry:
|
||||
"""内置工具目录项,集中声明工具所属阶段与默认可见性。"""
|
||||
|
||||
return [
|
||||
get_wait_tool_spec(),
|
||||
get_no_reply_tool_spec(),
|
||||
get_continue_tool_spec(),
|
||||
]
|
||||
name: str
|
||||
get_spec: Callable[[], ToolSpec]
|
||||
handle_tool: BuiltinToolRawHandler
|
||||
stage: BuiltinToolStage
|
||||
visibility: BuiltinToolVisibility = "visible"
|
||||
chat_scope: BuiltinToolChatScope = "all"
|
||||
|
||||
def build_spec(self) -> ToolSpec:
|
||||
"""生成带统一可见性元数据的工具声明。"""
|
||||
|
||||
tool_spec = deepcopy(self.get_spec())
|
||||
tool_spec.metadata["builtin_stage"] = self.stage
|
||||
tool_spec.metadata["visibility"] = self.visibility
|
||||
return tool_spec
|
||||
|
||||
|
||||
def get_action_tool_specs() -> List[ToolSpec]:
|
||||
"""获取 Action Loop 阶段可用的内置工具声明。"""
|
||||
def _get_query_memory_tool_spec() -> ToolSpec:
|
||||
"""根据配置生成 query_memory 工具声明。"""
|
||||
|
||||
return [
|
||||
get_finish_tool_spec(),
|
||||
get_reply_tool_spec(),
|
||||
get_view_complex_message_tool_spec(),
|
||||
get_query_jargon_tool_spec(),
|
||||
get_query_memory_tool_spec(enabled=bool(global_config.memory.enable_memory_query_tool)),
|
||||
get_send_emoji_tool_spec(),
|
||||
get_tool_search_tool_spec(),
|
||||
]
|
||||
return get_query_memory_tool_spec(enabled=bool(global_config.memory.enable_memory_query_tool))
|
||||
|
||||
|
||||
def get_builtin_tool_specs() -> List[ToolSpec]:
|
||||
"""获取默认暴露的 Maisaka 内置工具声明。"""
|
||||
|
||||
return get_action_tool_specs()
|
||||
BUILTIN_TOOL_ENTRIES: List[BuiltinToolEntry] = [
|
||||
BuiltinToolEntry("wait", get_wait_tool_spec, handle_wait_tool, stage="timing"),
|
||||
BuiltinToolEntry("no_reply", get_no_reply_tool_spec, handle_no_reply_tool, stage="timing"),
|
||||
BuiltinToolEntry("continue", get_continue_tool_spec, handle_continue_tool, stage="timing"),
|
||||
BuiltinToolEntry("finish", get_finish_tool_spec, handle_finish_tool, stage="action"),
|
||||
BuiltinToolEntry("reply", get_reply_tool_spec, handle_reply_tool, stage="action"),
|
||||
BuiltinToolEntry(
|
||||
"view_complex_message",
|
||||
get_view_complex_message_tool_spec,
|
||||
handle_view_complex_message_tool,
|
||||
stage="action",
|
||||
),
|
||||
BuiltinToolEntry("query_jargon", get_query_jargon_tool_spec, handle_query_jargon_tool, stage="action"),
|
||||
BuiltinToolEntry("query_memory", _get_query_memory_tool_spec, handle_query_memory_tool, stage="action"),
|
||||
BuiltinToolEntry(
|
||||
"query_person_info",
|
||||
get_query_person_info_tool_spec,
|
||||
handle_query_person_info_tool,
|
||||
stage="action",
|
||||
visibility="hidden",
|
||||
),
|
||||
BuiltinToolEntry("send_emoji", get_send_emoji_tool_spec, handle_send_emoji_tool, stage="action"),
|
||||
BuiltinToolEntry(
|
||||
"at",
|
||||
get_at_tool_spec,
|
||||
handle_at_tool,
|
||||
stage="action",
|
||||
visibility="deferred",
|
||||
chat_scope="group",
|
||||
),
|
||||
BuiltinToolEntry("tool_search", get_tool_search_tool_spec, handle_tool_search_tool, stage="action"),
|
||||
]
|
||||
|
||||
|
||||
def get_all_builtin_tool_specs() -> List[ToolSpec]:
|
||||
def _get_builtin_tool_entries(
|
||||
*,
|
||||
stage: Optional[BuiltinToolStage] = None,
|
||||
visibility: Optional[BuiltinToolVisibility] = None,
|
||||
context: Optional[ToolAvailabilityContext] = None,
|
||||
) -> List[BuiltinToolEntry]:
|
||||
"""按阶段与可见性筛选内置工具目录项。"""
|
||||
|
||||
entries = BUILTIN_TOOL_ENTRIES
|
||||
if stage is not None:
|
||||
entries = [entry for entry in entries if entry.stage == stage]
|
||||
if visibility is not None:
|
||||
entries = [entry for entry in entries if entry.visibility == visibility]
|
||||
if context is not None:
|
||||
entries = [entry for entry in entries if _is_builtin_tool_available(entry, context)]
|
||||
return entries
|
||||
|
||||
|
||||
def _is_builtin_tool_available(entry: BuiltinToolEntry, context: ToolAvailabilityContext) -> bool:
|
||||
"""判断内置工具是否适用于当前聊天。"""
|
||||
|
||||
if entry.chat_scope == "all":
|
||||
return True
|
||||
if entry.chat_scope == "group":
|
||||
return context.is_group_chat is True
|
||||
if entry.chat_scope == "private":
|
||||
return context.is_group_chat is False
|
||||
return True
|
||||
|
||||
|
||||
def get_builtin_tool_visibility(tool_spec: ToolSpec) -> BuiltinToolVisibility:
|
||||
"""读取工具声明里的可见性。"""
|
||||
|
||||
raw_visibility = str(tool_spec.metadata.get("visibility") or "").strip()
|
||||
if raw_visibility == "deferred":
|
||||
return "deferred"
|
||||
if raw_visibility == "hidden":
|
||||
return "hidden"
|
||||
return "visible"
|
||||
|
||||
|
||||
def is_builtin_tool_in_action_stage(tool_spec: ToolSpec) -> bool:
|
||||
"""判断内置工具是否属于 Action Loop 阶段。"""
|
||||
|
||||
return str(tool_spec.metadata.get("builtin_stage") or "").strip() == "action"
|
||||
|
||||
|
||||
def get_all_builtin_tool_specs(context: Optional[ToolAvailabilityContext] = None) -> List[ToolSpec]:
|
||||
"""获取全部内置工具声明。"""
|
||||
|
||||
return [
|
||||
*get_timing_tool_specs(),
|
||||
get_finish_tool_spec(),
|
||||
get_reply_tool_spec(),
|
||||
get_view_complex_message_tool_spec(),
|
||||
get_query_jargon_tool_spec(),
|
||||
get_query_memory_tool_spec(enabled=True),
|
||||
get_query_person_info_tool_spec(),
|
||||
get_send_emoji_tool_spec(),
|
||||
get_tool_search_tool_spec(),
|
||||
]
|
||||
return [entry.build_spec() for entry in _get_builtin_tool_entries(context=context)]
|
||||
|
||||
|
||||
def get_timing_tools() -> List[ToolDefinitionInput]:
|
||||
"""获取 Timing Gate 阶段的兼容工具定义。"""
|
||||
|
||||
return [tool_spec.to_llm_definition() for tool_spec in get_timing_tool_specs()]
|
||||
|
||||
|
||||
def get_action_tools() -> List[ToolDefinitionInput]:
|
||||
"""获取 Action Loop 阶段的兼容工具定义。"""
|
||||
|
||||
return [tool_spec.to_llm_definition() for tool_spec in get_action_tool_specs()]
|
||||
tool_specs = [
|
||||
entry.build_spec()
|
||||
for entry in _get_builtin_tool_entries(stage="timing", visibility="visible")
|
||||
]
|
||||
return [tool_spec.to_llm_definition() for tool_spec in tool_specs if tool_spec.enabled]
|
||||
|
||||
|
||||
def get_builtin_tools() -> List[ToolDefinitionInput]:
|
||||
"""获取默认暴露给模型层的内置工具定义。"""
|
||||
|
||||
return get_action_tools()
|
||||
tool_specs = [
|
||||
entry.build_spec()
|
||||
for entry in _get_builtin_tool_entries(stage="action", visibility="visible")
|
||||
]
|
||||
return [tool_spec.to_llm_definition() for tool_spec in tool_specs if tool_spec.enabled]
|
||||
|
||||
|
||||
def build_builtin_tool_handlers(tool_ctx: BuiltinToolRuntimeContext) -> Dict[str, BuiltinToolHandler]:
|
||||
"""构建内置工具处理器映射。"""
|
||||
|
||||
return {
|
||||
"continue": lambda invocation, context=None: handle_continue_tool(tool_ctx, invocation, context),
|
||||
"finish": lambda invocation, context=None: handle_finish_tool(tool_ctx, invocation, context),
|
||||
"reply": lambda invocation, context=None: handle_reply_tool(tool_ctx, invocation, context),
|
||||
"no_reply": lambda invocation, context=None: handle_no_reply_tool(tool_ctx, invocation, context),
|
||||
"query_jargon": lambda invocation, context=None: handle_query_jargon_tool(tool_ctx, invocation, context),
|
||||
"query_memory": lambda invocation, context=None: handle_query_memory_tool(tool_ctx, invocation, context),
|
||||
"query_person_info": lambda invocation, context=None: handle_query_person_info_tool(
|
||||
tool_ctx,
|
||||
invocation,
|
||||
context,
|
||||
),
|
||||
"wait": lambda invocation, context=None: handle_wait_tool(tool_ctx, invocation, context),
|
||||
"send_emoji": lambda invocation, context=None: handle_send_emoji_tool(tool_ctx, invocation, context),
|
||||
"tool_search": lambda invocation, context=None: handle_tool_search_tool(tool_ctx, invocation, context),
|
||||
"view_complex_message": lambda invocation, context=None: handle_view_complex_message_tool(
|
||||
tool_ctx,
|
||||
invocation,
|
||||
context,
|
||||
),
|
||||
entry.name: lambda invocation, context=None, entry=entry: entry.handle_tool(tool_ctx, invocation, context)
|
||||
for entry in BUILTIN_TOOL_ENTRIES
|
||||
}
|
||||
|
||||
186
src/maisaka/builtin_tool/at.py
Normal file
186
src/maisaka/builtin_tool/at.py
Normal file
@@ -0,0 +1,186 @@
|
||||
"""Maisaka 内置 at 工具。"""
|
||||
|
||||
from typing import Any, Optional, TYPE_CHECKING
|
||||
|
||||
from src.cli.maisaka_cli_sender import CLI_PLATFORM_NAME, render_cli_message
|
||||
from src.common.data_models.message_component_data_model import AtComponent, MessageSequence, TextComponent
|
||||
from src.common.logger import get_logger
|
||||
from src.core.tooling import ToolExecutionContext, ToolExecutionResult, ToolInvocation, ToolSpec
|
||||
from src.services import send_service
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .context import BuiltinToolRuntimeContext
|
||||
|
||||
logger = get_logger("maisaka_builtin_at")
|
||||
|
||||
|
||||
def get_tool_spec() -> ToolSpec:
|
||||
"""获取 at 工具声明。"""
|
||||
|
||||
return ToolSpec(
|
||||
name="at",
|
||||
brief_description="根据一条已知 msg_id 找到发言用户,并发送一条 @ 该用户的消息。",
|
||||
detailed_description=(
|
||||
"参数说明:\n"
|
||||
"- msg_id:string,必填。要 @ 的目标用户发过的消息编号。\n"
|
||||
"- text:string,可选。@ 后追加发送的短文本;只想单独 @ 人时留空。\n"
|
||||
"请优先从上下文里选择一条明确属于目标用户的 msg_id,不要凭昵称或印象猜测用户。"
|
||||
),
|
||||
parameters_schema={
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"msg_id": {
|
||||
"type": "string",
|
||||
"description": "要 @ 的目标用户发过的消息编号。",
|
||||
},
|
||||
"text": {
|
||||
"type": "string",
|
||||
"description": "@ 后追加发送的短文本;只想单独 @ 人时留空。",
|
||||
"default": "",
|
||||
},
|
||||
},
|
||||
"required": ["msg_id"],
|
||||
},
|
||||
provider_name="maisaka_builtin",
|
||||
provider_type="builtin",
|
||||
)
|
||||
|
||||
|
||||
def _get_target_user_info(target_message: Any) -> tuple[str, str, str]:
|
||||
"""从目标消息中提取可用于构造 at 组件的用户信息。"""
|
||||
|
||||
message_info = getattr(target_message, "message_info", None)
|
||||
user_info = getattr(message_info, "user_info", None)
|
||||
target_user_id = str(getattr(user_info, "user_id", "") or "").strip()
|
||||
target_user_nickname = str(getattr(user_info, "user_nickname", "") or "").strip()
|
||||
target_user_cardname = str(getattr(user_info, "user_cardname", "") or "").strip()
|
||||
return target_user_id, target_user_nickname, target_user_cardname
|
||||
|
||||
|
||||
def _build_at_message_sequence(
|
||||
*,
|
||||
target_user_id: str,
|
||||
target_user_nickname: str = "",
|
||||
target_user_cardname: str = "",
|
||||
text: str = "",
|
||||
) -> MessageSequence:
|
||||
"""构造 @ 用户的消息组件序列。"""
|
||||
|
||||
components = [
|
||||
AtComponent(
|
||||
target_user_id=target_user_id,
|
||||
target_user_nickname=target_user_nickname or None,
|
||||
target_user_cardname=target_user_cardname or None,
|
||||
)
|
||||
]
|
||||
normalized_text = text.strip()
|
||||
if normalized_text:
|
||||
components.append(TextComponent(f" {normalized_text}"))
|
||||
return MessageSequence(components=components)
|
||||
|
||||
|
||||
async def handle_tool(
|
||||
tool_ctx: "BuiltinToolRuntimeContext",
|
||||
invocation: ToolInvocation,
|
||||
context: Optional[ToolExecutionContext] = None,
|
||||
) -> ToolExecutionResult:
|
||||
"""执行 at 内置工具。"""
|
||||
|
||||
del context
|
||||
target_message_id = str(invocation.arguments.get("msg_id") or "").strip()
|
||||
text = str(invocation.arguments.get("text") or "").strip()
|
||||
|
||||
if not target_message_id:
|
||||
return tool_ctx.build_failure_result(
|
||||
invocation.tool_name,
|
||||
"at 工具需要提供有效的 `msg_id` 参数。",
|
||||
)
|
||||
|
||||
if not str(getattr(tool_ctx.runtime.chat_stream, "group_id", "") or "").strip():
|
||||
return tool_ctx.build_failure_result(
|
||||
invocation.tool_name,
|
||||
"at 工具只能在群聊中使用。",
|
||||
structured_content={"msg_id": target_message_id},
|
||||
)
|
||||
|
||||
target_message = tool_ctx.runtime._source_messages_by_id.get(target_message_id)
|
||||
if target_message is None:
|
||||
return tool_ctx.build_failure_result(
|
||||
invocation.tool_name,
|
||||
f"未找到要 @ 的目标消息,msg_id={target_message_id}",
|
||||
structured_content={"msg_id": target_message_id},
|
||||
)
|
||||
|
||||
target_user_id, target_user_nickname, target_user_cardname = _get_target_user_info(target_message)
|
||||
if not target_user_id:
|
||||
return tool_ctx.build_failure_result(
|
||||
invocation.tool_name,
|
||||
f"目标消息缺少有效用户 ID,msg_id={target_message_id}",
|
||||
structured_content={"msg_id": target_message_id},
|
||||
)
|
||||
|
||||
target_user_name = target_user_cardname or target_user_nickname or target_user_id
|
||||
message_sequence = _build_at_message_sequence(
|
||||
target_user_id=target_user_id,
|
||||
target_user_nickname=target_user_nickname,
|
||||
target_user_cardname=target_user_cardname,
|
||||
text=text,
|
||||
)
|
||||
display_message = f"@{target_user_name}" + (f" {text}" if text else "")
|
||||
|
||||
try:
|
||||
if tool_ctx.runtime.chat_stream.platform == CLI_PLATFORM_NAME:
|
||||
render_cli_message(display_message)
|
||||
tool_ctx.append_guided_reply_to_chat_history(display_message)
|
||||
sent_message = None
|
||||
sent = True
|
||||
else:
|
||||
sent_message = await send_service._send_to_target_with_message(
|
||||
message_sequence=message_sequence,
|
||||
stream_id=tool_ctx.runtime.session_id,
|
||||
display_message=display_message,
|
||||
typing=False,
|
||||
storage_message=True,
|
||||
show_log=True,
|
||||
sync_to_maisaka_history=True,
|
||||
maisaka_source_kind="guided_reply",
|
||||
)
|
||||
sent = sent_message is not None
|
||||
except Exception as exc:
|
||||
logger.exception(
|
||||
f"{tool_ctx.runtime.log_prefix} 发送 at 消息时发生异常: msg_id={target_message_id} user_id={target_user_id}"
|
||||
)
|
||||
return tool_ctx.build_failure_result(
|
||||
invocation.tool_name,
|
||||
f"发送 at 消息时发生异常:{exc}",
|
||||
structured_content={
|
||||
"msg_id": target_message_id,
|
||||
"target_user_id": target_user_id,
|
||||
"target_user_name": target_user_name,
|
||||
},
|
||||
)
|
||||
|
||||
if not sent:
|
||||
return tool_ctx.build_failure_result(
|
||||
invocation.tool_name,
|
||||
"at 消息发送失败。",
|
||||
structured_content={
|
||||
"msg_id": target_message_id,
|
||||
"target_user_id": target_user_id,
|
||||
"target_user_name": target_user_name,
|
||||
},
|
||||
)
|
||||
|
||||
sent_message_id = str(getattr(sent_message, "message_id", "") or "").strip() if sent_message is not None else ""
|
||||
tool_ctx.runtime._record_reply_sent()
|
||||
return tool_ctx.build_success_result(
|
||||
invocation.tool_name,
|
||||
f"已 @ {target_user_name}。",
|
||||
structured_content={
|
||||
"msg_id": target_message_id,
|
||||
"target_user_id": target_user_id,
|
||||
"target_user_name": target_user_name,
|
||||
"text": text,
|
||||
"sent_message_id": sent_message_id,
|
||||
},
|
||||
)
|
||||
@@ -12,7 +12,7 @@ from src.common.logger import get_logger
|
||||
from src.common.prompt_i18n import load_prompt
|
||||
from src.common.utils.utils_session import SessionUtils
|
||||
from src.config.config import global_config
|
||||
from src.core.tooling import ToolRegistry
|
||||
from src.core.tooling import ToolAvailabilityContext, ToolRegistry
|
||||
from src.llm_models.model_client.base_client import BaseClient
|
||||
from src.llm_models.payload_content.message import Message, MessageBuilder, RoleType
|
||||
from src.llm_models.payload_content.resp_format import RespFormat
|
||||
@@ -502,7 +502,13 @@ class MaisakaChatLoopService:
|
||||
if tool_definitions is not None:
|
||||
all_tools = list(tool_definitions)
|
||||
elif self._tool_registry is not None:
|
||||
tool_specs = await self._tool_registry.list_tools()
|
||||
tool_specs = await self._tool_registry.list_tools(
|
||||
ToolAvailabilityContext(
|
||||
session_id=self._session_id,
|
||||
stream_id=self._session_id,
|
||||
is_group_chat=self._is_group_chat,
|
||||
)
|
||||
)
|
||||
all_tools = [tool_spec.to_llm_definition() for tool_spec in tool_specs]
|
||||
else:
|
||||
all_tools = [*get_builtin_tools(), *self._extra_tools]
|
||||
|
||||
@@ -14,14 +14,14 @@ from src.chat.message_receive.message import SessionMessage
|
||||
from src.common.data_models.message_component_data_model import EmojiComponent, ImageComponent, MessageSequence
|
||||
from src.common.logger import get_logger
|
||||
from src.common.prompt_i18n import load_prompt
|
||||
from src.core.tooling import ToolExecutionContext, ToolExecutionResult, ToolInvocation, ToolSpec
|
||||
from src.core.tooling import ToolAvailabilityContext, ToolExecutionContext, ToolExecutionResult, ToolInvocation, ToolSpec
|
||||
from src.llm_models.exceptions import ReqAbortException
|
||||
from src.llm_models.payload_content.tool_option import ToolCall
|
||||
from src.services import database_service as database_api
|
||||
from src.services.memory_service import memory_service
|
||||
|
||||
from .builtin_tool import get_action_tool_specs
|
||||
from .builtin_tool import build_builtin_tool_handlers as build_split_builtin_tool_handlers
|
||||
from .builtin_tool import get_builtin_tool_visibility, is_builtin_tool_in_action_stage
|
||||
from .builtin_tool import get_timing_tools
|
||||
from .chat_loop_service import ChatResponse
|
||||
from .chat_history_visual_refresher import refresh_chat_history_visual_placeholders
|
||||
@@ -54,8 +54,6 @@ logger = get_logger("maisaka_reasoning_engine")
|
||||
TIMING_GATE_CONTEXT_LIMIT = 24
|
||||
TIMING_GATE_MAX_TOKENS = 384
|
||||
TIMING_GATE_TOOL_NAMES = {"continue", "no_reply", "wait"}
|
||||
ACTION_HIDDEN_TOOL_NAMES = {"continue", "no_reply"}
|
||||
ACTION_BUILTIN_TOOL_NAMES = {tool_spec.name for tool_spec in get_action_tool_specs()}
|
||||
|
||||
|
||||
class MaisakaReasoningEngine:
|
||||
@@ -175,15 +173,19 @@ class MaisakaReasoningEngine:
|
||||
self._runtime.set_current_action_tool_names([])
|
||||
return [], ""
|
||||
|
||||
tool_specs = await self._runtime._tool_registry.list_tools()
|
||||
availability_context = self._build_tool_availability_context()
|
||||
tool_specs = await self._runtime._tool_registry.list_tools(availability_context)
|
||||
visible_builtin_tool_specs: list[ToolSpec] = []
|
||||
deferred_tool_specs: list[ToolSpec] = []
|
||||
for tool_spec in tool_specs:
|
||||
if tool_spec.name in ACTION_HIDDEN_TOOL_NAMES:
|
||||
continue
|
||||
if tool_spec.provider_name == "maisaka_builtin":
|
||||
if tool_spec.name in ACTION_BUILTIN_TOOL_NAMES:
|
||||
if not is_builtin_tool_in_action_stage(tool_spec):
|
||||
continue
|
||||
visibility = get_builtin_tool_visibility(tool_spec)
|
||||
if visibility == "visible":
|
||||
visible_builtin_tool_specs.append(tool_spec)
|
||||
elif visibility == "deferred":
|
||||
deferred_tool_specs.append(tool_spec)
|
||||
continue
|
||||
deferred_tool_specs.append(tool_spec)
|
||||
|
||||
@@ -877,6 +879,19 @@ class MaisakaReasoningEngine:
|
||||
reasoning=latest_thought,
|
||||
)
|
||||
|
||||
def _build_tool_availability_context(self) -> ToolAvailabilityContext:
|
||||
"""构造当前聊天的工具暴露上下文。"""
|
||||
|
||||
chat_stream = self._runtime.chat_stream
|
||||
return ToolAvailabilityContext(
|
||||
session_id=self._runtime.session_id,
|
||||
stream_id=self._runtime.session_id,
|
||||
is_group_chat=chat_stream.is_group_session,
|
||||
group_id=str(getattr(chat_stream, "group_id", "") or "").strip(),
|
||||
user_id=str(getattr(chat_stream, "user_id", "") or "").strip(),
|
||||
platform=str(getattr(chat_stream, "platform", "") or "").strip(),
|
||||
)
|
||||
|
||||
def _build_tool_execution_context(
|
||||
self,
|
||||
latest_thought: str,
|
||||
@@ -1197,6 +1212,8 @@ class MaisakaReasoningEngine:
|
||||
source_kind="timing_gate",
|
||||
)
|
||||
)
|
||||
if tool_call.func_name == "wait":
|
||||
return
|
||||
self._append_tool_execution_result(tool_call, result)
|
||||
|
||||
def _build_tool_result_summary(self, tool_call: ToolCall, result: ToolExecutionResult) -> str:
|
||||
@@ -1290,9 +1307,10 @@ class MaisakaReasoningEngine:
|
||||
return False, tool_result_summaries, tool_monitor_results
|
||||
|
||||
execution_context = self._build_tool_execution_context(latest_thought, anchor_message)
|
||||
availability_context = self._build_tool_availability_context()
|
||||
tool_spec_map = {
|
||||
tool_spec.name: tool_spec
|
||||
for tool_spec in await self._runtime._tool_registry.list_tools()
|
||||
for tool_spec in await self._runtime._tool_registry.list_tools(availability_context)
|
||||
}
|
||||
total_tool_count = len(tool_calls)
|
||||
for tool_index, tool_call in enumerate(tool_calls, start=1):
|
||||
|
||||
@@ -5,7 +5,14 @@ from __future__ import annotations
|
||||
from collections.abc import Awaitable, Callable
|
||||
from typing import Dict, Optional
|
||||
|
||||
from src.core.tooling import ToolExecutionContext, ToolExecutionResult, ToolInvocation, ToolProvider, ToolSpec
|
||||
from src.core.tooling import (
|
||||
ToolAvailabilityContext,
|
||||
ToolExecutionContext,
|
||||
ToolExecutionResult,
|
||||
ToolInvocation,
|
||||
ToolProvider,
|
||||
ToolSpec,
|
||||
)
|
||||
|
||||
from .builtin_tool import get_all_builtin_tool_specs
|
||||
|
||||
@@ -27,10 +34,13 @@ class MaisakaBuiltinToolProvider(ToolProvider):
|
||||
|
||||
self._handlers = dict(handlers or {})
|
||||
|
||||
async def list_tools(self) -> list[ToolSpec]:
|
||||
async def list_tools(
|
||||
self,
|
||||
context: Optional[ToolAvailabilityContext] = None,
|
||||
) -> list[ToolSpec]:
|
||||
"""列出全部内置工具。"""
|
||||
|
||||
return list(get_all_builtin_tool_specs())
|
||||
return list(get_all_builtin_tool_specs(context))
|
||||
|
||||
async def invoke(
|
||||
self,
|
||||
|
||||
Reference in New Issue
Block a user