react-instantsearch 7.48.0 → 7.49.1

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,4 +1,4 @@
1
- /*! React InstantSearch 7.48.0 | © Algolia, Inc. and contributors; MIT License | https://github.com/algolia/instantsearch */
1
+ /*! React InstantSearch 7.49.1 | © Algolia, Inc. and contributors; MIT License | https://github.com/algolia/instantsearch */
2
2
  (function (global, factory) {
3
3
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react')) :
4
4
  typeof define === 'function' && define.amd ? define(['exports', 'react'], factory) :
@@ -24,7 +24,7 @@
24
24
 
25
25
  var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
26
26
 
27
- var version$2 = '7.48.0';
27
+ var version$2 = '7.49.1';
28
28
 
29
29
  function _define_property(obj, key, value) {
30
30
  if (key in obj) {
@@ -9392,7 +9392,7 @@
9392
9392
  });
9393
9393
  }
9394
9394
 
9395
- var version = '4.115.0';
9395
+ var version = '4.117.0';
9396
9396
 
9397
9397
  var ANONYMOUS_TOKEN_COOKIE_KEY = '_ALGOLIA';
9398
9398
  function getCookie(name) {
@@ -14580,6 +14580,7 @@
14580
14580
  var translations = _object_spread({
14581
14581
  messageLabel: 'Message',
14582
14582
  actionsLabel: 'Message actions',
14583
+ toolErrorRetryText: 'Retry',
14583
14584
  reasoningLabel: 'Reasoning'
14584
14585
  }, userTranslations);
14585
14586
  // A message rendered without a connector-attached store falls back to
@@ -14615,7 +14616,11 @@
14615
14616
  var isReasoningStreaming = reasoningParts.some(function(part) {
14616
14617
  return part.isStreaming;
14617
14618
  });
14618
- var showActions = Boolean(actions.length > 0 || ActionsComponent) && status === 'ready';
14619
+ // `status` is the chat's, not the row's: gating every row on it took the
14620
+ // actions off completed answers the moment a follow-up turn started,
14621
+ // reflowing rows the turn hasn't touched. Only the row the turn is
14622
+ // producing waits for the status to settle.
14623
+ var showActions = Boolean(actions.length > 0 || ActionsComponent) && (status === 'ready' || !isCurrentMessage);
14619
14624
  var cssClasses = {
14620
14625
  root: cx('ais-ChatMessage', "ais-ChatMessage--".concat(side), "ais-ChatMessage--".concat(variant), autoHideActions && 'ais-ChatMessage--auto-hide-actions', classNames.root),
14621
14626
  container: cx('ais-ChatMessage-container', classNames.container),
@@ -14674,11 +14679,7 @@
14674
14679
  });
14675
14680
  }
14676
14681
  if (part.type === 'text') {
14677
- // Back-compat shim for sessions started before the move from a
14678
- // `<context>{...}</context>` text part to `metadata.turnContext`.
14679
- // Safe to remove once existing sessionStorage transcripts have
14680
- // rolled over (~2 weeks after release).
14681
- if (part.text.startsWith('<context>') && part.text.endsWith('</context>')) {
14682
+ if (isPartTextEmpty(part)) {
14682
14683
  return null;
14683
14684
  }
14684
14685
  if (TextComponent) {
@@ -14740,7 +14741,30 @@
14740
14741
  return null;
14741
14742
  }
14742
14743
  if (!ToolLayoutComponent) {
14743
- return null;
14744
+ if (toolMessage.state !== 'output-error') {
14745
+ return null;
14746
+ }
14747
+ var messageIndex = messages.findIndex(function(candidate) {
14748
+ return candidate.id === message.id;
14749
+ });
14750
+ var canRetry = tool.retryOnError === true && Boolean(tool.onToolCall) && status === 'ready' && messageIndex >= 0 && !messages.slice(messageIndex + 1).some(function(candidate) {
14751
+ return candidate.role === 'user';
14752
+ });
14753
+ return /*#__PURE__*/ createElement("div", {
14754
+ key: "".concat(message.id, "-").concat(index),
14755
+ className: "ais-ChatMessage-tool ais-ChatMessage-toolError"
14756
+ }, /*#__PURE__*/ createElement("span", {
14757
+ className: "ais-ChatMessage-toolError-message"
14758
+ }, toolMessage.errorText || 'Tool call failed.'), canRetry && /*#__PURE__*/ createElement(Button, {
14759
+ variant: "primary",
14760
+ size: "sm",
14761
+ className: "ais-ChatMessage-toolError-action",
14762
+ onClick: function onClick() {
14763
+ return context.onReload(message.id);
14764
+ }
14765
+ }, /*#__PURE__*/ createElement(ReloadIcon, {
14766
+ createElement: createElement
14767
+ }), translations.toolErrorRetryText));
14744
14768
  }
14745
14769
  var toolSendEvent = tool.sendEvent || function() {};
14746
14770
  var agentId = (_tool_insightsEventContext = tool.insightsEventContext) === null || _tool_insightsEventContext === void 0 ? void 0 : _tool_insightsEventContext.agentId;
@@ -14776,6 +14800,13 @@
14776
14800
  }
14777
14801
  return null;
14778
14802
  }
