Add insight history view; feed recent insights back into the prompt

Dashboard now shows a collapsible history of past AI insights (reusing
the existing /history endpoint), and generation now includes the last
3 insights in the prompt so the model can reference what it already
said instead of repeating the same points every day.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
jtricerolph 2026-07-24 22:01:13 +00:00
parent cabaff8d35
commit 6339b33270
4 changed files with 100 additions and 4 deletions

View file

@ -46,6 +46,16 @@ export async function getAiInsightsConfig() {
}
}
// Last few generated insights, most recent first — fed back into the prompt so the
// model can reference what it already said instead of repeating itself verbatim.
export async function getRecentInsights(limit = 3) {
const res = await pool.query(
`SELECT generated_at, content FROM ai_insights ORDER BY generated_at DESC LIMIT $1`,
[limit]
)
return res.rows
}
export async function checkDailyBudget(budgetTokens) {
const res = await pool.query(
`SELECT COALESCE(SUM(input_tokens + output_tokens), 0) AS total
@ -315,17 +325,29 @@ export async function gatherRevenueCorrelation(monthProgress) {
}
}
export function buildPrompt(monthProgress, priorPeriod, rotaVsActual, forecast, anomalies, revenueCorrelation) {
export function buildPrompt(monthProgress, priorPeriod, rotaVsActual, forecast, anomalies, revenueCorrelation, recentInsights = []) {
const systemMsg =
"You are an AI assistant for a wage cost controller in a UK hospitality business. Analyze the data below and " +
"provide a concise daily briefing (3-5 bullet points). Focus on: how this month's wage cost is tracking " +
"against budget, the month-end forecast, notable variance between rota and actual cost by department and " +
"what might be causing it, individual pay anomalies worth a look, and wage cost as a percentage of revenue. " +
"Use UK date format (DD/MM/YYYY) and GBP (£) for all monetary values. Be specific with department/employee " +
"names and numbers. Keep it actionable — no fluff or generic advice."
"names and numbers. Keep it actionable — no fluff or generic advice.\n\n" +
"A 'Recent Previous Insights' section may be included below — compare against them explicitly: call out " +
"what's changed, what's resolved, and what's still an open issue. Don't just repeat the same points verbatim."
const lines = []
if (recentInsights.length) {
lines.push('## Recent Previous Insights (most recent first — reference these, do not just repeat them)')
for (const r of recentInsights) {
const when = new Date(r.generated_at).toLocaleString('en-GB', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' })
lines.push(`${when}:`)
lines.push(r.content)
lines.push('')
}
}
lines.push(`## Month to Date (${monthProgress.monthLabel})`)
lines.push(
`Day ${monthProgress.daysElapsed} of ${monthProgress.daysInMonth} (${fmtPct(monthProgress.pctMonthElapsed)} of month elapsed)`
@ -430,15 +452,16 @@ export async function generateInsight(triggeredBy = 'scheduler') {
}
const monthProgress = await gatherMonthProgressData()
const [priorPeriod, rotaVsActual, forecast, anomalies, revenueCorrelation] = await Promise.all([
const [priorPeriod, rotaVsActual, forecast, anomalies, revenueCorrelation, recentInsights] = await Promise.all([
gatherPriorPeriodData(),
gatherRotaVsActualData(),
gatherForecastData(monthProgress),
gatherEmployeeAnomalies(),
gatherRevenueCorrelation(monthProgress),
getRecentInsights(3),
])
const { systemMsg, userMsg } = buildPrompt(monthProgress, priorPeriod, rotaVsActual, forecast, anomalies, revenueCorrelation)
const { systemMsg, userMsg } = buildPrompt(monthProgress, priorPeriod, rotaVsActual, forecast, anomalies, revenueCorrelation, recentInsights)
let result
try {