157 lines
4.9 KiB
TypeScript
157 lines
4.9 KiB
TypeScript
/**
|
|
* Canvas Tool Registry — shared by server (Gemini function declarations) and client (shape spawning).
|
|
* Pure TypeScript, no DOM or server dependencies.
|
|
*/
|
|
|
|
export interface CanvasToolDefinition {
|
|
declaration: {
|
|
name: string;
|
|
description: string;
|
|
parameters: {
|
|
type: "object";
|
|
properties: Record<string, { type: string; description: string; enum?: string[] }>;
|
|
required: string[];
|
|
};
|
|
};
|
|
tagName: string;
|
|
buildProps: (args: Record<string, any>) => Record<string, any>;
|
|
actionLabel: (args: Record<string, any>) => string;
|
|
}
|
|
|
|
const registry: CanvasToolDefinition[] = [
|
|
{
|
|
declaration: {
|
|
name: "create_map",
|
|
description: "Create an interactive map centered on a location. Use when the user wants to see a place, get directions, or explore a geographic area.",
|
|
parameters: {
|
|
type: "object",
|
|
properties: {
|
|
latitude: { type: "number", description: "Latitude of the center point" },
|
|
longitude: { type: "number", description: "Longitude of the center point" },
|
|
zoom: { type: "number", description: "Zoom level (1-18, default 12)" },
|
|
location_name: { type: "string", description: "Human-readable name of the location" },
|
|
},
|
|
required: ["latitude", "longitude", "location_name"],
|
|
},
|
|
},
|
|
tagName: "folk-map",
|
|
buildProps: (args) => ({
|
|
center: [args.longitude, args.latitude],
|
|
zoom: args.zoom || 12,
|
|
}),
|
|
actionLabel: (args) => `Created map: ${args.location_name}`,
|
|
},
|
|
{
|
|
declaration: {
|
|
name: "create_note",
|
|
description: "Create a markdown note on the canvas. Use for text content, lists, summaries, instructions, or any written information.",
|
|
parameters: {
|
|
type: "object",
|
|
properties: {
|
|
content: { type: "string", description: "Markdown content for the note" },
|
|
title: { type: "string", description: "Optional title for the note" },
|
|
},
|
|
required: ["content"],
|
|
},
|
|
},
|
|
tagName: "folk-markdown",
|
|
buildProps: (args) => ({
|
|
value: args.title ? `# ${args.title}\n\n${args.content}` : args.content,
|
|
}),
|
|
actionLabel: (args) => `Created note${args.title ? `: ${args.title}` : ""}`,
|
|
},
|
|
{
|
|
declaration: {
|
|
name: "create_embed",
|
|
description: "Embed a webpage or web app on the canvas. Use for websites, search results, booking sites, videos, or any URL the user wants to view inline.",
|
|
parameters: {
|
|
type: "object",
|
|
properties: {
|
|
url: { type: "string", description: "The URL to embed" },
|
|
title: { type: "string", description: "Descriptive title for the embed" },
|
|
},
|
|
required: ["url"],
|
|
},
|
|
},
|
|
tagName: "folk-embed",
|
|
buildProps: (args) => ({
|
|
url: args.url,
|
|
}),
|
|
actionLabel: (args) => `Embedded: ${args.title || args.url}`,
|
|
},
|
|
{
|
|
declaration: {
|
|
name: "create_image",
|
|
description: "Display an image on the canvas from a URL. Use when showing an existing image, photo, diagram, or any direct image link.",
|
|
parameters: {
|
|
type: "object",
|
|
properties: {
|
|
src: { type: "string", description: "Image URL" },
|
|
alt: { type: "string", description: "Alt text describing the image" },
|
|
},
|
|
required: ["src"],
|
|
},
|
|
},
|
|
tagName: "folk-image",
|
|
buildProps: (args) => ({
|
|
src: args.src,
|
|
alt: args.alt || "",
|
|
}),
|
|
actionLabel: (args) => `Created image${args.alt ? `: ${args.alt}` : ""}`,
|
|
},
|
|
{
|
|
declaration: {
|
|
name: "create_bookmark",
|
|
description: "Create a bookmark card for a URL. Use when the user wants to save or reference a link without embedding the full page.",
|
|
parameters: {
|
|
type: "object",
|
|
properties: {
|
|
url: { type: "string", description: "The URL to bookmark" },
|
|
},
|
|
required: ["url"],
|
|
},
|
|
},
|
|
tagName: "folk-bookmark",
|
|
buildProps: (args) => ({
|
|
url: args.url,
|
|
}),
|
|
actionLabel: (args) => `Bookmarked: ${args.url}`,
|
|
},
|
|
{
|
|
declaration: {
|
|
name: "create_image_gen",
|
|
description: "Generate an AI image from a text prompt. Use when the user wants to create, generate, or imagine a new image that doesn't exist yet.",
|
|
parameters: {
|
|
type: "object",
|
|
properties: {
|
|
prompt: { type: "string", description: "Text prompt describing the image to generate" },
|
|
style: {
|
|
type: "string",
|
|
description: "Visual style for the generated image",
|
|
enum: ["photorealistic", "illustration", "painting", "sketch", "punk-zine", "collage", "vintage", "minimalist"],
|
|
},
|
|
},
|
|
required: ["prompt"],
|
|
},
|
|
},
|
|
tagName: "folk-image-gen",
|
|
buildProps: (args) => ({
|
|
prompt: args.prompt,
|
|
style: args.style || "photorealistic",
|
|
}),
|
|
actionLabel: (args) => `Generating image: ${args.prompt.slice(0, 50)}${args.prompt.length > 50 ? "..." : ""}`,
|
|
},
|
|
];
|
|
|
|
export const CANVAS_TOOLS: CanvasToolDefinition[] = [...registry];
|
|
|
|
export const CANVAS_TOOL_DECLARATIONS = CANVAS_TOOLS.map((t) => t.declaration);
|
|
|
|
export function findTool(name: string): CanvasToolDefinition | undefined {
|
|
return CANVAS_TOOLS.find((t) => t.declaration.name === name);
|
|
}
|
|
|
|
export function registerCanvasTool(def: CanvasToolDefinition): void {
|
|
CANVAS_TOOLS.push(def);
|
|
}
|