@runtypelabs/persona 1.36.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.
Files changed (61) hide show
  1. package/README.md +1080 -0
  2. package/dist/index.cjs +140 -0
  3. package/dist/index.cjs.map +1 -0
  4. package/dist/index.d.cts +2626 -0
  5. package/dist/index.d.ts +2626 -0
  6. package/dist/index.global.js +1843 -0
  7. package/dist/index.global.js.map +1 -0
  8. package/dist/index.js +140 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/install.global.js +2 -0
  11. package/dist/install.global.js.map +1 -0
  12. package/dist/widget.css +1627 -0
  13. package/package.json +79 -0
  14. package/src/@types/idiomorph.d.ts +37 -0
  15. package/src/client.test.ts +387 -0
  16. package/src/client.ts +1589 -0
  17. package/src/components/composer-builder.ts +530 -0
  18. package/src/components/feedback.ts +379 -0
  19. package/src/components/forms.ts +170 -0
  20. package/src/components/header-builder.ts +455 -0
  21. package/src/components/header-layouts.ts +303 -0
  22. package/src/components/launcher.ts +193 -0
  23. package/src/components/message-bubble.ts +528 -0
  24. package/src/components/messages.ts +54 -0
  25. package/src/components/panel.ts +204 -0
  26. package/src/components/reasoning-bubble.ts +144 -0
  27. package/src/components/registry.ts +87 -0
  28. package/src/components/suggestions.ts +97 -0
  29. package/src/components/tool-bubble.ts +288 -0
  30. package/src/defaults.ts +321 -0
  31. package/src/index.ts +175 -0
  32. package/src/install.ts +284 -0
  33. package/src/plugins/registry.ts +77 -0
  34. package/src/plugins/types.ts +95 -0
  35. package/src/postprocessors.ts +194 -0
  36. package/src/runtime/init.ts +162 -0
  37. package/src/session.ts +376 -0
  38. package/src/styles/tailwind.css +20 -0
  39. package/src/styles/widget.css +1627 -0
  40. package/src/types.ts +1635 -0
  41. package/src/ui.ts +3341 -0
  42. package/src/utils/actions.ts +227 -0
  43. package/src/utils/attachment-manager.ts +384 -0
  44. package/src/utils/code-generators.test.ts +500 -0
  45. package/src/utils/code-generators.ts +1806 -0
  46. package/src/utils/component-middleware.ts +137 -0
  47. package/src/utils/component-parser.ts +119 -0
  48. package/src/utils/constants.ts +16 -0
  49. package/src/utils/content.ts +306 -0
  50. package/src/utils/dom.ts +25 -0
  51. package/src/utils/events.ts +41 -0
  52. package/src/utils/formatting.test.ts +166 -0
  53. package/src/utils/formatting.ts +470 -0
  54. package/src/utils/icons.ts +92 -0
  55. package/src/utils/message-id.ts +37 -0
  56. package/src/utils/morph.ts +36 -0
  57. package/src/utils/positioning.ts +17 -0
  58. package/src/utils/storage.ts +72 -0
  59. package/src/utils/theme.ts +105 -0
  60. package/src/widget.css +1 -0
  61. package/widget.css +1 -0
