/** * Artifact data shapes — mirror of `langchain_canvas/protocol/artifacts.py`. * * An `Artifact` is transport-agnostic: `{ id, type, title, version, status, * data }`. `type` is a registry key resolved to a React component; `data` is the * type-specific payload that component reads. Keep this file in lockstep with * the Python module — a field here must exist there, and vice versa. */ type ArtifactStatus = "streaming" | "complete" | "error"; interface Artifact { /** Stable identity — the reconciliation key. */ id: string; /** Registry key: "document" | "chart" | ... */ type: string; /** Shown in the canvas header / tab. */ title: string; /** 1-based; bumped on every `canvas.replace`. */ version: number; status: ArtifactStatus; data: TData; meta?: Record; } /** * The base substrate: raw HTML, rendered in a sandboxed iframe. Everything a * canvas can show is ultimately HTML; `document` / `chart` / `table` are * structured conveniences the SDK renders for you, while `html` lets an agent * emit an arbitrary self-contained page (the Claude-Artifacts / Genspark model). */ interface HtmlData { html: string; } interface DocumentData { format: "markdown"; content: string; } interface ChartSeries { /** Column in `ChartData.rows` to plot. */ key: string; label?: string; color?: string; } interface ChartOptions { stacked?: boolean; yLabel?: string; /** Chart title shown above the plot. */ title?: string; /** Per-slice colors for pie charts, index-aligned to `rows`. */ colors?: string[]; } interface ChartData { chart: "line" | "bar" | "area" | "pie"; /** Tidy/long-form rows, consumed directly by the charting library. */ rows: Array>; /** Category / x-axis field. */ xKey: string; series: ChartSeries[]; options?: ChartOptions; /** * Optional raw ECharts `option`. When present it's rendered verbatim — an * escape hatch for agents/apps that already produce a full ECharts config * (the tidy `rows`/`series` model is ignored, and inline editing is disabled). */ echartsOption?: Record; } interface TableColumn { key: string; label?: string; align?: "left" | "right" | "center"; } interface TableData { columns: TableColumn[]; rows: Array>; /** * Opaque spreadsheet state (Fortune-sheet sheets) once the user has edited the * grid — carries merges, per-cell fonts/formats, and formulas that the simple * columns/rows shape can't hold. Present after the first interactive edit; * exporters prefer it over columns/rows. */ sheet?: Array>; } /** A freely-positioned element on a "blank" slide (percent geometry, 0–100). */ /** One table cell's own look, where it differs from the table's. The cell's * text lives in the table element's `rows`. */ interface SlideTableCell { r: number; c: number; fill?: string; color?: string; bold?: boolean; align?: "left" | "center" | "right"; fontSize?: number; colSpan?: number; rowSpan?: number; } interface SlideElement { id: string; type: "text" | "image" | "shape" | "table"; x: number; y: number; w: number; h: number; /** Clockwise rotation in degrees about the box centre (PowerPoint's own * units). Absent means 0 — unrotated. */ rotation?: number; text?: string; src?: string; fontSize?: number; bold?: boolean; color?: string; align?: "left" | "center" | "right"; /** Shape kind for `type: "shape"`. */ shape?: "rect" | "ellipse" | "line"; /** Fill (rect/ellipse) or stroke (line) colour — "#rrggbb", or "none" for * an explicitly unfilled shape. Absent means unsaid: nothing is drawn. */ fill?: string; /** Outline color, independent of fill — a box drawn by its border alone. */ stroke?: string; /** Outline weight in px, like `fontSize`. */ strokeWidth?: number; /** Type face; without it line breaks land elsewhere than in the source file. */ fontFamily?: string; /** Line box as a multiple of the font size. */ lineHeight?: number; /** Where text sits in its box. */ verticalAlign?: "top" | "middle" | "bottom"; /** Colour band behind the words, the way a highlighter marks a heading. */ highlight?: string; /** Space above the text, in px. */ spaceBefore?: number; /** Space below the text, in px. */ spaceAfter?: number; /** What happens when the words outgrow the box, as PowerPoint's autofit * settles it: `shape` grows the box, `text` shrinks the type, `none` * (the default) leaves the overflow for the deck check to name. */ autofit?: "shape" | "text" | "none"; /** `false` for a box PowerPoint never wraps (`bodyPr wrap="none"`) — the * canvas must not fold a one-line label the original shows straight. * Absent means the text wraps, as ever. */ wrap?: boolean; /** A table's words: a grid of strings, row-major. `stroke` draws the grid; * `fill` / `color` / `fontSize` / `fontFamily` / `bold` / `align` are the * cells' defaults. */ rows?: string[][]; /** The first row is a header row. */ header?: boolean; /** Column widths as percent of the table's box; absent means equal shares. */ colWidths?: number[]; /** Row heights as percent of the table's box; absent means equal shares. */ rowHeights?: number[]; /** What single cells do differently. */ cells?: SlideTableCell[]; } interface Slide { /** title · content (bullets) · section · image · two-column · blank (free canvas). */ layout?: "title" | "content" | "section" | "image" | "two-column" | "blank"; /** Freely-positioned elements for the "blank" layout. */ elements?: SlideElement[]; title?: string; subtitle?: string; bullets?: string[]; /** Right-hand bullets for the "two-column" layout. */ bullets2?: string[]; /** Image (data: URL or https URL) for the "image" layout. */ image?: string; /** Slide background color (hex). */ background?: string; /** Slide text color (hex). */ textColor?: string; /** Speaker notes (not shown on the slide; exported to the .pptx notes pane). */ notes?: string; /** Display-only backdrop: the original deck's master/layout rendered as an * image (assets/ path, set by the importer). Drawn behind the elements; * the pptx exporter ignores it — the template skin carries the real master. */ masterImage?: string; /** Content padding as a percent of the slide width (a safe margin around the * free canvas). Applied in the editor, present view, thumbnails, and export. */ padding?: number; } /** The deck's page size in inches — the coordinate space percent geometry * refers to. Absent means the classic 16:9 canvas (10 x 5.625). When a * template skin is attached, tools fill this with the skin's real page so * the editor, the preview, and the exported file agree on one aspect * ratio. */ interface SlidePage { widthIn: number; heightIn: number; } interface SlidesData { slides: Slide[]; page?: SlidePage; /** Optional pptx skin: a canvas reference ("sources/brand.pptx") whose * master and layouts the pptx export builds on. Export-time only — the * canvas preview does not render the skin; a missing or unreadable skin * degrades to the blank-layout export. */ template?: string; } /** * A stored canvas file shown as itself — a window onto the store, not a copy. * `path` is the canvas-relative reference (`sources/photo.png`); the renderer * resolves it against the host's asset endpoint for display and download. * `cover` / `excerpt` / `detail` are *derived* previews (never stored). */ interface FileData { path: string; name: string; mediaType?: string; size?: number; /** data: URI thumbnail of page one (page-renderable sources). */ cover?: string; /** Every page as labeled thumbnails tiled into grid sheets, 20 per sheet. */ grids?: string[]; /** Pages the host can render one at a time (see `pageBaseUrl`). */ pageCount?: number; /** A workbook's sheets, for a read-only grid (same shape as a table's data). */ workbook?: TableData; /** Rendered pages (1-based) that carry charts, shown under the grid. */ chartPages?: number[]; /** Short text sample, via the source converter. */ excerpt?: string; /** One-line content summary ("3 pages", "5 slides"). */ detail?: string; } type HtmlArtifact = Artifact & { type: "html"; }; type DocumentArtifact = Artifact & { type: "document"; }; type ChartArtifact = Artifact & { type: "chart"; }; type TableArtifact = Artifact & { type: "table"; }; type SlidesArtifact = Artifact & { type: "slides"; }; type FileArtifact = Artifact & { type: "file"; }; type KnownArtifact = HtmlArtifact | DocumentArtifact | ChartArtifact | TableArtifact | SlidesArtifact | FileArtifact; /** * Canvas Wire Protocol v1 — event envelopes. Mirror of * `langchain_canvas/protocol/events.py`. Every SSE frame is one `StreamEvent`, * discriminated by `type`. See `docs/02-protocol.md` for the specification. */ interface MessageDelta { type: "message.delta"; messageId: string; text: string; } interface MessageEnd { type: "message.end"; messageId: string; } interface ToolStart { type: "tool.start"; toolCallId: string; name: string; } interface ToolEnd { type: "tool.end"; toolCallId: string; ok: boolean; } interface CanvasCreate { type: "canvas.create"; artifact: Artifact; } /** Append `text` to the string at `data.` (e.g. a document body). */ interface CanvasAppend { type: "canvas.append"; id: string; path: string; text: string; } /** JSON-merge-patch (RFC 7386) `patch` into the artifact's `data`. */ interface CanvasPatch { type: "canvas.patch"; id: string; patch: Record; } /** * Replace a single element (by its `data-cid` tree path) inside an `html` * artifact with new outer HTML — an O(1) surgical edit that avoids resending the * whole page. The reconciler resolves the `cid` path against the source HTML. */ interface CanvasNodePatch { type: "canvas.node_patch"; id: string; cid: string; html: string; } /** Replace wholesale — the reconciler snapshots a new version. */ interface CanvasReplace { type: "canvas.replace"; id: string; artifact: Artifact; } interface CanvasStatus { type: "canvas.status"; id: string; status: ArtifactStatus; } /** * Promote the artifact's current state to a described version snapshot. * `revision` is the opaque store revision when a CanvasStore backs the canvas. */ interface CanvasCommit { type: "canvas.commit"; id: string; description: string; revision?: string; /** Set when this commit continues the version already on the rail: the * entry is replaced rather than joined, so a burst of small saves reads * as one work unit. */ amends?: string; } interface ErrorEvent { type: "error"; message: string; } interface DoneEvent { type: "done"; } type ChatEvent = MessageDelta | MessageEnd | ToolStart | ToolEnd; type CanvasEvent = CanvasCreate | CanvasAppend | CanvasPatch | CanvasNodePatch | CanvasReplace | CanvasStatus | CanvasCommit; type StreamEvent = ChatEvent | CanvasEvent | ErrorEvent | DoneEvent; /** Narrow a `StreamEvent` to the canvas family. */ declare function isCanvasEvent(event: StreamEvent): event is CanvasEvent; /** Narrow a `StreamEvent` to the chat family. */ declare function isChatEvent(event: StreamEvent): event is ChatEvent; /** * Element selection — a client→server concern (it rides the chat request, not * the SSE wire). When the user clicks an element inside an `html` artifact, the * inspector reports which element was chosen; an edit instruction then carries * this context so the agent can make a targeted change. */ interface ElementSelection { /** The `html` artifact the element belongs to. */ artifactId: string; /** Deterministic path id assigned by the inspector (e.g. "e-0-2"). */ cid: string; /** Human/agent-readable selector, e.g. "button.cta". */ selector: string; /** Lowercased tag name. */ tag: string; /** Short text preview of the element. */ text?: string; /** The element's current outer HTML (truncated) — edit context for the agent. */ outerHtml?: string; /** Snapshot of the element's key computed styles (for the style panel). */ styles?: Record; /** True when the element is a group wrapper (offers "Ungroup"). */ isGroup?: boolean; } /** * File suffixes whose selections address a document, not a DOM element. * * The twin of `DOCUMENT_OP_SUFFIXES` in `langchain_canvas.document_ops`; the * protocol parity test compares the two, so a format the tools learn to edit * cannot quietly keep the wrong framing here. */ declare const DOCUMENT_FILE_SUFFIXES: readonly [".docx"]; /** True when this selection points into a document file rather than a page. */ declare function isDocumentSelection(selection: ElementSelection): boolean; /** * Frame a targeted edit so the agent changes only what the user pointed at. * * The two kinds of canvas artifact are addressed in different languages and * have different tools, so one framing cannot serve both. A document is * addressed by position for *reading* only — `[p12]` moves the moment a * paragraph is inserted — so the instruction hands over the words at that place * and says to use them as the anchor. A page is edited by matching its markup, * so the instruction hands over the element's markup as the *file* has it. * * Both halves are about naming something the agent can actually find. The * screen's own pointing attributes (`data-cid` and friends) are stripped before * the source is stored, so an instruction that names one sends the agent * looking through the file for something that was never written there — and a * careful agent then refuses the edit rather than guessing. */ declare function withSelections(message: string, selections: ElementSelection[]): string; /** * `CanvasTransport` — the socket between the canvas UI and an agent backend. * * The whole contract is one promise: *given a user message, return the stream * of `StreamEvent`s the canvas should apply.* Everything downstream of the * socket (event batching, reconcile, rendering, error display) is * transport-agnostic, so swapping how the app talks to its backend never * touches a component. * * First-party implementations: `sseTransport` (the reference Canvas Wire * Protocol over SSE — the default), `mockTransport` (scripted offline * streams), and `langgraphTransport` (a LangGraph server, from the * `/langgraph` entry point). An app with its own backend implements this * interface instead of forking the hook. */ /** One user turn, as handed to the transport by `useCanvasStream`. */ interface TransportRequest { /** Conversation thread id (server-side memory / canvas scope). */ threadId: string; /** The user's message. */ message: string; /** Element context for a targeted edit (set when editing selected elements). */ selections?: ElementSelection[]; /** Aborted when the user hits stop or the component unmounts. */ signal?: AbortSignal; } interface CanvasTransport { /** Open the stream for one user turn and yield events until it ends. */ stream(request: TransportRequest): AsyncIterable; } export { type Artifact as A, type SlideTableCell as B, type CanvasTransport as C, type DocumentData as D, type ElementSelection as E, type FileData as F, type SlidesArtifact as G, type HtmlData as H, type TableArtifact as I, type TableColumn as J, type KnownArtifact as K, type ToolEnd as L, type MessageDelta as M, type ToolStart as N, type TransportRequest as O, isCanvasEvent as P, isChatEvent as Q, isDocumentSelection as R, type StreamEvent as S, type TableData as T, type CanvasEvent as a, type SlidesData as b, type ChartData as c, type ArtifactStatus as d, type CanvasAppend as e, type CanvasCommit as f, type CanvasCreate as g, type CanvasNodePatch as h, type CanvasPatch as i, type CanvasReplace as j, type CanvasStatus as k, type ChartArtifact as l, type ChartOptions as m, type ChartSeries as n, type ChatEvent as o, DOCUMENT_FILE_SUFFIXES as p, type DocumentArtifact as q, type DoneEvent as r, type ErrorEvent as s, type FileArtifact as t, type HtmlArtifact as u, type MessageEnd as v, withSelections as w, type Slide as x, type SlideElement as y, type SlidePage as z };