Skip to content
Closed
2 changes: 2 additions & 0 deletions astrbot/builtin_stars/astrbot/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
LTM_ACTIVE_REPLY_KEY = "_ltm_active_reply"
LTM_ACTIVE_REPLY_IN_PROGRESS_KEY = "_ltm_active_reply_in_progress"
13 changes: 11 additions & 2 deletions astrbot/builtin_stars/astrbot/long_term_memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
from astrbot.api.provider import LLMResponse, Provider, ProviderRequest
from astrbot.core.astrbot_config_mgr import AstrBotConfigManager

from .constants import LTM_ACTIVE_REPLY_KEY

"""
聊天记忆增强
"""
Expand Down Expand Up @@ -156,15 +158,22 @@ async def on_req_llm(self, event: AstrMessageEvent, req: ProviderRequest) -> Non
chats_str = "\n---\n".join(self.session_chats[event.unified_msg_origin])

cfg = self.cfg(event)
if cfg["enable_active_reply"]:
active_reply_req_id = event.get_extra(LTM_ACTIVE_REPLY_KEY, None)
is_active_reply = (
active_reply_req_id is not None and id(req) == active_reply_req_id
)

if cfg["enable_active_reply"] and is_active_reply:
# 仅在本次请求确实由主动回复触发时,才执行 chatroom 改写
# 避免普通 @ 请求也被错误地清空 req.contexts
prompt = req.prompt
req.prompt = (
f"You are now in a chatroom. The chat history is as follows:\n{chats_str}"
f"\nNow, a new message is coming: `{prompt}`. "
"Please react to it. Only output your response and do not output any other information. "
"You MUST use the SAME language as the chatroom is using."
)
req.contexts = [] # 清空上下文,当使用了主动回复,所有聊天记录都在一个prompt中。
req.contexts = [] # 清空上下文,主动回复时所有聊天记录都在一个 prompt 中
else:
req.system_prompt += (
"You are now in a chatroom. The chat history is as follows: \n"
Expand Down
28 changes: 26 additions & 2 deletions astrbot/builtin_stars/astrbot/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
session_waiter,
)

from .constants import LTM_ACTIVE_REPLY_IN_PROGRESS_KEY, LTM_ACTIVE_REPLY_KEY
from .long_term_memory import LongTermMemory


Expand Down Expand Up @@ -182,11 +183,15 @@ async def on_message(self, event: AstrMessageEvent):
logger.error("未找到对话,无法主动回复")
return

yield event.request_llm(
req = event.request_llm(
prompt=prompt,
session_id=event.session_id,
conversation=conv,
conversation=None, # 主动回复不应写回会话历史,避免 chatroom 内容污染 conv.history
)
event.set_extra(
LTM_ACTIVE_REPLY_KEY, id(req)
) # 存 req 的 id,避免影响其他插件触发的 LLM 请求
yield req
except BaseException as e:
logger.error(traceback.format_exc())
logger.error(f"主动回复失败: {e}")
Expand All @@ -197,6 +202,11 @@ async def decorate_llm_req(
) -> None:
"""在请求 LLM 前注入人格信息、Identifier、时间、回复内容等 System Prompt"""
if self.ltm and self.ltm_enabled(event):
# If this request matches the active reply req id, mark it as in-progress
# so on_llm_response can correctly identify the active reply response
active_reply_req_id = event.get_extra(LTM_ACTIVE_REPLY_KEY, None)
if active_reply_req_id is not None and id(req) == active_reply_req_id:
event.set_extra(LTM_ACTIVE_REPLY_IN_PROGRESS_KEY, True)
try:
await self.ltm.on_req_llm(event, req)
except BaseException as e:
Expand All @@ -208,6 +218,17 @@ async def record_llm_resp_to_ltm(
) -> None:
"""在 LLM 响应后记录对话"""
if self.ltm and self.ltm_enabled(event):
# Skip recording if this response is from an active reply request
if event.get_extra(LTM_ACTIVE_REPLY_IN_PROGRESS_KEY, False):
event.set_extra(
LTM_ACTIVE_REPLY_IN_PROGRESS_KEY, False
) # Clear immediately so subsequent responses are not affected
return
# Only record if group_icl_enable is on, to keep session_chats consistent
# (handle_message is also guarded by group_icl_enable)
cfg = self.context.get_config(umo=event.unified_msg_origin)
if not cfg["provider_ltm_settings"]["group_icl_enable"]:
return
try:
await self.ltm.after_req_llm(event, resp)
except Exception as e:
Expand All @@ -223,3 +244,6 @@ async def after_message_sent(self, event: AstrMessageEvent) -> None:
await self.ltm.remove_session(event)
except Exception as e:
logger.error(f"ltm: {e}")
# 清除主动回复标记,避免 event 被复用时意外影响后续流程
event.set_extra(LTM_ACTIVE_REPLY_KEY, None)
event.set_extra(LTM_ACTIVE_REPLY_IN_PROGRESS_KEY, False)
Loading