@ai-gui/core 0.4.4 → 0.5.0
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/dist/index.cjs +84 -2
- package/dist/index.d.cts +64 -2
- package/dist/index.d.ts +64 -2
- package/dist/index.js +82 -3
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1404,7 +1404,7 @@ function collectNodeRenderers(plugins = [], debugOptions = {}) {
|
|
|
1404
1404
|
map[k] = render;
|
|
1405
1405
|
continue;
|
|
1406
1406
|
}
|
|
1407
|
-
map[k] = (node) => {
|
|
1407
|
+
map[k] = (node, context) => {
|
|
1408
1408
|
const emit = (type, data) => target?.emitDebug(type, data) ?? debug?.emit(type, data);
|
|
1409
1409
|
emit("plugin-render-started", {
|
|
1410
1410
|
plugin: p.name,
|
|
@@ -1412,7 +1412,7 @@ function collectNodeRenderers(plugins = [], debugOptions = {}) {
|
|
|
1412
1412
|
nodeKey: node.key
|
|
1413
1413
|
});
|
|
1414
1414
|
try {
|
|
1415
|
-
const output = render(node);
|
|
1415
|
+
const output = render(node, context);
|
|
1416
1416
|
if (isPromise(output)) return output.then((resolved) => {
|
|
1417
1417
|
emit("async-output-resolved", {
|
|
1418
1418
|
plugin: p.name,
|
|
@@ -1672,6 +1672,85 @@ function normalizeLineEndings(src) {
|
|
|
1672
1672
|
return src.replace(/\r\n|\r/g, "\n");
|
|
1673
1673
|
}
|
|
1674
1674
|
|
|
1675
|
+
//#endregion
|
|
1676
|
+
//#region src/export-image.ts
|
|
1677
|
+
/** The intrinsic size of an SVG element, falling back to its attributes and then to a default. */
|
|
1678
|
+
function measure(svg, options) {
|
|
1679
|
+
const box = typeof svg.getBoundingClientRect === "function" ? svg.getBoundingClientRect() : void 0;
|
|
1680
|
+
const attribute = (name) => Number.parseFloat(svg.getAttribute(name) ?? "");
|
|
1681
|
+
const fromViewBox = (index) => {
|
|
1682
|
+
const parts = (svg.getAttribute("viewBox") ?? "").split(/[\s,]+/).map(Number);
|
|
1683
|
+
return parts.length === 4 && Number.isFinite(parts[index]) ? parts[index] : Number.NaN;
|
|
1684
|
+
};
|
|
1685
|
+
const pick = (...candidates) => candidates.find((value) => Number.isFinite(value) && value > 0);
|
|
1686
|
+
return {
|
|
1687
|
+
width: Math.round(pick(options.width ?? Number.NaN, box?.width ?? Number.NaN, attribute("width"), fromViewBox(2), 720)),
|
|
1688
|
+
height: Math.round(pick(options.height ?? Number.NaN, box?.height ?? Number.NaN, attribute("height"), fromViewBox(3), 400))
|
|
1689
|
+
};
|
|
1690
|
+
}
|
|
1691
|
+
/**
|
|
1692
|
+
* Render an SVG element to a raster data URL.
|
|
1693
|
+
*
|
|
1694
|
+
* The element is serialized as it stands, so whatever a plugin drew — including the theme it drew
|
|
1695
|
+
* it in — is what gets exported.
|
|
1696
|
+
*/
|
|
1697
|
+
async function exportSVGToImage(svg, options = {}) {
|
|
1698
|
+
const { width, height } = measure(svg, options);
|
|
1699
|
+
const scale = options.scale && options.scale > 0 ? options.scale : globalThis.devicePixelRatio || 1;
|
|
1700
|
+
const source = new XMLSerializer().serializeToString(svg);
|
|
1701
|
+
const namespaced = /\sxmlns=/.test(source) ? source : source.replace(/^<svg/, "<svg xmlns=\"http://www.w3.org/2000/svg\"");
|
|
1702
|
+
const url = URL.createObjectURL(new Blob([namespaced], { type: "image/svg+xml;charset=utf-8" }));
|
|
1703
|
+
try {
|
|
1704
|
+
const image = await loadImage(url);
|
|
1705
|
+
const canvas = document.createElement("canvas");
|
|
1706
|
+
canvas.width = Math.max(1, Math.round(width * scale));
|
|
1707
|
+
canvas.height = Math.max(1, Math.round(height * scale));
|
|
1708
|
+
const context = canvas.getContext("2d");
|
|
1709
|
+
if (!context) throw new Error("This browser cannot rasterize images");
|
|
1710
|
+
const background = options.background ?? "#ffffff";
|
|
1711
|
+
if (background !== "transparent") {
|
|
1712
|
+
context.fillStyle = background;
|
|
1713
|
+
context.fillRect(0, 0, canvas.width, canvas.height);
|
|
1714
|
+
}
|
|
1715
|
+
context.scale(scale, scale);
|
|
1716
|
+
context.drawImage(image, 0, 0, width, height);
|
|
1717
|
+
return {
|
|
1718
|
+
dataUrl: canvas.toDataURL(options.type ?? "image/png", options.quality),
|
|
1719
|
+
width: canvas.width,
|
|
1720
|
+
height: canvas.height
|
|
1721
|
+
};
|
|
1722
|
+
} finally {
|
|
1723
|
+
URL.revokeObjectURL(url);
|
|
1724
|
+
}
|
|
1725
|
+
}
|
|
1726
|
+
/**
|
|
1727
|
+
* Export every drawing inside a rendered answer.
|
|
1728
|
+
*
|
|
1729
|
+
* A host holds the element it handed to the renderer, not the individual charts, and the plugins
|
|
1730
|
+
* decide what lands in it.
|
|
1731
|
+
*/
|
|
1732
|
+
async function exportRenderedImages(root, options = {}) {
|
|
1733
|
+
const drawings = Array.from(root.querySelectorAll("svg"));
|
|
1734
|
+
const exported = [];
|
|
1735
|
+
for (const drawing of drawings) exported.push(await exportSVGToImage(drawing, options));
|
|
1736
|
+
return exported;
|
|
1737
|
+
}
|
|
1738
|
+
/** Save an exported image under the given file name. */
|
|
1739
|
+
function downloadImage(image, filename) {
|
|
1740
|
+
const link = document.createElement("a");
|
|
1741
|
+
link.download = filename;
|
|
1742
|
+
link.href = image.dataUrl;
|
|
1743
|
+
link.click();
|
|
1744
|
+
}
|
|
1745
|
+
function loadImage(url) {
|
|
1746
|
+
return new Promise((resolve, reject) => {
|
|
1747
|
+
const image = new Image();
|
|
1748
|
+
image.onload = () => resolve(image);
|
|
1749
|
+
image.onerror = () => reject(new Error("The drawing could not be decoded"));
|
|
1750
|
+
image.src = url;
|
|
1751
|
+
});
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1675
1754
|
//#endregion
|
|
1676
1755
|
//#region src/diff.ts
|
|
1677
1756
|
/** Produce a minimal set of patches turning `prev` into `next`, keyed by node key. */
|
|
@@ -2550,6 +2629,9 @@ exports.createActionRuntime = createActionRuntime
|
|
|
2550
2629
|
exports.createParser = createParser
|
|
2551
2630
|
exports.createParserWithMetadata = createParserWithMetadata
|
|
2552
2631
|
exports.diffAst = diffAst
|
|
2632
|
+
exports.downloadImage = downloadImage
|
|
2633
|
+
exports.exportRenderedImages = exportRenderedImages
|
|
2634
|
+
exports.exportSVGToImage = exportSVGToImage
|
|
2553
2635
|
exports.getActionKey = getActionKey
|
|
2554
2636
|
exports.getIdleActionState = getIdleActionState
|
|
2555
2637
|
exports.isCardPatchResult = isCardPatchResult
|
package/dist/index.d.cts
CHANGED
|
@@ -166,7 +166,18 @@ interface MountedCardSlot {
|
|
|
166
166
|
interface RenderMountContext {
|
|
167
167
|
mountCard?: (host: HTMLElement, request: MountCardSlotRequest) => MountedCardSlot | undefined;
|
|
168
168
|
}
|
|
169
|
-
|
|
169
|
+
/** What the host can tell a plugin about the surroundings it is rendering into. */
|
|
170
|
+
interface NodeRenderContext {
|
|
171
|
+
/**
|
|
172
|
+
* The host's colour scheme, "light" or "dark" by convention.
|
|
173
|
+
*
|
|
174
|
+
* A diagram or a chart picks its own palette, and a plugin has no way to read the palette of
|
|
175
|
+
* the page it is embedded in, so without this an answer rendered on a dark page comes back
|
|
176
|
+
* with white plot areas.
|
|
177
|
+
*/
|
|
178
|
+
readonly theme?: string;
|
|
179
|
+
}
|
|
180
|
+
type NodeRenderer = (node: ASTNode, context?: NodeRenderContext) => RenderOutput | Promise<RenderOutput>;
|
|
170
181
|
interface PluginCommitContext {
|
|
171
182
|
readonly generation: number;
|
|
172
183
|
emitDebug(type: string, data?: Record<string, unknown>): void;
|
|
@@ -550,6 +561,57 @@ declare function collectNodeRenderers(plugins?: AIGuiPlugin[], debugOptions?: Co
|
|
|
550
561
|
/** The set of node types claimed by the given plugins. */
|
|
551
562
|
declare function pluginNodeTypes(plugins?: AIGuiPlugin[]): Set<string>;
|
|
552
563
|
|
|
564
|
+
//#endregion
|
|
565
|
+
//#region src/export-image.d.ts
|
|
566
|
+
/**
|
|
567
|
+
* Turn what a plugin drew into a PNG the reader can keep.
|
|
568
|
+
*
|
|
569
|
+
* Charts and diagrams are the point of rendering a model's answer, and the first thing anyone
|
|
570
|
+
* wants to do with one is save it. There is no browser API for "download this SVG as an image":
|
|
571
|
+
* it has to be serialized, loaded through an `Image`, and painted onto a canvas. Every host that
|
|
572
|
+
* needs it rewrites those twenty lines, and gets the same details wrong — a transparent
|
|
573
|
+
* background that turns black in a viewer, a blurry export on a retina screen, or a light
|
|
574
|
+
* background hardcoded into a page that has since gone dark.
|
|
575
|
+
*/
|
|
576
|
+
interface ExportImageOptions {
|
|
577
|
+
/**
|
|
578
|
+
* Device pixels per CSS pixel. Defaults to the screen's own ratio, so an export looks as sharp
|
|
579
|
+
* as what it was copied from rather than half the resolution on a retina display.
|
|
580
|
+
*/
|
|
581
|
+
scale?: number;
|
|
582
|
+
/**
|
|
583
|
+
* What to paint behind the drawing. An SVG is usually transparent, which reads as black in most
|
|
584
|
+
* image viewers. Pass the page's own background — or "transparent" to keep the alpha channel.
|
|
585
|
+
*/
|
|
586
|
+
background?: string;
|
|
587
|
+
/** Overrides for the drawing's own size, in CSS pixels. */
|
|
588
|
+
width?: number;
|
|
589
|
+
height?: number;
|
|
590
|
+
type?: "image/png" | "image/jpeg" | "image/webp";
|
|
591
|
+
quality?: number;
|
|
592
|
+
}
|
|
593
|
+
interface ExportedImage {
|
|
594
|
+
dataUrl: string;
|
|
595
|
+
width: number;
|
|
596
|
+
height: number;
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* Render an SVG element to a raster data URL.
|
|
600
|
+
*
|
|
601
|
+
* The element is serialized as it stands, so whatever a plugin drew — including the theme it drew
|
|
602
|
+
* it in — is what gets exported.
|
|
603
|
+
*/
|
|
604
|
+
declare function exportSVGToImage(svg: SVGElement, options?: ExportImageOptions): Promise<ExportedImage>;
|
|
605
|
+
/**
|
|
606
|
+
* Export every drawing inside a rendered answer.
|
|
607
|
+
*
|
|
608
|
+
* A host holds the element it handed to the renderer, not the individual charts, and the plugins
|
|
609
|
+
* decide what lands in it.
|
|
610
|
+
*/
|
|
611
|
+
declare function exportRenderedImages(root: ParentNode, options?: ExportImageOptions): Promise<ExportedImage[]>;
|
|
612
|
+
/** Save an exported image under the given file name. */
|
|
613
|
+
declare function downloadImage(image: ExportedImage, filename: string): void;
|
|
614
|
+
|
|
553
615
|
//#endregion
|
|
554
616
|
//#region src/diff.d.ts
|
|
555
617
|
/** Produce a minimal set of patches turning `prev` into `next`, keyed by node key. */
|
|
@@ -694,4 +756,4 @@ declare function mockModelStream(events: Iterable<ModelStreamEvent> | AsyncItera
|
|
|
694
756
|
declare function readableBytes(chunks: Iterable<string | Uint8Array> | AsyncIterable<string | Uint8Array>): ReadableStream<Uint8Array>;
|
|
695
757
|
|
|
696
758
|
//#endregion
|
|
697
|
-
export { AIGuiPlugin, ASTNode, ActionAbortedError, ActionAlreadyRegisteredError, ActionContext, ActionDefinition, ActionDestroyedError, ActionDispatchOptions, ActionErrorEvent, ActionEventBase, ActionExecutionError, ActionNotFoundError, ActionRegisterOptions, ActionRegistry, ActionRequest, ActionRuntime, ActionRuntimeError, ActionRuntimeOptions, ActionStartEvent, ActionState, ActionStateListener, ActionStatus, ActionSuccessEvent, ActionTimeoutError, ActionValidationError, BuildSystemPromptOptions, ByteStreamSource, CARD_ID_MAX_LENGTH, CARD_JSON_MAX_DEPTH, CARD_JSON_MAX_NODES, CARD_PATCH_BATCH_MAX_SIZE, CardAction, CardActionError, CardDef, CardJSONError, CardLimitError, CardListener, CardNotFoundError, CardParseResult, CardPatch, CardPatchBatch, CardPatchResult, CardRecord, CardRegistry, CardRevisionConflictError, CardSnapshot, CardSnapshotError, CardStore, CardStoreError, CardStoreListener, CardStoreOptions, CardTypeConflictError, CardValidationError, ChannelSink, Citation, CollectNodeRendererOptions, DebugEmitter, DebugEvent, DebugEventListener, DebugEventTarget, DebugInstrumentationTarget, DebugOptions, DebugRedactContext, DebugSource, FeedChunk, FeedOptions, FeedSource, JSONSchema, JSONSchemaValidationResult, ModelStreamEvent, MountCardSlotRequest, MountedCardSlot, NodeRenderer, ParseResult, ParserOptions, PartialJSONResult, Patch, PluginCommitContext, RenderMountContext, RenderOutput, Renderer, RendererOptions, SSEEvent, SSEOptions, SafeDebugValueOptions, SanitizeHtmlOptions, SourceBlock, StreamParseOptions, StreamRouter, Usage, applyPatches, buildSystemPrompt, collectNodeRenderers, contentDeltas, createActionRuntime, createParser, createParserWithMetadata, diffAst, getActionKey, getIdleActionState, isCardPatchResult, jsonLines, mockModelStream, ndjson, parsePartialJSON, parseSSE, pluginNodeTypes, readableBytes, repairMarkdown, safeDebugValue, sanitizeHtml, textLines, validateJSONSchema };
|
|
759
|
+
export { AIGuiPlugin, ASTNode, ActionAbortedError, ActionAlreadyRegisteredError, ActionContext, ActionDefinition, ActionDestroyedError, ActionDispatchOptions, ActionErrorEvent, ActionEventBase, ActionExecutionError, ActionNotFoundError, ActionRegisterOptions, ActionRegistry, ActionRequest, ActionRuntime, ActionRuntimeError, ActionRuntimeOptions, ActionStartEvent, ActionState, ActionStateListener, ActionStatus, ActionSuccessEvent, ActionTimeoutError, ActionValidationError, BuildSystemPromptOptions, ByteStreamSource, CARD_ID_MAX_LENGTH, CARD_JSON_MAX_DEPTH, CARD_JSON_MAX_NODES, CARD_PATCH_BATCH_MAX_SIZE, CardAction, CardActionError, CardDef, CardJSONError, CardLimitError, CardListener, CardNotFoundError, CardParseResult, CardPatch, CardPatchBatch, CardPatchResult, CardRecord, CardRegistry, CardRevisionConflictError, CardSnapshot, CardSnapshotError, CardStore, CardStoreError, CardStoreListener, CardStoreOptions, CardTypeConflictError, CardValidationError, ChannelSink, Citation, CollectNodeRendererOptions, DebugEmitter, DebugEvent, DebugEventListener, DebugEventTarget, DebugInstrumentationTarget, DebugOptions, DebugRedactContext, DebugSource, ExportImageOptions, ExportedImage, FeedChunk, FeedOptions, FeedSource, JSONSchema, JSONSchemaValidationResult, ModelStreamEvent, MountCardSlotRequest, MountedCardSlot, NodeRenderContext, NodeRenderer, ParseResult, ParserOptions, PartialJSONResult, Patch, PluginCommitContext, RenderMountContext, RenderOutput, Renderer, RendererOptions, SSEEvent, SSEOptions, SafeDebugValueOptions, SanitizeHtmlOptions, SourceBlock, StreamParseOptions, StreamRouter, Usage, applyPatches, buildSystemPrompt, collectNodeRenderers, contentDeltas, createActionRuntime, createParser, createParserWithMetadata, diffAst, downloadImage, exportRenderedImages, exportSVGToImage, getActionKey, getIdleActionState, isCardPatchResult, jsonLines, mockModelStream, ndjson, parsePartialJSON, parseSSE, pluginNodeTypes, readableBytes, repairMarkdown, safeDebugValue, sanitizeHtml, textLines, validateJSONSchema };
|
package/dist/index.d.ts
CHANGED
|
@@ -166,7 +166,18 @@ interface MountedCardSlot {
|
|
|
166
166
|
interface RenderMountContext {
|
|
167
167
|
mountCard?: (host: HTMLElement, request: MountCardSlotRequest) => MountedCardSlot | undefined;
|
|
168
168
|
}
|
|
169
|
-
|
|
169
|
+
/** What the host can tell a plugin about the surroundings it is rendering into. */
|
|
170
|
+
interface NodeRenderContext {
|
|
171
|
+
/**
|
|
172
|
+
* The host's colour scheme, "light" or "dark" by convention.
|
|
173
|
+
*
|
|
174
|
+
* A diagram or a chart picks its own palette, and a plugin has no way to read the palette of
|
|
175
|
+
* the page it is embedded in, so without this an answer rendered on a dark page comes back
|
|
176
|
+
* with white plot areas.
|
|
177
|
+
*/
|
|
178
|
+
readonly theme?: string;
|
|
179
|
+
}
|
|
180
|
+
type NodeRenderer = (node: ASTNode, context?: NodeRenderContext) => RenderOutput | Promise<RenderOutput>;
|
|
170
181
|
interface PluginCommitContext {
|
|
171
182
|
readonly generation: number;
|
|
172
183
|
emitDebug(type: string, data?: Record<string, unknown>): void;
|
|
@@ -550,6 +561,57 @@ declare function collectNodeRenderers(plugins?: AIGuiPlugin[], debugOptions?: Co
|
|
|
550
561
|
/** The set of node types claimed by the given plugins. */
|
|
551
562
|
declare function pluginNodeTypes(plugins?: AIGuiPlugin[]): Set<string>;
|
|
552
563
|
|
|
564
|
+
//#endregion
|
|
565
|
+
//#region src/export-image.d.ts
|
|
566
|
+
/**
|
|
567
|
+
* Turn what a plugin drew into a PNG the reader can keep.
|
|
568
|
+
*
|
|
569
|
+
* Charts and diagrams are the point of rendering a model's answer, and the first thing anyone
|
|
570
|
+
* wants to do with one is save it. There is no browser API for "download this SVG as an image":
|
|
571
|
+
* it has to be serialized, loaded through an `Image`, and painted onto a canvas. Every host that
|
|
572
|
+
* needs it rewrites those twenty lines, and gets the same details wrong — a transparent
|
|
573
|
+
* background that turns black in a viewer, a blurry export on a retina screen, or a light
|
|
574
|
+
* background hardcoded into a page that has since gone dark.
|
|
575
|
+
*/
|
|
576
|
+
interface ExportImageOptions {
|
|
577
|
+
/**
|
|
578
|
+
* Device pixels per CSS pixel. Defaults to the screen's own ratio, so an export looks as sharp
|
|
579
|
+
* as what it was copied from rather than half the resolution on a retina display.
|
|
580
|
+
*/
|
|
581
|
+
scale?: number;
|
|
582
|
+
/**
|
|
583
|
+
* What to paint behind the drawing. An SVG is usually transparent, which reads as black in most
|
|
584
|
+
* image viewers. Pass the page's own background — or "transparent" to keep the alpha channel.
|
|
585
|
+
*/
|
|
586
|
+
background?: string;
|
|
587
|
+
/** Overrides for the drawing's own size, in CSS pixels. */
|
|
588
|
+
width?: number;
|
|
589
|
+
height?: number;
|
|
590
|
+
type?: "image/png" | "image/jpeg" | "image/webp";
|
|
591
|
+
quality?: number;
|
|
592
|
+
}
|
|
593
|
+
interface ExportedImage {
|
|
594
|
+
dataUrl: string;
|
|
595
|
+
width: number;
|
|
596
|
+
height: number;
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* Render an SVG element to a raster data URL.
|
|
600
|
+
*
|
|
601
|
+
* The element is serialized as it stands, so whatever a plugin drew — including the theme it drew
|
|
602
|
+
* it in — is what gets exported.
|
|
603
|
+
*/
|
|
604
|
+
declare function exportSVGToImage(svg: SVGElement, options?: ExportImageOptions): Promise<ExportedImage>;
|
|
605
|
+
/**
|
|
606
|
+
* Export every drawing inside a rendered answer.
|
|
607
|
+
*
|
|
608
|
+
* A host holds the element it handed to the renderer, not the individual charts, and the plugins
|
|
609
|
+
* decide what lands in it.
|
|
610
|
+
*/
|
|
611
|
+
declare function exportRenderedImages(root: ParentNode, options?: ExportImageOptions): Promise<ExportedImage[]>;
|
|
612
|
+
/** Save an exported image under the given file name. */
|
|
613
|
+
declare function downloadImage(image: ExportedImage, filename: string): void;
|
|
614
|
+
|
|
553
615
|
//#endregion
|
|
554
616
|
//#region src/diff.d.ts
|
|
555
617
|
/** Produce a minimal set of patches turning `prev` into `next`, keyed by node key. */
|
|
@@ -694,4 +756,4 @@ declare function mockModelStream(events: Iterable<ModelStreamEvent> | AsyncItera
|
|
|
694
756
|
declare function readableBytes(chunks: Iterable<string | Uint8Array> | AsyncIterable<string | Uint8Array>): ReadableStream<Uint8Array>;
|
|
695
757
|
|
|
696
758
|
//#endregion
|
|
697
|
-
export { AIGuiPlugin, ASTNode, ActionAbortedError, ActionAlreadyRegisteredError, ActionContext, ActionDefinition, ActionDestroyedError, ActionDispatchOptions, ActionErrorEvent, ActionEventBase, ActionExecutionError, ActionNotFoundError, ActionRegisterOptions, ActionRegistry, ActionRequest, ActionRuntime, ActionRuntimeError, ActionRuntimeOptions, ActionStartEvent, ActionState, ActionStateListener, ActionStatus, ActionSuccessEvent, ActionTimeoutError, ActionValidationError, BuildSystemPromptOptions, ByteStreamSource, CARD_ID_MAX_LENGTH, CARD_JSON_MAX_DEPTH, CARD_JSON_MAX_NODES, CARD_PATCH_BATCH_MAX_SIZE, CardAction, CardActionError, CardDef, CardJSONError, CardLimitError, CardListener, CardNotFoundError, CardParseResult, CardPatch, CardPatchBatch, CardPatchResult, CardRecord, CardRegistry, CardRevisionConflictError, CardSnapshot, CardSnapshotError, CardStore, CardStoreError, CardStoreListener, CardStoreOptions, CardTypeConflictError, CardValidationError, ChannelSink, Citation, CollectNodeRendererOptions, DebugEmitter, DebugEvent, DebugEventListener, DebugEventTarget, DebugInstrumentationTarget, DebugOptions, DebugRedactContext, DebugSource, FeedChunk, FeedOptions, FeedSource, JSONSchema, JSONSchemaValidationResult, ModelStreamEvent, MountCardSlotRequest, MountedCardSlot, NodeRenderer, ParseResult, ParserOptions, PartialJSONResult, Patch, PluginCommitContext, RenderMountContext, RenderOutput, Renderer, RendererOptions, SSEEvent, SSEOptions, SafeDebugValueOptions, SanitizeHtmlOptions, SourceBlock, StreamParseOptions, StreamRouter, Usage, applyPatches, buildSystemPrompt, collectNodeRenderers, contentDeltas, createActionRuntime, createParser, createParserWithMetadata, diffAst, getActionKey, getIdleActionState, isCardPatchResult, jsonLines, mockModelStream, ndjson, parsePartialJSON, parseSSE, pluginNodeTypes, readableBytes, repairMarkdown, safeDebugValue, sanitizeHtml, textLines, validateJSONSchema };
|
|
759
|
+
export { AIGuiPlugin, ASTNode, ActionAbortedError, ActionAlreadyRegisteredError, ActionContext, ActionDefinition, ActionDestroyedError, ActionDispatchOptions, ActionErrorEvent, ActionEventBase, ActionExecutionError, ActionNotFoundError, ActionRegisterOptions, ActionRegistry, ActionRequest, ActionRuntime, ActionRuntimeError, ActionRuntimeOptions, ActionStartEvent, ActionState, ActionStateListener, ActionStatus, ActionSuccessEvent, ActionTimeoutError, ActionValidationError, BuildSystemPromptOptions, ByteStreamSource, CARD_ID_MAX_LENGTH, CARD_JSON_MAX_DEPTH, CARD_JSON_MAX_NODES, CARD_PATCH_BATCH_MAX_SIZE, CardAction, CardActionError, CardDef, CardJSONError, CardLimitError, CardListener, CardNotFoundError, CardParseResult, CardPatch, CardPatchBatch, CardPatchResult, CardRecord, CardRegistry, CardRevisionConflictError, CardSnapshot, CardSnapshotError, CardStore, CardStoreError, CardStoreListener, CardStoreOptions, CardTypeConflictError, CardValidationError, ChannelSink, Citation, CollectNodeRendererOptions, DebugEmitter, DebugEvent, DebugEventListener, DebugEventTarget, DebugInstrumentationTarget, DebugOptions, DebugRedactContext, DebugSource, ExportImageOptions, ExportedImage, FeedChunk, FeedOptions, FeedSource, JSONSchema, JSONSchemaValidationResult, ModelStreamEvent, MountCardSlotRequest, MountedCardSlot, NodeRenderContext, NodeRenderer, ParseResult, ParserOptions, PartialJSONResult, Patch, PluginCommitContext, RenderMountContext, RenderOutput, Renderer, RendererOptions, SSEEvent, SSEOptions, SafeDebugValueOptions, SanitizeHtmlOptions, SourceBlock, StreamParseOptions, StreamRouter, Usage, applyPatches, buildSystemPrompt, collectNodeRenderers, contentDeltas, createActionRuntime, createParser, createParserWithMetadata, diffAst, downloadImage, exportRenderedImages, exportSVGToImage, getActionKey, getIdleActionState, isCardPatchResult, jsonLines, mockModelStream, ndjson, parsePartialJSON, parseSSE, pluginNodeTypes, readableBytes, repairMarkdown, safeDebugValue, sanitizeHtml, textLines, validateJSONSchema };
|
package/dist/index.js
CHANGED
|
@@ -1380,7 +1380,7 @@ function collectNodeRenderers(plugins = [], debugOptions = {}) {
|
|
|
1380
1380
|
map[k] = render;
|
|
1381
1381
|
continue;
|
|
1382
1382
|
}
|
|
1383
|
-
map[k] = (node) => {
|
|
1383
|
+
map[k] = (node, context) => {
|
|
1384
1384
|
const emit = (type, data) => target?.emitDebug(type, data) ?? debug?.emit(type, data);
|
|
1385
1385
|
emit("plugin-render-started", {
|
|
1386
1386
|
plugin: p.name,
|
|
@@ -1388,7 +1388,7 @@ function collectNodeRenderers(plugins = [], debugOptions = {}) {
|
|
|
1388
1388
|
nodeKey: node.key
|
|
1389
1389
|
});
|
|
1390
1390
|
try {
|
|
1391
|
-
const output = render(node);
|
|
1391
|
+
const output = render(node, context);
|
|
1392
1392
|
if (isPromise(output)) return output.then((resolved) => {
|
|
1393
1393
|
emit("async-output-resolved", {
|
|
1394
1394
|
plugin: p.name,
|
|
@@ -1648,6 +1648,85 @@ function normalizeLineEndings(src) {
|
|
|
1648
1648
|
return src.replace(/\r\n|\r/g, "\n");
|
|
1649
1649
|
}
|
|
1650
1650
|
|
|
1651
|
+
//#endregion
|
|
1652
|
+
//#region src/export-image.ts
|
|
1653
|
+
/** The intrinsic size of an SVG element, falling back to its attributes and then to a default. */
|
|
1654
|
+
function measure(svg, options) {
|
|
1655
|
+
const box = typeof svg.getBoundingClientRect === "function" ? svg.getBoundingClientRect() : void 0;
|
|
1656
|
+
const attribute = (name) => Number.parseFloat(svg.getAttribute(name) ?? "");
|
|
1657
|
+
const fromViewBox = (index) => {
|
|
1658
|
+
const parts = (svg.getAttribute("viewBox") ?? "").split(/[\s,]+/).map(Number);
|
|
1659
|
+
return parts.length === 4 && Number.isFinite(parts[index]) ? parts[index] : Number.NaN;
|
|
1660
|
+
};
|
|
1661
|
+
const pick = (...candidates) => candidates.find((value) => Number.isFinite(value) && value > 0);
|
|
1662
|
+
return {
|
|
1663
|
+
width: Math.round(pick(options.width ?? Number.NaN, box?.width ?? Number.NaN, attribute("width"), fromViewBox(2), 720)),
|
|
1664
|
+
height: Math.round(pick(options.height ?? Number.NaN, box?.height ?? Number.NaN, attribute("height"), fromViewBox(3), 400))
|
|
1665
|
+
};
|
|
1666
|
+
}
|
|
1667
|
+
/**
|
|
1668
|
+
* Render an SVG element to a raster data URL.
|
|
1669
|
+
*
|
|
1670
|
+
* The element is serialized as it stands, so whatever a plugin drew — including the theme it drew
|
|
1671
|
+
* it in — is what gets exported.
|
|
1672
|
+
*/
|
|
1673
|
+
async function exportSVGToImage(svg, options = {}) {
|
|
1674
|
+
const { width, height } = measure(svg, options);
|
|
1675
|
+
const scale = options.scale && options.scale > 0 ? options.scale : globalThis.devicePixelRatio || 1;
|
|
1676
|
+
const source = new XMLSerializer().serializeToString(svg);
|
|
1677
|
+
const namespaced = /\sxmlns=/.test(source) ? source : source.replace(/^<svg/, "<svg xmlns=\"http://www.w3.org/2000/svg\"");
|
|
1678
|
+
const url = URL.createObjectURL(new Blob([namespaced], { type: "image/svg+xml;charset=utf-8" }));
|
|
1679
|
+
try {
|
|
1680
|
+
const image = await loadImage(url);
|
|
1681
|
+
const canvas = document.createElement("canvas");
|
|
1682
|
+
canvas.width = Math.max(1, Math.round(width * scale));
|
|
1683
|
+
canvas.height = Math.max(1, Math.round(height * scale));
|
|
1684
|
+
const context = canvas.getContext("2d");
|
|
1685
|
+
if (!context) throw new Error("This browser cannot rasterize images");
|
|
1686
|
+
const background = options.background ?? "#ffffff";
|
|
1687
|
+
if (background !== "transparent") {
|
|
1688
|
+
context.fillStyle = background;
|
|
1689
|
+
context.fillRect(0, 0, canvas.width, canvas.height);
|
|
1690
|
+
}
|
|
1691
|
+
context.scale(scale, scale);
|
|
1692
|
+
context.drawImage(image, 0, 0, width, height);
|
|
1693
|
+
return {
|
|
1694
|
+
dataUrl: canvas.toDataURL(options.type ?? "image/png", options.quality),
|
|
1695
|
+
width: canvas.width,
|
|
1696
|
+
height: canvas.height
|
|
1697
|
+
};
|
|
1698
|
+
} finally {
|
|
1699
|
+
URL.revokeObjectURL(url);
|
|
1700
|
+
}
|
|
1701
|
+
}
|
|
1702
|
+
/**
|
|
1703
|
+
* Export every drawing inside a rendered answer.
|
|
1704
|
+
*
|
|
1705
|
+
* A host holds the element it handed to the renderer, not the individual charts, and the plugins
|
|
1706
|
+
* decide what lands in it.
|
|
1707
|
+
*/
|
|
1708
|
+
async function exportRenderedImages(root, options = {}) {
|
|
1709
|
+
const drawings = Array.from(root.querySelectorAll("svg"));
|
|
1710
|
+
const exported = [];
|
|
1711
|
+
for (const drawing of drawings) exported.push(await exportSVGToImage(drawing, options));
|
|
1712
|
+
return exported;
|
|
1713
|
+
}
|
|
1714
|
+
/** Save an exported image under the given file name. */
|
|
1715
|
+
function downloadImage(image, filename) {
|
|
1716
|
+
const link = document.createElement("a");
|
|
1717
|
+
link.download = filename;
|
|
1718
|
+
link.href = image.dataUrl;
|
|
1719
|
+
link.click();
|
|
1720
|
+
}
|
|
1721
|
+
function loadImage(url) {
|
|
1722
|
+
return new Promise((resolve, reject) => {
|
|
1723
|
+
const image = new Image();
|
|
1724
|
+
image.onload = () => resolve(image);
|
|
1725
|
+
image.onerror = () => reject(new Error("The drawing could not be decoded"));
|
|
1726
|
+
image.src = url;
|
|
1727
|
+
});
|
|
1728
|
+
}
|
|
1729
|
+
|
|
1651
1730
|
//#endregion
|
|
1652
1731
|
//#region src/diff.ts
|
|
1653
1732
|
/** Produce a minimal set of patches turning `prev` into `next`, keyed by node key. */
|
|
@@ -2491,4 +2570,4 @@ function delay(ms, signal) {
|
|
|
2491
2570
|
}
|
|
2492
2571
|
|
|
2493
2572
|
//#endregion
|
|
2494
|
-
export { ActionAbortedError, ActionAlreadyRegisteredError, ActionDestroyedError, ActionExecutionError, ActionNotFoundError, ActionRegistry, ActionRuntime, ActionRuntimeError, ActionTimeoutError, ActionValidationError, CARD_ID_MAX_LENGTH, CARD_JSON_MAX_DEPTH, CARD_JSON_MAX_NODES, CARD_PATCH_BATCH_MAX_SIZE, CardJSONError, CardLimitError, CardNotFoundError, CardRegistry, CardRevisionConflictError, CardSnapshotError, CardStore, CardStoreError, CardTypeConflictError, CardValidationError, DebugEmitter, Renderer, StreamRouter, applyPatches, buildSystemPrompt, collectNodeRenderers, contentDeltas, createActionRuntime, createParser, createParserWithMetadata, diffAst, getActionKey, getIdleActionState, isCardPatchResult, jsonLines, mockModelStream, ndjson, parsePartialJSON, parseSSE, pluginNodeTypes, readableBytes, repairMarkdown, safeDebugValue, sanitizeHtml, textLines, validateJSONSchema };
|
|
2573
|
+
export { ActionAbortedError, ActionAlreadyRegisteredError, ActionDestroyedError, ActionExecutionError, ActionNotFoundError, ActionRegistry, ActionRuntime, ActionRuntimeError, ActionTimeoutError, ActionValidationError, CARD_ID_MAX_LENGTH, CARD_JSON_MAX_DEPTH, CARD_JSON_MAX_NODES, CARD_PATCH_BATCH_MAX_SIZE, CardJSONError, CardLimitError, CardNotFoundError, CardRegistry, CardRevisionConflictError, CardSnapshotError, CardStore, CardStoreError, CardTypeConflictError, CardValidationError, DebugEmitter, Renderer, StreamRouter, applyPatches, buildSystemPrompt, collectNodeRenderers, contentDeltas, createActionRuntime, createParser, createParserWithMetadata, diffAst, downloadImage, exportRenderedImages, exportSVGToImage, getActionKey, getIdleActionState, isCardPatchResult, jsonLines, mockModelStream, ndjson, parsePartialJSON, parseSSE, pluginNodeTypes, readableBytes, repairMarkdown, safeDebugValue, sanitizeHtml, textLines, validateJSONSchema };
|
package/package.json
CHANGED