@runtypelabs/persona 4.23.2 → 4.24.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 (156) hide show
  1. package/dist/animations/glyph-cycle.d.cts +1 -1
  2. package/dist/animations/glyph-cycle.d.ts +1 -1
  3. package/dist/animations/{types-CI7OckWI.d.cts → types-Db61aI9J.d.cts} +2 -0
  4. package/dist/animations/{types-CI7OckWI.d.ts → types-Db61aI9J.d.ts} +2 -0
  5. package/dist/animations/wipe.d.cts +1 -1
  6. package/dist/animations/wipe.d.ts +1 -1
  7. package/dist/animations-extra.d.cts +2 -0
  8. package/dist/animations-extra.d.ts +2 -0
  9. package/dist/approval-ui-3NMYNXBD.js +1 -0
  10. package/dist/approval-ui.cjs +2 -2
  11. package/dist/approval-ui.d.cts +215 -37
  12. package/dist/approval-ui.d.ts +215 -37
  13. package/dist/approval-ui.js +2 -2
  14. package/dist/{artifacts-ui-F4N6VMKF.js → artifacts-ui-IGB5YKLO.js} +4 -4
  15. package/dist/artifacts-ui.d.cts +210 -25
  16. package/dist/artifacts-ui.d.ts +210 -25
  17. package/dist/{chunk-NIKYKSNZ.js → chunk-7CO4T5KB.js} +1 -1
  18. package/dist/codegen.cjs +11 -11
  19. package/dist/codegen.js +13 -13
  20. package/dist/context-mentions.d.cts +210 -25
  21. package/dist/context-mentions.d.ts +210 -25
  22. package/dist/event-stream-view.d.cts +210 -25
  23. package/dist/event-stream-view.d.ts +210 -25
  24. package/dist/forms-ui.d.cts +245 -27
  25. package/dist/forms-ui.d.ts +245 -27
  26. package/dist/history-view.d.cts +2 -0
  27. package/dist/history-view.d.ts +2 -0
  28. package/dist/index.cjs +70 -69
  29. package/dist/index.cjs.map +1 -1
  30. package/dist/index.d.cts +270 -39
  31. package/dist/index.d.ts +270 -39
  32. package/dist/index.global.js +57 -54
  33. package/dist/index.global.js.map +1 -1
  34. package/dist/index.js +70 -69
  35. package/dist/index.js.map +1 -1
  36. package/dist/install.global.js +1 -1
  37. package/dist/install.global.js.map +1 -1
  38. package/dist/launcher.global.js +2 -2
  39. package/dist/launcher.global.js.map +1 -1
  40. package/dist/session-reconnect.d.cts +210 -25
  41. package/dist/session-reconnect.d.ts +210 -25
  42. package/dist/smart-dom-reader.d.cts +210 -25
  43. package/dist/smart-dom-reader.d.ts +210 -25
  44. package/dist/theme-editor-preview.cjs +74 -73
  45. package/dist/theme-editor-preview.d.cts +217 -25
  46. package/dist/theme-editor-preview.d.ts +217 -25
  47. package/dist/theme-editor-preview.js +51 -50
  48. package/dist/theme-editor.cjs +10 -10
  49. package/dist/theme-editor.d.cts +230 -27
  50. package/dist/theme-editor.d.ts +230 -27
  51. package/dist/theme-editor.js +10 -10
  52. package/dist/theme-reference.cjs +1 -1
  53. package/dist/theme-reference.d.cts +1522 -11
  54. package/dist/theme-reference.d.ts +1522 -11
  55. package/dist/theme-reference.js +1 -1
  56. package/dist/widget.css +1 -1
  57. package/package.json +3 -2
  58. package/src/__fixtures__/defaults-parity.v4.json +776 -0
  59. package/src/approval-ui-entry.ts +0 -1
  60. package/src/approval-ui-loader.ts +5 -4
  61. package/src/approval-ui.ts +0 -1
  62. package/src/client-identity-proof.test.ts +193 -0
  63. package/src/client-session-warm.test.ts +216 -0
  64. package/src/client-visitor-history.test.ts +6 -0
  65. package/src/client.ts +122 -30
  66. package/src/codegen.test.ts +24 -0
  67. package/src/components/activity-row.test.ts +100 -0
  68. package/src/components/activity-row.ts +136 -0
  69. package/src/components/approval-actions.test.ts +8 -5
  70. package/src/components/approval-actions.ts +19 -6
  71. package/src/components/approval-bubble.test.ts +56 -9
  72. package/src/components/approval-bubble.ts +36 -41
  73. package/src/components/composer-builder.ts +5 -2
  74. package/src/components/composer-parts.ts +10 -2
  75. package/src/components/header-builder.test.ts +32 -0
  76. package/src/components/header-builder.ts +7 -4
  77. package/src/components/header-layouts.test.ts +12 -0
  78. package/src/components/header-layouts.ts +3 -2
  79. package/src/components/launcher.ts +11 -2
  80. package/src/components/message-bubble.test.ts +22 -0
  81. package/src/components/message-bubble.ts +7 -3
  82. package/src/components/panel.test.ts +52 -1
  83. package/src/components/panel.ts +47 -8
  84. package/src/components/pill-composer-builder.test.ts +2 -0
  85. package/src/components/pill-composer-builder.ts +0 -1
  86. package/src/components/reasoning-bubble.ts +29 -17
  87. package/src/components/suggestions.test.ts +1 -0
  88. package/src/components/suggestions.ts +0 -16
  89. package/src/components/tool-bubble.ts +131 -114
  90. package/src/components/tool-details.test.ts +87 -0
  91. package/src/components/tool-details.ts +102 -0
  92. package/src/components/welcome.test.ts +8 -0
  93. package/src/components/welcome.ts +4 -2
  94. package/src/defaults-parity.test.ts +158 -0
  95. package/src/defaults.test.ts +69 -0
  96. package/src/defaults.ts +128 -49
  97. package/src/generated/runtype-openapi-contract.ts +2 -2
  98. package/src/index-core.ts +2 -0
  99. package/src/install.test.ts +24 -0
  100. package/src/install.ts +3 -1
  101. package/src/launcher-global.ts +2 -1
  102. package/src/launcher-variants.test.ts +52 -0
  103. package/src/runtime/init-update-reset.test.ts +21 -0
  104. package/src/session.ts +29 -6
  105. package/src/styles/widget-styles.test.ts +19 -0
  106. package/src/styles/widget.css +295 -23
  107. package/src/theme-editor/index.ts +2 -0
  108. package/src/theme-editor/preview-utils.test.ts +8 -0
  109. package/src/theme-editor/preview-utils.ts +7 -3
  110. package/src/theme-editor/sections.test.ts +31 -0
  111. package/src/theme-editor/sections.ts +55 -1
  112. package/src/theme-editor/state-preferences.test.ts +49 -0
  113. package/src/theme-editor/state.ts +73 -15
  114. package/src/theme-reference.test.ts +20 -0
  115. package/src/theme-reference.ts +11 -5
  116. package/src/tool-call-display-defaults.test.ts +33 -1
  117. package/src/types/theme.ts +80 -3
  118. package/src/types.ts +136 -22
  119. package/src/ui.activity-row.test.ts +91 -0
  120. package/src/ui.approval-plugin.test.ts +63 -0
  121. package/src/ui.composer-compact.test.ts +24 -2
  122. package/src/ui.composer-placement.test.ts +23 -0
  123. package/src/ui.detached-panel.test.ts +33 -6
  124. package/src/ui.docked.test.ts +19 -0
  125. package/src/ui.header-update-stability.test.ts +25 -0
  126. package/src/ui.identity-proof.test.ts +58 -0
  127. package/src/ui.launcher-teaser.test.ts +25 -0
  128. package/src/ui.message-width.test.ts +17 -2
  129. package/src/ui.reasoning-display.test.ts +92 -0
  130. package/src/ui.rebuild-composer.test.ts +20 -3
  131. package/src/ui.scroll.test.ts +32 -0
  132. package/src/ui.session-init.test.ts +312 -0
  133. package/src/ui.status-indicator.test.ts +82 -0
  134. package/src/ui.suggest-replies.test.ts +11 -0
  135. package/src/ui.ts +363 -74
  136. package/src/ui.v5-defaults.test.ts +144 -0
  137. package/src/ui.welcome.test.ts +92 -3
  138. package/src/utils/__snapshots__/tokens-parity.test.ts.snap +811 -140
  139. package/src/utils/code-generators.ts +14 -0
  140. package/src/utils/composer-compact.test.ts +0 -2
  141. package/src/utils/composer-compact.ts +2 -4
  142. package/src/utils/composer-placement.ts +2 -3
  143. package/src/utils/config-merge.test.ts +81 -5
  144. package/src/utils/config-merge.ts +13 -3
  145. package/src/utils/defaults-provenance.ts +67 -0
  146. package/src/utils/dock.ts +7 -1
  147. package/src/utils/launcher-variant.ts +16 -0
  148. package/src/utils/panel-config.ts +97 -0
  149. package/src/utils/status-indicator.ts +39 -0
  150. package/src/utils/theme.test.ts +182 -0
  151. package/src/utils/theme.ts +131 -18
  152. package/src/utils/tokens.test.ts +122 -1
  153. package/src/utils/tokens.ts +177 -17
  154. package/src/welcome.test.ts +23 -0
  155. package/src/welcome.ts +16 -9
  156. package/dist/approval-ui-K7R5Q5OC.js +0 -1
