vanilla-agent 0.2.0 → 1.1.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,6 +1,6 @@
1
1
  import { createElement } from "../utils/dom";
2
2
  import { renderLucideIcon } from "../utils/icons";
3
- import { ChatWidgetConfig } from "../types";
3
+ import { AgentWidgetConfig } from "../types";
4
4
  import { positionMap } from "../utils/positioning";
5
5
 
6
6
  export interface PanelWrapper {
@@ -8,7 +8,7 @@ export interface PanelWrapper {
8
8
  panel: HTMLElement;
9
9
  }
10
10
 
11
- export const createWrapper = (config?: ChatWidgetConfig): PanelWrapper => {
11
+ export const createWrapper = (config?: AgentWidgetConfig): PanelWrapper => {
12
12
  const launcherEnabled = config?.launcher?.enabled ?? true;
13
13
 
14
14
  if (!launcherEnabled) {
@@ -40,7 +40,7 @@ export const createWrapper = (config?: ChatWidgetConfig): PanelWrapper => {
40
40
  "tvw-relative tvw-min-h-[320px]"
41
41
  );
42
42
  const launcherWidth = config?.launcher?.width ?? config?.launcherWidth;
43
- const width = launcherWidth ?? "min(360px, calc(100vw - 24px))";
43
+ const width = launcherWidth ?? "min(400px, calc(100vw - 24px))";
44
44
  panel.style.width = width;
45
45
  panel.style.maxWidth = width;
46
46
 
@@ -63,10 +63,13 @@ export interface PanelElements {
63
63
  introTitle: HTMLElement;
64
64
  introSubtitle: HTMLElement;
65
65
  closeButton: HTMLButtonElement;
66
+ closeButtonWrapper: HTMLElement;
67
+ clearChatButton: HTMLButtonElement | null;
68
+ clearChatButtonWrapper: HTMLElement | null;
66
69
  iconHolder: HTMLElement;
67
70
  }
68
71
 
69
- export const buildPanel = (config?: ChatWidgetConfig, showClose = true): PanelElements => {
72
+ export const buildPanel = (config?: AgentWidgetConfig, showClose = true): PanelElements => {
70
73
  const container = createElement(
71
74
  "div",
72
75
  "tvw-flex tvw-h-full tvw-w-full tvw-flex-col tvw-bg-cw-surface tvw-text-cw-primary tvw-rounded-2xl tvw-overflow-hidden tvw-shadow-2xl tvw-border tvw-border-cw-border"
@@ -141,19 +144,184 @@ export const buildPanel = (config?: ChatWidgetConfig, showClose = true): PanelEl
141
144
  header.append(headerCopy);
142
145
  }
143
146
 
147
+ // Create clear chat button if enabled
148
+ const clearChatConfig = launcher.clearChat ?? {};
149
+ const clearChatEnabled = clearChatConfig.enabled ?? true;
150
+ let clearChatButton: HTMLButtonElement | null = null;
151
+ let clearChatButtonWrapper: HTMLElement | null = null;
152
+
153
+ if (clearChatEnabled) {
154
+ const clearChatSize = clearChatConfig.size ?? "32px";
155
+ const clearChatIconName = clearChatConfig.iconName ?? "refresh-cw";
156
+ const clearChatIconColor = clearChatConfig.iconColor ?? "";
157
+ const clearChatBgColor = clearChatConfig.backgroundColor ?? "";
158
+ const clearChatBorderWidth = clearChatConfig.borderWidth ?? "";
159
+ const clearChatBorderColor = clearChatConfig.borderColor ?? "";
160
+ const clearChatBorderRadius = clearChatConfig.borderRadius ?? "";
161
+ const clearChatPaddingX = clearChatConfig.paddingX ?? "";
162
+ const clearChatPaddingY = clearChatConfig.paddingY ?? "";
163
+ const clearChatTooltipText = clearChatConfig.tooltipText ?? "Clear chat";
164
+ const clearChatShowTooltip = clearChatConfig.showTooltip ?? true;
165
+
166
+ // Create button wrapper for tooltip
167
+ clearChatButtonWrapper = createElement(
168
+ "div",
169
+ "tvw-relative tvw-ml-auto tvw-clear-chat-button-wrapper"
170
+ );
171
+
172
+ clearChatButton = createElement(
173
+ "button",
174
+ "tvw-inline-flex tvw-items-center tvw-justify-center tvw-rounded-full tvw-text-cw-muted hover:tvw-bg-gray-100 tvw-cursor-pointer tvw-border-none"
175
+ ) as HTMLButtonElement;
176
+
177
+ clearChatButton.style.height = clearChatSize;
178
+ clearChatButton.style.width = clearChatSize;
179
+ clearChatButton.type = "button";
180
+ clearChatButton.setAttribute("aria-label", clearChatTooltipText);
181
+
182
+ // Add icon
183
+ const iconSvg = renderLucideIcon(clearChatIconName, "20px", clearChatIconColor || "", 2);
184
+ if (iconSvg) {
185
+ clearChatButton.appendChild(iconSvg);
186
+ }
187
+
188
+ // Apply styling from config
189
+ if (clearChatIconColor) {
190
+ clearChatButton.style.color = clearChatIconColor;
191
+ clearChatButton.classList.remove("tvw-text-cw-muted");
192
+ }
193
+
194
+ if (clearChatBgColor) {
195
+ clearChatButton.style.backgroundColor = clearChatBgColor;
196
+ clearChatButton.classList.remove("hover:tvw-bg-gray-100");
197
+ }
198
+
199
+ if (clearChatBorderWidth || clearChatBorderColor) {
200
+ const borderWidth = clearChatBorderWidth || "0px";
201
+ const borderColor = clearChatBorderColor || "transparent";
202
+ clearChatButton.style.border = `${borderWidth} solid ${borderColor}`;
203
+ clearChatButton.classList.remove("tvw-border-none");
204
+ }
205
+
206
+ if (clearChatBorderRadius) {
207
+ clearChatButton.style.borderRadius = clearChatBorderRadius;
208
+ clearChatButton.classList.remove("tvw-rounded-full");
209
+ }
210
+
211
+ // Apply padding styling
212
+ if (clearChatPaddingX) {
213
+ clearChatButton.style.paddingLeft = clearChatPaddingX;
214
+ clearChatButton.style.paddingRight = clearChatPaddingX;
215
+ } else {
216
+ clearChatButton.style.paddingLeft = "";
217
+ clearChatButton.style.paddingRight = "";
218
+ }
219
+ if (clearChatPaddingY) {
220
+ clearChatButton.style.paddingTop = clearChatPaddingY;
221
+ clearChatButton.style.paddingBottom = clearChatPaddingY;
222
+ } else {
223
+ clearChatButton.style.paddingTop = "";
224
+ clearChatButton.style.paddingBottom = "";
225
+ }
226
+
227
+ clearChatButtonWrapper.appendChild(clearChatButton);
228
+
229
+ // Add tooltip with portaling to document.body to escape overflow clipping
230
+ if (clearChatShowTooltip && clearChatTooltipText && clearChatButton && clearChatButtonWrapper) {
231
+ let portaledTooltip: HTMLElement | null = null;
232
+
233
+ const showTooltip = () => {
234
+ if (portaledTooltip || !clearChatButton) return; // Already showing or button doesn't exist
235
+
236
+ // Create tooltip element
237
+ portaledTooltip = createElement("div", "tvw-clear-chat-tooltip");
238
+ portaledTooltip.textContent = clearChatTooltipText;
239
+
240
+ // Add arrow
241
+ const arrow = createElement("div");
242
+ arrow.className = "tvw-clear-chat-tooltip-arrow";
243
+ portaledTooltip.appendChild(arrow);
244
+
245
+ // Get button position
246
+ const buttonRect = clearChatButton.getBoundingClientRect();
247
+
248
+ // Position tooltip above button
249
+ portaledTooltip.style.position = "fixed";
250
+ portaledTooltip.style.left = `${buttonRect.left + buttonRect.width / 2}px`;
251
+ portaledTooltip.style.top = `${buttonRect.top - 8}px`;
252
+ portaledTooltip.style.transform = "translate(-50%, -100%)";
253
+
254
+ // Append to body
255
+ document.body.appendChild(portaledTooltip);
256
+ };
257
+
258
+ const hideTooltip = () => {
259
+ if (portaledTooltip && portaledTooltip.parentNode) {
260
+ portaledTooltip.parentNode.removeChild(portaledTooltip);
261
+ portaledTooltip = null;
262
+ }
263
+ };
264
+
265
+ // Add event listeners
266
+ clearChatButtonWrapper.addEventListener("mouseenter", showTooltip);
267
+ clearChatButtonWrapper.addEventListener("mouseleave", hideTooltip);
268
+ clearChatButton.addEventListener("focus", showTooltip);
269
+ clearChatButton.addEventListener("blur", hideTooltip);
270
+
271
+ // Store cleanup function on the button for later use
272
+ (clearChatButtonWrapper as any)._cleanupTooltip = () => {
273
+ hideTooltip();
274
+ if (clearChatButtonWrapper) {
275
+ clearChatButtonWrapper.removeEventListener("mouseenter", showTooltip);
276
+ clearChatButtonWrapper.removeEventListener("mouseleave", hideTooltip);
277
+ }
278
+ if (clearChatButton) {
279
+ clearChatButton.removeEventListener("focus", showTooltip);
280
+ clearChatButton.removeEventListener("blur", hideTooltip);
281
+ }
282
+ };
283
+ }
284
+
285
+ header.appendChild(clearChatButtonWrapper);
286
+ }
287
+
288
+ // Create close button wrapper for tooltip positioning
289
+ const closeButtonWrapper = createElement(
290
+ "div",
291
+ closeButtonPlacement === "top-right"
292
+ ? "tvw-absolute tvw-top-4 tvw-right-4 tvw-z-50"
293
+ : (clearChatEnabled
294
+ ? ""
295
+ : "tvw-ml-auto")
296
+ );
297
+
144
298
  // Create close button with base classes
145
299
  const closeButton = createElement(
146
300
  "button",
147
- closeButtonPlacement === "top-right"
148
- ? "tvw-absolute tvw-top-4 tvw-right-4 tvw-z-50 tvw-inline-flex tvw-items-center tvw-justify-center tvw-rounded-full tvw-text-cw-muted hover:tvw-bg-gray-100 tvw-cursor-pointer tvw-border-none"
149
- : "tvw-ml-auto tvw-inline-flex tvw-items-center tvw-justify-center tvw-rounded-full tvw-text-cw-muted hover:tvw-bg-gray-100 tvw-cursor-pointer tvw-border-none"
301
+ "tvw-inline-flex tvw-items-center tvw-justify-center tvw-rounded-full tvw-text-cw-muted hover:tvw-bg-gray-100 tvw-cursor-pointer tvw-border-none"
150
302
  ) as HTMLButtonElement;
151
303
  closeButton.style.height = closeButtonSize;
152
304
  closeButton.style.width = closeButtonSize;
153
305
  closeButton.type = "button";
154
- closeButton.setAttribute("aria-label", "Close chat");
155
- closeButton.textContent = "×";
306
+
307
+ // Get tooltip config
308
+ const closeButtonTooltipText = launcher.closeButtonTooltipText ?? "Close chat";
309
+ const closeButtonShowTooltip = launcher.closeButtonShowTooltip ?? true;
310
+
311
+ closeButton.setAttribute("aria-label", closeButtonTooltipText);
156
312
  closeButton.style.display = showClose ? "" : "none";
313
+
314
+ // Add icon or fallback text
315
+ const closeButtonIconName = launcher.closeButtonIconName ?? "x";
316
+ const closeButtonIconText = launcher.closeButtonIconText ?? "×";
317
+
318
+ // Try to render Lucide icon, fallback to text if not provided or fails
319
+ const iconSvg = renderLucideIcon(closeButtonIconName, "20px", launcher.closeButtonColor || "", 2);
320
+ if (iconSvg) {
321
+ closeButton.appendChild(iconSvg);
322
+ } else {
323
+ closeButton.textContent = closeButtonIconText;
324
+ }
157
325
 
158
326
  // Apply close button styling from config
159
327
  if (launcher.closeButtonColor) {
@@ -190,15 +358,85 @@ export const buildPanel = (config?: ChatWidgetConfig, showClose = true): PanelEl
190
358
  closeButton.style.borderRadius = "";
191
359
  closeButton.classList.add("tvw-rounded-full");
192
360
  }
193
-
194
- // Position close button based on placement
361
+
362
+ // Apply padding styling
363
+ if (launcher.closeButtonPaddingX) {
364
+ closeButton.style.paddingLeft = launcher.closeButtonPaddingX;
365
+ closeButton.style.paddingRight = launcher.closeButtonPaddingX;
366
+ } else {
367
+ closeButton.style.paddingLeft = "";
368
+ closeButton.style.paddingRight = "";
369
+ }
370
+ if (launcher.closeButtonPaddingY) {
371
+ closeButton.style.paddingTop = launcher.closeButtonPaddingY;
372
+ closeButton.style.paddingBottom = launcher.closeButtonPaddingY;
373
+ } else {
374
+ closeButton.style.paddingTop = "";
375
+ closeButton.style.paddingBottom = "";
376
+ }
377
+
378
+ closeButtonWrapper.appendChild(closeButton);
379
+
380
+ // Add tooltip with portaling to document.body to escape overflow clipping
381
+ if (closeButtonShowTooltip && closeButtonTooltipText) {
382
+ let portaledTooltip: HTMLElement | null = null;
383
+
384
+ const showTooltip = () => {
385
+ if (portaledTooltip) return; // Already showing
386
+
387
+ // Create tooltip element
388
+ portaledTooltip = createElement("div", "tvw-clear-chat-tooltip");
389
+ portaledTooltip.textContent = closeButtonTooltipText;
390
+
391
+ // Add arrow
392
+ const arrow = createElement("div");
393
+ arrow.className = "tvw-clear-chat-tooltip-arrow";
394
+ portaledTooltip.appendChild(arrow);
395
+
396
+ // Get button position
397
+ const buttonRect = closeButton.getBoundingClientRect();
398
+
399
+ // Position tooltip above button
400
+ portaledTooltip.style.position = "fixed";
401
+ portaledTooltip.style.left = `${buttonRect.left + buttonRect.width / 2}px`;
402
+ portaledTooltip.style.top = `${buttonRect.top - 8}px`;
403
+ portaledTooltip.style.transform = "translate(-50%, -100%)";
404
+
405
+ // Append to body
406
+ document.body.appendChild(portaledTooltip);
407
+ };
408
+
409
+ const hideTooltip = () => {
410
+ if (portaledTooltip && portaledTooltip.parentNode) {
411
+ portaledTooltip.parentNode.removeChild(portaledTooltip);
412
+ portaledTooltip = null;
413
+ }
414
+ };
415
+
416
+ // Add event listeners
417
+ closeButtonWrapper.addEventListener("mouseenter", showTooltip);
418
+ closeButtonWrapper.addEventListener("mouseleave", hideTooltip);
419
+ closeButton.addEventListener("focus", showTooltip);
420
+ closeButton.addEventListener("blur", hideTooltip);
421
+
422
+ // Store cleanup function on the wrapper for later use
423
+ (closeButtonWrapper as any)._cleanupTooltip = () => {
424
+ hideTooltip();
425
+ closeButtonWrapper.removeEventListener("mouseenter", showTooltip);
426
+ closeButtonWrapper.removeEventListener("mouseleave", hideTooltip);
427
+ closeButton.removeEventListener("focus", showTooltip);
428
+ closeButton.removeEventListener("blur", hideTooltip);
429
+ };
430
+ }
431
+
432
+ // Position close button wrapper based on placement
195
433
  if (closeButtonPlacement === "top-right") {
196
434
  // Make container position relative for absolute positioning
197
435
  container.style.position = "relative";
198
- container.appendChild(closeButton);
436
+ container.appendChild(closeButtonWrapper);
199
437
  } else {
200
438
  // Inline placement: append to header
201
- header.appendChild(closeButton);
439
+ header.appendChild(closeButtonWrapper);
202
440
  }
203
441
 
204
442
  const body = createElement(
@@ -547,6 +785,9 @@ export const buildPanel = (config?: ChatWidgetConfig, showClose = true): PanelEl
547
785
  introTitle,
548
786
  introSubtitle,
549
787
  closeButton,
788
+ closeButtonWrapper,
789
+ clearChatButton,
790
+ clearChatButtonWrapper,
550
791
  iconHolder
551
792
  };
552
793
  };
@@ -1,11 +1,11 @@
1
1
  import { createElement } from "../utils/dom";
2
- import { ChatWidgetMessage } from "../types";
2
+ import { AgentWidgetMessage } from "../types";
3
3
  import { describeReasonStatus } from "../utils/formatting";
4
4
 
5
5
  // Expansion state per widget instance
6
6
  const reasoningExpansionState = new Set<string>();
7
7
 
8
- export const createReasoningBubble = (message: ChatWidgetMessage): HTMLElement => {
8
+ export const createReasoningBubble = (message: AgentWidgetMessage): HTMLElement => {
9
9
  const reasoning = message.reasoning;
10
10
  const bubble = createElement(
11
11
  "div",
@@ -1,16 +1,16 @@
1
1
  import { createElement } from "../utils/dom";
2
- import { ChatWidgetSession } from "../session";
3
- import { ChatWidgetMessage } from "../types";
2
+ import { AgentWidgetSession } from "../session";
3
+ import { AgentWidgetMessage } from "../types";
4
4
 
5
5
  export interface SuggestionButtons {
6
6
  buttons: HTMLButtonElement[];
7
- render: (chips: string[] | undefined, session: ChatWidgetSession, textarea: HTMLTextAreaElement, messages?: ChatWidgetMessage[]) => void;
7
+ render: (chips: string[] | undefined, session: AgentWidgetSession, textarea: HTMLTextAreaElement, messages?: AgentWidgetMessage[]) => void;
8
8
  }
9
9
 
10
10
  export const createSuggestions = (container: HTMLElement): SuggestionButtons => {
11
11
  const suggestionButtons: HTMLButtonElement[] = [];
12
12
 
13
- const render = (chips: string[] | undefined, session: ChatWidgetSession, textarea: HTMLTextAreaElement, messages?: ChatWidgetMessage[]) => {
13
+ const render = (chips: string[] | undefined, session: AgentWidgetSession, textarea: HTMLTextAreaElement, messages?: AgentWidgetMessage[]) => {
14
14
  container.innerHTML = "";
15
15
  suggestionButtons.length = 0;
16
16
  if (!chips || !chips.length) return;
@@ -1,11 +1,11 @@
1
1
  import { createElement } from "../utils/dom";
2
- import { ChatWidgetMessage } from "../types";
2
+ import { AgentWidgetMessage } from "../types";
3
3
  import { formatUnknownValue, describeToolTitle } from "../utils/formatting";
4
4
 
5
5
  // Expansion state per widget instance
6
6
  const toolExpansionState = new Set<string>();
7
7
 
8
- export const createToolBubble = (message: ChatWidgetMessage): HTMLElement => {
8
+ export const createToolBubble = (message: AgentWidgetMessage): HTMLElement => {
9
9
  const tool = message.toolCall;
10
10
  const bubble = createElement(
11
11
  "div",
@@ -0,0 +1,180 @@
1
+ import type { AgentWidgetConfig } from "./types";
2
+
3
+ /**
4
+ * Default widget configuration
5
+ * Single source of truth for all default values
6
+ */
7
+ export const DEFAULT_WIDGET_CONFIG: Partial<AgentWidgetConfig> = {
8
+ apiUrl: "http://localhost:43111/api/chat/dispatch",
9
+ theme: {
10
+ primary: "#111827",
11
+ accent: "#1d4ed8",
12
+ surface: "#ffffff",
13
+ muted: "#6b7280",
14
+ container: "#f8fafc",
15
+ border: "#f1f5f9",
16
+ divider: "#f1f5f9",
17
+ messageBorder: "#f1f5f9",
18
+ inputBackground: "#ffffff",
19
+ callToAction: "#000000",
20
+ callToActionBackground: "#ffffff",
21
+ sendButtonBackgroundColor: "#111827",
22
+ sendButtonTextColor: "#ffffff",
23
+ sendButtonBorderColor: "#60a5fa",
24
+ closeButtonColor: "#6b7280",
25
+ closeButtonBackgroundColor: "transparent",
26
+ closeButtonBorderColor: "",
27
+ clearChatIconColor: "#6b7280",
28
+ clearChatBackgroundColor: "transparent",
29
+ clearChatBorderColor: "transparent",
30
+ micIconColor: "#111827",
31
+ micBackgroundColor: "transparent",
32
+ micBorderColor: "transparent",
33
+ recordingIconColor: "#ffffff",
34
+ recordingBackgroundColor: "#ef4444",
35
+ recordingBorderColor: "transparent",
36
+ inputFontFamily: "sans-serif",
37
+ inputFontWeight: "400",
38
+ radiusSm: "0.75rem",
39
+ radiusMd: "1rem",
40
+ radiusLg: "1.5rem",
41
+ launcherRadius: "9999px",
42
+ buttonRadius: "9999px",
43
+ },
44
+ launcher: {
45
+ enabled: true,
46
+ title: "Chat Assistant",
47
+ subtitle: "Here to help you get answers fast",
48
+ agentIconText: "💬",
49
+ position: "bottom-right",
50
+ width: "min(400px, calc(100vw - 24px))",
51
+ autoExpand: false,
52
+ callToActionIconHidden: false,
53
+ agentIconSize: "40px",
54
+ headerIconSize: "40px",
55
+ closeButtonSize: "32px",
56
+ callToActionIconName: "arrow-up-right",
57
+ callToActionIconText: "",
58
+ callToActionIconSize: "32px",
59
+ callToActionIconPadding: "5px",
60
+ callToActionIconColor: "#000000",
61
+ callToActionIconBackgroundColor: "#ffffff",
62
+ closeButtonColor: "#6b7280",
63
+ closeButtonBackgroundColor: "transparent",
64
+ clearChat: {
65
+ iconColor: "#6b7280",
66
+ backgroundColor: "transparent",
67
+ borderColor: "transparent",
68
+ enabled: true,
69
+ iconName: "refresh-cw",
70
+ size: "29px",
71
+ showTooltip: true,
72
+ tooltipText: "Clear chat",
73
+ paddingX: "0px",
74
+ paddingY: "0px",
75
+ },
76
+ headerIconHidden: false,
77
+ },
78
+ copy: {
79
+ welcomeTitle: "Hello 👋",
80
+ welcomeSubtitle: "Ask anything about your account or products.",
81
+ inputPlaceholder: "How can I help...",
82
+ sendButtonLabel: "Send",
83
+ },
84
+ sendButton: {
85
+ borderWidth: "0px",
86
+ paddingX: "12px",
87
+ paddingY: "10px",
88
+ backgroundColor: "#111827",
89
+ textColor: "#ffffff",
90
+ borderColor: "#60a5fa",
91
+ useIcon: true,
92
+ iconText: "↑",
93
+ size: "40px",
94
+ showTooltip: true,
95
+ tooltipText: "Send message",
96
+ iconName: "send",
97
+ },
98
+ statusIndicator: {
99
+ visible: true,
100
+ idleText: "Online",
101
+ connectingText: "Connecting…",
102
+ connectedText: "Streaming…",
103
+ errorText: "Offline",
104
+ },
105
+ voiceRecognition: {
106
+ enabled: true,
107
+ pauseDuration: 2000,
108
+ iconName: "mic",
109
+ iconSize: "39px",
110
+ borderWidth: "0px",
111
+ paddingX: "9px",
112
+ paddingY: "14px",
113
+ iconColor: "#111827",
114
+ backgroundColor: "transparent",
115
+ borderColor: "transparent",
116
+ recordingIconColor: "#ffffff",
117
+ recordingBackgroundColor: "#ef4444",
118
+ recordingBorderColor: "transparent",
119
+ showTooltip: true,
120
+ tooltipText: "Start voice recognition",
121
+ },
122
+ features: {
123
+ showReasoning: true,
124
+ showToolCalls: true,
125
+ },
126
+ suggestionChips: [
127
+ "What can you help me with?",
128
+ "Tell me about your features",
129
+ "How does this work?",
130
+ ],
131
+ debug: false,
132
+ };
133
+
134
+ /**
135
+ * Helper to deep merge user config with defaults
136
+ * This ensures all default values are present while allowing selective overrides
137
+ */
138
+ export function mergeWithDefaults(
139
+ config?: Partial<AgentWidgetConfig>
140
+ ): Partial<AgentWidgetConfig> {
141
+ if (!config) return DEFAULT_WIDGET_CONFIG;
142
+
143
+ return {
144
+ ...DEFAULT_WIDGET_CONFIG,
145
+ ...config,
146
+ theme: {
147
+ ...DEFAULT_WIDGET_CONFIG.theme,
148
+ ...config.theme,
149
+ },
150
+ launcher: {
151
+ ...DEFAULT_WIDGET_CONFIG.launcher,
152
+ ...config.launcher,
153
+ clearChat: {
154
+ ...DEFAULT_WIDGET_CONFIG.launcher?.clearChat,
155
+ ...config.launcher?.clearChat,
156
+ },
157
+ },
158
+ copy: {
159
+ ...DEFAULT_WIDGET_CONFIG.copy,
160
+ ...config.copy,
161
+ },
162
+ sendButton: {
163
+ ...DEFAULT_WIDGET_CONFIG.sendButton,
164
+ ...config.sendButton,
165
+ },
166
+ statusIndicator: {
167
+ ...DEFAULT_WIDGET_CONFIG.statusIndicator,
168
+ ...config.statusIndicator,
169
+ },
170
+ voiceRecognition: {
171
+ ...DEFAULT_WIDGET_CONFIG.voiceRecognition,
172
+ ...config.voiceRecognition,
173
+ },
174
+ features: {
175
+ ...DEFAULT_WIDGET_CONFIG.features,
176
+ ...config.features,
177
+ },
178
+ suggestionChips: config.suggestionChips ?? DEFAULT_WIDGET_CONFIG.suggestionChips,
179
+ };
180
+ }
package/src/index.ts CHANGED
@@ -1,37 +1,40 @@
1
1
  import {
2
- initChatWidget as initChatWidgetFn,
3
- type ChatWidgetInitHandle
2
+ initAgentWidget as initAgentWidgetFn,
3
+ type AgentWidgetInitHandle
4
4
  } from "./runtime/init";
5
5
 
6
6
  export type {
7
- ChatWidgetConfig,
8
- ChatWidgetTheme,
9
- ChatWidgetFeatureFlags,
10
- ChatWidgetInitOptions,
11
- ChatWidgetMessage,
12
- ChatWidgetLauncherConfig,
13
- ChatWidgetEvent
7
+ AgentWidgetConfig,
8
+ AgentWidgetTheme,
9
+ AgentWidgetFeatureFlags,
10
+ AgentWidgetInitOptions,
11
+ AgentWidgetMessage,
12
+ AgentWidgetLauncherConfig,
13
+ AgentWidgetEvent
14
14
  } from "./types";
15
15
 
16
- export { initChatWidgetFn as initChatWidget };
16
+ export { initAgentWidgetFn as initAgentWidget };
17
17
  export {
18
- createChatExperience,
19
- type ChatWidgetController
18
+ createAgentExperience,
19
+ type AgentWidgetController
20
20
  } from "./ui";
21
21
  export {
22
- ChatWidgetSession,
23
- type ChatWidgetSessionStatus
22
+ AgentWidgetSession,
23
+ type AgentWidgetSessionStatus
24
24
  } from "./session";
25
- export { ChatWidgetClient } from "./client";
25
+ export { AgentWidgetClient } from "./client";
26
26
  export {
27
27
  markdownPostprocessor,
28
28
  escapeHtml,
29
29
  directivePostprocessor
30
30
  } from "./postprocessors";
31
- export type { ChatWidgetInitHandle };
31
+ export type { AgentWidgetInitHandle };
32
32
 
33
33
  // Plugin system exports
34
- export type { ChatWidgetPlugin } from "./plugins/types";
34
+ export type { AgentWidgetPlugin } from "./plugins/types";
35
35
  export { pluginRegistry } from "./plugins/registry";
36
36
 
37
- export default initChatWidgetFn;
37
+ // Default configuration exports
38
+ export { DEFAULT_WIDGET_CONFIG, mergeWithDefaults } from "./defaults";
39
+
40
+ export default initAgentWidgetFn;
package/src/install.ts CHANGED
@@ -17,7 +17,7 @@ interface SiteAgentInstallConfig {
17
17
  declare global {
18
18
  interface Window {
19
19
  siteAgentConfig?: SiteAgentInstallConfig;
20
- ChatWidget?: any;
20
+ AgentWidget?: any;
21
21
  }
22
22
  }
23
23
 
@@ -67,7 +67,7 @@ declare global {
67
67
 
68
68
  // Check if JS is already loaded
69
69
  const isJsLoaded = () => {
70
- return !!(window as any).ChatWidget;
70
+ return !!(window as any).AgentWidget;
71
71
  };
72
72
 
73
73
  // Load CSS
@@ -107,8 +107,8 @@ declare global {
107
107
 
108
108
  // Initialize widget
109
109
  const initWidget = () => {
110
- if (!window.ChatWidget || !window.ChatWidget.initChatWidget) {
111
- console.warn("ChatWidget not available. Make sure the script loaded successfully.");
110
+ if (!window.AgentWidget || !window.AgentWidget.initAgentWidget) {
111
+ console.warn("AgentWidget not available. Make sure the script loaded successfully.");
112
112
  return;
113
113
  }
114
114
 
@@ -125,12 +125,12 @@ declare global {
125
125
  }
126
126
 
127
127
  try {
128
- window.ChatWidget.initChatWidget({
128
+ window.AgentWidget.initAgentWidget({
129
129
  target,
130
130
  config: widgetConfig
131
131
  });
132
132
  } catch (error) {
133
- console.error("Failed to initialize ChatWidget:", error);
133
+ console.error("Failed to initialize AgentWidget:", error);
134
134
  }
135
135
  };
136
136
 
@@ -141,11 +141,11 @@ declare global {
141
141
  await loadJS();
142
142
 
143
143
  if (autoInit && (config.config || (config as any).apiUrl)) {
144
- // Wait a tick to ensure ChatWidget is fully initialized
144
+ // Wait a tick to ensure AgentWidget is fully initialized
145
145
  setTimeout(initWidget, 0);
146
146
  }
147
147
  } catch (error) {
148
- console.error("Failed to install ChatWidget:", error);
148
+ console.error("Failed to install AgentWidget:", error);
149
149
  }
150
150
  };
151
151