@runtypelabs/persona 3.10.1 → 3.12.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.
@@ -1,2 +1,2 @@
1
- "use strict";var SiteAgentInstaller=(()=>{var w=Object.defineProperty;var P=Object.getOwnPropertyDescriptor;var j=Object.getOwnPropertyNames;var W=Object.prototype.hasOwnProperty;var T=(s,i,d,t)=>{if(i&&typeof i=="object"||typeof i=="function")for(let a of j(i))!W.call(s,a)&&a!==d&&w(s,a,{get:()=>i[a],enumerable:!(t=P(i,a))||t.enumerable});return s};var _=s=>T(w({},"__esModule",{value:!0}),s);var F={};(function(){"use strict";if(window.__siteAgentInstallerLoaded)return;window.__siteAgentInstallerLoaded=!0;let i=(()=>{let n=document.currentScript;if(!n)return{};let e={},o=n.getAttribute("data-config");if(o)try{let c=JSON.parse(o);if(c.config){let{__proto__:E,constructor:M,prototype:$,...v}=c;Object.assign(e,v)}else e.config=c}catch(c){console.error("Failed to parse data-config JSON:",c)}let r=n.getAttribute("data-runtype-token");r&&(e.clientToken=r);let l=n.getAttribute("data-flow-id");l&&(e.flowId=l);let f=n.getAttribute("data-api-url");f&&(e.apiUrl=f);let p=n.getAttribute("data-preview-param");return p&&(e.previewQueryParam=p),e})(),t={...window.siteAgentConfig||{},...i};if(!(()=>{if(!t.previewQueryParam)return!0;let e=new URLSearchParams(window.location.search).get(t.previewQueryParam);return e!==null&&e!==""&&e.toLowerCase()!=="false"&&e!=="0"})())return;let m=t.version||"latest",A=t.cdn||"jsdelivr",C=t.autoInit!==!1,h=()=>{if(t.cssUrl&&t.jsUrl)return{cssUrl:t.cssUrl,jsUrl:t.jsUrl};let e=`/npm/@runtypelabs/persona@${m}/dist`;return A==="unpkg"?{cssUrl:`https://unpkg.com${e}/widget.css`,jsUrl:`https://unpkg.com${e}/index.global.js`}:{cssUrl:`https://cdn.jsdelivr.net${e}/widget.css`,jsUrl:`https://cdn.jsdelivr.net${e}/index.global.js`}},{cssUrl:g,jsUrl:u}=h(),y=()=>!!document.head.querySelector("link[data-persona]")||!!document.head.querySelector('link[href*="widget.css"]'),k=()=>!!window.AgentWidget,S=n=>{let e=!1,o=()=>{e||(e=!0,n())},r=()=>{typeof requestIdleCallback!="undefined"?requestIdleCallback(()=>{requestAnimationFrame(()=>{requestAnimationFrame(o)})},{timeout:3e3}):setTimeout(o,300)};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",r):r()},U=()=>new Promise((n,e)=>{if(y()){n();return}let o=document.createElement("link");o.rel="stylesheet",o.href=g,o.setAttribute("data-persona","true"),o.onload=()=>n(),o.onerror=()=>e(new Error(`Failed to load CSS from ${g}`)),document.head.appendChild(o)}),b=()=>new Promise((n,e)=>{if(k()){n();return}let o=document.createElement("script");o.src=u,o.async=!0,o.onload=()=>n(),o.onerror=()=>e(new Error(`Failed to load JS from ${u}`)),document.head.appendChild(o)}),I=()=>{var r;if(!window.AgentWidget||!window.AgentWidget.initAgentWidget){console.warn("AgentWidget not available. Make sure the script loaded successfully.");return}let n=t.target||"body",e={...t.config};if(t.apiUrl&&!e.apiUrl&&(e.apiUrl=t.apiUrl),t.clientToken&&!e.clientToken&&(e.clientToken=t.clientToken),t.flowId&&!e.flowId&&(e.flowId=t.flowId),!(!(e.apiUrl||e.clientToken)&&Object.keys(e).length===0)){!e.postprocessMessage&&window.AgentWidget.markdownPostprocessor&&(e.postprocessMessage=({text:l})=>window.AgentWidget.markdownPostprocessor(l));try{window.AgentWidget.initAgentWidget({target:n,config:e,useShadowDom:(r=t.useShadowDom)!=null?r:!1})}catch(l){console.error("Failed to initialize AgentWidget:",l)}}};S(async()=>{try{await U(),await b(),C&&(t.config||t.apiUrl||t.clientToken)&&setTimeout(I,0)}catch(n){console.error("Failed to install AgentWidget:",n)}})})();return _(F);})();
1
+ "use strict";var SiteAgentInstaller=(()=>{var m=Object.defineProperty;var j=Object.getOwnPropertyDescriptor;var W=Object.getOwnPropertyNames;var T=Object.prototype.hasOwnProperty;var _=(s,i,g,t)=>{if(i&&typeof i=="object"||typeof i=="function")for(let a of W(i))!T.call(s,a)&&a!==g&&m(s,a,{get:()=>i[a],enumerable:!(t=j(i,a))||t.enumerable});return s};var F=s=>_(m({},"__esModule",{value:!0}),s);var L={};(function(){"use strict";if(window.__siteAgentInstallerLoaded)return;window.__siteAgentInstallerLoaded=!0;let i=(()=>{let n=document.currentScript;if(!n)return{};let e={},o=n.getAttribute("data-config");if(o)try{let c=o.replace(/[\r\n]+\s*/g,""),d=JSON.parse(c);if(d.config){let{__proto__:M,constructor:$,prototype:J,...P}=d;Object.assign(e,P)}else e.config=d}catch(c){console.error("Failed to parse data-config JSON:",c)}let r=n.getAttribute("data-runtype-token");r&&(e.clientToken=r);let l=n.getAttribute("data-flow-id");l&&(e.flowId=l);let p=n.getAttribute("data-api-url");p&&(e.apiUrl=p);let w=n.getAttribute("data-preview-param");return w&&(e.previewQueryParam=w),e})(),t={...window.siteAgentConfig||{},...i};if(!(()=>{if(!t.previewQueryParam)return!0;let e=new URLSearchParams(window.location.search).get(t.previewQueryParam);return e!==null&&e!==""&&e.toLowerCase()!=="false"&&e!=="0"})())return;let A=t.version||"latest",C=t.cdn||"jsdelivr",h=t.autoInit!==!1,y=()=>{if(t.cssUrl&&t.jsUrl)return{cssUrl:t.cssUrl,jsUrl:t.jsUrl};let e=`/npm/@runtypelabs/persona@${A}/dist`;return C==="unpkg"?{cssUrl:`https://unpkg.com${e}/widget.css`,jsUrl:`https://unpkg.com${e}/index.global.js`}:{cssUrl:`https://cdn.jsdelivr.net${e}/widget.css`,jsUrl:`https://cdn.jsdelivr.net${e}/index.global.js`}},{cssUrl:u,jsUrl:f}=y(),k=()=>!!document.head.querySelector("link[data-persona]")||!!document.head.querySelector('link[href*="widget.css"]'),S=()=>!!window.AgentWidget,U=n=>{let e=!1,o=()=>{e||(e=!0,n())},r=()=>{typeof requestIdleCallback!="undefined"?requestIdleCallback(()=>{requestAnimationFrame(()=>{requestAnimationFrame(o)})},{timeout:3e3}):setTimeout(o,300)};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",r):r()},b=()=>new Promise((n,e)=>{if(k()){n();return}let o=document.createElement("link");o.rel="stylesheet",o.href=u,o.setAttribute("data-persona","true"),o.onload=()=>n(),o.onerror=()=>e(new Error(`Failed to load CSS from ${u}`)),document.head.appendChild(o)}),I=()=>new Promise((n,e)=>{if(S()){n();return}let o=document.createElement("script");o.src=f,o.async=!0,o.onload=()=>n(),o.onerror=()=>e(new Error(`Failed to load JS from ${f}`)),document.head.appendChild(o)}),v=()=>{var r;if(!window.AgentWidget||!window.AgentWidget.initAgentWidget){console.warn("AgentWidget not available. Make sure the script loaded successfully.");return}let n=t.target||"body",e={...t.config};if(t.apiUrl&&!e.apiUrl&&(e.apiUrl=t.apiUrl),t.clientToken&&!e.clientToken&&(e.clientToken=t.clientToken),t.flowId&&!e.flowId&&(e.flowId=t.flowId),!(!(e.apiUrl||e.clientToken)&&Object.keys(e).length===0)){!e.postprocessMessage&&window.AgentWidget.markdownPostprocessor&&(e.postprocessMessage=({text:l})=>window.AgentWidget.markdownPostprocessor(l));try{window.AgentWidget.initAgentWidget({target:n,config:e,useShadowDom:(r=t.useShadowDom)!=null?r:!1})}catch(l){console.error("Failed to initialize AgentWidget:",l)}}};U(async()=>{try{await b(),await I(),h&&(t.config||t.apiUrl||t.clientToken)&&setTimeout(v,0)}catch(n){console.error("Failed to install AgentWidget:",n)}})})();return F(L);})();
2
2
  //# sourceMappingURL=install.global.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/install.ts"],"sourcesContent":["/**\n * Standalone installer script for easy script tag installation\n * This script automatically loads CSS and JS, then initializes the widget\n * if configuration is provided via window.siteAgentConfig\n */\n\nexport {};\n\ninterface SiteAgentInstallConfig {\n version?: string;\n cdn?: \"unpkg\" | \"jsdelivr\";\n cssUrl?: string;\n jsUrl?: string;\n target?: string | HTMLElement;\n config?: any;\n autoInit?: boolean;\n // Client token mode options (can also be set via data attributes)\n clientToken?: string;\n flowId?: string;\n apiUrl?: string;\n // Optional query param key that gates widget installation in preview mode\n previewQueryParam?: string;\n // Shadow DOM option (defaults to false for better CSS compatibility)\n useShadowDom?: boolean;\n}\n\ndeclare global {\n interface Window {\n siteAgentConfig?: SiteAgentInstallConfig;\n AgentWidget?: any;\n }\n}\n\n(function() {\n \"use strict\";\n\n // Prevent double installation\n if ((window as any).__siteAgentInstallerLoaded) {\n return;\n }\n (window as any).__siteAgentInstallerLoaded = true;\n\n /**\n * Read configuration from data attributes on the current script tag.\n * Supports: data-config (JSON), data-runtype-token, data-flow-id, data-api-url\n */\n const getConfigFromScript = (): Partial<SiteAgentInstallConfig> => {\n // Try to get the current script element\n const script = document.currentScript as HTMLScriptElement | null;\n if (!script) return {};\n\n const scriptConfig: Partial<SiteAgentInstallConfig> = {};\n\n // Full config from data-config attribute (JSON string)\n const configJson = script.getAttribute('data-config');\n if (configJson) {\n try {\n const parsedConfig = JSON.parse(configJson);\n // If it has nested 'config' property, use it; otherwise treat as widget config\n if (parsedConfig.config) {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { __proto__: _a, constructor: _b, prototype: _c, ...safeConfig } = parsedConfig;\n Object.assign(scriptConfig, safeConfig);\n } else {\n // Treat the entire object as widget config\n scriptConfig.config = parsedConfig;\n }\n } catch (e) {\n console.error(\"Failed to parse data-config JSON:\", e);\n }\n }\n\n // Client token from data attribute (primary method for client token mode)\n const token = script.getAttribute('data-runtype-token');\n if (token) {\n scriptConfig.clientToken = token;\n }\n\n // Optional flow ID\n const flowId = script.getAttribute('data-flow-id');\n if (flowId) {\n scriptConfig.flowId = flowId;\n }\n\n // Optional API URL override\n const apiUrl = script.getAttribute('data-api-url');\n if (apiUrl) {\n scriptConfig.apiUrl = apiUrl;\n }\n\n // Optional preview query param gate\n const previewQueryParam = script.getAttribute('data-preview-param');\n if (previewQueryParam) {\n scriptConfig.previewQueryParam = previewQueryParam;\n }\n\n return scriptConfig;\n };\n\n // Get config from script attributes (must be called synchronously during script execution)\n const scriptConfig = getConfigFromScript();\n\n // Merge script attributes with window config (script attributes take precedence)\n const windowConfig: SiteAgentInstallConfig = window.siteAgentConfig || {};\n const config: SiteAgentInstallConfig = { ...windowConfig, ...scriptConfig };\n\n const isPreviewModeEnabled = (): boolean => {\n if (!config.previewQueryParam) {\n return true;\n }\n\n const params = new URLSearchParams(window.location.search);\n const value = params.get(config.previewQueryParam);\n return value !== null && value !== \"\" && value.toLowerCase() !== \"false\" && value !== \"0\";\n };\n\n if (!isPreviewModeEnabled()) {\n return;\n }\n \n const version = config.version || \"latest\";\n const cdn = config.cdn || \"jsdelivr\";\n const autoInit = config.autoInit !== false; // Default to true\n\n // Determine CDN base URL\n const getCdnBase = () => {\n if (config.cssUrl && config.jsUrl) {\n return { cssUrl: config.cssUrl, jsUrl: config.jsUrl };\n }\n \n const packageName = \"@runtypelabs/persona\";\n const basePath = `/npm/${packageName}@${version}/dist`;\n \n if (cdn === \"unpkg\") {\n return {\n cssUrl: `https://unpkg.com${basePath}/widget.css`,\n jsUrl: `https://unpkg.com${basePath}/index.global.js`\n };\n } else {\n return {\n cssUrl: `https://cdn.jsdelivr.net${basePath}/widget.css`,\n jsUrl: `https://cdn.jsdelivr.net${basePath}/index.global.js`\n };\n }\n };\n\n const { cssUrl, jsUrl } = getCdnBase();\n\n // Check if CSS is already loaded\n const isCssLoaded = () => {\n return !!document.head.querySelector('link[data-persona]') ||\n !!document.head.querySelector(`link[href*=\"widget.css\"]`);\n };\n\n // Check if JS is already loaded\n const isJsLoaded = () => {\n return !!(window as any).AgentWidget;\n };\n\n /**\n * Wait for framework hydration to complete (Next.js, Nuxt, etc.)\n * This prevents the framework from removing dynamically added CSS during reconciliation.\n * Uses requestIdleCallback + double requestAnimationFrame for reliable detection.\n */\n const waitForHydration = (callback: () => void): void => {\n let executed = false;\n \n const execute = () => {\n if (executed) return;\n executed = true;\n callback();\n };\n\n const afterDom = () => {\n // Strategy 1: Use requestIdleCallback if available (best for detecting idle after hydration)\n if (typeof requestIdleCallback !== 'undefined') {\n requestIdleCallback(() => {\n // Double requestAnimationFrame ensures at least one full paint cycle completed\n requestAnimationFrame(() => {\n requestAnimationFrame(execute);\n });\n }, { timeout: 3000 }); // Max wait 3 seconds, then proceed anyway\n } else {\n // Strategy 2: Fallback for Safari (no requestIdleCallback)\n // 300ms is typically enough for hydration on most pages\n setTimeout(execute, 300);\n }\n };\n\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', afterDom);\n } else {\n // DOM already ready, but still wait for potential hydration\n afterDom();\n }\n };\n\n // Load CSS\n const loadCSS = (): Promise<void> => {\n return new Promise((resolve, reject) => {\n if (isCssLoaded()) {\n resolve();\n return;\n }\n\n const link = document.createElement(\"link\");\n link.rel = \"stylesheet\";\n link.href = cssUrl;\n link.setAttribute(\"data-persona\", \"true\");\n \n link.onload = () => resolve();\n link.onerror = () => reject(new Error(`Failed to load CSS from ${cssUrl}`));\n document.head.appendChild(link);\n });\n };\n\n // Load JS\n const loadJS = (): Promise<void> => {\n return new Promise((resolve, reject) => {\n if (isJsLoaded()) {\n resolve();\n return;\n }\n\n const script = document.createElement(\"script\");\n script.src = jsUrl;\n script.async = true;\n script.onload = () => resolve();\n script.onerror = () => reject(new Error(`Failed to load JS from ${jsUrl}`));\n document.head.appendChild(script);\n });\n };\n\n // Initialize widget\n const initWidget = () => {\n if (!window.AgentWidget || !window.AgentWidget.initAgentWidget) {\n console.warn(\"AgentWidget not available. Make sure the script loaded successfully.\");\n return;\n }\n\n const target = config.target || \"body\";\n // Merge top-level config options into widget config\n const widgetConfig = { ...config.config };\n \n // Merge apiUrl from top-level config into widget config if present\n if (config.apiUrl && !widgetConfig.apiUrl) {\n widgetConfig.apiUrl = config.apiUrl;\n }\n \n // Merge clientToken from top-level config into widget config if present\n if (config.clientToken && !widgetConfig.clientToken) {\n widgetConfig.clientToken = config.clientToken;\n }\n \n // Merge flowId from top-level config into widget config if present\n if (config.flowId && !widgetConfig.flowId) {\n widgetConfig.flowId = config.flowId;\n }\n\n // Only initialize if we have either apiUrl OR clientToken (or other config)\n const hasApiConfig = widgetConfig.apiUrl || widgetConfig.clientToken;\n if (!hasApiConfig && Object.keys(widgetConfig).length === 0) {\n return;\n }\n\n // Auto-apply markdown postprocessor if not explicitly set and available\n if (!widgetConfig.postprocessMessage && window.AgentWidget.markdownPostprocessor) {\n widgetConfig.postprocessMessage = ({ text }: { text: string }) => \n window.AgentWidget.markdownPostprocessor(text);\n }\n\n try {\n window.AgentWidget.initAgentWidget({\n target,\n config: widgetConfig,\n // Explicitly disable shadow DOM for better CSS compatibility with host page\n useShadowDom: config.useShadowDom ?? false\n });\n } catch (error) {\n console.error(\"Failed to initialize AgentWidget:\", error);\n }\n };\n\n // Main installation flow (called after hydration completes)\n const install = async () => {\n try {\n await loadCSS();\n await loadJS();\n \n // Auto-init if we have config OR apiUrl OR clientToken\n const shouldAutoInit = autoInit && (\n config.config || \n config.apiUrl || \n config.clientToken\n );\n \n if (shouldAutoInit) {\n // Wait a tick to ensure AgentWidget is fully initialized\n setTimeout(initWidget, 0);\n }\n } catch (error) {\n console.error(\"Failed to install AgentWidget:\", error);\n }\n };\n\n // Start installation after hydration completes\n // This prevents Next.js/Nuxt/etc. from removing dynamically added CSS\n waitForHydration(install);\n})();\n\n"],"mappings":"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","names":["install_exports","scriptConfig","script","configJson","parsedConfig","_a","_b","_c","safeConfig","e","token","flowId","apiUrl","previewQueryParam","config","value","version","cdn","autoInit","getCdnBase","basePath","cssUrl","jsUrl","isCssLoaded","isJsLoaded","waitForHydration","callback","executed","execute","afterDom","loadCSS","resolve","reject","link","loadJS","initWidget","target","widgetConfig","text","error"]}
1
+ {"version":3,"sources":["../src/install.ts"],"sourcesContent":["/**\n * Standalone installer script for easy script tag installation\n * This script automatically loads CSS and JS, then initializes the widget\n * if configuration is provided via window.siteAgentConfig\n */\n\nexport {};\n\ninterface SiteAgentInstallConfig {\n version?: string;\n cdn?: \"unpkg\" | \"jsdelivr\";\n cssUrl?: string;\n jsUrl?: string;\n target?: string | HTMLElement;\n config?: any;\n autoInit?: boolean;\n // Client token mode options (can also be set via data attributes)\n clientToken?: string;\n flowId?: string;\n apiUrl?: string;\n // Optional query param key that gates widget installation in preview mode\n previewQueryParam?: string;\n // Shadow DOM option (defaults to false for better CSS compatibility)\n useShadowDom?: boolean;\n}\n\ndeclare global {\n interface Window {\n siteAgentConfig?: SiteAgentInstallConfig;\n AgentWidget?: any;\n }\n}\n\n(function() {\n \"use strict\";\n\n // Prevent double installation\n if ((window as any).__siteAgentInstallerLoaded) {\n return;\n }\n (window as any).__siteAgentInstallerLoaded = true;\n\n /**\n * Read configuration from data attributes on the current script tag.\n * Supports: data-config (JSON), data-runtype-token, data-flow-id, data-api-url\n */\n const getConfigFromScript = (): Partial<SiteAgentInstallConfig> => {\n // Try to get the current script element\n const script = document.currentScript as HTMLScriptElement | null;\n if (!script) return {};\n\n const scriptConfig: Partial<SiteAgentInstallConfig> = {};\n\n // Full config from data-config attribute (JSON string)\n const configJson = script.getAttribute('data-config');\n if (configJson) {\n try {\n // HTML attributes preserve literal newlines/tabs which are invalid\n // control characters inside JSON string literals — strip them.\n const normalizedJson = configJson.replace(/[\\r\\n]+\\s*/g, '');\n const parsedConfig = JSON.parse(normalizedJson);\n // If it has nested 'config' property, use it; otherwise treat as widget config\n if (parsedConfig.config) {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { __proto__: _a, constructor: _b, prototype: _c, ...safeConfig } = parsedConfig;\n Object.assign(scriptConfig, safeConfig);\n } else {\n // Treat the entire object as widget config\n scriptConfig.config = parsedConfig;\n }\n } catch (e) {\n console.error(\"Failed to parse data-config JSON:\", e);\n }\n }\n\n // Client token from data attribute (primary method for client token mode)\n const token = script.getAttribute('data-runtype-token');\n if (token) {\n scriptConfig.clientToken = token;\n }\n\n // Optional flow ID\n const flowId = script.getAttribute('data-flow-id');\n if (flowId) {\n scriptConfig.flowId = flowId;\n }\n\n // Optional API URL override\n const apiUrl = script.getAttribute('data-api-url');\n if (apiUrl) {\n scriptConfig.apiUrl = apiUrl;\n }\n\n // Optional preview query param gate\n const previewQueryParam = script.getAttribute('data-preview-param');\n if (previewQueryParam) {\n scriptConfig.previewQueryParam = previewQueryParam;\n }\n\n return scriptConfig;\n };\n\n // Get config from script attributes (must be called synchronously during script execution)\n const scriptConfig = getConfigFromScript();\n\n // Merge script attributes with window config (script attributes take precedence)\n const windowConfig: SiteAgentInstallConfig = window.siteAgentConfig || {};\n const config: SiteAgentInstallConfig = { ...windowConfig, ...scriptConfig };\n\n const isPreviewModeEnabled = (): boolean => {\n if (!config.previewQueryParam) {\n return true;\n }\n\n const params = new URLSearchParams(window.location.search);\n const value = params.get(config.previewQueryParam);\n return value !== null && value !== \"\" && value.toLowerCase() !== \"false\" && value !== \"0\";\n };\n\n if (!isPreviewModeEnabled()) {\n return;\n }\n \n const version = config.version || \"latest\";\n const cdn = config.cdn || \"jsdelivr\";\n const autoInit = config.autoInit !== false; // Default to true\n\n // Determine CDN base URL\n const getCdnBase = () => {\n if (config.cssUrl && config.jsUrl) {\n return { cssUrl: config.cssUrl, jsUrl: config.jsUrl };\n }\n \n const packageName = \"@runtypelabs/persona\";\n const basePath = `/npm/${packageName}@${version}/dist`;\n \n if (cdn === \"unpkg\") {\n return {\n cssUrl: `https://unpkg.com${basePath}/widget.css`,\n jsUrl: `https://unpkg.com${basePath}/index.global.js`\n };\n } else {\n return {\n cssUrl: `https://cdn.jsdelivr.net${basePath}/widget.css`,\n jsUrl: `https://cdn.jsdelivr.net${basePath}/index.global.js`\n };\n }\n };\n\n const { cssUrl, jsUrl } = getCdnBase();\n\n // Check if CSS is already loaded\n const isCssLoaded = () => {\n return !!document.head.querySelector('link[data-persona]') ||\n !!document.head.querySelector(`link[href*=\"widget.css\"]`);\n };\n\n // Check if JS is already loaded\n const isJsLoaded = () => {\n return !!(window as any).AgentWidget;\n };\n\n /**\n * Wait for framework hydration to complete (Next.js, Nuxt, etc.)\n * This prevents the framework from removing dynamically added CSS during reconciliation.\n * Uses requestIdleCallback + double requestAnimationFrame for reliable detection.\n */\n const waitForHydration = (callback: () => void): void => {\n let executed = false;\n \n const execute = () => {\n if (executed) return;\n executed = true;\n callback();\n };\n\n const afterDom = () => {\n // Strategy 1: Use requestIdleCallback if available (best for detecting idle after hydration)\n if (typeof requestIdleCallback !== 'undefined') {\n requestIdleCallback(() => {\n // Double requestAnimationFrame ensures at least one full paint cycle completed\n requestAnimationFrame(() => {\n requestAnimationFrame(execute);\n });\n }, { timeout: 3000 }); // Max wait 3 seconds, then proceed anyway\n } else {\n // Strategy 2: Fallback for Safari (no requestIdleCallback)\n // 300ms is typically enough for hydration on most pages\n setTimeout(execute, 300);\n }\n };\n\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', afterDom);\n } else {\n // DOM already ready, but still wait for potential hydration\n afterDom();\n }\n };\n\n // Load CSS\n const loadCSS = (): Promise<void> => {\n return new Promise((resolve, reject) => {\n if (isCssLoaded()) {\n resolve();\n return;\n }\n\n const link = document.createElement(\"link\");\n link.rel = \"stylesheet\";\n link.href = cssUrl;\n link.setAttribute(\"data-persona\", \"true\");\n \n link.onload = () => resolve();\n link.onerror = () => reject(new Error(`Failed to load CSS from ${cssUrl}`));\n document.head.appendChild(link);\n });\n };\n\n // Load JS\n const loadJS = (): Promise<void> => {\n return new Promise((resolve, reject) => {\n if (isJsLoaded()) {\n resolve();\n return;\n }\n\n const script = document.createElement(\"script\");\n script.src = jsUrl;\n script.async = true;\n script.onload = () => resolve();\n script.onerror = () => reject(new Error(`Failed to load JS from ${jsUrl}`));\n document.head.appendChild(script);\n });\n };\n\n // Initialize widget\n const initWidget = () => {\n if (!window.AgentWidget || !window.AgentWidget.initAgentWidget) {\n console.warn(\"AgentWidget not available. Make sure the script loaded successfully.\");\n return;\n }\n\n const target = config.target || \"body\";\n // Merge top-level config options into widget config\n const widgetConfig = { ...config.config };\n \n // Merge apiUrl from top-level config into widget config if present\n if (config.apiUrl && !widgetConfig.apiUrl) {\n widgetConfig.apiUrl = config.apiUrl;\n }\n \n // Merge clientToken from top-level config into widget config if present\n if (config.clientToken && !widgetConfig.clientToken) {\n widgetConfig.clientToken = config.clientToken;\n }\n \n // Merge flowId from top-level config into widget config if present\n if (config.flowId && !widgetConfig.flowId) {\n widgetConfig.flowId = config.flowId;\n }\n\n // Only initialize if we have either apiUrl OR clientToken (or other config)\n const hasApiConfig = widgetConfig.apiUrl || widgetConfig.clientToken;\n if (!hasApiConfig && Object.keys(widgetConfig).length === 0) {\n return;\n }\n\n // Auto-apply markdown postprocessor if not explicitly set and available\n if (!widgetConfig.postprocessMessage && window.AgentWidget.markdownPostprocessor) {\n widgetConfig.postprocessMessage = ({ text }: { text: string }) => \n window.AgentWidget.markdownPostprocessor(text);\n }\n\n try {\n window.AgentWidget.initAgentWidget({\n target,\n config: widgetConfig,\n // Explicitly disable shadow DOM for better CSS compatibility with host page\n useShadowDom: config.useShadowDom ?? false\n });\n } catch (error) {\n console.error(\"Failed to initialize AgentWidget:\", error);\n }\n };\n\n // Main installation flow (called after hydration completes)\n const install = async () => {\n try {\n await loadCSS();\n await loadJS();\n \n // Auto-init if we have config OR apiUrl OR clientToken\n const shouldAutoInit = autoInit && (\n config.config || \n config.apiUrl || \n config.clientToken\n );\n \n if (shouldAutoInit) {\n // Wait a tick to ensure AgentWidget is fully initialized\n setTimeout(initWidget, 0);\n }\n } catch (error) {\n console.error(\"Failed to install AgentWidget:\", error);\n }\n };\n\n // Start installation after hydration completes\n // This prevents Next.js/Nuxt/etc. from removing dynamically added CSS\n waitForHydration(install);\n})();\n\n"],"mappings":"4YAAA,IAAAA,EAAA,IAiCC,UAAW,CACV,aAGA,GAAK,OAAe,2BAClB,OAED,OAAe,2BAA6B,GA+D7C,IAAMC,GAzDsB,IAAuC,CAEjE,IAAMC,EAAS,SAAS,cACxB,GAAI,CAACA,EAAQ,MAAO,CAAC,EAErB,IAAMD,EAAgD,CAAC,EAGjDE,EAAaD,EAAO,aAAa,aAAa,EACpD,GAAIC,EACF,GAAI,CAGF,IAAMC,EAAiBD,EAAW,QAAQ,cAAe,EAAE,EACrDE,EAAe,KAAK,MAAMD,CAAc,EAE9C,GAAIC,EAAa,OAAQ,CAEvB,GAAM,CAAE,UAAWC,EAAI,YAAaC,EAAI,UAAWC,EAAI,GAAGC,CAAW,EAAIJ,EACzE,OAAO,OAAOJ,EAAcQ,CAAU,CACxC,MAEER,EAAa,OAASI,CAE1B,OAASK,EAAG,CACV,QAAQ,MAAM,oCAAqCA,CAAC,CACtD,CAIF,IAAMC,EAAQT,EAAO,aAAa,oBAAoB,EAClDS,IACFV,EAAa,YAAcU,GAI7B,IAAMC,EAASV,EAAO,aAAa,cAAc,EAC7CU,IACFX,EAAa,OAASW,GAIxB,IAAMC,EAASX,EAAO,aAAa,cAAc,EAC7CW,IACFZ,EAAa,OAASY,GAIxB,IAAMC,EAAoBZ,EAAO,aAAa,oBAAoB,EAClE,OAAIY,IACFb,EAAa,kBAAoBa,GAG5Bb,CACT,GAGyC,EAInCc,EAAiC,CAAE,GADI,OAAO,iBAAmB,CAAC,EACd,GAAGd,CAAa,EAY1E,GAAI,EAVyB,IAAe,CAC1C,GAAI,CAACc,EAAO,kBACV,MAAO,GAIT,IAAMC,EADS,IAAI,gBAAgB,OAAO,SAAS,MAAM,EACpC,IAAID,EAAO,iBAAiB,EACjD,OAAOC,IAAU,MAAQA,IAAU,IAAMA,EAAM,YAAY,IAAM,SAAWA,IAAU,GACxF,GAE0B,EACxB,OAGF,IAAMC,EAAUF,EAAO,SAAW,SAC5BG,EAAMH,EAAO,KAAO,WACpBI,EAAWJ,EAAO,WAAa,GAG/BK,EAAa,IAAM,CACvB,GAAIL,EAAO,QAAUA,EAAO,MAC1B,MAAO,CAAE,OAAQA,EAAO,OAAQ,MAAOA,EAAO,KAAM,EAItD,IAAMM,EAAW,6BAAuBJ,CAAO,QAE/C,OAAIC,IAAQ,QACH,CACL,OAAQ,oBAAoBG,CAAQ,cACpC,MAAO,oBAAoBA,CAAQ,kBACrC,EAEO,CACL,OAAQ,2BAA2BA,CAAQ,cAC3C,MAAO,2BAA2BA,CAAQ,kBAC5C,CAEJ,EAEM,CAAE,OAAAC,EAAQ,MAAAC,CAAM,EAAIH,EAAW,EAG/BI,EAAc,IACX,CAAC,CAAC,SAAS,KAAK,cAAc,oBAAoB,GAClD,CAAC,CAAC,SAAS,KAAK,cAAc,0BAA0B,EAI3DC,EAAa,IACV,CAAC,CAAE,OAAe,YAQrBC,EAAoBC,GAA+B,CACvD,IAAIC,EAAW,GAETC,EAAU,IAAM,CAChBD,IACJA,EAAW,GACXD,EAAS,EACX,EAEMG,EAAW,IAAM,CAEjB,OAAO,qBAAwB,YACjC,oBAAoB,IAAM,CAExB,sBAAsB,IAAM,CAC1B,sBAAsBD,CAAO,CAC/B,CAAC,CACH,EAAG,CAAE,QAAS,GAAK,CAAC,EAIpB,WAAWA,EAAS,GAAG,CAE3B,EAEI,SAAS,aAAe,UAC1B,SAAS,iBAAiB,mBAAoBC,CAAQ,EAGtDA,EAAS,CAEb,EAGMC,EAAU,IACP,IAAI,QAAQ,CAACC,EAASC,IAAW,CACtC,GAAIT,EAAY,EAAG,CACjBQ,EAAQ,EACR,MACF,CAEA,IAAME,EAAO,SAAS,cAAc,MAAM,EAC1CA,EAAK,IAAM,aACXA,EAAK,KAAOZ,EACZY,EAAK,aAAa,eAAgB,MAAM,EAExCA,EAAK,OAAS,IAAMF,EAAQ,EAC5BE,EAAK,QAAU,IAAMD,EAAO,IAAI,MAAM,2BAA2BX,CAAM,EAAE,CAAC,EAC1E,SAAS,KAAK,YAAYY,CAAI,CAChC,CAAC,EAIGC,EAAS,IACN,IAAI,QAAQ,CAACH,EAASC,IAAW,CACtC,GAAIR,EAAW,EAAG,CAChBO,EAAQ,EACR,MACF,CAEA,IAAM9B,EAAS,SAAS,cAAc,QAAQ,EAC9CA,EAAO,IAAMqB,EACbrB,EAAO,MAAQ,GACfA,EAAO,OAAS,IAAM8B,EAAQ,EAC9B9B,EAAO,QAAU,IAAM+B,EAAO,IAAI,MAAM,0BAA0BV,CAAK,EAAE,CAAC,EAC1E,SAAS,KAAK,YAAYrB,CAAM,CAClC,CAAC,EAIGkC,EAAa,IAAM,CA7O3B,IAAA9B,EA8OI,GAAI,CAAC,OAAO,aAAe,CAAC,OAAO,YAAY,gBAAiB,CAC9D,QAAQ,KAAK,sEAAsE,EACnF,MACF,CAEA,IAAM+B,EAAStB,EAAO,QAAU,OAE1BuB,EAAe,CAAE,GAAGvB,EAAO,MAAO,EAmBxC,GAhBIA,EAAO,QAAU,CAACuB,EAAa,SACjCA,EAAa,OAASvB,EAAO,QAI3BA,EAAO,aAAe,CAACuB,EAAa,cACtCA,EAAa,YAAcvB,EAAO,aAIhCA,EAAO,QAAU,CAACuB,EAAa,SACjCA,EAAa,OAASvB,EAAO,QAK3B,IADiBuB,EAAa,QAAUA,EAAa,cACpC,OAAO,KAAKA,CAAY,EAAE,SAAW,GAK1D,CAAI,CAACA,EAAa,oBAAsB,OAAO,YAAY,wBACzDA,EAAa,mBAAqB,CAAC,CAAE,KAAAC,CAAK,IACxC,OAAO,YAAY,sBAAsBA,CAAI,GAGjD,GAAI,CACF,OAAO,YAAY,gBAAgB,CACjC,OAAAF,EACA,OAAQC,EAER,cAAchC,EAAAS,EAAO,eAAP,KAAAT,EAAuB,EACvC,CAAC,CACH,OAASkC,EAAO,CACd,QAAQ,MAAM,oCAAqCA,CAAK,CAC1D,EACF,EA0BAd,EAvBgB,SAAY,CAC1B,GAAI,CACF,MAAMK,EAAQ,EACd,MAAMI,EAAO,EAGUhB,IACrBJ,EAAO,QACPA,EAAO,QACPA,EAAO,cAKP,WAAWqB,EAAY,CAAC,CAE5B,OAASI,EAAO,CACd,QAAQ,MAAM,iCAAkCA,CAAK,CACvD,CACF,CAIwB,CAC1B,GAAG","names":["install_exports","scriptConfig","script","configJson","normalizedJson","parsedConfig","_a","_b","_c","safeConfig","e","token","flowId","apiUrl","previewQueryParam","config","value","version","cdn","autoInit","getCdnBase","basePath","cssUrl","jsUrl","isCssLoaded","isJsLoaded","waitForHydration","callback","executed","execute","afterDom","loadCSS","resolve","reject","link","loadJS","initWidget","target","widgetConfig","text","error"]}
@@ -233,12 +233,14 @@ var DEFAULT_WIDGET_CONFIG = {
233
233
  activePreview: false,
234
234
  grouped: false,
235
235
  previewMaxLines: 3,
236
- expandable: true
236
+ expandable: true,
237
+ loadingAnimation: "none"
237
238
  },
238
239
  reasoningDisplay: {
239
240
  activePreview: false,
240
241
  previewMaxLines: 3,
241
- expandable: true
242
+ expandable: true,
243
+ loadingAnimation: "none"
242
244
  }
243
245
  },
244
246
  suggestionChips: [
@@ -3345,6 +3347,70 @@ var describeToolTitle = (tool) => {
3345
3347
  }
3346
3348
  return "Using tool...";
3347
3349
  };
3350
+ var formatElapsedMs = (ms) => {
3351
+ const seconds = ms / 1e3;
3352
+ if (seconds < 0.1) return "<0.1s";
3353
+ if (seconds >= 10) return `${Math.round(seconds)}s`;
3354
+ return `${seconds.toFixed(1).replace(/\.0$/, "")}s`;
3355
+ };
3356
+ var computeToolElapsed = (tool) => {
3357
+ var _a, _b, _c;
3358
+ const durationMs = typeof tool.duration === "number" ? tool.duration : typeof tool.durationMs === "number" ? tool.durationMs : Math.max(
3359
+ 0,
3360
+ ((_a = tool.completedAt) != null ? _a : Date.now()) - ((_c = (_b = tool.startedAt) != null ? _b : tool.completedAt) != null ? _c : Date.now())
3361
+ );
3362
+ return formatElapsedMs(durationMs);
3363
+ };
3364
+ var computeReasoningElapsed = (reasoning) => {
3365
+ var _a, _b, _c;
3366
+ const durationMs = reasoning.durationMs !== void 0 ? reasoning.durationMs : Math.max(
3367
+ 0,
3368
+ ((_a = reasoning.completedAt) != null ? _a : Date.now()) - ((_c = (_b = reasoning.startedAt) != null ? _b : reasoning.completedAt) != null ? _c : Date.now())
3369
+ );
3370
+ return formatElapsedMs(durationMs);
3371
+ };
3372
+ var resolveToolHeaderText = (tool, template, fallback) => {
3373
+ var _a;
3374
+ if (!template) return fallback;
3375
+ const toolName = ((_a = tool.name) == null ? void 0 : _a.trim()) || "tool";
3376
+ const duration = computeToolElapsed(tool);
3377
+ return template.replace(/\{toolName\}/g, toolName).replace(/\{duration\}/g, duration);
3378
+ };
3379
+ var parseFormattedTemplate = (template, toolName) => {
3380
+ const resolved = template.replace(/\{toolName\}/g, toolName);
3381
+ const segments = [];
3382
+ const regex = /\*\*(.+?)\*\*|\*(.+?)\*|~(.+?)~/g;
3383
+ let lastIndex = 0;
3384
+ let match;
3385
+ while ((match = regex.exec(resolved)) !== null) {
3386
+ if (match.index > lastIndex) {
3387
+ pushSegments(segments, resolved.slice(lastIndex, match.index), []);
3388
+ }
3389
+ if (match[1] !== void 0) {
3390
+ pushSegments(segments, match[1], ["bold"]);
3391
+ } else if (match[2] !== void 0) {
3392
+ pushSegments(segments, match[2], ["italic"]);
3393
+ } else if (match[3] !== void 0) {
3394
+ pushSegments(segments, match[3], ["dim"]);
3395
+ }
3396
+ lastIndex = match.index + match[0].length;
3397
+ }
3398
+ if (lastIndex < resolved.length) {
3399
+ pushSegments(segments, resolved.slice(lastIndex), []);
3400
+ }
3401
+ return segments;
3402
+ };
3403
+ var pushSegments = (segments, text, styles) => {
3404
+ const parts = text.split("{duration}");
3405
+ for (let i = 0; i < parts.length; i++) {
3406
+ if (parts[i]) {
3407
+ segments.push({ text: parts[i], styles });
3408
+ }
3409
+ if (i < parts.length - 1) {
3410
+ segments.push({ text: "{duration}", styles, isDuration: true });
3411
+ }
3412
+ }
3413
+ };
3348
3414
  var createRegexJsonParserInternal = () => {
3349
3415
  let extractedText = null;
3350
3416
  let processedLength = 0;
@@ -7962,10 +8028,24 @@ var morphMessages = (container, newContent, options = {}) => {
7962
8028
  import_idiomorph.Idiomorph.morph(container, newContent.innerHTML, {
7963
8029
  morphStyle: "innerHTML",
7964
8030
  callbacks: {
7965
- beforeNodeMorphed(oldNode, _newNode) {
8031
+ beforeNodeMorphed(oldNode, newNode) {
8032
+ var _a, _b;
7966
8033
  if (!(oldNode instanceof HTMLElement)) return;
7967
8034
  if (preserveTypingAnimation) {
7968
- if (oldNode.classList.contains("persona-animate-typing") || oldNode.hasAttribute("data-preserve-animation")) {
8035
+ if (oldNode.classList.contains("persona-animate-typing")) {
8036
+ return false;
8037
+ }
8038
+ if (oldNode.hasAttribute("data-preserve-animation")) {
8039
+ if (newNode instanceof HTMLElement && !newNode.hasAttribute("data-preserve-animation")) {
8040
+ return;
8041
+ }
8042
+ if (newNode instanceof HTMLElement && newNode.hasAttribute("data-preserve-animation")) {
8043
+ const oldText = (_a = oldNode.textContent) != null ? _a : "";
8044
+ const newText = (_b = newNode.textContent) != null ? _b : "";
8045
+ if (oldText !== newText) {
8046
+ return;
8047
+ }
8048
+ }
7969
8049
  return false;
7970
8050
  }
7971
8051
  }
@@ -7976,7 +8056,7 @@ var morphMessages = (container, newContent, options = {}) => {
7976
8056
 
7977
8057
  // src/utils/message-fingerprint.ts
7978
8058
  function computeMessageFingerprint(message, configVersion) {
7979
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A;
8059
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C;
7980
8060
  return [
7981
8061
  message.id,
7982
8062
  message.role,
@@ -7988,11 +8068,12 @@ function computeMessageFingerprint(message, configVersion) {
7988
8068
  (_i = (_h = message.llmContent) == null ? void 0 : _h.length) != null ? _i : 0,
7989
8069
  (_k = (_j = message.approval) == null ? void 0 : _j.status) != null ? _k : "",
7990
8070
  (_m = (_l = message.toolCall) == null ? void 0 : _l.status) != null ? _m : "",
7991
- (_p = (_o = (_n = message.toolCall) == null ? void 0 : _n.chunks) == null ? void 0 : _o.length) != null ? _p : 0,
7992
- (_t = (_s = (_r = (_q = message.toolCall) == null ? void 0 : _q.chunks) == null ? void 0 : _r[message.toolCall.chunks.length - 1]) == null ? void 0 : _s.slice(-32)) != null ? _t : "",
7993
- typeof ((_u = message.toolCall) == null ? void 0 : _u.args) === "string" ? message.toolCall.args.length : ((_v = message.toolCall) == null ? void 0 : _v.args) ? JSON.stringify(message.toolCall.args).length : 0,
7994
- (_y = (_x = (_w = message.reasoning) == null ? void 0 : _w.chunks) == null ? void 0 : _x.length) != null ? _y : 0,
7995
- (_A = (_z = message.contentParts) == null ? void 0 : _z.length) != null ? _A : 0,
8071
+ (_o = (_n = message.toolCall) == null ? void 0 : _n.name) != null ? _o : "",
8072
+ (_r = (_q = (_p = message.toolCall) == null ? void 0 : _p.chunks) == null ? void 0 : _q.length) != null ? _r : 0,
8073
+ (_v = (_u = (_t = (_s = message.toolCall) == null ? void 0 : _s.chunks) == null ? void 0 : _t[message.toolCall.chunks.length - 1]) == null ? void 0 : _u.slice(-32)) != null ? _v : "",
8074
+ typeof ((_w = message.toolCall) == null ? void 0 : _w.args) === "string" ? message.toolCall.args.length : ((_x = message.toolCall) == null ? void 0 : _x.args) ? JSON.stringify(message.toolCall.args).length : 0,
8075
+ (_A = (_z = (_y = message.reasoning) == null ? void 0 : _y.chunks) == null ? void 0 : _z.length) != null ? _A : 0,
8076
+ (_C = (_B = message.contentParts) == null ? void 0 : _B.length) != null ? _C : 0,
7996
8077
  configVersion
7997
8078
  ].join("\0");
7998
8079
  }
@@ -10114,7 +10195,7 @@ var updateReasoningBubbleUI = (messageId, bubble) => {
10114
10195
  }
10115
10196
  };
10116
10197
  var createReasoningBubble = (message, config) => {
10117
- var _a, _b, _c, _d, _e, _f, _g;
10198
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
10118
10199
  const reasoning = message.reasoning;
10119
10200
  const bubble = createElement(
10120
10201
  "div",
@@ -10157,13 +10238,23 @@ var createReasoningBubble = (message, config) => {
10157
10238
  const headerContent = createElement("div", "persona-flex persona-flex-col persona-text-left");
10158
10239
  const title = createElement("span", "persona-text-xs persona-text-persona-primary");
10159
10240
  const defaultSummary = "Thinking...";
10160
- const customSummary = (_e = (_d = config == null ? void 0 : config.reasoning) == null ? void 0 : _d.renderCollapsedSummary) == null ? void 0 : _e.call(_d, {
10241
+ const reasoningConfig = (_d = config == null ? void 0 : config.reasoning) != null ? _d : {};
10242
+ const startedAt = String((_e = reasoning.startedAt) != null ? _e : Date.now());
10243
+ const createElapsedSpan = () => {
10244
+ const span = createElement("span", "");
10245
+ span.setAttribute("data-tool-elapsed", startedAt);
10246
+ span.textContent = computeReasoningElapsed(reasoning);
10247
+ return span;
10248
+ };
10249
+ const customSummary = (_f = reasoningConfig.renderCollapsedSummary) == null ? void 0 : _f.call(reasoningConfig, {
10161
10250
  message,
10162
10251
  reasoning,
10163
10252
  defaultSummary,
10164
10253
  previewText,
10165
10254
  isActive,
10166
- config: config != null ? config : {}
10255
+ config: config != null ? config : {},
10256
+ elapsed: computeReasoningElapsed(reasoning),
10257
+ createElapsedElement: createElapsedSpan
10167
10258
  });
10168
10259
  if (typeof customSummary === "string" && customSummary.trim()) {
10169
10260
  title.textContent = customSummary;
@@ -10177,10 +10268,101 @@ var createReasoningBubble = (message, config) => {
10177
10268
  const status = createElement("span", "persona-text-xs persona-text-persona-primary");
10178
10269
  status.textContent = describeReasonStatus(reasoning);
10179
10270
  headerContent.appendChild(status);
10180
- if (reasoning.status === "complete") {
10181
- title.style.display = "none";
10182
- } else {
10271
+ const loadingAnimation = (_g = reasoningDisplayConfig.loadingAnimation) != null ? _g : "none";
10272
+ const activeTemplate = reasoningConfig.activeTextTemplate;
10273
+ const completeTemplate = reasoningConfig.completeTextTemplate;
10274
+ const currentTemplate = isActive ? activeTemplate : completeTemplate;
10275
+ const skipCustomElement = customSummary instanceof HTMLElement;
10276
+ const appendCharSpans = (container, text2, startIndex) => {
10277
+ let idx = startIndex;
10278
+ for (const char of text2) {
10279
+ const span = createElement("span", "persona-tool-char");
10280
+ span.style.setProperty("--char-index", String(idx));
10281
+ span.textContent = char === " " ? "\xA0" : char;
10282
+ container.appendChild(span);
10283
+ idx++;
10284
+ }
10285
+ return idx;
10286
+ };
10287
+ const renderFormattedTitle = (template, animated) => {
10288
+ title.textContent = "";
10289
+ const segments = parseFormattedTemplate(template, "");
10290
+ let charIndex = 0;
10291
+ for (const seg of segments) {
10292
+ const parent = seg.styles.length > 0 ? (() => {
10293
+ const w = createElement("span", seg.styles.map((s) => `persona-tool-text-${s}`).join(" "));
10294
+ title.appendChild(w);
10295
+ return w;
10296
+ })() : title;
10297
+ if (seg.isDuration && isActive) {
10298
+ parent.appendChild(createElapsedSpan());
10299
+ } else {
10300
+ const text2 = seg.isDuration ? computeReasoningElapsed(reasoning) : seg.text;
10301
+ if (animated) {
10302
+ charIndex = appendCharSpans(parent, text2, charIndex);
10303
+ } else {
10304
+ parent.appendChild(document.createTextNode(text2));
10305
+ }
10306
+ }
10307
+ }
10308
+ };
10309
+ if (!skipCustomElement && currentTemplate) {
10310
+ status.style.display = "none";
10311
+ title.style.display = "";
10312
+ if (isActive && loadingAnimation !== "none") {
10313
+ const animDuration = (_h = reasoningConfig.loadingAnimationDuration) != null ? _h : 2e3;
10314
+ title.setAttribute("data-preserve-animation", "true");
10315
+ if (loadingAnimation === "pulse") {
10316
+ title.classList.add("persona-tool-loading-pulse");
10317
+ title.style.setProperty("--persona-tool-anim-duration", `${animDuration}ms`);
10318
+ renderFormattedTitle(currentTemplate, false);
10319
+ } else {
10320
+ title.classList.add(`persona-tool-loading-${loadingAnimation}`);
10321
+ title.style.setProperty("--persona-tool-anim-duration", `${animDuration}ms`);
10322
+ if (loadingAnimation === "shimmer-color") {
10323
+ if (reasoningConfig.loadingAnimationColor) {
10324
+ title.style.setProperty("--persona-tool-anim-color", reasoningConfig.loadingAnimationColor);
10325
+ }
10326
+ if (reasoningConfig.loadingAnimationSecondaryColor) {
10327
+ title.style.setProperty("--persona-tool-anim-secondary-color", reasoningConfig.loadingAnimationSecondaryColor);
10328
+ }
10329
+ }
10330
+ renderFormattedTitle(currentTemplate, true);
10331
+ }
10332
+ } else {
10333
+ renderFormattedTitle(currentTemplate, false);
10334
+ }
10335
+ } else if (!skipCustomElement && isActive && loadingAnimation !== "none") {
10183
10336
  title.style.display = "";
10337
+ const animDuration = (_i = reasoningConfig.loadingAnimationDuration) != null ? _i : 2e3;
10338
+ title.setAttribute("data-preserve-animation", "true");
10339
+ if (loadingAnimation === "pulse") {
10340
+ title.classList.add("persona-tool-loading-pulse");
10341
+ title.style.setProperty("--persona-tool-anim-duration", `${animDuration}ms`);
10342
+ } else {
10343
+ title.classList.add(`persona-tool-loading-${loadingAnimation}`);
10344
+ title.style.setProperty("--persona-tool-anim-duration", `${animDuration}ms`);
10345
+ if (loadingAnimation === "shimmer-color") {
10346
+ if (reasoningConfig.loadingAnimationColor) {
10347
+ title.style.setProperty("--persona-tool-anim-color", reasoningConfig.loadingAnimationColor);
10348
+ }
10349
+ if (reasoningConfig.loadingAnimationSecondaryColor) {
10350
+ title.style.setProperty("--persona-tool-anim-secondary-color", reasoningConfig.loadingAnimationSecondaryColor);
10351
+ }
10352
+ }
10353
+ const text2 = title.textContent || defaultSummary;
10354
+ title.textContent = "";
10355
+ appendCharSpans(title, text2, 0);
10356
+ }
10357
+ if (reasoning.status === "complete") {
10358
+ title.style.display = "none";
10359
+ }
10360
+ } else if (!skipCustomElement) {
10361
+ if (reasoning.status === "complete") {
10362
+ title.style.display = "none";
10363
+ } else {
10364
+ title.style.display = "";
10365
+ }
10184
10366
  }
10185
10367
  let toggleIcon = null;
10186
10368
  if (expandable) {
@@ -10206,7 +10388,7 @@ var createReasoningBubble = (message, config) => {
10206
10388
  collapsedPreview.style.display = "none";
10207
10389
  collapsedPreview.style.whiteSpace = "pre-wrap";
10208
10390
  if (!expanded && isActive && reasoningDisplayConfig.activePreview && previewText) {
10209
- const renderedPreview = (_g = (_f = config == null ? void 0 : config.reasoning) == null ? void 0 : _f.renderCollapsedPreview) == null ? void 0 : _g.call(_f, {
10391
+ const renderedPreview = (_k = (_j = config == null ? void 0 : config.reasoning) == null ? void 0 : _j.renderCollapsedPreview) == null ? void 0 : _k.call(_j, {
10210
10392
  message,
10211
10393
  reasoning,
10212
10394
  defaultPreview: previewText,
@@ -10282,7 +10464,7 @@ var getToolPreviewText = (message, maxLines) => {
10282
10464
  return argsText.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).slice(0, maxLines).join("\n");
10283
10465
  };
10284
10466
  var getToolSummaryText = (message, config) => {
10285
- var _a, _b, _c, _d;
10467
+ var _a, _b, _c, _d, _e;
10286
10468
  const tool = message.toolCall;
10287
10469
  const toolDisplayConfig = (_a = config == null ? void 0 : config.features) == null ? void 0 : _a.toolCallDisplay;
10288
10470
  const collapsedMode = (_b = toolDisplayConfig == null ? void 0 : toolDisplayConfig.collapsedMode) != null ? _b : "tool-call";
@@ -10292,12 +10474,18 @@ var getToolSummaryText = (message, config) => {
10292
10474
  return { summary: defaultSummary, previewText, isActive: false };
10293
10475
  }
10294
10476
  const isActive = tool.status !== "complete";
10477
+ const toolCallConfig = (_d = config == null ? void 0 : config.toolCall) != null ? _d : {};
10295
10478
  let summary = defaultSummary;
10296
10479
  if (collapsedMode === "tool-name") {
10297
- summary = ((_d = tool.name) == null ? void 0 : _d.trim()) || defaultSummary;
10480
+ summary = ((_e = tool.name) == null ? void 0 : _e.trim()) || defaultSummary;
10298
10481
  } else if (collapsedMode === "tool-preview" && previewText) {
10299
10482
  summary = previewText;
10300
10483
  }
10484
+ if (isActive && toolCallConfig.activeTextTemplate) {
10485
+ summary = resolveToolHeaderText(tool, toolCallConfig.activeTextTemplate, summary);
10486
+ } else if (!isActive && toolCallConfig.completeTextTemplate) {
10487
+ summary = resolveToolHeaderText(tool, toolCallConfig.completeTextTemplate, summary);
10488
+ }
10301
10489
  return { summary, previewText, isActive };
10302
10490
  };
10303
10491
  var updateToolBubbleUI = (messageId, bubble, config) => {
@@ -10327,7 +10515,7 @@ var updateToolBubbleUI = (messageId, bubble, config) => {
10327
10515
  }
10328
10516
  };
10329
10517
  var createToolBubble = (message, config) => {
10330
- var _a, _b, _c, _d, _e, _f;
10518
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
10331
10519
  const tool = message.toolCall;
10332
10520
  const toolCallConfig = (_a = config == null ? void 0 : config.toolCall) != null ? _a : {};
10333
10521
  const bubble = createElement(
@@ -10395,14 +10583,23 @@ var createToolBubble = (message, config) => {
10395
10583
  if (toolCallConfig.headerTextColor) {
10396
10584
  title.style.color = toolCallConfig.headerTextColor;
10397
10585
  }
10398
- const customSummary = (_e = toolCallConfig.renderCollapsedSummary) == null ? void 0 : _e.call(toolCallConfig, {
10586
+ const startedAt = String((_d = tool.startedAt) != null ? _d : Date.now());
10587
+ const createElapsedSpan = () => {
10588
+ const span = createElement("span", "");
10589
+ span.setAttribute("data-tool-elapsed", startedAt);
10590
+ span.textContent = computeToolElapsed(tool);
10591
+ return span;
10592
+ };
10593
+ const customSummary = (_f = toolCallConfig.renderCollapsedSummary) == null ? void 0 : _f.call(toolCallConfig, {
10399
10594
  message,
10400
10595
  toolCall: tool,
10401
10596
  defaultSummary: summary,
10402
10597
  previewText,
10403
- collapsedMode: (_d = toolDisplayConfig.collapsedMode) != null ? _d : "tool-call",
10598
+ collapsedMode: (_e = toolDisplayConfig.collapsedMode) != null ? _e : "tool-call",
10404
10599
  isActive,
10405
- config: config != null ? config : {}
10600
+ config: config != null ? config : {},
10601
+ elapsed: computeToolElapsed(tool),
10602
+ createElapsedElement: createElapsedSpan
10406
10603
  });
10407
10604
  if (typeof customSummary === "string" && customSummary.trim()) {
10408
10605
  title.textContent = customSummary;
@@ -10413,6 +10610,79 @@ var createToolBubble = (message, config) => {
10413
10610
  title.textContent = summary;
10414
10611
  headerContent.appendChild(title);
10415
10612
  }
10613
+ const loadingAnimation = (_g = toolDisplayConfig.loadingAnimation) != null ? _g : "none";
10614
+ const activeTemplate = toolCallConfig.activeTextTemplate;
10615
+ const completeTemplate = toolCallConfig.completeTextTemplate;
10616
+ const currentTemplate = isActive ? activeTemplate : completeTemplate;
10617
+ const skipCustomElement = customSummary instanceof HTMLElement;
10618
+ const appendCharSpans = (container, text, startIndex) => {
10619
+ let idx = startIndex;
10620
+ for (const char of text) {
10621
+ const span = createElement("span", "persona-tool-char");
10622
+ span.style.setProperty("--char-index", String(idx));
10623
+ span.textContent = char === " " ? "\xA0" : char;
10624
+ container.appendChild(span);
10625
+ idx++;
10626
+ }
10627
+ return idx;
10628
+ };
10629
+ const renderFormattedTitle = (template, animated) => {
10630
+ var _a2;
10631
+ title.textContent = "";
10632
+ const toolName = ((_a2 = tool.name) == null ? void 0 : _a2.trim()) || "tool";
10633
+ const segments = parseFormattedTemplate(template, toolName);
10634
+ let charIndex = 0;
10635
+ for (const seg of segments) {
10636
+ const parent = seg.styles.length > 0 ? (() => {
10637
+ const w = createElement("span", seg.styles.map((s) => `persona-tool-text-${s}`).join(" "));
10638
+ title.appendChild(w);
10639
+ return w;
10640
+ })() : title;
10641
+ if (seg.isDuration && isActive) {
10642
+ parent.appendChild(createElapsedSpan());
10643
+ } else {
10644
+ const text = seg.isDuration ? computeToolElapsed(tool) : seg.text;
10645
+ if (animated) {
10646
+ charIndex = appendCharSpans(parent, text, charIndex);
10647
+ } else {
10648
+ parent.appendChild(document.createTextNode(text));
10649
+ }
10650
+ }
10651
+ }
10652
+ };
10653
+ if (!skipCustomElement) {
10654
+ if (isActive && loadingAnimation !== "none") {
10655
+ const animDuration = (_h = toolCallConfig.loadingAnimationDuration) != null ? _h : 2e3;
10656
+ title.setAttribute("data-preserve-animation", "true");
10657
+ if (loadingAnimation === "pulse") {
10658
+ title.classList.add("persona-tool-loading-pulse");
10659
+ title.style.setProperty("--persona-tool-anim-duration", `${animDuration}ms`);
10660
+ if (currentTemplate) {
10661
+ renderFormattedTitle(currentTemplate, false);
10662
+ }
10663
+ } else {
10664
+ title.classList.add(`persona-tool-loading-${loadingAnimation}`);
10665
+ title.style.setProperty("--persona-tool-anim-duration", `${animDuration}ms`);
10666
+ if (loadingAnimation === "shimmer-color") {
10667
+ if (toolCallConfig.loadingAnimationColor) {
10668
+ title.style.setProperty("--persona-tool-anim-color", toolCallConfig.loadingAnimationColor);
10669
+ }
10670
+ if (toolCallConfig.loadingAnimationSecondaryColor) {
10671
+ title.style.setProperty("--persona-tool-anim-secondary-color", toolCallConfig.loadingAnimationSecondaryColor);
10672
+ }
10673
+ }
10674
+ if (currentTemplate) {
10675
+ renderFormattedTitle(currentTemplate, true);
10676
+ } else {
10677
+ const text = title.textContent || summary;
10678
+ title.textContent = "";
10679
+ appendCharSpans(title, text, 0);
10680
+ }
10681
+ }
10682
+ } else if (currentTemplate) {
10683
+ renderFormattedTitle(currentTemplate, false);
10684
+ }
10685
+ }
10416
10686
  let toggleIcon = null;
10417
10687
  if (expandable) {
10418
10688
  toggleIcon = createElement("div", "persona-flex persona-items-center");
@@ -10437,7 +10707,7 @@ var createToolBubble = (message, config) => {
10437
10707
  collapsedPreview.style.display = "none";
10438
10708
  collapsedPreview.style.whiteSpace = "pre-wrap";
10439
10709
  if (!expanded && isActive && toolDisplayConfig.activePreview && previewText) {
10440
- const renderedPreview = (_f = toolCallConfig.renderCollapsedPreview) == null ? void 0 : _f.call(toolCallConfig, {
10710
+ const renderedPreview = (_i = toolCallConfig.renderCollapsedPreview) == null ? void 0 : _i.call(toolCallConfig, {
10441
10711
  message,
10442
10712
  toolCall: tool,
10443
10713
  defaultPreview: previewText,
@@ -14830,8 +15100,9 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
14830
15100
  let scrollRAF = null;
14831
15101
  let isAutoScrolling = false;
14832
15102
  let hasPendingAutoScroll = false;
14833
- const USER_SCROLL_THRESHOLD = 1;
14834
- const BOTTOM_THRESHOLD = 8;
15103
+ const USER_SCROLL_THRESHOLD = 4;
15104
+ const BOTTOM_THRESHOLD = 24;
15105
+ const AUTO_SCROLL_SNAP_THRESHOLD = 80;
14835
15106
  const messageState = /* @__PURE__ */ new Map();
14836
15107
  const voiceState = {
14837
15108
  active: false,
@@ -14972,6 +15243,14 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
14972
15243
  lastScrollTop = element.scrollTop;
14973
15244
  return;
14974
15245
  }
15246
+ if (Math.abs(distance) >= AUTO_SCROLL_SNAP_THRESHOLD) {
15247
+ cancelSmoothScroll();
15248
+ isAutoScrolling = true;
15249
+ element.scrollTop = target;
15250
+ lastScrollTop = element.scrollTop;
15251
+ isAutoScrolling = false;
15252
+ return;
15253
+ }
14975
15254
  cancelSmoothScroll();
14976
15255
  const startTime = performance.now();
14977
15256
  isAutoScrolling = true;
@@ -15580,9 +15859,28 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
15580
15859
  }
15581
15860
  };
15582
15861
  }
15862
+ let toolElapsedTimerId = null;
15863
+ const ensureToolElapsedTimer = () => {
15864
+ if (toolElapsedTimerId != null) return;
15865
+ toolElapsedTimerId = setInterval(() => {
15866
+ const spans = messagesWrapper.querySelectorAll("[data-tool-elapsed]");
15867
+ if (spans.length === 0) {
15868
+ clearInterval(toolElapsedTimerId);
15869
+ toolElapsedTimerId = null;
15870
+ return;
15871
+ }
15872
+ const now = Date.now();
15873
+ spans.forEach((span) => {
15874
+ const startedAt = Number(span.getAttribute("data-tool-elapsed"));
15875
+ if (!startedAt) return;
15876
+ span.textContent = formatElapsedMs(now - startedAt);
15877
+ });
15878
+ }, 100);
15879
+ };
15583
15880
  session = new AgentWidgetSession(config, {
15584
15881
  onMessagesChanged(messages) {
15585
15882
  renderMessagesWithPlugins(messagesWrapper, messages, postprocess);
15883
+ ensureToolElapsedTimer();
15586
15884
  if (session) {
15587
15885
  const hasUserMessage = messages.some((msg) => msg.role === "user");
15588
15886
  if (hasUserMessage) {
@@ -17745,6 +18043,10 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
17745
18043
  return session.submitNPSFeedback(rating, comment);
17746
18044
  },
17747
18045
  destroy() {
18046
+ if (toolElapsedTimerId != null) {
18047
+ clearInterval(toolElapsedTimerId);
18048
+ toolElapsedTimerId = null;
18049
+ }
17748
18050
  destroyCallbacks.forEach((cb) => cb());
17749
18051
  wrapper.remove();
17750
18052
  launcherButtonInstance == null ? void 0 : launcherButtonInstance.destroy();