feat(bots): Add initial post trigger and improve scheduler logging

- Add initial post trigger on bot creation to establish schedule reference point
- Implement background post creation in scheduled bot processor using triggerPost
- Add fresh content fetching before checking availability in scheduler
- Enhance scheduler logging with detailed skip reasons and error reporting
- Include autonomous bot skip reasons and scheduled bot status details in logs
- Add error tracking and reporting for failed bot post attempts
- Improve debugging visibility for bot task execution and failures
This commit is contained in:
AskIt
2026-01-26 05:23:43 +01:00
parent 76e7d7fd55
commit 5e75482ec1
3 changed files with 61 additions and 8 deletions
+10
View File
@@ -232,6 +232,16 @@ export default function NewBotPage() {
body: JSON.stringify(sourcePayload), body: JSON.stringify(sourcePayload),
}); });
} }
// Trigger the first post to establish a reference point for the schedule
// This runs in the background - we don't wait for it
fetch(`/api/bots/${data.bot.id}/post`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({}),
}).catch(() => {
// Silently fail - the bot will post on the next scheduled run
});
} }
router.push(`/settings/bots/${data.bot.id}`); router.push(`/settings/bots/${data.bot.id}`);
+27
View File
@@ -34,8 +34,35 @@ async function runBotTasks() {
const autonomousResult = await processAllAutonomousBots(); const autonomousResult = await processAllAutonomousBots();
const posted = autonomousResult.filter(r => r.result.posted).length; const posted = autonomousResult.filter(r => r.result.posted).length;
const skipped = scheduledResult.skipped;
const errors = scheduledResult.errors.length + autonomousResult.filter(r => r.error).length;
// Always log bot task results for debugging
if (scheduledResult.processed > 0 || posted > 0) { if (scheduledResult.processed > 0 || posted > 0) {
log('BOTS', `Processed ${scheduledResult.processed} scheduled, ${posted} autonomous posts`); log('BOTS', `Processed ${scheduledResult.processed} scheduled, ${posted} autonomous posts`);
} else if (scheduledResult.details.length > 0 || autonomousResult.length > 0) {
// Log why bots didn't post
const reasons = scheduledResult.details
.filter(d => d.status !== 'posted')
.map(d => `${d.botId.slice(0, 8)}: ${d.status}${d.message ? ` (${d.message})` : ''}`)
.slice(0, 3);
const autoReasons = autonomousResult
.filter(r => !r.result.posted)
.map(r => `${r.botHandle}: ${r.result.reason || r.error || 'unknown'}`)
.slice(0, 3);
if (reasons.length > 0 || autoReasons.length > 0) {
log('BOTS', `No posts created. Scheduled: ${scheduledResult.details.length} checked, ${skipped} skipped. Autonomous: ${autonomousResult.length} checked.`);
if (reasons.length > 0) log('BOTS', `Scheduled skip reasons: ${reasons.join('; ')}`);
if (autoReasons.length > 0) log('BOTS', `Autonomous skip reasons: ${autoReasons.join('; ')}`);
}
} else {
log('BOTS', 'No active bots found');
}
if (errors > 0) {
log('BOTS', `Errors: ${scheduledResult.errors.join('; ')}`);
} }
} catch (error) { } catch (error) {
log('BOTS', `Error: ${error}`); log('BOTS', `Error: ${error}`);
+20 -4
View File
@@ -10,6 +10,8 @@
import { db, bots, botContentSources, botContentItems } from '@/db'; import { db, bots, botContentSources, botContentItems } from '@/db';
import { eq, and } from 'drizzle-orm'; import { eq, and } from 'drizzle-orm';
import { canPost } from './rateLimiter'; import { canPost } from './rateLimiter';
import { triggerPost } from './posting';
import { fetchAllSourcesForBot } from './contentFetcher';
// ============================================ // ============================================
// TYPES // TYPES
@@ -833,6 +835,9 @@ export async function processScheduledPosts(): Promise<ProcessScheduledPostsResu
continue; continue;
} }
// Fetch fresh content from sources before checking availability
await fetchAllSourcesForBot(bot.id, { maxItems: 20, timeout: 15000 });
// Check for unprocessed content (Requirement 5.5) // Check for unprocessed content (Requirement 5.5)
const hasContent = await hasUnprocessedContent(bot.id); const hasContent = await hasUnprocessedContent(bot.id);
@@ -859,15 +864,26 @@ export async function processScheduledPosts(): Promise<ProcessScheduledPostsResu
continue; continue;
} }
// At this point, we would trigger post generation // Trigger post creation with the content item
// This will be implemented in the posting module (Task 15) const postResult = await triggerPost(bot.id, {
// For now, we just mark it as ready to post sourceContentId: contentItem.id,
});
if (postResult.success) {
result.details.push({ result.details.push({
botId: bot.id, botId: bot.id,
status: 'posted', status: 'posted',
message: `Ready to post content: ${contentItem.title}`, message: `Posted: ${contentItem.title.substring(0, 50)}...`,
}); });
result.processed++; result.processed++;
} else {
result.details.push({
botId: bot.id,
status: 'error',
message: postResult.error || 'Failed to create post',
});
result.errors.push(`Bot ${bot.id}: ${postResult.error}`);
}
} catch (error) { } catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Unknown error'; const errorMessage = error instanceof Error ? error.message : 'Unknown error';