vanilla-agent 0.1.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/ui.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { escapeHtml } from "./postprocessors";
2
- import { ChatWidgetSession, ChatWidgetSessionStatus } from "./session";
3
- import { ChatWidgetConfig, ChatWidgetMessage } from "./types";
2
+ import { AgentWidgetSession, AgentWidgetSessionStatus } from "./session";
3
+ import { AgentWidgetConfig, AgentWidgetMessage } from "./types";
4
4
  import { applyThemeVariables } from "./utils/theme";
5
5
  import { renderLucideIcon } from "./utils/icons";
6
6
  import { createElement } from "./utils/dom";
@@ -14,16 +14,18 @@ import { createToolBubble } from "./components/tool-bubble";
14
14
  import { createSuggestions } from "./components/suggestions";
15
15
  import { enhanceWithForms } from "./components/forms";
16
16
  import { pluginRegistry } from "./plugins/registry";
17
+ import { mergeWithDefaults } from "./defaults";
17
18
 
18
19
  type Controller = {
19
- update: (config: ChatWidgetConfig) => void;
20
+ update: (config: AgentWidgetConfig) => void;
20
21
  destroy: () => void;
21
22
  open: () => void;
22
23
  close: () => void;
23
24
  toggle: () => void;
25
+ clearChat: () => void;
24
26
  };
25
27
 
