carbon-tokenization / backend /src /agent /embed-tools.ts
tfrere's picture
tfrere HF Staff
feat(editor): embed studio with data files and agent-aware editing
8fc8501
import { tool } from "ai";
import { z } from "zod";
/**
* Tools for the Embed Studio AI. These return instructions that the
* frontend executes on the EmbedStore (Y.Map). The backend never
* touches the Yjs document directly.
*/
export const embedTools = {
createEmbed: tool({
description:
"Create or fully replace an HTML embed chart. Use when building a new chart from scratch " +
"or when changes are so extensive that a full rewrite is cleaner than patching. " +
"The HTML must be a self-contained fragment following D3 embed conventions " +
"(root div + scoped style + IIFE script).",
inputSchema: z.object({
html: z
.string()
.describe(
"Complete self-contained HTML fragment (root div + scoped style + IIFE script)",
),
title: z
.string()
.optional()
.describe("Short descriptive title for the chart"),
source: z
.string()
.optional()
.describe("Data source attribution"),
filename: z
.string()
.optional()
.describe(
"Descriptive file name slug for this chart, WITHOUT extension " +
"(e.g. 'attention-heatmap', 'model-accuracy', 'sales-by-region'). " +
"Use kebab-case, ASCII only, concise (2-4 words, <40 chars). " +
"REQUIRED on the first createEmbed call for a new chart - the " +
"client will slugify it, ensure uniqueness, and rename the file " +
"automatically. Omit on subsequent calls that only update the " +
"existing chart (the current name will be kept).",
),
}),
}),
patchEmbed: tool({
description:
"Replace a specific block of code in the current chart HTML. " +
"Use for targeted edits (color change, label update, data tweak, bug fix). " +
"Always prefer this over createEmbed when modifying an existing chart. " +
"The search string must be an exact verbatim excerpt from the current HTML " +
"(whitespace included). Call readEmbed first if unsure of the exact content.",
inputSchema: z.object({
search: z
.string()
.describe(
"Exact verbatim excerpt from the current chart HTML to find and replace. " +
"Must be long enough to be unique (at least 3-5 lines of context).",
),
replace: z
.string()
.describe("The new code that replaces the search block"),
}),
}),
readEmbed: tool({
description:
"Read the full current chart HTML. Use before calling patchEmbed " +
"to verify the exact content, or to understand the current structure before editing.",
inputSchema: z.object({}),
}),
listDataFiles: tool({
description:
"List all data files (CSV, TSV, JSON, NDJSON, TXT) the user has " +
"attached to this document. Returns one line per file with name, " +
"extension, size, row count, and column names when available. " +
"Call this when the user mentions data, a dataset, or wants to " +
"visualize content from a specific file.",
inputSchema: z.object({}),
}),
readDataFile: tool({
description:
"Read the full raw content of a data file previously listed by " +
"listDataFiles. Use this to inspect the exact structure, sample " +
"values, or to embed small datasets directly into the chart. Large " +
"files may be truncated - prefer loading via fetch from " +
"/data/<name> for charts that rely on the full dataset.",
inputSchema: z.object({
name: z
.string()
.describe("Exact file name as returned by listDataFiles (e.g. 'sales.csv')"),
}),
}),
};