package/src/index.ts ADDED
@@ -0,0 +1,175 @@
1
+ import {
2
+ initAgentWidget as initAgentWidgetFn,
3
+ type AgentWidgetInitHandle
4
+ } from "./runtime/init";
5
+
6
+ export type {
7
+ AgentWidgetConfig,
8
+ AgentWidgetTheme,
9
+ AgentWidgetFeatureFlags,
10
+ AgentWidgetInitOptions,
11
+ AgentWidgetMessage,
12
+ AgentWidgetLauncherConfig,
13
+ AgentWidgetEvent,
14
+ AgentWidgetStreamParser,
15
+ AgentWidgetStreamParserResult,
16
+ AgentWidgetRequestPayload,
17
+ AgentWidgetCustomFetch,
18
+ AgentWidgetSSEEventParser,
19
+ AgentWidgetSSEEventResult,
20
+ AgentWidgetHeadersFunction,
21
+ // Multi-modal content types
22
+ TextContentPart,
23
+ ImageContentPart,
24
+ ContentPart,
25
+ MessageContent,
26
+ // Attachment config type
27
+ AgentWidgetAttachmentsConfig,
28
+ // Layout types
29
+ AgentWidgetLayoutConfig,
30
+ AgentWidgetHeaderLayoutConfig,
31
+ AgentWidgetMessageLayoutConfig,
32
+ AgentWidgetAvatarConfig,
33
+ AgentWidgetTimestampConfig,
34
+ WidgetLayoutSlot,
35
+ SlotRenderer,
36
+ SlotRenderContext,
37
+ HeaderRenderContext,
38
+ MessageRenderContext,
39
+ // Markdown types
40
+ AgentWidgetMarkdownConfig,
41
+ AgentWidgetMarkdownOptions,
42
+ AgentWidgetMarkdownRendererOverrides,
43
+ // Message actions types
44
+ AgentWidgetMessageActionsConfig,
45
+ AgentWidgetMessageFeedback,
46
+ // Client token types
47
+ ClientSession,
48
+ ClientInitResponse,
49
+ ClientChatRequest,
50
+ ClientFeedbackRequest,
51
+ ClientFeedbackType
52
+ } from "./types";
53
+
54
+ export { initAgentWidgetFn as initAgentWidget };
55
+ export {
56
+ createAgentExperience,
57
+ type AgentWidgetController
58
+ } from "./ui";
59
+ export {
60
+ AgentWidgetSession,
61
+ type AgentWidgetSessionStatus
62
+ } from "./session";
63
+ export { AgentWidgetClient } from "./client";
64
+ export { createLocalStorageAdapter } from "./utils/storage";
65
+ export {
66
+ createActionManager,
67
+ defaultActionHandlers,
68
+ defaultJsonActionParser
69
+ } from "./utils/actions";
70
+ export {
71
+ markdownPostprocessor,
72
+ escapeHtml,
73
+ directivePostprocessor,
74
+ createMarkdownProcessor,
75
+ createMarkdownProcessorFromConfig,
76
+ createDirectivePostprocessor
77
+ } from "./postprocessors";
78
+ export type { MarkdownProcessorOptions } from "./postprocessors";
79
+ export {
80
+ createPlainTextParser,
81
+ createJsonStreamParser,
82
+ createFlexibleJsonStreamParser,
83
+ createRegexJsonParser,
84
+ createXmlParser
85
+ } from "./utils/formatting";
86
+ export {
87
+ // Multi-modal content utilities
88
+ normalizeContent,
89
+ getDisplayText,
90
+ hasImages,
91
+ getImageParts,
92
+ createTextPart,
93
+ createImagePart,
94
+ fileToImagePart,
95
+ validateImageFile
96
+ } from "./utils/content";
97
+ export {
98
+ AttachmentManager,
99
+ type PendingAttachment,
100
+ type AttachmentManagerConfig
101
+ } from "./utils/attachment-manager";
102
+ export {
103
+ generateMessageId,
104
+ generateUserMessageId,
105
+ generateAssistantMessageId
106
+ } from "./utils/message-id";
107
+ export { generateCodeSnippet } from "./utils/code-generators";
108
+ export type { CodeFormat, CodeGeneratorHooks, CodeGeneratorOptions } from "./utils/code-generators";
109
+ export type { AgentWidgetInitHandle };
110
+
111
+ // Plugin system exports
112
+ export type { AgentWidgetPlugin } from "./plugins/types";
113
+ export { pluginRegistry } from "./plugins/registry";
114
+
115
+ // Component system exports
116
+ export { componentRegistry } from "./components/registry";
117
+ export type { ComponentRenderer, ComponentContext } from "./components/registry";
118
+ export {
119
+ createComponentStreamParser,
120
+ isComponentDirectiveType
121
+ } from "./utils/component-parser";
122
+ export type { ComponentDirective } from "./utils/component-parser";
123
+ export {
124
+ renderComponentDirective,
125
+ createComponentMiddleware,
126
+ hasComponentDirective,
127
+ extractComponentDirectiveFromMessage
128
+ } from "./utils/component-middleware";
129
+
130
+ // Default configuration exports
131
+ export {
132
+ DEFAULT_WIDGET_CONFIG,
133
+ DEFAULT_LIGHT_THEME,
134
+ DEFAULT_DARK_THEME,
135
+ mergeWithDefaults
136
+ } from "./defaults";
137
+
138
+ // Layout system exports
139
+ export {
140
+ buildHeader,
141
+ buildComposer,
142
+ attachHeaderToContainer
143
+ } from "./components/panel";
144
+ export type {
145
+ HeaderElements,
146
+ HeaderBuildContext,
147
+ ComposerElements,
148
+ ComposerBuildContext
149
+ } from "./components/panel";
150
+ export {
151
+ headerLayouts,
152
+ getHeaderLayout,
153
+ buildHeaderWithLayout,
154
+ buildDefaultHeader,
155
+ buildMinimalHeader,
156
+ buildExpandedHeader
157
+ } from "./components/header-layouts";
158
+ export type {
159
+ HeaderLayoutContext,
160
+ HeaderLayoutRenderer
161
+ } from "./components/header-layouts";
162
+ export {
163
+ createStandardBubble,
164
+ createBubbleWithLayout,
165
+ createTypingIndicator,
166
+ createMessageActions
167
+ } from "./components/message-bubble";
168
+ export type { MessageTransform, MessageActionCallbacks } from "./components/message-bubble";
169
+ export {
170
+ createCSATFeedback,
171
+ createNPSFeedback
172
+ } from "./components/feedback";
173
+ export type { CSATFeedbackOptions, NPSFeedbackOptions } from "./components/feedback";
174
+
175
+ export default initAgentWidgetFn;
package/src/install.ts ADDED
@@ -0,0 +1,284 @@
1
+ /**
2
+ * Standalone installer script for easy script tag installation
3
+ * This script automatically loads CSS and JS, then initializes the widget
4
+ * if configuration is provided via window.siteAgentConfig
5
+ */
6
+
7
+ interface SiteAgentInstallConfig {
8
+ version?: string;
9
+ cdn?: "unpkg" | "jsdelivr";
10
+ cssUrl?: string;
11
+ jsUrl?: string;
12
+ target?: string | HTMLElement;
13
+ config?: any;
14
+ autoInit?: boolean;
15
+ // Client token mode options (can also be set via data attributes)
16
+ clientToken?: string;
17
+ flowId?: string;
18
+ apiUrl?: string;
19
+ // Shadow DOM option (defaults to false for better CSS compatibility)
20
+ useShadowDom?: boolean;
21
+ }
22
+
23
+ declare global {
24
+ interface Window {
25
+ siteAgentConfig?: SiteAgentInstallConfig;
26
+ AgentWidget?: any;
27
+ }
28
+ }
29
+
30
+ (function() {
31
+ "use strict";
32
+
33
+ // Prevent double installation
34
+ if ((window as any).__siteAgentInstallerLoaded) {
35
+ return;
36
+ }
37
+ (window as any).__siteAgentInstallerLoaded = true;
38
+
39
+ /**
40
+ * Read configuration from data attributes on the current script tag.
41
+ * Supports: data-config (JSON), data-travrse-token, data-flow-id, data-api-url
42
+ */
43
+ const getConfigFromScript = (): Partial<SiteAgentInstallConfig> => {
44
+ // Try to get the current script element
45
+ const script = document.currentScript as HTMLScriptElement | null;
46
+ if (!script) return {};
47
+
48
+ const scriptConfig: Partial<SiteAgentInstallConfig> = {};
49
+
50
+ // Full config from data-config attribute (JSON string)
51
+ const configJson = script.getAttribute('data-config');
52
+ if (configJson) {
53
+ try {
54
+ const parsedConfig = JSON.parse(configJson);
55
+ // If it has nested 'config' property, use it; otherwise treat as widget config
56
+ if (parsedConfig.config) {
57
+ Object.assign(scriptConfig, parsedConfig);
58
+ } else {
59
+ // Treat the entire object as widget config
60
+ scriptConfig.config = parsedConfig;
61
+ }
62
+ } catch (e) {
63
+ console.error("Failed to parse data-config JSON:", e);
64
+ }
65
+ }
66
+
67
+ // Client token from data attribute (primary method for client token mode)
68
+ const token = script.getAttribute('data-travrse-token');
69
+ if (token) {
70
+ scriptConfig.clientToken = token;
71
+ }
72
+
73
+ // Optional flow ID
74
+ const flowId = script.getAttribute('data-flow-id');
75
+ if (flowId) {
76
+ scriptConfig.flowId = flowId;
77
+ }
78
+
79
+ // Optional API URL override
80
+ const apiUrl = script.getAttribute('data-api-url');
81
+ if (apiUrl) {
82
+ scriptConfig.apiUrl = apiUrl;
83
+ }
84
+
85
+ return scriptConfig;
86
+ };
87
+
88
+ // Get config from script attributes (must be called synchronously during script execution)
89
+ const scriptConfig = getConfigFromScript();
90
+
91
+ // Merge script attributes with window config (script attributes take precedence)
92
+ const windowConfig: SiteAgentInstallConfig = window.siteAgentConfig || {};
93
+ const config: SiteAgentInstallConfig = { ...windowConfig, ...scriptConfig };
94
+
95
+ const version = config.version || "latest";
96
+ const cdn = config.cdn || "jsdelivr";
97
+ const autoInit = config.autoInit !== false; // Default to true
98
+
99
+ // Determine CDN base URL
100
+ const getCdnBase = () => {
101
+ if (config.cssUrl && config.jsUrl) {
102
+ return { cssUrl: config.cssUrl, jsUrl: config.jsUrl };
103
+ }
104
+
105
+ const packageName = "@runtypelabs/persona";
106
+ const basePath = `/npm/${packageName}@${version}/dist`;
107
+
108
+ if (cdn === "unpkg") {
109
+ return {
110
+ cssUrl: `https://unpkg.com${basePath}/widget.css`,
111
+ jsUrl: `https://unpkg.com${basePath}/index.global.js`
112
+ };
113
+ } else {
114
+ return {
115
+ cssUrl: `https://cdn.jsdelivr.net${basePath}/widget.css`,
116
+ jsUrl: `https://cdn.jsdelivr.net${basePath}/index.global.js`
117
+ };
118
+ }
119
+ };
120
+
121
+ const { cssUrl, jsUrl } = getCdnBase();
122
+
123
+ // Check if CSS is already loaded
124
+ const isCssLoaded = () => {
125
+ return !!document.head.querySelector('link[data-persona]') ||
126
+ !!document.head.querySelector(`link[href*="widget.css"]`);
127
+ };
128
+
129
+ // Check if JS is already loaded
130
+ const isJsLoaded = () => {
131
+ return !!(window as any).AgentWidget;
132
+ };
133
+
134
+ /**
135
+ * Wait for framework hydration to complete (Next.js, Nuxt, etc.)
136
+ * This prevents the framework from removing dynamically added CSS during reconciliation.
137
+ * Uses requestIdleCallback + double requestAnimationFrame for reliable detection.
138
+ */
139
+ const waitForHydration = (callback: () => void): void => {
140
+ let executed = false;
141
+
142
+ const execute = () => {
143
+ if (executed) return;
144
+ executed = true;
145
+ callback();
146
+ };
147
+
148
+ const afterDom = () => {
149
+ // Strategy 1: Use requestIdleCallback if available (best for detecting idle after hydration)
150
+ if (typeof requestIdleCallback !== 'undefined') {
151
+ requestIdleCallback(() => {
152
+ // Double requestAnimationFrame ensures at least one full paint cycle completed
153
+ requestAnimationFrame(() => {
154
+ requestAnimationFrame(execute);
155
+ });
156
+ }, { timeout: 3000 }); // Max wait 3 seconds, then proceed anyway
157
+ } else {
158
+ // Strategy 2: Fallback for Safari (no requestIdleCallback)
159
+ // 300ms is typically enough for hydration on most pages
160
+ setTimeout(execute, 300);
161
+ }
162
+ };
163
+
164
+ if (document.readyState === 'loading') {
165
+ document.addEventListener('DOMContentLoaded', afterDom);
166
+ } else {
167
+ // DOM already ready, but still wait for potential hydration
168
+ afterDom();
169
+ }
170
+ };
171
+
172
+ // Load CSS
173
+ const loadCSS = (): Promise<void> => {
174
+ return new Promise((resolve, reject) => {
175
+ if (isCssLoaded()) {
176
+ resolve();
177
+ return;
178
+ }
179
+
180
+ const link = document.createElement("link");
181
+ link.rel = "stylesheet";
182
+ link.href = cssUrl;
183
+ link.setAttribute("data-persona", "true");
184
+
185
+ link.onload = () => resolve();
186
+ link.onerror = () => reject(new Error(`Failed to load CSS from ${cssUrl}`));
187
+ document.head.appendChild(link);
188
+ });
189
+ };
190
+
191
+ // Load JS
192
+ const loadJS = (): Promise<void> => {
193
+ return new Promise((resolve, reject) => {
194
+ if (isJsLoaded()) {
195
+ resolve();
196
+ return;
197
+ }
198
+
199
+ const script = document.createElement("script");
200
+ script.src = jsUrl;
201
+ script.async = true;
202
+ script.onload = () => resolve();
203
+ script.onerror = () => reject(new Error(`Failed to load JS from ${jsUrl}`));
204
+ document.head.appendChild(script);
205
+ });
206
+ };
207
+
208
+ // Initialize widget
209
+ const initWidget = () => {
210
+ if (!window.AgentWidget || !window.AgentWidget.initAgentWidget) {
211
+ console.warn("AgentWidget not available. Make sure the script loaded successfully.");
212
+ return;
213
+ }
214
+
215
+ const target = config.target || "body";
216
+ // Merge top-level config options into widget config
217
+ const widgetConfig = { ...config.config };
218
+
219
+ // Merge apiUrl from top-level config into widget config if present
220
+ if (config.apiUrl && !widgetConfig.apiUrl) {
221
+ widgetConfig.apiUrl = config.apiUrl;
222
+ }
223
+
224
+ // Merge clientToken from top-level config into widget config if present
225
+ if (config.clientToken && !widgetConfig.clientToken) {
226
+ widgetConfig.clientToken = config.clientToken;
227
+ }
228
+
229
+ // Merge flowId from top-level config into widget config if present
230
+ if (config.flowId && !widgetConfig.flowId) {
231
+ widgetConfig.flowId = config.flowId;
232
+ }
233
+
234
+ // Only initialize if we have either apiUrl OR clientToken (or other config)
235
+ const hasApiConfig = widgetConfig.apiUrl || widgetConfig.clientToken;
236
+ if (!hasApiConfig && Object.keys(widgetConfig).length === 0) {
237
+ return;
238
+ }
239
+
240
+ // Auto-apply markdown postprocessor if not explicitly set and available
241
+ if (!widgetConfig.postprocessMessage && window.AgentWidget.markdownPostprocessor) {
242
+ widgetConfig.postprocessMessage = ({ text }: { text: string }) =>
243
+ window.AgentWidget.markdownPostprocessor(text);
244
+ }
245
+
246
+ try {
247
+ window.AgentWidget.initAgentWidget({
248
+ target,
249
+ config: widgetConfig,
250
+ // Explicitly disable shadow DOM for better CSS compatibility with host page
251
+ useShadowDom: config.useShadowDom ?? false
252
+ });
253
+ } catch (error) {
254
+ console.error("Failed to initialize AgentWidget:", error);
255
+ }
256
+ };
257
+
258
+ // Main installation flow (called after hydration completes)
259
+ const install = async () => {
260
+ try {
261
+ await loadCSS();
262
+ await loadJS();
263
+
264
+ // Auto-init if we have config OR apiUrl OR clientToken
265
+ const shouldAutoInit = autoInit && (
266
+ config.config ||
267
+ config.apiUrl ||
268
+ config.clientToken
269
+ );
270
+
271
+ if (shouldAutoInit) {
272
+ // Wait a tick to ensure AgentWidget is fully initialized
273
+ setTimeout(initWidget, 0);
274
+ }
275
+ } catch (error) {
276
+ console.error("Failed to install AgentWidget:", error);
277
+ }
278
+ };
279
+
280
+ // Start installation after hydration completes
281
+ // This prevents Next.js/Nuxt/etc. from removing dynamically added CSS
282
+ waitForHydration(install);
283
+ })();
284
+
@@ -0,0 +1,77 @@
1
+ import { AgentWidgetPlugin } from "./types";
2
+
3
+ class PluginRegistry {
4
+ private plugins: Map<string, AgentWidgetPlugin> = new Map();
5
+
6
+ /**
7
+ * Register a plugin
8
+ */
9
+ register(plugin: AgentWidgetPlugin): void {
10
+ if (this.plugins.has(plugin.id)) {
11
+ console.warn(`Plugin "${plugin.id}" is already registered. Overwriting.`);
12
+ }
13
+
14
+ this.plugins.set(plugin.id, plugin);
15
+ plugin.onRegister?.();
16
+ }
17
+
18
+ /**
19
+ * Unregister a plugin
20
+ */
21
+ unregister(pluginId: string): void {
22
+ const plugin = this.plugins.get(pluginId);
23
+ if (plugin) {
24
+ plugin.onUnregister?.();
25
+ this.plugins.delete(pluginId);
26
+ }
27
+ }
28
+
29
+ /**
30
+ * Get all plugins sorted by priority
31
+ */
32
+ getAll(): AgentWidgetPlugin[] {
33
+ return Array.from(this.plugins.values()).sort(
34
+ (a, b) => (b.priority ?? 0) - (a.priority ?? 0)
35
+ );
36
+ }
37
+
38
+ /**
39
+ * Get plugins for a specific instance (from config)
40
+ * Merges instance plugins with globally registered plugins
41
+ */
42
+ getForInstance(instancePlugins?: AgentWidgetPlugin[]): AgentWidgetPlugin[] {
43
+ const allPlugins = this.getAll();
44
+
45
+ if (!instancePlugins || instancePlugins.length === 0) {
46
+ return allPlugins;
47
+ }
48
+
49
+ // Merge instance plugins with global plugins
50
+ // Instance plugins override global plugins with the same ID
51
+ const instanceIds = new Set(instancePlugins.map(p => p.id));
52
+ const merged = [
53
+ ...allPlugins.filter(p => !instanceIds.has(p.id)),
54
+ ...instancePlugins
55
+ ];
56
+
57
+ return merged.sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
58
+ }
59
+
60
+ /**
61
+ * Clear all plugins
62
+ */
63
+ clear(): void {
64
+ this.plugins.forEach(plugin => plugin.onUnregister?.());
65
+ this.plugins.clear();
66
+ }
67
+ }
68
+
69
+ export const pluginRegistry = new PluginRegistry();
70
+
71
+
72
+
73
+
74
+
75
+
76
+
77
+
@@ -0,0 +1,95 @@
1
+ import { AgentWidgetMessage, AgentWidgetConfig } from "../types";
2
+
3
+ /**
4
+ * Plugin interface for customizing widget components
5
+ */
6
+ export interface AgentWidgetPlugin {
7
+ /**
8
+ * Unique identifier for the plugin
9
+ */
10
+ id: string;
11
+
12
+ /**
13
+ * Optional priority (higher = runs first). Default: 0
14
+ */
15
+ priority?: number;
16
+
17
+ /**
18
+ * Custom renderer for message bubbles
19
+ * Return null to use default renderer
20
+ */
21
+ renderMessage?: (context: {
22
+ message: AgentWidgetMessage;
23
+ defaultRenderer: () => HTMLElement;
24
+ config: AgentWidgetConfig;
25
+ }) => HTMLElement | null;
26
+
27
+ /**
28
+ * Custom renderer for launcher button
29
+ * Return null to use default renderer
30
+ */
31
+ renderLauncher?: (context: {
32
+ config: AgentWidgetConfig;
33
+ defaultRenderer: () => HTMLElement;
34
+ onToggle: () => void;
35
+ }) => HTMLElement | null;
36
+
37
+ /**
38
+ * Custom renderer for panel header
39
+ * Return null to use default renderer
40
+ */
41
+ renderHeader?: (context: {
42
+ config: AgentWidgetConfig;
43
+ defaultRenderer: () => HTMLElement;
44
+ onClose?: () => void;
45
+ }) => HTMLElement | null;
46
+
47
+ /**
48
+ * Custom renderer for composer/input area
49
+ * Return null to use default renderer
50
+ */
51
+ renderComposer?: (context: {
52
+ config: AgentWidgetConfig;
53
+ defaultRenderer: () => HTMLElement;
54
+ onSubmit: (text: string) => void;
55
+ disabled: boolean;
56
+ }) => HTMLElement | null;
57
+
58
+ /**
59
+ * Custom renderer for reasoning bubbles
60
+ * Return null to use default renderer
61
+ */
62
+ renderReasoning?: (context: {
63
+ message: AgentWidgetMessage;
64
+ defaultRenderer: () => HTMLElement;
65
+ config: AgentWidgetConfig;
66
+ }) => HTMLElement | null;
67
+
68
+ /**
69
+ * Custom renderer for tool call bubbles
70
+ * Return null to use default renderer
71
+ */
72
+ renderToolCall?: (context: {
73
+ message: AgentWidgetMessage;
74
+ defaultRenderer: () => HTMLElement;
75
+ config: AgentWidgetConfig;
76
+ }) => HTMLElement | null;
77
+
78
+ /**
79
+ * Called when plugin is registered
80
+ */
81
+ onRegister?: () => void;
82
+
83
+ /**
84
+ * Called when plugin is unregistered
85
+ */
86
+ onUnregister?: () => void;
87
+ }
88
+
89
+
90
+
91
+
92
+
93
+
94
+
95
+