@gui-chat-plugin/sequence 0.4.1 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.5.1
4
+
5
+ - **Markdown slides fit in movies too.** A dense Markdown slide shrank to fit in the View, whose page
6
+ runs the fitting, but a movie made from it (MulmoChat's makeMovie: an `html_tailwind` beat) cut
7
+ it off at the top and bottom. `SLIDE_FIT_SCRIPT` is the same fitting, for the host to give the
8
+ movie's page (MulmoCast's html_tailwind beat takes it as its `script`). The Markdown slide's box
9
+ no longer shrinks as a flex item: MulmoCast's page makes the body a flex column, where it did,
10
+ and its text was fitted into the shrunken box, much too small. Checked in a MulmoChat movie: a
11
+ 14-item slide with a formula on every line fits, its title and last line in view.
12
+
13
+ ## 0.5.0
14
+
15
+ - **Chart slides**: `presentSlide` takes `chart`, a Chart.js configuration (`{ type, data,
16
+ options }`, as MulmoCast's chart beats take it), for numbers to compare, a trend or proportions.
17
+ The View draws it under the slide's title on a sandboxed page of its own
18
+ (`chartSlideDocument`), with the same kind of policy as an HTML slide's: Chart.js from jsDelivr,
19
+ checked by its hash, and the configuration as data. Chart.js's own types only
20
+ (`SLIDE_CHART_TYPES`). The parameter is JSON text: as an object without properties, Gemini
21
+ Live used it for 2 charts in 4 asked for, drawing the others in HTML; as JSON text, 3 in 3. An
22
+ object is read too.
23
+ - **Markdown slides with TeX math**: `presentSlide` takes `markdown`, with math between `$…$` or
24
+ `$$…$$`, for equations, definitions, short lists and small tables. `execute()` makes it an HTML
25
+ slide (`markdownSlideHtml`), so Views and movies show it as one; the record and the result keep
26
+ the text too, in `markdown`. Math is MathML, drawn by the browser with nothing to load, with the
27
+ thin spaces around function names and the matrix column gaps Chrome's MathML leaves out. The
28
+ slide's type shrinks until it fits. New dependencies: marked and KaTeX, imported only when a
29
+ Markdown slide is made.
30
+ - The prompt tells the model which kind a slide should be: a picture for a scene, a chart for
31
+ numbers, Markdown for math and text, HTML for designed layouts and diagrams.
32
+ - An HTML slide's page shrinks a box marked `data-fit` until it fits (its script's hash changed).
33
+
3
34
  ## 0.4.1
4
35
 
5
36
  - **Slides are explained, not announced.** Asked only to "explain" the slide on the screen, OpenAI's
package/README.md CHANGED
@@ -3,11 +3,11 @@
3
3
  Tools that show things one step at a time, as pictures, for
