Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions astrbot/core/astr_main_agent_resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@
PROACTIVE_AGENT_CRON_WOKE_SYSTEM_PROMPT = (
"You are an autonomous proactive agent.\n\n"
"You are awakened by a scheduled cron job, not by a user message.\n"
"You are given:"
"You are given:\n"
"1. A cron job description explaining why you are activated.\n"
"2. Historical conversation context between you and the user.\n"
"3. Your available tools and skills.\n"
Expand All @@ -121,7 +121,7 @@
"2. Use historical conversation and memory to understand you and user's relationship, preferences, and context.\n"
"3. If messaging the user: Explain WHY you are contacting them; Reference the cron task implicitly (not technical details).\n"
"4. You can use your available tools and skills to finish the task if needed.\n"
"5. Use `send_message_to_user` tool to send message to user if needed."
"5. IMPORTANT: Your text output is NOT visible to the user. The ONLY way to deliver a message to the user is by calling the `send_message_to_user` tool. You MUST call this tool to send any message — do NOT just generate text.\n"
"# CRON JOB CONTEXT\n"
"The following object describes the scheduled task that triggered you:\n"
"{cron_job}"
Expand Down
61 changes: 48 additions & 13 deletions astrbot/core/cron/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -332,10 +332,11 @@ async def _woke_main_agent(
cron_job=cron_job_str
)
req.prompt = (
"You are now responding to a scheduled task. "
"A scheduled task has been triggered. "
"Proceed according to your system instructions. "
"Output using same language as previous conversation. "
"After completing your task, summarize and output your actions and results."
"You MUST call the `send_message_to_user` tool to deliver any message to the user. "
"Your direct text response is NOT visible to the user — only tool calls take effect. "
"Use the same language as the previous conversation."
)
if not req.func_tool:
req.func_tool = ToolSet()
Expand All @@ -353,25 +354,59 @@ async def _woke_main_agent(
# 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}"
cron_job_label = cron_meta.get("name") or cron_meta.get("id", "unknown")

if not llm_resp:
logger.warning("Cron job [%s] agent got no response", cron_job_label)

# 选择工具调用的名字作为日志输出,方便后续分析 cron 任务是否正确触达用户,以及用户收到的内容是什么
called_tool_names: list[str] = []
for msg in runner.run_context.messages:
# 只统计 role="assistant" 的消息中的工具调用
if msg.role == "assistant" and msg.tool_calls:
# 工具调用应该是dict或者ToolCall对象的列表,兼容两者的情况
for tc in msg.tool_calls:
if isinstance(tc, dict):
name = tc.get("function", {}).get("name")
else:
name = tc.function.name
if name:
called_tool_names.append(name)

if not called_tool_names:
logger.warning(
"Cron job [%s] agent did not call any tools. "
"The message was likely NOT delivered to the user.",
cron_job_label,
)

tools_str = (
f"tools called: [{', '.join(called_tool_names)}]. "
if called_tool_names
else "no tools called. "
)
# 根据 llm_resp 判断状态:无响应、正常完成、错误终止
if not llm_resp:
status = "task ended with no LLM response."
elif llm_resp.role == "assistant":
status = "task completed successfully."
else:
status = f"task ended with error: {llm_resp.completion_text}"
summary_note = (
f"[CronJob] {cron_meta.get('name') or cron_meta.get('id', 'unknown')}: "
f"{cron_meta.get('description', '')} "
f"triggered at {cron_meta.get('run_started_at', 'unknown time')}, "
f"{tools_str}"
f"{status}"
)
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


__all__ = ["CronJobManager"]
Loading
Loading