Add bot graphics

Bots can now show a concept as a visual: create_graphic (with
update_graphic, read_graphic and list_graphics, on every run, no computer
needed) stores one HTML document in bot_graphics, per user like the
conversation, and the chat renders its [graphic:ID] ref as an inline card
sized to fit, with a large view and a page of its own (no rail).

Graphic HTML is treated as hostile: it is only served at /graphics/<id>
with a CSP sandbox allowing scripts under an origin of its own and no
network, loading only the vendored Chart.js and Mermaid from
/graphics-lib/. The document carries the app's theme vars and scrollbars,
reports its height to the thread, and a frame that navigates away is
closed.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-27 08:11:15 +01:00
co-authored by Claude Opus 5.5
parent 51fd4d5538
commit bea656ade8
65 changed files with 1959 additions and 21 deletions
@@ -0,0 +1,10 @@
import { AppData } from "@/src/data/app-data";
import { GraphicsLibPrefix, GraphicsLibs } from "@/src/dict/graphics-dict";
/**
* How a graphic's HTML must be written, in the tool descriptions: what the
* sandbox lets it load and the theme it can draw with.
*/
export const GraphicAuthoringNote = `Write one self-contained HTML document (or a fragment), up to ${AppData.BotGraphicMaxChars} characters: inline <style>, <svg> and <script>. It runs sandboxed with no network: outside URLs (CDNs, fetch, remote images or fonts, links that leave) are blocked, so put the data in the document. The only scripts you can load are these, by exactly these tags:
${GraphicsLibs.map((lib) => `- <script src="${GraphicsLibPrefix}/${lib.file}"></script>: ${lib.description}`).join("\n")}
The app's theme is set as CSS variables: var(--c-paper) (the background, already applied to body), var(--c-surface), var(--c-sunken), var(--c-ink) (text), var(--c-ink-secondary), var(--c-border), var(--c-border-strong), var(--font-sans), var(--font-mono). The root has the class "dark" in the dark theme: use the variables, or pick colours that read on both. It shows about 700px wide in the chat and full screen when opened, so keep it responsive; its height grows to fit.`;