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]>
54 lines
1.5 KiB
TypeScript
54 lines
1.5 KiB
TypeScript
import BunSQLite from "@moduletrace/bun-sqlite";
|
|
import type { BUN_SQLITE_COBBLE_BOT_GRAPHICS, BunSQLiteTables } from "@/db/types/db";
|
|
import checkGraphicInput from "./check-graphic-input";
|
|
|
|
type Params = {
|
|
user_id: number | string;
|
|
bot_id: number | string;
|
|
session_id?: number | string | null;
|
|
workspace_id?: number | string | null;
|
|
/**
|
|
* The run that made it, so its message is linked once posted.
|
|
*/
|
|
job_id?: number | string | null;
|
|
title: string;
|
|
html: string;
|
|
};
|
|
|
|
/**
|
|
* Stores a graphic a bot made for a user. Returns its id.
|
|
*/
|
|
export default async function createBotGraphic({
|
|
user_id,
|
|
bot_id,
|
|
session_id,
|
|
workspace_id,
|
|
job_id,
|
|
title,
|
|
html,
|
|
}: Params) {
|
|
const checked = checkGraphicInput({ title, html });
|
|
|
|
const res = await BunSQLite.insert<BUN_SQLITE_COBBLE_BOT_GRAPHICS, (typeof BunSQLiteTables)[number]>({
|
|
table: "bot_graphics",
|
|
data: [
|
|
{
|
|
title: checked.title,
|
|
html: checked.html,
|
|
version: 1,
|
|
user_id: Number(user_id),
|
|
bot_id: Number(bot_id),
|
|
session_id: session_id ? Number(session_id) : undefined,
|
|
workspace_id: workspace_id ? Number(workspace_id) : undefined,
|
|
job_id: job_id ? Number(job_id) : undefined,
|
|
},
|
|
],
|
|
});
|
|
|
|
const id = Number(res.singleRes?.id || res.postInsertReturn?.insertId);
|
|
|
|
if (!res.success || !id) throw new Error(`Couldn't store the graphic: ${res.msg}`);
|
|
|
|
return id;
|
|
}
|