26
- const buildPostprocessor = (cfg?: ChatWidgetConfig): MessageTransform => {
28
+ const buildPostprocessor = (cfg?: AgentWidgetConfig): MessageTransform => {
27
29
  if (cfg?.postprocessMessage) {
28
30
  return (context) =>
29
31
  cfg.postprocessMessage!({
@@ -35,16 +37,16 @@ const buildPostprocessor = (cfg?: ChatWidgetConfig): MessageTransform => {
35
37
  return ({ text }) => escapeHtml(text);
36
38
  };
37
39
 
38
- export const createChatExperience = (
40
+ export const createAgentExperience = (
39
41
  mount: HTMLElement,
40
- initialConfig?: ChatWidgetConfig
42
+ initialConfig?: AgentWidgetConfig
41
43
  ): Controller => {
42
44
  // Tailwind config uses important: "#vanilla-agent-root", so ensure mount has this ID
43
45
  if (!mount.id || mount.id !== "vanilla-agent-root") {
44
46
  mount.id = "vanilla-agent-root";
45
47
  }
46
48
 
47
- let config = { ...initialConfig };
49
+ let config = mergeWithDefaults(initialConfig) as AgentWidgetConfig;
48
50
  applyThemeVariables(mount, config);
49
51
 
50
52
  // Get plugins for this instance
@@ -61,7 +63,7 @@ export const createChatExperience = (
61
63
 
62
64
  // Get status indicator config
63
65
  const statusConfig = config.statusIndicator ?? {};
64
- const getStatusText = (status: ChatWidgetSessionStatus): string => {
66
+ const getStatusText = (status: AgentWidgetSessionStatus): string => {
65
67
  if (status === "idle") return statusConfig.idleText ?? statusCopy.idle;
66
68
  if (status === "connecting") return statusConfig.connectingText ?? statusCopy.connecting;
67
69
  if (status === "connected") return statusConfig.connectedText ?? statusCopy.connected;
@@ -97,7 +99,7 @@ export const createChatExperience = (
97
99
  const destroyCallbacks: Array<() => void> = [];
98
100
  const suggestionsManager = createSuggestions(suggestions);
99
101
  let closeHandler: (() => void) | null = null;
100
- let session: ChatWidgetSession;
102
+ let session: AgentWidgetSession;
101
103
  let isStreaming = false;
102
104
  let shouldAutoScroll = true;
103
105
  let lastScrollTop = 0;
@@ -178,7 +180,7 @@ export const createChatExperience = (
178
180
  // Message rendering with plugin support
179
181
  const renderMessagesWithPlugins = (
180
182
  container: HTMLElement,
181
- messages: ChatWidgetMessage[],
183
+ messages: AgentWidgetMessage[],
182
184
  transform: MessageTransform
183
185
  ) => {
184
186
  container.innerHTML = "";
@@ -259,9 +261,28 @@ export const createChatExperience = (
259
261
  // Add typing indicator if streaming and there's at least one user message
260
262
  if (isStreaming && messages.some((msg) => msg.role === "user")) {
261
263
  const typingIndicator = createTypingIndicator();
264
+
265
+ // Create a bubble wrapper for the typing indicator (similar to assistant messages)
266
+ const typingBubble = document.createElement("div");
267
+ typingBubble.className = [
268
+ "tvw-max-w-[85%]",
269
+ "tvw-rounded-2xl",
270
+ "tvw-text-sm",
271
+ "tvw-leading-relaxed",
272
+ "tvw-shadow-sm",
273
+ "tvw-bg-cw-surface",
274
+ "tvw-border",
275
+ "tvw-border-cw-message-border",
276
+ "tvw-text-cw-primary",
277
+ "tvw-px-5",
278
+ "tvw-py-3"
279
+ ].join(" ");
280
+
281
+ typingBubble.appendChild(typingIndicator);
282
+
262
283
  const typingWrapper = document.createElement("div");
263
- typingWrapper.className = "tvw-flex tvw-justify-end";
264
- typingWrapper.appendChild(typingIndicator);
284
+ typingWrapper.className = "tvw-flex";
285
+ typingWrapper.appendChild(typingBubble);
265
286
  fragment.appendChild(typingWrapper);
266
287
  }
267
288
 
@@ -317,9 +338,14 @@ export const createChatExperience = (
317
338
  introSubtitle.textContent =
318
339
  config.copy?.welcomeSubtitle ??
319
340
  "Ask anything about your account or products.";
320
- textarea.placeholder = config.copy?.inputPlaceholder ?? "Type your message…";
321
- sendButton.textContent = config.copy?.sendButtonLabel ?? "Send";
322
-
341
+ textarea.placeholder = config.copy?.inputPlaceholder ?? "How can I help...";
342
+
343
+ // Only update send button text if NOT using icon mode
344
+ const useIcon = config.sendButton?.useIcon ?? false;
345
+ if (!useIcon) {
346
+ sendButton.textContent = config.copy?.sendButtonLabel ?? "Send";
347
+ }
348
+
323
349
  // Update textarea font family and weight
324
350
  const fontFamily = config.theme?.inputFontFamily ?? "sans-serif";
325
351
  const fontWeight = config.theme?.inputFontWeight ?? "400";
@@ -340,7 +366,7 @@ export const createChatExperience = (
340
366
  textarea.style.fontWeight = fontWeight;
341
367
  };
342
368
 
343
- session = new ChatWidgetSession(config, {
369
+ session = new AgentWidgetSession(config, {
344
370
  onMessagesChanged(messages) {
345
371
  renderMessagesWithPlugins(messagesWrapper, messages, postprocess);
346
372
  // Re-render suggestions to hide them after first user message
@@ -359,7 +385,7 @@ export const createChatExperience = (
359
385
  },
360
386
  onStatusChanged(status) {
361
387
  const currentStatusConfig = config.statusIndicator ?? {};
362
- const getCurrentStatusText = (status: ChatWidgetSessionStatus): string => {
388
+ const getCurrentStatusText = (status: AgentWidgetSessionStatus): string => {
363
389
  if (status === "idle") return currentStatusConfig.idleText ?? statusCopy.idle;
364
390
  if (status === "connecting") return currentStatusConfig.connectingText ?? statusCopy.connecting;
365
391
  if (status === "connected") return currentStatusConfig.connectedText ?? statusCopy.connected;
@@ -568,7 +594,7 @@ export const createChatExperience = (
568
594
  };
569
595
 
570
596
  // Function to create mic button dynamically
571
- const createMicButton = (voiceConfig: ChatWidgetConfig['voiceRecognition'], sendButtonConfig: ChatWidgetConfig['sendButton']): { micButton: HTMLButtonElement; micButtonWrapper: HTMLElement } | null => {
597
+ const createMicButton = (voiceConfig: AgentWidgetConfig['voiceRecognition'], sendButtonConfig: AgentWidgetConfig['sendButton']): { micButton: HTMLButtonElement; micButtonWrapper: HTMLElement } | null => {
572
598
  const hasSpeechRecognition =
573
599
  typeof window !== 'undefined' &&
574
600
  (typeof (window as any).webkitSpeechRecognition !== 'undefined' ||
@@ -711,7 +737,7 @@ export const createChatExperience = (
711
737
  return;
712
738
  }
713
739
  const launcherWidth = config?.launcher?.width ?? config?.launcherWidth;
714
- const width = launcherWidth ?? "min(360px, calc(100vw - 24px))";
740
+ const width = launcherWidth ?? "min(400px, calc(100vw - 24px))";
715
741
  panel.style.width = width;
716
742
  panel.style.maxWidth = width;
717
743
  const viewportHeight = window.innerHeight;
@@ -777,6 +803,25 @@ export const createChatExperience = (
777
803
 
778
804
  refreshCloseButton();
779
805
 
806
+ // Setup clear chat button click handler
807
+ const setupClearChatButton = () => {
808
+ const { clearChatButton } = panelElements;
809
+ if (!clearChatButton) return;
810
+
811
+ clearChatButton.addEventListener("click", () => {
812
+ // Clear messages in session (this will trigger onMessagesChanged which re-renders)
813
+ session.clearMessages();
814
+
815
+ // Dispatch custom event for external handlers (e.g., localStorage clearing in examples)
816
+ const clearEvent = new CustomEvent("vanilla-agent:clear-chat", {
817
+ detail: { timestamp: new Date().toISOString() }
818
+ });
819
+ window.dispatchEvent(clearEvent);
820
+ });
821
+ };
822
+
823
+ setupClearChatButton();
824
+
780
825
  composerForm.addEventListener("submit", handleSubmit);
781
826
  textarea.addEventListener("keydown", handleInputEnter);
782
827
 
@@ -796,7 +841,7 @@ export const createChatExperience = (
796
841
  }
797
842
 
798
843
  return {
799
- update(nextConfig: ChatWidgetConfig) {
844
+ update(nextConfig: AgentWidgetConfig) {
800
845
  config = { ...config, ...nextConfig };
801
846
  applyThemeVariables(mount, config);
802
847
 
@@ -995,6 +1040,259 @@ export const createChatExperience = (
995
1040
  closeButton.style.borderRadius = "";
996
1041
  closeButton.classList.add("tvw-rounded-full");
997
1042
  }
1043
+
1044
+ // Update padding
1045
+ if (launcher.closeButtonPaddingX) {
1046
+ closeButton.style.paddingLeft = launcher.closeButtonPaddingX;
1047
+ closeButton.style.paddingRight = launcher.closeButtonPaddingX;
1048
+ } else {
1049
+ closeButton.style.paddingLeft = "";
1050
+ closeButton.style.paddingRight = "";
1051
+ }
1052
+ if (launcher.closeButtonPaddingY) {
1053
+ closeButton.style.paddingTop = launcher.closeButtonPaddingY;
1054
+ closeButton.style.paddingBottom = launcher.closeButtonPaddingY;
1055
+ } else {
1056
+ closeButton.style.paddingTop = "";
1057
+ closeButton.style.paddingBottom = "";
1058
+ }
1059
+
1060
+ // Update icon
1061
+ const closeButtonIconName = launcher.closeButtonIconName ?? "x";
1062
+ const closeButtonIconText = launcher.closeButtonIconText ?? "×";
1063
+
1064
+ // Clear existing content and render new icon
1065
+ closeButton.innerHTML = "";
1066
+ const iconSvg = renderLucideIcon(closeButtonIconName, "20px", launcher.closeButtonColor || "", 2);
1067
+ if (iconSvg) {
1068
+ closeButton.appendChild(iconSvg);
1069
+ } else {
1070
+ closeButton.textContent = closeButtonIconText;
1071
+ }
1072
+
1073
+ // Update tooltip
1074
+ const { closeButtonWrapper } = panelElements;
1075
+ const closeButtonTooltipText = launcher.closeButtonTooltipText ?? "Close chat";
1076
+ const closeButtonShowTooltip = launcher.closeButtonShowTooltip ?? true;
1077
+
1078
+ closeButton.setAttribute("aria-label", closeButtonTooltipText);
1079
+
1080
+ if (closeButtonWrapper) {
1081
+ // Clean up old tooltip event listeners if they exist
1082
+ if ((closeButtonWrapper as any)._cleanupTooltip) {
1083
+ (closeButtonWrapper as any)._cleanupTooltip();
1084
+ delete (closeButtonWrapper as any)._cleanupTooltip;
1085
+ }
1086
+
1087
+ // Set up new portaled tooltip with event listeners
1088
+ if (closeButtonShowTooltip && closeButtonTooltipText) {
1089
+ let portaledTooltip: HTMLElement | null = null;
1090
+
1091
+ const showTooltip = () => {
1092
+ if (portaledTooltip || !closeButton) return; // Already showing or button doesn't exist
1093
+
1094
+ // Create tooltip element
1095
+ portaledTooltip = createElement("div", "tvw-clear-chat-tooltip");
1096
+ portaledTooltip.textContent = closeButtonTooltipText;
1097
+
1098
+ // Add arrow
1099
+ const arrow = createElement("div");
1100
+ arrow.className = "tvw-clear-chat-tooltip-arrow";
1101
+ portaledTooltip.appendChild(arrow);
1102
+
1103
+ // Get button position
1104
+ const buttonRect = closeButton.getBoundingClientRect();
1105
+
1106
+ // Position tooltip above button
1107
+ portaledTooltip.style.position = "fixed";
1108
+ portaledTooltip.style.left = `${buttonRect.left + buttonRect.width / 2}px`;
1109
+ portaledTooltip.style.top = `${buttonRect.top - 8}px`;
1110
+ portaledTooltip.style.transform = "translate(-50%, -100%)";
1111
+
1112
+ // Append to body
1113
+ document.body.appendChild(portaledTooltip);
1114
+ };
1115
+
1116
+ const hideTooltip = () => {
1117
+ if (portaledTooltip && portaledTooltip.parentNode) {
1118
+ portaledTooltip.parentNode.removeChild(portaledTooltip);
1119
+ portaledTooltip = null;
1120
+ }
1121
+ };
1122
+
1123
+ // Add event listeners
1124
+ closeButtonWrapper.addEventListener("mouseenter", showTooltip);
1125
+ closeButtonWrapper.addEventListener("mouseleave", hideTooltip);
1126
+ closeButton.addEventListener("focus", showTooltip);
1127
+ closeButton.addEventListener("blur", hideTooltip);
1128
+
1129
+ // Store cleanup function on the wrapper for later use
1130
+ (closeButtonWrapper as any)._cleanupTooltip = () => {
1131
+ hideTooltip();
1132
+ if (closeButtonWrapper) {
1133
+ closeButtonWrapper.removeEventListener("mouseenter", showTooltip);
1134
+ closeButtonWrapper.removeEventListener("mouseleave", hideTooltip);
1135
+ }
1136
+ if (closeButton) {
1137
+ closeButton.removeEventListener("focus", showTooltip);
1138
+ closeButton.removeEventListener("blur", hideTooltip);
1139
+ }
1140
+ };
1141
+ }
1142
+ }
1143
+ }
1144
+
1145
+ // Update clear chat button styling from config
1146
+ const { clearChatButton, clearChatButtonWrapper } = panelElements;
1147
+ if (clearChatButton) {
1148
+ const clearChatConfig = launcher.clearChat ?? {};
1149
+ const clearChatEnabled = clearChatConfig.enabled ?? true;
1150
+
1151
+ // Show/hide button based on enabled state
1152
+ if (clearChatButtonWrapper) {
1153
+ clearChatButtonWrapper.style.display = clearChatEnabled ? "" : "none";
1154
+ }
1155
+
1156
+ if (clearChatEnabled) {
1157
+ // Update size
1158
+ const clearChatSize = clearChatConfig.size ?? "32px";
1159
+ clearChatButton.style.height = clearChatSize;
1160
+ clearChatButton.style.width = clearChatSize;
1161
+
1162
+ // Update icon
1163
+ const clearChatIconName = clearChatConfig.iconName ?? "refresh-cw";
1164
+ const clearChatIconColor = clearChatConfig.iconColor ?? "";
1165
+
1166
+ // Clear existing icon and render new one
1167
+ clearChatButton.innerHTML = "";
1168
+ const iconSvg = renderLucideIcon(clearChatIconName, "20px", clearChatIconColor || "", 2);
1169
+ if (iconSvg) {
1170
+ clearChatButton.appendChild(iconSvg);
1171
+ }
1172
+
1173
+ // Update icon color
1174
+ if (clearChatIconColor) {
1175
+ clearChatButton.style.color = clearChatIconColor;
1176
+ clearChatButton.classList.remove("tvw-text-cw-muted");
1177
+ } else {
1178
+ clearChatButton.style.color = "";
1179
+ clearChatButton.classList.add("tvw-text-cw-muted");
1180
+ }
1181
+
1182
+ // Update background color
1183
+ if (clearChatConfig.backgroundColor) {
1184
+ clearChatButton.style.backgroundColor = clearChatConfig.backgroundColor;
1185
+ clearChatButton.classList.remove("hover:tvw-bg-gray-100");
1186
+ } else {
1187
+ clearChatButton.style.backgroundColor = "";
1188
+ clearChatButton.classList.add("hover:tvw-bg-gray-100");
1189
+ }
1190
+
1191
+ // Update border
1192
+ if (clearChatConfig.borderWidth || clearChatConfig.borderColor) {
1193
+ const borderWidth = clearChatConfig.borderWidth || "0px";
1194
+ const borderColor = clearChatConfig.borderColor || "transparent";
1195
+ clearChatButton.style.border = `${borderWidth} solid ${borderColor}`;
1196
+ clearChatButton.classList.remove("tvw-border-none");
1197
+ } else {
1198
+ clearChatButton.style.border = "";
1199
+ clearChatButton.classList.add("tvw-border-none");
1200
+ }
1201
+
1202
+ // Update border radius
1203
+ if (clearChatConfig.borderRadius) {
1204
+ clearChatButton.style.borderRadius = clearChatConfig.borderRadius;
1205
+ clearChatButton.classList.remove("tvw-rounded-full");
1206
+ } else {
1207
+ clearChatButton.style.borderRadius = "";
1208
+ clearChatButton.classList.add("tvw-rounded-full");
1209
+ }
1210
+
1211
+ // Update padding
1212
+ if (clearChatConfig.paddingX) {
1213
+ clearChatButton.style.paddingLeft = clearChatConfig.paddingX;
1214
+ clearChatButton.style.paddingRight = clearChatConfig.paddingX;
1215
+ } else {
1216
+ clearChatButton.style.paddingLeft = "";
1217
+ clearChatButton.style.paddingRight = "";
1218
+ }
1219
+ if (clearChatConfig.paddingY) {
1220
+ clearChatButton.style.paddingTop = clearChatConfig.paddingY;
1221
+ clearChatButton.style.paddingBottom = clearChatConfig.paddingY;
1222
+ } else {
1223
+ clearChatButton.style.paddingTop = "";
1224
+ clearChatButton.style.paddingBottom = "";
1225
+ }
1226
+
1227
+ const clearChatTooltipText = clearChatConfig.tooltipText ?? "Clear chat";
1228
+ const clearChatShowTooltip = clearChatConfig.showTooltip ?? true;
1229
+
1230
+ clearChatButton.setAttribute("aria-label", clearChatTooltipText);
1231
+
1232
+ if (clearChatButtonWrapper) {
1233
+ // Clean up old tooltip event listeners if they exist
1234
+ if ((clearChatButtonWrapper as any)._cleanupTooltip) {
1235
+ (clearChatButtonWrapper as any)._cleanupTooltip();
1236
+ delete (clearChatButtonWrapper as any)._cleanupTooltip;
1237
+ }
1238
+
1239
+ // Set up new portaled tooltip with event listeners
1240
+ if (clearChatShowTooltip && clearChatTooltipText) {
1241
+ let portaledTooltip: HTMLElement | null = null;
1242
+
1243
+ const showTooltip = () => {
1244
+ if (portaledTooltip || !clearChatButton) return; // Already showing or button doesn't exist
1245
+
1246
+ // Create tooltip element
1247
+ portaledTooltip = createElement("div", "tvw-clear-chat-tooltip");
1248
+ portaledTooltip.textContent = clearChatTooltipText;
1249
+
1250
+ // Add arrow
1251
+ const arrow = createElement("div");
1252
+ arrow.className = "tvw-clear-chat-tooltip-arrow";
1253
+ portaledTooltip.appendChild(arrow);
1254
+
1255
+ // Get button position
1256
+ const buttonRect = clearChatButton.getBoundingClientRect();
1257
+
1258
+ // Position tooltip above button
1259
+ portaledTooltip.style.position = "fixed";
1260
+ portaledTooltip.style.left = `${buttonRect.left + buttonRect.width / 2}px`;
1261
+ portaledTooltip.style.top = `${buttonRect.top - 8}px`;
1262
+ portaledTooltip.style.transform = "translate(-50%, -100%)";
1263
+
1264
+ // Append to body
1265
+ document.body.appendChild(portaledTooltip);
1266
+ };
1267
+
1268
+ const hideTooltip = () => {
1269
+ if (portaledTooltip && portaledTooltip.parentNode) {
1270
+ portaledTooltip.parentNode.removeChild(portaledTooltip);
1271
+ portaledTooltip = null;
1272
+ }
1273
+ };
1274
+
1275
+ // Add event listeners
1276
+ clearChatButtonWrapper.addEventListener("mouseenter", showTooltip);
1277
+ clearChatButtonWrapper.addEventListener("mouseleave", hideTooltip);
1278
+ clearChatButton.addEventListener("focus", showTooltip);
1279
+ clearChatButton.addEventListener("blur", hideTooltip);
1280
+
1281
+ // Store cleanup function on the button for later use
1282
+ (clearChatButtonWrapper as any)._cleanupTooltip = () => {
1283
+ hideTooltip();
1284
+ if (clearChatButtonWrapper) {
1285
+ clearChatButtonWrapper.removeEventListener("mouseenter", showTooltip);
1286
+ clearChatButtonWrapper.removeEventListener("mouseleave", hideTooltip);
1287
+ }
1288
+ if (clearChatButton) {
1289
+ clearChatButton.removeEventListener("focus", showTooltip);
1290
+ clearChatButton.removeEventListener("blur", hideTooltip);
1291
+ }
1292
+ };
1293
+ }
1294
+ }
1295
+ }
998
1296
  }
999
1297
 
1000
1298
  postprocess = buildPostprocessor(config);
@@ -1289,7 +1587,7 @@ export const createChatExperience = (
1289
1587
  // Update status text if status is currently set
1290
1588
  if (session) {
1291
1589
  const currentStatus = session.getStatus();
1292
- const getCurrentStatusText = (status: ChatWidgetSessionStatus): string => {
1590
+ const getCurrentStatusText = (status: AgentWidgetSessionStatus): string => {
1293
1591
  if (status === "idle") return statusIndicatorConfig.idleText ?? statusCopy.idle;
1294
1592
  if (status === "connecting") return statusIndicatorConfig.connectingText ?? statusCopy.connecting;
1295
1593
  if (status === "connected") return statusIndicatorConfig.connectedText ?? statusCopy.connected;
@@ -1311,6 +1609,16 @@ export const createChatExperience = (
1311
1609
  if (!launcherEnabled) return;
1312
1610
  setOpenState(!open);
1313
1611
  },
1612
+ clearChat() {
1613
+ // Clear messages in session (this will trigger onMessagesChanged which re-renders)
1614
+ session.clearMessages();
1615
+
1616
+ // Dispatch custom event for external handlers (e.g., localStorage clearing in examples)
1617
+ const clearEvent = new CustomEvent("vanilla-agent:clear-chat", {
1618
+ detail: { timestamp: new Date().toISOString() }
1619
+ });
1620
+ window.dispatchEvent(clearEvent);
1621
+ },
1314
1622
  destroy() {
1315
1623
  destroyCallbacks.forEach((cb) => cb());
1316
1624
  wrapper.remove();
@@ -1322,4 +1630,4 @@ export const createChatExperience = (
1322
1630
  };
1323
1631
  };
1324
1632
 
1325
- export type ChatWidgetController = Controller;
1633
+ export type AgentWidgetController = Controller;
@@ -1,6 +1,6 @@
1
- import { ChatWidgetSessionStatus } from "../session";
1
+ import { AgentWidgetSessionStatus } from "../session";
2
2
 
3
- export const statusCopy: Record<ChatWidgetSessionStatus, string> = {
3
+ export const statusCopy: Record<AgentWidgetSessionStatus, string> = {
4
4
  idle: "Online",
5
5
  connecting: "Connecting…",
6
6
  connected: "Streaming…",
@@ -9,3 +9,5 @@ export const statusCopy: Record<ChatWidgetSessionStatus, string> = {
9
9
 
10
10
 
11
11
 
12
+
13
+
package/src/utils/dom.ts CHANGED
@@ -18,3 +18,5 @@ export const createFragment = (): DocumentFragment => {
18
18
 
19
19
 
20
20
 
21
+
22
+
@@ -1,4 +1,4 @@
1
- import { ChatWidgetReasoning, ChatWidgetToolCall } from "../types";
1
+ import { AgentWidgetReasoning, AgentWidgetToolCall } from "../types";
2
2
 
3
3
  export const formatUnknownValue = (value: unknown): string => {
4
4
  if (value === null) return "null";
@@ -14,7 +14,7 @@ export const formatUnknownValue = (value: unknown): string => {
14
14
  }
15
15
  };
16
16
 
17
- export const formatReasoningDuration = (reasoning: ChatWidgetReasoning) => {
17
+ export const formatReasoningDuration = (reasoning: AgentWidgetReasoning) => {
18
18
  const end = reasoning.completedAt ?? Date.now();
19
19
  const start = reasoning.startedAt ?? end;
20
20
  const durationMs =
@@ -32,13 +32,13 @@ export const formatReasoningDuration = (reasoning: ChatWidgetReasoning) => {
32
32
  return `Thought for ${formatted} seconds`;
33
33
  };
34
34
 
35
- export const describeReasonStatus = (reasoning: ChatWidgetReasoning) => {
35
+ export const describeReasonStatus = (reasoning: AgentWidgetReasoning) => {
36
36
  if (reasoning.status === "complete") return formatReasoningDuration(reasoning);
37
37
  if (reasoning.status === "pending") return "Waiting";
38
38
  return "";
39
39
  };
40
40
 
41
- export const formatToolDuration = (tool: ChatWidgetToolCall) => {
41
+ export const formatToolDuration = (tool: AgentWidgetToolCall) => {
42
42
  const durationMs =
43
43
  typeof tool.duration === "number"
44
44
  ? tool.duration
@@ -60,13 +60,13 @@ export const formatToolDuration = (tool: ChatWidgetToolCall) => {
60
60
  return `Used tool for ${formatted} seconds`;
61
61
  };
62
62
 
63
- export const describeToolStatus = (status: ChatWidgetToolCall["status"]) => {
63
+ export const describeToolStatus = (status: AgentWidgetToolCall["status"]) => {
64
64
  if (status === "complete") return "";
65
65
  if (status === "pending") return "Starting";
66
66
  return "Running";
67
67
  };
68
68
 
69
- export const describeToolTitle = (tool: ChatWidgetToolCall) => {
69
+ export const describeToolTitle = (tool: AgentWidgetToolCall) => {
70
70
  if (tool.status === "complete") {
71
71
  return formatToolDuration(tool);
72
72
  }
@@ -75,3 +75,5 @@ export const describeToolTitle = (tool: ChatWidgetToolCall) => {
75
75
 
76
76
 
77
77
 
78
+
79
+
@@ -1,4 +1,4 @@
1
- import { icons } from "lucide";
1
+ import * as icons from "lucide";
2
2
  import type { IconNode } from "lucide";
3
3
 
4
4
  /**
@@ -10,3 +10,5 @@ export const positionMap: Record<
10
10
 
11
11
 
12
12
 
13
+
14
+
@@ -1,8 +1,8 @@
1
- import { ChatWidgetConfig } from "../types";
1
+ import { AgentWidgetConfig } from "../types";
2
2
 
3
3
  export const applyThemeVariables = (
4
4
  element: HTMLElement,
5
- config?: ChatWidgetConfig
5
+ config?: AgentWidgetConfig
6
6
  ) => {
7
7
  const theme = config?.theme ?? {};
8
8
  Object.entries(theme).forEach(([key, value]) => {
@@ -18,3 +18,5 @@ export const applyThemeVariables = (
18
18
 
19
19
 
20
20
 
21
+
22
+