From 75c9496cd2e6432ca3edc1b92ebaaf2ce6e3cc78 Mon Sep 17 00:00:00 2001 From: Simon KP Date: Tue, 27 Jan 2026 10:16:20 +1100 Subject: [PATCH] fix(checkins): use systemEvent for cron triggers instead of agentTurn Isolated agent sessions load plugins fresh with storage=null, causing the tool factory to return null and no tools to be available. The agent then outputs XML-like text instead of making proper tool calls. Switch cron jobs to use systemEvent payload which runs in the main gateway process where storage IS initialized. The message_received hook already handles [system] checkins:trigger: and checkins:cleanup: events. --- extensions/checkins/src/cleanup.ts | 8 ++++---- extensions/checkins/src/scheduler.ts | 21 ++++++--------------- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/extensions/checkins/src/cleanup.ts b/extensions/checkins/src/cleanup.ts index 1bae2a03e..5d7e84ec0 100644 --- a/extensions/checkins/src/cleanup.ts +++ b/extensions/checkins/src/cleanup.ts @@ -59,6 +59,7 @@ export function buildCleanupCronJobs(storage: CheckinsStorage): CronJobCreate[] } // Build cleanup job for each timezone + // Use systemEvent to run in main gateway process (has access to initialized storage) const jobs: CronJobCreate[] = []; for (const tz of timezones) { jobs.push({ @@ -70,12 +71,11 @@ export function buildCleanupCronJobs(storage: CheckinsStorage): CronJobCreate[] expr: "5 0 * * *", // 00:05 (5 minutes past midnight per RESEARCH.md) tz, }, - sessionTarget: "isolated", + sessionTarget: "main", wakeMode: "now", payload: { - kind: "agentTurn", - message: `[system] checkins:cleanup:${tz}`, - deliver: false, + kind: "systemEvent", + text: `[system] checkins:cleanup:${tz}`, }, }); } diff --git a/extensions/checkins/src/scheduler.ts b/extensions/checkins/src/scheduler.ts index 726f77b5b..2e3e1881b 100644 --- a/extensions/checkins/src/scheduler.ts +++ b/extensions/checkins/src/scheduler.ts @@ -32,17 +32,8 @@ export function getCheckInJobId(memberId: string): string { * @returns CronJobCreate configuration */ export function buildCheckInCronJob(member: Member, team: Team): CronJobCreate { - // Build a clear instruction for the agent to call the trigger tool - const triggerMessage = [ - "SCHEDULED CHECK-IN TRIGGER", - "", - "You must call the checkins_trigger tool with these exact parameters:", - ` memberId: "${member.id}"`, - ` teamId: "${team.id}"`, - "", - "Do not respond with any other message. Just call the tool.", - ].join("\n"); - + // Use systemEvent to trigger check-in via the main gateway process + // This avoids isolated agent sessions which don't have initialized plugin storage return { name: `Check-in: ${member.displayName ?? member.discordUserId}`, description: `Daily check-in for team ${team.name}`, @@ -52,12 +43,12 @@ export function buildCheckInCronJob(member: Member, team: Team): CronJobCreate { expr: convertTimeToCronExpr(member.schedule.checkInTime), tz: member.schedule.timezone, }, - sessionTarget: "isolated", + // sessionTarget is auto-set to "main" for systemEvent payloads + sessionTarget: "main", wakeMode: "now", payload: { - kind: "agentTurn", - message: triggerMessage, - deliver: false, + kind: "systemEvent", + text: `[system] checkins:trigger:${member.id}:${team.id}`, }, }; }