feat: 重构 KFC 回复动作,优化回复生成流程和上下文注入
This commit is contained in:
@@ -1,34 +1,53 @@
|
|||||||
"""
|
"""
|
||||||
KFC 回复动作模块
|
KFC 回复动作模块
|
||||||
|
|
||||||
KFC 的 reply 动作与 AFC 不同:
|
KFC 的 reply 动作:
|
||||||
- 不调用 LLM 生成回复,content 由 Replyer 提前生成
|
- 完整的回复流程在 execute() 中实现
|
||||||
- 动作本身只负责发送 content 参数中的内容
|
- 调用 Replyer 生成回复文本
|
||||||
|
- 回复后处理(系统格式词过滤、分段发送、错字生成等)
|
||||||
|
- 发送回复消息
|
||||||
|
|
||||||
|
与 AFC 类似,但使用 KFC 专属的 Replyer 和 Session 系统。
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from typing import ClassVar
|
import asyncio
|
||||||
|
from typing import TYPE_CHECKING, ClassVar, Optional
|
||||||
|
|
||||||
from src.common.logger import get_logger
|
from src.common.logger import get_logger
|
||||||
|
from src.config.config import global_config
|
||||||
from src.plugin_system import ActionActivationType, BaseAction, ChatMode
|
from src.plugin_system import ActionActivationType, BaseAction, ChatMode
|
||||||
from src.plugin_system.apis import send_api
|
from src.plugin_system.apis import send_api
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from ..session import KokoroSession
|
||||||
|
|
||||||
logger = get_logger("kfc_reply_action")
|
logger = get_logger("kfc_reply_action")
|
||||||
|
|
||||||
|
|
||||||
class KFCReplyAction(BaseAction):
|
class KFCReplyAction(BaseAction):
|
||||||
"""KFC Reply 动作 - 发送已生成的回复内容
|
"""KFC Reply 动作 - 完整的私聊回复流程
|
||||||
|
|
||||||
特点:
|
特点:
|
||||||
- 不调用 LLM,直接发送 content 参数中的内容
|
- 完整的回复流程:生成回复 → 后处理 → 分段发送
|
||||||
- content 由 Replyer 提前生成
|
- 使用 KFC 专属的 Replyer 生成回复
|
||||||
|
- 支持系统格式词过滤、分段发送、错字生成等后处理
|
||||||
- 仅限 KokoroFlowChatter 使用
|
- 仅限 KokoroFlowChatter 使用
|
||||||
|
|
||||||
注意:使用 kfc_reply 作为动作名称以避免与 AFC 的 reply 动作冲突
|
action_data 参数:
|
||||||
|
- user_id: 用户ID(必需,用于获取 Session)
|
||||||
|
- user_name: 用户名称(必需)
|
||||||
|
- thought: Planner 生成的想法/内心独白(必需)
|
||||||
|
- situation_type: 情况类型(可选,默认 "new_message")
|
||||||
|
- extra_context: 额外上下文(可选)
|
||||||
|
- content: 预生成的回复内容(可选,如果提供则直接发送)
|
||||||
|
- should_quote_reply: 是否引用原消息(可选,默认 false)
|
||||||
|
- enable_splitter: 是否启用分段发送(可选,默认 true)
|
||||||
|
- enable_chinese_typo: 是否启用错字生成(可选,默认 true)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# 动作基本信息
|
# 动作基本信息
|
||||||
action_name = "kfc_reply"
|
action_name = "kfc_reply"
|
||||||
action_description = "发送回复消息。content 参数包含要发送的内容。"
|
action_description = "发送回复消息。会根据当前对话情境生成并发送回复。"
|
||||||
|
|
||||||
# 激活设置
|
# 激活设置
|
||||||
activation_type = ActionActivationType.ALWAYS
|
activation_type = ActionActivationType.ALWAYS
|
||||||
@@ -40,45 +59,230 @@ class KFCReplyAction(BaseAction):
|
|||||||
|
|
||||||
# 动作参数定义
|
# 动作参数定义
|
||||||
action_parameters: ClassVar = {
|
action_parameters: ClassVar = {
|
||||||
"content": "要发送的回复内容(必需,由 Replyer 生成)",
|
"content": "要发送的回复内容(可选,如果不提供则自动生成)",
|
||||||
"should_quote_reply": "是否引用原消息(可选,true/false,默认 false)",
|
"should_quote_reply": "是否引用原消息(可选,true/false,默认 false)",
|
||||||
}
|
}
|
||||||
|
|
||||||
# 动作使用场景
|
# 动作使用场景
|
||||||
action_require: ClassVar = [
|
action_require: ClassVar = [
|
||||||
"发送回复消息时使用",
|
"需要发送回复消息时使用",
|
||||||
"content 参数必须包含要发送的内容",
|
"私聊场景的标准回复动作",
|
||||||
]
|
]
|
||||||
|
|
||||||
# 关联类型
|
# 关联类型
|
||||||
associated_types: ClassVar[list[str]] = ["text"]
|
associated_types: ClassVar[list[str]] = ["text"]
|
||||||
|
|
||||||
async def execute(self) -> tuple[bool, str]:
|
async def execute(self) -> tuple[bool, str]:
|
||||||
"""执行 reply 动作 - 发送 content 中的内容"""
|
"""执行 reply 动作 - 完整的回复流程"""
|
||||||
try:
|
try:
|
||||||
# 获取要发送的内容
|
# 1. 检查是否有预生成的内容
|
||||||
content = self.action_data.get("content", "")
|
content = self.action_data.get("content", "")
|
||||||
|
|
||||||
if not content:
|
if not content:
|
||||||
logger.warning(f"{self.log_prefix} content 为空,跳过发送")
|
# 2. 需要生成回复,获取必要信息
|
||||||
return True, ""
|
user_id = self.action_data.get("user_id")
|
||||||
|
user_name = self.action_data.get("user_name", "用户")
|
||||||
|
thought = self.action_data.get("thought", "")
|
||||||
|
situation_type = self.action_data.get("situation_type", "new_message")
|
||||||
|
extra_context = self.action_data.get("extra_context")
|
||||||
|
|
||||||
|
if not user_id:
|
||||||
|
logger.warning(f"{self.log_prefix} 缺少 user_id,无法生成回复")
|
||||||
|
return False, ""
|
||||||
|
|
||||||
|
# 3. 获取 Session
|
||||||
|
session = await self._get_session(user_id)
|
||||||
|
if not session:
|
||||||
|
logger.warning(f"{self.log_prefix} 无法获取 Session: {user_id}")
|
||||||
|
return False, ""
|
||||||
|
|
||||||
|
# 4. 调用 Replyer 生成回复
|
||||||
|
success, content = await self._generate_reply(
|
||||||
|
session=session,
|
||||||
|
user_name=user_name,
|
||||||
|
thought=thought,
|
||||||
|
situation_type=situation_type,
|
||||||
|
extra_context=extra_context,
|
||||||
|
)
|
||||||
|
|
||||||
|
if not success or not content:
|
||||||
|
logger.warning(f"{self.log_prefix} 回复生成失败")
|
||||||
|
return False, ""
|
||||||
|
|
||||||
# 获取是否引用
|
# 5. 回复后处理(系统格式词过滤 + 分段处理)
|
||||||
should_quote = self.action_data.get("should_quote_reply", False)
|
enable_splitter = self.action_data.get("enable_splitter", True)
|
||||||
|
enable_chinese_typo = self.action_data.get("enable_chinese_typo", True)
|
||||||
|
|
||||||
# 发送消息
|
processed_segments = self._post_process_reply(
|
||||||
await send_api.text_to_stream(
|
content=content,
|
||||||
text=content,
|
enable_splitter=enable_splitter,
|
||||||
stream_id=self.chat_stream.stream_id,
|
enable_chinese_typo=enable_chinese_typo,
|
||||||
reply_to_message=self.action_message,
|
|
||||||
set_reply=should_quote and bool(self.action_message),
|
|
||||||
typing=False,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.info(f"{self.log_prefix} KFC reply 动作执行成功")
|
if not processed_segments:
|
||||||
return True, content
|
logger.warning(f"{self.log_prefix} 回复后处理后内容为空")
|
||||||
|
return False, ""
|
||||||
|
|
||||||
|
# 6. 分段发送回复
|
||||||
|
should_quote = self.action_data.get("should_quote_reply", False)
|
||||||
|
reply_text = await self._send_segments(
|
||||||
|
segments=processed_segments,
|
||||||
|
should_quote=should_quote,
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.info(f"{self.log_prefix} KFC reply 动作执行成功: {reply_text[:50]}...")
|
||||||
|
return True, reply_text
|
||||||
|
|
||||||
|
except asyncio.CancelledError:
|
||||||
|
logger.debug(f"{self.log_prefix} 回复任务被取消")
|
||||||
|
return False, ""
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"{self.log_prefix} KFC reply 动作执行失败: {e}")
|
logger.error(f"{self.log_prefix} KFC reply 动作执行失败: {e}")
|
||||||
import traceback
|
import traceback
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return False, ""
|
return False, ""
|
||||||
|
|
||||||
|
def _post_process_reply(
|
||||||
|
self,
|
||||||
|
content: str,
|
||||||
|
enable_splitter: bool = True,
|
||||||
|
enable_chinese_typo: bool = True,
|
||||||
|
) -> list[str]:
|
||||||
|
"""
|
||||||
|
回复后处理
|
||||||
|
|
||||||
|
包括:
|
||||||
|
1. 系统格式词过滤(移除 [回复...]、[表情包:...]、@<...> 等)
|
||||||
|
2. 分段处理(根据标点分句、智能合并)
|
||||||
|
3. 错字生成(拟人化)
|
||||||
|
|
||||||
|
Args:
|
||||||
|
content: 原始回复内容
|
||||||
|
enable_splitter: 是否启用分段
|
||||||
|
enable_chinese_typo: 是否启用错字生成
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
处理后的文本段落列表
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
from src.chat.utils.utils import filter_system_format_content, process_llm_response
|
||||||
|
|
||||||
|
# 1. 过滤系统格式词
|
||||||
|
filtered_content = filter_system_format_content(content)
|
||||||
|
|
||||||
|
if not filtered_content or not filtered_content.strip():
|
||||||
|
logger.warning(f"{self.log_prefix} 过滤系统格式词后内容为空")
|
||||||
|
return []
|
||||||
|
|
||||||
|
# 2. 分段处理 + 错字生成
|
||||||
|
processed_segments = process_llm_response(
|
||||||
|
filtered_content,
|
||||||
|
enable_splitter=enable_splitter,
|
||||||
|
enable_chinese_typo=enable_chinese_typo,
|
||||||
|
)
|
||||||
|
|
||||||
|
# 过滤空段落
|
||||||
|
processed_segments = [seg for seg in processed_segments if seg and seg.strip()]
|
||||||
|
|
||||||
|
logger.debug(
|
||||||
|
f"{self.log_prefix} 回复后处理完成: "
|
||||||
|
f"原始长度={len(content)}, 过滤后长度={len(filtered_content)}, "
|
||||||
|
f"分段数={len(processed_segments)}"
|
||||||
|
)
|
||||||
|
|
||||||
|
return processed_segments
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"{self.log_prefix} 回复后处理失败: {e}")
|
||||||
|
# 失败时返回原始内容
|
||||||
|
return [content] if content else []
|
||||||
|
|
||||||
|
async def _send_segments(
|
||||||
|
self,
|
||||||
|
segments: list[str],
|
||||||
|
should_quote: bool = False,
|
||||||
|
) -> str:
|
||||||
|
"""
|
||||||
|
分段发送回复
|
||||||
|
|
||||||
|
Args:
|
||||||
|
segments: 要发送的文本段落列表
|
||||||
|
should_quote: 是否引用原消息(仅第一条消息引用)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
完整的回复文本(所有段落拼接)
|
||||||
|
"""
|
||||||
|
reply_text = ""
|
||||||
|
first_sent = False
|
||||||
|
|
||||||
|
# 获取分段发送的间隔时间
|
||||||
|
typing_delay = 0.5
|
||||||
|
if global_config and hasattr(global_config, 'response_splitter'):
|
||||||
|
typing_delay = getattr(global_config.response_splitter, "typing_delay", 0.5)
|
||||||
|
|
||||||
|
for segment in segments:
|
||||||
|
if not segment or not segment.strip():
|
||||||
|
continue
|
||||||
|
|
||||||
|
reply_text += segment
|
||||||
|
|
||||||
|
# 发送消息
|
||||||
|
if not first_sent:
|
||||||
|
# 第一条消息:可能需要引用
|
||||||
|
await send_api.text_to_stream(
|
||||||
|
text=segment,
|
||||||
|
stream_id=self.chat_stream.stream_id,
|
||||||
|
reply_to_message=self.action_message,
|
||||||
|
set_reply=should_quote and bool(self.action_message),
|
||||||
|
typing=False,
|
||||||
|
)
|
||||||
|
first_sent = True
|
||||||
|
else:
|
||||||
|
# 后续消息:模拟打字延迟
|
||||||
|
if typing_delay > 0:
|
||||||
|
await asyncio.sleep(typing_delay)
|
||||||
|
|
||||||
|
await send_api.text_to_stream(
|
||||||
|
text=segment,
|
||||||
|
stream_id=self.chat_stream.stream_id,
|
||||||
|
reply_to_message=None,
|
||||||
|
set_reply=False,
|
||||||
|
typing=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
return reply_text
|
||||||
|
|
||||||
|
async def _get_session(self, user_id: str) -> Optional["KokoroSession"]:
|
||||||
|
"""获取用户 Session"""
|
||||||
|
try:
|
||||||
|
from ..session import get_session_manager
|
||||||
|
|
||||||
|
session_manager = get_session_manager()
|
||||||
|
return await session_manager.get_session(user_id, self.chat_stream.stream_id)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"{self.log_prefix} 获取 Session 失败: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
async def _generate_reply(
|
||||||
|
self,
|
||||||
|
session: "KokoroSession",
|
||||||
|
user_name: str,
|
||||||
|
thought: str,
|
||||||
|
situation_type: str,
|
||||||
|
extra_context: Optional[dict] = None,
|
||||||
|
) -> tuple[bool, str]:
|
||||||
|
"""调用 Replyer 生成回复"""
|
||||||
|
try:
|
||||||
|
from ..replyer import generate_reply_text
|
||||||
|
|
||||||
|
return await generate_reply_text(
|
||||||
|
session=session,
|
||||||
|
user_name=user_name,
|
||||||
|
thought=thought,
|
||||||
|
situation_type=situation_type,
|
||||||
|
chat_stream=self.chat_stream,
|
||||||
|
extra_context=extra_context,
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"{self.log_prefix} 生成回复失败: {e}")
|
||||||
|
return False, ""
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ Kokoro Flow Chatter - Chatter 主类
|
|||||||
|
|
||||||
极简设计,只负责:
|
极简设计,只负责:
|
||||||
1. 收到消息
|
1. 收到消息
|
||||||
2. 调用 Replyer 生成响应
|
2. 调用 Planner 生成规划
|
||||||
3. 执行动作
|
3. 执行动作(回复在 Action.execute() 中生成)
|
||||||
4. 更新 Session
|
4. 更新 Session
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -20,7 +20,6 @@ from src.plugin_system.base.component_types import ChatType
|
|||||||
|
|
||||||
from .models import SessionStatus
|
from .models import SessionStatus
|
||||||
from .planner import generate_plan
|
from .planner import generate_plan
|
||||||
from .replyer import generate_reply_text
|
|
||||||
from .session import get_session_manager
|
from .session import get_session_manager
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@@ -153,30 +152,19 @@ class KokoroFlowChatter(BaseChatter):
|
|||||||
available_actions=available_actions,
|
available_actions=available_actions,
|
||||||
)
|
)
|
||||||
|
|
||||||
# 10. 对于需要回复的动作,调用 Replyer 生成实际文本
|
# 10. 为 kfc_reply 动作注入必要的上下文信息
|
||||||
processed_actions = []
|
|
||||||
for action in plan_response.actions:
|
for action in plan_response.actions:
|
||||||
if action.type == "kfc_reply":
|
if action.type == "kfc_reply":
|
||||||
# 调用 replyer 生成回复文本
|
# 注入回复生成所需的上下文
|
||||||
success, reply_text = await generate_reply_text(
|
action.params["user_id"] = user_id
|
||||||
session=session,
|
action.params["user_name"] = user_name
|
||||||
user_name=user_name,
|
action.params["thought"] = plan_response.thought
|
||||||
thought=plan_response.thought,
|
action.params["situation_type"] = situation_type
|
||||||
situation_type=situation_type,
|
|
||||||
chat_stream=chat_stream,
|
|
||||||
)
|
|
||||||
if success and reply_text:
|
|
||||||
# 更新 action 的 content
|
|
||||||
action.params["content"] = reply_text
|
|
||||||
else:
|
|
||||||
logger.warning("[KFC] 回复生成失败,跳过该动作")
|
|
||||||
continue
|
|
||||||
processed_actions.append(action)
|
|
||||||
|
|
||||||
# 11. 执行动作
|
# 11. 执行动作(回复生成在 Action.execute() 中完成)
|
||||||
exec_results = []
|
exec_results = []
|
||||||
has_reply = False
|
has_reply = False
|
||||||
for action in processed_actions:
|
for action in plan_response.actions:
|
||||||
result = await self.action_manager.execute_action(
|
result = await self.action_manager.execute_action(
|
||||||
action_name=action.type,
|
action_name=action.type,
|
||||||
chat_id=self.stream_id,
|
chat_id=self.stream_id,
|
||||||
@@ -193,7 +181,7 @@ class KokoroFlowChatter(BaseChatter):
|
|||||||
# 12. 记录 Bot 规划到 mental_log
|
# 12. 记录 Bot 规划到 mental_log
|
||||||
session.add_bot_planning(
|
session.add_bot_planning(
|
||||||
thought=plan_response.thought,
|
thought=plan_response.thought,
|
||||||
actions=[a.to_dict() for a in processed_actions],
|
actions=[a.to_dict() for a in plan_response.actions],
|
||||||
expected_reaction=plan_response.expected_reaction,
|
expected_reaction=plan_response.expected_reaction,
|
||||||
max_wait_seconds=plan_response.max_wait_seconds,
|
max_wait_seconds=plan_response.max_wait_seconds,
|
||||||
)
|
)
|
||||||
@@ -222,7 +210,7 @@ class KokoroFlowChatter(BaseChatter):
|
|||||||
logger.info(
|
logger.info(
|
||||||
f"{SOFT_PURPLE}[KFC]{RESET} 处理完成: "
|
f"{SOFT_PURPLE}[KFC]{RESET} 处理完成: "
|
||||||
f"user={user_name}, situation={situation_type}, "
|
f"user={user_name}, situation={situation_type}, "
|
||||||
f"actions={[a.type for a in processed_actions]}, "
|
f"actions={[a.type for a in plan_response.actions]}, "
|
||||||
f"wait={plan_response.max_wait_seconds}s"
|
f"wait={plan_response.max_wait_seconds}s"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ from src.plugin_system.apis.unified_scheduler import TriggerType, unified_schedu
|
|||||||
|
|
||||||
from .models import EventType, SessionStatus
|
from .models import EventType, SessionStatus
|
||||||
from .planner import generate_plan
|
from .planner import generate_plan
|
||||||
from .replyer import _clean_reply_text, generate_reply_text
|
from .replyer import _clean_reply_text
|
||||||
from .session import KokoroSession, get_session_manager
|
from .session import KokoroSession, get_session_manager
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@@ -412,26 +412,16 @@ class ProactiveThinker:
|
|||||||
available_actions=action_manager.get_using_actions(),
|
available_actions=action_manager.get_using_actions(),
|
||||||
)
|
)
|
||||||
|
|
||||||
# 对于需要回复的动作,调用 Replyer 生成实际文本
|
# 为 kfc_reply 动作注入必要的上下文信息
|
||||||
processed_actions = []
|
|
||||||
for action in plan_response.actions:
|
for action in plan_response.actions:
|
||||||
if action.type == "kfc_reply":
|
if action.type == "kfc_reply":
|
||||||
success, reply_text = await generate_reply_text(
|
action.params["user_id"] = session.user_id
|
||||||
session=session,
|
action.params["user_name"] = user_name
|
||||||
user_name=user_name,
|
action.params["thought"] = plan_response.thought
|
||||||
thought=plan_response.thought,
|
action.params["situation_type"] = "timeout"
|
||||||
situation_type="timeout",
|
|
||||||
chat_stream=chat_stream,
|
|
||||||
)
|
|
||||||
if success and reply_text:
|
|
||||||
action.params["content"] = reply_text
|
|
||||||
else:
|
|
||||||
logger.warning("[ProactiveThinker] 回复生成失败,跳过该动作")
|
|
||||||
continue
|
|
||||||
processed_actions.append(action)
|
|
||||||
|
|
||||||
# 执行动作
|
# 执行动作(回复生成在 Action.execute() 中完成)
|
||||||
for action in processed_actions:
|
for action in plan_response.actions:
|
||||||
await action_manager.execute_action(
|
await action_manager.execute_action(
|
||||||
action_name=action.type,
|
action_name=action.type,
|
||||||
chat_id=session.stream_id,
|
chat_id=session.stream_id,
|
||||||
@@ -445,7 +435,7 @@ class ProactiveThinker:
|
|||||||
# 记录到 mental_log
|
# 记录到 mental_log
|
||||||
session.add_bot_planning(
|
session.add_bot_planning(
|
||||||
thought=plan_response.thought,
|
thought=plan_response.thought,
|
||||||
actions=[a.to_dict() for a in processed_actions],
|
actions=[a.to_dict() for a in plan_response.actions],
|
||||||
expected_reaction=plan_response.expected_reaction,
|
expected_reaction=plan_response.expected_reaction,
|
||||||
max_wait_seconds=plan_response.max_wait_seconds,
|
max_wait_seconds=plan_response.max_wait_seconds,
|
||||||
)
|
)
|
||||||
@@ -466,7 +456,7 @@ class ProactiveThinker:
|
|||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
f"[ProactiveThinker] 超时决策完成: user={session.user_id}, "
|
f"[ProactiveThinker] 超时决策完成: user={session.user_id}, "
|
||||||
f"actions={[a.type for a in processed_actions]}, "
|
f"actions={[a.type for a in plan_response.actions]}, "
|
||||||
f"continue_wait={plan_response.max_wait_seconds > 0}"
|
f"continue_wait={plan_response.max_wait_seconds > 0}"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -612,27 +602,17 @@ class ProactiveThinker:
|
|||||||
await self.session_manager.save_session(session.user_id)
|
await self.session_manager.save_session(session.user_id)
|
||||||
return
|
return
|
||||||
|
|
||||||
# 对于需要回复的动作,调用 Replyer 生成实际文本
|
# 为 kfc_reply 动作注入必要的上下文信息
|
||||||
processed_actions = []
|
|
||||||
for action in plan_response.actions:
|
for action in plan_response.actions:
|
||||||
if action.type == "kfc_reply":
|
if action.type == "kfc_reply":
|
||||||
success, reply_text = await generate_reply_text(
|
action.params["user_id"] = session.user_id
|
||||||
session=session,
|
action.params["user_name"] = user_name
|
||||||
user_name=user_name,
|
action.params["thought"] = plan_response.thought
|
||||||
thought=plan_response.thought,
|
action.params["situation_type"] = "proactive"
|
||||||
situation_type="proactive",
|
action.params["extra_context"] = extra_context
|
||||||
chat_stream=chat_stream,
|
|
||||||
extra_context=extra_context,
|
|
||||||
)
|
|
||||||
if success and reply_text:
|
|
||||||
action.params["content"] = reply_text
|
|
||||||
else:
|
|
||||||
logger.warning("[ProactiveThinker] 回复生成失败,跳过该动作")
|
|
||||||
continue
|
|
||||||
processed_actions.append(action)
|
|
||||||
|
|
||||||
# 执行动作
|
# 执行动作(回复生成在 Action.execute() 中完成)
|
||||||
for action in processed_actions:
|
for action in plan_response.actions:
|
||||||
await action_manager.execute_action(
|
await action_manager.execute_action(
|
||||||
action_name=action.type,
|
action_name=action.type,
|
||||||
chat_id=session.stream_id,
|
chat_id=session.stream_id,
|
||||||
@@ -646,7 +626,7 @@ class ProactiveThinker:
|
|||||||
# 记录到 mental_log
|
# 记录到 mental_log
|
||||||
session.add_bot_planning(
|
session.add_bot_planning(
|
||||||
thought=plan_response.thought,
|
thought=plan_response.thought,
|
||||||
actions=[a.to_dict() for a in processed_actions],
|
actions=[a.to_dict() for a in plan_response.actions],
|
||||||
expected_reaction=plan_response.expected_reaction,
|
expected_reaction=plan_response.expected_reaction,
|
||||||
max_wait_seconds=plan_response.max_wait_seconds,
|
max_wait_seconds=plan_response.max_wait_seconds,
|
||||||
)
|
)
|
||||||
@@ -664,7 +644,7 @@ class ProactiveThinker:
|
|||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
f"[ProactiveThinker] 主动发起完成: user={session.user_id}, "
|
f"[ProactiveThinker] 主动发起完成: user={session.user_id}, "
|
||||||
f"actions={[a.type for a in processed_actions]}"
|
f"actions={[a.type for a in plan_response.actions]}"
|
||||||
)
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
Reference in New Issue
Block a user