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

@@ -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}` }
}
},
}),