14803
+ var renderedParts = message.parts.map(renderMessagePart);
14804
+ var hasRenderedParts = renderedParts.some(function(part) {
14805
+ return part != null;
14806
+ });
14807
+ if (!hasRenderedParts && !loaderElement && !(ActionsComponent && showActions) && !FooterComponent) {
14808
+ return suggestionsElement !== null && suggestionsElement !== void 0 ? suggestionsElement : null;
14809
+ }
14779
14810
  return /*#__PURE__*/ createElement("article", _object_spread_props(_object_spread({}, props), {
14780
14811
  className: cx(cssClasses.root, props.className),
14781
14812
  "aria-label": translations.messageLabel
@@ -14787,7 +14818,7 @@
14787
14818
  className: cx(cssClasses.content)
14788
14819
  }, /*#__PURE__*/ createElement("div", {
14789
14820
  className: cx(cssClasses.message)
14790
- }, message.parts.map(renderMessagePart), loaderElement), suggestionsElement, showActions && /*#__PURE__*/ createElement("div", {
14821
+ }, renderedParts, loaderElement), suggestionsElement, showActions && /*#__PURE__*/ createElement("div", {
14791
14822
  className: cx(cssClasses.actions),
14792
14823
  "aria-label": translations.actionsLabel
14793
14824
  }, ActionsComponent ? /*#__PURE__*/ createElement(ActionsComponent, {
@@ -15286,7 +15317,7 @@
15286
15317
  return Promise.resolve();
15287
15318
  } : _userProps_regenerate, _userProps_stop = userProps.stop, stop = _userProps_stop === void 0 ? function() {
15288
15319
  return Promise.resolve();
15289
- } : _userProps_stop, _userProps_open = userProps.open, open = _userProps_open === void 0 ? false : _userProps_open, _userProps_maximized = userProps.maximized, maximized = _userProps_maximized === void 0 ? false : _userProps_maximized, setInput = userProps.setInput, userTranslations = userProps.translations, userMessageProps = userProps.userMessageProps, assistantMessageProps = userProps.assistantMessageProps, _userProps_isClearing = userProps.isClearing, isClearing = _userProps_isClearing === void 0 ? false : _userProps_isClearing, onClearTransitionEnd = userProps.onClearTransitionEnd, isScrollAtBottom = userProps.isScrollAtBottom, scrollRef = userProps.scrollRef, contentRef = userProps.contentRef, onScrollToBottom = userProps.onScrollToBottom, suggestionsElement = userProps.suggestionsElement, _userProps_suggestionsLoading = userProps.suggestionsLoading, suggestionsLoading = _userProps_suggestionsLoading === void 0 ? false : _userProps_suggestionsLoading, onFeedback = userProps.onFeedback, feedbackState = userProps.feedbackState, props = _object_without_properties(userProps, [
15320
+ } : _userProps_stop, _userProps_open = userProps.open, open = _userProps_open === void 0 ? false : _userProps_open, _userProps_maximized = userProps.maximized, maximized = _userProps_maximized === void 0 ? false : _userProps_maximized, setInput = userProps.setInput, userTranslations = userProps.translations, userMessageProps = userProps.userMessageProps, assistantMessageProps = userProps.assistantMessageProps, _userProps_isClearing = userProps.isClearing, isClearing = _userProps_isClearing === void 0 ? false : _userProps_isClearing, onClearTransitionEnd = userProps.onClearTransitionEnd, isScrollAtBottom = userProps.isScrollAtBottom, scrollRef = userProps.scrollRef, contentRef = userProps.contentRef, onScrollToBottom = userProps.onScrollToBottom, suggestionsElement = userProps.suggestionsElement, onFeedback = userProps.onFeedback, feedbackState = userProps.feedbackState, props = _object_without_properties(userProps, [
15290
15321
  "classNames",
15291
15322
  "messageClassNames",
15292
15323
  "messageTranslations",
@@ -15325,7 +15356,6 @@
15325
15356
  "contentRef",
15326
15357
  "onScrollToBottom",
15327
15358
  "suggestionsElement",
15328
- "suggestionsLoading",
15329
15359
  "onFeedback",
15330
15360
  "feedbackState"
15331
15361
  ]);
@@ -15415,9 +15445,6 @@
15415
15445
  loaderText: loaderText
15416
15446
  }
15417
15447
  }) : undefined;
15418
- // Waits for the answer's text and for the loader to step aside, so two
15419
- // progress affordances never stack up.
15420
- var showPendingSuggestions = suggestionsLoading && !showLoader && lastMessage !== undefined && hasTextContent(lastMessage);
15421
15448
  return /*#__PURE__*/ createElement("div", _object_spread_props(_object_spread({}, props), {
15422
15449
  className: cx(cssClasses.root, props.className),
15423
15450
  role: "log",
@@ -15461,7 +15488,7 @@
15461
15488
  classNames: messageClassNames,
15462
15489
  messageTranslations: messageTranslations,
15463
15490
  context: context,
15464
- suggestionsElement: (status === 'ready' || showPendingSuggestions) && message.role === 'assistant' && index === messages.length - 1 ? suggestionsElement : undefined,
15491
+ suggestionsElement: status === 'ready' && message.role === 'assistant' && index === messages.length - 1 ? suggestionsElement : undefined,
15465
15492
  loaderElement: isLoaderInline && index === messages.length - 1 ? loaderElement : undefined
15466
15493
  });
15467
15494
  }), !isLoaderInline && loaderElement, status === 'error' && /*#__PURE__*/ createElement(DefaultError, {
@@ -15527,9 +15554,13 @@
15527
15554
  if (status !== 'submitted' && status !== 'streaming') return false;
15528
15555
  if (status === 'submitted') return true;
15529
15556
  var lastMessage = messages[messages.length - 1];
15557
+ // `processStream` sets `streaming` before the `start` chunk pushes the
15558
+ // assistant. Until then the last message is still the user's, and its text
15559
+ // must not be read as the answer or the loader hides and comes back.
15560
+ if ((lastMessage === null || lastMessage === void 0 ? void 0 : lastMessage.role) !== 'assistant') return true;
15530
15561
  // Parts that render nothing must not answer for the turn's progress, or the
15531
15562
  // loader flips on a part that changed nothing on screen.
15532
- var lastPart = findLastProgressPart(lastMessage === null || lastMessage === void 0 ? void 0 : lastMessage.parts);
15563
+ var lastPart = findLastProgressPart(lastMessage.parts);
15533
15564
  if (!lastPart) return true;
15534
15565
  // An active disclosure carries its own progress affordance, so the loader would
15535
15566
  // double it. Settled reasoning still shows it: the answer has not started.
@@ -15765,31 +15796,23 @@
15765
15796
  createElement: createElement
15766
15797
  });
15767
15798
  return function ChatPromptSuggestions(userProps) {
15768
- var _userProps_suggestions = userProps.suggestions, suggestions = _userProps_suggestions === void 0 ? [] : _userProps_suggestions, onSuggestionClick = userProps.onSuggestionClick, _userProps_isLoading = userProps.isLoading, isLoading = _userProps_isLoading === void 0 ? false : _userProps_isLoading, _userProps_skeletonCount = userProps.skeletonCount, skeletonCount = _userProps_skeletonCount === void 0 ? 3 : _userProps_skeletonCount, _userProps_classNames = userProps.classNames, classNames = _userProps_classNames === void 0 ? {} : _userProps_classNames;
15799
+ var _userProps_suggestions = userProps.suggestions, suggestions = _userProps_suggestions === void 0 ? [] : _userProps_suggestions, onSuggestionClick = userProps.onSuggestionClick, _userProps_classNames = userProps.classNames, classNames = _userProps_classNames === void 0 ? {} : _userProps_classNames;
15769
15800
  var visibleSuggestions = suggestions.filter(function(suggestion) {
15770
15801
  return suggestion.trim() !== '';
15771
15802
  });
15772
- if (visibleSuggestions.length === 0 && !isLoading) {
15803
+ if (visibleSuggestions.length === 0) {
15773
15804
  return null;
15774
15805
  }
15775
15806
  return /*#__PURE__*/ createElement("div", {
15776
15807
  className: cx('ais-ChatPromptSuggestions', classNames.root)
15777
- }, isLoading && visibleSuggestions.length === 0 ? _to_consumable_array(new Array(skeletonCount)).map(function(_, index) {
15778
- return /*#__PURE__*/ createElement("div", {
15779
- key: index,
15780
- className: cx('ais-ChatPromptSuggestions-skeletonItem', classNames.skeletonItem)
15781
- });
15782
- }) : visibleSuggestions.map(function(suggestion, index) {
15808
+ }, visibleSuggestions.map(function(suggestion, index) {
15783
15809
  return /*#__PURE__*/ createElement(Button, {
15784
15810
  key: index,
15785
15811
  size: "sm",
15786
15812
  variant: "primary",
15787
15813
  className: cx('ais-ChatPromptSuggestions-suggestion', classNames.suggestion),
15788
- // A half-written suggestion can't be sent. Not `disabled`,
15789
- // which would restyle the pill mid-stream.
15790
15814
  onClick: function onClick() {
15791
- if (isLoading) return;
15792
- onSuggestionClick(suggestion);
15815
+ return onSuggestionClick(suggestion);
15793
15816
  }
15794
15817
  }, suggestion);
15795
15818
  }));
@@ -15882,7 +15905,6 @@
15882
15905
  error: error,
15883
15906
  classNames: classNames.messages,
15884
15907
  messageClassNames: classNames.message,
15885
- suggestionsLoading: suggestionsProps.isLoading,
15886
15908
  suggestionsElement: createElement(SuggestionsComponent || ChatPromptSuggestions, _object_spread_props(_object_spread({}, suggestionsProps), {
15887
15909
  classNames: classNames.suggestions
15888
15910
  }))
@@ -17919,6 +17941,26 @@
17919
17941
  var _computedKey$1;
17920
17942
  var defaultGuardrailFallbackResponse = 'Sorry, we are not able to generate a response at the moment.';
17921
17943
  var TOOL_CALL_CANCELLED_ERROR_TEXT = 'The tool call was cancelled: the conversation moved on before a result was provided.';
17944
+ var RESTORED_TOOL_CALL_ERROR_TEXT = 'The page was reloaded before a tool result was received. The operation may have completed.';
17945
+ var RESTORED_TOOL_INPUT_ERROR_TEXT = 'The page was reloaded before the tool input was complete. The operation was not started.';
17946
+ function getTerminalToolState(options) {
17947
+ if (options.state === 'output-error') {
17948
+ return {
17949
+ state: 'output-error',
17950
+ errorText: options.errorText || 'Tool call failed.'
17951
+ };
17952
+ }
17953
+ if (options.state === undefined && 'errorText' in options && typeof options.errorText === 'string') {
17954
+ return {
17955
+ state: 'output-error',
17956
+ errorText: options.errorText || 'Tool call failed.'
17957
+ };
17958
+ }
17959
+ return {
17960
+ state: 'output-available',
17961
+ output: options.output
17962
+ };
17963
+ }
17922
17964
  function getToolName(part) {
17923
17965
  if (part.type === 'dynamic-tool') {
17924
17966
  var _part_toolName;
@@ -17956,7 +17998,7 @@
17956
17998
  */ var AbstractChat = /*#__PURE__*/ function() {
17957
17999
  function AbstractChat(param) {
17958
18000
  var _this = this;
17959
- var _param_generateId = param.generateId, generateId$1 = _param_generateId === void 0 ? generateId : _param_generateId, _param_id = param.id, id = _param_id === void 0 ? generateId$1() : _param_id, transport = param.transport, state = param.state, onError = param.onError, onToolCall = param.onToolCall, onFinish = param.onFinish, onData = param.onData, sendAutomaticallyWhen = param.sendAutomaticallyWhen, shouldRepairToolInput = param.shouldRepairToolInput, resolveCancelledToolOutput = param.resolveCancelledToolOutput;
18001
+ var _param_generateId = param.generateId, generateId$1 = _param_generateId === void 0 ? generateId : _param_generateId, _param_id = param.id, id = _param_id === void 0 ? generateId$1() : _param_id, transport = param.transport, state = param.state, onError = param.onError, onToolCall = param.onToolCall, onFinish = param.onFinish, onData = param.onData, sendAutomaticallyWhen = param.sendAutomaticallyWhen, shouldRepairToolInput = param.shouldRepairToolInput, shouldRepairRestoredPendingToolPart = param.shouldRepairRestoredPendingToolPart, resolveCancelledToolOutput = param.resolveCancelledToolOutput;
17960
18002
  var _this1 = this;
17961
18003
  _class_call_check(this, AbstractChat);
17962
18004
  _define_property(this, "conversationId", void 0);
@@ -17969,11 +18011,13 @@
17969
18011
  _define_property(this, "onData", void 0);
17970
18012
  _define_property(this, "sendAutomaticallyWhen", void 0);
17971
18013
  _define_property(this, "shouldRepairToolInput", void 0);
18014
+ _define_property(this, "shouldRepairRestoredPendingToolPart", void 0);
17972
18015
  _define_property(this, "resolveCancelledToolOutput", void 0);
17973
18016
  _define_property(this, "activeResponse", null);
17974
18017
  _define_property(this, "latestResponse", null);
17975
18018
  _define_property(this, "responsesByToolCallId", new Map());
17976
18019
  _define_property(this, "responseByMessage", new WeakMap());
18020
+ _define_property(this, "restoredToolCalls", void 0);
17977
18021
  // Once tool ownership is discarded, an identifier-only result cannot prove
17978
18022
  // which response generation submitted it. Scoped submissions remain safe.
17979
18023
  _define_property(this, "acceptsIdentifierOnlyToolResults", true);
@@ -18141,7 +18185,7 @@
18141
18185
  warnInvalidGlobalToolResult(options.toolCallId);
18142
18186
  return Promise.resolve();
18143
18187
  }
18144
- if (!_this.commit(options.toolCallId, options.output, message.id, undefined, message)) {
18188
+ if (!_this.commit(options.toolCallId, getTerminalToolState(options), message.id, undefined, message)) {
18145
18189
  return Promise.resolve();
18146
18190
  }
18147
18191
  return _this.continueResponse();
@@ -18188,6 +18232,7 @@
18188
18232
  this.onData = onData;
18189
18233
  this.sendAutomaticallyWhen = sendAutomaticallyWhen;
18190
18234
  this.shouldRepairToolInput = shouldRepairToolInput;
18235
+ this.shouldRepairRestoredPendingToolPart = shouldRepairRestoredPendingToolPart;
18191
18236
  this.resolveCancelledToolOutput = resolveCancelledToolOutput;
18192
18237
  }
18193
18238
  _create_class(AbstractChat, [
@@ -18360,7 +18405,7 @@
18360
18405
  },
18361
18406
  {
18362
18407
  key: "commit",
18363
- value: function commit(toolCallId, output, messageId, response, expectedMessage) {
18408
+ value: function commit(toolCallId, terminalState, messageId, response, expectedMessage) {
18364
18409
  var isTargetPart = function isTargetPart(part) {
18365
18410
  return 'toolCallId' in part && part.toolCallId === toolCallId;
18366
18411
  };
@@ -18375,10 +18420,7 @@
18375
18420
  return false;
18376
18421
  }
18377
18422
  var updatedParts = _to_consumable_array(message.parts);
18378
- updatedParts[partIndex] = withTerminalToolState(part, {
18379
- state: 'output-available',
18380
- output: output
18381
- });
18423
+ updatedParts[partIndex] = withTerminalToolState(part, terminalState);
18382
18424
  var updatedMessage = _object_spread_props(_object_spread({}, message), {
18383
18425
  parts: updatedParts
18384
18426
  });
@@ -18386,6 +18428,60 @@
18386
18428
  return true;
18387
18429
  }
18388
18430
  },
18431
+ {
18432
+ key: "captureRestoredToolCalls",
18433
+ value: function captureRestoredToolCalls() {
18434
+ var restoredToolCalls = new Map();
18435
+ this.messages.forEach(function(message) {
18436
+ message.parts.forEach(function(part) {
18437
+ var _restoredToolCalls_get;
18438
+ if (!isPendingToolPart(part)) return;
18439
+ var toolCallIds = (_restoredToolCalls_get = restoredToolCalls.get(message.id)) !== null && _restoredToolCalls_get !== void 0 ? _restoredToolCalls_get : new Set();
18440
+ toolCallIds.add(part.toolCallId);
18441
+ restoredToolCalls.set(message.id, toolCallIds);
18442
+ });
18443
+ });
18444
+ this.restoredToolCalls = restoredToolCalls;
18445
+ }
18446
+ },
18447
+ {
18448
+ key: "clearRestoredToolCalls",
18449
+ value: function clearRestoredToolCalls() {
18450
+ this.restoredToolCalls = undefined;
18451
+ }
18452
+ },
18453
+ {
18454
+ key: "repairRestoredPendingToolParts",
18455
+ value: function repairRestoredPendingToolParts() {
18456
+ var _this = this;
18457
+ var shouldRepairRestoredPendingToolPart = this.shouldRepairRestoredPendingToolPart;
18458
+ if (!shouldRepairRestoredPendingToolPart) return;
18459
+ this.messages.forEach(function(message, messageIndex) {
18460
+ message.parts.forEach(function(part) {
18461
+ var _this_restoredToolCalls_get;
18462
+ if (!isPendingToolPart(part)) return;
18463
+ if (_this.restoredToolCalls && !((_this_restoredToolCalls_get = _this.restoredToolCalls.get(message.id)) === null || _this_restoredToolCalls_get === void 0 ? void 0 : _this_restoredToolCalls_get.has(part.toolCallId))) {
18464
+ return;
18465
+ }
18466
+ var shouldRepair = false;
18467
+ try {
18468
+ shouldRepair = shouldRepairRestoredPendingToolPart({
18469
+ toolName: getToolName(part),
18470
+ toolCallId: part.toolCallId,
18471
+ input: 'input' in part ? part.input : undefined
18472
+ });
18473
+ } catch (unused) {
18474
+ return;
18475
+ }
18476
+ if (!shouldRepair) return;
18477
+ _this.commit(part.toolCallId, {
18478
+ state: 'output-error',
18479
+ errorText: part.state === 'input-streaming' ? RESTORED_TOOL_INPUT_ERROR_TEXT : RESTORED_TOOL_CALL_ERROR_TEXT
18480
+ }, message.id, undefined, _this.messages[messageIndex]);
18481
+ });
18482
+ });
18483
+ }
18484
+ },
18389
18485
  {
18390
18486
  key: "getOutboundMessages",
18391
18487
  value: /**
@@ -18520,18 +18616,18 @@
18520
18616
  },
18521
18617
  {
18522
18618
  key: "submitToolResult",
18523
- value: function submitToolResult(response, param) {
18619
+ value: function submitToolResult(response, options) {
18524
18620
  var _this = this;
18525
- var toolCallId = param.toolCallId, output = param.output, messageId = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : response === null || response === void 0 ? void 0 : response.messageId, expectedMessage = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : messageId ? this.messages.find(function(message) {
18621
+ var messageId = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : response === null || response === void 0 ? void 0 : response.messageId, expectedMessage = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : messageId ? this.messages.find(function(message) {
18526
18622
  return message.id === messageId;
18527
18623
  }) : undefined;
18528
18624
  if (response === null || response === void 0 ? void 0 : response.isRetired) return Promise.resolve();
18529
18625
  var commitResult = function commitResult() {
18530
- if (!_this.commit(toolCallId, output, messageId, response, expectedMessage)) {
18626
+ if (!_this.commit(options.toolCallId, getTerminalToolState(options), messageId, response, expectedMessage)) {
18531
18627
  return Promise.resolve();
18532
18628
  }
18533
- if (response === null || response === void 0 ? void 0 : response.requiredToolCallIds.has(toolCallId)) {
18534
- response.resolvedToolCallIds.add(toolCallId);
18629
+ if (response === null || response === void 0 ? void 0 : response.requiredToolCallIds.has(options.toolCallId)) {
18630
+ response.resolvedToolCallIds.add(options.toolCallId);
18535
18631
  }
18536
18632
  return _this.continueResponse(response);
18537
18633
  };
@@ -18915,13 +19011,16 @@
18915
19011
  _this.responsesByToolCallId.set(chunk.toolCallId, owners);
18916
19012
  response.pendingToolCallbacks++;
18917
19013
  try {
19014
+ var _this_restoredToolCalls_get, _this_restoredToolCalls;
19015
+ (_this_restoredToolCalls = _this.restoredToolCalls) === null || _this_restoredToolCalls === void 0 ? void 0 : (_this_restoredToolCalls_get = _this_restoredToolCalls.get(currentMessage.id)) === null || _this_restoredToolCalls_get === void 0 ? void 0 : _this_restoredToolCalls_get.delete(chunk.toolCallId);
18918
19016
  var result = _this.onToolCall({
18919
19017
  toolCall: {
18920
19018
  toolName: chunk.toolName,
18921
19019
  toolCallId: chunk.toolCallId,
18922
19020
  input: chunk.input,
18923
19021
  dynamic: 'dynamic' in chunk ? chunk.dynamic : undefined
18924
- }
19022
+ },
19023
+ signal: response.abortController.signal
18925
19024
  }, function(options) {
18926
19025
  return response.isRetired ? Promise.resolve() : _this.submitToolResult(response, options);
18927
19026
  });
@@ -19241,7 +19340,7 @@
19241
19340
  return AbstractChat;
19242
19341
  }();
19243
19342
 
19244
- var _computedKey, _computedKey1, _computedKey2, _computedKey3, _computedKey4, _computedKey5;
19343
+ var _computedKey, _computedKey1, _computedKey2, _computedKey3, _computedKey4, _computedKey5, _computedKey6, _computedKey7;
19245
19344
  var CACHE_KEY = 'instantsearch-chat-initial-messages';
19246
19345
  // Message history is a browser concern, and a server render constructs a Chat
19247
19346
  // too. Reading storage there throws during rendering; the write below only
@@ -19263,8 +19362,8 @@
19263
19362
  }
19264
19363
  });
19265
19364
  }
19266
- _computedKey = '~registerMessagesCallback', _computedKey1 = '~registerStatusCallback', _computedKey2 = '~registerErrorCallback';
19267
- var _computedKey6 = _computedKey, _computedKey7 = _computedKey1, _computedKey8 = _computedKey2;
19365
+ _computedKey = '~persistMessages', _computedKey1 = '~registerMessagesCallback', _computedKey2 = '~registerStatusCallback', _computedKey3 = '~registerErrorCallback';
19366
+ var _computedKey8 = _computedKey, _computedKey9 = _computedKey1, _computedKey10 = _computedKey2, _computedKey11 = _computedKey3;
19268
19367
  var ChatState = /*#__PURE__*/ function() {
19269
19368
  function ChatState() {
19270
19369
  var _this = this;
@@ -19276,6 +19375,7 @@
19276
19375
  _define_property(this, "_messagesCallbacks", new Set());
19277
19376
  _define_property(this, "_statusCallbacks", new Set());
19278
19377
  _define_property(this, "_errorCallbacks", new Set());
19378
+ _define_property(this, "persistenceKey", void 0);
19279
19379
  _define_property(this, "pushMessage", function(message) {
19280
19380
  _this._messages = _this._messages.concat(message);
19281
19381
  _this._callMessagesCallbacks();
@@ -19294,20 +19394,31 @@
19294
19394
  _define_property(this, "snapshot", function(thing) {
19295
19395
  return JSON.parse(JSON.stringify(thing));
19296
19396
  });
19297
- _define_property(this, _computedKey6, function(onChange) {
19397
+ _define_property(this, _computedKey8, function() {
19398
+ var persistenceKey = _this.persistenceKey;
19399
+ if (!persistenceKey) return;
19400
+ safelyRunOnBrowser(function() {
19401
+ try {
19402
+ sessionStorage.setItem(persistenceKey, JSON.stringify(_this.messages));
19403
+ } catch (e) {
19404
+ // Do nothing if sessionStorage is not available or full
19405
+ }
19406
+ });
19407
+ });
19408
+ _define_property(this, _computedKey9, function(onChange) {
19298
19409
  var callback = onChange;
19299
19410
  _this._messagesCallbacks.add(callback);
19300
19411
  return function() {
19301
19412
  _this._messagesCallbacks.delete(callback);
19302
19413
  };
19303
19414
  });
19304
- _define_property(this, _computedKey7, function(onChange) {
19415
+ _define_property(this, _computedKey10, function(onChange) {
19305
19416
  _this._statusCallbacks.add(onChange);
19306
19417
  return function() {
19307
19418
  _this._statusCallbacks.delete(onChange);
19308
19419
  };
19309
19420
  });
19310
- _define_property(this, _computedKey8, function(onChange) {
19421
+ _define_property(this, _computedKey11, function(onChange) {
19311
19422
  _this._errorCallbacks.add(onChange);
19312
19423
  return function() {
19313
19424
  _this._errorCallbacks.delete(onChange);
@@ -19338,19 +19449,14 @@
19338
19449
  if (!persistence) {
19339
19450
  return;
19340
19451
  }
19341
- var saveMessagesInLocalStorage = function saveMessagesInLocalStorage() {
19452
+ this.persistenceKey = CACHE_KEY + (id ? "-".concat(id) : '');
19453
+ var saveMessagesInSessionStorage = function saveMessagesInSessionStorage() {
19342
19454
  if (_this.status === 'ready') {
19343
- safelyRunOnBrowser(function() {
19344
- try {
19345
- sessionStorage.setItem(CACHE_KEY + (id ? "-".concat(id) : ''), JSON.stringify(_this.messages));
19346
- } catch (e) {
19347
- // Do nothing if sessionStorage is not available or full
19348
- }
19349
- });
19455
+ _this['~persistMessages']();
19350
19456
  }
19351
19457
  };
19352
- this['~registerMessagesCallback'](saveMessagesInLocalStorage);
19353
- this['~registerStatusCallback'](saveMessagesInLocalStorage);
19458
+ this['~registerMessagesCallback'](saveMessagesInSessionStorage);
19459
+ this['~registerStatusCallback'](saveMessagesInSessionStorage);
19354
19460
  }
19355
19461
  _create_class(ChatState, [
19356
19462
  {
@@ -19386,8 +19492,8 @@
19386
19492
  ]);
19387
19493
  return ChatState;
19388
19494
  }();
19389
- _computedKey3 = '~registerMessagesCallback', _computedKey4 = '~registerStatusCallback', _computedKey5 = '~registerErrorCallback';
19390
- var _computedKey9 = _computedKey3, _computedKey10 = _computedKey4, _computedKey11 = _computedKey5;
19495
+ _computedKey4 = '~repairRestoredPendingToolParts', _computedKey5 = '~registerMessagesCallback', _computedKey6 = '~registerStatusCallback', _computedKey7 = '~registerErrorCallback';
19496
+ var _computedKey12 = _computedKey4, _computedKey13 = _computedKey5, _computedKey14 = _computedKey6, _computedKey15 = _computedKey7;
19391
19497
  var Chat$1 = /*#__PURE__*/ function(AbstractChat) {
19392
19498
  _inherits(Chat, AbstractChat);
19393
19499
  function Chat(_0) {
@@ -19403,14 +19509,25 @@
19403
19509
  _object_spread_props(_object_spread({}, init), {
19404
19510
  state: state
19405
19511
  })
19406
- ]), _define_property(_this, "_state", void 0), _define_property(_this, _computedKey9, function(onChange) {
19512
+ ]), _define_property(_this, "_state", void 0), _define_property(_this, "hasRestoredMessages", false), _define_property(_this, _computedKey12, function() {
19513
+ if (!_this.hasRestoredMessages) return;
19514
+ _this.hasRestoredMessages = false;
19515
+ _this.repairRestoredPendingToolParts();
19516
+ _this.clearRestoredToolCalls();
19517
+ _this._state['~persistMessages']();
19518
+ }), _define_property(_this, _computedKey13, function(onChange) {
19407
19519
  return _this._state['~registerMessagesCallback'](onChange);
19408
- }), _define_property(_this, _computedKey10, function(onChange) {
19520
+ }), _define_property(_this, _computedKey14, function(onChange) {
19409
19521
  return _this._state['~registerStatusCallback'](onChange);
19410
- }), _define_property(_this, _computedKey11, function(onChange) {
19522
+ }), _define_property(_this, _computedKey15, function(onChange) {
19411
19523
  return _this._state['~registerErrorCallback'](onChange);
19412
19524
  });
19413
19525
  _this._state = state;
19526
+ if (messages === undefined && persistence) {
19527
+ _this.hasRestoredMessages = true;
19528
+ _this.captureRestoredToolCalls();
19529
+ _this.repairRestoredPendingToolParts();
19530
+ }
19414
19531
  return _this;
19415
19532
  }
19416
19533
  return Chat;
@@ -19465,6 +19582,7 @@
19465
19582
  var MemorySearchToolType = 'algolia_memory_search';
19466
19583
  var PonderToolType = 'algolia_ponder';
19467
19584
  var DisplayResultsToolType = 'algolia_display_results';
19585
+ var GroupedResultsToolType = 'algolia_grouped_results';
19468
19586
  /**
19469
19587
  * Whether `toolName` is the search tool as the Algolia MCP Server exposes it:
19470
19588
  * one tool per index, named after the index it searches
@@ -19673,6 +19791,9 @@
19673
19791
  name: 'chat',
19674
19792
  connector: true
19675
19793
  });
19794
+ var DEFAULT_TOOL_TIMEOUT = 20000;
19795
+ var TOOL_TIMEOUT_ERROR_TEXT = 'The tool call timed out before a result was received. The operation may have completed.';
19796
+ var TOOL_ABORTED_ERROR_TEXT = 'The tool call was cancelled before a result was received.';
19676
19797
  var OPEN_STATE_CACHE_KEY = 'instantsearch-chat-open-state';
19677
19798
  function normalizePersistence(persistence, hasCustomChat) {
19678
19799
  if (hasCustomChat) {
@@ -19830,7 +19951,7 @@
19830
19951
  var hasValidatedEntryPoints = false;
19831
19952
  var agentId = 'agentId' in options ? options.agentId : undefined;
19832
19953
  // Collected here rather than by the tool that searched: that tool renders
19833
- // nothing while display-results presents its records, and a record has to
19954
+ // nothing while Grouped Results presents its records, and a record has to
19834
19955
  // outlive the render that produced it.
19835
19956
  var records = createChatRecordsStore();
19836
19957
  var collectRecords = function collectRecords() {
@@ -19862,28 +19983,6 @@
19862
19983
  var _findSuggestionsPart;
19863
19984
  return (_findSuggestionsPart = findSuggestionsPart(findLastAssistantMessage(messages))) === null || _findSuggestionsPart === void 0 ? void 0 : _findSuggestionsPart.data.suggestions;
19864
19985
  };
19865
- // "Still coming" has to be inferred: the turn is running and has no
19866
- // `data-suggestions` part yet. Expecting any at all needs evidence, or an
19867
- // agent that never sends them would sit under a placeholder forever.
19868
- var getSuggestionsStatus = function getSuggestionsStatus(messages) {
19869
- var _lastAssistantMessage_metadata;
19870
- var status = _chatInstance.status;
19871
- if (status !== 'submitted' && status !== 'streaming') {
19872
- return 'idle';
19873
- }
19874
- var lastAssistantMessage = findLastAssistantMessage(messages);
19875
- if (findSuggestionsPart(lastAssistantMessage)) {
19876
- return 'idle';
19877
- }
19878
- var declaresSuggestions = (lastAssistantMessage === null || lastAssistantMessage === void 0 ? void 0 : (_lastAssistantMessage_metadata = lastAssistantMessage.metadata) === null || _lastAssistantMessage_metadata === void 0 ? void 0 : _lastAssistantMessage_metadata.suggestionsEnabled) === true;
19879
- if (declaresSuggestions) {
19880
- return 'loading';
19881
- }
19882
- var hasSuggestionsHistory = messages.some(function(message) {
19883
- return message !== lastAssistantMessage && message.role === 'assistant' && Boolean(findSuggestionsPart(message));
19884
- });
19885
- return hasSuggestionsHistory ? 'loading' : 'idle';
19886
- };
19887
19986
  var setMessages = function setMessages(messagesParam) {
19888
19987
  if (typeof messagesParam === 'function') {
19889
19988
  messagesParam = messagesParam(_chatInstance.messages);
@@ -20020,7 +20119,8 @@
20020
20119
  if (!transport) {
20021
20120
  throw new Error(withUsage$q('You need to provide either an `agentId` or a `transport`.'));
20022
20121
  }
20023
- return new Chat$1(_object_spread_props(_object_spread({}, options), {
20122
+ var canRepairRestoredPendingToolParts = !resume;
20123
+ var chat = new Chat$1(_object_spread_props(_object_spread({}, options), {
20024
20124
  persistence: normalizedPersistence.messages,
20025
20125
  sendAutomaticallyWhen: sendAutomaticallyWhen,
20026
20126
  transport: transport,
@@ -20029,6 +20129,11 @@
20029
20129
  if (!tool) return true;
20030
20130
  return Boolean(tool.streamInput);
20031
20131
  },
20132
+ shouldRepairRestoredPendingToolPart: function shouldRepairRestoredPendingToolPart(param) {
20133
+ var toolName = param.toolName;
20134
+ var tool = findTool(toolName, tools);
20135
+ return Boolean(canRepairRestoredPendingToolParts && (tool === null || tool === void 0 ? void 0 : tool.onToolCall) && tool.timeout !== false);
20136
+ },
20032
20137
  resolveCancelledToolOutput: function resolveCancelledToolOutput(param) {
20033
20138
  var toolName = param.toolName, toolCallId = param.toolCallId, input = param.input;
20034
20139
  var _findTool;
@@ -20048,7 +20153,7 @@
20048
20153
  }
20049
20154
  },
20050
20155
  onToolCall: function onToolCall(param, submitToolResult) {
20051
- var toolCall = param.toolCall;
20156
+ var toolCall = param.toolCall, signal = param.signal;
20052
20157
  var tool = findTool(toolCall.toolName, tools);
20053
20158
  if (!tool) {
20054
20159
  return submitToolResult({
@@ -20058,21 +20163,103 @@
20058
20163
  });
20059
20164
  }
20060
20165
  if (tool.onToolCall) {
20061
- var addToolResult = function addToolResult(param) {
20062
- var output = param.output;
20063
- return submitToolResult({
20064
- output: output,
20166
+ var toolAbortController = new AbortController();
20167
+ var timeoutId;
20168
+ var settled = false;
20169
+ var resolveExecution;
20170
+ var rejectExecution;
20171
+ var execution = new Promise(function(resolve, reject) {
20172
+ resolveExecution = resolve;
20173
+ rejectExecution = reject;
20174
+ });
20175
+ var cleanup = function cleanup() {
20176
+ if (timeoutId !== undefined) {
20177
+ clearTimeout(timeoutId);
20178
+ }
20179
+ signal.removeEventListener('abort', abortToolCall);
20180
+ };
20181
+ var addToolResult = function addToolResult(options) {
20182
+ if (settled) return Promise.resolve();
20183
+ settled = true;
20184
+ cleanup();
20185
+ var submission = submitToolResult(_object_spread_props(_object_spread({}, options), {
20065
20186
  tool: toolCall.toolName,
20066
20187
  toolCallId: toolCall.toolCallId
20188
+ }));
20189
+ submission.then(resolveExecution, rejectExecution);
20190
+ return submission;
20191
+ };
20192
+ var addToolError = function addToolError(error) {
20193
+ var errorText = _instanceof(error, Error) ? error.message : String(error !== null && error !== void 0 ? error : '');
20194
+ return addToolResult({
20195
+ state: 'output-error',
20196
+ errorText: errorText || 'Tool call failed.'
20067
20197
  });
20068
20198
  };
20069
- return tool.onToolCall(_object_spread_props(_object_spread({}, toolCall), {
20070
- addToolResult: addToolResult
20071
- }));
20199
+ function abortToolCall() {
20200
+ var submission = addToolResult({
20201
+ state: 'output-error',
20202
+ errorText: TOOL_ABORTED_ERROR_TEXT
20203
+ });
20204
+ toolAbortController.abort();
20205
+ void submission.catch(function() {
20206
+ return undefined;
20207
+ });
20208
+ }
20209
+ if (signal.aborted) {
20210
+ abortToolCall();
20211
+ return execution;
20212
+ }
20213
+ signal.addEventListener('abort', abortToolCall, {
20214
+ once: true
20215
+ });
20216
+ if (tool.timeout !== false) {
20217
+ var _tool_timeout;
20218
+ timeoutId = setTimeout(function() {
20219
+ var submission = addToolResult({
20220
+ state: 'output-error',
20221
+ errorText: TOOL_TIMEOUT_ERROR_TEXT
20222
+ });
20223
+ toolAbortController.abort();
20224
+ void submission.catch(function() {
20225
+ return undefined;
20226
+ });
20227
+ }, (_tool_timeout = tool.timeout) !== null && _tool_timeout !== void 0 ? _tool_timeout : DEFAULT_TOOL_TIMEOUT);
20228
+ }
20229
+ var toolExecution;
20230
+ try {
20231
+ toolExecution = tool.onToolCall(_object_spread_props(_object_spread({}, toolCall), {
20232
+ addToolResult: addToolResult,
20233
+ signal: toolAbortController.signal
20234
+ }));
20235
+ } catch (error) {
20236
+ return addToolError(error);
20237
+ }
20238
+ var returnedExecution = Promise.resolve(toolExecution).catch(addToolError);
20239
+ if (tool.timeout === false) {
20240
+ return Promise.race([
20241
+ returnedExecution.then(cleanup),
20242
+ execution
20243
+ ]);
20244
+ }
20245
+ void returnedExecution.catch(function() {
20246
+ return undefined;
20247
+ });
20248
+ return execution;
20072
20249
  }
20073
20250
  return Promise.resolve();
20074
20251
  }
20075
20252
  }));
20253
+ if (resume) {
20254
+ var resumeStream = chat.resumeStream;
20255
+ chat.resumeStream = function(requestOptions) {
20256
+ return resumeStream(requestOptions).finally(function() {
20257
+ canRepairRestoredPendingToolParts = true;
20258
+ chat['~repairRestoredPendingToolParts']();
20259
+ });
20260
+ };
20261
+ }
20262
+ return chat;
20076
20263
  };
20077
20264
  return {
20078
20265
  $$type: 'ais.chat',
@@ -20283,7 +20470,6 @@
20283
20470
  '~isOpenStatePersistenceEnabled': normalizedPersistence.open,
20284
20471
  setMessages: setMessages,
20285
20472
  suggestions: getSuggestionsFromMessages(_chatInstance.messages),
20286
- suggestionsStatus: getSuggestionsStatus(_chatInstance.messages),
20287
20473
  clearMessages: clearMessages,
20288
20474
  tools: toolsWithAddToolResult,
20289
20475
  records: records,
@@ -20903,9 +21089,6 @@
20903
21089
  return null;
20904
21090
  }
20905
21091
  }
20906
- function buildSuggestionMessage(suggestion) {
20907
- return "The user clicked this on-page suggestion. Use the current page context first, then search only if needed.\n\nSuggestion: ".concat(suggestion);
20908
- }
20909
21092
  function stripInternalHitMetadata(hit) {
20910
21093
  var clean = {};
20911
21094
  Object.keys(hit).forEach(function(key) {
@@ -20979,6 +21162,9 @@
20979
21162
  // the widget is unmounted; this guard stops those late callbacks from
20980
21163
  // calling `renderFn` into a torn-down container.
20981
21164
  var disposed = false;
21165
+ // Whether the "is a chat widget mounted on this index?" question has been
21166
+ // settled — see `validateChat`.
21167
+ var hasValidatedChat = false;
20982
21168
  // True between a state-signature change and the debounced refetch that
20983
21169
  // follows it. While pending, the search state has already moved on, so a
20984
21170
  // still-in-flight request from the previous state must not paint its
@@ -21011,21 +21197,26 @@
21011
21197
  };
21012
21198
  var sendToChat = function sendToChat(renderOptions) {
21013
21199
  return function(prompt) {
21014
- var _ref, _ref1;
21200
+ var _ref, _getLatestResults;
21015
21201
  var chatRenderState = getChatRenderState(renderOptions);
21016
21202
  if (!chatRenderState || !chatRenderState.sendMessage) {
21017
21203
  return false;
21018
21204
  }
21019
- var results = (_ref = (_ref1 = latestRenderOptions === null || latestRenderOptions === void 0 ? void 0 : latestRenderOptions.results) !== null && _ref1 !== void 0 ? _ref1 : 'results' in renderOptions ? renderOptions.results : null) !== null && _ref !== void 0 ? _ref : null;
21205
+ var results = (_ref = (_getLatestResults = getLatestResults()) !== null && _getLatestResults !== void 0 ? _getLatestResults : 'results' in renderOptions ? renderOptions.results : null) !== null && _ref !== void 0 ? _ref : null;
21020
21206
  return openChat(chatRenderState, {
21021
- message: buildSuggestionMessage(prompt),
21207
+ message: prompt,
21022
21208
  referer: 'prompt-suggestions-widget',
21023
21209
  turnContext: buildTurnContext(results)
21024
21210
  });
21025
21211
  };
21026
21212
  };
21027
- var resolvePageContext = function resolvePageContext(results) {
21028
- var resolvedContext = typeof context === 'function' ? context() : context;
21213
+ // `context` may be a function, so the option alone says nothing about what
21214
+ // a given fetch actually has to send. Resolve it once per fetch and let
21215
+ // callers read the value rather than the option.
21216
+ var resolveContext = function resolveContext() {
21217
+ return typeof context === 'function' ? context() : context;
21218
+ };
21219
+ var buildPageContext = function buildPageContext(resolvedContext, results) {
21029
21220
  // Explicit context replaces auto-extraction; otherwise derive it from
21030
21221
  // the current search state. The task's server-owned instructions decide
21031
21222
  // how to interpret the shape — the client doesn't label it.
@@ -21044,15 +21235,11 @@
21044
21235
  hitsSample: transformHits(results.hits)
21045
21236
  });
21046
21237
  };
21047
- var buildInput = function buildInput(results) {
21048
- var _resolvePageContext;
21049
- return (_resolvePageContext = resolvePageContext(results)) !== null && _resolvePageContext !== void 0 ? _resolvePageContext : {};
21050
- };
21051
21238
  // The same page context, flattened for the chat handoff: `turnContext` is
21052
21239
  // a flat `Record<string, string>` per the Agent Studio contract, so
21053
21240
  // non-string values (e.g. `hitsSample`) are serialized.
21054
21241
  var buildTurnContext = function buildTurnContext(results) {
21055
- var pageContext = resolvePageContext(results);
21242
+ var pageContext = buildPageContext(resolveContext(), results);
21056
21243
  if (!pageContext) {
21057
21244
  return undefined;
21058
21245
  }
@@ -21068,6 +21255,16 @@
21068
21255
  });
21069
21256
  return entries.length > 0 ? Object.fromEntries(entries) : undefined;
21070
21257
  };
21258
+ // `latestRenderOptions` may be the `init()` options, which carry no
21259
+ // `results` key at all, so the read has to be narrowed rather than
21260
+ // optional-chained.
21261
+ var getLatestResults = function getLatestResults() {
21262
+ var _latestRenderOptions_results;
21263
+ if (!latestRenderOptions || !('results' in latestRenderOptions)) {
21264
+ return null;
21265
+ }
21266
+ return (_latestRenderOptions_results = latestRenderOptions.results) !== null && _latestRenderOptions_results !== void 0 ? _latestRenderOptions_results : null;
21267
+ };
21071
21268
  var renderOutward = function renderOutward(renderOptions) {
21072
21269
  if (disposed) return;
21073
21270
  renderFn(_object_spread_props(_object_spread({}, getWidgetRenderState(renderOptions)), {
@@ -21093,13 +21290,20 @@
21093
21290
  };
21094
21291
  var fetchAndRender = function fetchAndRender(results, renderOptions) {
21095
21292
  var _ref = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : {}, _ref_force = _ref.force, force = _ref_force === void 0 ? false : _ref_force;
21293
+ var _buildPageContext;
21096
21294
  var _results_hits;
21097
21295
  if (disposed || !tasksState) return;
21098
21296
  var hadDroppedInnerRender = droppedInnerRender;
21099
21297
  refetchPending = false;
21100
21298
  droppedInnerRender = false;
21101
- var hasContext = context !== undefined;
21102
- if (!hasContext && !(results === null || results === void 0 ? void 0 : (_results_hits = results.hits) === null || _results_hits === void 0 ? void 0 : _results_hits.length)) {
21299
+ var resolvedContext = resolveContext();
21300
+ var input = (_buildPageContext = buildPageContext(resolvedContext, results)) !== null && _buildPageContext !== void 0 ? _buildPageContext : {};
21301
+ // Two ways there is nothing worth sending: no context for this fetch and
21302
+ // no hits to derive one from, or a context that resolved to something
21303
+ // empty. The first reads the resolved value rather than the option, so
21304
+ // `context: () => undefined` is gated exactly like an omitted `context`.
21305
+ // Sending an empty input spends a model call on no information.
21306
+ if (resolvedContext === undefined && !(results === null || results === void 0 ? void 0 : (_results_hits = results.hits) === null || _results_hits === void 0 ? void 0 : _results_hits.length) || Object.keys(input).length === 0) {
21103
21307
  tasksState.invalidate();
21104
21308
  suggestions = [];
21105
21309
  isLoading = false;
@@ -21108,7 +21312,6 @@
21108
21312
  renderOutward(renderOptions);
21109
21313
  return;
21110
21314
  }
21111
- var input = buildInput(results);
21112
21315
  var payload = taskPayloadKey(input);
21113
21316
  // A moved search state does not always mean a different question: with an
21114
21317
  // explicit `context` the payload ignores the results entirely, so a new
@@ -21133,10 +21336,14 @@
21133
21336
  };
21134
21337
  var refresh = function refresh() {
21135
21338
  if (isLoading) return;
21136
- var results = latestRenderOptions === null || latestRenderOptions === void 0 ? void 0 : latestRenderOptions.results;
21137
- if (!results || !latestRenderOptions) return;
21339
+ if (!latestRenderOptions) return;
21340
+ var results = getLatestResults();
21138
21341
  clearTimeout(debounceTimer);
21139
- lastStateSignature = getStateSignature(results);
21342
+ // Only meaningful with results: without them there is no signature for a
21343
+ // later automatic fetch to compare against.
21344
+ if (results) {
21345
+ lastStateSignature = getStateSignature(results);
21346
+ }
21140
21347
  fetchAndRender(results, latestRenderOptions, {
21141
21348
  force: true
21142
21349
  });
@@ -21150,12 +21357,17 @@
21150
21357
  var chatRenderState = getChatRenderState(renderOptions);
21151
21358
  var isChatBusy$1 = chatRenderState ? !chatRenderState.sendMessage || isChatBusy(chatRenderState) : false;
21152
21359
  var send = sendToChat(renderOptions);
21360
+ // `sendToChat` is withheld only once the mount window has closed: a chat
21361
+ // widget further down a React tree is added after this widget's `init`,
21362
+ // so until `validateChat` runs its absence is not yet conclusive and
21363
+ // withholding the handler would make a valid setup look broken.
21364
+ var canSendToChat = Boolean(chatRenderState === null || chatRenderState === void 0 ? void 0 : chatRenderState.sendMessage) || !hasValidatedChat;
21153
21365
  return {
21154
21366
  suggestions: transformed,
21155
21367
  isLoading: isLoading,
21156
21368
  error: error,
21157
- onSuggestionClick: send,
21158
- sendToChat: send,
21369
+ onSuggestionClick: canSendToChat ? send : noop,
21370
+ sendToChat: canSendToChat ? send : undefined,
21159
21371
  refresh: refresh,
21160
21372
  isChatBusy: isChatBusy$1,
21161
21373
  widgetParams: widgetParams
@@ -21178,6 +21390,24 @@
21178
21390
  }
21179
21391
  adoptInnerState(renderState);
21180
21392
  };
21393
+ // Deferred because a chat widget can be registered after this one: React
21394
+ // adds widgets in mount order, so a `chat` further down the tree only
21395
+ // lands after this widget's `init` has run. Until this closes the window,
21396
+ // `sendToChat` is handed out optimistically.
21397
+ var validateChat = defer(function(renderOptions) {
21398
+ var _getChatRenderState;
21399
+ if (hasValidatedChat) return;
21400
+ hasValidatedChat = true;
21401
+ if ((_getChatRenderState = getChatRenderState(renderOptions)) === null || _getChatRenderState === void 0 ? void 0 : _getChatRenderState.sendMessage) return;
21402
+ // A render may already have gone out with the optimistic `sendToChat`;
21403
+ // re-render so the widget layer sees the settled answer. The `init()`
21404
+ // options don't count: nothing has painted yet, so the next render
21405
+ // carries it — and a mount that never renders results shows no pills
21406
+ // to mislead anyone.
21407
+ if (latestRenderOptions && 'results' in latestRenderOptions) {
21408
+ renderOutward(latestRenderOptions);
21409
+ }
21410
+ });
21181
21411
  var tasksParams;
21182
21412
  if (agentId) {
21183
21413
  tasksParams = {
@@ -21200,12 +21430,37 @@
21200
21430
  var tasksWidget = connectTasks(handleInnerRender, noop)(tasksParams);
21201
21431
  return {
21202
21432
  $$type: 'ais.promptSuggestions',
21433
+ // Clicking a suggestion opens the chat, so this widget counts as an
21434
+ // entry point for `connectChat`'s trigger validation.
21435
+ opensChat: true,
21203
21436
  init: function init(initOptions) {
21204
21437
  var instantSearchInstance = initOptions.instantSearchInstance;
21205
21438
  tasksWidget.init(initOptions);
21439
+ // Set after the inner init so its initial no-op render is still
21440
+ // ignored, and before the first outward render so `refresh()` has a
21441
+ // render target even on a mount where `render()` never sees results.
21442
+ latestRenderOptions = initOptions;
21443
+ validateChat(initOptions);
21206
21444
  renderFn(_object_spread_props(_object_spread({}, getWidgetRenderState(initOptions)), {
21207
21445
  instantSearchInstance: instantSearchInstance
21208
21446
  }), true);
21447
+ // With an explicit `context` the payload never reads the results, so
21448
+ // waiting for a search is waiting on something the request does not
21449
+ // use — and a page that triggers no search (a `searchFunction` query
21450
+ // gate, or a mount made only for the widgets) would wait forever.
21451
+ // Fetch here instead, after the first render so the `isFirstRender`
21452
+ // one still arrives first.
21453
+ //
21454
+ // There are no results yet by definition, so "is there anything to
21455
+ // send" reduces to "did the context resolve to something". Checking it
21456
+ // here rather than letting `fetchAndRender` reject the call keeps init
21457
+ // out of the "nothing to send" branch, whose `invalidate()` would add
21458
+ // two outward renders to every mount that has no context — leaving the
21459
+ // auto-extracted path, the one that does need results, untouched.
21460
+ var initialContext = resolveContext();
21461
+ if (initialContext && Object.keys(initialContext).length > 0) {
21462
+ fetchAndRender(null, initOptions);
21463
+ }
21209
21464
  },
21210
21465
  render: function render(renderOptions) {
21211
21466
  var results = renderOptions.results, instantSearchInstance = renderOptions.instantSearchInstance;
@@ -21223,8 +21478,9 @@
21223
21478
  error = undefined;
21224
21479
  clearTimeout(debounceTimer);
21225
21480
  debounceTimer = setTimeout(function() {
21226
- if (latestRenderOptions === null || latestRenderOptions === void 0 ? void 0 : latestRenderOptions.results) {
21227
- fetchAndRender(latestRenderOptions.results, latestRenderOptions);
21481
+ var latestResults = getLatestResults();
21482
+ if (latestResults && latestRenderOptions) {
21483
+ fetchAndRender(latestResults, latestRenderOptions);
21228
21484
  }
21229
21485
  }, DEBOUNCE_MS);
21230
21486
  }
@@ -21235,6 +21491,7 @@
21235
21491
  dispose: function dispose(disposeOptions) {
21236
21492
  disposed = true;
21237
21493
  clearTimeout(debounceTimer);
21494
+ validateChat.cancel();
21238
21495
  tasksWidget.dispose(disposeOptions);
21239
21496
  unmountFn();
21240
21497
  },
@@ -26751,7 +27008,7 @@
26751
27008
  createElement: React.createElement
26752
27009
  });
26753
27010
 
26754
- function createDisplayResultsTool(itemComponent) {
27011
+ function createGroupedResultsTool(itemComponent) {
26755
27012
  var DisplayResultsUIComponent = createDisplayResultsToolComponent({
26756
27013
  createElement: React.createElement,
26757
27014
  Fragment: React.Fragment,
@@ -26846,14 +27103,14 @@
26846
27103
  function createDefaultTools(itemComponent, getSearchPageURL) {
26847
27104
  var _obj;
26848
27105
  return _obj = {}, _define_property(_obj, SearchIndexToolType, _object_spread_props(_object_spread({}, createCarouselTool(true, itemComponent, getSearchPageURL)), {
26849
- // The agent decides per turn whether the richer display-results tool
27106
+ // The agent decides per turn whether the richer Grouped Results tool
26850
27107
  // takes over the rendering of the search results.
26851
27108
  shouldRender: isDisplayResultsDisabled
26852
- })), _define_property(_obj, RecommendToolType, createCarouselTool(false, itemComponent, getSearchPageURL)), _define_property(_obj, DisplayResultsToolType, createDisplayResultsTool(itemComponent)), _define_property(_obj, MemorizeToolType, {}), _define_property(_obj, MemorySearchToolType, {}), _define_property(_obj, PonderToolType, {}), _obj;
27109
+ })), _define_property(_obj, RecommendToolType, createCarouselTool(false, itemComponent, getSearchPageURL)), _define_property(_obj, DisplayResultsToolType, createGroupedResultsTool(itemComponent)), _define_property(_obj, GroupedResultsToolType, createGroupedResultsTool(itemComponent)), _define_property(_obj, MemorizeToolType, {}), _define_property(_obj, MemorySearchToolType, {}), _define_property(_obj, PonderToolType, {}), _obj;
26853
27110
  }
26854
27111
  /**
26855
27112
  * Whether the search tool renders its own results, i.e. the agent did not hand
26856
- * the turn to the display-results tool. Set on the message by the backend.
27113
+ * the turn to the Grouped Results tool. Set on the message by the backend.
26857
27114
  */ function isDisplayResultsDisabled(param) {
26858
27115
  var parentMessage = param.parentMessage;
26859
27116
  var _parentMessage_metadata;
@@ -26984,7 +27241,7 @@
26984
27241
  tools: tools,
26985
27242
  disableTriggerValidation: effectiveDisableTriggerValidation
26986
27243
  }));
26987
- var messages = chatState.messages, sendMessage = chatState.sendMessage, status = chatState.status, regenerate = chatState.regenerate, stop = chatState.stop, error = chatState.error, input = chatState.input, setInput = chatState.setInput, open = chatState.open, setOpen = chatState.setOpen, clearMessages = chatState.clearMessages, toolsFromConnector = chatState.tools, suggestions = chatState.suggestions, suggestionsStatus = chatState.suggestionsStatus, onFeedback = chatState.sendChatMessageFeedback, feedbackState = chatState.feedbackState, consumeInputFocus = chatState['~consumeInputFocus'], isOpenStatePersistenceEnabled = chatState['~isOpenStatePersistenceEnabled'];
27244
+ var messages = chatState.messages, sendMessage = chatState.sendMessage, status = chatState.status, regenerate = chatState.regenerate, stop = chatState.stop, error = chatState.error, input = chatState.input, setInput = chatState.setInput, open = chatState.open, setOpen = chatState.setOpen, clearMessages = chatState.clearMessages, toolsFromConnector = chatState.tools, suggestions = chatState.suggestions, onFeedback = chatState.sendChatMessageFeedback, feedbackState = chatState.feedbackState, consumeInputFocus = chatState['~consumeInputFocus'], isOpenStatePersistenceEnabled = chatState['~isOpenStatePersistenceEnabled'];
26988
27245
  var sendMessageAndScrollToBottom = React.useCallback(function() {
26989
27246
  for(var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++){
26990
27247
  args[_key] = arguments[_key];
@@ -27145,7 +27402,6 @@
27145
27402
  }),
27146
27403
  suggestionsProps: {
27147
27404
  suggestions: suggestions,
27148
- isLoading: suggestionsStatus === 'loading',
27149
27405
  onSuggestionClick: function onSuggestionClick(suggestion) {
27150
27406
  sendMessageAndScrollToBottom({
27151
27407
  text: suggestion
@@ -27193,9 +27449,16 @@
27193
27449
  }), {
27194
27450
  $$widgetType: 'ais.promptSuggestions'
27195
27451
  }), suggestions = _usePromptSuggestions.suggestions, isLoading = _usePromptSuggestions.isLoading, error = _usePromptSuggestions.error, onSuggestionClick = _usePromptSuggestions.onSuggestionClick, isChatBusy = _usePromptSuggestions.isChatBusy, sendToChat = _usePromptSuggestions.sendToChat;
27452
+ if (!sendToChat && !onSuggestionClickOverride) {
27453
+ throw new Error('No <Chat> widget is mounted on this index, so there is nothing to send a clicked suggestion to. Mount a <Chat> on the same index, or pass `onSuggestionClick` to handle the click yourself.');
27454
+ }
27196
27455
  var handleClick = onSuggestionClickOverride ? function(prompt) {
27197
27456
  return onSuggestionClickOverride(prompt, {
27198
- sendToChat: sendToChat
27457
+ // `sendToChat` is only absent when the override above owns the click,
27458
+ // in which case falling through to the chat is a no-op.
27459
+ sendToChat: sendToChat !== null && sendToChat !== void 0 ? sendToChat : function() {
27460
+ return false;
27461
+ }
27199
27462
  });
27200
27463
  } : onSuggestionClick;
27201
27464
  if (LayoutComponent) {
@@ -29088,6 +29351,7 @@
29088
29351
  exports.Feeds = Feeds;
29089
29352
  exports.FilterSuggestions = FilterSuggestions;
29090
29353
  exports.FrequentlyBoughtTogether = FrequentlyBoughtTogether;
29354
+ exports.GroupedResultsToolType = GroupedResultsToolType;
29091
29355
  exports.HierarchicalMenu = HierarchicalMenu;
29092
29356
  exports.Highlight = Highlight;
29093
29357
  exports.Hits = Hits;