@xapp/chat-widget 1.91.0 → 1.93.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/dist/index.js CHANGED
@@ -3213,9 +3213,11 @@ function getPageContext(override) {
3213
3213
  }
3214
3214
  var MCPChat = /** @class */ (function () {
3215
3215
  function MCPChat(config, options) {
3216
+ var _a;
3216
3217
  this._userId = "";
3217
3218
  this._sessionId = "";
3218
3219
  this._accessToken = "";
3220
+ this._debugMode = false;
3219
3221
  this._attributes = {};
3220
3222
  // Streaming throttle state
3221
3223
  this.streamBuffer = "";
@@ -3238,6 +3240,7 @@ var MCPChat = /** @class */ (function () {
3238
3240
  this.options = options;
3239
3241
  this.configurableMessages = options === null || options === void 0 ? void 0 : options.configurableMessages;
3240
3242
  this.isNewSession = false;
3243
+ this._debugMode = (_a = config.debugMode) !== null && _a !== void 0 ? _a : false;
3241
3244
  this.hooks = options === null || options === void 0 ? void 0 : options.hooks;
3242
3245
  // Validate business_owner mode requires authToken
3243
3246
  var mode = config.mode || "homeowner";
@@ -3281,14 +3284,8 @@ var MCPChat = /** @class */ (function () {
3281
3284
  // Dispatch bot joined early so it appears before the greeting.
3282
3285
  // getBot() is config-derived (uses options.bot), so it's safe to call before setVisitorInfo.
3283
3286
  this.userJoined(this.getBot(undefined));
3284
- // Returning user with existing session - validate session silently
3285
- // New user without session - initialize new session to get greeting
3286
- if (this._sessionId) {
3287
- this.validateSession();
3288
- }
3289
- else {
3290
- this.initializeNewSession();
3291
- }
3287
+ // Session initialization is deferred to setVisitorInfo() to avoid
3288
+ // making network requests before the widget is visible.
3292
3289
  };
3293
3290
  /**
3294
3291
  * Validates an existing session with the server ("Silent Handshake").
@@ -3342,7 +3339,7 @@ var MCPChat = /** @class */ (function () {
3342
3339
  */
3343
3340
  MCPChat.prototype.buildRequestPayload = function (additionalData) {
3344
3341
  if (additionalData === void 0) { additionalData = {}; }
3345
- return __assign({
3342
+ return __assign(__assign({
3346
3343
  // Identity - server generates these, we just send back what we have
3347
3344
  userId: this._userId || undefined, sessionId: this._sessionId || undefined,
3348
3345
  // Fingerprint for user identification (can be disabled for privacy)
@@ -3352,7 +3349,7 @@ var MCPChat = /** @class */ (function () {
3352
3349
  // Client timestamp for latency measurement and clock drift detection
3353
3350
  clientTime: new Date().toISOString(),
3354
3351
  // Last sequence number for replay on reconnect
3355
- lastSeq: this.lastSeq }, additionalData);
3352
+ lastSeq: this.lastSeq }, (this._debugMode && { debug: true })), additionalData);
3356
3353
  };
3357
3354
  /**
3358
3355
  * Initializes a new session by calling the endpoint with { newSession: true }.
@@ -3362,9 +3359,12 @@ var MCPChat = /** @class */ (function () {
3362
3359
  return __awaiter$1(this, void 0, void 0, function () {
3363
3360
  var endpoint, error_2;
3364
3361
  var _this = this;
3365
- return __generator$1(this, function (_a) {
3366
- switch (_a.label) {
3362
+ var _a;
3363
+ return __generator$1(this, function (_b) {
3364
+ switch (_b.label) {
3367
3365
  case 0:
3366
+ // Reset debug mode on new session (respects config default)
3367
+ this._debugMode = (_a = this.config.debugMode) !== null && _a !== void 0 ? _a : false;
3368
3368
  // Prevent multiple concurrent initialization requests
3369
3369
  if (this.isInitializingSession) {
3370
3370
  log("New session initialization already in progress, skipping");
@@ -3378,15 +3378,15 @@ var MCPChat = /** @class */ (function () {
3378
3378
  _this.resolveSessionInit = resolve;
3379
3379
  });
3380
3380
  this.typing();
3381
- _a.label = 1;
3381
+ _b.label = 1;
3382
3382
  case 1:
3383
- _a.trys.push([1, 3, 4, 5]);
3383
+ _b.trys.push([1, 3, 4, 5]);
3384
3384
  return [4 /*yield*/, this.performSSERequest(this.buildRequestPayload({ newSession: true, generateGreeting: true }))];
3385
3385
  case 2:
3386
- _a.sent();
3386
+ _b.sent();
3387
3387
  return [3 /*break*/, 5];
3388
3388
  case 3:
3389
- error_2 = _a.sent();
3389
+ error_2 = _b.sent();
3390
3390
  err("Failed to initialize new session: ".concat(error_2));
3391
3391
  this.stopTyping();
3392
3392
  this.setConnectionStatus("offline");
@@ -3635,6 +3635,7 @@ var MCPChat = /** @class */ (function () {
3635
3635
  toolCallId: params.toolCallId,
3636
3636
  displayName: params.displayName,
3637
3637
  label: params.label,
3638
+ toolInput: params.toolInput,
3638
3639
  hidden: params.hidden,
3639
3640
  toolResult: params.toolResult,
3640
3641
  toolError: params.toolError,
@@ -3936,10 +3937,28 @@ var MCPChat = /** @class */ (function () {
3936
3937
  */
3937
3938
  MCPChat.prototype.attemptSSERequest = function (message) {
3938
3939
  return __awaiter$1(this, void 0, void 0, function () {
3939
- var messageText;
3940
+ var messageText, statusMsg, msgId;
3940
3941
  var _a;
3941
3942
  return __generator$1(this, function (_b) {
3942
3943
  messageText = ((_a = message.msg) === null || _a === void 0 ? void 0 : _a.text) || "";
3944
+ // Intercept /debug command — toggle debug mode client-side without sending to LLM
3945
+ if (messageText.trim().toLowerCase() === '/debug') {
3946
+ this._debugMode = !this._debugMode;
3947
+ statusMsg = this._debugMode ? 'Debug mode enabled' : 'Debug mode disabled';
3948
+ log("[attemptSSERequest] ".concat(statusMsg));
3949
+ msgId = "debug-".concat(Date.now());
3950
+ this.dispatch({
3951
+ type: "chat",
3952
+ detail: {
3953
+ type: "chat.stream.end",
3954
+ user: this.getBot(undefined),
3955
+ messageId: msgId,
3956
+ msg: { text: statusMsg },
3957
+ timestamp: +new Date(),
3958
+ },
3959
+ });
3960
+ return [2 /*return*/];
3961
+ }
3943
3962
  log("[attemptSSERequest] Sending message: \"".concat(messageText, "\", userId: ").concat(this._userId, ", sessionId: ").concat(this._sessionId));
3944
3963
  return [2 /*return*/, this.performSSERequest(this.buildRequestPayload({ message: messageText }))];
3945
3964
  });
@@ -4124,8 +4143,19 @@ var MCPChat = /** @class */ (function () {
4124
4143
  toolCall.error = data.toolError;
4125
4144
  toolCall.label = data.label; // Update with completion label
4126
4145
  toolCall.hidden = data.hidden; // Update hidden status
4127
- toolCall.endTime = Date.now();
4146
+ // Use server-side batch duration if available (debug mode), otherwise client-side
4147
+ toolCall.endTime = (data.toolBatchDurationMs && toolCall.startTime != null)
4148
+ ? toolCall.startTime + data.toolBatchDurationMs
4149
+ : Date.now();
4128
4150
  toolCall.isExecuting = false;
4151
+ // Capture tool input from debug-enriched events
4152
+ if (data.toolInput) {
4153
+ toolCall.input = data.toolInput;
4154
+ }
4155
+ }
4156
+ // Toggle debug mode when toggle_debug tool is called by the LLM
4157
+ if (data.toolName === 'toggle_debug') {
4158
+ _this._debugMode = !_this._debugMode;
4129
4159
  }
4130
4160
  // Always dispatch tool end for user-friendly progress display
4131
4161
  _this.dispatchToolEnd({
@@ -4135,6 +4165,7 @@ var MCPChat = /** @class */ (function () {
4135
4165
  displayName: data.displayName,
4136
4166
  label: data.label,
4137
4167
  hidden: data.hidden,
4168
+ toolInput: data.toolInput,
4138
4169
  toolResult: data.toolResult,
4139
4170
  toolError: data.toolError,
4140
4171
  });
@@ -4173,8 +4204,8 @@ var MCPChat = /** @class */ (function () {
4173
4204
  sources: sources,
4174
4205
  displays: data.response.displays,
4175
4206
  };
4176
- // Capture tool calls before flushing (debug mode)
4177
- var toolCalls_1 = _this.config.debugMode ? __spreadArray$1([], _this.currentToolCalls, true) : undefined;
4207
+ // Capture tool calls before flushing (debug mode — config or runtime toggle)
4208
+ var toolCalls_1 = (_this.config.debugMode || _this._debugMode) ? __spreadArray$1([], _this.currentToolCalls, true) : undefined;
4178
4209
  _this.flushStreamBuffer().then(function () {
4179
4210
  _this.dispatchStreamEnd(messageId, finalMessage_1, toolCalls_1);
4180
4211
  _this.currentToolCalls = []; // Clear after dispatch
@@ -4269,12 +4300,20 @@ var MCPChat = /** @class */ (function () {
4269
4300
  this._attributes.currentUrl = window.location.href;
4270
4301
  }
4271
4302
  this._accessToken = this.visitorInfo.accessToken;
4272
- // Bot joined is dispatched in init() to ensure correct ordering
4273
- // Show typing indicator if we're still waiting for initial greeting
4303
+ this.startSession(sessionId);
4304
+ // Initialize session now that the widget is visible and visitor info is set.
4305
+ // Returning user with existing session - validate session silently
4306
+ // New user without session - initialize new session to get greeting
4307
+ if (this._sessionId) {
4308
+ this.validateSession();
4309
+ }
4310
+ else {
4311
+ this.initializeNewSession();
4312
+ }
4313
+ // Show typing indicator while waiting for session init response
4274
4314
  if (this.isInitializingSession) {
4275
4315
  this.typing();
4276
4316
  }
4277
- this.startSession(sessionId);
4278
4317
  cb();
4279
4318
  };
4280
4319
  MCPChat.prototype.sendChatRating = function () { };
@@ -10997,6 +11036,14 @@ function isCard(display) {
10997
11036
  function isList(display) {
10998
11037
  return !!display && (display.type === "LIST" || display.type === "CAROUSEL");
10999
11038
  }
11039
+ /**
11040
+ * Is the Display a Table
11041
+ */
11042
+ function isTable(display) {
11043
+ return !!display && display.type === "TABLE"
11044
+ && Array.isArray(display.headers)
11045
+ && Array.isArray(display.rows);
11046
+ }
11000
11047
 
11001
11048
  var CardMiddlewareWidget = function (props) {
11002
11049
  var msg = props.msg, ctx = props.ctx;
@@ -11297,10 +11344,31 @@ var MultiSelectMiddleware = function (next) { return function (props) {
11297
11344
  return next(props);
11298
11345
  }; };
11299
11346
 
11347
+ var Table = function (_a) {
11348
+ var table = _a.table;
11349
+ return (require$$0.jsxs("div", { className: "xappw-table", children: [table.title && require$$0.jsx("div", { className: "xappw-table__header", children: table.title }), require$$0.jsx("div", { className: "xappw-table__container", children: require$$0.jsxs("table", { children: [require$$0.jsx("thead", { children: require$$0.jsx("tr", { children: table.headers.map(function (header, i) { return (require$$0.jsx("th", { scope: "col", children: header }, "".concat(header, "-").concat(i))); }) }) }), require$$0.jsx("tbody", { children: table.rows.map(function (row, rowIndex) { return (require$$0.jsx("tr", { children: row.map(function (cell, cellIndex) { return (require$$0.jsx("td", { children: cell }, cellIndex)); }) }, rowIndex)); }) })] }) })] }));
11350
+ };
11351
+
11352
+ var TableMiddlewareWidget = function (props) {
11353
+ var msg = props.msg, ctx = props.ctx;
11354
+ if (!ctx) {
11355
+ throw new TypeError("ctx not provided to ".concat(TableMiddlewareWidget.name));
11356
+ }
11357
+ return (require$$0.jsx(ChatMessagePart, { showAvatar: false, user: ctx.user, fullWidth: true, children: require$$0.jsx("div", { className: "chat-msg chat-msg--expand", children: require$$0.jsx(Table, { table: msg }) }) }));
11358
+ };
11359
+ var TableMiddleware = function (next) { return function (props) {
11360
+ var msg = props.msg, ctx = props.ctx;
11361
+ if (isTable(msg)) {
11362
+ return require$$0.jsx(TableMiddlewareWidget, { msg: msg, ctx: ctx });
11363
+ }
11364
+ return next(props);
11365
+ }; };
11366
+
11300
11367
  var StandardMiddlewaresBuilder = joinMiddlewares([
11301
11368
  ListMiddleware,
11302
11369
  CardMiddleware,
11303
- MultiSelectMiddleware
11370
+ MultiSelectMiddleware,
11371
+ TableMiddleware
11304
11372
  ]);
11305
11373
  function useStandardMiddlewareBuilder() {
11306
11374
  var lateMiddleware = useLateMiddleware();
@@ -11554,14 +11622,72 @@ var ToolCallDisplay = function (_a) {
11554
11622
  };
11555
11623
 
11556
11624
  /**
11557
- * Parses basic markdown to HTML.
11558
- * Supports: bold, italic, links, headers, and unordered lists.
11625
+ * Escape &, <, >, and " for safe insertion into HTML text nodes and attribute values.
11559
11626
  */
11627
+ function escapeHtml(text) {
11628
+ return text
11629
+ .replace(/&/g, "&amp;")
11630
+ .replace(/</g, "&lt;")
11631
+ .replace(/>/g, "&gt;")
11632
+ .replace(/"/g, "&quot;");
11633
+ }
11634
+ function parseInlineMarkdown(text) {
11635
+ return escapeHtml(text)
11636
+ .replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>")
11637
+ .replace(/__(.+?)__/g, "<strong>$1</strong>")
11638
+ .replace(/\*([^*]+?)\*/g, "<em>$1</em>")
11639
+ .replace(/_([^_]+?)_/g, "<em>$1</em>");
11640
+ }
11641
+ function tableToHtml(headerLine, separatorLine, bodyBlock) {
11642
+ var parseRow = function (row) {
11643
+ return row.split("|").slice(1, -1).map(function (cell) { return parseInlineMarkdown(cell.trim()); });
11644
+ };
11645
+ var separators = separatorLine.split("|").slice(1, -1).map(function (s) { return s.trim(); });
11646
+ var alignments = separators.map(function (sep) {
11647
+ if (sep.startsWith(":") && sep.endsWith(":"))
11648
+ return "center";
11649
+ if (sep.endsWith(":"))
11650
+ return "right";
11651
+ return "left";
11652
+ });
11653
+ var headers = parseRow(headerLine);
11654
+ var headerHtml = headers.map(function (h, i) {
11655
+ return "<th scope=\"col\" style=\"text-align:".concat(alignments[i] || "left", "\">").concat(h, "</th>");
11656
+ }).join("");
11657
+ var bodyRows = bodyBlock.trim().split("\n").filter(function (row) { return row.trim() !== ""; });
11658
+ var bodyHtml = bodyRows.map(function (row) {
11659
+ var cells = parseRow(row);
11660
+ return "<tr>" + cells.map(function (c, i) {
11661
+ return "<td style=\"text-align:".concat(alignments[i] || "left", "\">").concat(c, "</td>");
11662
+ }).join("") + "</tr>";
11663
+ }).join("");
11664
+ return "<div style=\"overflow-x:auto\"><table><thead><tr>".concat(headerHtml, "</tr></thead><tbody>").concat(bodyHtml, "</tbody></table></div>");
11665
+ }
11560
11666
  function parseMarkdown(text) {
11561
11667
  if (!text)
11562
11668
  return "";
11563
- var html = text
11564
- // Escape HTML entities first
11669
+ // Extract fenced code blocks first, replace with placeholders
11670
+ var codeBlocks = [];
11671
+ var processed = text.replace(/```([^\s`]*)\r?\n([\s\S]*?)```/g, function (_match, lang, code) {
11672
+ var escaped = escapeHtml(code.replace(/\n$/, ""));
11673
+ var langAttr = lang ? " data-language=\"".concat(escapeHtml(lang), "\"") : "";
11674
+ codeBlocks.push("<pre><code".concat(langAttr, ">").concat(escaped, "</code></pre>"));
11675
+ return "%%CODEBLOCK".concat(codeBlocks.length - 1, "%%");
11676
+ });
11677
+ // Extract tables, replace with placeholders
11678
+ var tables = [];
11679
+ processed = processed.replace(/(?:^|\n)(\|.+\|)\n(\|[\s:|-]+\|)\n((?:\|.+\|\n?)+)/g, function (_match, headerLine, separatorLine, bodyBlock) {
11680
+ tables.push(tableToHtml(headerLine, separatorLine, bodyBlock));
11681
+ return "\n%%TABLE".concat(tables.length - 1, "%%\n");
11682
+ });
11683
+ // Extract inline code, replace with placeholders
11684
+ var inlineCodes = [];
11685
+ processed = processed.replace(/`([^`\n]+)`/g, function (_match, code) {
11686
+ inlineCodes.push("<code>".concat(escapeHtml(code), "</code>"));
11687
+ return "%%INLINECODE".concat(inlineCodes.length - 1, "%%");
11688
+ });
11689
+ // Now safely escape and parse markdown on the non-table/code text
11690
+ processed = processed
11565
11691
  .replace(/&/g, "&amp;")
11566
11692
  .replace(/</g, "&lt;")
11567
11693
  .replace(/>/g, "&gt;")
@@ -11582,13 +11708,26 @@ function parseMarkdown(text) {
11582
11708
  // Line breaks
11583
11709
  .replace(/\n/g, "<br>");
11584
11710
  // Wrap consecutive <li> elements in <ul>
11585
- html = html.replace(/(<li>.*?<\/li>)(<br>)?/g, "$1");
11586
- html = html.replace(/(<li>.*?<\/li>)+/g, "<ul>$&</ul>");
11711
+ processed = processed.replace(/(<li>.*?<\/li>)(<br>)?/g, "$1");
11712
+ processed = processed.replace(/(<li>.*?<\/li>)+/g, "<ul>$&</ul>");
11587
11713
  // Clean up <br> inside <ul>
11588
- html = html.replace(/<ul>(.*?)<\/ul>/g, function (match) {
11714
+ processed = processed.replace(/<ul>(.*?)<\/ul>/g, function (match) {
11589
11715
  return match.replace(/<br>/g, "");
11590
11716
  });
11591
- return html;
11717
+ // Restore table placeholders (strip adjacent <br> tags)
11718
+ // Use function replacer to avoid $ special-sequence interpretation in replacement strings
11719
+ tables.forEach(function (tableHtml, i) {
11720
+ processed = processed.replace(new RegExp("(?:<br>)?%%TABLE".concat(i, "%%(?:<br>)?")), function () { return tableHtml; });
11721
+ });
11722
+ // Restore code block placeholders (strip adjacent <br> tags)
11723
+ codeBlocks.forEach(function (codeHtml, i) {
11724
+ processed = processed.replace(new RegExp("(?:<br>)?%%CODEBLOCK".concat(i, "%%(?:<br>)?")), function () { return codeHtml; });
11725
+ });
11726
+ // Restore inline code placeholders
11727
+ inlineCodes.forEach(function (codeHtml, i) {
11728
+ processed = processed.replace("%%INLINECODE".concat(i, "%%"), function () { return codeHtml; });
11729
+ });
11730
+ return processed;
11592
11731
  }
11593
11732
  var ChatTextMessage = function (props) {
11594
11733
  var _a;
@@ -35656,7 +35795,7 @@ var ChatWidgetConnected = function (props) {
35656
35795
  * Exported for use by StaticChatWidgetContainer to avoid infinite loops.
35657
35796
  */
35658
35797
  var ChatWidgetUI = function (props) {
35659
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14;
35798
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13;
35660
35799
  var innerDispatch = useChatDispatch();
35661
35800
  var dispatch = useChatServerDispatch();
35662
35801
  // From Redux
@@ -35686,24 +35825,30 @@ var ChatWidgetUI = function (props) {
35686
35825
  chatState.visuals = {};
35687
35826
  }
35688
35827
  // Our state - pull from storage
35689
- var _15 = require$$1.useState((!canMinimize && !canCancel) ||
35828
+ // Parse autoOpenOnWidth once for use in both initial state and useEffect
35829
+ var autoOpenOnWidthValue = ((_m = props.config) === null || _m === void 0 ? void 0 : _m.autoOpenOnWidth)
35830
+ ? parseInt(props.config.autoOpenOnWidth, 10)
35831
+ : NaN;
35832
+ var autoOpenOnWidthMatch = !isNaN(autoOpenOnWidthValue) && window.innerWidth >= autoOpenOnWidthValue;
35833
+ // When autoOpenOnWidth is configured, use width check instead of persisted visible state
35834
+ // to prevent greeting requests on viewports below the threshold
35835
+ var _14 = require$$1.useState((!canMinimize && !canCancel) ||
35690
35836
  // !!get("visible") ||
35691
- chatState.visuals.visible ||
35692
- (((_m = props.config) === null || _m === void 0 ? void 0 : _m.autoOpenOnWidth) &&
35693
- window.matchMedia("(min-width: ".concat((_o = props.config) === null || _o === void 0 ? void 0 : _o.autoOpenOnWidth, ")")).matches)), visible = _15[0], setVisibleState = _15[1];
35694
- var _16 = require$$1.useState(false); _16[0]; var setTypingState = _16[1]; // false initially - state kept for potential external observers
35837
+ (!isNaN(autoOpenOnWidthValue) ? autoOpenOnWidthMatch : chatState.visuals.visible)), visible = _14[0], setVisibleState = _14[1];
35838
+ var _15 = require$$1.useState(false); _15[0]; var setTypingState = _15[1]; // false initially - state kept for potential external observers
35695
35839
  // Ref to track typing state for use in timeout callbacks
35696
35840
  var typingRef = require$$1.useRef(false);
35697
35841
  // Timeout ref for debouncing "stop typing" events
35698
35842
  var stopTypingTimeoutRef = require$$1.useRef(null);
35843
+ // Track whether autoOpenOnWidth has already fired so it doesn't re-open after user closes
35844
+ var autoOpenFiredRef = require$$1.useRef(autoOpenOnWidthMatch);
35699
35845
  var chatServer = require$$1.useContext(ChatServerContext);
35700
- var patternsConfig = (_q = (_p = props.config) === null || _p === void 0 ? void 0 : _p.autoOpenOnPattern) === null || _q === void 0 ? void 0 : _q.patterns;
35846
+ var patternsConfig = (_p = (_o = props.config) === null || _o === void 0 ? void 0 : _o.autoOpenOnPattern) === null || _p === void 0 ? void 0 : _p.patterns;
35701
35847
  var currentUrl = window.location.href;
35702
35848
  var patternExist = patternsConfig && patternsConfig.length > 0;
35703
35849
  var patternMatches = patternsConfig === null || patternsConfig === void 0 ? void 0 : patternsConfig.some(function (pattern) { return currentUrl.includes(pattern); });
35704
- var configWidth = (_s = (_r = props.config) === null || _r === void 0 ? void 0 : _r.autoOpenOnPattern) === null || _s === void 0 ? void 0 : _s.minimumWidth;
35705
- // eslint-disable-next-line no-restricted-globals
35706
- var currentWidth = screen.width;
35850
+ var configWidth = (_r = (_q = props.config) === null || _q === void 0 ? void 0 : _q.autoOpenOnPattern) === null || _r === void 0 ? void 0 : _r.minimumWidth;
35851
+ var currentWidth = window.innerWidth;
35707
35852
  var setVisible = require$$1.useCallback(function (newVisible) {
35708
35853
  if (staticMode || previewMode) {
35709
35854
  return;
@@ -35737,7 +35882,7 @@ var ChatWidgetUI = function (props) {
35737
35882
  };
35738
35883
  // eslint-disable-next-line react-hooks/exhaustive-deps
35739
35884
  }, []);
35740
- var _17 = require$$1.useState(!document.hidden), isTabVisible = _17[0], setIsTabVisible = _17[1];
35885
+ var _16 = require$$1.useState(!document.hidden), isTabVisible = _16[0], setIsTabVisible = _16[1];
35741
35886
  require$$1.useEffect(function () {
35742
35887
  var handleVisibilityChange = function () {
35743
35888
  setIsTabVisible(!document.hidden);
@@ -35786,10 +35931,8 @@ var ChatWidgetUI = function (props) {
35786
35931
  if (chatState.visuals.opened) {
35787
35932
  setVisible(true);
35788
35933
  }
35789
- else {
35790
- if (mode === "normal") {
35791
- setVisible(false);
35792
- }
35934
+ else if (mode === "normal" && !autoOpenOnWidthMatch) {
35935
+ setVisible(false);
35793
35936
  }
35794
35937
  if (patternExist && patternMatches) {
35795
35938
  setVisible(true);
@@ -35797,6 +35940,10 @@ var ChatWidgetUI = function (props) {
35797
35940
  if (currentWidth < +configWidth) {
35798
35941
  setVisible(false);
35799
35942
  }
35943
+ if (autoOpenOnWidthMatch && !autoOpenFiredRef.current) {
35944
+ autoOpenFiredRef.current = true;
35945
+ setVisible(true);
35946
+ }
35800
35947
  }, [
35801
35948
  currentWidth,
35802
35949
  patternExist,
@@ -35805,6 +35952,7 @@ var ChatWidgetUI = function (props) {
35805
35952
  setVisible,
35806
35953
  chatState.visuals.opened,
35807
35954
  mode,
35955
+ autoOpenOnWidthMatch,
35808
35956
  ]);
35809
35957
  var stopTyping = require$$1.useCallback(function () {
35810
35958
  if (!typingRef.current)
@@ -35952,8 +36100,8 @@ var ChatWidgetUI = function (props) {
35952
36100
  }));
35953
36101
  }
35954
36102
  // Action Bar state and handlers
35955
- var _18 = require$$1.useState(false), formModalOpen = _18[0], setFormModalOpen = _18[1];
35956
- var _19 = require$$1.useState(null), activeFormConfig = _19[0], setActiveFormConfig = _19[1];
36103
+ var _17 = require$$1.useState(false), formModalOpen = _17[0], setFormModalOpen = _17[1];
36104
+ var _18 = require$$1.useState(null), activeFormConfig = _18[0], setActiveFormConfig = _18[1];
35957
36105
  var handleFormButtonClick = require$$1.useCallback(function (formButton) {
35958
36106
  // If form-widget is configured, use its openForm API
35959
36107
  // The form-widget script should already be pre-loaded
@@ -36020,7 +36168,7 @@ var ChatWidgetUI = function (props) {
36020
36168
  var messages = chatState && chatState.chats;
36021
36169
  log("Rendering - accountStatus: \"".concat(chatState.accountStatus, "\", connectionStatus: \"").concat(chatState.connection.connectionStatus, "\""));
36022
36170
  var config = props.config, onConnectionStatusChange = props.onConnectionStatusChange;
36023
- var actionBarEnabled = ((_t = config === null || config === void 0 ? void 0 : config.actionBar) === null || _t === void 0 ? void 0 : _t.enabled) === true;
36171
+ var actionBarEnabled = ((_s = config === null || config === void 0 ? void 0 : config.actionBar) === null || _s === void 0 ? void 0 : _s.enabled) === true;
36024
36172
  // Disable greeting in preview mode
36025
36173
  useGreeting(!isOffline && !props.preChatFormEnabled && visible && !previewMode);
36026
36174
  var connectionStatus = chatState.connection.connectionStatus;
@@ -36029,7 +36177,7 @@ var ChatWidgetUI = function (props) {
36029
36177
  onConnectionStatusChange(connectionStatus);
36030
36178
  }
36031
36179
  }, [connectionStatus, onConnectionStatusChange]);
36032
- useExternalScript((_u = props.config) === null || _u === void 0 ? void 0 : _u.middlewareUrl);
36180
+ useExternalScript((_t = props.config) === null || _t === void 0 ? void 0 : _t.middlewareUrl);
36033
36181
  // Pre-load form-widget script if formWidgetKey is provided
36034
36182
  require$$1.useEffect(function () {
36035
36183
  if (config === null || config === void 0 ? void 0 : config.formWidgetKey) {
@@ -36061,15 +36209,15 @@ var ChatWidgetUI = function (props) {
36061
36209
  };
36062
36210
  }, [actionBarEnabled]);
36063
36211
  // This is a pseudo agent. It represent's the widget (shown in the header avatar for instance)
36064
- var widgetAgent = ((_v = chatState.agents["agent:robot"]) === null || _v === void 0 ? void 0 : _v.user) ||
36212
+ var widgetAgent = ((_u = chatState.agents["agent:robot"]) === null || _u === void 0 ? void 0 : _u.user) ||
36065
36213
  (config === null || config === void 0 ? void 0 : config.agent) || {
36066
36214
  nick: "agent:robot",
36067
36215
  avatarPath: config.avatarUrl,
36068
36216
  display_name: "Agent",
36069
36217
  };
36070
- return (require$$0.jsxs(require$$0.Fragment, { children: [require$$0.jsxs("div", { className: "widget-container ".concat(modeClass, " ").concat(getVisibilityClass()).concat(actionBarEnabled ? " widget-container--with-action-bar" : ""), children: [require$$0.jsx(WidgetStylesheet, { theme: config === null || config === void 0 ? void 0 : config.theme }), require$$0.jsx(ChatHeader, { accountStatus: chatState.accountStatus, refreshOnClick: handleRestartClick, minimizeOnClick: handleMinimizeClick, cancelOnClick: handleCancelClick, agent: widgetAgent, canRefresh: canRefresh, canMinimize: canMinimize, canCancel: canCancel, config: config === null || config === void 0 ? void 0 : config.header, menuConfig: config.menu, debugMode: (_y = (_x = (_w = props.config) === null || _w === void 0 ? void 0 : _w.connection) === null || _x === void 0 ? void 0 : _x.mcp) === null || _y === void 0 ? void 0 : _y.debugMode, onSubmit: handleOnSubmit }), require$$0.jsx(MessageList, { visible: visible, queuePosition: chatState.queuePosition, isChatting: chatState.isChatting, isOffline: isOffline, messages: messages, agents: chatState.agents, agent: config === null || config === void 0 ? void 0 : config.agent, lastRatingRequestTimestamp: chatState.lastRatingRequestTimestamp, hasRating: chatState.hasRating, visitorId: chatState.visitorId, hasWsButton: !!chatState.wsButton, messageMiddleware: props.messageMiddleware, textTypingStatusEnabled: (_0 = (_z = props.config) === null || _z === void 0 ? void 0 : _z.typingStatus) === null || _0 === void 0 ? void 0 : _0.textTypingStatusEnabled, disableAutoScroll: props.disableAutoScroll, onSend: handleSendMessage, onWrite: handleWriteMessage, onOpenUrl: handleOpenUrl, minimizeOnClick: handleMinimizeClick }), require$$0.jsx("div", { className: "xa-spinner-container ".concat(visible && connectionStatus === "pending" ? "visible" : ""), children: require$$0.jsx("div", { className: "xa-spinner" }) }), connectionStatus === "offline" && require$$0.jsx(ServerOffline, {}), chatState.wsButton && visible && (require$$0.jsx(WsButton, { button: chatState.wsButton, onPress: handleWsButtonPress })), require$$0.jsx(ChatFooter, { isAdmin: config === null || config === void 0 ? void 0 : config.isAdmin, isChatting: chatState.isChatting, placeholder: (_1 = config === null || config === void 0 ? void 0 : config.input) === null || _1 === void 0 ? void 0 : _1.placeholder, sendButtonIcon: (_3 = (_2 = config === null || config === void 0 ? void 0 : config.footer) === null || _2 === void 0 ? void 0 : _2.sendButton) === null || _3 === void 0 ? void 0 : _3.icon, sendButtonIconHover: (_5 = (_4 = config === null || config === void 0 ? void 0 : config.footer) === null || _4 === void 0 ? void 0 : _4.sendButton) === null || _5 === void 0 ? void 0 : _5.iconHover, sendButtonIconDisabled: (_7 = (_6 = config === null || config === void 0 ? void 0 : config.footer) === null || _6 === void 0 ? void 0 : _6.sendButton) === null || _7 === void 0 ? void 0 : _7.iconDisabled, visible: visible, hasWsButton: !!chatState.wsButton, menuConfig: (_8 = props.config) === null || _8 === void 0 ? void 0 : _8.menu, footerConfig: (_9 = props.config) === null || _9 === void 0 ? void 0 : _9.footer, inputConfig: (_10 = props.config) === null || _10 === void 0 ? void 0 : _10.input, disabled: previewMode, onChange: handleOnChange, onSubmit: handleOnSubmit, onFileUpload: handleFileUpload }), require$$0.jsx("div", { className: "restartModal", ref: modalRef, onClick: handleRestartModalCloseClick, children: require$$0.jsx(ModalContent, { onClose: handleRestartModalCloseClick, onReset: handleReset }) })] }), actionBarEnabled && config.actionBar ? (require$$0.jsxs(require$$0.Fragment, { children: [require$$0.jsx(ActionBar, { config: __assign(__assign({}, config.actionBar), {
36218
+ return (require$$0.jsxs(require$$0.Fragment, { children: [require$$0.jsxs("div", { className: "widget-container ".concat(modeClass, " ").concat(getVisibilityClass()).concat(actionBarEnabled ? " widget-container--with-action-bar" : ""), children: [require$$0.jsx(WidgetStylesheet, { theme: config === null || config === void 0 ? void 0 : config.theme }), require$$0.jsx(ChatHeader, { accountStatus: chatState.accountStatus, refreshOnClick: handleRestartClick, minimizeOnClick: handleMinimizeClick, cancelOnClick: handleCancelClick, agent: widgetAgent, canRefresh: canRefresh, canMinimize: canMinimize, canCancel: canCancel, config: config === null || config === void 0 ? void 0 : config.header, menuConfig: config.menu, debugMode: (_x = (_w = (_v = props.config) === null || _v === void 0 ? void 0 : _v.connection) === null || _w === void 0 ? void 0 : _w.mcp) === null || _x === void 0 ? void 0 : _x.debugMode, onSubmit: handleOnSubmit }), require$$0.jsx(MessageList, { visible: visible, queuePosition: chatState.queuePosition, isChatting: chatState.isChatting, isOffline: isOffline, messages: messages, agents: chatState.agents, agent: config === null || config === void 0 ? void 0 : config.agent, lastRatingRequestTimestamp: chatState.lastRatingRequestTimestamp, hasRating: chatState.hasRating, visitorId: chatState.visitorId, hasWsButton: !!chatState.wsButton, messageMiddleware: props.messageMiddleware, textTypingStatusEnabled: (_z = (_y = props.config) === null || _y === void 0 ? void 0 : _y.typingStatus) === null || _z === void 0 ? void 0 : _z.textTypingStatusEnabled, disableAutoScroll: props.disableAutoScroll, onSend: handleSendMessage, onWrite: handleWriteMessage, onOpenUrl: handleOpenUrl, minimizeOnClick: handleMinimizeClick }), require$$0.jsx("div", { className: "xa-spinner-container ".concat(visible && connectionStatus === "pending" ? "visible" : ""), children: require$$0.jsx("div", { className: "xa-spinner" }) }), connectionStatus === "offline" && require$$0.jsx(ServerOffline, {}), chatState.wsButton && visible && (require$$0.jsx(WsButton, { button: chatState.wsButton, onPress: handleWsButtonPress })), require$$0.jsx(ChatFooter, { isAdmin: config === null || config === void 0 ? void 0 : config.isAdmin, isChatting: chatState.isChatting, placeholder: (_0 = config === null || config === void 0 ? void 0 : config.input) === null || _0 === void 0 ? void 0 : _0.placeholder, sendButtonIcon: (_2 = (_1 = config === null || config === void 0 ? void 0 : config.footer) === null || _1 === void 0 ? void 0 : _1.sendButton) === null || _2 === void 0 ? void 0 : _2.icon, sendButtonIconHover: (_4 = (_3 = config === null || config === void 0 ? void 0 : config.footer) === null || _3 === void 0 ? void 0 : _3.sendButton) === null || _4 === void 0 ? void 0 : _4.iconHover, sendButtonIconDisabled: (_6 = (_5 = config === null || config === void 0 ? void 0 : config.footer) === null || _5 === void 0 ? void 0 : _5.sendButton) === null || _6 === void 0 ? void 0 : _6.iconDisabled, visible: visible, hasWsButton: !!chatState.wsButton, menuConfig: (_7 = props.config) === null || _7 === void 0 ? void 0 : _7.menu, footerConfig: (_8 = props.config) === null || _8 === void 0 ? void 0 : _8.footer, inputConfig: (_9 = props.config) === null || _9 === void 0 ? void 0 : _9.input, disabled: previewMode, onChange: handleOnChange, onSubmit: handleOnSubmit, onFileUpload: handleFileUpload }), require$$0.jsx("div", { className: "restartModal", ref: modalRef, onClick: handleRestartModalCloseClick, children: require$$0.jsx(ModalContent, { onClose: handleRestartModalCloseClick, onReset: handleReset }) })] }), actionBarEnabled && config.actionBar ? (require$$0.jsxs(require$$0.Fragment, { children: [require$$0.jsx(ActionBar, { config: __assign(__assign({}, config.actionBar), {
36071
36219
  // Use actionBar.cta if set, otherwise fall back to widget-level cta
36072
- cta: (_11 = config.actionBar.cta) !== null && _11 !== void 0 ? _11 : config.cta }), visible: visible, chatDisabled: config.disabled, hasUserInteracted: (_12 = chatState.visuals) === null || _12 === void 0 ? void 0 : _12.hasInteracted, onChatClick: chatButtonOnClick, onChatMinimize: handleMinimizeClick, onFormClick: handleFormButtonClick, onCtaDismiss: handleCtaDismiss }), formModalOpen && activeFormConfig && (require$$0.jsx(FormModal, { config: activeFormConfig, widgetEnv: config, onClose: handleFormModalClose }))] })) : (require$$0.jsx(ChatButton, { addClass: visible ? "visible" : "", onClick: chatButtonOnClick, config: config === null || config === void 0 ? void 0 : config.cta, imageUrl: (_13 = config === null || config === void 0 ? void 0 : config.chatButton) === null || _13 === void 0 ? void 0 : _13.imageUrl, visible: visible, hasInteracted: (_14 = chatState.visuals) === null || _14 === void 0 ? void 0 : _14.hasInteracted, onCtaDismiss: handleCtaDismiss })), require$$0.jsx(ErrorOverlay, { enableErrorOverlay: config === null || config === void 0 ? void 0 : config.enableErrorOverlay })] }));
36220
+ cta: (_10 = config.actionBar.cta) !== null && _10 !== void 0 ? _10 : config.cta }), visible: visible, chatDisabled: config.disabled, hasUserInteracted: (_11 = chatState.visuals) === null || _11 === void 0 ? void 0 : _11.hasInteracted, onChatClick: chatButtonOnClick, onChatMinimize: handleMinimizeClick, onFormClick: handleFormButtonClick, onCtaDismiss: handleCtaDismiss }), formModalOpen && activeFormConfig && (require$$0.jsx(FormModal, { config: activeFormConfig, widgetEnv: config, onClose: handleFormModalClose }))] })) : (require$$0.jsx(ChatButton, { addClass: visible ? "visible" : "", onClick: chatButtonOnClick, config: config === null || config === void 0 ? void 0 : config.cta, imageUrl: (_12 = config === null || config === void 0 ? void 0 : config.chatButton) === null || _12 === void 0 ? void 0 : _12.imageUrl, visible: visible, hasInteracted: (_13 = chatState.visuals) === null || _13 === void 0 ? void 0 : _13.hasInteracted, onCtaDismiss: handleCtaDismiss })), require$$0.jsx(ErrorOverlay, { enableErrorOverlay: config === null || config === void 0 ? void 0 : config.enableErrorOverlay })] }));
36073
36221
  };
36074
36222
  /**
36075
36223
  * Top-level wrapper that dispatches between preview mode and connected mode.
@@ -36162,9 +36310,10 @@ var LocalStorage = /** @class */ (function () {
36162
36310
  function persistStateReducer(storage, initialState, innerReducer) {
36163
36311
  var _a;
36164
36312
  var obj = (_a = storage.get()) !== null && _a !== void 0 ? _a : initialState;
36165
- // Clean up hasInteracted flag on page load - don't persist across browser refreshes
36313
+ // Clean up transient visual state on page load - don't persist across browser refreshes
36314
+ // visible is derived from config (autoOpenOnWidth, autoOpenOnPattern) and visuals.opened
36166
36315
  if (obj && obj.visuals) {
36167
- obj = __assign(__assign({}, obj), { visuals: __assign(__assign({}, obj.visuals), { hasInteracted: undefined }) });
36316
+ obj = __assign(__assign({}, obj), { visuals: __assign(__assign({}, obj.visuals), { hasInteracted: undefined, visible: undefined }) });
36168
36317
  }
36169
36318
  return function (state, action) {
36170
36319
  if (state === void 0) { state = obj; }
@@ -36498,13 +36647,13 @@ function update(state, action) {
36498
36647
  var _a;
36499
36648
  if (index === streamingIndex_3 && isChatMsgDetail(chat)) {
36500
36649
  var toolCalls = (_a = chat.toolCalls) === null || _a === void 0 ? void 0 : _a.map(function (tc) {
36501
- var _a;
36650
+ var _a, _b;
36502
36651
  // Match by toolCallId if available, otherwise fall back to name + isExecuting
36503
36652
  var isMatch = toolEndDetail_1.toolCallId
36504
36653
  ? tc.toolCallId === toolEndDetail_1.toolCallId
36505
36654
  : tc.name === toolEndDetail_1.toolName && tc.isExecuting;
36506
36655
  if (isMatch) {
36507
- return __assign(__assign({}, tc), { displayName: toolEndDetail_1.displayName || tc.displayName, label: toolEndDetail_1.label, hidden: (_a = toolEndDetail_1.hidden) !== null && _a !== void 0 ? _a : tc.hidden, result: toolEndDetail_1.toolResult, error: toolEndDetail_1.toolError, endTime: toolEndDetail_1.timestamp, isExecuting: false });
36656
+ return __assign(__assign({}, tc), { displayName: toolEndDetail_1.displayName || tc.displayName, label: toolEndDetail_1.label, hidden: (_a = toolEndDetail_1.hidden) !== null && _a !== void 0 ? _a : tc.hidden, input: (_b = toolEndDetail_1.toolInput) !== null && _b !== void 0 ? _b : tc.input, result: toolEndDetail_1.toolResult, error: toolEndDetail_1.toolError, endTime: toolEndDetail_1.timestamp, isExecuting: false });
36508
36657
  }
36509
36658
  return tc;
36510
36659
  });