From f0999263a024bbd3df273b071927f8511db96542 Mon Sep 17 00:00:00 2001 From: sepehr Date: Sun, 26 Apr 2026 13:00:55 +0200 Subject: [PATCH] fix: remove nextRun recalculation from getAgents() that blocked cron The getAgents() function was recalculating nextRun to future dates when it found past values. This prevented the cron scheduler from ever finding due agents (nextRun <= now was always false since getAgents had already pushed it to the future). Also fix toast polling: use null sentinel for agents without initial actions so first execution is still detected. Limit cron to 3 agents per cycle and add logging. Co-Authored-By: Claude Opus 4.7 --- .../app/(main)/agents/agents-page-client.tsx | 18 +++++++++-------- memento-note/app/actions/agent-actions.ts | 20 ------------------- memento-note/app/api/cron/agents/route.ts | 6 ++++-- 3 files changed, 14 insertions(+), 30 deletions(-) diff --git a/memento-note/app/(main)/agents/agents-page-client.tsx b/memento-note/app/(main)/agents/agents-page-client.tsx index 27d30f9..83a79c1 100644 --- a/memento-note/app/(main)/agents/agents-page-client.tsx +++ b/memento-note/app/(main)/agents/agents-page-client.tsx @@ -91,16 +91,15 @@ export function AgentsPageClient({ }, []) // Track latest action per agent to detect new executions - const prevActionsRef = useRef>({}) + // null = agent tracked with no initial actions, undefined = not tracked yet + const prevActionsRef = useRef>({}) // Poll every 30s to detect agent executions and show toast notifications useEffect(() => { - // Initialize tracking from initial data + // Initialize tracking from initial data — use null for agents without actions + // so we can still detect their FIRST execution for (const agent of initialAgents) { - const lastAction = agent.actions[0] - if (lastAction) { - prevActionsRef.current[agent.id] = lastAction.id - } + prevActionsRef.current[agent.id] = agent.actions[0]?.id ?? null } const interval = setInterval(async () => { @@ -112,8 +111,11 @@ export function AgentsPageClient({ if (!lastAction) continue const prevId = prevActionsRef.current[agent.id] - if (prevId && prevId !== lastAction.id) { - // New action detected + // undefined = agent not in initial list (created by someone else, skip) + if (prevId === undefined) continue + + if (prevId !== lastAction.id) { + // New execution detected (first action ever, or new run) if (lastAction.status === 'success') { toast.success(t('agents.toasts.autoRunSuccess', { name: agent.name })) } else if (lastAction.status === 'failure') { diff --git a/memento-note/app/actions/agent-actions.ts b/memento-note/app/actions/agent-actions.ts index 58449a5..306b561 100644 --- a/memento-note/app/actions/agent-actions.ts +++ b/memento-note/app/actions/agent-actions.ts @@ -206,26 +206,6 @@ export async function getAgents() { orderBy: { createdAt: 'desc' } }) - // Fix stale nextRun: recalculate if in the past for scheduled agents - const now = new Date() - for (const agent of agents) { - if (agent.frequency !== 'manual' && agent.nextRun && new Date(agent.nextRun) < now) { - const nextRun = calculateNextRun({ - frequency: agent.frequency, - scheduledTime: agent.scheduledTime, - scheduledDay: agent.scheduledDay, - timezone: agent.timezone, - }) - if (nextRun) { - await prisma.agent.update({ - where: { id: agent.id }, - data: { nextRun }, - }) - agent.nextRun = nextRun - } - } - } - return agents } catch (error) { console.error('Error fetching agents:', error) diff --git a/memento-note/app/api/cron/agents/route.ts b/memento-note/app/api/cron/agents/route.ts index 914c1a7..8190ee2 100644 --- a/memento-note/app/api/cron/agents/route.ts +++ b/memento-note/app/api/cron/agents/route.ts @@ -46,10 +46,12 @@ export async function POST(request: NextRequest) { return NextResponse.json({ success: true, executed: 0 }) } + console.log(`[CronAgents] Found ${dueAgents.length} due agent(s)`) + const results: { id: string; success: boolean; error?: string }[] = [] - // Execute agents sequentially to avoid overwhelming the AI provider - for (const agent of dueAgents) { + // Execute agents sequentially (max 3 per cycle) to avoid overwhelming the AI provider + for (const agent of dueAgents.slice(0, 3)) { try { const { executeAgent } = await import('@/lib/ai/services/agent-executor.service') const result = await executeAgent(agent.id, agent.userId)