@@ -1,10 +1,19 @@
1
1
  // @vitest-environment jsdom
2
2
 
3
3
  import { describe, expect, it } from "vitest";
4
- import { createWrapper } from "./panel";
4
+ import { buildPanel, createWrapper, resolvePanelGeometry } from "./panel";
5
+ import { mergeWithDefaults } from "../defaults";
5
6
  import type { AgentWidgetConfig } from "../types";
6
7
 
7
8
  describe("createWrapper: composer-bar mode", () => {
9
+ it.each([{ v5Defaults: false }, { v5Defaults: true }])(
10
+ "routes the transcript gap through the message token under v5Defaults=%s",
11
+ (future) => {
12
+ const { messagesWrapper } = buildPanel({ apiUrl: "/api", future } as AgentWidgetConfig);
13
+ expect(messagesWrapper.style.gap).toBe("var(--persona-components-message-gap, 12px)");
14
+ }
15
+ );
16
+
8
17
  it("marks the wrapper with composer-bar data-attrs and leaves geometry to updateOpenState", () => {
9
18
  const config: AgentWidgetConfig = {
10
19
  apiUrl: "/api",
@@ -59,3 +68,45 @@ describe("createWrapper: composer-bar mode", () => {
59
68
  expect(wrapper.hasAttribute("data-persona-composer-bar")).toBe(false);
60
69
  });
61
70
  });
71
+
72
+ describe.each([false, true])("resolvePanelGeometry (v5=%s)", (v5Defaults) => {
73
+ it("uses panel token variables when no legacy width alias was supplied", () => {
74
+ const config = mergeWithDefaults({ apiUrl: "/api", future: { v5Defaults } }) as AgentWidgetConfig;
75
+ expect(resolvePanelGeometry(config)).toMatchObject({
76
+ width: "var(--persona-components-panel-width)",
77
+ maxWidth: "var(--persona-components-panel-maxWidth)",
78
+ height: "max(200px, var(--persona-components-panel-height))",
79
+ maxHeight: "var(--persona-components-panel-maxHeight)",
80
+ });
81
+ });
82
+
83
+ it("keeps an explicit launcher width ahead of panel tokens", () => {
84
+ const config = mergeWithDefaults({
85
+ apiUrl: "/api",
86
+ future: { v5Defaults },
87
+ launcher: { width: "600px" },
88
+ theme: { components: { panel: { width: "320px", maxWidth: "320px" } } },
89
+ }) as AgentWidgetConfig;
90
+ expect(resolvePanelGeometry(config)).toMatchObject({ width: "600px", maxWidth: "600px" });
91
+ });
92
+
93
+ it("applies heightOffset regardless of which width source wins", () => {
94
+ const config = mergeWithDefaults({
95
+ apiUrl: "/api",
96
+ future: { v5Defaults },
97
+ launcher: { width: "600px", heightOffset: 24 },
98
+ }) as AgentWidgetConfig;
99
+ expect(resolvePanelGeometry(config).height).toBe(
100
+ "max(200px, calc(var(--persona-components-panel-height) - 24px))"
101
+ );
102
+ });
103
+ });
104
+
105
+ describe.each([false, true])('inline width (V5=%s)', v5Defaults => {
106
+ it('fills the host with inherited defaults and honors explicit widths', () => {
107
+ const config = { future: { v5Defaults }, launcher: { enabled: false } };
108
+ expect(createWrapper(mergeWithDefaults(config)).wrapper.style.width).toBe('100%');
109
+ expect(createWrapper(mergeWithDefaults({ ...config, launcher: { enabled: false, width: '600px' } })).wrapper.style.width).toBe('600px');
110
+ expect(createWrapper(mergeWithDefaults({ ...config, theme: { components: { panel: { width: '700px' } } } })).wrapper.style.width).toBe('var(--persona-components-panel-width)');
111
+ });
112
+ });
@@ -1,5 +1,4 @@
1
1
  import { createElement, createNode } from "../utils/dom";
2
- import { DEFAULT_FLOATING_LAUNCHER_WIDTH } from "../defaults";
3
2
  import { AgentWidgetConfig, AgentWidgetSuggestionSurface } from "../types";
4
3
  import { suggestionSurfaceAttr } from "./suggestions";
5
4
  import { positionMap } from "../utils/positioning";
@@ -20,6 +19,42 @@ import {
20
19
  } from "./welcome";
21
20
  import { isWelcomeVisible, resolveWelcomeConfig } from "../welcome";
22
21
  import { resolveContentMaxWidth } from "../utils/content-width";
22
+ import { getPanelAliasProvenance, PANEL_WIDTH_VAR } from "../utils/panel-config";
23
+
24
+ const PANEL_MAX_WIDTH_VAR = "var(--persona-components-panel-maxWidth)";
25
+ const PANEL_HEIGHT_VAR = "var(--persona-components-panel-height)";
26
+ const PANEL_MAX_HEIGHT_VAR = "var(--persona-components-panel-maxHeight)";
27
+
28
+ export type PanelGeometry = {
29
+ width: string;
30
+ maxWidth: string;
31
+ height: string;
32
+ maxHeight: string;
33
+ };
34
+
35
+ /**
36
+ * Legacy aliases win when a caller explicitly supplied them; otherwise the
37
+ * resolved panel token variables own geometry. Provenance keeps a materialized
38
+ * launcher default from masquerading as a legacy override after config merge.
39
+ */
40
+ export const resolvePanelGeometry = (config?: AgentWidgetConfig): PanelGeometry => {
41
+ const aliases = getPanelAliasProvenance(config);
42
+ const legacyWidth = aliases.launcherWidth
43
+ ? config?.launcher?.width
44
+ : aliases.legacyLauncherWidth
45
+ ? config?.launcherWidth
46
+ : undefined;
47
+ const heightOffset = config?.launcher?.heightOffset ?? 0;
48
+ const height = heightOffset === 0
49
+ ? `max(200px, ${PANEL_HEIGHT_VAR})`
50
+ : `max(200px, calc(${PANEL_HEIGHT_VAR} - ${heightOffset}px))`;
51
+ return {
52
+ width: legacyWidth ?? PANEL_WIDTH_VAR,
53
+ maxWidth: legacyWidth ?? PANEL_MAX_WIDTH_VAR,
54
+ height,
55
+ maxHeight: PANEL_MAX_HEIGHT_VAR,
56
+ };
57
+ };
23
58
 
24
59
  /**
25
60
  * Composer-bar chrome sizes. Not header controls: these float over the
@@ -116,7 +151,10 @@ export const createWrapper = (config?: AgentWidgetConfig): PanelWrapper => {
116
151
  );
117
152
 
118
153
  // Apply width from config, defaulting to 100% for inline embed mode
119
- const inlineWidth = config?.launcher?.width ?? "100%";
154
+ const aliases = getPanelAliasProvenance(config);
155
+ const hasWidth = aliases.launcherWidth || aliases.legacyLauncherWidth ||
156
+ config?.theme?.components?.panel?.width !== undefined;
157
+ const inlineWidth = hasWidth ? resolvePanelGeometry(config).width : "100%";
120
158
  wrapper.style.width = inlineWidth;
121
159
  panel.style.width = "100%";
122
160
 
@@ -140,10 +178,9 @@ export const createWrapper = (config?: AgentWidgetConfig): PanelWrapper => {
140
178
  "div",
141
179
  "persona-widget-panel persona-relative persona-min-h-[320px]"
142
180
  );
143
- const launcherWidth = config?.launcher?.width ?? config?.launcherWidth;
144
- const width = launcherWidth ?? DEFAULT_FLOATING_LAUNCHER_WIDTH;
145
- panel.style.width = width;
146
- panel.style.maxWidth = width;
181
+ const geometry = resolvePanelGeometry(config);
182
+ panel.style.width = geometry.width;
183
+ panel.style.maxWidth = geometry.maxWidth;
147
184
 
148
185
  wrapper.appendChild(panel);
149
186
  return { wrapper, panel };
@@ -339,8 +376,9 @@ const buildComposerBarPanel = (
339
376
 
340
377
  const messagesWrapper = createElement(
341
378
  "div",
342
- "persona-widget-messages persona-flex persona-flex-col persona-gap-3"
379
+ "persona-widget-messages persona-flex persona-flex-col"
343
380
  );
381
+ messagesWrapper.style.gap = "var(--persona-components-message-gap, 12px)";
344
382
  const transcriptSuggestions = createSuggestionHost("followUp");
345
383
  const contentMaxWidth = resolveContentMaxWidth(config, true);
346
384
  if (contentMaxWidth) {
@@ -471,8 +509,9 @@ export const buildPanel = (config?: AgentWidgetConfig, showClose = true): PanelE
471
509
 
472
510
  const messagesWrapper = createElement(
473
511
  "div",
474
- "persona-widget-messages persona-flex persona-flex-col persona-gap-3"
512
+ "persona-widget-messages persona-flex persona-flex-col"
475
513
  );
514
+ messagesWrapper.style.gap = "var(--persona-components-message-gap, 12px)";
476
515
  const transcriptSuggestions = createSuggestionHost("followUp");
477
516
 
478
517
  const contentMaxWidth = resolveContentMaxWidth(config, false);
@@ -22,6 +22,8 @@ describe("buildPillComposer (single-row pill composer)", () => {
22
22
  expect(elements.composerForm.classList.contains("persona-rounded-2xl")).toBe(false);
23
23
 
24
24
  expect(elements.composerForm.getAttribute("data-persona-composer-form")).toBe("");
25
+ // The shared focusRing token must not be suppressed by an inline outline.
26
+ expect(elements.composerForm.style.outline).toBe("");
25
27
  expect(elements.textarea.getAttribute("data-persona-composer-input")).toBe("");
26
28
  expect(elements.sendButton.getAttribute("data-persona-composer-submit")).toBe("");
27
29
  });
@@ -115,7 +115,6 @@ export const buildPillComposer = (context: ComposerBuildContext): ComposerElemen
115
115
  const composerForm = createNode("form", {
116
116
  className: "persona-widget-composer persona-pill-composer",
117
117
  attrs: { "data-persona-composer-form": "" },
118
- style: { outline: "none" },
119
118
  });
120
119
 
121
120
  // Three columns of the grid: [paperclip?] · textarea · mic + send.
@@ -1,6 +1,8 @@
1
+ import { applyActivityRow, activityDisplay, activityVariant, activityDuration } from "./activity-row";
1
2
  import { createElement } from "../utils/dom";
2
3
  import { renderLucideIcon } from "../utils/icons";
3
4
  import { AgentWidgetConfig, AgentWidgetMessage } from "../types";
5
+ import { DEFAULT_REASONING_DISPLAY } from "../defaults";
4
6
  import { describeReasonStatus, computeReasoningElapsed, parseFormattedTemplate } from "../utils/formatting";
5
7
  import { appendCharSpans } from "../utils/tool-loading-animation";
6
8
  import {
@@ -12,9 +14,6 @@ import {
12
14
  updateExpandableBubbleUI,
13
15
  } from "./expandable-bubble";
14
16
 
15
- // Expansion state per widget instance
16
- export const reasoningExpansionState = new Set<string>();
17
-
18
17
  const getReasoningPreviewText = (message: AgentWidgetMessage, maxLines: number): string => {
19
18
  const text = message.reasoning?.chunks.join("").trim() ?? "";
20
19
  if (!text) return "";
@@ -27,32 +26,45 @@ const getReasoningPreviewText = (message: AgentWidgetMessage, maxLines: number):
27
26
  };
28
27
 
29
28
  // Helper function to update reasoning bubble UI after expansion state changes
30
- export const updateReasoningBubbleUI = (messageId: string, bubble: HTMLElement): void => {
29
+ export const updateReasoningBubbleUI = (
30
+ messageId: string,
31
+ bubble: HTMLElement,
32
+ expansionState: Set<string>
33
+ ): void => {
31
34
  updateExpandableBubbleUI(messageId, bubble, {
32
- stateSet: reasoningExpansionState,
35
+ stateSet: expansionState,
33
36
  previewKind: "reasoning",
34
37
  iconColor: "currentColor",
35
38
  });
36
39
  };
37
40
 
38
- export const createReasoningBubble = (message: AgentWidgetMessage, config?: AgentWidgetConfig): HTMLElement => {
41
+ export const createReasoningBubble = (
42
+ message: AgentWidgetMessage,
43
+ config?: AgentWidgetConfig,
44
+ expansionState = new Set<string>()
45
+ ): HTMLElement => {
46
+ config = activityDisplay(config, "reasoning");
39
47
  const reasoning = message.reasoning;
40
48
  const bubble = createExpandableBubbleShell("persona-reasoning-bubble", message.id);
41
49
 
42
50
  if (!reasoning) {
43
- return bubble;
51
+ return applyActivityRow(bubble, message, config, "reasoning");
44
52
  }
45
53
 
46
54
  const reasoningDisplayConfig = config?.features?.reasoningDisplay ?? {};
47
- const expandable = reasoningDisplayConfig.expandable !== false;
48
- const expanded = expandable && reasoningExpansionState.has(message.id);
55
+ const expandable = reasoningDisplayConfig.expandable ?? DEFAULT_REASONING_DISPLAY.expandable;
56
+ const expanded = expandable && expansionState.has(message.id);
49
57
  const isActive = reasoning.status !== "complete";
50
- const previewText = getReasoningPreviewText(message, reasoningDisplayConfig.previewMaxLines ?? 3);
58
+ const previewText = getReasoningPreviewText(
59
+ message,
60
+ reasoningDisplayConfig.previewMaxLines ?? DEFAULT_REASONING_DISPLAY.previewMaxLines
61
+ );
51
62
  const header = createExpandableHeader({ expandable, expanded, bubbleType: "reasoning" });
52
63
 
53
64
  const headerContent = createElement("div", "persona-flex persona-flex-col persona-text-left");
54
65
  const title = createElement("span", "persona-text-xs persona-text-persona-primary");
55
- const defaultSummary = "Thinking...";
66
+ const row = activityVariant(config, "reasoning") === "row";
67
+ const defaultSummary = row && !isActive ? `Thought for ${activityDuration(reasoning.durationMs ?? (reasoning.completedAt !== undefined && reasoning.startedAt !== undefined ? reasoning.completedAt - reasoning.startedAt : undefined))}` : "Thinking...";
56
68
  const reasoningConfig = config?.reasoning ?? {};
57
69
 
58
70
  // Elapsed helpers: defined early so they're available to renderCollapsedSummary
@@ -88,10 +100,10 @@ export const createReasoningBubble = (message: AgentWidgetMessage, config?: Agen
88
100
  // Status span: used in the legacy (no-template) path
89
101
  const status = createElement("span", "persona-text-xs persona-text-persona-primary");
90
102
  status.textContent = describeReasonStatus(reasoning);
91
- headerContent.appendChild(status);
103
+ if (!row) headerContent.appendChild(status);
92
104
 
93
105
  // Template and animation support
94
- const loadingAnimation = reasoningDisplayConfig.loadingAnimation ?? "none";
106
+ const loadingAnimation = reasoningDisplayConfig.loadingAnimation ?? DEFAULT_REASONING_DISPLAY.loadingAnimation;
95
107
  const activeTemplate = reasoningConfig.activeTextTemplate;
96
108
  const completeTemplate = reasoningConfig.completeTextTemplate;
97
109
  const currentTemplate = isActive ? activeTemplate : completeTemplate;
@@ -190,12 +202,12 @@ export const createReasoningBubble = (message: AgentWidgetMessage, config?: Agen
190
202
  }
191
203
 
192
204
  // Legacy: hide title on complete, show status
193
- if (reasoning.status === "complete") {
205
+ if (reasoning.status === "complete" && !row) {
194
206
  title.style.display = "none";
195
207
  }
196
208
  } else if (!skipCustomElement) {
197
209
  // Legacy path: no template, no animation
198
- if (reasoning.status === "complete") {
210
+ if (reasoning.status === "complete" && !row) {
199
211
  title.style.display = "none";
200
212
  } else {
201
213
  title.style.display = "";
@@ -246,7 +258,7 @@ export const createReasoningBubble = (message: AgentWidgetMessage, config?: Agen
246
258
 
247
259
  if (!expandable) {
248
260
  bubble.append(header, collapsedPreview);
249
- return bubble;
261
+ return applyActivityRow(bubble, message, config, "reasoning");
250
262
  }
251
263
 
252
264
  const content = createElement(
@@ -270,5 +282,5 @@ export const createReasoningBubble = (message: AgentWidgetMessage, config?: Agen
270
282
  applyExpansionDisplay({ expanded, header, toggleIcon, content, collapsedPreview, iconColor });
271
283
 
272
284
  bubble.append(header, collapsedPreview, content);
273
- return bubble;
285
+ return applyActivityRow(bubble, message, config, "reasoning");
274
286
  };
@@ -257,6 +257,7 @@ describe("legacy suggestionChipsConfig scoping", () => {
257
257
  expect(button.style.paddingLeft).toBe("12px");
258
258
  expect(button.style.paddingTop).toBe("6px");
259
259
  expect(button.style.fontWeight).toBe("500");
260
+ expect(button.style.fontFamily).toBe("");
260
261
  });
261
262
 
262
263
  it("does not let chip config override card and list padding tokens", () => {
@@ -97,19 +97,6 @@ export const normalizeSuggestion = (
97
97
  };
98
98
  };
99
99
 
100
- const fontFamilyValue = (
101
- family: "sans-serif" | "serif" | "mono"
102
- ): string => {
103
- switch (family) {
104
- case "serif":
105
- return 'Georgia, "Times New Roman", Times, serif';
106
- case "mono":
107
- return '"Courier New", Courier, "Lucida Console", Monaco, monospace';
108
- default:
109
- return '-apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Arial, sans-serif';
110
- }
111
- };
112
-
113
100
  // Module-level, keyed on the widget config: one widget owns several suggestion
114
101
  // managers, so a per-instance flag hints once per surface instead of once.
115
102
  const hintedOverflowVariant = new WeakSet<AgentWidgetConfig>();
@@ -264,9 +251,6 @@ export const createSuggestionElement = (
264
251
  // Legacy `suggestionChipsConfig` compat is chip-only: its inline
265
252
  // styles would otherwise override the card/list padding tokens.
266
253
  if (variant === "chip") {
267
- if (chipsConfig?.fontFamily) {
268
- button.style.fontFamily = fontFamilyValue(chipsConfig.fontFamily);
269
- }
270
254
  if (chipsConfig?.fontWeight) {
271
255
  button.style.fontWeight = chipsConfig.fontWeight;
272
256
  }