fix: wire up cron job --deliver flag to actually deliver responses (#290)
Co-authored-by: letta-code <248085862+letta-code@users.noreply.github.com> Co-authored-by: Cameron <cpfiffer@users.noreply.github.com> Co-authored-by: Cameron <cameron@pfiffer.org>
This commit is contained in:
committed by
GitHub
parent
6ef987a04f
commit
b6bfd14cd9
@@ -5,7 +5,7 @@ description: Create and manage scheduled tasks (cron jobs) that send you message
|
||||
|
||||
# Cron Jobs
|
||||
|
||||
Schedule tasks that send you messages at specified times. Jobs are scheduled immediately when created.
|
||||
Schedule tasks that send messages to the agent at specified times. Jobs are scheduled immediately when created.
|
||||
|
||||
## Quick Reference
|
||||
|
||||
@@ -30,20 +30,27 @@ lettabot-cron create \
|
||||
**Options:**
|
||||
- `-n, --name` - Job name (required)
|
||||
- `-s, --schedule` - Cron expression (required)
|
||||
- `-m, --message` - Message sent to you when job runs (required)
|
||||
- `-d, --deliver` - Where to send response (format: `channel:chatId`). **Defaults to last messaged chat.**
|
||||
- `--disabled` - Create disabled
|
||||
- `-m, --message` - Prompt sent to the agent when the job fires (required)
|
||||
- `-d, --deliver` - Auto-deliver the agent's response to a channel (format: `channel:chatId`). Without this flag, the job runs in **silent mode** (see below).
|
||||
- `--disabled` - Create in disabled state
|
||||
|
||||
## Silent Mode vs Delivery Mode
|
||||
|
||||
Cron jobs run in one of two modes:
|
||||
|
||||
- **Silent mode** (no `--deliver`): The agent receives the message and can act on it (e.g., update memory, run tools), but the response is NOT automatically sent to any chat. If the agent wants to send a message, it must explicitly use `lettabot-message send`.
|
||||
- **Delivery mode** (`--deliver channel:chatId`): The agent's response is automatically delivered to the specified channel/chat after execution.
|
||||
|
||||
## Message Format
|
||||
|
||||
When a cron job runs, you receive a message like:
|
||||
When a cron job runs, the agent receives a message like:
|
||||
|
||||
```
|
||||
[cron:cron-123abc Morning Briefing] Good morning! Review tasks for today.
|
||||
Current time: 1/27/2026, 8:00:00 AM (America/Los_Angeles)
|
||||
```
|
||||
|
||||
This tells you:
|
||||
This tells the agent:
|
||||
- The message came from a cron job (not a user)
|
||||
- The job ID and name
|
||||
- The current time
|
||||
@@ -87,9 +94,18 @@ lettabot-cron create \
|
||||
-d slack:C1234567890
|
||||
```
|
||||
|
||||
**Background task (silent mode - agent acts but no auto-delivery):**
|
||||
```bash
|
||||
lettabot-cron create \
|
||||
-n "Email Check" \
|
||||
-s "0 */2 * * *" \
|
||||
-m "Check for new emails and summarize anything important."
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Jobs schedule immediately when created (no restart needed)
|
||||
- Use `lettabot-cron list` to see next run times and last run status
|
||||
- Jobs persist in `cron-jobs.json`
|
||||
- Logs written to `cron-log.jsonl`
|
||||
- Without `--deliver`, the agent must use `lettabot-message send` to communicate results to users
|
||||
|
||||
@@ -191,7 +191,17 @@ function createJob(args: string[]): void {
|
||||
enabled = false;
|
||||
} else if ((arg === '--deliver' || arg === '-d') && next) {
|
||||
// Format: channel:chatId (e.g., telegram:123456789 or discord:123456789012345678)
|
||||
const [ch, id] = next.split(':');
|
||||
const [ch, ...rest] = next.split(':');
|
||||
const id = rest.join(':'); // Rejoin in case chatId contains colons
|
||||
const validChannels = ['telegram', 'telegram-mtproto', 'slack', 'discord', 'whatsapp', 'signal'];
|
||||
if (!validChannels.includes(ch)) {
|
||||
console.error(`Error: invalid channel "${ch}". Must be one of: ${validChannels.join(', ')}`);
|
||||
process.exit(1);
|
||||
}
|
||||
if (!id) {
|
||||
console.error('Error: --deliver requires format channel:chatId (e.g., telegram:123456789)');
|
||||
process.exit(1);
|
||||
}
|
||||
deliverChannel = ch;
|
||||
deliverChatId = id;
|
||||
i++;
|
||||
@@ -349,8 +359,8 @@ Create options:
|
||||
--name, -n <name> Task name (required)
|
||||
--schedule, -s <cron> Cron expression for recurring tasks
|
||||
--at, -a <datetime> ISO datetime for one-off reminder (auto-deletes after)
|
||||
--message, -m <msg> Message to send (required)
|
||||
--deliver, -d <target> Delivery target (channel:chatId)
|
||||
--message, -m <msg> Prompt sent to agent when job fires (required)
|
||||
--deliver, -d <target> Auto-deliver response to channel:chatId (omit for silent mode)
|
||||
--disabled Create in disabled state
|
||||
|
||||
Examples:
|
||||
|
||||
@@ -390,10 +390,27 @@ export class CronService {
|
||||
`Current time: ${formattedTime} (${timezone})`,
|
||||
].join('\n');
|
||||
|
||||
// Send message to agent (SILENT MODE - response NOT auto-delivered)
|
||||
// Agent must use `lettabot-message` CLI to send messages explicitly
|
||||
// Send message to agent
|
||||
const response = await this.bot.sendToAgent(messageWithMetadata);
|
||||
|
||||
// Deliver response to channel if configured
|
||||
const deliverMode = job.deliver ? 'deliver' : 'silent';
|
||||
if (job.deliver && response) {
|
||||
try {
|
||||
await this.bot.deliverToChannel(job.deliver.channel, job.deliver.chatId, { text: response });
|
||||
console.log(`[Cron] 📬 Delivered response to ${job.deliver.channel}:${job.deliver.chatId}`);
|
||||
} catch (deliverError) {
|
||||
console.error(`[Cron] Failed to deliver response to ${job.deliver.channel}:${job.deliver.chatId}:`, deliverError);
|
||||
logEvent('job_deliver_failed', {
|
||||
id: job.id,
|
||||
name: job.name,
|
||||
channel: job.deliver.channel,
|
||||
chatId: job.deliver.chatId,
|
||||
error: deliverError instanceof Error ? deliverError.message : String(deliverError),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Update state
|
||||
job.state.lastRunAt = new Date();
|
||||
job.state.lastStatus = 'ok';
|
||||
@@ -410,16 +427,21 @@ export class CronService {
|
||||
}
|
||||
|
||||
console.log(`\n${'='.repeat(50)}`);
|
||||
console.log(`[Cron] ✅ JOB COMPLETED: ${job.name} [SILENT MODE]`);
|
||||
console.log(`[Cron] ✅ JOB COMPLETED: ${job.name} [${deliverMode.toUpperCase()} MODE]`);
|
||||
console.log(` Response: ${response?.slice(0, 200)}${(response?.length || 0) > 200 ? '...' : ''}`);
|
||||
if (deliverMode === 'silent') {
|
||||
console.log(` (Response NOT auto-delivered - agent uses lettabot-message CLI)`);
|
||||
} else {
|
||||
console.log(` (Response delivered to ${job.deliver!.channel}:${job.deliver!.chatId})`);
|
||||
}
|
||||
console.log(`${'='.repeat(50)}\n`);
|
||||
|
||||
logEvent('job_completed', {
|
||||
id: job.id,
|
||||
name: job.name,
|
||||
status: 'ok',
|
||||
mode: 'silent',
|
||||
mode: deliverMode,
|
||||
deliverTarget: job.deliver ? `${job.deliver.channel}:${job.deliver.chatId}` : undefined,
|
||||
nextRun: job.state.nextRunAt?.toISOString(),
|
||||
responseLength: response?.length || 0,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user