canvas-ai-tools

Canvas AI Tools Skill

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "canvas-ai-tools" with this command: npx skills add omerakben/omer-akben/omerakben-omer-akben-canvas-ai-tools

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

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

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

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

// 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

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

// 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 ( <div className="flex items-center gap-2 text-sm text-muted-foreground"> <div className="h-2 w-2 rounded-full bg-green-500 animate-pulse" /> {toolResult.action === 'open_canvas' ? Opening canvas: ${toolResult.canvasConfig.title} : 'Updating canvas...'} </div> ); }

Code Execution Result

// lib/ai/genui/code-result.tsx import { CheckCircle, XCircle, Clock } from 'lucide-react'; import { cn } from '@/lib/utils';

interface CodeResultProps { result: { success: boolean; output: string; error: string | null; durationMs: number; }; }

export function CodeResultGenUI({ result }: CodeResultProps) { return ( <div className={cn( 'rounded-lg border p-4', result.success ? 'bg-green-50 border-green-200' : 'bg-red-50 border-red-200' )}> <div className="flex items-center gap-2 mb-2"> {result.success ? ( <CheckCircle className="h-4 w-4 text-green-600" /> ) : ( <XCircle className="h-4 w-4 text-red-600" /> )} <span className="font-medium"> {result.success ? 'Execution Successful' : 'Execution Failed'} </span> <span className="text-xs text-muted-foreground ml-auto flex items-center gap-1"> <Clock className="h-3 w-3" /> {result.durationMs}ms </span> </div>

  {result.output &#x26;&#x26; (
    &#x3C;pre className="text-sm bg-white/50 rounded p-2 overflow-x-auto">
      {result.output}
    &#x3C;/pre>
  )}

  {result.error &#x26;&#x26; (
    &#x3C;pre className="text-sm text-red-700 bg-white/50 rounded p-2 overflow-x-auto">
      {result.error}
    &#x3C;/pre>
  )}
&#x3C;/div>

); }

AI Tool Message Handling

Processing Tool Calls

// In chat message handler import { useChat } from 'ai/react'; import { CanvasGenUI } from '@/lib/ai/genui/canvas-genui';

function ChatMessages() { const { messages } = useChat();

return ( <> {messages.map((message) => ( <div key={message.id}> {/* Regular content */} {message.content}

      {/* Tool invocations */}
      {message.toolInvocations?.map((tool) => {
        if (tool.toolName === 'open_canvas' || tool.toolName === 'update_canvas') {
          return (
            &#x3C;CanvasGenUI
              key={tool.toolCallId}
              toolResult={tool.result}
            />
          );
        }
        // Handle other tools...
      })}
    &#x3C;/div>
  ))}
&#x3C;/>

); }

Code Generation Best Practices

Prompt Engineering for Code

const codeGenerationPrompt = ` Generate {language} code that:

  1. Is educational and well-commented
  2. Follows best practices for {language}
  3. Is appropriate for {difficulty} level students
  4. Demonstrates the concept: {concept}

Include:

  • Clear variable names
  • Step-by-step comments
  • Example output as comments

Educational context:

  • Topic: {topic}
  • Learning objective: {learningObjective} `;

Response Format

// AI should return structured code blocks interface CodeGenerationResult { code: string; explanation: string; examples: string[]; nextSteps: string[]; }

Tool Invocation Tracking

Artifact Persistence

// Track tool invocations for artifact persistence interface CanvasArtifact { artifactId: string; conversationId: string; messageId: string; toolInvocationId: string; type: CanvasType; content: string; createdAt: Date; updatedAt: Date; }

// Save artifact when canvas content changes async function saveCanvasArtifact( conversationId: string, messageId: string, toolInvocationId: string, content: string ) { await db.insert(canvasArtifacts).values({ id: nanoid(), conversationId, messageId, toolInvocationId, content, // ... }); }

Error Handling in Tools

Tool Error Response

export const openCanvasTool = tool({ // ... execute: async (args, { abortSignal }) => { try { // Check signal for cancellation if (abortSignal?.aborted) { return { action: 'cancelled' }; }

  const config = CanvasConfigSchema.parse(args);
  return {
    action: 'open_canvas' as const,
    canvasConfig: config,
  };
} catch (error) {
  if (error instanceof z.ZodError) {
    return {
      action: 'error',
      error: 'Invalid canvas configuration',
      details: error.errors,
    };
  }
  throw error; // Re-throw unexpected errors
}

}, });

UI Error Display

function ToolErrorDisplay({ error }: { error: { message: string; details?: unknown } }) { return ( <div className="rounded-lg border border-destructive/50 bg-destructive/10 p-3"> <p className="text-sm text-destructive font-medium">{error.message}</p> {error.details && ( <pre className="text-xs mt-2 text-muted-foreground"> {JSON.stringify(error.details, null, 2)} </pre> )} </div> ); }

Model-Specific Considerations

Tuning for Different Models

// lib/ai/config/model-canvas.ts

export const CANVAS_MODEL_CONFIG = { 'gemini-3-flash': { // Gemini tends to be less verbose toolCallBehavior: 'lenient', promptSuffix: 'When using tools, provide complete implementations.', }, 'grok-4.1-fast': { // Grok excels at agentic tool calling toolCallBehavior: 'strict', maxToolRoundtrips: 5, }, 'claude-4.5': { toolCallBehavior: 'balanced', maxToolRoundtrips: 3, }, } as const;

Testing Checklist

  • open_canvas creates correct configuration

  • update_canvas merges properly

  • run_code returns structured results

  • GenUI components render correctly

  • Tool errors display user-friendly messages

  • Artifact tracking persists data

  • Tool cancellation works

  • Model-specific tuning applied

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

bundle-optimization

No summary provided by upstream source.

Repository SourceNeeds Review
General

react-email

No summary provided by upstream source.

Repository SourceNeeds Review
General

api-route-creator

No summary provided by upstream source.

Repository SourceNeeds Review
General

doc-coauthoring

No summary provided by upstream source.

Repository SourceNeeds Review