diff --git a/integration-tests/cron-tools.test.ts b/integration-tests/cron-tools.test.ts index 6a69ffa30..485eec1f2 100644 --- a/integration-tests/cron-tools.test.ts +++ b/integration-tests/cron-tools.test.ts @@ -65,7 +65,7 @@ describe('cron-tools', () => { }); const result = await rig.run( - 'Call cron_create with cron_expression "*/5 * * * *", prompt "test ping", recurring true. Then call cron_list. Then delete that job using cron_delete. Then call cron_list again. How many jobs remain? Reply with just the number.', + 'Call cron_create with cron "*/5 * * * *", prompt "test ping", recurring true. Then call cron_list. Then delete that job using cron_delete. Then call cron_list again. How many jobs remain? Reply with just the number.', ); const foundCreate = await rig.waitForToolCall('cron_create'); @@ -94,7 +94,7 @@ describe('cron-tools', () => { }); const result = await rig.run( - 'Do these steps: (1) Call cron_create with cron_expression "*/5 * * * *", prompt "one-shot test", recurring false. (2) Call cron_list. Is the job marked as recurring or one-shot? Remember the answer. (3) Delete all cron jobs. Reply with just "recurring" or "one-shot".', + 'Do these steps: (1) Call cron_create with cron "*/5 * * * *", prompt "one-shot test", recurring false. (2) Call cron_list. Is the job marked as recurring or one-shot? Remember the answer. (3) Delete all cron jobs. Reply with just "recurring" or "one-shot".', ); const foundCreate = await rig.waitForToolCall('cron_create'); diff --git a/packages/core/src/skills/bundled/loop/SKILL.md b/packages/core/src/skills/bundled/loop/SKILL.md index 0b0969eca..074ff02ae 100644 --- a/packages/core/src/skills/bundled/loop/SKILL.md +++ b/packages/core/src/skills/bundled/loop/SKILL.md @@ -29,7 +29,7 @@ You are setting up a recurring in-session loop. Parse the user's input to extrac 2. Convert the interval to a cron expression 3. Append to the prompt: `\n\nBe concise. If nothing has changed, reply with a single short sentence.` 4. Call `cron_create` with: - - `cron_expression`: the computed cron expression + - `cron`: the computed cron expression - `prompt`: the extracted prompt with the conciseness instruction appended - `recurring`: true 5. Confirm to the user: "Loop created — I'll [description] every [interval]." diff --git a/packages/core/src/tools/cron-create.test.ts b/packages/core/src/tools/cron-create.test.ts index a44eae733..74145f424 100644 --- a/packages/core/src/tools/cron-create.test.ts +++ b/packages/core/src/tools/cron-create.test.ts @@ -27,7 +27,7 @@ describe('CronCreateTool', () => { it('creates a recurring job by default', async () => { const invocation = tool.build({ - cron_expression: '*/5 * * * *', + cron: '*/5 * * * *', prompt: 'check status', }); const result = await invocation.execute(new AbortController().signal); @@ -39,7 +39,7 @@ describe('CronCreateTool', () => { it('creates a one-shot job when recurring=false', async () => { const invocation = tool.build({ - cron_expression: '*/1 * * * *', + cron: '*/1 * * * *', prompt: 'once', recurring: false, }); @@ -53,7 +53,7 @@ describe('CronCreateTool', () => { it('returns error for invalid cron expression', async () => { const invocation = tool.build({ - cron_expression: 'bad cron', + cron: 'bad cron', prompt: 'fail', }); const result = await invocation.execute(new AbortController().signal); @@ -61,9 +61,7 @@ describe('CronCreateTool', () => { }); it('validates required params', () => { - expect(() => - tool.build({ cron_expression: '*/1 * * * *' } as never), - ).toThrow(); + expect(() => tool.build({ cron: '*/1 * * * *' } as never)).toThrow(); expect(() => tool.build({ prompt: 'test' } as never)).toThrow(); }); }); diff --git a/packages/core/src/tools/cron-create.ts b/packages/core/src/tools/cron-create.ts index cdfaba286..94edff3b3 100644 --- a/packages/core/src/tools/cron-create.ts +++ b/packages/core/src/tools/cron-create.ts @@ -9,7 +9,7 @@ import type { Config } from '../config/config.js'; import { nextFireTime } from '../utils/cronParser.js'; export interface CronCreateParams { - cron_expression: string; + cron: string; prompt: string; recurring?: boolean; } @@ -28,7 +28,7 @@ class CronCreateInvocation extends BaseToolInvocation< getDescription(): string { const recurrence = this.params.recurring !== false ? 'recurring' : 'one-shot'; - return `Create ${recurrence} cron job: ${this.params.cron_expression}`; + return `Create ${recurrence} cron job: ${this.params.cron}`; } async execute(): Promise { @@ -37,12 +37,12 @@ class CronCreateInvocation extends BaseToolInvocation< try { const job = scheduler.create( - this.params.cron_expression, + this.params.cron, this.params.prompt, recurring, ); - const next = nextFireTime(this.params.cron_expression, new Date()); + const next = nextFireTime(this.params.cron, new Date()); const result = [ `Created ${recurring ? 'recurring' : 'one-shot'} cron job.`, ` ID: ${job.id}`, @@ -76,34 +76,49 @@ export class CronCreateTool extends BaseDeclarativeTool< super( CronCreateTool.Name, ToolDisplayNames.CRON_CREATE, - 'Create a new in-session cron job that fires a prompt on a schedule. ' + - 'The job runs within the current session and is gone when the session ends. ' + - 'Use standard 5-field cron expressions (minute hour day-of-month month day-of-week). ' + - 'Examples: "*/5 * * * *" (every 5 min), "0 */2 * * *" (every 2 hours), "*/1 * * * *" (every minute).', + 'Schedule a prompt to be enqueued at a future time. Use for both recurring schedules and one-shot reminders.\n\n' + + 'Uses standard 5-field cron in the user\'s local timezone: minute hour day-of-month month day-of-week. "0 9 * * *" means 9am local — no timezone conversion needed.\n\n' + + '## One-shot tasks (recurring: false)\n\n' + + 'For "remind me at X" or "at