fix(chart): simplify to single insert_chart tool that does everything
Some checks failed
CI / Lint, Test & Build (push) Failing after 15s
CI / Deploy production (on server) (push) Has been skipped

This commit is contained in:
Antigravity
2026-05-22 18:30:11 +00:00
parent a00b39728b
commit bfaacc557f
3 changed files with 59 additions and 94 deletions

View File

@@ -220,13 +220,12 @@ Momento is an intelligent note-taking application. Key features include:
- **Lab**: Experimental AI tools for data analysis and deeper insights.
## Available tools
You have access to: note_search, note_read, note_find_and_update, document_search, task_extract, web_search, web_scrape, generate_chart, insert_chart_in_note.
You have access to: note_search, note_read, note_find_and_update, document_search, task_extract, web_search, web_scrape, insert_chart.
Only use tools if you need more information. Never invent note IDs or URLs.
- document_search: Searches attached PDF documents for the current note/notebook. Use when the user asks about documents or files.
- task_extract: Extracts action items from notes and creates a synthesis note. Use when the user asks to extract tasks or TODOs.
- note_find_and_update: Finds a note by search query and appends/prepends/replaces content. Use when the user says "find the note about X and add Y to it".
- generate_chart: Generates a chart (bar, line, area, pie, radar, funnel, gauge) from data and returns it as markdown. Use when the user asks for a chart, graph, visualization, or wants to see data visually.
- insert_chart_in_note: Creates a chart and directly inserts it into a note. Use when the user says "make a chart", "create a graph", "visualize this data" in the context of editing a note.`,
- insert_chart: Generates a chart (bar, line, area, pie, radar) and inserts it directly into the note. Use when the user asks "make a chart", "create a graph", "visualize this data", "show me a chart of X". Chart types: bar (comparisons), horizontal-bar (long labels), line/area (trends), pie (proportions), radar (comparisons).`,
},
fr: {
contextWithNotes: `## Notes et documents de l'utilisateur\n\n${contextNotes}\n\nQuand tu utilises une info venant des notes ci-dessus, cite le titre de la note source entre parenthèses, ex: "Le déploiement se fait via Docker (💻 Development Guide)". Pour les documents PDF, cite le nom du fichier et la page, ex: "Le chiffre d'affaires est de 5M$ (📄 rapport.pdf p.12)". Ne recopie pas mot pour mot — reformule.`,
@@ -257,12 +256,11 @@ Only use tools if you need more information. Never invent note IDs or URLs.
Momento est une application de prise de notes intelligente. Ses fonctionnalités : Éditeur Markdown riche, Copilot IA, Organisation par Carnets, Recherche sémantique, Agents IA, Lab.
## Outils disponibles
Tu as accès à : note_search, note_read, note_find_and_update, document_search, task_extract, web_search, web_scrape, generate_chart, insert_chart_in_note.
Tu as accès à : note_search, note_read, note_find_and_update, document_search, task_extract, web_search, web_scrape, insert_chart.
- document_search : Recherche dans les documents PDF attachés à la note/au carnet.
- task_extract : Extrait les tâches/action items des notes et crée une note de synthèse.
- note_find_and_update : Trouve une note par recherche textuelle et ajoute/prépose/remplace du contenu. Utilise quand l'utilisateur dit "trouve la note sur X et ajoute-y Y".
- generate_chart : Génère un graphique (barres, ligne, aire, circulaire, radar, entonnoir, jauge) à partir de données et le retourne en markdown. Utilise quand l'utilisateur demande un graphique, une visualisation, ou veut voir des données visuellement.
- insert_chart_in_note : Crée un graphique et l'insère directement dans une note. Utilise quand l'utilisateur dit "fais un graphique", "crée un chart", "visualise ces données" dans le contexte d'édition d'une note.`,
- insert_chart : Génère un graphique (barres, ligne, aire, circulaire, radar) et l'insère directement dans la note. Utilise quand l'utilisateur demande "fais un graphique", "crée un chart", "visualise ces données", "montre-moi un chart de X". Types : bar (comparaisons), horizontal-bar (labels longs), line/area (tendances), pie (proportions), radar (comparaisons).`,
},
fa: {
contextWithNotes: `## یادداشت‌های کاربر\n\n${contextNotes}\n\nهنگام استفاده از اطلاعات یادداشت‌های بالا، عنوان یادداشت منبع را در پرانتز ذکر کنید.`,

View File

@@ -6,111 +6,78 @@
import { tool } from 'ai'
import { z } from 'zod'
import { toolRegistry } from './registry'
import { prisma } from '@/lib/prisma'
// Chart generation tool - inserts chart as markdown code block
// Simple chart insertion tool - does everything in one call
toolRegistry.register({
name: 'generate_chart',
description: 'Generate an inline chart from data and insert it into a note as markdown. The chart will be rendered directly in the note.',
name: 'insert_chart',
description: 'Generate a chart and insert it directly into a note. Use when the user asks for a chart, graph, or visualization.',
isInternal: true,
buildTool: (ctx) =>
tool({
description: `Generate an inline chart from data and return it as a markdown code block that can be inserted into a note.
description: `Generate a chart and insert it directly into the note content.
Available chart types:
- "bar": Vertical bar chart
- "horizontal-bar": Horizontal bar chart
- "line": Line chart for trends over time
- "area": Area chart (filled line)
- "pie": Pie/donut chart for proportions
- "radar": Radar chart for comparing multiple dimensions
- "funnel": Funnel chart for stages/conversions
- "gauge": Gauge/meter for a single value
- "bar": Vertical bar chart (default for comparisons)
- "horizontal-bar": Horizontal bar chart (use when labels are long)
- "line": Line chart (use for time series or trends)
- "area": Area chart (filled line chart)
- "pie": Pie chart (use for proportions/percentages)
- "radar": Radar chart (use for comparing multiple dimensions)
Data format: Array of objects with "label" (string) and "value" (number).
IMPORTANT: When the user asks for a chart/graph/visualization:
1. Extract the data from the note or user request
2. Choose the appropriate chart type based on the data
3. Generate the chart markdown using this format:
IMPORTANT:
- Extract data from the note content when possible
- Keep labels short (max 20 characters)
- Round values to reasonable precision (max 2 decimal places)
- For time series, use short date formats (Jan, Feb, Mar or 2023, 2024)
- Maximum 12 data points for readability
- The output will be rendered as a visual chart in the note`,
\`\`\`chart
{chartType}
{title}
{label1}: {value1}
{label2}: {value2}
...
\`\`\`
Example for "show sales by month":
\`\`\`chart
bar
Sales by Month
Jan: 5000
Feb: 7500
Mar: 6200
\`\`\`
4. Call this tool with the noteId, the chart markdown, and where to insert it`,
inputSchema: z.object({
chartType: z.enum(['bar', 'horizontal-bar', 'line', 'area', 'pie', 'radar', 'funnel', 'gauge']).describe('Type of chart to generate'),
title: z.string().optional().describe('Optional title for the chart'),
data: z.array(z.object({
label: z.string().describe('Label for the data point (e.g., month name, category)'),
value: z.number().describe('Numeric value for the data point'),
})).describe('Array of data points with label and value'),
insertLocation: z.enum(['append', 'prepend', 'replace']).default('append').describe('Where to insert the chart in the note'),
targetNoteId: z.string().optional().describe('Optional: specific note ID to update. If not provided, use the current note.'),
noteId: z.string().describe('The note ID to update'),
chartMarkdown: z.string().describe('The complete chart markdown block to insert (including the ```chart fences)'),
insertLocation: z.enum(['append', 'prepend']).default('append').describe('append: add to end, prepend: add to start'),
}),
execute: async ({ chartType, title, data, insertLocation, targetNoteId }) => {
execute: async ({ noteId, chartMarkdown, insertLocation }) => {
try {
// Generate the markdown code block for the chart
const chartData = data.map(d => `${d.label}: ${d.value}`).join('\n')
const chartMarkdown = `\`\`\`chart
${chartType}${title ? `\n${title}` : ''}
${chartData}
\`\`\`\n`
const note = await prisma.note.findFirst({
where: { id: noteId, userId: ctx.userId },
select: { content: true },
})
if (!note) return { error: 'Note not found' }
const updatedContent = insertLocation === 'append'
? `${note.content}\n\n${chartMarkdown}`
: `${chartMarkdown}\n\n${note.content}`
await prisma.note.update({
where: { id: noteId },
data: { content: updatedContent },
})
return {
success: true,
message: `Chart ${insertLocation === 'append' ? 'appended' : 'prepended'} to note.`,
chartMarkdown,
chartType,
dataPointCount: data.length,
message: `Chart generated with ${data.length} data points. Insert this markdown into the note.`,
}
} catch (e: any) {
return { success: false, error: `Chart generation failed: ${e.message}` }
}
},
}),
})
// Quick chart insert tool - directly updates a note with a chart
toolRegistry.register({
name: 'insert_chart_in_note',
description: 'Insert a chart directly into a note. Reads the note, extracts relevant data, generates a chart, and updates the note content.',
isInternal: true,
buildTool: (ctx) =>
tool({
description: `Insert a chart directly into a note. This tool will:
1. Read the current note content
2. Extract relevant data from the note (sales, metrics, comparisons, etc.)
3. Generate an appropriate chart type based on the data
4. Insert the chart markdown into the note
Use this when the user says "make a chart", "create a graph", "visualize this data", etc.
Choose the chart type based on the data:
- Use "bar" for comparing values across categories (default)
- Use "horizontal-bar" when labels are long
- Use "line" or "area" for time series or trends
- Use "pie" for showing proportions/percentages
- Use "radar" for comparing multiple attributes
- Use "funnel" for stages or conversion data
- Use "gauge" for progress/KPI (single value)`,
inputSchema: z.object({
noteId: z.string().describe('The note ID to read and update'),
chartHint: z.string().optional().describe('Optional hint about what to chart (e.g., "sales by month", "comparison of products")'),
insertLocation: z.enum(['append', 'prepend', 'before-section', 'after-section']).default('append').describe('Where to insert the chart'),
sectionMarker: z.string().optional().describe('For before-section/after-section: the heading text to find (e.g., "## Sales Data")'),
}),
execute: async ({ noteId, chartHint, insertLocation, sectionMarker }) => {
try {
// We'll return the instructions for the AI to format the chart
// The actual note update will be done by note_find_and_update or note_update
return {
success: true,
instructions: 'Generate a chart markdown block using the generate_chart tool, then use note_update or note_find_and_update to insert it into the note.',
noteId,
chartHint,
insertLocation,
sectionMarker,
}
} catch (e: any) {
return { success: false, error: `Failed to prepare chart insertion: ${e.message}` }
return { success: false, error: `Failed: ${e.message}` }
}
},
}),

View File

@@ -52,7 +52,7 @@ class ToolRegistry {
* When webOnly is true, only web tools are included (no note access).
*/
buildToolsForChat(ctx: ToolContext & { webOnly?: boolean }): Record<string, any> {
const toolNames: string[] = ctx.webOnly ? [] : ['note_search', 'note_read', 'note_find_and_update', 'document_search', 'task_extract', 'generate_chart', 'insert_chart_in_note']
const toolNames: string[] = ctx.webOnly ? [] : ['note_search', 'note_read', 'note_find_and_update', 'document_search', 'task_extract', 'insert_chart']
// Add web tools only when user toggled web search AND config is present
if (ctx.webSearch) {