@compilr-dev/sdk 0.18.1 → 0.18.2

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.
@@ -12,6 +12,18 @@
12
12
  */
13
13
  import type { PlatformToolsConfig } from '../context.js';
14
14
  import type { ControlManifest } from '../../canvas/types.js';
15
+ /**
16
+ * Guard the `html` arg against shapes that CANNOT render in the sandboxed
17
+ * canvas iframe (canvas-robustness-spec §3.3). Returns a corrective error
18
+ * string (which the agent sees as a tool error and retries on), or null if OK.
19
+ *
20
+ * Deliberately conservative — only rejects clear cases so valid HTML/SVG is
21
+ * never blocked. In particular it does NOT trip on SVG namespaces
22
+ * (`xmlns="http://www.w3.org/2000/svg"`), inline `<script>`/`<style>`, or
23
+ * `<a href="http…">` anchors (those are all fine); it targets the loaders the
24
+ * CSP actually blocks.
25
+ */
26
+ export declare function validateCanvasHtml(html: string): string | null;
15
27
  export declare function createCanvasTools(config: PlatformToolsConfig): (import("@compilr-dev/agents").Tool<{
16
28
  type: string;
17
29
  title: string;
@@ -53,6 +53,48 @@ function countOccurrences(haystack, needle) {
53
53
  }
54
54
  return count;
55
55
  }
56
+ /**
57
+ * Guard the `html` arg against shapes that CANNOT render in the sandboxed
58
+ * canvas iframe (canvas-robustness-spec §3.3). Returns a corrective error
59
+ * string (which the agent sees as a tool error and retries on), or null if OK.
60
+ *
61
+ * Deliberately conservative — only rejects clear cases so valid HTML/SVG is
62
+ * never blocked. In particular it does NOT trip on SVG namespaces
63
+ * (`xmlns="http://www.w3.org/2000/svg"`), inline `<script>`/`<style>`, or
64
+ * `<a href="http…">` anchors (those are all fine); it targets the loaders the
65
+ * CSP actually blocks.
66
+ */
67
+ export function validateCanvasHtml(html) {
68
+ const src = html.trim();
69
+ if (!src)
70
+ return null; // emptiness is handled by the caller/schema
71
+ const hasTag = /<[a-z][\s\S]*>/i.test(src);
72
+ // 1. Mermaid source (diagram keyword at the very start, and no HTML tags).
73
+ const mermaidStart = /^(?:%%\{[^}]*\}%%\s*)?(?:graph\s|flowchart\s|sequenceDiagram|classDiagram|stateDiagram|erDiagram|gantt|mindmap|journey|pie\s|gitGraph|timeline|quadrantChart)/i;
74
+ if (!hasTag && mermaidStart.test(src)) {
75
+ return ('That looks like Mermaid, not HTML. The canvas renders raw HTML/SVG in a sandbox — ' +
76
+ 'Mermaid does not run. Re-author as HTML, or draw the diagram as inline <svg> ' +
77
+ '(boxes with <rect>/<text>, connectors with <line>/<path>).');
78
+ }
79
+ // 2. Markdown source (a fenced block, or headings/lists) with no HTML tags.
80
+ if (!hasTag && (/^```/.test(src) || /^#{1,6}\s/.test(src) || /^[-*]\s/m.test(src))) {
81
+ return ('That looks like Markdown, not HTML. The canvas renders raw HTML/SVG — author it as ' +
82
+ 'HTML (e.g. <h1>, <p>, <ul><li>), not Markdown.');
83
+ }
84
+ // 3. External / CDN resources. The sandbox CSP is script-src/style-src/img-src
85
+ // 'self' 'unsafe-inline' data: blob: — no network, no CDN — so these load
86
+ // attempts are silently blocked and the canvas renders blank. Only match a
87
+ // URL immediately after a loader attribute (src=/href=/@import/fetch) so SVG
88
+ // xmlns and anchor hrefs don't false-positive.
89
+ const externalLoader = /(?:<script\b[^>]*\bsrc|<link\b[^>]*\bhref|<img\b[^>]*\bsrc|@import\s+(?:url\()?)\s*=?\s*["'(]?\s*(?:https?:)?\/\//i;
90
+ const externalFetch = /\bfetch\s*\(\s*["'`](?:https?:)?\/\//i;
91
+ if (externalLoader.test(src) || externalFetch.test(src)) {
92
+ return ('The canvas sandbox blocks external scripts, styles, and images (no network / CDN). ' +
93
+ 'Inline everything: use inline <svg> instead of a CDN library like Mermaid or Chart.js, ' +
94
+ 'inline <style>/<script>, and data: URIs (or inline SVG) for images.');
95
+ }
96
+ return null;
97
+ }
56
98
  // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
57
99
  export function createCanvasTools(config) {
58
100
  const ctx = config.context;
@@ -64,7 +106,10 @@ export function createCanvasTools(config) {
64
106
  // ---------------------------------------------------------------------------
65
107
  const canvasWriteTool = defineTool({
66
108
  name: 'canvas_write',
67
- description: 'Create or update a visual canvas (infographic, carousel, or board) rendered from HTML/SVG. ' +
109
+ description: 'Create or update a visual canvas — use this for ANY visual deliverable: a mockup, UI layout, ' +
110
+ 'diagram, poster, infographic, slide deck, board, or a DESIGN PROPOSAL / REVAMP the user asks to "sketch", ' +
111
+ '"visualize", "propose a layout", or "redesign". (For a plain list of text options to pick from, that is ' +
112
+ 'propose_alternatives, not this.) The canvas is authored as raw HTML/SVG (infographic, carousel, or board). ' +
68
113
  'Optionally declare a controls manifest ("Tweaks") of live parameters the user can adjust: ' +
69
114
  'each control is { type: slider|number|toggle|select|color|text, param, label, default, ...type config }. ' +
70
115
  'Bind params in your HTML via CSS custom properties var(--param), [data-bind="param"] text, and ' +
@@ -84,8 +129,11 @@ export function createCanvasTools(config) {
84
129
  title: { type: 'string', description: 'Canvas title (shown in the library and tab).' },
85
130
  html: {
86
131
  type: 'string',
87
- description: 'The canvas content as HTML/SVG. Raw content only — the app injects the sandbox/CSP. ' +
88
- 'May include a <script> defining window.applyParams(values) for live recompute.',
132
+ description: 'The canvas content as RAW HTML/SVG — NOT Mermaid, NOT Markdown. The app renders it in a ' +
133
+ 'sandboxed iframe with a strict CSP: NO external scripts/styles/images and NO network, so ' +
134
+ 'inline everything (inline <style>/<script>, inline <svg> instead of a CDN chart/diagram ' +
135
+ 'library, data: URIs for images). May include a <script> defining window.applyParams(values) ' +
136
+ 'for live recompute.',
89
137
  },
90
138
  controls: {
91
139
  type: 'object',
@@ -114,6 +162,12 @@ export function createCanvasTools(config) {
114
162
  },
115
163
  execute: async (input) => {
116
164
  try {
165
+ // Reject content that can't render in the sandbox (Mermaid/Markdown/
166
+ // external-CDN) with a corrective message → the agent retries with
167
+ // inline HTML/SVG instead of persisting a blank canvas.
168
+ const htmlError = validateCanvasHtml(input.html);
169
+ if (htmlError)
170
+ return createErrorResult(htmlError);
117
171
  if (input.controls) {
118
172
  const check = validateControlManifest(input.controls);
119
173
  if (!check.ok) {
@@ -25,10 +25,12 @@ import { defineTool } from '@compilr-dev/agents';
25
25
  export function createProposeAlternativesTool(handler) {
26
26
  return defineTool({
27
27
  name: 'propose_alternatives',
28
- description: 'Present 2-3 alternatives for the user to compare and choose from. ' +
29
- "Use when there are multiple valid approaches and the user's preference matters. " +
30
- 'Each alternative can include rich content (code, markdown, mermaid diagrams) for visual comparison. ' +
31
- 'Include pros and cons to help the user decide. The user picks one or provides feedback.',
28
+ description: 'Present 2-3 alternatives for the user to COMPARE and CHOOSE from — a DECISION tool for when ' +
29
+ "multiple valid approaches exist and the user's preference matters. Each alternative is a short " +
30
+ 'text/code summary with pros and cons; the user picks one or gives feedback. ' +
31
+ 'Do NOT use this to produce a visual deliverable — a mockup, UI layout, poster, diagram, or a ' +
32
+ 'design PROPOSAL/REVAMP the user wants to SEE rendered. For anything visual, use the canvas ' +
33
+ '(canvas_write), even when the request says "propose" or "alternatives".',
32
34
  inputSchema: {
33
35
  type: 'object',
34
36
  properties: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@compilr-dev/sdk",
3
- "version": "0.18.1",
3
+ "version": "0.18.2",
4
4
  "description": "Universal agent runtime for building AI-powered applications",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",