feat:修复私聊回复问题,修复wait动作,补上回复后处理

This commit is contained in:
SengokuCola
2026-03-29 19:57:34 +08:00
parent 96844a9bf5
commit b5408b4550
4 changed files with 241 additions and 107 deletions

View File

@@ -14,7 +14,7 @@ from sqlmodel import select
from src.chat.heart_flow.heartFC_utils import CycleDetail
from src.chat.message_receive.message import SessionMessage
from src.chat.replyer.replyer_manager import replyer_manager
from src.chat.utils.utils import get_bot_account
from src.chat.utils.utils import get_bot_account, process_llm_response
from src.common.database.database import get_db_session
from src.common.database.database_model import Jargon
from src.common.data_models.mai_message_data_model import UserInfo
@@ -58,14 +58,26 @@ class MaisakaReasoningEngine:
try:
while self._runtime._running:
cached_messages = await self._runtime._internal_turn_queue.get()
if not cached_messages:
timeout_triggered = cached_messages is None
if not timeout_triggered and not cached_messages:
self._runtime._internal_turn_queue.task_done()
continue
self._runtime._agent_state = self._runtime._STATE_RUNNING
await self._ingest_messages(cached_messages)
anchor_message = cached_messages[-1]
if cached_messages:
await self._ingest_messages(cached_messages)
anchor_message = cached_messages[-1]
else:
anchor_message = self._get_timeout_anchor_message()
if anchor_message is None:
logger.warning(
f"{self._runtime.log_prefix} wait 超时后缺少可复用的锚点消息,跳过本轮继续思考"
)
self._runtime._internal_turn_queue.task_done()
continue
logger.info(f"{self._runtime.log_prefix} wait 超时后开始新一轮思考")
self._runtime._chat_history.append(self._build_wait_timeout_message(anchor_message))
self._trim_chat_history()
try:
for round_index in range(self._runtime._max_internal_rounds):
cycle_detail = self._start_cycle()
@@ -126,6 +138,24 @@ class MaisakaReasoningEngine:
logger.exception("%s Maisaka internal loop crashed", self._runtime.log_prefix)
raise
def _get_timeout_anchor_message(self) -> Optional[SessionMessage]:
"""在 wait 超时后复用最近一条真实用户消息作为锚点。"""
if self._runtime.message_cache:
return self._runtime.message_cache[-1]
return None
def _build_wait_timeout_message(self, anchor_message: SessionMessage) -> SessionMessage:
"""构造 wait 超时后的工具结果消息,用于触发下一轮思考。"""
return build_message(
role="tool",
content="wait 已超时,期间没有收到新的用户输入。请基于现有上下文继续下一轮思考。",
source="tool",
platform=anchor_message.platform,
session_id=self._runtime.session_id,
group_info=self._runtime._build_group_info(anchor_message),
user_info=UserInfo(user_id="maisaka_tool", user_nickname="tool", user_cardname=None),
)
async def _ingest_messages(self, messages: list[SessionMessage]) -> None:
"""处理传入消息列表,将其转换为历史消息并加入聊天历史缓存。"""
for message in messages:
@@ -417,6 +447,19 @@ class MaisakaReasoningEngine:
logger.info(f"{self._runtime.log_prefix} reasoning similarity: {similarity:.2f}")
return similarity > 0.9
@staticmethod
def _post_process_reply_text(reply_text: str) -> list[str]:
"""沿用旧回复链的文本后处理,执行分段与错别字注入。"""
processed_segments: list[str] = []
for segment in process_llm_response(reply_text):
normalized_segment = segment.strip()
if normalized_segment:
processed_segments.append(normalized_segment)
if processed_segments:
return processed_segments
return [reply_text.strip()]
async def _handle_tool_calls(
self,
tool_calls: list[ToolCall],
@@ -426,8 +469,10 @@ class MaisakaReasoningEngine:
for tool_call in tool_calls:
if tool_call.func_name == "reply":
reply_sent = await self._handle_reply(tool_call, latest_thought, anchor_message)
if reply_sent:
return True
if not reply_sent:
logger.warning(
f"{self._runtime.log_prefix} reply tool did not produce a visible message, continuing loop"
)
continue
if tool_call.func_name == "no_reply":
@@ -634,19 +679,31 @@ class MaisakaReasoningEngine:
)
return False
reply_segments = self._post_process_reply_text(reply_text)
combined_reply_text = "".join(reply_segments)
logger.info(
f"{self._runtime.log_prefix} reply post process finished: "
f"target_msg_id={target_message_id} segment_count={len(reply_segments)} "
f"segments={reply_segments!r}"
)
logger.info(
f"{self._runtime.log_prefix} sending guided reply: "
f"target_msg_id={target_message_id} quote={quote_reply} reply_text={reply_text!r}"
f"target_msg_id={target_message_id} quote={quote_reply} reply_segments={reply_segments!r}"
)
try:
sent = await send_service.text_to_stream(
text=reply_text,
stream_id=self._runtime.session_id,
set_reply=quote_reply,
reply_message=target_message if quote_reply else None,
selected_expressions=reply_result.selected_expression_ids or None,
typing=False,
)
sent = False
for index, segment in enumerate(reply_segments):
sent = await send_service.text_to_stream(
text=segment,
stream_id=self._runtime.session_id,
set_reply=quote_reply if index == 0 else False,
reply_message=target_message if quote_reply and index == 0 else None,
selected_expressions=reply_result.selected_expression_ids or None,
typing=index > 0,
)
if not sent:
break
except Exception:
logger.exception(
f"{self._runtime.log_prefix} send_service.text_to_stream crashed "
@@ -675,11 +732,12 @@ class MaisakaReasoningEngine:
if self._runtime.chat_stream is not None:
await database_api.store_tool_info(
chat_stream=self._runtime.chat_stream,
display_prompt=f"你对{target_user_name}进行了回复:{reply_text}",
display_prompt=f"你对{target_user_name}进行了回复:{combined_reply_text}",
tool_data={
"msg_id": target_message_id,
"quote": quote_reply,
"reply_text": reply_text,
"reply_text": combined_reply_text,
"reply_segments": reply_segments,
},
tool_name="reply",
tool_reasoning=latest_thought,
@@ -693,17 +751,25 @@ class MaisakaReasoningEngine:
user_cardname=None,
)
history_message = build_message(
role="assistant",
content=reply_text,
role="user",
content="",
source="guided_reply",
platform=target_platform,
session_id=self._runtime.session_id,
group_info=self._runtime._build_group_info(target_message),
user_info=bot_user_info,
)
structured_visible_text = f"{self._build_planner_user_prefix(history_message)}{reply_text}"
history_message.display_message = structured_visible_text
history_message.processed_plain_text = structured_visible_text
history_message.raw_message = MessageSequence(
[TextComponent(f"{self._build_planner_user_prefix(history_message)}{combined_reply_text}")]
)
visible_reply_text = format_speaker_content(
bot_name,
combined_reply_text,
history_message.timestamp,
history_message.message_id,
)
history_message.display_message = visible_reply_text
history_message.processed_plain_text = visible_reply_text
self._runtime._chat_history.append(history_message)
return True