Merge PR #533: feat(cron): add 'at' parameter for one-time scheduled tasks

This commit is contained in:
Re-bin 2026-02-12 06:50:53 +00:00
commit cc427261d9
3 changed files with 27 additions and 5 deletions

View File

@ -73,7 +73,9 @@ Skills with available="false" need dependencies installed first - you can try in
def _get_identity(self) -> str: def _get_identity(self) -> str:
"""Get the core identity section.""" """Get the core identity section."""
from datetime import datetime from datetime import datetime
import time as _time
now = datetime.now().strftime("%Y-%m-%d %H:%M (%A)") now = datetime.now().strftime("%Y-%m-%d %H:%M (%A)")
tz = _time.strftime("%Z") or "UTC"
workspace_path = str(self.workspace.expanduser().resolve()) workspace_path = str(self.workspace.expanduser().resolve())
system = platform.system() system = platform.system()
runtime = f"{'macOS' if system == 'Darwin' else system} {platform.machine()}, Python {platform.python_version()}" runtime = f"{'macOS' if system == 'Darwin' else system} {platform.machine()}, Python {platform.python_version()}"
@ -88,7 +90,7 @@ You are nanobot, a helpful AI assistant. You have access to tools that allow you
- Spawn subagents for complex background tasks - Spawn subagents for complex background tasks
## Current Time ## Current Time
{now} {now} ({tz})
## Runtime ## Runtime
{runtime} {runtime}

View File

@ -50,6 +50,10 @@ class CronTool(Tool):
"type": "string", "type": "string",
"description": "Cron expression like '0 9 * * *' (for scheduled tasks)" "description": "Cron expression like '0 9 * * *' (for scheduled tasks)"
}, },
"at": {
"type": "string",
"description": "ISO datetime for one-time execution (e.g. '2026-02-12T10:30:00')"
},
"job_id": { "job_id": {
"type": "string", "type": "string",
"description": "Job ID (for remove)" "description": "Job ID (for remove)"
@ -64,30 +68,38 @@ class CronTool(Tool):
message: str = "", message: str = "",
every_seconds: int | None = None, every_seconds: int | None = None,
cron_expr: str | None = None, cron_expr: str | None = None,
at: str | None = None,
job_id: str | None = None, job_id: str | None = None,
**kwargs: Any **kwargs: Any
) -> str: ) -> str:
if action == "add": if action == "add":
return self._add_job(message, every_seconds, cron_expr) return self._add_job(message, every_seconds, cron_expr, at)
elif action == "list": elif action == "list":
return self._list_jobs() return self._list_jobs()
elif action == "remove": elif action == "remove":
return self._remove_job(job_id) return self._remove_job(job_id)
return f"Unknown action: {action}" return f"Unknown action: {action}"
def _add_job(self, message: str, every_seconds: int | None, cron_expr: str | None) -> str: def _add_job(self, message: str, every_seconds: int | None, cron_expr: str | None, at: str | None) -> str:
if not message: if not message:
return "Error: message is required for add" return "Error: message is required for add"
if not self._channel or not self._chat_id: if not self._channel or not self._chat_id:
return "Error: no session context (channel/chat_id)" return "Error: no session context (channel/chat_id)"
# Build schedule # Build schedule
delete_after = False
if every_seconds: if every_seconds:
schedule = CronSchedule(kind="every", every_ms=every_seconds * 1000) schedule = CronSchedule(kind="every", every_ms=every_seconds * 1000)
elif cron_expr: elif cron_expr:
schedule = CronSchedule(kind="cron", expr=cron_expr) schedule = CronSchedule(kind="cron", expr=cron_expr)
elif at:
from datetime import datetime
dt = datetime.fromisoformat(at)
at_ms = int(dt.timestamp() * 1000)
schedule = CronSchedule(kind="at", at_ms=at_ms)
delete_after = True
else: else:
return "Error: either every_seconds or cron_expr is required" return "Error: either every_seconds, cron_expr, or at is required"
job = self._cron.add_job( job = self._cron.add_job(
name=message[:30], name=message[:30],
@ -96,6 +108,7 @@ class CronTool(Tool):
deliver=True, deliver=True,
channel=self._channel, channel=self._channel,
to=self._chat_id, to=self._chat_id,
delete_after_run=delete_after,
) )
return f"Created job '{job.name}' (id: {job.id})" return f"Created job '{job.name}' (id: {job.id})"

View File

@ -7,10 +7,11 @@ description: Schedule reminders and recurring tasks.
Use the `cron` tool to schedule reminders or recurring tasks. Use the `cron` tool to schedule reminders or recurring tasks.
## Two Modes ## Three Modes
1. **Reminder** - message is sent directly to user 1. **Reminder** - message is sent directly to user
2. **Task** - message is a task description, agent executes and sends result 2. **Task** - message is a task description, agent executes and sends result
3. **One-time** - runs once at a specific time, then auto-deletes
## Examples ## Examples
@ -24,6 +25,11 @@ Dynamic task (agent executes each time):
cron(action="add", message="Check HKUDS/nanobot GitHub stars and report", every_seconds=600) cron(action="add", message="Check HKUDS/nanobot GitHub stars and report", every_seconds=600)
``` ```
One-time scheduled task (compute ISO datetime from current time):
```
cron(action="add", message="Remind me about the meeting", at="<ISO datetime>")
```
List/remove: List/remove:
``` ```
cron(action="list") cron(action="list")
@ -38,3 +44,4 @@ cron(action="remove", job_id="abc123")
| every hour | every_seconds: 3600 | | every hour | every_seconds: 3600 |
| every day at 8am | cron_expr: "0 8 * * *" | | every day at 8am | cron_expr: "0 8 * * *" |
| weekdays at 5pm | cron_expr: "0 17 * * 1-5" | | weekdays at 5pm | cron_expr: "0 17 * * 1-5" |
| at a specific time | at: ISO datetime string (compute from current time) |