diff --git a/src/chat/focus_chat/heartFC_chat.py b/src/chat/focus_chat/heartFC_chat.py index 4a28652d1..ff4f7fdb0 100644 --- a/src/chat/focus_chat/heartFC_chat.py +++ b/src/chat/focus_chat/heartFC_chat.py @@ -91,7 +91,6 @@ class HeartFChatting: self.action_manager = ActionManager() self.action_planner = ActionPlanner(log_prefix=self.log_prefix, action_manager=self.action_manager) - # --- 处理器列表 --- self.processors: List[BaseProcessor] = [] self._register_default_processors() @@ -526,5 +525,3 @@ class HeartFChatting: if last_n is not None: history = history[-last_n:] return [cycle.to_dict() for cycle in history] - - diff --git a/src/chat/focus_chat/planners/action_factory.py b/src/chat/focus_chat/planners/action_factory.py index 257156a25..bca49c496 100644 --- a/src/chat/focus_chat/planners/action_factory.py +++ b/src/chat/focus_chat/planners/action_factory.py @@ -1,7 +1,5 @@ -from typing import Dict, List, Optional, Callable, Coroutine, Type, Any, Union -import os -import importlib -from src.chat.focus_chat.planners.actions.base_action import BaseAction, _ACTION_REGISTRY, _DEFAULT_ACTIONS +from typing import Dict, List, Optional, Callable, Coroutine, Type, Any +from src.chat.focus_chat.planners.actions.base_action import BaseAction, _ACTION_REGISTRY from src.chat.heart_flow.observation.observation import Observation from src.chat.focus_chat.expressors.default_expressor import DefaultExpressor from src.chat.message_receive.chat_stream import ChatStream @@ -9,8 +7,6 @@ from src.chat.focus_chat.heartFC_Cycleinfo import CycleDetail from src.common.logger_manager import get_logger # 导入动作类,确保装饰器被执行 -from src.chat.focus_chat.planners.actions.reply_action import ReplyAction -from src.chat.focus_chat.planners.actions.no_reply_action import NoReplyAction logger = get_logger("action_factory") @@ -31,20 +27,19 @@ class ActionManager: self._using_actions: Dict[str, ActionInfo] = {} # 临时备份原始使用中的动作 self._original_actions_backup: Optional[Dict[str, ActionInfo]] = None - + # 默认动作集,仅作为快照,用于恢复默认 self._default_actions: Dict[str, ActionInfo] = {} - + # 加载所有已注册动作 self._load_registered_actions() - + # 初始化时将默认动作加载到使用中的动作 self._using_actions = self._default_actions.copy() - + # logger.info(f"当前可用动作: {list(self._using_actions.keys())}") # for action_name, action_info in self._using_actions.items(): - # logger.info(f"动作名称: {action_name}, 动作信息: {action_info}") - + # logger.info(f"动作名称: {action_name}, 动作信息: {action_info}") def _load_registered_actions(self) -> None: """ @@ -54,35 +49,35 @@ class ActionManager: # 从_ACTION_REGISTRY获取所有已注册动作 for action_name, action_class in _ACTION_REGISTRY.items(): # 获取动作相关信息 - action_description:str = getattr(action_class, "action_description", "") - action_parameters:dict[str:str] = getattr(action_class, "action_parameters", {}) - action_require:list[str] = getattr(action_class, "action_require", []) - is_default:bool = getattr(action_class, "default", False) - + action_description: str = getattr(action_class, "action_description", "") + action_parameters: dict[str:str] = getattr(action_class, "action_parameters", {}) + action_require: list[str] = getattr(action_class, "action_require", []) + is_default: bool = getattr(action_class, "default", False) + if action_name and action_description: # 创建动作信息字典 action_info = { "description": action_description, "parameters": action_parameters, - "require": action_require + "require": action_require, } - + # 注册2 print("注册2") print(action_info) - + # 添加到所有已注册的动作 self._registered_actions[action_name] = action_info - + # 添加到默认动作(如果是默认动作) if is_default: self._default_actions[action_name] = action_info - + logger.info(f"所有注册动作: {list(self._registered_actions.keys())}") logger.info(f"默认动作: {list(self._default_actions.keys())}") # for action_name, action_info in self._default_actions.items(): - # logger.info(f"动作名称: {action_name}, 动作信息: {action_info}") - + # logger.info(f"动作名称: {action_name}, 动作信息: {action_info}") + except Exception as e: logger.error(f"加载已注册动作失败: {e}") @@ -129,7 +124,7 @@ class ActionManager: if action_name not in self._using_actions: logger.warning(f"当前不可用的动作类型: {action_name}") return None - + handler_class = _ACTION_REGISTRY.get(action_name) if not handler_class: logger.warning(f"未注册的动作类型: {action_name}") @@ -153,7 +148,7 @@ class ActionManager: expressor=expressor, chat_stream=chat_stream, ) - + return instance except Exception as e: @@ -167,7 +162,7 @@ class ActionManager: def get_default_actions(self) -> Dict[str, ActionInfo]: """获取默认动作集""" return self._default_actions.copy() - + def get_using_actions(self) -> Dict[str, ActionInfo]: """获取当前正在使用的动作集""" return self._using_actions.copy() @@ -175,21 +170,21 @@ class ActionManager: def add_action_to_using(self, action_name: str) -> bool: """ 添加已注册的动作到当前使用的动作集 - + Args: action_name: 动作名称 - + Returns: bool: 添加是否成功 """ if action_name not in self._registered_actions: logger.warning(f"添加失败: 动作 {action_name} 未注册") return False - + if action_name in self._using_actions: logger.info(f"动作 {action_name} 已经在使用中") return True - + self._using_actions[action_name] = self._registered_actions[action_name] logger.info(f"添加动作 {action_name} 到使用集") return True @@ -197,17 +192,17 @@ class ActionManager: def remove_action_from_using(self, action_name: str) -> bool: """ 从当前使用的动作集中移除指定动作 - + Args: action_name: 动作名称 - + Returns: bool: 移除是否成功 """ if action_name not in self._using_actions: logger.warning(f"移除失败: 动作 {action_name} 不在当前使用的动作集中") return False - + del self._using_actions[action_name] logger.info(f"已从使用集中移除动作 {action_name}") return True @@ -215,30 +210,26 @@ class ActionManager: def add_action(self, action_name: str, description: str, parameters: Dict = None, require: List = None) -> bool: """ 添加新的动作到注册集 - + Args: action_name: 动作名称 description: 动作描述 parameters: 动作参数定义,默认为空字典 require: 动作依赖项,默认为空列表 - + Returns: bool: 添加是否成功 """ if action_name in self._registered_actions: return False - + if parameters is None: parameters = {} if require is None: require = [] - - action_info = { - "description": description, - "parameters": parameters, - "require": require - } - + + action_info = {"description": description, "parameters": parameters, "require": require} + self._registered_actions[action_name] = action_info return True @@ -264,7 +255,7 @@ class ActionManager: if self._original_actions_backup is not None: self._using_actions = self._original_actions_backup.copy() self._original_actions_backup = None - + def restore_default_actions(self) -> None: """恢复默认动作集到使用集""" self._using_actions = self._default_actions.copy() @@ -273,10 +264,10 @@ class ActionManager: def get_action(self, action_name: str) -> Optional[Type[BaseAction]]: """ 获取指定动作的处理器类 - + Args: action_name: 动作名称 - + Returns: Optional[Type[BaseAction]]: 动作处理器类,如果不存在则返回None """ diff --git a/src/chat/focus_chat/planners/actions/base_action.py b/src/chat/focus_chat/planners/actions/base_action.py index 7c77c300c..82d259677 100644 --- a/src/chat/focus_chat/planners/actions/base_action.py +++ b/src/chat/focus_chat/planners/actions/base_action.py @@ -12,7 +12,7 @@ _DEFAULT_ACTIONS: Dict[str, str] = {} def register_action(cls): """ 动作注册装饰器 - + 用法: @register_action class MyAction(BaseAction): @@ -24,22 +24,22 @@ def register_action(cls): if not hasattr(cls, "action_name") or not hasattr(cls, "action_description"): logger.error(f"动作类 {cls.__name__} 缺少必要的属性: action_name 或 action_description") return cls - - action_name = getattr(cls, "action_name") - action_description = getattr(cls, "action_description") + + action_name = cls.action_name + action_description = cls.action_description is_default = getattr(cls, "default", False) - + if not action_name or not action_description: logger.error(f"动作类 {cls.__name__} 的 action_name 或 action_description 为空") return cls - + # 将动作类注册到全局注册表 _ACTION_REGISTRY[action_name] = cls - + # 如果是默认动作,添加到默认动作集 if is_default: _DEFAULT_ACTIONS[action_name] = action_description - + logger.info(f"已注册动作: {action_name} -> {cls.__name__},默认: {is_default}") return cls @@ -60,15 +60,14 @@ class BaseAction(ABC): cycle_timers: 计时器字典 thinking_id: 思考ID """ - #每个动作必须实现 - self.action_name:str = "base_action" - self.action_description:str = "基础动作" - self.action_parameters:dict = {} - self.action_require:list[str] = [] - - self.default:bool = False - - + # 每个动作必须实现 + self.action_name: str = "base_action" + self.action_description: str = "基础动作" + self.action_parameters: dict = {} + self.action_require: list[str] = [] + + self.default: bool = False + self.action_data = action_data self.reasoning = reasoning self.cycle_timers = cycle_timers diff --git a/src/chat/focus_chat/planners/actions/no_reply_action.py b/src/chat/focus_chat/planners/actions/no_reply_action.py index a29812c7a..71f1cb3f3 100644 --- a/src/chat/focus_chat/planners/actions/no_reply_action.py +++ b/src/chat/focus_chat/planners/actions/no_reply_action.py @@ -29,7 +29,7 @@ class NoReplyAction(BaseAction): action_require = [ "话题无关/无聊/不感兴趣/不懂", "最后一条消息是你自己发的且无人回应你", - "你发送了太多消息,且无人回复" + "你发送了太多消息,且无人回复", ] default = True @@ -46,7 +46,7 @@ class NoReplyAction(BaseAction): total_no_reply_count: int = 0, total_waiting_time: float = 0.0, shutting_down: bool = False, - **kwargs + **kwargs, ): """初始化不回复动作处理器 diff --git a/src/chat/focus_chat/planners/actions/reply_action.py b/src/chat/focus_chat/planners/actions/reply_action.py index 7b2e88fa0..6e4f41d4d 100644 --- a/src/chat/focus_chat/planners/actions/reply_action.py +++ b/src/chat/focus_chat/planners/actions/reply_action.py @@ -2,9 +2,8 @@ # -*- coding: utf-8 -*- from src.common.logger_manager import get_logger -from src.chat.utils.timer_calculator import Timer from src.chat.focus_chat.planners.actions.base_action import BaseAction, register_action -from typing import Tuple, List, Optional +from typing import Tuple, List from src.chat.heart_flow.observation.observation import Observation from src.chat.focus_chat.expressors.default_expressor import DefaultExpressor from src.chat.message_receive.chat_stream import ChatStream @@ -22,14 +21,14 @@ class ReplyAction(BaseAction): 处理构建和发送消息回复的动作。 """ - action_name:str = "reply" - action_description:str = "表达想法,可以只包含文本、表情或两者都有" - action_parameters:dict[str:str] = { + action_name: str = "reply" + action_description: str = "表达想法,可以只包含文本、表情或两者都有" + action_parameters: dict[str:str] = { "text": "你想要表达的内容(可选)", "emojis": "描述当前使用表情包的场景(可选)", "target": "你想要回复的原始文本内容(非必须,仅文本,不包含发送者)(可选)", } - action_require:list[str] = [ + action_require: list[str] = [ "有实质性内容需要表达", "有人提到你,但你还没有回应他", "在合适的时候添加表情(不要总是添加)", @@ -38,7 +37,7 @@ class ReplyAction(BaseAction): "一次只回复一个人,一次只回复一个话题,突出重点", "如果是自己发的消息想继续,需自然衔接", "避免重复或评价自己的发言,不要和自己聊天", - "注意:回复尽量简短一些。可以参考贴吧,知乎和微博的回复风格,回复不要浮夸,不要用夸张修辞,平淡一些。" + "注意:回复尽量简短一些。可以参考贴吧,知乎和微博的回复风格,回复不要浮夸,不要用夸张修辞,平淡一些。", ] default = True @@ -54,7 +53,7 @@ class ReplyAction(BaseAction): chat_stream: ChatStream, current_cycle: CycleDetail, log_prefix: str, - **kwargs + **kwargs, ): """初始化回复动作处理器 @@ -89,9 +88,9 @@ class ReplyAction(BaseAction): reasoning=self.reasoning, reply_data=self.action_data, cycle_timers=self.cycle_timers, - thinking_id=self.thinking_id + thinking_id=self.thinking_id, ) - + async def _handle_reply( self, reasoning: str, reply_data: dict, cycle_timers: dict, thinking_id: str ) -> tuple[bool, str]: diff --git a/src/chat/focus_chat/planners/planner.py b/src/chat/focus_chat/planners/planner.py index bb87e1da7..83c8b6791 100644 --- a/src/chat/focus_chat/planners/planner.py +++ b/src/chat/focus_chat/planners/planner.py @@ -4,7 +4,6 @@ from typing import List, Dict, Any, Optional from rich.traceback import install from src.chat.models.utils_model import LLMRequest from src.config.config import global_config -from src.chat.focus_chat.heartflow_prompt_builder import prompt_builder from src.chat.focus_chat.info.info_base import InfoBase from src.chat.focus_chat.info.obs_info import ObsInfo from src.chat.focus_chat.info.cycle_info import CycleInfo @@ -15,10 +14,12 @@ from src.chat.utils.prompt_builder import Prompt, global_prompt_manager from src.individuality.individuality import Individuality from src.chat.focus_chat.planners.action_factory import ActionManager from src.chat.focus_chat.planners.action_factory import ActionInfo + logger = get_logger("planner") install(extra_lines=3) + def init_prompt(): Prompt( """你的名字是{bot_name},{prompt_personality},{chat_context_description}。需要基于以下信息决定如何参与对话: @@ -44,8 +45,9 @@ def init_prompt(): }} 请输出你的决策 JSON:""", -"planner_prompt",) - + "planner_prompt", + ) + Prompt( """ action_name: {action_name} @@ -57,7 +59,7 @@ action_name: {action_name} """, "action_prompt", ) - + class ActionPlanner: def __init__(self, log_prefix: str, action_manager: ActionManager): @@ -68,7 +70,7 @@ class ActionPlanner: max_tokens=1000, request_type="action_planning", # 用于动作规划 ) - + self.action_manager = action_manager async def plan(self, all_plan_info: List[InfoBase], cycle_timers: dict) -> Dict[str, Any]: @@ -103,10 +105,10 @@ class ActionPlanner: cycle_info = info.get_observe_info() elif isinstance(info, StructuredInfo): logger.debug(f"{self.log_prefix} 结构化信息: {info}") - structured_info = info.get_data() + _structured_info = info.get_data() current_available_actions = self.action_manager.get_using_actions() - + # --- 构建提示词 (调用修改后的 PromptBuilder 方法) --- prompt = await self.build_planner_prompt( is_group_chat=is_group_chat, # <-- Pass HFC state @@ -197,7 +199,6 @@ class ActionPlanner: # 返回结果字典 return plan_result - async def build_planner_prompt( self, is_group_chat: bool, # Now passed as argument @@ -218,7 +219,6 @@ class ActionPlanner: ) chat_context_description = f"你正在和 {chat_target_name} 私聊" - chat_content_block = "" if observed_messages_str: chat_content_block = f"聊天记录:\n{observed_messages_str}" @@ -234,7 +234,6 @@ class ActionPlanner: individuality = Individuality.get_instance() personality_block = individuality.get_prompt(x_person=2, level=2) - action_options_block = "" for using_actions_name, using_actions_info in current_available_actions.items(): # print(using_actions_name) @@ -242,29 +241,26 @@ class ActionPlanner: # print(using_actions_info["parameters"]) # print(using_actions_info["require"]) # print(using_actions_info["description"]) - + using_action_prompt = await global_prompt_manager.get_prompt_async("action_prompt") - + param_text = "" for param_name, param_description in using_actions_info["parameters"].items(): param_text += f"{param_name}: {param_description}\n" - + require_text = "" for require_item in using_actions_info["require"]: require_text += f"- {require_item}\n" - + using_action_prompt = using_action_prompt.format( action_name=using_actions_name, action_description=using_actions_info["description"], action_parameters=param_text, action_require=require_text, ) - + action_options_block += using_action_prompt - - - planner_prompt_template = await global_prompt_manager.get_prompt_async("planner_prompt") prompt = planner_prompt_template.format( bot_name=global_config.BOT_NICKNAME,