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