- {slide.mermaid ?
:
No diagram
}
+
+
{slide.title}
+ {slide.subtitle &&
{slide.subtitle}
}
+
+
+ {slide.mermaid ?
:
No diagram
}
)
diff --git a/memento-note/lib/ai/tools/slides.tool.ts b/memento-note/lib/ai/tools/slides.tool.ts
index bc13054..b5975bb 100644
--- a/memento-note/lib/ai/tools/slides.tool.ts
+++ b/memento-note/lib/ai/tools/slides.tool.ts
@@ -45,17 +45,16 @@ Available slide types:
- "summary": title, items[] (conclusion with checkmarks)
RULES:
-- MAXIMUM 8 slides total — NEVER exceed 8, even for long notes
-- Count only plain-text words, ignore markdown syntax, URLs, and metadata
-- For short notes (<100 plain words): 3-4 slides max
-- For medium notes (100-300 plain words): 5-6 slides max
-- For any other note: 7-8 slides max — HARD LIMIT
+- Count the plain-text words in the note (ignore markdown, URLs, metadata, headers)
+- <50 words → 2-3 slides MAXIMUM (title + 1 content + summary)
+- 50-150 words → 3-4 slides max
+- 150-400 words → 5-6 slides max
+- >400 words → 7-8 slides max — HARD LIMIT, NEVER exceed 8
- First slide MUST be type "title"
- Last slide MUST be type "summary"
-- Include at most 1 "chart" or "stats" slide — only if real numeric data exists in the note
+- Include "chart" ONLY if real numeric data exists in the note — otherwise FORBIDDEN
- Use VARIED types — never 2 identical types in a row
-- All text content must come from the source notes (never invent data)
-- Each bullet/card must be a real sentence (15+ words, not generic)`,
+- All text must come from the source note — never invent data`,
inputSchema: z.object({
title: z.string().describe('Short presentation title (6 words max)'),
theme: z.string().optional().describe('Visual recipe: architectural-saas, midnight-cathedral, aurora-borealis, venture-pitch, clinical-precision, coastal-morning, etc.'),
@@ -64,9 +63,11 @@ RULES:
execute: async ({ title, theme, slides }) => {
try {
- console.log('[Slides Tool] Building presentation:', title, '| Slides:', slides.length, '| Theme:', theme)
+ // Hard cap: never more than 8 slides regardless of what the model outputs
+ const cappedSlides = slides.slice(0, 8)
+ console.log('[Slides Tool] Building presentation:', title, '| Slides:', cappedSlides.length, '| Theme:', theme)
- const html = buildPresentationHTML({ title, theme, slides: slides as any })
+ const html = buildPresentationHTML({ title, theme, slides: cappedSlides as any })
const canvas = await prisma.canvas.create({
data: {
@@ -75,15 +76,15 @@ RULES:
type: 'slides',
title: title || 'Présentation',
html,
- slideCount: slides.length,
+ slideCount: cappedSlides.length,
theme: theme || 'architectural-saas',
- spec: { title, theme, slides },
+ spec: { title, theme, slides: cappedSlides },
}),
userId: ctx.userId,
},
})
- console.log('[Slides Tool] Canvas created:', canvas.id, '| Slides:', slides.length, '| Size:', Math.round(html.length / 1024), 'KB')
+ console.log('[Slides Tool] Canvas created:', canvas.id, '| Slides:', cappedSlides.length, '| Size:', Math.round(html.length / 1024), 'KB')
// Decrement slide_generate quota after successful canvas creation
incrementUsageAsync(ctx.userId, 'slide_generate')
@@ -94,7 +95,7 @@ RULES:
data: {
status: 'success',
result: canvas.id,
- log: `Slides generated: ${slides.length} slides, ${Math.round(html.length / 1024)}KB`,
+ log: `Slides generated: ${cappedSlides.length} slides, ${Math.round(html.length / 1024)}KB`,
},
}).catch(err => console.error('[Slides Tool] Failed to update action status:', err))
}
@@ -103,8 +104,8 @@ RULES:
success: true,
canvasId: canvas.id,
canvasName: canvas.name,
- slideCount: slides.length,
- message: `Presentation "${canvas.name}" created with ${slides.length} slides.`,
+ slideCount: cappedSlides.length,
+ message: `Presentation "${canvas.name}" created with ${cappedSlides.length} slides.`,
}
} catch (e: any) {
console.error('[Slides Tool] FATAL:', e)