feat:合并no_reply和wait

This commit is contained in:
SengokuCola
2026-05-07 16:48:44 +08:00
parent f41051f836
commit 2b327a31d3
14 changed files with 82 additions and 88 deletions

View File

@@ -435,7 +435,7 @@ class ChatConfig(ConfigBase):
"advanced": True,
},
)
"""Timing Gate 返回 wait/no_reply 时的最小窗口秒数0 表示不启用冷却"""
"""Timing Gate 返回 no_reply 时的最小窗口秒数0 表示不启用冷却"""
group_chat_prompt: str = Field(
default=(

View File

@@ -30,8 +30,6 @@ from .tool_search import get_tool_spec as get_tool_search_tool_spec
from .tool_search import handle_tool as handle_tool_search_tool
from .view_complex_message import get_tool_spec as get_view_complex_message_tool_spec
from .view_complex_message import handle_tool as handle_view_complex_message_tool
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[
@@ -70,7 +68,6 @@ def _get_query_memory_tool_spec() -> ToolSpec:
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"),

View File

@@ -12,7 +12,7 @@ def get_tool_spec() -> ToolSpec:
return ToolSpec(
name="no_reply",
brief_description="本轮不进行回复,等待其他用户的新消息。",
brief_description="本轮不进行回复,等待其他用户的新消息;也用于用户可能还没说完、需要先把发言权交还给用户的场景",
provider_name="maisaka_builtin",
provider_type="builtin",
)

View File

@@ -1,51 +0,0 @@
"""wait 内置工具。"""
from typing import Optional
from src.core.tooling import ToolExecutionContext, ToolExecutionResult, ToolInvocation, ToolSpec
from .context import BuiltinToolRuntimeContext
def get_tool_spec() -> ToolSpec:
"""获取 wait 工具声明。"""
return ToolSpec(
name="wait",
brief_description="暂停当前对话并固定等待一段时间,期间不因新消息提前恢复。",
detailed_description="参数说明:\n- secondsinteger必填。等待的秒数。等待期间收到的新消息只会暂存直到超时后再继续处理。",
parameters_schema={
"type": "object",
"properties": {
"seconds": {
"type": "integer",
"description": "等待的秒数。",
},
},
"required": ["seconds"],
},
provider_name="maisaka_builtin",
provider_type="builtin",
)
async def handle_tool(
tool_ctx: BuiltinToolRuntimeContext,
invocation: ToolInvocation,
context: Optional[ToolExecutionContext] = None,
) -> ToolExecutionResult:
"""执行 wait 内置工具。"""
del context
seconds = invocation.arguments.get("seconds", 30)
try:
wait_seconds = int(seconds)
except (TypeError, ValueError):
wait_seconds = 30
wait_seconds = max(0, wait_seconds)
tool_ctx.runtime._enter_wait_state(seconds=wait_seconds, tool_call_id=invocation.call_id)
return tool_ctx.build_success_result(
invocation.tool_name,
f"当前对话循环进入等待状态,将固定等待 {wait_seconds} 秒;期间收到的新消息不会提前打断本次等待。",
metadata={"pause_execution": True},
)

View File

@@ -40,7 +40,7 @@ from .history_utils import drop_orphan_tool_results, normalize_tool_result_order
from .display.prompt_cli_renderer import PromptCLIVisualizer
from .visual_mode_utils import resolve_enable_visual_planner
TIMING_GATE_TOOL_NAMES = {"continue", "no_reply", "wait"}
TIMING_GATE_TOOL_NAMES = {"continue", "no_reply"}
REQUEST_TYPE_BY_REQUEST_KIND = {
"planner": "maisaka_planner",
"timing_gate": "maisaka_timing_gate",

View File

@@ -54,7 +54,7 @@ logger = get_logger("maisaka_reasoning_engine")
TIMING_GATE_CONTEXT_DROP_HEAD_RATIO = 0.7
TIMING_GATE_MAX_ATTEMPTS = 3
TIMING_GATE_TOOL_NAMES = {"continue", "no_reply", "wait"}
TIMING_GATE_TOOL_NAMES = {"continue", "no_reply"}
HISTORY_SILENT_TOOL_NAMES = {"finish"}
@@ -149,10 +149,9 @@ class MaisakaReasoningEngine:
return (
"你是 Maisaka 的 timing gate 子代理,只负责决定当前会话下一步的节奏控制。\n"
"你必须且只能调用一个工具,不要输出普通文本答案。\n"
"可用工具只有个:\n"
"1. wait: 适合暂时等待一段时间,再重新判断是否继续\n"
"2. no_reply: 适合当前不继续本轮,直接等待新的外部消息\n"
"3. continue: 适合现在立刻进入下一轮正常思考、回复、查询和其他工具执行。\n"
"可用工具只有个:\n"
"1. no_reply: 适合当前不继续本轮发言,等待新的外部消息或让用户继续说完\n"
"2. continue: 适合现在立刻进入下一轮正常思考、回复、查询和其他工具执行\n"
"如果需要真正回复消息、查询信息或使用其他工具,应该调用 continue让主分支继续执行而不是在这里完成。\n"
"不要连续调用多个工具,也不要输出工具之外的计划。"
)
@@ -242,7 +241,7 @@ class MaisakaReasoningEngine:
async def _run_timing_gate(
self,
anchor_message: SessionMessage,
) -> tuple[Literal["continue", "no_reply", "wait"], Any, list[str], list[dict[str, Any]]]:
) -> tuple[Literal["continue", "no_reply"], Any, list[str], list[dict[str, Any]]]:
"""运行 Timing Gate 子代理并返回控制决策。"""
if self._runtime._force_next_timing_continue:
@@ -388,7 +387,7 @@ class MaisakaReasoningEngine:
hint_content = (
"Timing Gate 上一轮选择了非法工具:"
f"{normalized_tool_text}\n"
"Timing Gate 只能调用 continue、wait 或 no_reply 中的一个工具。"
"Timing Gate 只能调用 continue 或 no_reply 中的一个工具。"
)
self._runtime._chat_history.append(
SessionBackedMessage(

View File

@@ -572,7 +572,7 @@ class MaisakaHeartFlowChatting:
return self._force_next_timing_continue
async def _wait_for_timing_gate_non_continue_cooldown(self, elapsed_seconds: float) -> None:
"""仅对 Timing Gate 的 wait/no_reply 动作应用冷却窗口。"""
"""仅对 Timing Gate 的 no_reply 动作应用冷却窗口。"""
cooldown_seconds = self._timing_gate_non_continue_cooldown_seconds
if cooldown_seconds <= 0:

View File

@@ -44,7 +44,6 @@ BUILTIN_TOOL_NAMES = frozenset(
{
"reply",
"no_reply",
"wait",
"stop",
"create_table",
"list_tables",