Files
Mofox-Core/src/chat/chat_loop/hfc_utils.py
minecraft1024a f53993e34a feat(proactive_thinking): 重构主动思考为由Planner直接决策
重构了主动思考的触发和决策流程。原有的通过生成特定prompt来启动思考循环的方式被移除,改为直接调用Planner的`PROACTIVE`模式。

- **Planner增强**:
  - 新增`PROACTIVE`聊天模式,用于处理主动思考场景。
  - 为`PROACTIVE`模式设计了专用的prompt模板,整合了长期记忆、当前状态等信息。
  - 引入`do_nothing`动作,允许Planner在分析后决定保持沉默。
  - 增加从海马体(长期记忆)获取上下文的功能,为决策提供更丰富的背景。

- **ProactiveThinker简化**:
  - 移除了原有的prompt生成和调用`observe`的逻辑。
  - 现在直接调用`action_planner.plan(mode=ChatMode.PROACTIVE)`来获取决策。
  - 根据Planner返回的动作(如`do_nothing`或具体行动),决定是保持沉默还是执行计划。

- **CycleProcessor & Tracker调整**:
  - `CycleProcessor`新增`execute_plan`方法,用于执行一个已经由Planner预先制定好的计划。
  - `CycleTracker`能够区分并标记由主动思考发起的循环(例如,cycle_id为 "1.p"),以便于追踪和分析。
2025-11-19 22:45:16 +08:00

204 lines
6.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import time
from typing import Optional, Dict, Any, Union
from src.config.config import global_config
from src.common.logger import get_logger
from src.chat.message_receive.chat_stream import get_chat_manager
from src.plugin_system.apis import send_api
from maim_message.message_base import GroupInfo
from src.common.message_repository import count_messages
logger = get_logger("hfc")
class CycleDetail:
"""
循环信息记录类
功能说明:
- 记录单次思考循环的详细信息
- 包含循环ID、思考ID、时间戳等基本信息
- 存储循环的规划信息和动作信息
- 提供序列化和转换功能
"""
def __init__(self, cycle_id: Union[int, str]):
"""
初始化循环详情记录
Args:
cycle_id: 循环ID用于标识循环的顺序
功能说明:
- 设置循环基本标识信息
- 初始化时间戳和计时器
- 准备循环信息存储容器
"""
self.cycle_id = cycle_id
self.thinking_id = ""
self.start_time = time.time()
self.end_time: Optional[float] = None
self.timers: Dict[str, float] = {}
self.loop_plan_info: Dict[str, Any] = {}
self.loop_action_info: Dict[str, Any] = {}
def to_dict(self) -> Dict[str, Any]:
"""
将循环信息转换为字典格式
Returns:
dict: 包含所有循环信息的字典,已处理循环引用和序列化问题
功能说明:
- 递归转换复杂对象为可序列化格式
- 防止循环引用导致的无限递归
- 限制递归深度避免栈溢出
- 只保留基本数据类型和可序列化的值
"""
def convert_to_serializable(obj, depth=0, seen=None):
if seen is None:
seen = set()
# 防止递归过深
if depth > 5: # 降低递归深度限制
return str(obj)
# 防止循环引用
obj_id = id(obj)
if obj_id in seen:
return str(obj)
seen.add(obj_id)
try:
if hasattr(obj, "to_dict"):
# 对于有to_dict方法的对象直接调用其to_dict方法
return obj.to_dict()
elif isinstance(obj, dict):
# 对于字典,只保留基本类型和可序列化的值
return {
k: convert_to_serializable(v, depth + 1, seen)
for k, v in obj.items()
if isinstance(k, (str, int, float, bool))
}
elif isinstance(obj, (list, tuple)):
# 对于列表和元组,只保留可序列化的元素
return [
convert_to_serializable(item, depth + 1, seen)
for item in obj
if not isinstance(item, (dict, list, tuple))
or isinstance(item, (str, int, float, bool, type(None)))
]
elif isinstance(obj, (str, int, float, bool, type(None))):
return obj
else:
return str(obj)
finally:
seen.remove(obj_id)
return {
"cycle_id": self.cycle_id,
"start_time": self.start_time,
"end_time": self.end_time,
"timers": self.timers,
"thinking_id": self.thinking_id,
"loop_plan_info": convert_to_serializable(self.loop_plan_info),
"loop_action_info": convert_to_serializable(self.loop_action_info),
}
def set_loop_info(self, loop_info: Dict[str, Any]):
"""
设置循环信息
Args:
loop_info: 包含循环规划和动作信息的字典
功能说明:
- 从传入的循环信息中提取规划和动作信息
- 更新当前循环详情的相关字段
"""
self.loop_plan_info = loop_info["loop_plan_info"]
self.loop_action_info = loop_info["loop_action_info"]
def get_recent_message_stats(minutes: float = 30, chat_id: Optional[str] = None) -> dict:
"""
获取最近消息统计信息
Args:
minutes: 检索的分钟数默认30分钟
chat_id: 指定的chat_id仅统计该chat下的消息。为None时统计全部
Returns:
dict: {"bot_reply_count": int, "total_message_count": int}
功能说明:
- 统计指定时间范围内的消息数量
- 区分机器人回复和总消息数
- 可以针对特定聊天或全局统计
- 用于分析聊天活跃度和机器人参与度
"""
now = time.time()
start_time = now - minutes * 60
bot_id = global_config.bot.qq_account
filter_base: Dict[str, Any] = {"time": {"$gte": start_time}}
if chat_id is not None:
filter_base["chat_id"] = chat_id
# 总消息数
total_message_count = count_messages(filter_base)
# bot自身回复数
bot_filter = filter_base.copy()
bot_filter["user_id"] = bot_id
bot_reply_count = count_messages(bot_filter)
return {"bot_reply_count": bot_reply_count, "total_message_count": total_message_count}
async def send_typing():
"""
发送打字状态指示
功能说明:
- 创建内心聊天流(用于状态显示)
- 发送typing状态消息
- 不存储到消息记录中
- 用于S4U功能的视觉反馈
"""
group_info = GroupInfo(platform="amaidesu_default", group_id="114514", group_name="内心")
chat = await get_chat_manager().get_or_create_stream(
platform="amaidesu_default",
user_info=None,
group_info=group_info,
)
await send_api.custom_to_stream(
message_type="state", content="typing", stream_id=chat.stream_id, storage_message=False
)
async def stop_typing():
"""
停止打字状态指示
功能说明:
- 创建内心聊天流(用于状态显示)
- 发送stop_typing状态消息
- 不存储到消息记录中
- 结束S4U功能的视觉反馈
"""
group_info = GroupInfo(platform="amaidesu_default", group_id="114514", group_name="内心")
chat = await get_chat_manager().get_or_create_stream(
platform="amaidesu_default",
user_info=None,
group_info=group_info,
)
await send_api.custom_to_stream(
message_type="state", content="stop_typing", stream_id=chat.stream_id, storage_message=False
)