diff --git a/astrbot/core/agent/runners/tool_loop_agent_runner.py b/astrbot/core/agent/runners/tool_loop_agent_runner.py index 3d492783e..03d53427f 100644 --- a/astrbot/core/agent/runners/tool_loop_agent_runner.py +++ b/astrbot/core/agent/runners/tool_loop_agent_runner.py @@ -569,6 +569,7 @@ class ToolLoopAgentRunner(BaseAgentRunner[TContext]): ) ], ) + logger.info(f"Tool `{func_tool_name}` Result: {last_tcr_content}") # 处理函数调用响应 if tool_call_result_blocks: diff --git a/astrbot/core/astr_main_agent_resources.py b/astrbot/core/astr_main_agent_resources.py index 37bf318e3..779f0d0c3 100644 --- a/astrbot/core/astr_main_agent_resources.py +++ b/astrbot/core/astr_main_agent_resources.py @@ -3,6 +3,7 @@ import base64 from pydantic import Field from pydantic.dataclasses import dataclass +import astrbot.core.message.components as Comp from astrbot.api import logger, sp from astrbot.core.agent.run_context import ContextWrapper from astrbot.core.agent.tool import FunctionTool, ToolExecResult @@ -183,12 +184,15 @@ class SendMessageToUserTool(FunctionTool[AstrAgentContext]): "type": "string", "description": "What you want to tell the user.", }, + "image_path": { + "type": "string", + "description": "Optional. Send an image to the user by specifying the file path. Use an absolute path when possible; otherwise, ensure the path is relative to `data/`.", + }, "session": { "type": "string", "description": "Optional target session in format platform_id:message_type:session_id. Defaults to current session.", }, }, - "required": ["message"], } ) @@ -196,11 +200,19 @@ class SendMessageToUserTool(FunctionTool[AstrAgentContext]): self, context: ContextWrapper[AstrAgentContext], **kwargs ) -> ToolExecResult: message = str(kwargs.get("message", "")).strip() + image_path = kwargs.get("image_path") session = kwargs.get("session") or context.context.event.unified_msg_origin - if not message: + if not message and not image_path: return "error: message is empty." + comps: list[Comp.BaseMessageComponent] = [] + + if message: + comps.append(Comp.Plain(text=message)) + if image_path: + comps.append(Comp.Image.fromFileSystem(path=image_path)) + try: target_session = ( MessageSession.from_str(session) @@ -212,7 +224,7 @@ class SendMessageToUserTool(FunctionTool[AstrAgentContext]): await context.context.context.send_message( target_session, - MessageChain().message(message), + MessageChain(chain=comps), ) return f"Message sent to session {target_session}" diff --git a/astrbot/core/db/po.py b/astrbot/core/db/po.py index 8068864d0..d676fe845 100644 --- a/astrbot/core/db/po.py +++ b/astrbot/core/db/po.py @@ -159,7 +159,7 @@ class CronJob(TimestampMixin, SQLModel, table=True): description: str | None = Field(default=None, sa_type=Text) job_type: str = Field( max_length=32, nullable=False - ) # basic | active_agent | background + ) # 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) diff --git a/astrbot/core/skills/skill_manager.py b/astrbot/core/skills/skill_manager.py index 6e53e751e..1e6f01a6d 100644 --- a/astrbot/core/skills/skill_manager.py +++ b/astrbot/core/skills/skill_manager.py @@ -62,6 +62,7 @@ def build_skills_prompt(skills: list[SkillInfo]) -> str: # Based on openai/codex return ( "## Skills\n" + "You have many useful skills that can help you accomplish various tasks.\n" "A skill is a set of local instructions stored in a `SKILL.md` file.\n" "### Available skills\n" f"{skills_block}\n" @@ -69,21 +70,21 @@ def build_skills_prompt(skills: list[SkillInfo]) -> str: "\n" "- Discovery: The list above shows all skills available in this session. Full instructions live in the referenced `SKILL.md`.\n" "- Trigger rules: Use a skill if the user names it or the task matches its description. Do not carry skills across turns unless re-mentioned\n" - "- Unavailable: If a skill is missing or unreadable, say so and fallback.\n" "### How to use a skill (progressive disclosure):\n" - " 1) After deciding to use a skill, open its `SKILL.md` and read only what is necessary to follow the workflow.\n" - " 2) Load only directly referenced files, DO NOT bulk-load everything.\n" - " 3) If `scripts/` exist, prefer running or patching them instead of retyping large blocks of code.\n" - " 4) If `assets/` or templates exist, reuse them rather than recreating everything from scratch.\n" + " 0) Mandatory grounding: Before using any skill, you MUST inspect its `SKILL.md` using shell tools" + " (e.g., `cat`, `head`, `sed`, `awk`, `grep`). Do not rely on assumptions or memory.\n" + " 1) Load only directly referenced files, DO NOT bulk-load everything.\n" + " 2) If `scripts/` exist, prefer running or patching them instead of retyping large blocks of code.\n" + " 3) If `assets/` or templates exist, reuse them rather than recreating everything from scratch.\n" "- Coordination:\n" " - If multiple skills apply, choose the minimal set that covers the request and state the order in which you will use them.\n" " - Announce which skill(s) you are using and why (one short line). If you skip an obvious skill, explain why.\n" " - Prefer to use `astrbot_*` tools to perform skills that need to run scripts.\n" "- Context hygiene:\n" - " - Keep context small: summarize long sections instead of pasting them, and load extra files only when necessary.\n" " - Avoid deep reference chasing: unless blocked, open only files that are directly linked from `SKILL.md`.\n" - " - When variants exist (frameworks, providers, domains), select only the relevant reference file(s) and note that choice.\n" - "- Failure handling: If a skill cannot be applied, state the issue and continue with the best alternative." + "- Failure handling: If a skill cannot be applied, state the issue and continue with the best alternative.\n" + "### Example\n" + "When you decided to use a skill, use shell tool to read its `SKILL.md`, e.g., `head -40 skills/code_formatter/SKILL.md`, and you can increase or decrease the number of lines as needed.\n" ) diff --git a/astrbot/core/tools/cron_tools.py b/astrbot/core/tools/cron_tools.py index c4259aebd..a605e8e77 100644 --- a/astrbot/core/tools/cron_tools.py +++ b/astrbot/core/tools/cron_tools.py @@ -62,7 +62,7 @@ class CreateActiveCronTool(FunctionTool[AstrAgentContext]): next_run = job.next_run_time return ( f"Scheduled future task {job.job_id} ({job.name}) with expression '{cron_expression}'. " - f"Your future agent will wake at: {next_run}" + f"You will be awakened at: {next_run}" ) diff --git a/astrbot/dashboard/routes/cron.py b/astrbot/dashboard/routes/cron.py index df3110770..80c692684 100644 --- a/astrbot/dashboard/routes/cron.py +++ b/astrbot/dashboard/routes/cron.py @@ -28,6 +28,11 @@ class CronRoute(Route): for k in ["created_at", "updated_at", "last_run_at", "next_run_time"]: if isinstance(data.get(k), datetime): data[k] = data[k].isoformat() + # expose note explicitly for UI (prefer payload.note then description) + payload = data.get("payload") or {} + data["note"] = payload.get("note") or data.get("description") or "" + # status is internal; hide to avoid implying one-time completion for recurring jobs + data.pop("status", None) return data async def list_jobs(self): diff --git a/dashboard/src/i18n/locales/en-US/core/navigation.json b/dashboard/src/i18n/locales/en-US/core/navigation.json index 86828377a..ada9315df 100644 --- a/dashboard/src/i18n/locales/en-US/core/navigation.json +++ b/dashboard/src/i18n/locales/en-US/core/navigation.json @@ -8,7 +8,7 @@ "toolUse": "MCP Tools", "config": "Config", "chat": "Chat", - "cron": "Cron Jobs", + "cron": "Future Tasks", "extension": "Extensions", "conversation": "Conversations", "sessionManagement": "Custom Rules", diff --git a/dashboard/src/i18n/locales/zh-CN/core/navigation.json b/dashboard/src/i18n/locales/zh-CN/core/navigation.json index cfeb42681..58b5c81d5 100644 --- a/dashboard/src/i18n/locales/zh-CN/core/navigation.json +++ b/dashboard/src/i18n/locales/zh-CN/core/navigation.json @@ -9,7 +9,7 @@ "extension": "插件", "config": "配置文件", "chat": "聊天", - "cron": "定时任务", + "cron": "未来任务", "conversation": "对话数据", "sessionManagement": "自定义规则", "console": "平台日志", diff --git a/dashboard/src/views/CronJobPage.vue b/dashboard/src/views/CronJobPage.vue index ac205bb0f..08c9e8703 100644 --- a/dashboard/src/views/CronJobPage.vue +++ b/dashboard/src/views/CronJobPage.vue @@ -2,58 +2,21 @@
-

Cron Job 管理

-
查看、创建与管理定时任务(ActiveAgent & 后台任务)。
+

未来任务管理

+
查看给 AstrBot 布置的未来任务。AstrBot 将会被自动唤醒、执行任务,然后将结果告知任务布置方。
刷新
- - -
新建主动型 Agent 定时任务
- - - - - - -
使用标准 5 段 Cron,例:0 8 * * * 表示每天 8:00。
-
- - -
从聊天侧栏或 Session 管理中复制 unified_msg_origin。
-
- - - - - - - - - - - - - - - - - 创建任务 - -
-
-
-
已注册任务
- 暂无定时任务。 + 暂无任务。 {{ item.timezone || 'local' }}
- + +