@runtypelabs/persona 3.10.1 → 3.11.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.
@@ -233,7 +233,8 @@ 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,
@@ -3345,6 +3346,62 @@ var describeToolTitle = (tool) => {
3345
3346
  }
3346
3347
  return "Using tool...";
3347
3348
  };
3349
+ var formatElapsedMs = (ms) => {
3350
+ const seconds = ms / 1e3;
3351
+ if (seconds < 0.1) return "<0.1s";
3352
+ if (seconds >= 10) return `${Math.round(seconds)}s`;
3353
+ return `${seconds.toFixed(1).replace(/\.0$/, "")}s`;
3354
+ };
3355
+ var computeToolElapsed = (tool) => {
3356
+ var _a, _b, _c;
3357
+ const durationMs = typeof tool.duration === "number" ? tool.duration : typeof tool.durationMs === "number" ? tool.durationMs : Math.max(
3358
+ 0,
3359
+ ((_a = tool.completedAt) != null ? _a : Date.now()) - ((_c = (_b = tool.startedAt) != null ? _b : tool.completedAt) != null ? _c : Date.now())
3360
+ );
3361
+ return formatElapsedMs(durationMs);
3362
+ };
3363
+ var resolveToolHeaderText = (tool, template, fallback) => {
3364
+ var _a;
3365
+ if (!template) return fallback;
3366
+ const toolName = ((_a = tool.name) == null ? void 0 : _a.trim()) || "tool";
3367
+ const duration = computeToolElapsed(tool);
3368
+ return template.replace(/\{toolName\}/g, toolName).replace(/\{duration\}/g, duration);
3369
+ };
3370
+ var parseFormattedTemplate = (template, toolName) => {
3371
+ const resolved = template.replace(/\{toolName\}/g, toolName);
3372
+ const segments = [];
3373
+ const regex = /\*\*(.+?)\*\*|\*(.+?)\*|~(.+?)~/g;
3374
+ let lastIndex = 0;
3375
+ let match;
3376
+ while ((match = regex.exec(resolved)) !== null) {
3377
+ if (match.index > lastIndex) {
3378
+ pushSegments(segments, resolved.slice(lastIndex, match.index), []);
3379
+ }
3380
+ if (match[1] !== void 0) {
3381
+ pushSegments(segments, match[1], ["bold"]);
3382
+ } else if (match[2] !== void 0) {
3383
+ pushSegments(segments, match[2], ["italic"]);
3384
+ } else if (match[3] !== void 0) {
3385
+ pushSegments(segments, match[3], ["dim"]);
3386
+ }
3387
+ lastIndex = match.index + match[0].length;
3388
+ }
3389
+ if (lastIndex < resolved.length) {
3390
+ pushSegments(segments, resolved.slice(lastIndex), []);
3391
+ }
3392
+ return segments;
3393
+ };
3394
+ var pushSegments = (segments, text, styles) => {
3395
+ const parts = text.split("{duration}");
3396
+ for (let i = 0; i < parts.length; i++) {
3397
+ if (parts[i]) {
3398
+ segments.push({ text: parts[i], styles });
3399
+ }
3400
+ if (i < parts.length - 1) {
3401
+ segments.push({ text: "{duration}", styles, isDuration: true });
3402
+ }
3403
+ }
3404
+ };
3348
3405
  var createRegexJsonParserInternal = () => {
3349
3406
  let extractedText = null;
3350
3407
  let processedLength = 0;
@@ -7962,10 +8019,16 @@ var morphMessages = (container, newContent, options = {}) => {
7962
8019
  import_idiomorph.Idiomorph.morph(container, newContent.innerHTML, {
7963
8020
  morphStyle: "innerHTML",
7964
8021
  callbacks: {
7965
- beforeNodeMorphed(oldNode, _newNode) {
8022
+ beforeNodeMorphed(oldNode, newNode) {
7966
8023
  if (!(oldNode instanceof HTMLElement)) return;
7967
8024
  if (preserveTypingAnimation) {
7968
- if (oldNode.classList.contains("persona-animate-typing") || oldNode.hasAttribute("data-preserve-animation")) {
8025
+ if (oldNode.classList.contains("persona-animate-typing")) {
8026
+ return false;
8027
+ }
8028
+ if (oldNode.hasAttribute("data-preserve-animation")) {
8029
+ if (newNode instanceof HTMLElement && !newNode.hasAttribute("data-preserve-animation")) {
8030
+ return;
8031
+ }
7969
8032
  return false;
7970
8033
  }
7971
8034
  }
@@ -10282,7 +10345,7 @@ var getToolPreviewText = (message, maxLines) => {
10282
10345
  return argsText.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).slice(0, maxLines).join("\n");
10283
10346
  };
10284
10347
  var getToolSummaryText = (message, config) => {
10285
- var _a, _b, _c, _d;
10348
+ var _a, _b, _c, _d, _e;
10286
10349
  const tool = message.toolCall;
10287
10350
  const toolDisplayConfig = (_a = config == null ? void 0 : config.features) == null ? void 0 : _a.toolCallDisplay;
10288
10351
  const collapsedMode = (_b = toolDisplayConfig == null ? void 0 : toolDisplayConfig.collapsedMode) != null ? _b : "tool-call";
@@ -10292,12 +10355,18 @@ var getToolSummaryText = (message, config) => {
10292
10355
  return { summary: defaultSummary, previewText, isActive: false };
10293
10356
  }
10294
10357
  const isActive = tool.status !== "complete";
10358
+ const toolCallConfig = (_d = config == null ? void 0 : config.toolCall) != null ? _d : {};
10295
10359
  let summary = defaultSummary;
10296
10360
  if (collapsedMode === "tool-name") {
10297
- summary = ((_d = tool.name) == null ? void 0 : _d.trim()) || defaultSummary;
10361
+ summary = ((_e = tool.name) == null ? void 0 : _e.trim()) || defaultSummary;
10298
10362
  } else if (collapsedMode === "tool-preview" && previewText) {
10299
10363
  summary = previewText;
10300
10364
  }
10365
+ if (isActive && toolCallConfig.activeTextTemplate) {
10366
+ summary = resolveToolHeaderText(tool, toolCallConfig.activeTextTemplate, summary);
10367
+ } else if (!isActive && toolCallConfig.completeTextTemplate) {
10368
+ summary = resolveToolHeaderText(tool, toolCallConfig.completeTextTemplate, summary);
10369
+ }
10301
10370
  return { summary, previewText, isActive };
10302
10371
  };
10303
10372
  var updateToolBubbleUI = (messageId, bubble, config) => {
@@ -10327,7 +10396,7 @@ var updateToolBubbleUI = (messageId, bubble, config) => {
10327
10396
  }
10328
10397
  };
10329
10398
  var createToolBubble = (message, config) => {
10330
- var _a, _b, _c, _d, _e, _f;
10399
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
10331
10400
  const tool = message.toolCall;
10332
10401
  const toolCallConfig = (_a = config == null ? void 0 : config.toolCall) != null ? _a : {};
10333
10402
  const bubble = createElement(
@@ -10395,14 +10464,23 @@ var createToolBubble = (message, config) => {
10395
10464
  if (toolCallConfig.headerTextColor) {
10396
10465
  title.style.color = toolCallConfig.headerTextColor;
10397
10466
  }
10398
- const customSummary = (_e = toolCallConfig.renderCollapsedSummary) == null ? void 0 : _e.call(toolCallConfig, {
10467
+ const startedAt = String((_d = tool.startedAt) != null ? _d : Date.now());
10468
+ const createElapsedSpan = () => {
10469
+ const span = createElement("span", "");
10470
+ span.setAttribute("data-tool-elapsed", startedAt);
10471
+ span.textContent = computeToolElapsed(tool);
10472
+ return span;
10473
+ };
10474
+ const customSummary = (_f = toolCallConfig.renderCollapsedSummary) == null ? void 0 : _f.call(toolCallConfig, {
10399
10475
  message,
10400
10476
  toolCall: tool,
10401
10477
  defaultSummary: summary,
10402
10478
  previewText,
10403
- collapsedMode: (_d = toolDisplayConfig.collapsedMode) != null ? _d : "tool-call",
10479
+ collapsedMode: (_e = toolDisplayConfig.collapsedMode) != null ? _e : "tool-call",
10404
10480
  isActive,
10405
- config: config != null ? config : {}
10481
+ config: config != null ? config : {},
10482
+ elapsed: computeToolElapsed(tool),
10483
+ createElapsedElement: createElapsedSpan
10406
10484
  });
10407
10485
  if (typeof customSummary === "string" && customSummary.trim()) {
10408
10486
  title.textContent = customSummary;
@@ -10413,6 +10491,79 @@ var createToolBubble = (message, config) => {
10413
10491
  title.textContent = summary;
10414
10492
  headerContent.appendChild(title);
10415
10493
  }
10494
+ const loadingAnimation = (_g = toolDisplayConfig.loadingAnimation) != null ? _g : "none";
10495
+ const activeTemplate = toolCallConfig.activeTextTemplate;
10496
+ const completeTemplate = toolCallConfig.completeTextTemplate;
10497
+ const currentTemplate = isActive ? activeTemplate : completeTemplate;
10498
+ const skipCustomElement = customSummary instanceof HTMLElement;
10499
+ const appendCharSpans = (container, text, startIndex) => {
10500
+ let idx = startIndex;
10501
+ for (const char of text) {
10502
+ const span = createElement("span", "persona-tool-char");
10503
+ span.style.setProperty("--char-index", String(idx));
10504
+ span.textContent = char === " " ? "\xA0" : char;
10505
+ container.appendChild(span);
10506
+ idx++;
10507
+ }
10508
+ return idx;
10509
+ };
10510
+ const renderFormattedTitle = (template, animated) => {
10511
+ var _a2;
10512
+ title.textContent = "";
10513
+ const toolName = ((_a2 = tool.name) == null ? void 0 : _a2.trim()) || "tool";
10514
+ const segments = parseFormattedTemplate(template, toolName);
10515
+ let charIndex = 0;
10516
+ for (const seg of segments) {
10517
+ const parent = seg.styles.length > 0 ? (() => {
10518
+ const w = createElement("span", seg.styles.map((s) => `persona-tool-text-${s}`).join(" "));
10519
+ title.appendChild(w);
10520
+ return w;
10521
+ })() : title;
10522
+ if (seg.isDuration && isActive) {
10523
+ parent.appendChild(createElapsedSpan());
10524
+ } else {
10525
+ const text = seg.isDuration ? computeToolElapsed(tool) : seg.text;
10526
+ if (animated) {
10527
+ charIndex = appendCharSpans(parent, text, charIndex);
10528
+ } else {
10529
+ parent.appendChild(document.createTextNode(text));
10530
+ }
10531
+ }
10532
+ }
10533
+ };
10534
+ if (!skipCustomElement) {
10535
+ if (isActive && loadingAnimation !== "none") {
10536
+ const animDuration = (_h = toolCallConfig.loadingAnimationDuration) != null ? _h : 2e3;
10537
+ title.setAttribute("data-preserve-animation", "true");
10538
+ if (loadingAnimation === "pulse") {
10539
+ title.classList.add("persona-tool-loading-pulse");
10540
+ title.style.setProperty("--persona-tool-anim-duration", `${animDuration}ms`);
10541
+ if (currentTemplate) {
10542
+ renderFormattedTitle(currentTemplate, false);
10543
+ }
10544
+ } else {
10545
+ title.classList.add(`persona-tool-loading-${loadingAnimation}`);
10546
+ title.style.setProperty("--persona-tool-anim-duration", `${animDuration}ms`);
10547
+ if (loadingAnimation === "shimmer-color") {
10548
+ if (toolCallConfig.loadingAnimationColor) {
10549
+ title.style.setProperty("--persona-tool-anim-color", toolCallConfig.loadingAnimationColor);
10550
+ }
10551
+ if (toolCallConfig.loadingAnimationSecondaryColor) {
10552
+ title.style.setProperty("--persona-tool-anim-secondary-color", toolCallConfig.loadingAnimationSecondaryColor);
10553
+ }
10554
+ }
10555
+ if (currentTemplate) {
10556
+ renderFormattedTitle(currentTemplate, true);
10557
+ } else {
10558
+ const text = title.textContent || summary;
10559
+ title.textContent = "";
10560
+ appendCharSpans(title, text, 0);
10561
+ }
10562
+ }
10563
+ } else if (currentTemplate) {
10564
+ renderFormattedTitle(currentTemplate, false);
10565
+ }
10566
+ }
10416
10567
  let toggleIcon = null;
10417
10568
  if (expandable) {
10418
10569
  toggleIcon = createElement("div", "persona-flex persona-items-center");
@@ -10437,7 +10588,7 @@ var createToolBubble = (message, config) => {
10437
10588
  collapsedPreview.style.display = "none";
10438
10589
  collapsedPreview.style.whiteSpace = "pre-wrap";
10439
10590
  if (!expanded && isActive && toolDisplayConfig.activePreview && previewText) {
10440
- const renderedPreview = (_f = toolCallConfig.renderCollapsedPreview) == null ? void 0 : _f.call(toolCallConfig, {
10591
+ const renderedPreview = (_i = toolCallConfig.renderCollapsedPreview) == null ? void 0 : _i.call(toolCallConfig, {
10441
10592
  message,
10442
10593
  toolCall: tool,
10443
10594
  defaultPreview: previewText,
@@ -14830,8 +14981,9 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
14830
14981
  let scrollRAF = null;
14831
14982
  let isAutoScrolling = false;
14832
14983
  let hasPendingAutoScroll = false;
14833
- const USER_SCROLL_THRESHOLD = 1;
14834
- const BOTTOM_THRESHOLD = 8;
14984
+ const USER_SCROLL_THRESHOLD = 4;
14985
+ const BOTTOM_THRESHOLD = 24;
14986
+ const AUTO_SCROLL_SNAP_THRESHOLD = 80;
14835
14987
  const messageState = /* @__PURE__ */ new Map();
14836
14988
  const voiceState = {
14837
14989
  active: false,
@@ -14972,6 +15124,14 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
14972
15124
  lastScrollTop = element.scrollTop;
14973
15125
  return;
14974
15126
  }
15127
+ if (Math.abs(distance) >= AUTO_SCROLL_SNAP_THRESHOLD) {
15128
+ cancelSmoothScroll();
15129
+ isAutoScrolling = true;
15130
+ element.scrollTop = target;
15131
+ lastScrollTop = element.scrollTop;
15132
+ isAutoScrolling = false;
15133
+ return;
15134
+ }
14975
15135
  cancelSmoothScroll();
14976
15136
  const startTime = performance.now();
14977
15137
  isAutoScrolling = true;
@@ -15580,9 +15740,28 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
15580
15740
  }
15581
15741
  };
15582
15742
  }
15743
+ let toolElapsedTimerId = null;
15744
+ const ensureToolElapsedTimer = () => {
15745
+ if (toolElapsedTimerId != null) return;
15746
+ toolElapsedTimerId = setInterval(() => {
15747
+ const spans = messagesWrapper.querySelectorAll("[data-tool-elapsed]");
15748
+ if (spans.length === 0) {
15749
+ clearInterval(toolElapsedTimerId);
15750
+ toolElapsedTimerId = null;
15751
+ return;
15752
+ }
15753
+ const now = Date.now();
15754
+ spans.forEach((span) => {
15755
+ const startedAt = Number(span.getAttribute("data-tool-elapsed"));
15756
+ if (!startedAt) return;
15757
+ span.textContent = formatElapsedMs(now - startedAt);
15758
+ });
15759
+ }, 100);
15760
+ };
15583
15761
  session = new AgentWidgetSession(config, {
15584
15762
  onMessagesChanged(messages) {
15585
15763
  renderMessagesWithPlugins(messagesWrapper, messages, postprocess);
15764
+ ensureToolElapsedTimer();
15586
15765
  if (session) {
15587
15766
  const hasUserMessage = messages.some((msg) => msg.role === "user");
15588
15767
  if (hasUserMessage) {
@@ -17745,6 +17924,10 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
17745
17924
  return session.submitNPSFeedback(rating, comment);
17746
17925
  },
17747
17926
  destroy() {
17927
+ if (toolElapsedTimerId != null) {
17928
+ clearInterval(toolElapsedTimerId);
17929
+ toolElapsedTimerId = null;
17930
+ }
17748
17931
  destroyCallbacks.forEach((cb) => cb());
17749
17932
  wrapper.remove();
17750
17933
  launcherButtonInstance == null ? void 0 : launcherButtonInstance.destroy();
@@ -1126,6 +1126,13 @@ type AgentWidgetScrollToBottomFeature = {
1126
1126
  label?: string;
1127
1127
  };
1128
1128
  type AgentWidgetToolCallCollapsedMode = "tool-call" | "tool-name" | "tool-preview";
1129
+ /**
1130
+ * Animation mode applied to tool call header text while the tool is running.
1131
+ * Character-by-character modes (`shimmer`, `shimmer-color`, `rainbow`) wrap each
1132
+ * character in a span with staggered `animation-delay`. `pulse` applies to the
1133
+ * entire text container. Honors `prefers-reduced-motion`.
1134
+ */
1135
+ type AgentWidgetToolCallLoadingAnimation = "none" | "pulse" | "shimmer" | "shimmer-color" | "rainbow";
1129
1136
  type AgentWidgetToolCallDisplayFeature = {
1130
1137
  /**
1131
1138
  * Controls what collapsed tool call rows show in their header/summary area.
@@ -1139,6 +1146,8 @@ type AgentWidgetToolCallDisplayFeature = {
1139
1146
  activePreview?: boolean;
1140
1147
  /**
1141
1148
  * Optional CSS min-height applied to active collapsed tool call rows.
1149
+ * @default undefined (no min-height)
1150
+ * @example "100px"
1142
1151
  */
1143
1152
  activeMinHeight?: string;
1144
1153
  /**
@@ -1157,6 +1166,16 @@ type AgentWidgetToolCallDisplayFeature = {
1157
1166
  * @default true
1158
1167
  */
1159
1168
  expandable?: boolean;
1169
+ /**
1170
+ * Animation mode applied to the tool call header text while the tool is active.
1171
+ * - "none" — static text, no animation
1172
+ * - "pulse" — opacity pulse on the entire header text
1173
+ * - "shimmer" — monochrome opacity sweep per character
1174
+ * - "shimmer-color" — color gradient sweep per character
1175
+ * - "rainbow" — rainbow color cycle per character
1176
+ * @default "none"
1177
+ */
1178
+ loadingAnimation?: AgentWidgetToolCallLoadingAnimation;
1160
1179
  };
1161
1180
  type AgentWidgetReasoningDisplayFeature = {
1162
1181
  /**
@@ -1672,22 +1691,39 @@ type AgentWidgetApprovalConfig = {
1672
1691
  type AgentWidgetToolCallConfig$1 = {
1673
1692
  /** Box-shadow for tool-call bubbles; overrides `theme.toolBubbleShadow` when set. */
1674
1693
  shadow?: string;
1694
+ /** Background color of the tool call bubble container. */
1675
1695
  backgroundColor?: string;
1696
+ /** Border color of the tool call bubble container. */
1676
1697
  borderColor?: string;
1698
+ /** Border width of the tool call bubble container (CSS value, e.g. `"1px"`). */
1677
1699
  borderWidth?: string;
1700
+ /** Border radius of the tool call bubble container (CSS value, e.g. `"12px"`). */
1678
1701
  borderRadius?: string;
1702
+ /** Background color of the collapsed header row. */
1679
1703
  headerBackgroundColor?: string;
1704
+ /** Text color of the collapsed header row (tool name / summary). */
1680
1705
  headerTextColor?: string;
1706
+ /** Horizontal padding of the collapsed header row (CSS value). */
1681
1707
  headerPaddingX?: string;
1708
+ /** Vertical padding of the collapsed header row (CSS value). */
1682
1709
  headerPaddingY?: string;
1710
+ /** Background color of the expanded content area. */
1683
1711
  contentBackgroundColor?: string;
1712
+ /** Text color of the expanded content area. */
1684
1713
  contentTextColor?: string;
1714
+ /** Horizontal padding of the expanded content area (CSS value). */
1685
1715
  contentPaddingX?: string;
1716
+ /** Vertical padding of the expanded content area (CSS value). */
1686
1717
  contentPaddingY?: string;
1718
+ /** Background color of code blocks (arguments / result) in the expanded area. */
1687
1719
  codeBlockBackgroundColor?: string;
1720
+ /** Border color of code blocks in the expanded area. */
1688
1721
  codeBlockBorderColor?: string;
1722
+ /** Text color of code blocks in the expanded area. */
1689
1723
  codeBlockTextColor?: string;
1724
+ /** Color of the expand/collapse toggle icon. */
1690
1725
  toggleTextColor?: string;
1726
+ /** Color of section labels ("Arguments", "Result", "Activity") in the expanded area. */
1691
1727
  labelTextColor?: string;
1692
1728
  /**
1693
1729
  * Override the collapsed summary row content for a tool call bubble.
@@ -1701,6 +1737,14 @@ type AgentWidgetToolCallConfig$1 = {
1701
1737
  collapsedMode: AgentWidgetToolCallCollapsedMode;
1702
1738
  isActive: boolean;
1703
1739
  config: AgentWidgetConfig;
1740
+ /** Static elapsed time snapshot, e.g. "2.6s". */
1741
+ elapsed: string;
1742
+ /**
1743
+ * Returns a `<span>` whose text content is automatically updated every
1744
+ * 100ms by the widget's global timer. Place it anywhere in your returned
1745
+ * HTMLElement to get a live-ticking duration display.
1746
+ */
1747
+ createElapsedElement: () => HTMLElement;
1704
1748
  }) => HTMLElement | string | null;
1705
1749
  /**
1706
1750
  * Override the lightweight collapsed preview content shown for active tool rows.
@@ -1723,6 +1767,47 @@ type AgentWidgetToolCallConfig$1 = {
1723
1767
  defaultSummary: string;
1724
1768
  config: AgentWidgetConfig;
1725
1769
  }) => HTMLElement | string | null;
1770
+ /**
1771
+ * Template string for the header text while a tool call is active (running).
1772
+ *
1773
+ * **Placeholders:** `{toolName}` (tool name), `{duration}` (live-updating elapsed time).
1774
+ *
1775
+ * **Inline formatting:** `~dim~`, `*italic*`, `**bold**` — parsed at render time and
1776
+ * applied as styled `<span>` elements. Works with all animation modes.
1777
+ *
1778
+ * When not set, falls back to the current `collapsedMode` behavior.
1779
+ * @example "Calling {toolName}... ~{duration}~"
1780
+ * @example "**Searching** *{toolName}*..."
1781
+ */
1782
+ activeTextTemplate?: string;
1783
+ /**
1784
+ * Template string for the header text when a tool call is complete.
1785
+ *
1786
+ * **Placeholders:** `{toolName}` (tool name), `{duration}` (final elapsed time).
1787
+ *
1788
+ * **Inline formatting:** `~dim~`, `*italic*`, `**bold**` — same syntax as `activeTextTemplate`.
1789
+ *
1790
+ * When not set, falls back to the existing "Used tool for X seconds" text.
1791
+ * @example "Finished {toolName} ~{duration}~"
1792
+ */
1793
+ completeTextTemplate?: string;
1794
+ /**
1795
+ * Primary color for shimmer-color animation mode.
1796
+ * Defaults to the current text color.
1797
+ */
1798
+ loadingAnimationColor?: string;
1799
+ /**
1800
+ * Secondary/end color for shimmer-color animation mode.
1801
+ * Creates a gradient sweep between `loadingAnimationColor` and this color.
1802
+ * @default "#3b82f6"
1803
+ */
1804
+ loadingAnimationSecondaryColor?: string;
1805
+ /**
1806
+ * Duration of one full animation cycle in milliseconds.
1807
+ * Applies to pulse, shimmer, shimmer-color, and rainbow modes.
1808
+ * @default 2000
1809
+ */
1810
+ loadingAnimationDuration?: number;
1726
1811
  };
1727
1812
  type AgentWidgetReasoningConfig = {
1728
1813
  /**
@@ -1126,6 +1126,13 @@ type AgentWidgetScrollToBottomFeature = {
1126
1126
  label?: string;
1127
1127
  };
1128
1128
  type AgentWidgetToolCallCollapsedMode = "tool-call" | "tool-name" | "tool-preview";
1129
+ /**
1130
+ * Animation mode applied to tool call header text while the tool is running.
1131
+ * Character-by-character modes (`shimmer`, `shimmer-color`, `rainbow`) wrap each
1132
+ * character in a span with staggered `animation-delay`. `pulse` applies to the
1133
+ * entire text container. Honors `prefers-reduced-motion`.
1134
+ */
1135
+ type AgentWidgetToolCallLoadingAnimation = "none" | "pulse" | "shimmer" | "shimmer-color" | "rainbow";
1129
1136
  type AgentWidgetToolCallDisplayFeature = {
1130
1137
  /**
1131
1138
  * Controls what collapsed tool call rows show in their header/summary area.
@@ -1139,6 +1146,8 @@ type AgentWidgetToolCallDisplayFeature = {
1139
1146
  activePreview?: boolean;
1140
1147
  /**
1141
1148
  * Optional CSS min-height applied to active collapsed tool call rows.
1149
+ * @default undefined (no min-height)
1150
+ * @example "100px"
1142
1151
  */
1143
1152
  activeMinHeight?: string;
1144
1153
  /**
@@ -1157,6 +1166,16 @@ type AgentWidgetToolCallDisplayFeature = {
1157
1166
  * @default true
1158
1167
  */
1159
1168
  expandable?: boolean;
1169
+ /**
1170
+ * Animation mode applied to the tool call header text while the tool is active.
1171
+ * - "none" — static text, no animation
1172
+ * - "pulse" — opacity pulse on the entire header text
1173
+ * - "shimmer" — monochrome opacity sweep per character
1174
+ * - "shimmer-color" — color gradient sweep per character
1175
+ * - "rainbow" — rainbow color cycle per character
1176
+ * @default "none"
1177
+ */
1178
+ loadingAnimation?: AgentWidgetToolCallLoadingAnimation;
1160
1179
  };
1161
1180
  type AgentWidgetReasoningDisplayFeature = {
1162
1181
  /**
@@ -1672,22 +1691,39 @@ type AgentWidgetApprovalConfig = {
1672
1691
  type AgentWidgetToolCallConfig$1 = {
1673
1692
  /** Box-shadow for tool-call bubbles; overrides `theme.toolBubbleShadow` when set. */
1674
1693
  shadow?: string;
1694
+ /** Background color of the tool call bubble container. */
1675
1695
  backgroundColor?: string;
1696
+ /** Border color of the tool call bubble container. */
1676
1697
  borderColor?: string;
1698
+ /** Border width of the tool call bubble container (CSS value, e.g. `"1px"`). */
1677
1699
  borderWidth?: string;
1700
+ /** Border radius of the tool call bubble container (CSS value, e.g. `"12px"`). */
1678
1701
  borderRadius?: string;
1702
+ /** Background color of the collapsed header row. */
1679
1703
  headerBackgroundColor?: string;
1704
+ /** Text color of the collapsed header row (tool name / summary). */
1680
1705
  headerTextColor?: string;
1706
+ /** Horizontal padding of the collapsed header row (CSS value). */
1681
1707
  headerPaddingX?: string;
1708
+ /** Vertical padding of the collapsed header row (CSS value). */
1682
1709
  headerPaddingY?: string;
1710
+ /** Background color of the expanded content area. */
1683
1711
  contentBackgroundColor?: string;
1712
+ /** Text color of the expanded content area. */
1684
1713
  contentTextColor?: string;
1714
+ /** Horizontal padding of the expanded content area (CSS value). */
1685
1715
  contentPaddingX?: string;
1716
+ /** Vertical padding of the expanded content area (CSS value). */
1686
1717
  contentPaddingY?: string;
1718
+ /** Background color of code blocks (arguments / result) in the expanded area. */
1687
1719
  codeBlockBackgroundColor?: string;
1720
+ /** Border color of code blocks in the expanded area. */
1688
1721
  codeBlockBorderColor?: string;
1722
+ /** Text color of code blocks in the expanded area. */
1689
1723
  codeBlockTextColor?: string;
1724
+ /** Color of the expand/collapse toggle icon. */
1690
1725
  toggleTextColor?: string;
1726
+ /** Color of section labels ("Arguments", "Result", "Activity") in the expanded area. */
1691
1727
  labelTextColor?: string;
1692
1728
  /**
1693
1729
  * Override the collapsed summary row content for a tool call bubble.
@@ -1701,6 +1737,14 @@ type AgentWidgetToolCallConfig$1 = {
1701
1737
  collapsedMode: AgentWidgetToolCallCollapsedMode;
1702
1738
  isActive: boolean;
1703
1739
  config: AgentWidgetConfig;
1740
+ /** Static elapsed time snapshot, e.g. "2.6s". */
1741
+ elapsed: string;
1742
+ /**
1743
+ * Returns a `<span>` whose text content is automatically updated every
1744
+ * 100ms by the widget's global timer. Place it anywhere in your returned
1745
+ * HTMLElement to get a live-ticking duration display.
1746
+ */
1747
+ createElapsedElement: () => HTMLElement;
1704
1748
  }) => HTMLElement | string | null;
1705
1749
  /**
1706
1750
  * Override the lightweight collapsed preview content shown for active tool rows.
@@ -1723,6 +1767,47 @@ type AgentWidgetToolCallConfig$1 = {
1723
1767
  defaultSummary: string;
1724
1768
  config: AgentWidgetConfig;
1725
1769
  }) => HTMLElement | string | null;
1770
+ /**
1771
+ * Template string for the header text while a tool call is active (running).
1772
+ *
1773
+ * **Placeholders:** `{toolName}` (tool name), `{duration}` (live-updating elapsed time).
1774
+ *
1775
+ * **Inline formatting:** `~dim~`, `*italic*`, `**bold**` — parsed at render time and
1776
+ * applied as styled `<span>` elements. Works with all animation modes.
1777
+ *
1778
+ * When not set, falls back to the current `collapsedMode` behavior.
1779
+ * @example "Calling {toolName}... ~{duration}~"
1780
+ * @example "**Searching** *{toolName}*..."
1781
+ */
1782
+ activeTextTemplate?: string;
1783
+ /**
1784
+ * Template string for the header text when a tool call is complete.
1785
+ *
1786
+ * **Placeholders:** `{toolName}` (tool name), `{duration}` (final elapsed time).
1787
+ *
1788
+ * **Inline formatting:** `~dim~`, `*italic*`, `**bold**` — same syntax as `activeTextTemplate`.
1789
+ *
1790
+ * When not set, falls back to the existing "Used tool for X seconds" text.
1791
+ * @example "Finished {toolName} ~{duration}~"
1792
+ */
1793
+ completeTextTemplate?: string;
1794
+ /**
1795
+ * Primary color for shimmer-color animation mode.
1796
+ * Defaults to the current text color.
1797
+ */
1798
+ loadingAnimationColor?: string;
1799
+ /**
1800
+ * Secondary/end color for shimmer-color animation mode.
1801
+ * Creates a gradient sweep between `loadingAnimationColor` and this color.
1802
+ * @default "#3b82f6"
1803
+ */
1804
+ loadingAnimationSecondaryColor?: string;
1805
+ /**
1806
+ * Duration of one full animation cycle in milliseconds.
1807
+ * Applies to pulse, shimmer, shimmer-color, and rainbow modes.
1808
+ * @default 2000
1809
+ */
1810
+ loadingAnimationDuration?: number;
1726
1811
  };
1727
1812
  type AgentWidgetReasoningConfig = {
1728
1813
  /**