4
4
  [GUI Chat Protocol](https://github.com/receptron/gui-chat-protocol) hosts:
5
5
 
6
- | Tool | Shows |
7
- | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
8
- | `presentSlide` | One slide of a spoken slideshow (mode `"presentation"`), or one step of a step-by-step guide the user follows along with (mode `"steps"`): a generated picture, or a slide in HTML |
9
- | `defineStoryboard` | A story's cast: a reference sheet for each recurring character |
10
- | `presentPanel` | One panel of the story, with its characters drawn as in their sheets; an interactive story offers choices |
6
+ | Tool | Shows |
7
+ | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
8
+ | `presentSlide` | One slide of a spoken slideshow (mode `"presentation"`), or one step of a step-by-step guide the user follows along with (mode `"steps"`): a generated picture, a chart, or a slide in Markdown (with TeX math) or HTML |
9
+ | `defineStoryboard` | A story's cast: a reference sheet for each recurring character |
10
+ | `presentPanel` | One panel of the story, with its characters drawn as in their sheets; an interactive story offers choices |
11
11
 
12
12
  From MulmoChat and MulmoGlass, tested there by voice on OpenAI Realtime, Gemini Live and Grok, and
13
13
  in text chat.
@@ -60,11 +60,47 @@ overlap (a host that runs `execute()` on a server gets them as concurrent reques
60
60
  claimed before anything is awaited, so an identical one waits for it and a later step is held while
61
61
  it is drawn.
62
62
 
63
- ## HTML slides
64
-
65
- A slide is a generated picture (`imagePrompt`) or HTML (`html`), the model's choice per slide: a
66
- picture for a scene or an object, HTML for words, numbers, lists, comparisons and diagrams, which
67
- picture models draw badly. The model writes the inside of `<body>` for a 1280x720 canvas, with
63
+ ## Slides that aren't pictures
64
+
65
+ A slide is a generated picture (`imagePrompt`), a chart (`chart`), Markdown (`markdown`) or HTML
66
+ (`html`), the model's choice per slide: a picture for a scene or an object; a chart for numbers to
67
+ compare, a trend or proportions; Markdown for equations (TeX math), definitions, short lists and
68
+ small tables; HTML for designed layouts, comparisons, timelines and diagrams. Picture models draw
69
+ words, numbers and math badly. A slide sent with more than one is one kind: `html` first, then
70
+ `markdown`, then `chart`, then the picture.
71
+
72
+ ### Markdown slides
73
+
74
+ `markdown` is GitHub-flavored Markdown with TeX math between `$…$` (inline) or `$$…$$` (a
75
+ displayed equation), `\(…\)` and `\[…\]` too. A dollar starts math only before a non-space and
76
+ ends it only after one, not before a digit, so "$5 and $10" stays money; `\$` is a dollar sign.
77
+ `execute()` makes it into an HTML slide (`markdownSlideHtml`, with [marked](https://marked.js.org)
78
+ and [KaTeX](https://katex.org), imported only when a Markdown slide is made), so it is shown, saved
79
+ and made into a movie as one: the result and the record have the HTML in `html` and the text as the
80
+ model wrote it in `markdown`. Math is MathML (KaTeX's `mathml` output), which the browser draws with
81
+ no stylesheet or font to load: it works offline and in a movie as on the screen. Function names
82
+ (`\log`, `\sin`) get TeX's thin spaces, and matrix cells padding, which Chrome's MathML doesn't give
83
+ them. TeX that KaTeX can't read is shown as written, in red. The slide's type is sized by how much it
84
+ says, and the page shrinks it until it fits. A page that shows the slide's HTML without the View's
85
+ page (a movie's) fits it with `SLIDE_FIT_SCRIPT`: MulmoCast's `html_tailwind` beat takes it as its
86
+ `script`.
87
+
88
+ ### Chart slides
89
+
90
+ `chart` is a [Chart.js](https://www.chartjs.org) configuration, `{ type, data, options }`, as
91
+ MulmoCast's `chart` beats take it (their `chartData`), of one of Chart.js's own types
92
+ (`SLIDE_CHART_TYPES`: bar, line, pie, doughnut, radar, polarArea, scatter, bubble). The tool advertises it as JSON text (an object without properties, Gemini Live
93
+ used for 2 charts in 4 asked for; JSON text for 3 in 3), and an object is read too; one of another type, or without `data`, is refused, and the model is told
94
+ why. The record and the result keep it in `chart`. `chartSlideDocument(title, chart)` (core entry)
95
+ makes the page: the slide's title over the chart, which Chart.js (from jsDelivr, one version,
96
+ checked by its hash) draws growing into place. The configuration is in a JSON data block, so it
97
+ can't run anything, and its policy, like an HTML slide's, lets the page send nothing out and run no
98
+ script but its own and Chart.js. Offline, the page says the chart couldn't be drawn.
99
+
100
+ ### HTML slides
101
+
102
+ The model writes the inside of `<body>` for a 1280x720 canvas, with
103
+ Tailwind CSS classes, and animates it with [MulmoCast](https://github.com/receptron/mulmocast-cli)'s The model writes the inside of `<body>` for a 1280x720 canvas, with
68
104
  Tailwind CSS classes, and animates it with [MulmoCast](https://github.com/receptron/mulmocast-cli)'s
69
105
  declarative `data-animation` attributes: `animate` (`data-opacity`, `data-translate-x/y`,
70
106
  `data-scale`, `data-rotate`, `data-width`/`data-height`), `counter` and `typewriter`, each with
@@ -94,7 +130,7 @@ that an HTML step is on the screen; a guide step asked for again is then shown a
94
130
 
95
131
  Saved through `files.artifacts`, with their pictures' paths:
96
132
 
97
- - `slideshows/<id>.json`: `{ id, title, mode, totalSlides, slides: { "1": { title, imagePrompt, imagePath } } }`; an HTML slide has `html`, an `imagePrompt` of `""` and no `imagePath`
133
+ - `slideshows/<id>.json`: `{ id, title, mode, totalSlides, slides: { "1": { title, imagePrompt, imagePath } } }`; a slide that isn't a picture has an `imagePrompt` of `""` and no `imagePath`, and has `html` (an HTML slide), `html` and `markdown` (a Markdown slide) or `chart` (a chart slide)
98
134
  - `storyboards/<id>.json`: `{ id, title, style, totalPanels, interactive, characters: [{ name, description, imagePath }], panels: { "1": { caption, characters, imagePrompt, imagePath, choices } } }`
99
135
 
100
136
  IDs are 12 hex digits. The results name them, so a later tool call can refer to a slideshow or a
@@ -0,0 +1,14 @@
1
+ /** The chart types a slide can have: Chart.js's own, with no plugin. */
2
+ export declare const SLIDE_CHART_TYPES: readonly ["bar", "line", "pie", "doughnut", "radar", "polarArea", "scatter", "bubble"];
3
+ /** A Chart.js configuration: `type`, `data` and optionally `options`. */
4
+ export type SlideChart = Record<string, unknown> & {
5
+ type: (typeof SLIDE_CHART_TYPES)[number];
6
+ data: Record<string, unknown>;
7
+ };
8
+ /** CHART_PAGE_SCRIPT's hash, which the policy allows (checked by a test). */
9
+ export declare const CHART_PAGE_SCRIPT_HASH = "sha256-TfZZxJX+yWgzYLy7zqsMa85OJEaC+zNLIpKLDZVnUqA=";
10
+ /** JSON that can sit in a <script> data block: no "<", so no "</script>"
11
+ * and no "<!--" can end it early. */
12
+ export declare const scriptSafeJson: (value: unknown) => string;
13
+ /** The page a chart slide is shown as. */
14
+ export declare function chartSlideDocument(title: string, chart: SlideChart): string;
@@ -1,4 +1,5 @@
1
1
  import type { ToolDefinition } from "gui-chat-protocol";
2
+ import { type SlideChart } from "./chartSlide";
2
3
  export declare const PRESENT_SLIDE = "presentSlide";
3
4
  export declare const DEFINE_STORYBOARD = "defineStoryboard";
4
5
  export declare const PRESENT_PANEL = "presentPanel";
@@ -13,16 +14,22 @@ export interface SlideArgs {
13
14
  slide: number;
14
15
  totalSlides: number;
15
16
  title: string;
16
- /** The picture's prompt; "" for an HTML slide. */
17
+ /** The picture's prompt; "" for a slide that isn't a picture. */
17
18
  imagePrompt: string;
18
- /** An HTML slide's body; absent for a picture. */
19
+ /** An HTML slide's body. */
19
20
  html?: string;
21
+ /** A Markdown slide's text, with TeX math. */
22
+ markdown?: string;
23
+ /** A chart slide's Chart.js configuration. */
24
+ chart?: SlideChart;
20
25
  mode: SlideMode;
21
26
  }
22
- export declare const SLIDE_ARGS_ERROR = "presentSlide needs slide and totalSlides (whole numbers, slide from 1 to totalSlides), and either an imagePrompt or html";
23
- export declare const SLIDE_HTML_TOO_LONG = "presentSlide's html is too long: keep a slide under 60000 characters";
27
+ export declare const SLIDE_ARGS_ERROR = "presentSlide needs slide and totalSlides (whole numbers, slide from 1 to totalSlides), and one of imagePrompt, html, markdown or chart";
28
+ export declare const SLIDE_HTML_TOO_LONG = "presentSlide's slide is too long: keep its html, markdown or chart under 60000 characters";
29
+ export declare const SLIDE_CHART_INVALID: string;
24
30
  /** The slide arguments, or what is wrong with them (said to the model). A
25
- * slide with html is an HTML slide, whatever imagePrompt says. */
31
+ * slide is one kind: html first, then markdown, then chart, then a
32
+ * picture, whatever else was sent with it. */
26
33
  export declare function parseSlideArgs(args: Record<string, unknown>): SlideArgs | string;
27
34
  /** What the model does once a slide is on the screen. */
28
35
  export declare const slideShownInstructions: ({ slide, totalSlides, title, mode, }: SlideArgs) => string;
@@ -35,19 +42,27 @@ export interface Slideshow {
35
42
  totalSlides: number;
36
43
  slides: Record<string, {
37
44
  title: string;
38
- /** "" for an HTML slide. */
45
+ /** "" for a slide that isn't a picture. */
39
46
  imagePrompt: string;
40
47
  imagePath?: string;
41
- /** An HTML slide's body (slideHtmlDocument makes it a page). */
48
+ /** An HTML slide's body (slideHtmlDocument makes it a page); for a
49
+ * Markdown slide, the HTML made of it. */
42
50
  html?: string;
51
+ /** A Markdown slide's text, as the model wrote it. */
52
+ markdown?: string;
53
+ /** A chart slide's Chart.js configuration (chartSlideDocument). */
54
+ chart?: SlideChart;
43
55
  }>;
44
56
  }
45
- /** A shown slide's result data: a picture, or an HTML slide's body. */
57
+ /** A shown slide's result data: a picture, an HTML slide's body (a
58
+ * Markdown slide's included, with its markdown), or a chart. */
46
59
  export interface SlideData {
47
60
  imageData?: string;
48
61
  imagePath?: string;
49
62
  html?: string;
50
- /** The picture's prompt; "" for an HTML slide. */
63
+ markdown?: string;
64
+ chart?: SlideChart;
65
+ /** The picture's prompt; "" for a slide that isn't a picture. */
51
66
  prompt: string;
52
67
  slideshowId: string;
53
68
  slide: number;
@@ -13,11 +13,14 @@ export declare function imageOf(result: ToolResult | null | undefined): {
13
13
  };
14
14
  /** An HTML slide's body, when the result is one. */
15
15
  export declare function htmlOf(result: ToolResult | null | undefined): string;
16
- /** Whether a result shows something: a picture or an HTML slide. */
16
+ /** A chart slide's configuration as text, when the result is one. */
17
+ export declare function chartOf(result: ToolResult | null | undefined): string;
18
+ /** Whether a result shows something: a picture, an HTML slide (a Markdown
19
+ * slide is one) or a chart. */
17
20
  export declare const shownContent: (result: ToolResult) => boolean;
18
21
  /** Whether two results show the same picture: by its saved path when both
19
22
  * have one (a host may send the current result without its image data),
20
- * else by the picture itself, or the same HTML slide. A host that sends the
23
+ * else by the picture itself, or the same HTML slide or chart. A host that sends the
21
24
  * current result by its path only can't tell an HTML slide is on the
22
25
  * screen: one asked for again is shown again. */
23
26
  export declare function samePicture(a: ToolResult | null | undefined, b: ToolResult | null | undefined): boolean;
@@ -4,6 +4,8 @@ export declare const presentSlidePluginCore: SequencePluginCore;
4
4
  export declare const defineStoryboardPluginCore: SequencePluginCore;
5
5
  export declare const presentPanelPluginCore: SequencePluginCore;
6
6
  export * from "./definitions";
7
- export { MAX_SLIDE_HTML, SLIDE_ANIMATION_KINDS, SLIDE_AUTO_END_SECONDS, SLIDE_CSS_ANIMATIONS_FINISHED, SLIDE_HEIGHT, SLIDE_WIDTH, slideHtmlDocument, } from "./slideHtml";
7
+ export { MAX_SLIDE_HTML, SLIDE_ANIMATION_KINDS, SLIDE_AUTO_END_SECONDS, SLIDE_CSS_ANIMATIONS_FINISHED, SLIDE_FIT_SCRIPT, SLIDE_HEIGHT, SLIDE_WIDTH, slideHtmlDocument, } from "./slideHtml";
8
+ export { SLIDE_CHART_TYPES, chartSlideDocument, type SlideChart, } from "./chartSlide";
9
+ export { markdownSlideHtml } from "./markdownSlide";
8
10
  export { SLIDESHOWS_DIR, STORYBOARDS_DIR, loadRecord } from "./records";
9
11
  export type { SequenceContext } from "./host";
@@ -0,0 +1,9 @@
1
+ /** The box's first font size, in px, from how much the slide says: a few
2
+ * lines are large, many smaller. The page shrinks it further when the slide
3
+ * still doesn't fit; a movie, which doesn't run the page's script, has this
4
+ * one. */
5
+ export declare function markdownFontSize(markdown: string): number;
6
+ /** KaTeX's MathML, spaced as TeX spaces it where Chrome doesn't. */
7
+ export declare const spaceFunctionNames: (mathml: string) => string;
8
+ /** A Markdown slide's HTML: the body of an HTML slide. */
9
+ export declare function markdownSlideHtml(markdown: string): Promise<string>;
@@ -11,8 +11,16 @@ export declare const SLIDE_ANIMATION_KINDS: readonly ["animate", "counter", "typ
11
11
  * it runs to the end of its beat, which the narration decides and the View
12
12
  * doesn't know. */
13
13
  export declare const SLIDE_AUTO_END_SECONDS = 8;
14
+ /** A script that fits a slide's data-fit boxes, as the View's page does, for
15
+ * a page that shows the slide's HTML without it: a host making a movie of a
16
+ * Markdown slide runs it in the movie's page (MulmoCast's html_tailwind
17
+ * beat takes it as its script), or dense text is cut off there. It fits at
18
+ * once and again when the page has loaded. */
19
+ export declare const SLIDE_FIT_SCRIPT = "(() => {\n const fit = () => {\n for (const el of document.querySelectorAll(\"[data-fit]\")) {\n let size = parseFloat(getComputedStyle(el).fontSize);\n while (size > 12 && (el.scrollHeight > el.clientHeight + 1 || el.scrollWidth > el.clientWidth + 1)) {\n size -= 1;\n el.style.fontSize = size + \"px\";\n }\n }\n };\n fit();\n addEventListener(\"load\", fit);\n})();";
14
20
  /** PAGE_SCRIPT's hash, which the policy allows (checked by a test). */
15
- export declare const PAGE_SCRIPT_HASH = "sha256-0zsqCvkCfq5Z1iJCn46NiAtSAyIr/JDkyNs/Fae1J+Y=";
21
+ export declare const PAGE_SCRIPT_HASH = "sha256-bNBxv6ehYc2PHOgmTReFSYsrxiGvq6aqqg9m5RwS7Lc=";
22
+ /** Text as HTML text or an attribute's value. */
23
+ export declare const escapeHtml: (text: string) => string;
16
24
  /** The slide's HTML, made safe to show:
17
25
  * - the tags that act on the page from outside the body are plain text:
18
26
  * <meta> (a refresh navigates the frame, a policy of its own), <base> and