--- name: canvas-ai-tools description: Implements AI tools for Canvas generation and updates. Use when creating GenUI tools for code generation, document editing, or Canvas interactions. allowed-tools: Read, Write, Edit, Glob context: fork --- # Canvas AI Tools Skill ## When to Use Use this skill when: - Creating AI tools that generate Canvas content - Implementing code generation/editing tools - Building GenUI tools for Canvas interaction - Adding AI-powered features to Canvas ## GenUI Tool Architecture ``` lib/ai/tools/ # Tool definitions ├── canvas-tools.ts # open_canvas, update_canvas, etc. ├── code-tools.ts # run_code, explain_code └── index.ts # Registry lib/ai/genui/ # UI components for tools ├── canvas-genui.tsx # Canvas generation UI └── code-result.tsx # Code execution results ``` ## Canvas Tool Definitions ### open_canvas Tool ```typescript import { z } from 'zod'; import { tool } from 'ai'; import { CANVAS_TYPES, CanvasConfigSchema } from '@/lib/canvas/types'; export const openCanvasTool = tool({ description: `Opens an interactive canvas for code editing, visualization, or document creation. Use this when the student needs to: - Write, edit, or run code - Create visualizations - Work on documents - Practice with interactive exercises The canvas provides a Monaco editor with syntax highlighting and execution support.`, parameters: z.object({ type: z.enum(CANVAS_TYPES).describe('Type of canvas to open'), title: z.string().max(100).describe('Title for the canvas'), language: z.string().optional().describe('Programming language (for code type)'), initialContent: z.string().optional().describe('Starting content'), generationPrompt: z.string().optional().describe('Internal prompt for generation'), educationalContext: z.object({ topic: z.string().optional(), difficulty: z.enum(['beginner', 'intermediate', 'advanced']).optional(), learningObjective: z.string().optional(), }).optional(), }), execute: async (args) => { // Validate with full schema const config = CanvasConfigSchema.parse(args); return { action: 'open_canvas' as const, canvasConfig: config, }; }, }); ``` ### update_canvas Tool ```typescript export const updateCanvasTool = tool({ description: `Updates the content of the currently open canvas. Use this when: - Fixing errors in student code - Adding examples or explanations - Modifying existing content based on student request Only updates specified fields, preserving others.`, parameters: z.object({ content: z.string().optional().describe('New content for the canvas'), title: z.string().max(100).optional().describe('New title'), language: z.string().optional().describe('Change programming language'), }), execute: async (args) => { return { action: 'update_canvas' as const, updates: args, }; }, }); ``` ### run_code Tool ```typescript export const runCodeTool = tool({ description: `Executes the current code in the canvas and returns the result. Supports: - Python (via Pyodide) - JavaScript/TypeScript (via iframe sandbox) - HTML/CSS (preview) Returns output, errors, and execution time.`, parameters: z.object({ includeVariables: z.boolean().optional().describe('Include final variable values'), }), execute: async (args) => { return { action: 'run_code' as const, options: args, }; }, }); ``` ## Tool Registry Pattern ### Registering Canvas Tools ```typescript // lib/ai/tools/registry.ts import { openCanvasTool, updateCanvasTool, runCodeTool } from './canvas-tools'; export const CANVAS_TOOLS = { open_canvas: openCanvasTool, update_canvas: updateCanvasTool, run_code: runCodeTool, } as const; // For AI SDK export const canvasToolsArray = Object.values(CANVAS_TOOLS); ``` ### Using in Chat ```typescript import { streamText } from 'ai'; import { CANVAS_TOOLS } from '@/lib/ai/tools/registry'; const result = await streamText({ model, messages, tools: CANVAS_TOOLS, maxToolRoundtrips: 3, }); ``` ## GenUI Component Pattern ### Tool Result Rendering ```tsx // lib/ai/genui/canvas-genui.tsx 'use client'; import { useEffect } from 'react'; import { useCanvasStore } from '@/stores/canvas-store'; import type { OpenCanvasResult, UpdateCanvasResult } from '@/lib/canvas/types'; interface CanvasGenUIProps { toolResult: OpenCanvasResult | UpdateCanvasResult; } export function CanvasGenUI({ toolResult }: CanvasGenUIProps) { const { openCanvas, updateCanvas } = useCanvasStore(); useEffect(() => { if (toolResult.action === 'open_canvas') { openCanvas(toolResult.canvasConfig); } else if (toolResult.action === 'update_canvas') { updateCanvas(toolResult.updates); } }, [toolResult, openCanvas, updateCanvas]); // Return minimal UI - canvas opens in side panel return (
{result.output}
)}
{result.error && (
{result.error}
)}
{error.message}
{error.details && (
{JSON.stringify(error.details, null, 2)}
)}