feat: implement history persistence for agent interactions and enhance cron job permission handling

This commit is contained in:
Soulter
2026-02-01 17:42:08 +08:00
parent bddf7b8623
commit 193676012f
5 changed files with 82 additions and 6 deletions
+19
View File
@@ -28,6 +28,7 @@ from astrbot.core.message.message_event_result import (
from astrbot.core.platform.message_session import MessageSession
from astrbot.core.provider.entites import ProviderRequest
from astrbot.core.provider.register import llm_tools
from astrbot.core.utils.history_saver import persist_agent_history
class FunctionToolExecutor(BaseFunctionToolExecutor[AstrAgentContext]):
@@ -199,6 +200,7 @@ class FunctionToolExecutor(BaseFunctionToolExecutor[AstrAgentContext]):
extras=extras,
message_type=session.message_type,
)
cron_event.role = event.role
config = MainAgentBuildConfig(tool_call_timeout=3600)
req = ProviderRequest()
@@ -221,6 +223,7 @@ class FunctionToolExecutor(BaseFunctionToolExecutor[AstrAgentContext]):
req.prompt = (
"Proceed according to your system instructions. "
"Output using same language as previous conversation."
" After completing your task, summarize and output your actions and results."
)
if not req.func_tool:
req.func_tool = ToolSet()
@@ -238,6 +241,22 @@ class FunctionToolExecutor(BaseFunctionToolExecutor[AstrAgentContext]):
# agent will send message to user via using tools
pass
llm_resp = runner.get_final_llm_resp()
task_meta = extras.get("background_task_result", {})
summary_note = (
f"[BackgroundTask] {task_meta.get('tool_name', tool.name)} "
f"(task_id={task_meta.get('task_id', task_id)}) finished. "
f"Result: {task_meta.get('result') or result_text or 'no content'}"
)
if llm_resp and llm_resp.completion_text:
summary_note += (
f"I finished the task, here is the result: {llm_resp.completion_text}"
)
await persist_agent_history(
ctx.conversation_manager,
event=cron_event,
req=req,
summary_note=summary_note,
)
if not llm_resp:
logger.warning("background task agent got no response")
return
+1 -1
View File
@@ -31,9 +31,9 @@ from astrbot.core.astr_main_agent_resources import (
LOCAL_PYTHON_TOOL,
PYTHON_TOOL,
SANDBOX_MODE_PROMPT,
SEND_MESSAGE_TO_USER_TOOL,
TOOL_CALL_PROMPT,
TOOL_CALL_PROMPT_SKILLS_LIKE_MODE,
SEND_MESSAGE_TO_USER_TOOL,
retrieve_knowledge_base,
)
from astrbot.core.conversation_mgr import Conversation
+30 -2
View File
@@ -15,6 +15,7 @@ from astrbot.core.db import BaseDatabase
from astrbot.core.db.po import CronJob
from astrbot.core.platform.message_session import MessageSession
from astrbot.core.provider.entites import ProviderRequest
from astrbot.core.utils.history_saver import persist_agent_history
if TYPE_CHECKING:
from astrbot.core.star.context import Context
@@ -182,7 +183,7 @@ class CronJobManager:
if job.job_type == "basic":
await self._run_basic_job(job)
elif job.job_type == "active_agent":
await self._run_active_agent_job(job)
await self._run_active_agent_job(job, start_time=start_time)
else:
raise ValueError(f"Unknown cron job type: {job.job_type}")
except Exception as e: # noqa: BLE001
@@ -208,7 +209,7 @@ class CronJobManager:
if asyncio.iscoroutine(result):
await result
async def _run_active_agent_job(self, job: CronJob):
async def _run_active_agent_job(self, job: CronJob, start_time: datetime):
payload = job.payload or {}
session_str = payload.get("session")
if not session_str:
@@ -222,6 +223,7 @@ class CronJobManager:
"type": job.job_type,
"description": job.description,
"note": note,
"run_started_at": start_time.isoformat(),
},
"cron_payload": payload,
}
@@ -268,6 +270,15 @@ class CronJobManager:
message_type=session.message_type,
)
# judge user's role
umo = cron_event.unified_msg_origin
cfg = self.ctx.get_config(umo=umo)
admin_ids = cfg.get("admins_id", [])
if admin_ids:
cron_event.role = (
"admin" if cron_event.get_sender_id() in admin_ids else "member"
)
config = MainAgentBuildConfig(
tool_call_timeout=3600,
llm_safety_mode=False,
@@ -295,6 +306,7 @@ class CronJobManager:
"You are now responding to a scheduled task"
"Proceed according to your system instructions. "
"Output using same language as previous conversation."
"After completing your task, summarize and output your actions and results."
)
if not req.func_tool:
req.func_tool = ToolSet()
@@ -312,6 +324,22 @@ class CronJobManager:
# agent will send message to user via using tools
pass
llm_resp = runner.get_final_llm_resp()
cron_meta = extras.get("cron_job", {}) if extras else {}
summary_note = (
f"[CronJob] {cron_meta.get('name') or cron_meta.get('id', 'unknown')}: {cron_meta.get('description', '')} "
f" triggered at {cron_meta.get('run_started_at', 'unknown time')}, "
)
if llm_resp and llm_resp.role == "assistant":
summary_note += (
f"I finished this job, here is the result: {llm_resp.completion_text}"
)
await persist_agent_history(
self.ctx.conversation_manager,
event=cron_event,
req=req,
summary_note=summary_note,
)
if not llm_resp:
logger.warning("Cron job agent got no response")
return
+1 -3
View File
@@ -157,9 +157,7 @@ class CronJob(TimestampMixin, SQLModel, table=True):
)
name: str = Field(max_length=255, nullable=False)
description: str | None = Field(default=None, sa_type=Text)
job_type: str = Field(
max_length=32, nullable=False
) # basic | active_agent
job_type: str = Field(max_length=32, nullable=False) # basic | active_agent
cron_expression: str | None = Field(default=None, max_length=255)
timezone: str | None = Field(default=None, max_length=64)
payload: dict = Field(default_factory=dict, sa_type=JSON)
+31
View File
@@ -0,0 +1,31 @@
import json
from astrbot import logger
from astrbot.core.conversation_mgr import ConversationManager
from astrbot.core.platform.astr_message_event import AstrMessageEvent
from astrbot.core.provider.entities import ProviderRequest
async def persist_agent_history(
conversation_manager: ConversationManager,
*,
event: AstrMessageEvent,
req: ProviderRequest,
summary_note: str,
) -> None:
"""Persist agent interaction into conversation history."""
if not req or not req.conversation:
return
history = []
try:
history = json.loads(req.conversation.history or "[]")
except Exception as exc: # noqa: BLE001
logger.warning("Failed to parse conversation history: %s", exc)
history.append({"role": "user", "content": "Output your last task result below."})
history.append({"role": "assistant", "content": summary_note})
await conversation_manager.update_conversation(
event.unified_msg_origin,
req.conversation.cid,
history=history,
)