react-instantsearch 7.45.0 → 7.47.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- /*! React InstantSearch 7.45.0 | © Algolia, Inc. and contributors; MIT License | https://github.com/algolia/instantsearch */
1
+ /*! React InstantSearch 7.47.0 | © 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.45.0';
27
+ var version$2 = '7.47.0';
28
28
 
29
29
  function _define_property(obj, key, value) {
30
30
  if (key in obj) {
@@ -6715,23 +6715,33 @@
6715
6715
  }
6716
6716
 
6717
6717
  var nextMicroTask = Promise.resolve();
6718
- function defer(callback) {
6718
+ function defer(callback, // arguments: the first caller of the window decides what the single run
6719
+ // receives. Pass this to fold every later argument into the pending ones
6720
+ // instead.
6721
+ mergeArguments) {
6719
6722
  var progress = null;
6720
6723
  var cancelled = false;
6724
+ var pendingArgs = null;
6721
6725
  var fn = function fn() {
6722
6726
  for(var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++){
6723
6727
  args[_key] = arguments[_key];
6724
6728
  }
6725
6729
  if (progress !== null) {
6730
+ if (mergeArguments && pendingArgs !== null) {
6731
+ pendingArgs = mergeArguments(pendingArgs, args);
6732
+ }
6726
6733
  return;
6727
6734
  }
6735
+ pendingArgs = args;
6728
6736
  progress = nextMicroTask.then(function() {
6729
6737
  progress = null;
6738
+ var runArgs = pendingArgs;
6739
+ pendingArgs = null;
6730
6740
  if (cancelled) {
6731
6741
  cancelled = false;
6732
6742
  return;
6733
6743
  }
6734
- callback.apply(void 0, _to_consumable_array(args));
6744
+ callback.apply(void 0, _to_consumable_array(runArgs));
6735
6745
  });
6736
6746
  };
6737
6747
  fn.wait = function() {
@@ -7614,22 +7624,18 @@
7614
7624
  clearTimeout(cleanupTimerRef.current);
7615
7625
  // Warning: if an unstable function prop is provided, `dequal` is not able
7616
7626
  // to keep its reference and therefore will consider that props did change.
7617
- // This could unsollicitely remove/add the widget, therefore forget its state,
7618
- // and could be a source of confusion.
7627
+ // This unintentionally replaces the widget, which is wasteful (it causes
7628
+ // a search), even though `updateWidget` below keeps its state.
7619
7629
  // If users face this issue, we should advise them to provide stable function
7620
7630
  // references.
7621
7631
  var arePropsEqual = dequal(props, prevPropsRef.current);
7622
- // If props did change, then we execute the cleanup function instantly
7623
- // and then add the widget back. This lets us add the widget without
7632
+ // If props did change, then we replace the widget instantly instead of
7624
7633
  // waiting for the scheduled cleanup function to finish (that we canceled
7625
- // above).
7634
+ // above). `updateWidget` hands the previous widget's `uiState` over to the
7635
+ // new one, so that a parameter change doesn't reset the state the widget
7636
+ // still owns — which would otherwise break routing.
7626
7637
  if (!arePropsEqual) {
7627
- parentIndex.removeWidgets([
7628
- previousWidget
7629
- ]);
7630
- parentIndex.addWidgets([
7631
- widget
7632
- ]);
7638
+ parentIndex.updateWidget(previousWidget, widget);
7633
7639
  }
7634
7640
  }
7635
7641
  return function() {
@@ -7988,6 +7994,11 @@
7988
7994
  return undefined;
7989
7995
  }
7990
7996
 
7997
+ function reduceChildrenUiState(widgets, uiState, widgetUiStateOptions) {
7998
+ return widgets.reduce(function(state, widget) {
7999
+ return widget.getWidgetUiState ? widget.getWidgetUiState(state, widgetUiStateOptions) : state;
8000
+ }, uiState);
8001
+ }
7991
8002
  function createFeedContainer(feedID, parentIndex, instantSearchInstance) {
7992
8003
  var localWidgets = [];
7993
8004
  var initialized = false;
@@ -8189,13 +8200,10 @@
8189
8200
  },
8190
8201
  getWidgetUiState: function getWidgetUiState(uiState) {
8191
8202
  var helper = parentIndex.getHelper();
8192
- var widgetUiStateOptions = {
8203
+ return reduceChildrenUiState(localWidgets, uiState, {
8193
8204
  searchParameters: helper.state,
8194
8205
  helper: helper
8195
- };
8196
- return localWidgets.reduce(function(state, widget) {
8197
- return widget.getWidgetUiState ? widget.getWidgetUiState(state, widgetUiStateOptions) : state;
8198
- }, uiState);
8206
+ });
8199
8207
  },
8200
8208
  getWidgetSearchParameters: function getWidgetSearchParameters(searchParameters, param) {
8201
8209
  var uiState = param.uiState;
@@ -8205,6 +8213,73 @@
8205
8213
  }) : params;
8206
8214
  }, searchParameters);
8207
8215
  },
8216
+ updateWidget: function updateWidget(previousWidget, nextWidget) {
8217
+ var helper = parentIndex.getHelper();
8218
+ // The `uiState` the children own, read before the previous widget is
8219
+ // detached, so that the state it owns can be handed over to the next one.
8220
+ var previousUiState = helper ? reduceChildrenUiState(localWidgets, {}, {
8221
+ searchParameters: helper.state,
8222
+ helper: helper
8223
+ }) : {};
8224
+ previousWidget.parent = undefined;
8225
+ nextWidget.parent = container;
8226
+ // The next widget takes the place of the previous one, so that the order
8227
+ // in which children contribute to the search parameters is unchanged.
8228
+ var nextWidgets = localWidgets.slice();
8229
+ var position = nextWidgets.indexOf(previousWidget);
8230
+ if (position === -1) {
8231
+ nextWidgets.push(nextWidget);
8232
+ } else {
8233
+ nextWidgets[position] = nextWidget;
8234
+ }
8235
+ localWidgets = nextWidgets;
8236
+ if (!helper || !initialized) {
8237
+ return container;
8238
+ }
8239
+ // We still dispose the previous widget, for its side effects and so that
8240
+ // it drops the search parameters it declared on the parent helper.
8241
+ var cleanedState = helper.state;
8242
+ if (previousWidget.dispose) {
8243
+ var next = previousWidget.dispose({
8244
+ helper: helper,
8245
+ state: cleanedState,
8246
+ recommendState: helper.recommendState,
8247
+ parent: container
8248
+ });
8249
+ if (next && !_instanceof(next, algoliasearchHelper.RecommendParameters)) {
8250
+ cleanedState = next;
8251
+ }
8252
+ }
8253
+ // We hand the previous `uiState` over to the children, then read the
8254
+ // `uiState` back from them, so that state no mounted child claims anymore
8255
+ // is dropped. This mirrors the index widget's `updateWidget`.
8256
+ var narrowedUiState = reduceChildrenUiState(localWidgets, {}, {
8257
+ searchParameters: container.getWidgetSearchParameters(cleanedState, {
8258
+ uiState: previousUiState
8259
+ }),
8260
+ helper: helper
8261
+ });
8262
+ // The search parameters are then computed again from that narrowed
8263
+ // `uiState`, so that they can't hold state the `uiState` doesn't describe.
8264
+ var newState = container.getWidgetSearchParameters(cleanedState, {
8265
+ uiState: narrowedUiState
8266
+ });
8267
+ if (nextWidget.getRenderState) {
8268
+ var renderState = nextWidget.getRenderState(instantSearchInstance.renderState[container.getIndexId()] || {}, createInitArgs(instantSearchInstance, container, instantSearchInstance._initialUiState));
8269
+ storeRenderState({
8270
+ renderState: renderState,
8271
+ instantSearchInstance: instantSearchInstance,
8272
+ parent: container
8273
+ });
8274
+ }
8275
+ if (nextWidget.init) {
8276
+ nextWidget.init(createInitArgs(instantSearchInstance, container, instantSearchInstance._initialUiState));
8277
+ }
8278
+ if (newState !== helper.state) {
8279
+ helper.setState(newState);
8280
+ }
8281
+ return container;
8282
+ },
8208
8283
  refreshUiState: function refreshUiState() {
8209
8284
  // no-op: FeedContainer doesn't own UI state
8210
8285
  },
@@ -8566,6 +8641,11 @@
8566
8641
  var helper = null;
8567
8642
  var derivedHelper = null;
8568
8643
  var lastValidSearchParameters = null;
8644
+ // The error this index has already rolled back for. Renders also happen for
8645
+ // reasons unrelated to a search (a chat panel opening, a recommend result,
8646
+ // the stalled timer), and rolling back on every one of them would discard
8647
+ // state written after the failed search.
8648
+ var restoredForError;
8569
8649
  var recomputeLocalRequestDependencies = function recomputeLocalRequestDependencies() {
8570
8650
  if (localInstantSearchInstance) {
8571
8651
  recomputeInstantSearchRequestDependencies(localInstantSearchInstance);
@@ -8705,6 +8785,92 @@
8705
8785
  }
8706
8786
  return this;
8707
8787
  },
8788
+ updateWidget: function updateWidget(previousWidget, nextWidget) {
8789
+ if (typeof previousWidget.dispose !== 'function') {
8790
+ throw new Error(withUsage$u('The widget definition expects a `dispose` method.'));
8791
+ }
8792
+ if (typeof nextWidget.init !== 'function' && typeof nextWidget.render !== 'function') {
8793
+ throw new Error(withUsage$u('The widget definition expects a `render` and/or an `init` method.'));
8794
+ }
8795
+ // The `uiState` as it is before the previous widget is detached, so that
8796
+ // the state it owns can be handed over to the next widget.
8797
+ var previousUiState = localUiState;
8798
+ previousWidget.parent = undefined;
8799
+ nextWidget.parent = this;
8800
+ if (!isIndexWidget(nextWidget)) {
8801
+ addWidgetId(nextWidget);
8802
+ }
8803
+ // The next widget takes the place of the previous one, so that the order
8804
+ // in which widgets contribute to the search parameters is unchanged.
8805
+ var nextWidgets = localWidgets.slice();
8806
+ var position = nextWidgets.indexOf(previousWidget);
8807
+ if (position === -1) {
8808
+ nextWidgets.push(nextWidget);
8809
+ } else {
8810
+ nextWidgets[position] = nextWidget;
8811
+ }
8812
+ localWidgets = nextWidgets;
8813
+ recomputeLocalRequestDependencies();
8814
+ if (!localInstantSearchInstance) {
8815
+ return this;
8816
+ }
8817
+ // We still dispose the previous widget, for its side effects. The search
8818
+ // state it returns is only used as a base when shared state isn't preserved
8819
+ // on unmount, like in `removeWidgets`.
8820
+ var disposedState = previousWidget.dispose({
8821
+ helper: helper,
8822
+ state: helper.state,
8823
+ recommendState: helper.recommendState,
8824
+ parent: this
8825
+ });
8826
+ var cleanedRecommendState = _instanceof(disposedState, algoliasearchHelper.RecommendParameters) ? disposedState : helper.recommendState;
8827
+ var cleanedSearchState = disposedState && !_instanceof(disposedState, algoliasearchHelper.RecommendParameters) ? disposedState : helper.state;
8828
+ var initialSearchParameters = localInstantSearchInstance.future.preserveSharedStateOnUnmount ? new algoliasearchHelper.SearchParameters({
8829
+ index: this.getIndexName()
8830
+ }) : cleanedSearchState;
8831
+ // We hand the previous `uiState` over to the next widgets, then read the
8832
+ // `uiState` back from them. Widgets only pick up the state they claim, so
8833
+ // this drops state that no mounted widget owns anymore (an attribute that
8834
+ // changed, for instance) instead of seeding it with `previousUiState`.
8835
+ localUiState = getLocalWidgetsUiState(localWidgets, {
8836
+ searchParameters: getLocalWidgetsSearchParameters(localWidgets, {
8837
+ uiState: previousUiState,
8838
+ initialSearchParameters: initialSearchParameters
8839
+ }),
8840
+ helper: helper
8841
+ });
8842
+ // The search parameters are then computed again from that narrowed
8843
+ // `uiState`, so that they can't hold state the `uiState` doesn't describe.
8844
+ var newState = getLocalWidgetsSearchParameters(localWidgets, {
8845
+ uiState: localUiState,
8846
+ initialSearchParameters: initialSearchParameters
8847
+ });
8848
+ privateHelperSetState(helper, {
8849
+ state: newState,
8850
+ recommendState: getLocalWidgetsRecommendParameters(localWidgets, {
8851
+ uiState: localUiState,
8852
+ initialRecommendParameters: cleanedRecommendState
8853
+ }),
8854
+ _uiState: localUiState
8855
+ });
8856
+ if (nextWidget.getRenderState) {
8857
+ var renderState = nextWidget.getRenderState(localInstantSearchInstance.renderState[this.getIndexId()] || {}, createInitArgs(localInstantSearchInstance, this, localInstantSearchInstance._initialUiState));
8858
+ storeRenderState({
8859
+ renderState: renderState,
8860
+ instantSearchInstance: localInstantSearchInstance,
8861
+ parent: this
8862
+ });
8863
+ }
8864
+ if (nextWidget.init) {
8865
+ nextWidget.init(createInitArgs(localInstantSearchInstance, this, localInstantSearchInstance._initialUiState));
8866
+ }
8867
+ if (isolated) {
8868
+ this.scheduleLocalSearch();
8869
+ } else {
8870
+ localInstantSearchInstance.scheduleSearch();
8871
+ }
8872
+ return this;
8873
+ },
8708
8874
  removeWidgets: function removeWidgets(widgets) {
8709
8875
  var _this = this;
8710
8876
  if (!Array.isArray(widgets)) {
@@ -8956,7 +9122,10 @@
8956
9122
  var instantSearchInstance = param.instantSearchInstance;
8957
9123
  // we can't attach a listener to the error event of search, as the error
8958
9124
  // then would no longer be thrown for global handlers.
8959
- if (instantSearchInstance.status === 'error' && !instantSearchInstance.mainHelper.hasPendingRequests() && lastValidSearchParameters) {
9125
+ if (instantSearchInstance.status !== 'error') {
9126
+ restoredForError = undefined;
9127
+ } else if (instantSearchInstance.error !== restoredForError && !instantSearchInstance.mainHelper.hasPendingRequests() && lastValidSearchParameters) {
9128
+ restoredForError = instantSearchInstance.error;
8960
9129
  helper.setState(lastValidSearchParameters);
8961
9130
  }
8962
9131
  // We only render index widgets if there are no results.
@@ -9223,7 +9392,7 @@
9223
9392
  });
9224
9393
  }
9225
9394
 
9226
- var version = '4.112.0';
9395
+ var version = '4.114.0';
9227
9396
 
9228
9397
  var ANONYMOUS_TOKEN_COOKIE_KEY = '_ALGOLIA';
9229
9398
  function getCookie(name) {
@@ -11135,6 +11304,14 @@
11135
11304
  instantSearchInstance: _this
11136
11305
  });
11137
11306
  _this.emit('render');
11307
+ }, // status reset accumulates instead of letting the first caller decide: a
11308
+ // render scheduled for a reason unrelated to the search must not cancel the
11309
+ // one a search result asks for, or it would strand the status on `loading`.
11310
+ function(param, param1) {
11311
+ var _param = _sliced_to_array(param, 1), tmp = _param[0], shouldResetStatus = tmp === void 0 ? true : tmp, _param1 = _sliced_to_array(param1, 1), tmp1 = _param1[0], nextShouldResetStatus = tmp1 === void 0 ? true : tmp1;
11312
+ return [
11313
+ shouldResetStatus || nextShouldResetStatus
11314
+ ];
11138
11315
  })), _define_property(_this, "onInternalStateChange", defer(function() {
11139
11316
  var nextUiState = _this.mainIndex.getWidgetUiState({});
11140
11317
  _this.middleware.forEach(function(param) {
@@ -13953,19 +14130,168 @@
13953
14130
  return laterPart.type !== 'reasoning' || laterPart.state === 'streaming';
13954
14131
  });
13955
14132
  }
13956
- var findTool = function findTool(partType, tools) {
13957
- var toolName = partType.replace('tool-', '');
13958
- var tool = tools[toolName];
13959
- if (!tool) {
13960
- var _Object_entries_find;
13961
- tool = (_Object_entries_find = Object.entries(tools).find(function(param) {
13962
- var _param = _sliced_to_array(param, 1), key = _param[0];
13963
- return startsWith(toolName, "".concat(key, "_"));
13964
- })) === null || _Object_entries_find === void 0 ? void 0 : _Object_entries_find[1];
13965
- }
13966
- return tool;
14133
+ /**
14134
+ * Whether a text part renders nothing. `text-start` creates the part before its
14135
+ * first delta, and `<context>` wrappers are a shim `ChatMessage` also drops.
14136
+ */ var isPartTextEmpty = function isPartTextEmpty(part) {
14137
+ return part.text.trim().length === 0 || part.text.startsWith('<context>') && part.text.endsWith('</context>');
14138
+ };
14139
+ /**
14140
+ * Whether a part says something about the turn's progress. Data parts and
14141
+ * unwritten text parts render nothing, so reading them would answer "what is
14142
+ * this turn doing" with a part that changed nothing on screen.
14143
+ */ var isPartProgressSignal = function isPartProgressSignal(part) {
14144
+ if (startsWith(part.type, 'data-')) {
14145
+ return false;
14146
+ }
14147
+ if (isPartText(part)) {
14148
+ return !isPartTextEmpty(part);
14149
+ }
14150
+ return true;
14151
+ };
14152
+ var findLastProgressPart = function findLastProgressPart(parts) {
14153
+ if (!parts) {
14154
+ return undefined;
14155
+ }
14156
+ for(var index = parts.length - 1; index >= 0; index--){
14157
+ var part = parts[index];
14158
+ if (isPartProgressSignal(part)) {
14159
+ return part;
14160
+ }
14161
+ }
14162
+ return undefined;
14163
+ };
14164
+ var TOOL_PART_PREFIX = 'tool-';
14165
+ /**
14166
+ * Resolves the tool a message part belongs to, from either a part type
14167
+ * (`tool-algolia_search_index`) or a bare tool name.
14168
+ *
14169
+ * An exact registration wins. Otherwise only tools whose `matchesToolName`
14170
+ * claims the name are considered, most specific first, for servers that name a
14171
+ * call after the registered tool: the Algolia MCP Server appends the index name
14172
+ * (`algolia_search_index_products`).
14173
+ *
14174
+ * Generic over the tool shape: the renderer, the loader, the widget and the
14175
+ * connector hold different subsets of the tool contract.
14176
+ */ var findTool = function findTool(partType, tools) {
14177
+ var toolName = startsWith(partType, TOOL_PART_PREFIX) ? partType.slice(TOOL_PART_PREFIX.length) : partType;
14178
+ if (tools[toolName]) {
14179
+ return tools[toolName];
14180
+ }
14181
+ var claimants = Object.keys(tools).filter(function(key) {
14182
+ var _tools_key_matchesToolName, _tools_key;
14183
+ return Boolean((_tools_key = tools[key]) === null || _tools_key === void 0 ? void 0 : (_tools_key_matchesToolName = _tools_key.matchesToolName) === null || _tools_key_matchesToolName === void 0 ? void 0 : _tools_key_matchesToolName.call(_tools_key, toolName));
14184
+ });
14185
+ if (claimants.length === 0) {
14186
+ return undefined;
14187
+ }
14188
+ // Most specific claim wins, ties by name, so the winner doesn't depend on
14189
+ // registration order.
14190
+ claimants.sort(function(a, b) {
14191
+ return b.length - a.length || (a < b ? -1 : 1);
14192
+ });
14193
+ return tools[claimants[0]];
13967
14194
  };
13968
14195
  var FACET_KEY_PREFIX = 'facet_';
14196
+ /**
14197
+ * A numeric facet value as the Algolia MCP Server emits it: an operator
14198
+ * followed by a number (`'<=1500'`). Mirrors that server's own
14199
+ * `NUMERIC_FILTER_REGEX` so the two sides cannot drift.
14200
+ */ var NUMERIC_FACET_VALUE = /^(<=|>=|=|!=|<|>)\s*(-?\d+(\.\d+)?)$/;
14201
+ var isNumericFacetValues = function isNumericFacetValues(values) {
14202
+ return values.length > 0 && values.every(function(value) {
14203
+ return NUMERIC_FACET_VALUE.test(value);
14204
+ });
14205
+ };
14206
+ /**
14207
+ * The key the Algolia MCP Server attaches its resolved search parameters under,
14208
+ * on the tool result's `_meta`. Agent Studio forwards this one key to the
14209
+ * browser by allowlist, as a `data-tool-output-metadata` part correlated by
14210
+ * `toolCallId`.
14211
+ *
14212
+ * These params are the filters the server actually searched with, after
14213
+ * defaults, clamping and the allow-list — including ones the model never saw.
14214
+ * That makes them exact where the raw `facet_` keys are ambiguous.
14215
+ */ var RESOLVED_SEARCH_PARAMS_META_KEY = 'com.algolia/resolved-search-params';
14216
+ var TOOL_OUTPUT_METADATA_PART_TYPE = 'data-tool-output-metadata';
14217
+ var isStringArray = function isStringArray(value) {
14218
+ return Array.isArray(value) && value.every(function(item) {
14219
+ return typeof item === 'string';
14220
+ });
14221
+ };
14222
+ var RESOLVED_SEARCH_PARAMS_KEYS = [
14223
+ 'query',
14224
+ 'facetFilters',
14225
+ 'numericFilters'
14226
+ ];
14227
+ /**
14228
+ * Recognizes a single resolved-params bag by shape.
14229
+ *
14230
+ * The server attaches the same `_meta` key in three shapes: one bag for a
14231
+ * single-index search, one bag per variation (an array) for a bulk search, and
14232
+ * a per-index map for a multi-index search. Only the single bag can be read
14233
+ * here. An array or a map parses to nothing, and an empty bag would still beat
14234
+ * the raw `facet_` keys and search with the query alone — so the other two
14235
+ * shapes are left to the fallback path instead.
14236
+ */ var isResolvedSearchParamsBag = function isResolvedSearchParamsBag(value) {
14237
+ return (typeof value === "undefined" ? "undefined" : _type_of(value)) === 'object' && value !== null && !Array.isArray(value) && RESOLVED_SEARCH_PARAMS_KEYS.some(function(key) {
14238
+ return key in value;
14239
+ });
14240
+ };
14241
+ /**
14242
+ * Reads the resolved search params a search tool call was answered with.
14243
+ *
14244
+ * The metadata arrives as a transient data part next to the tool call. It is
14245
+ * read from `messages` rather than through `onData` because the chat retains
14246
+ * every `data-*` part on the message, which covers the live and the replayed
14247
+ * conversation with one path. Returns `undefined` when the part is absent —
14248
+ * the case whenever the server does not emit `_meta` — or when its value is
14249
+ * not a single params bag, so that the caller falls back to the raw
14250
+ * `facet_` keys instead of searching with no filters at all.
14251
+ */ var getResolvedSearchParams = function getResolvedSearchParams(messages, toolCallId) {
14252
+ if (!messages || !toolCallId) {
14253
+ return undefined;
14254
+ }
14255
+ // Newest first: a re-answered tool call should win over its earlier result.
14256
+ for(var i = messages.length - 1; i >= 0; i--){
14257
+ var _messages_i;
14258
+ var parts = (_messages_i = messages[i]) === null || _messages_i === void 0 ? void 0 : _messages_i.parts;
14259
+ if (!Array.isArray(parts)) {
14260
+ continue;
14261
+ }
14262
+ for(var j = parts.length - 1; j >= 0; j--){
14263
+ var _data_metadata;
14264
+ var part = parts[j];
14265
+ if (!part || part.type !== TOOL_OUTPUT_METADATA_PART_TYPE) {
14266
+ continue;
14267
+ }
14268
+ var data = part.data;
14269
+ if ((data === null || data === void 0 ? void 0 : data.toolCallId) !== toolCallId) {
14270
+ continue;
14271
+ }
14272
+ var resolved = (_data_metadata = data.metadata) === null || _data_metadata === void 0 ? void 0 : _data_metadata[RESOLVED_SEARCH_PARAMS_META_KEY];
14273
+ if (!isResolvedSearchParamsBag(resolved)) {
14274
+ continue;
14275
+ }
14276
+ // Algolia reads a plain string entry as its own group, and the search
14277
+ // tool's schema accepts that mixed form
14278
+ // (`['category:Books', ['author:Alice', 'author:Bob']]`), so a flat
14279
+ // entry is a normal producer output.
14280
+ var facetFilters = Array.isArray(resolved.facetFilters) ? resolved.facetFilters.map(function(entry) {
14281
+ return typeof entry === 'string' ? [
14282
+ entry
14283
+ ] : entry;
14284
+ }).filter(isStringArray) : undefined;
14285
+ var numericFilters = isStringArray(resolved.numericFilters) ? resolved.numericFilters : undefined;
14286
+ return {
14287
+ query: typeof resolved.query === 'string' ? resolved.query : undefined,
14288
+ facetFilters: facetFilters && facetFilters.length > 0 ? facetFilters : undefined,
14289
+ numericFilters: numericFilters && numericFilters.length > 0 ? numericFilters : undefined
14290
+ };
14291
+ }
14292
+ }
14293
+ return undefined;
14294
+ };
13969
14295
  var hasQueries = function hasQueries(input) {
13970
14296
  return Array.isArray(input.queries);
13971
14297
  };
@@ -13984,18 +14310,41 @@
13984
14310
  }
13985
14311
  var facetFilters = Object.entries(query).reduce(function(acc, param) {
13986
14312
  var _param = _sliced_to_array(param, 2), key = _param[0], value = _param[1];
13987
- if (!startsWith(key, FACET_KEY_PREFIX) || !Array.isArray(value)) {
14313
+ if (!startsWith(key, FACET_KEY_PREFIX)) {
13988
14314
  return acc;
13989
14315
  }
13990
14316
  var attribute = key.slice(FACET_KEY_PREFIX.length);
14317
+ if (!attribute) {
14318
+ return acc;
14319
+ }
14320
+ // A boolean facet arrives as a primitive, not an array.
14321
+ if (typeof value === 'boolean') {
14322
+ acc.push([
14323
+ "".concat(attribute, ":").concat(value)
14324
+ ]);
14325
+ return acc;
14326
+ }
14327
+ if (!Array.isArray(value)) {
14328
+ return acc;
14329
+ }
13991
14330
  var values = value.filter(function(item) {
13992
14331
  return typeof item === 'string';
13993
14332
  });
13994
- if (attribute && values.length > 0) {
13995
- acc.push(values.map(function(item) {
13996
- return "".concat(attribute, ":").concat(item);
13997
- }));
14333
+ if (values.length === 0) {
14334
+ return acc;
13998
14335
  }
14336
+ // A numeric facet needs a numeric refinement, which this shape cannot
14337
+ // express. `price:<=1500` would refine on a value no record holds, so the
14338
+ // search would quietly return the wrong results. Dropping it loses the
14339
+ // filter instead, which the user can see. Where the tool's resolved
14340
+ // search params are available, `getResolvedSearchParams` applies the
14341
+ // numeric refinement properly and this path is not reached.
14342
+ if (isNumericFacetValues(values)) {
14343
+ return acc;
14344
+ }
14345
+ acc.push(values.map(function(item) {
14346
+ return "".concat(attribute, ":").concat(item);
14347
+ }));
13999
14348
  return acc;
14000
14349
  }, []);
14001
14350
  return facetFilters.length > 0 ? facetFilters : undefined;
@@ -14008,8 +14357,24 @@
14008
14357
  * Algolia MCP Server search tool instead expresses refinements as individual
14009
14358
  * `facet_<attribute>` keys (e.g. `facet_categories: ['Books', 'Toys']`), which
14010
14359
  * are converted here into `[['attribute:value']]`.
14011
- */ var getApplyFiltersParamsFromToolInput = function getApplyFiltersParamsFromToolInput(input) {
14360
+ *
14361
+ * Pass `resolved` (from `getResolvedSearchParams`) to use the filters the
14362
+ * server actually searched with instead of re-deriving them from the raw keys.
14363
+ * That is the only way to apply a numeric refinement.
14364
+ */ var getApplyFiltersParamsFromToolInput = function getApplyFiltersParamsFromToolInput(input, resolved) {
14012
14365
  var query = getSearchToolQuery(input);
14366
+ // The resolved params are what the server actually searched with, so they win
14367
+ // wherever they exist. Only they can express a numeric refinement: a numeric
14368
+ // facet and a string facet whose value is literally `'<=1500'` are identical
14369
+ // in the raw `facet_` keys.
14370
+ if (resolved) {
14371
+ var _resolved_query;
14372
+ return {
14373
+ query: (_resolved_query = resolved.query) !== null && _resolved_query !== void 0 ? _resolved_query : query === null || query === void 0 ? void 0 : query.query,
14374
+ facetFilters: resolved.facetFilters,
14375
+ numericFilters: resolved.numericFilters
14376
+ };
14377
+ }
14013
14378
  return {
14014
14379
  query: query === null || query === void 0 ? void 0 : query.query,
14015
14380
  facetFilters: getFacetFilters(query)
@@ -14130,8 +14495,6 @@
14130
14495
  sendEvent: context.sendEvent
14131
14496
  };
14132
14497
  }
14133
- // Keep in sync with packages/instantsearch.js/src/lib/chat/index.ts
14134
- var SearchIndexToolType$1 = 'algolia_search_index';
14135
14498
  function createChatMessageComponent(param) {
14136
14499
  var createElement = param.createElement, Fragment = param.Fragment;
14137
14500
  var Button = createButtonComponent({
@@ -14142,7 +14505,7 @@
14142
14505
  });
14143
14506
  return function ChatMessage(userProps) {
14144
14507
  var _messages_;
14145
- var _userProps_classNames = userProps.classNames, classNames = _userProps_classNames === void 0 ? {} : _userProps_classNames, message = userProps.message, _userProps_side = userProps.side, side = _userProps_side === void 0 ? 'left' : _userProps_side, _userProps_variant = userProps.variant, variant = _userProps_variant === void 0 ? 'subtle' : _userProps_variant, _userProps_actions = userProps.actions, actions = _userProps_actions === void 0 ? [] : _userProps_actions, _userProps_autoHideActions = userProps.autoHideActions, autoHideActions = _userProps_autoHideActions === void 0 ? false : _userProps_autoHideActions, LeadingComponent = userProps.leadingComponent, ActionsComponent = userProps.actionsComponent, FooterComponent = userProps.footerComponent, TextComponent = userProps.textComponent, indexUiState = userProps.indexUiState, setIndexUiState = userProps.setIndexUiState, userTranslations = userProps.translations, suggestionsElement = userProps.suggestionsElement, _userProps_showReasoning = userProps.showReasoning, showReasoning = _userProps_showReasoning === void 0 ? false : _userProps_showReasoning, _userProps_parseMarkdown = userProps.parseMarkdown, parseMarkdown = _userProps_parseMarkdown === void 0 ? true : _userProps_parseMarkdown, ownMessages = userProps.messages, /* eslint-disable typescript/no-deprecated -- reading the
14508
+ var _userProps_classNames = userProps.classNames, classNames = _userProps_classNames === void 0 ? {} : _userProps_classNames, message = userProps.message, _userProps_side = userProps.side, side = _userProps_side === void 0 ? 'left' : _userProps_side, _userProps_variant = userProps.variant, variant = _userProps_variant === void 0 ? 'subtle' : _userProps_variant, _userProps_actions = userProps.actions, actions = _userProps_actions === void 0 ? [] : _userProps_actions, _userProps_autoHideActions = userProps.autoHideActions, autoHideActions = _userProps_autoHideActions === void 0 ? false : _userProps_autoHideActions, LeadingComponent = userProps.leadingComponent, ActionsComponent = userProps.actionsComponent, FooterComponent = userProps.footerComponent, TextComponent = userProps.textComponent, indexUiState = userProps.indexUiState, setIndexUiState = userProps.setIndexUiState, userTranslations = userProps.translations, suggestionsElement = userProps.suggestionsElement, loaderElement = userProps.loaderElement, _userProps_showReasoning = userProps.showReasoning, showReasoning = _userProps_showReasoning === void 0 ? false : _userProps_showReasoning, _userProps_parseMarkdown = userProps.parseMarkdown, parseMarkdown = _userProps_parseMarkdown === void 0 ? true : _userProps_parseMarkdown, ownMessages = userProps.messages, /* eslint-disable typescript/no-deprecated -- reading the
14146
14509
  deprecated aliases is the point: they are resolved into `context`
14147
14510
  below so callers on the previous API keep working. */ ownStatus = userProps.status, ownTools = userProps.tools, ownOnClose = userProps.onClose, /* eslint-enable typescript/no-deprecated */ sharedContext = userProps.context, props = _object_without_properties(userProps, [
14148
14511
  "classNames",
@@ -14159,6 +14522,7 @@
14159
14522
  "setIndexUiState",
14160
14523
  "translations",
14161
14524
  "suggestionsElement",
14525
+ "loaderElement",
14162
14526
  "showReasoning",
14163
14527
  "parseMarkdown",
14164
14528
  "messages",
@@ -14273,15 +14637,12 @@
14273
14637
  }, markdown);
14274
14638
  }
14275
14639
  if (startsWith(part.type, 'tool-')) {
14276
- var _message_metadata;
14277
- var toolName = part.type.replace('tool-', '');
14278
- var tool = tools[toolName];
14279
- // Compatibility shim with Algolia MCP Server search tool
14280
- if (!tool && startsWith(toolName, "".concat(SearchIndexToolType$1, "_"))) {
14281
- tool = tools[SearchIndexToolType$1];
14282
- }
14283
- var displayResultsEnabled = ((_message_metadata = message.metadata) === null || _message_metadata === void 0 ? void 0 : _message_metadata.displayResultsEnabled) === true;
14284
- if (displayResultsEnabled && tool && tool === tools[SearchIndexToolType$1]) {
14640
+ var _tool_shouldRender;
14641
+ var tool = findTool(part.type, tools);
14642
+ if ((tool === null || tool === void 0 ? void 0 : (_tool_shouldRender = tool.shouldRender) === null || _tool_shouldRender === void 0 ? void 0 : _tool_shouldRender.call(tool, _object_spread_props(_object_spread({}, context), {
14643
+ message: part,
14644
+ parentMessage: message
14645
+ }))) === false) {
14285
14646
  return null;
14286
14647
  }
14287
14648
  if (tool) {
@@ -14350,7 +14711,7 @@
14350
14711
  className: cx(cssClasses.content)
14351
14712
  }, /*#__PURE__*/ createElement("div", {
14352
14713
  className: cx(cssClasses.message)
14353
- }, message.parts.map(renderMessagePart)), suggestionsElement, showActions && /*#__PURE__*/ createElement("div", {
14714
+ }, message.parts.map(renderMessagePart), loaderElement), suggestionsElement, showActions && /*#__PURE__*/ createElement("div", {
14354
14715
  className: cx(cssClasses.actions),
14355
14716
  "aria-label": translations.actionsLabel
14356
14717
  }, ActionsComponent ? /*#__PURE__*/ createElement(ActionsComponent, {
@@ -14453,28 +14814,23 @@
14453
14814
  function createChatMessageLoaderComponent(param) {
14454
14815
  var createElement = param.createElement;
14455
14816
  return function ChatMessageLoader(userProps) {
14456
- var userTranslations = userProps.translations;
14817
+ var userTranslations = userProps.translations, _userProps_inline = userProps.inline, inline = _userProps_inline === void 0 ? false : _userProps_inline, className = userProps.className; // The turn context is for custom loaders, not for the DOM.
14457
14818
  userProps.context;
14458
14819
  var props = _object_without_properties(userProps, [
14459
14820
  "translations",
14821
+ "inline",
14822
+ "className",
14460
14823
  "context"
14461
14824
  ]);
14462
14825
  var translations = _object_spread({
14463
14826
  loaderText: ''
14464
14827
  }, userTranslations);
14465
- return /*#__PURE__*/ createElement("article", _object_spread({
14466
- className: "ais-ChatMessageLoader ais-ChatMessage ais-ChatMessage--left ais-ChatMessage--subtle"
14467
- }, props), /*#__PURE__*/ createElement("div", {
14468
- className: "ais-ChatMessage-container"
14469
- }, /*#__PURE__*/ createElement("div", {
14470
- className: "ais-ChatMessage-leading"
14471
- }, /*#__PURE__*/ createElement("div", {
14828
+ var spinner = /*#__PURE__*/ createElement("div", {
14472
14829
  className: "ais-ChatMessageLoader-spinner"
14473
14830
  }, /*#__PURE__*/ createElement(LoadingSpinnerIcon, {
14474
14831
  createElement: createElement
14475
- }))), /*#__PURE__*/ createElement("div", {
14476
- className: "ais-ChatMessage-content"
14477
- }, /*#__PURE__*/ createElement("div", {
14832
+ }));
14833
+ var body = /*#__PURE__*/ createElement("div", {
14478
14834
  className: "ais-ChatMessage-message"
14479
14835
  }, translations.loaderText && /*#__PURE__*/ createElement("div", {
14480
14836
  className: "ais-ChatMessageLoader-text"
@@ -14484,13 +14840,30 @@
14484
14840
  className: "ais-ChatMessageLoader-skeletonItem"
14485
14841
  }), /*#__PURE__*/ createElement("div", {
14486
14842
  className: "ais-ChatMessageLoader-skeletonItem"
14487
- }))))));
14843
+ })));
14844
+ if (inline) {
14845
+ return /*#__PURE__*/ createElement("div", _object_spread_props(_object_spread({}, props), {
14846
+ className: cx('ais-ChatMessageLoader', 'ais-ChatMessageLoader--inline', className)
14847
+ }), spinner, body);
14848
+ }
14849
+ return /*#__PURE__*/ createElement("article", _object_spread_props(_object_spread({}, props), {
14850
+ className: cx('ais-ChatMessageLoader ais-ChatMessage ais-ChatMessage--left ais-ChatMessage--subtle', className)
14851
+ }), /*#__PURE__*/ createElement("div", {
14852
+ className: "ais-ChatMessage-container"
14853
+ }, /*#__PURE__*/ createElement("div", {
14854
+ className: "ais-ChatMessage-leading"
14855
+ }, spinner), /*#__PURE__*/ createElement("div", {
14856
+ className: "ais-ChatMessage-content"
14857
+ }, body)));
14488
14858
  };
14489
14859
  }
14490
14860
 
14491
14861
  var copyToClipboard = function copyToClipboard(message) {
14492
14862
  navigator.clipboard.writeText(getTextContent(message));
14493
14863
  };
14864
+ var DEFAULT_LOADER_SHOW_DELAY = 250;
14865
+ // Short enough that it never lingers over the content that replaced it.
14866
+ var DEFAULT_LOADER_MIN_DURATION = 200;
14494
14867
  function getInstantSearchStatus(tools) {
14495
14868
  var _Object_values_find_insightsEventContext, _Object_values_find;
14496
14869
  return (_Object_values_find = Object.values(tools).find(function(tool) {
@@ -14509,7 +14882,7 @@
14509
14882
  Fragment: Fragment
14510
14883
  });
14511
14884
  return function DefaultMessage(param) {
14512
- var message = param.message, userMessageProps = param.userMessageProps, assistantMessageProps = param.assistantMessageProps, indexUiState = param.indexUiState, setIndexUiState = param.setIndexUiState, onReload = param.onReload, onFeedback = param.onFeedback, feedbackState = param.feedbackState, actionsComponent = param.actionsComponent, classNames = param.classNames, messageTranslations = param.messageTranslations, translations = param.translations, suggestionsElement = param.suggestionsElement, context = param.context;
14885
+ var message = param.message, userMessageProps = param.userMessageProps, assistantMessageProps = param.assistantMessageProps, indexUiState = param.indexUiState, setIndexUiState = param.setIndexUiState, onReload = param.onReload, onFeedback = param.onFeedback, feedbackState = param.feedbackState, actionsComponent = param.actionsComponent, classNames = param.classNames, messageTranslations = param.messageTranslations, translations = param.translations, suggestionsElement = param.suggestionsElement, loaderElement = param.loaderElement, context = param.context;
14513
14886
  var defaultAssistantActions = _to_consumable_array(hasTextContent(message) ? [
14514
14887
  {
14515
14888
  title: translations.copyToClipboardLabel,
@@ -14600,6 +14973,7 @@
14600
14973
  classNames: classNames,
14601
14974
  translations: messageTranslations,
14602
14975
  suggestionsElement: suggestionsElement,
14976
+ loaderElement: loaderElement,
14603
14977
  context: context
14604
14978
  }, messageProps), {
14605
14979
  message: message,
@@ -14608,10 +14982,128 @@
14608
14982
  };
14609
14983
  }
14610
14984
  function createChatMessagesComponent(param) {
14611
- var createElement = param.createElement, Fragment = param.Fragment, useMemo = param.useMemo;
14985
+ var createElement = param.createElement, Fragment = param.Fragment, useMemo = param.useMemo, useState = param.useState, useEffect = param.useEffect;
14612
14986
  var Button = createButtonComponent({
14613
14987
  createElement: createElement
14614
14988
  });
14989
+ /**
14990
+ * Smooths the loading state into a visibility. Several transitions in a turn
14991
+ * flip it twice within a few frames, which reads as the loader popping in and
14992
+ * out, so a loader coming back mid-turn waits out `showDelay` and a visible
14993
+ * one holds for `minDuration`.
14994
+ */ function useLoaderVisibility(param) {
14995
+ var isLoading = param.isLoading, isTurnActive = param.isTurnActive, showDelay = param.showDelay, minDuration = param.minDuration;
14996
+ var _useState = _sliced_to_array(useState({
14997
+ phase: 'idle'
14998
+ }), 2), loaderState = _useState[0], setLoaderState = _useState[1];
14999
+ var isVisible = isTurnActive && (isLoading && (loaderState.phase === 'idle' || loaderState.phase === 'ready' || loaderState.phase === 'hidden' && showDelay <= 0) || loaderState.phase === 'visible' && (isLoading || minDuration > loaderState.elapsedDuration));
15000
+ useEffect(function() {
15001
+ if (!isTurnActive) {
15002
+ if (loaderState.phase !== 'idle') {
15003
+ setLoaderState({
15004
+ phase: 'idle'
15005
+ });
15006
+ }
15007
+ return undefined;
15008
+ }
15009
+ if (loaderState.phase === 'idle') {
15010
+ if (isLoading) {
15011
+ setLoaderState({
15012
+ phase: 'visible',
15013
+ shownAt: Date.now(),
15014
+ elapsedDuration: 0
15015
+ });
15016
+ }
15017
+ return undefined;
15018
+ }
15019
+ if (loaderState.phase === 'visible') {
15020
+ if (!isLoading && minDuration <= loaderState.elapsedDuration) {
15021
+ setLoaderState({
15022
+ phase: 'hidden'
15023
+ });
15024
+ return undefined;
15025
+ }
15026
+ if (minDuration <= loaderState.elapsedDuration) {
15027
+ return undefined;
15028
+ }
15029
+ var remaining = Math.max(0, loaderState.shownAt + minDuration - Date.now());
15030
+ if (remaining === 0) {
15031
+ setLoaderState(_object_spread_props(_object_spread({}, loaderState), {
15032
+ elapsedDuration: minDuration
15033
+ }));
15034
+ return undefined;
15035
+ }
15036
+ var timer = setTimeout(function() {
15037
+ setLoaderState(function(current) {
15038
+ return current.phase === 'visible' && current.shownAt === loaderState.shownAt ? _object_spread_props(_object_spread({}, current), {
15039
+ elapsedDuration: Math.max(current.elapsedDuration, minDuration)
15040
+ }) : current;
15041
+ });
15042
+ }, remaining);
15043
+ return function() {
15044
+ return clearTimeout(timer);
15045
+ };
15046
+ }
15047
+ if (loaderState.phase === 'hidden') {
15048
+ if (isLoading) {
15049
+ var now = Date.now();
15050
+ setLoaderState(showDelay <= 0 ? {
15051
+ phase: 'visible',
15052
+ shownAt: now,
15053
+ elapsedDuration: 0
15054
+ } : {
15055
+ phase: 'waiting',
15056
+ pendingSince: now
15057
+ });
15058
+ }
15059
+ return undefined;
15060
+ }
15061
+ if (loaderState.phase === 'ready') {
15062
+ setLoaderState(isLoading ? {
15063
+ phase: 'visible',
15064
+ shownAt: loaderState.shownAt,
15065
+ elapsedDuration: loaderState.elapsedDuration
15066
+ } : {
15067
+ phase: 'hidden'
15068
+ });
15069
+ return undefined;
15070
+ }
15071
+ if (!isLoading) {
15072
+ setLoaderState({
15073
+ phase: 'hidden'
15074
+ });
15075
+ return undefined;
15076
+ }
15077
+ var remaining1 = Math.max(0, loaderState.pendingSince + showDelay - Date.now());
15078
+ if (remaining1 === 0) {
15079
+ setLoaderState({
15080
+ phase: 'visible',
15081
+ shownAt: Date.now(),
15082
+ elapsedDuration: 0
15083
+ });
15084
+ return undefined;
15085
+ }
15086
+ var timer1 = setTimeout(function() {
15087
+ setLoaderState(function(current) {
15088
+ return current.phase === 'waiting' && current.pendingSince === loaderState.pendingSince ? {
15089
+ phase: 'ready',
15090
+ shownAt: Date.now(),
15091
+ elapsedDuration: 0
15092
+ } : current;
15093
+ });
15094
+ }, remaining1);
15095
+ return function() {
15096
+ return clearTimeout(timer1);
15097
+ };
15098
+ }, [
15099
+ isLoading,
15100
+ isTurnActive,
15101
+ loaderState,
15102
+ minDuration,
15103
+ showDelay
15104
+ ]);
15105
+ return isVisible;
15106
+ }
14615
15107
  var DefaultMessageComponent = createDefaultMessageComponent({
14616
15108
  createElement: createElement,
14617
15109
  Fragment: Fragment
@@ -14632,6 +15124,12 @@
14632
15124
  var showReasoning = messageProps === null || messageProps === void 0 ? void 0 : messageProps.showReasoning;
14633
15125
  var parseMarkdown = messageProps === null || messageProps === void 0 ? void 0 : messageProps.parseMarkdown;
14634
15126
  var textComponent = messageProps === null || messageProps === void 0 ? void 0 : messageProps.textComponent;
15127
+ // A completed row is memoized against its own message, but `shouldRender`
15128
+ // reads the whole `context`: a predicate can hide an older tool result once a
15129
+ // newer message arrives. Track the verdicts themselves rather than
15130
+ // `context.messages`, so the row re-renders exactly when one flips instead of
15131
+ // on every streaming delta.
15132
+ var shouldRenderVerdicts = getShouldRenderVerdicts(props.context, props.message);
14635
15133
  // Custom text components receive the conversation, so their completed rows
14636
15134
  // must update with it. Keep the default renderer's streaming optimization.
14637
15135
  var textComponentMessages = textComponent ? props.context.messages : undefined;
@@ -14659,10 +15157,12 @@
14659
15157
  props.message,
14660
15158
  props.isCurrentMessage,
14661
15159
  props.status,
15160
+ shouldRenderVerdicts,
14662
15161
  props.context.maximized,
14663
15162
  props.context.open,
14664
15163
  instantSearchStatus,
14665
15164
  props.suggestionsElement,
15165
+ props.loaderElement,
14666
15166
  messageFeedback,
14667
15167
  showReasoning,
14668
15168
  parseMarkdown,
@@ -14687,17 +15187,21 @@
14687
15187
  return function ChatMessages(userProps) {
14688
15188
  var _ref;
14689
15189
  var _lastMessage_parts, _lastMessage_parts1;
14690
- var _userProps_classNames = userProps.classNames, classNames = _userProps_classNames === void 0 ? {} : _userProps_classNames, _userProps_messageClassNames = userProps.messageClassNames, messageClassNames = _userProps_messageClassNames === void 0 ? {} : _userProps_messageClassNames, messageTranslations = userProps.messageTranslations, _userProps_messages = userProps.messages, messages = _userProps_messages === void 0 ? [] : _userProps_messages, MessageComponent = userProps.messageComponent, LoaderComponent = userProps.loaderComponent, ErrorComponent = userProps.errorComponent, EmptyComponent = userProps.emptyComponent, ActionsComponent = userProps.actionsComponent, tools = userProps.tools, indexUiState = userProps.indexUiState, setIndexUiState = userProps.setIndexUiState, _userProps_status = userProps.status, status = _userProps_status === void 0 ? 'ready' : _userProps_status, error = userProps.error, _userProps_hideScrollToBottom = userProps.hideScrollToBottom, hideScrollToBottom = _userProps_hideScrollToBottom === void 0 ? false : _userProps_hideScrollToBottom, onReload = userProps.onReload, onNewConversation = userProps.onNewConversation, onClose = userProps.onClose, sendMessage = userProps.sendMessage, _userProps_regenerate = userProps.regenerate, regenerate = _userProps_regenerate === void 0 ? function() {
15190
+ var _userProps_classNames = userProps.classNames, classNames = _userProps_classNames === void 0 ? {} : _userProps_classNames, _userProps_messageClassNames = userProps.messageClassNames, messageClassNames = _userProps_messageClassNames === void 0 ? {} : _userProps_messageClassNames, messageTranslations = userProps.messageTranslations, _userProps_messages = userProps.messages, messages = _userProps_messages === void 0 ? [] : _userProps_messages, MessageComponent = userProps.messageComponent, LoaderComponent = userProps.loaderComponent, _userProps_loaderPosition = userProps.loaderPosition, loaderPosition = _userProps_loaderPosition === void 0 ? 'messages-end' : _userProps_loaderPosition, shouldShowLoader = userProps.shouldShowLoader, _userProps_loaderShowDelay = userProps.loaderShowDelay, loaderShowDelay = _userProps_loaderShowDelay === void 0 ? DEFAULT_LOADER_SHOW_DELAY : _userProps_loaderShowDelay, _userProps_loaderMinDuration = userProps.loaderMinDuration, loaderMinDuration = _userProps_loaderMinDuration === void 0 ? DEFAULT_LOADER_MIN_DURATION : _userProps_loaderMinDuration, ErrorComponent = userProps.errorComponent, EmptyComponent = userProps.emptyComponent, ActionsComponent = userProps.actionsComponent, tools = userProps.tools, indexUiState = userProps.indexUiState, setIndexUiState = userProps.setIndexUiState, _userProps_status = userProps.status, status = _userProps_status === void 0 ? 'ready' : _userProps_status, error = userProps.error, _userProps_hideScrollToBottom = userProps.hideScrollToBottom, hideScrollToBottom = _userProps_hideScrollToBottom === void 0 ? false : _userProps_hideScrollToBottom, onReload = userProps.onReload, onNewConversation = userProps.onNewConversation, onClose = userProps.onClose, sendMessage = userProps.sendMessage, _userProps_regenerate = userProps.regenerate, regenerate = _userProps_regenerate === void 0 ? function() {
14691
15191
  return Promise.resolve();
14692
15192
  } : _userProps_regenerate, _userProps_stop = userProps.stop, stop = _userProps_stop === void 0 ? function() {
14693
15193
  return Promise.resolve();
14694
- } : _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, [
15194
+ } : _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, [
14695
15195
  "classNames",
14696
15196
  "messageClassNames",
14697
15197
  "messageTranslations",
14698
15198
  "messages",
14699
15199
  "messageComponent",
14700
15200
  "loaderComponent",
15201
+ "loaderPosition",
15202
+ "shouldShowLoader",
15203
+ "loaderShowDelay",
15204
+ "loaderMinDuration",
14701
15205
  "errorComponent",
14702
15206
  "emptyComponent",
14703
15207
  "actionsComponent",
@@ -14726,6 +15230,7 @@
14726
15230
  "contentRef",
14727
15231
  "onScrollToBottom",
14728
15232
  "suggestionsElement",
15233
+ "suggestionsLoading",
14729
15234
  "onFeedback",
14730
15235
  "feedbackState"
14731
15236
  ]);
@@ -14746,6 +15251,7 @@
14746
15251
  scrollToBottomHidden: cx('ais-ChatMessages-scrollToBottom--hidden', classNames.scrollToBottomHidden)
14747
15252
  };
14748
15253
  var lastMessage = messages[messages.length - 1];
15254
+ var showReasoning = assistantMessageProps === null || assistantMessageProps === void 0 ? void 0 : assistantMessageProps.showReasoning;
14749
15255
  var lastPart = lastMessage === null || lastMessage === void 0 ? void 0 : (_lastMessage_parts = lastMessage.parts) === null || _lastMessage_parts === void 0 ? void 0 : _lastMessage_parts[lastMessage.parts.length - 1];
14750
15256
  // `activePart` means "the part currently being processed". It must clear
14751
15257
  // when nothing is in progress: once the response settles (`ready`/`error`),
@@ -14756,10 +15262,13 @@
14756
15262
  var activePart = isProcessing && (lastMessage === null || lastMessage === void 0 ? void 0 : lastMessage.role) === 'assistant' ? lastPart : undefined;
14757
15263
  // The scan slices the remaining parts per candidate, and only the loader reads
14758
15264
  // it, so skip it entirely while the opt-in is off.
14759
- var hasActiveReasoning = (assistantMessageProps === null || assistantMessageProps === void 0 ? void 0 : assistantMessageProps.showReasoning) ? (_ref = lastMessage === null || lastMessage === void 0 ? void 0 : (_lastMessage_parts1 = lastMessage.parts) === null || _lastMessage_parts1 === void 0 ? void 0 : _lastMessage_parts1.some(function(_, index, parts) {
15265
+ // The loader reports on the assistant's turn, so it only ever belongs to an
15266
+ // assistant message. While `submitted` the last message is still the user's
15267
+ // own, and the loader belongs to no message at all.
15268
+ var loaderMessage = (lastMessage === null || lastMessage === void 0 ? void 0 : lastMessage.role) === 'assistant' ? lastMessage : undefined;
15269
+ var hasActiveReasoning = showReasoning ? (_ref = lastMessage === null || lastMessage === void 0 ? void 0 : (_lastMessage_parts1 = lastMessage.parts) === null || _lastMessage_parts1 === void 0 ? void 0 : _lastMessage_parts1.some(function(_, index, parts) {
14760
15270
  return isReasoningPartActive(parts, index);
14761
15271
  })) !== null && _ref !== void 0 ? _ref : false : false;
14762
- var showLoader = getShowLoader(status, lastPart, tools, assistantMessageProps === null || assistantMessageProps === void 0 ? void 0 : assistantMessageProps.showReasoning, hasActiveReasoning);
14763
15272
  // The shared context handed to every overridable chat component, so custom
14764
15273
  // components can read the current chat state and common callbacks from a
14765
15274
  // single, consistent place.
@@ -14780,14 +15289,45 @@
14780
15289
  onNewConversation: onNewConversation,
14781
15290
  onClose: onClose
14782
15291
  };
15292
+ // The loader also reads what the turn is doing, which no other component
15293
+ // needs, so its context extends the shared one.
15294
+ var loaderContext = _object_spread_props(_object_spread({}, context), {
15295
+ phase: getLoaderPhase(status, loaderMessage, showReasoning),
15296
+ message: loaderMessage
15297
+ });
15298
+ var defaultShowLoader = getShowLoader(context, showReasoning, hasActiveReasoning);
15299
+ var isLoading = shouldShowLoader ? shouldShowLoader(_object_spread_props(_object_spread({}, loaderContext), {
15300
+ defaultValue: defaultShowLoader
15301
+ })) : defaultShowLoader;
15302
+ var showLoader = useLoaderVisibility({
15303
+ isLoading: isLoading,
15304
+ isTurnActive: isProcessing,
15305
+ showDelay: loaderShowDelay,
15306
+ minDuration: loaderMinDuration
15307
+ });
14783
15308
  var showEmpty = messages.length === 0 && !showLoader && !isClearing && status !== 'error';
14784
15309
  var DefaultMessage = MessageComponent || MemoizedDefaultMessage;
14785
15310
  var DefaultLoader = LoaderComponent || DefaultLoaderComponent;
14786
15311
  var DefaultError = ErrorComponent || DefaultErrorComponent;
15312
+ // An inline loader needs an assistant message to live in; before the first
15313
+ // response part there is none, so it falls back to its own row.
15314
+ var isLoaderInline = loaderPosition === 'message-inline' && loaderMessage !== undefined;
15315
+ var loaderText = typeof translations.loaderText === 'function' ? translations.loaderText(loaderContext) : translations.loaderText;
15316
+ var loaderElement = showLoader ? /*#__PURE__*/ createElement(DefaultLoader, {
15317
+ context: loaderContext,
15318
+ inline: isLoaderInline,
15319
+ translations: {
15320
+ loaderText: loaderText
15321
+ }
15322
+ }) : undefined;
15323
+ // Waits for the answer's text and for the loader to step aside, so two
15324
+ // progress affordances never stack up.
15325
+ var showPendingSuggestions = suggestionsLoading && !showLoader && lastMessage !== undefined && hasTextContent(lastMessage);
14787
15326
  return /*#__PURE__*/ createElement("div", _object_spread_props(_object_spread({}, props), {
14788
15327
  className: cx(cssClasses.root, props.className),
14789
15328
  role: "log",
14790
- "aria-live": "polite"
15329
+ "aria-live": "polite",
15330
+ "aria-busy": isProcessing ? 'true' : undefined
14791
15331
  }), /*#__PURE__*/ createElement("div", {
14792
15332
  className: cx(cssClasses.scroll),
14793
15333
  ref: scrollRef
@@ -14826,14 +15366,10 @@
14826
15366
  classNames: messageClassNames,
14827
15367
  messageTranslations: messageTranslations,
14828
15368
  context: context,
14829
- suggestionsElement: status === 'ready' && message.role === 'assistant' && index === messages.length - 1 ? suggestionsElement : undefined
15369
+ suggestionsElement: (status === 'ready' || showPendingSuggestions) && message.role === 'assistant' && index === messages.length - 1 ? suggestionsElement : undefined,
15370
+ loaderElement: isLoaderInline && index === messages.length - 1 ? loaderElement : undefined
14830
15371
  });
14831
- }), showLoader && /*#__PURE__*/ createElement(DefaultLoader, {
14832
- translations: {
14833
- loaderText: translations.loaderText
14834
- },
14835
- context: context
14836
- }), status === 'error' && /*#__PURE__*/ createElement(DefaultError, {
15372
+ }), !isLoaderInline && loaderElement, status === 'error' && /*#__PURE__*/ createElement(DefaultError, {
14837
15373
  onNewConversation: onNewConversation,
14838
15374
  errorMessage: error === null || error === void 0 ? void 0 : error.message,
14839
15375
  translations: // `fallbackResponse` that's safe to display verbatim; for
@@ -14860,17 +15396,65 @@
14860
15396
  })));
14861
15397
  };
14862
15398
  }
14863
- var getShowLoader = function getShowLoader(status, lastPart, tools, showReasoning, hasActiveReasoning) {
15399
+ var getLoaderPhase = function getLoaderPhase(status, message, showReasoning) {
15400
+ if (status === 'submitted') return 'submitted';
15401
+ var lastPart = findLastProgressPart(message === null || message === void 0 ? void 0 : message.parts);
15402
+ if (!lastPart) return 'thinking';
15403
+ if (isPartTool(lastPart)) return 'tool';
15404
+ if (showReasoning && lastPart.type === 'reasoning') return 'reasoning';
15405
+ return 'thinking';
15406
+ };
15407
+ /**
15408
+ * A stable signature of every `shouldRender` verdict in a message, so a memoized
15409
+ * row can be invalidated when a verdict changes. `undefined` when no tool part
15410
+ * in the message declares the predicate.
15411
+ */ var getShouldRenderVerdicts = function getShouldRenderVerdicts(context, message) {
15412
+ var _message_parts;
15413
+ var verdicts;
15414
+ (_message_parts = message.parts) === null || _message_parts === void 0 ? void 0 : _message_parts.forEach(function(part, index) {
15415
+ var _findTool;
15416
+ if (!isPartTool(part)) {
15417
+ return;
15418
+ }
15419
+ var shouldRender = (_findTool = findTool(part.type, context.tools)) === null || _findTool === void 0 ? void 0 : _findTool.shouldRender;
15420
+ if (!shouldRender) {
15421
+ return;
15422
+ }
15423
+ verdicts = "".concat(verdicts !== null && verdicts !== void 0 ? verdicts : '').concat(index, ":").concat(shouldRender(_object_spread_props(_object_spread({}, context), {
15424
+ message: part,
15425
+ parentMessage: message
15426
+ })), ";");
15427
+ });
15428
+ return verdicts;
15429
+ };
15430
+ var getShowLoader = function getShowLoader(context, showReasoning, hasActiveReasoning) {
15431
+ var status = context.status, messages = context.messages, tools = context.tools;
14864
15432
  if (status !== 'submitted' && status !== 'streaming') return false;
14865
15433
  if (status === 'submitted') return true;
15434
+ var lastMessage = messages[messages.length - 1];
15435
+ // Parts that render nothing must not answer for the turn's progress, or the
15436
+ // loader flips on a part that changed nothing on screen.
15437
+ var lastPart = findLastProgressPart(lastMessage === null || lastMessage === void 0 ? void 0 : lastMessage.parts);
14866
15438
  if (!lastPart) return true;
14867
15439
  // An active disclosure carries its own progress affordance, so the loader would
14868
15440
  // double it. Settled reasoning still shows it: the answer has not started.
14869
15441
  if (showReasoning && hasActiveReasoning) return false;
14870
15442
  if (isPartText(lastPart)) return false;
14871
- if (isPartTool(lastPart) && lastPart.state === 'input-streaming') {
15443
+ if (isPartTool(lastPart)) {
15444
+ var _tool_shouldRender;
14872
15445
  var tool = findTool(lastPart.type, tools);
14873
- return !(tool === null || tool === void 0 ? void 0 : tool.streamInput);
15446
+ // A part the tool declines to render leaves nothing on screen, so the turn
15447
+ // still reads as in progress — keep the loader up rather than letting a
15448
+ // settled-but-hidden part terminate it.
15449
+ if (lastMessage && (tool === null || tool === void 0 ? void 0 : (_tool_shouldRender = tool.shouldRender) === null || _tool_shouldRender === void 0 ? void 0 : _tool_shouldRender.call(tool, _object_spread_props(_object_spread({}, context), {
15450
+ message: lastPart,
15451
+ parentMessage: lastMessage
15452
+ }))) === false) {
15453
+ return true;
15454
+ }
15455
+ if (lastPart.state === 'input-streaming') {
15456
+ return !(tool === null || tool === void 0 ? void 0 : tool.streamInput);
15457
+ }
14874
15458
  }
14875
15459
  return true;
14876
15460
  };
@@ -15086,20 +15670,31 @@
15086
15670
  createElement: createElement
15087
15671
  });
15088
15672
  return function ChatPromptSuggestions(userProps) {
15089
- 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;
15090
- if (suggestions.length === 0) {
15673
+ 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;
15674
+ var visibleSuggestions = suggestions.filter(function(suggestion) {
15675
+ return suggestion.trim() !== '';
15676
+ });
15677
+ if (visibleSuggestions.length === 0 && !isLoading) {
15091
15678
  return null;
15092
15679
  }
15093
15680
  return /*#__PURE__*/ createElement("div", {
15094
15681
  className: cx('ais-ChatPromptSuggestions', classNames.root)
15095
- }, suggestions.map(function(suggestion, index) {
15682
+ }, isLoading && visibleSuggestions.length === 0 ? _to_consumable_array(new Array(skeletonCount)).map(function(_, index) {
15683
+ return /*#__PURE__*/ createElement("div", {
15684
+ key: index,
15685
+ className: cx('ais-ChatPromptSuggestions-skeletonItem', classNames.skeletonItem)
15686
+ });
15687
+ }) : visibleSuggestions.map(function(suggestion, index) {
15096
15688
  return /*#__PURE__*/ createElement(Button, {
15097
15689
  key: index,
15098
15690
  size: "sm",
15099
15691
  variant: "primary",
15100
15692
  className: cx('ais-ChatPromptSuggestions-suggestion', classNames.suggestion),
15693
+ // A half-written suggestion can't be sent. Not `disabled`,
15694
+ // which would restyle the pill mid-stream.
15101
15695
  onClick: function onClick() {
15102
- return onSuggestionClick(suggestion);
15696
+ if (isLoading) return;
15697
+ onSuggestionClick(suggestion);
15103
15698
  }
15104
15699
  }, suggestion);
15105
15700
  }));
@@ -15110,7 +15705,7 @@
15110
15705
  return typeof window !== 'undefined' && typeof window.matchMedia === 'function' && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
15111
15706
  }
15112
15707
  function createChatComponent(param) {
15113
- var createElement = param.createElement, Fragment = param.Fragment, useMemo = param.useMemo, useState = param.useState;
15708
+ var createElement = param.createElement, Fragment = param.Fragment, useMemo = param.useMemo, useState = param.useState, useEffect = param.useEffect;
15114
15709
  var ChatHeader = createChatHeaderComponent({
15115
15710
  createElement: createElement,
15116
15711
  Fragment: Fragment
@@ -15118,7 +15713,9 @@
15118
15713
  var ChatMessages = createChatMessagesComponent({
15119
15714
  createElement: createElement,
15120
15715
  Fragment: Fragment,
15121
- useMemo: useMemo
15716
+ useMemo: useMemo,
15717
+ useState: useState,
15718
+ useEffect: useEffect
15122
15719
  });
15123
15720
  var ChatPrompt = createChatPromptComponent({
15124
15721
  createElement: createElement,
@@ -15190,6 +15787,7 @@
15190
15787
  error: error,
15191
15788
  classNames: classNames.messages,
15192
15789
  messageClassNames: classNames.message,
15790
+ suggestionsLoading: suggestionsProps.isLoading,
15193
15791
  suggestionsElement: createElement(SuggestionsComponent || ChatPromptSuggestions, _object_spread_props(_object_spread({}, suggestionsProps), {
15194
15792
  classNames: classNames.suggestions
15195
15793
  }))
@@ -15495,7 +16093,7 @@
15495
16093
  createElement: createElement
15496
16094
  });
15497
16095
  return function HeaderComponent(param) {
15498
- var showViewAll = param.showViewAll, canScrollLeft = param.canScrollLeft, canScrollRight = param.canScrollRight, scrollLeft = param.scrollLeft, scrollRight = param.scrollRight, nbHits = param.nbHits, input = param.input, nbItems = param.nbItems, applyFilters = param.applyFilters, getSearchPageURL = param.getSearchPageURL, onClose = param.onClose;
16096
+ var showViewAll = param.showViewAll, canScrollLeft = param.canScrollLeft, canScrollRight = param.canScrollRight, scrollLeft = param.scrollLeft, scrollRight = param.scrollRight, nbHits = param.nbHits, input = param.input, resolvedSearchParams = param.resolvedSearchParams, nbItems = param.nbItems, applyFilters = param.applyFilters, getSearchPageURL = param.getSearchPageURL, onClose = param.onClose;
15499
16097
  if (nbItems < 1) {
15500
16098
  return null;
15501
16099
  }
@@ -15510,7 +16108,7 @@
15510
16108
  size: "sm",
15511
16109
  onClick: function onClick() {
15512
16110
  if (!input || !applyFilters) return;
15513
- var params = applyFilters(getApplyFiltersParamsFromToolInput(input));
16111
+ var params = applyFilters(getApplyFiltersParamsFromToolInput(input, resolvedSearchParams));
15514
16112
  if (getSearchPageURL) {
15515
16113
  var searchPageURL = getSearchPageURL(params);
15516
16114
  var resolvedURL = new URL(searchPageURL, window.location.href);
@@ -15564,6 +16162,14 @@
15564
16162
  var message = context.message, applyFilters = context.applyFilters, insightsEventContext = context.insightsEventContext, sendEvent = context.sendEvent, onClose = context.onClose;
15565
16163
  var instantSearchStatus = (_ref = insightsEventContext === null || insightsEventContext === void 0 ? void 0 : insightsEventContext.instantSearchStatus) !== null && _ref !== void 0 ? _ref : 'idle';
15566
16164
  var input = message === null || message === void 0 ? void 0 : message.input;
16165
+ // What the server actually searched with, when it sent it. Absent for the
16166
+ // default search tool and whenever the MCP server emits no `_meta`.
16167
+ var resolvedSearchParams = useMemo(function() {
16168
+ return getResolvedSearchParams(context.messages, message === null || message === void 0 ? void 0 : message.toolCallId);
16169
+ }, [
16170
+ context.messages,
16171
+ message === null || message === void 0 ? void 0 : message.toolCallId
16172
+ ]);
15567
16173
  var output = message === null || message === void 0 ? void 0 : message.output;
15568
16174
  var hits = (output === null || output === void 0 ? void 0 : output.hits) || [];
15569
16175
  var items = addQueryID(addAbsolutePosition(hits, 0, hits.length), output === null || output === void 0 ? void 0 : output.queryID);
@@ -15611,6 +16217,7 @@
15611
16217
  showViewAll: showViewAll,
15612
16218
  nbHits: output === null || output === void 0 ? void 0 : output.nbHits,
15613
16219
  input: input,
16220
+ resolvedSearchParams: resolvedSearchParams,
15614
16221
  applyFilters: applyFilters,
15615
16222
  getSearchPageURL: getSearchPageURL,
15616
16223
  onClose: onClose
@@ -15622,6 +16229,7 @@
15622
16229
  showViewAll: showViewAll,
15623
16230
  nbHits: output === null || output === void 0 ? void 0 : output.nbHits,
15624
16231
  input: input,
16232
+ resolvedSearchParams: resolvedSearchParams,
15625
16233
  applyFilters: applyFilters,
15626
16234
  getSearchPageURL: getSearchPageURL,
15627
16235
  onClose: onClose
@@ -15632,6 +16240,7 @@
15632
16240
  HeaderComponent,
15633
16241
  output === null || output === void 0 ? void 0 : output.nbHits,
15634
16242
  input,
16243
+ resolvedSearchParams,
15635
16244
  applyFilters,
15636
16245
  getSearchPageURL,
15637
16246
  onClose
@@ -18760,6 +19369,13 @@
18760
19369
  var MemorySearchToolType = 'algolia_memory_search';
18761
19370
  var PonderToolType = 'algolia_ponder';
18762
19371
  var DisplayResultsToolType = 'algolia_display_results';
19372
+ /**
19373
+ * Whether `toolName` is the search tool as the Algolia MCP Server exposes it:
19374
+ * one tool per index, named after the index it searches
19375
+ * (`algolia_search_index_products`).
19376
+ */ var matchesSearchIndexToolName = function matchesSearchIndexToolName(toolName) {
19377
+ return toolName.startsWith("".concat(SearchIndexToolType, "_"));
19378
+ };
18763
19379
 
18764
19380
  function flat(arr) {
18765
19381
  return arr.reduce(function(acc, array) {
@@ -19019,6 +19635,11 @@
19019
19635
  return refinement.attribute;
19020
19636
  }));
19021
19637
  }
19638
+ /**
19639
+ * One Algolia `numericFilters` entry: `'price <= 1500'`. The operators are
19640
+ * exactly the set `helper.addNumericRefinement` accepts, and exactly the set
19641
+ * the Algolia MCP Server emits.
19642
+ */ var NUMERIC_FILTER = /^(.+?)\s*(<=|>=|!=|=|<|>)\s*(-?\d+(?:\.\d+)?)$/;
19022
19643
  function updateStateFromSearchToolInput(params, helper) {
19023
19644
  // clear all filters first
19024
19645
  var attributesToClear = getAttributesToClear$1({
@@ -19062,6 +19683,16 @@
19062
19683
  helper.toggleFacetRefinement(name, value);
19063
19684
  });
19064
19685
  }
19686
+ if (params.numericFilters) {
19687
+ params.numericFilters.forEach(function(filter) {
19688
+ var match = filter.match(NUMERIC_FILTER);
19689
+ if (!match) {
19690
+ return;
19691
+ }
19692
+ var _match = _sliced_to_array(match, 4), attribute = _match[1], operator = _match[2], value = _match[3];
19693
+ helper.addNumericRefinement(attribute, operator, Number(value));
19694
+ });
19695
+ }
19065
19696
  if (params.query) {
19066
19697
  helper.setQuery(params.query);
19067
19698
  }
@@ -19072,7 +19703,7 @@
19072
19703
  var unmountFn = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : noop;
19073
19704
  checkRendering(renderFn, withUsage$q());
19074
19705
  return function(widgetParams) {
19075
- var _ref = widgetParams || {}, _ref_resume = _ref.resume, resume = _ref_resume === void 0 ? false : _ref_resume, _ref_tools = _ref.tools, tools = _ref_tools === void 0 ? {} : _ref_tools, _ref_type = _ref.type, type = _ref_type === void 0 ? 'chat' : _ref_type, persistence = _ref.persistence, context = _ref.context, initialUserMessage = _ref.initialUserMessage, initialMessages = _ref.initialMessages, _ref_disableTriggerValidation = _ref.disableTriggerValidation, disableTriggerValidation = _ref_disableTriggerValidation === void 0 ? false : _ref_disableTriggerValidation, _ref_sendAutomaticallyWhen = _ref.sendAutomaticallyWhen, sendAutomaticallyWhen = _ref_sendAutomaticallyWhen === void 0 ? lastAssistantMessageIsCompleteWithToolCalls : _ref_sendAutomaticallyWhen, _ref_requiresSearch = _ref.requiresSearch, requiresSearch = _ref_requiresSearch === void 0 ? true : _ref_requiresSearch, options = _object_without_properties(_ref, [
19706
+ var _ref = widgetParams || {}, _ref_resume = _ref.resume, resume = _ref_resume === void 0 ? false : _ref_resume, tmp = _ref.tools, tools_ = tmp === void 0 ? {} : tmp, _ref_type = _ref.type, type = _ref_type === void 0 ? 'chat' : _ref_type, persistence = _ref.persistence, context = _ref.context, initialUserMessage = _ref.initialUserMessage, initialMessages = _ref.initialMessages, _ref_disableTriggerValidation = _ref.disableTriggerValidation, disableTriggerValidation = _ref_disableTriggerValidation === void 0 ? false : _ref_disableTriggerValidation, _ref_sendAutomaticallyWhen = _ref.sendAutomaticallyWhen, sendAutomaticallyWhen = _ref_sendAutomaticallyWhen === void 0 ? lastAssistantMessageIsCompleteWithToolCalls : _ref_sendAutomaticallyWhen, _ref_requiresSearch = _ref.requiresSearch, requiresSearch = _ref_requiresSearch === void 0 ? true : _ref_requiresSearch, options = _object_without_properties(_ref, [
19076
19707
  "resume",
19077
19708
  "tools",
19078
19709
  "type",
@@ -19085,11 +19716,12 @@
19085
19716
  "requiresSearch"
19086
19717
  ]);
19087
19718
  var normalizedPersistence = normalizePersistence(persistence, 'chat' in options);
19088
- // Compatibility shim with Algolia MCP Server search tool, which suffixes
19089
- // the tool name with the index name (`searchIndex_products`).
19090
- var resolveTool = function resolveTool(toolName) {
19091
- return tools[toolName] || (toolName.startsWith("".concat(SearchIndexToolType, "_")) ? tools[SearchIndexToolType] : undefined);
19092
- };
19719
+ // The Algolia MCP Server exposes the search tool once per index and names
19720
+ // it after the index (`algolia_search_index_products`). A `matchesToolName`
19721
+ // set by the user wins, as does a tool registered under the derived name.
19722
+ var tools = tools_[SearchIndexToolType] && tools_[SearchIndexToolType].matchesToolName === undefined ? _object_spread_props(_object_spread({}, tools_), _define_property({}, SearchIndexToolType, _object_spread_props(_object_spread({}, tools_[SearchIndexToolType]), {
19723
+ matchesToolName: matchesSearchIndexToolName
19724
+ }))) : tools_;
19093
19725
  var _chatInstance;
19094
19726
  var input = '';
19095
19727
  var open = false;
@@ -19117,21 +19749,44 @@
19117
19749
  return unsubscribe();
19118
19750
  });
19119
19751
  };
19120
- // Extract suggestions from the last assistant message's data-suggestions part
19121
- var getSuggestionsFromMessages = function getSuggestionsFromMessages(messages) {
19122
- // Find the last assistant message (iterate from end)
19123
- var lastAssistantMessage = _to_consumable_array(messages).reverse().find(function(message) {
19752
+ var findSuggestionsPart = function findSuggestionsPart(message) {
19753
+ var _message_parts;
19754
+ return message === null || message === void 0 ? void 0 : (_message_parts = message.parts) === null || _message_parts === void 0 ? void 0 : _message_parts.find(function(part) {
19755
+ var _part_data;
19756
+ return 'type' in part && part.type === 'data-suggestions' && 'data' in part && Array.isArray((_part_data = part.data) === null || _part_data === void 0 ? void 0 : _part_data.suggestions);
19757
+ });
19758
+ };
19759
+ var findLastAssistantMessage = function findLastAssistantMessage(messages) {
19760
+ return _to_consumable_array(messages).reverse().find(function(message) {
19124
19761
  return message.role === 'assistant' && message.parts;
19125
19762
  });
19126
- if (!(lastAssistantMessage === null || lastAssistantMessage === void 0 ? void 0 : lastAssistantMessage.parts)) {
19127
- return undefined;
19763
+ };
19764
+ // Extract suggestions from the last assistant message's data-suggestions part
19765
+ var getSuggestionsFromMessages = function getSuggestionsFromMessages(messages) {
19766
+ var _findSuggestionsPart;
19767
+ return (_findSuggestionsPart = findSuggestionsPart(findLastAssistantMessage(messages))) === null || _findSuggestionsPart === void 0 ? void 0 : _findSuggestionsPart.data.suggestions;
19768
+ };
19769
+ // "Still coming" has to be inferred: the turn is running and has no
19770
+ // `data-suggestions` part yet. Expecting any at all needs evidence, or an
19771
+ // agent that never sends them would sit under a placeholder forever.
19772
+ var getSuggestionsStatus = function getSuggestionsStatus(messages) {
19773
+ var _lastAssistantMessage_metadata;
19774
+ var status = _chatInstance.status;
19775
+ if (status !== 'submitted' && status !== 'streaming') {
19776
+ return 'idle';
19128
19777
  }
19129
- // Find the data-suggestions part
19130
- var suggestionsPart = lastAssistantMessage.parts.find(function(part) {
19131
- var _part_data;
19132
- return 'type' in part && part.type === 'data-suggestions' && 'data' in part && Array.isArray((_part_data = part.data) === null || _part_data === void 0 ? void 0 : _part_data.suggestions);
19778
+ var lastAssistantMessage = findLastAssistantMessage(messages);
19779
+ if (findSuggestionsPart(lastAssistantMessage)) {
19780
+ return 'idle';
19781
+ }
19782
+ var declaresSuggestions = (lastAssistantMessage === null || lastAssistantMessage === void 0 ? void 0 : (_lastAssistantMessage_metadata = lastAssistantMessage.metadata) === null || _lastAssistantMessage_metadata === void 0 ? void 0 : _lastAssistantMessage_metadata.suggestionsEnabled) === true;
19783
+ if (declaresSuggestions) {
19784
+ return 'loading';
19785
+ }
19786
+ var hasSuggestionsHistory = messages.some(function(message) {
19787
+ return message !== lastAssistantMessage && message.role === 'assistant' && Boolean(findSuggestionsPart(message));
19133
19788
  });
19134
- return suggestionsPart === null || suggestionsPart === void 0 ? void 0 : suggestionsPart.data.suggestions;
19789
+ return hasSuggestionsHistory ? 'loading' : 'idle';
19135
19790
  };
19136
19791
  var setMessages = function setMessages(messagesParam) {
19137
19792
  if (typeof messagesParam === 'function') {
@@ -19274,14 +19929,14 @@
19274
19929
  sendAutomaticallyWhen: sendAutomaticallyWhen,
19275
19930
  transport: transport,
19276
19931
  shouldRepairToolInput: function shouldRepairToolInput(toolName) {
19277
- var tool = resolveTool(toolName);
19932
+ var tool = findTool(toolName, tools);
19278
19933
  if (!tool) return true;
19279
19934
  return Boolean(tool.streamInput);
19280
19935
  },
19281
19936
  resolveCancelledToolOutput: function resolveCancelledToolOutput(param) {
19282
19937
  var toolName = param.toolName, toolCallId = param.toolCallId, input = param.input;
19283
- var _resolveTool;
19284
- var cancelOutput = (_resolveTool = resolveTool(toolName)) === null || _resolveTool === void 0 ? void 0 : _resolveTool.cancelOutput;
19938
+ var _findTool;
19939
+ var cancelOutput = (_findTool = findTool(toolName, tools)) === null || _findTool === void 0 ? void 0 : _findTool.cancelOutput;
19285
19940
  if (!cancelOutput) return undefined;
19286
19941
  try {
19287
19942
  var output = cancelOutput({
@@ -19298,7 +19953,7 @@
19298
19953
  },
19299
19954
  onToolCall: function onToolCall(param, submitToolResult) {
19300
19955
  var toolCall = param.toolCall;
19301
- var tool = resolveTool(toolCall.toolName);
19956
+ var tool = findTool(toolCall.toolName, tools);
19302
19957
  if (!tool) {
19303
19958
  return submitToolResult({
19304
19959
  output: 'No tool implemented for "'.concat(toolCall.toolName, '".'),
@@ -19348,7 +20003,8 @@
19348
20003
  // `open` is read by sibling widgets (e.g. `chatTrigger`) via the
19349
20004
  // shared `renderState`. Schedule a full re-render so they pick up
19350
20005
  // the new value instead of staying frozen on their initial state.
19351
- initOptions.instantSearchInstance.scheduleRender();
20006
+ // No search runs here, so it must not settle the main search.
20007
+ initOptions.instantSearchInstance.scheduleRender(false);
19352
20008
  };
19353
20009
  setOpen = function setOpen(nextOpen) {
19354
20010
  updateOpen(nextOpen, nextOpen && !open);
@@ -19401,14 +20057,15 @@
19401
20057
  // disable themselves, so a transition has to escape this widget's own
19402
20058
  // render. Message deltas deliberately don't: they stay local to keep
19403
20059
  // streaming cheap. The `status` setter notifies on every write, hence
19404
- // the comparison.
20060
+ // the comparison. A chat turn is not a search, so the render it
20061
+ // schedules must not settle the main search.
19405
20062
  var lastStatus = _chatInstance.status;
19406
20063
  var renderOnStatusChange = function renderOnStatusChange() {
19407
20064
  var statusChanged = _chatInstance.status !== lastStatus;
19408
20065
  lastStatus = _chatInstance.status;
19409
20066
  render();
19410
20067
  if (statusChanged) {
19411
- initOptions.instantSearchInstance.scheduleRender();
20068
+ initOptions.instantSearchInstance.scheduleRender(false);
19412
20069
  }
19413
20070
  };
19414
20071
  safelyRunOnBrowser(function() {
@@ -19438,8 +20095,10 @@
19438
20095
  renderFn(_object_spread_props(_object_spread({}, this.getWidgetRenderState(initOptions)), {
19439
20096
  instantSearchInstance: instantSearchInstance
19440
20097
  }), true);
20098
+ // A restored open panel is new to the sibling entry points, but it is
20099
+ // not a search result.
19441
20100
  if (open) {
19442
- instantSearchInstance.scheduleRender();
20101
+ instantSearchInstance.scheduleRender(false);
19443
20102
  }
19444
20103
  },
19445
20104
  render: function render(renderOptions) {
@@ -19528,6 +20187,7 @@
19528
20187
  '~isOpenStatePersistenceEnabled': normalizedPersistence.open,
19529
20188
  setMessages: setMessages,
19530
20189
  suggestions: getSuggestionsFromMessages(_chatInstance.messages),
20190
+ suggestionsStatus: getSuggestionsStatus(_chatInstance.messages),
19531
20191
  clearMessages: clearMessages,
19532
20192
  tools: toolsWithAddToolResult,
19533
20193
  records: records,
@@ -19605,7 +20265,11 @@
19605
20265
 
19606
20266
  function useChat(props, additionalWidgetProperties) {
19607
20267
  var isHydrated = useIsHydrated();
20268
+ React.useRef(props);
20269
+ React.useRef(null);
20270
+ useIsomorphicLayoutEffect(function() {});
19608
20271
  var chatState = useConnector(connectChat, props, additionalWidgetProperties);
20272
+ useIsomorphicLayoutEffect(function() {});
19609
20273
  if (isHydrated) {
19610
20274
  return chatState;
19611
20275
  }
@@ -19631,120 +20295,333 @@
19631
20295
  });
19632
20296
  }
19633
20297
 
19634
- function buildEndpoint(param) {
19635
- var appId = param.appId, agentId = param.agentId;
19636
- return "https://".concat(appId, ".algolia.net/agent-studio/1/agents/").concat(agentId, "/tasks");
20298
+ function isHeaders$1(headers) {
20299
+ return !Array.isArray(headers) && 'entries' in headers && typeof headers.entries === 'function';
19637
20300
  }
19638
- function resolveEndpoint(params) {
19639
- if (params.transport) {
19640
- return {
19641
- endpoint: params.transport.api,
19642
- headers: params.transport.headers || {},
19643
- prepareSendMessagesRequest: params.transport.prepareSendMessagesRequest
19644
- };
20301
+ function headersToRecord$1(headers) {
20302
+ if (!headers) {
20303
+ return {};
19645
20304
  }
19646
- if (!params.appId || !params.apiKey || !params.agentId) {
19647
- throw new Error('[tasks] Either `transport` or `{ appId, apiKey, agentId }` is required.');
20305
+ if (isHeaders$1(headers)) {
20306
+ return Object.fromEntries(headers.entries());
19648
20307
  }
19649
- var headers = {
19650
- 'x-algolia-application-id': params.appId,
19651
- 'x-algolia-api-key': params.apiKey
19652
- };
19653
- if (params.algoliaAgent) {
19654
- headers['x-algolia-agent'] = "".concat(params.algoliaAgent, "; tasks");
20308
+ if (Array.isArray(headers)) {
20309
+ return Object.fromEntries(headers);
19655
20310
  }
19656
- return {
19657
- endpoint: buildEndpoint({
19658
- appId: params.appId,
19659
- agentId: params.agentId
19660
- }),
19661
- headers: headers
19662
- };
20311
+ return headers;
19663
20312
  }
19664
-
19665
- function buildTaskPayload(param) {
19666
- var task = param.task, input = param.input, prepareRequest = param.prepareRequest;
19667
- var payload = {
19668
- task: task,
19669
- input: input
19670
- };
19671
- return prepareRequest ? prepareRequest(payload).body : payload;
20313
+ function withJsonContentType(headers) {
20314
+ var merged = _object_spread({}, headersToRecord$1(headers));
20315
+ Object.keys(merged).forEach(function(name) {
20316
+ if (name.toLowerCase() === 'content-type') {
20317
+ delete merged[name];
20318
+ }
20319
+ });
20320
+ merged['Content-Type'] = 'application/json';
20321
+ return merged;
19672
20322
  }
19673
20323
  function withStreamParam(url) {
19674
20324
  return url.includes('?') ? "".concat(url, "&stream=true") : "".concat(url, "?stream=true");
19675
20325
  }
19676
- function resolveStreamedOutput(data, previous) {
19677
- return typeof data === 'string' ? parsePartialJson(data, previous) : data;
20326
+ function createTaskPreparationContext(context) {
20327
+ function hideProperty(key) {
20328
+ var value = context[key];
20329
+ Object.defineProperty(context, key, {
20330
+ configurable: true,
20331
+ enumerable: false,
20332
+ get: function get() {
20333
+ return value;
20334
+ },
20335
+ set: function set(nextValue) {
20336
+ Reflect.deleteProperty(context, key);
20337
+ Object.defineProperty(context, key, {
20338
+ configurable: true,
20339
+ enumerable: true,
20340
+ value: nextValue,
20341
+ writable: true
20342
+ });
20343
+ }
20344
+ });
20345
+ }
20346
+ // Rich metadata stays out of legacy body spreads until assigned as payload.
20347
+ hideProperty('stream');
20348
+ hideProperty('body');
20349
+ hideProperty('credentials');
20350
+ hideProperty('headers');
20351
+ hideProperty('api');
20352
+ return context;
19678
20353
  }
19679
- function consumeTaskStream(body, onData) {
20354
+ function unwrap(envelope) {
20355
+ if ((typeof envelope === "undefined" ? "undefined" : _type_of(envelope)) === 'object' && envelope !== null && 'output' in envelope) {
20356
+ return envelope.output;
20357
+ }
20358
+ return undefined;
20359
+ }
20360
+ function consumeTaskTextStream(body, onData) {
19680
20361
  return new Promise(function(resolve, reject) {
19681
- var chunkStream = parseJsonEventStream(body);
20362
+ var decoder = new TextDecoder();
20363
+ var reader = body.getReader();
20364
+ var accumulatedText = '';
19682
20365
  var latest;
19683
- processStream(chunkStream, function(chunk) {
19684
- if (!chunk) {
19685
- return;
20366
+ var publish = function publish(output) {
20367
+ if (!isEqual(output, latest)) {
20368
+ latest = output;
20369
+ onData === null || onData === void 0 ? void 0 : onData({
20370
+ output: output
20371
+ });
19686
20372
  }
19687
- // A terminal `error` event aborts the task: reject rather than let the
19688
- // stream close and resolve the last partial snapshot as a success.
19689
- // Throwing here lets `processStream` release the reader and stop
19690
- // consuming; the rejection propagates to the caller's `.catch`.
19691
- if (chunk.type === 'error') {
19692
- throw new Error(chunk.errorText || 'Task stream error');
20373
+ };
20374
+ var read = function read1() {
20375
+ reader.read().then(function(param) {
20376
+ var done = param.done, value = param.value;
20377
+ if (done) {
20378
+ accumulatedText += decoder.decode();
20379
+ reader.releaseLock();
20380
+ try {
20381
+ var output = JSON.parse(accumulatedText);
20382
+ publish(output);
20383
+ resolve({
20384
+ output: output
20385
+ });
20386
+ } catch (error) {
20387
+ reject(error);
20388
+ }
20389
+ return;
20390
+ }
20391
+ try {
20392
+ accumulatedText += decoder.decode(value, {
20393
+ stream: true
20394
+ });
20395
+ var partial = parsePartialJson(accumulatedText, latest);
20396
+ if (partial !== undefined) {
20397
+ publish(partial);
20398
+ }
20399
+ read();
20400
+ } catch (error) {
20401
+ reader.releaseLock();
20402
+ reject(error);
20403
+ }
20404
+ }, function(error) {
20405
+ reader.releaseLock();
20406
+ reject(error);
20407
+ });
20408
+ };
20409
+ read();
20410
+ });
20411
+ }
20412
+ /** Default HTTP transport for named Tasks requests and task-output streams. */ var DefaultTaskTransport = /*#__PURE__*/ function() {
20413
+ function DefaultTaskTransport() {
20414
+ var _ref = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {}, _ref_api = _ref.api, api = _ref_api === void 0 ? '/api/tasks' : _ref_api, credentials = _ref.credentials, headers = _ref.headers, body = _ref.body, customFetch = _ref.fetch, prepareSendMessagesRequest = _ref.prepareSendMessagesRequest;
20415
+ _class_call_check(this, DefaultTaskTransport);
20416
+ _define_property(this, "api", void 0);
20417
+ _define_property(this, "credentials", void 0);
20418
+ _define_property(this, "headers", void 0);
20419
+ _define_property(this, "body", void 0);
20420
+ _define_property(this, "fetch", void 0);
20421
+ _define_property(this, "prepareSendMessagesRequest", void 0);
20422
+ this.api = api;
20423
+ this.credentials = credentials;
20424
+ this.headers = headers;
20425
+ this.body = body;
20426
+ this.fetch = customFetch;
20427
+ this.prepareSendMessagesRequest = prepareSendMessagesRequest;
20428
+ }
20429
+ _create_class(DefaultTaskTransport, [
20430
+ {
20431
+ key: "sendTask",
20432
+ value: function sendTask(param) {
20433
+ var task = param.task, kind = param.kind, input = param.input, stream = param.stream, onData = param.onData;
20434
+ return this.sendTaskRequest({
20435
+ task: task,
20436
+ kind: kind,
20437
+ input: input,
20438
+ stream: stream,
20439
+ onData: onData ? function(data) {
20440
+ return onData(unwrap(data));
20441
+ } : undefined
20442
+ }).then(unwrap);
19693
20443
  }
19694
- if (chunk.type !== 'data-task-output') {
19695
- return;
20444
+ },
20445
+ {
20446
+ /** @internal */ key: "sendTaskRequest",
20447
+ value: function sendTaskRequest(param) {
20448
+ var _this = this;
20449
+ var task = param.task, kind = param.kind, input = param.input, stream = param.stream, onData = param.onData;
20450
+ var _this_fetch;
20451
+ var fetchFn = (_this_fetch = this.fetch) !== null && _this_fetch !== void 0 ? _this_fetch : fetch;
20452
+ return Promise.all([
20453
+ resolveValue(this.credentials),
20454
+ resolveValue(this.headers),
20455
+ resolveValue(this.body)
20456
+ ]).then(function(param) {
20457
+ var _param = _sliced_to_array(param, 3), resolvedCredentials = _param[0], resolvedHeaders = _param[1], resolvedBody = _param[2];
20458
+ var api = _this.api;
20459
+ var credentials = resolvedCredentials;
20460
+ var headers = withJsonContentType(resolvedHeaders);
20461
+ var body = _object_spread(_object_spread_props(_object_spread({}, task === undefined ? {} : {
20462
+ task: task
20463
+ }, kind === undefined ? {} : {
20464
+ kind: kind
20465
+ }), {
20466
+ input: input
20467
+ }), resolvedBody);
20468
+ var preparedBody = resolvedBody ? _object_spread({}, resolvedBody) : undefined;
20469
+ var preparePromise = _this.prepareSendMessagesRequest ? Promise.resolve(_this.prepareSendMessagesRequest(createTaskPreparationContext({
20470
+ task: task,
20471
+ kind: kind,
20472
+ input: input,
20473
+ stream: stream,
20474
+ body: preparedBody,
20475
+ credentials: resolvedCredentials,
20476
+ headers: resolvedHeaders,
20477
+ api: _this.api
20478
+ }))) : Promise.resolve(null);
20479
+ return preparePromise.then(function(prepared) {
20480
+ if (prepared) {
20481
+ body = prepared.body;
20482
+ if (prepared.api) {
20483
+ api = prepared.api;
20484
+ }
20485
+ if (prepared.credentials) {
20486
+ credentials = prepared.credentials;
20487
+ }
20488
+ if (prepared.headers) {
20489
+ headers = withJsonContentType(prepared.headers);
20490
+ }
20491
+ }
20492
+ var request = {
20493
+ method: 'POST',
20494
+ headers: headers,
20495
+ body: JSON.stringify(body)
20496
+ };
20497
+ if (credentials !== undefined) {
20498
+ request.credentials = credentials;
20499
+ }
20500
+ return fetchFn(stream ? withStreamParam(api) : api, request).then(function(response) {
20501
+ var _response_headers_get, _response_headers;
20502
+ if (!response.ok) {
20503
+ throw new Error("HTTP error ".concat(response.status));
20504
+ }
20505
+ var contentType = ((_response_headers = response.headers) === null || _response_headers === void 0 ? void 0 : (_response_headers_get = _response_headers.get) === null || _response_headers_get === void 0 ? void 0 : _response_headers_get.call(_response_headers, 'content-type')) || '';
20506
+ if (stream && contentType.includes('text/plain')) {
20507
+ if (!response.body) {
20508
+ throw new Error('Response body is empty');
20509
+ }
20510
+ return consumeTaskTextStream(response.body, onData);
20511
+ }
20512
+ return response.json();
20513
+ });
20514
+ });
20515
+ });
19696
20516
  }
19697
- latest = resolveStreamedOutput(chunk.data, latest);
19698
- if (onData) {
19699
- onData(latest);
20517
+ }
20518
+ ]);
20519
+ return DefaultTaskTransport;
20520
+ }();
20521
+
20522
+ function buildEndpoint(param) {
20523
+ var appId = param.appId, agentId = param.agentId;
20524
+ return "https://".concat(appId, ".algolia.net/agent-studio/1/agents/").concat(agentId, "/tasks");
20525
+ }
20526
+ function isHeaders(headers) {
20527
+ return !Array.isArray(headers) && 'entries' in headers && typeof headers.entries === 'function';
20528
+ }
20529
+ function headersToRecord(headers) {
20530
+ if (!headers) {
20531
+ return {};
20532
+ }
20533
+ if (isHeaders(headers)) {
20534
+ return Object.fromEntries(headers.entries());
20535
+ }
20536
+ if (Array.isArray(headers)) {
20537
+ return Object.fromEntries(headers);
20538
+ }
20539
+ return _object_spread({}, headers);
20540
+ }
20541
+ function mergeProtectedHeaders(headers, protectedHeaders) {
20542
+ var merged = headersToRecord(headers);
20543
+ Object.entries(protectedHeaders).forEach(function(param) {
20544
+ var _param = _sliced_to_array(param, 2), protectedName = _param[0], value = _param[1];
20545
+ Object.keys(merged).forEach(function(name) {
20546
+ if (name.toLowerCase() === protectedName.toLowerCase()) {
20547
+ delete merged[name];
19700
20548
  }
19701
- }, function() {
19702
- return resolve(latest);
19703
- }, reject);
20549
+ });
20550
+ merged[protectedName] = value;
19704
20551
  });
20552
+ return merged;
19705
20553
  }
19706
- function fetchTask(param) {
19707
- var endpoint = param.endpoint, headers = param.headers, payload = param.payload, onData = param.onData, _param_stream = param.stream, stream = _param_stream === void 0 ? true : _param_stream;
19708
- return fetch(stream ? withStreamParam(endpoint) : endpoint, {
19709
- method: 'POST',
19710
- headers: _object_spread_props(_object_spread({}, headers), {
19711
- 'Content-Type': 'application/json'
20554
+ /** @internal */ function createTaskTransport(param) {
20555
+ var _param_transport = param.transport, transport = _param_transport === void 0 ? {} : _param_transport, appId = param.appId, apiKey = param.apiKey, agentId = param.agentId, algoliaAgent = param.algoliaAgent;
20556
+ var _transport_api;
20557
+ if (!agentId) {
20558
+ return new DefaultTaskTransport(transport);
20559
+ }
20560
+ if (!appId || !apiKey) {
20561
+ throw new Error('[tasks] `appId` and `apiKey` are required when `agentId` is provided.');
20562
+ }
20563
+ var protectedHeaders = {
20564
+ 'x-algolia-application-id': appId,
20565
+ 'x-algolia-api-key': apiKey
20566
+ };
20567
+ if (algoliaAgent) {
20568
+ protectedHeaders['x-algolia-agent'] = "".concat(algoliaAgent, "; tasks");
20569
+ }
20570
+ var originalPrepare = transport.prepareSendMessagesRequest;
20571
+ var prepareSendMessagesRequest = originalPrepare ? function(request) {
20572
+ return Promise.resolve(originalPrepare(request)).then(function(prepared) {
20573
+ return _object_spread_props(_object_spread({}, prepared), {
20574
+ headers: prepared.headers ? mergeProtectedHeaders(prepared.headers, protectedHeaders) : undefined
20575
+ });
20576
+ });
20577
+ } : undefined;
20578
+ return new DefaultTaskTransport(_object_spread_props(_object_spread({}, transport), {
20579
+ api: (_transport_api = transport.api) !== null && _transport_api !== void 0 ? _transport_api : buildEndpoint({
20580
+ appId: appId,
20581
+ agentId: agentId
19712
20582
  }),
19713
- body: JSON.stringify(payload)
19714
- }).then(function(response) {
19715
- var _response_headers_get, _response_headers;
19716
- if (!response.ok) {
19717
- throw new Error("HTTP error ".concat(response.status));
19718
- }
19719
- var contentType = ((_response_headers = response.headers) === null || _response_headers === void 0 ? void 0 : (_response_headers_get = _response_headers.get) === null || _response_headers_get === void 0 ? void 0 : _response_headers_get.call(_response_headers, 'content-type')) || '';
19720
- if (stream && response.body && contentType.includes('text/event-stream')) {
19721
- return consumeTaskStream(response.body, onData);
19722
- }
19723
- return response.json();
19724
- });
19725
- }
19726
- function unwrap(envelope) {
19727
- return envelope === null || envelope === void 0 ? void 0 : envelope.output;
20583
+ headers: function headers() {
20584
+ return Promise.resolve(resolveValue(transport.headers)).then(function(headers) {
20585
+ return mergeProtectedHeaders(headers, protectedHeaders);
20586
+ });
20587
+ },
20588
+ prepareSendMessagesRequest: prepareSendMessagesRequest
20589
+ }));
19728
20590
  }
19729
- function createTaskRunner(param) {
19730
- var endpoint = param.endpoint, headers = param.headers, task = param.task, _param_stream = param.stream, stream = _param_stream === void 0 ? true : _param_stream, prepareRequest = param.prepareRequest;
20591
+
20592
+ function createTaskRunner(options) {
20593
+ var task = options.task, kind = options.kind, _options_stream = options.stream, stream = _options_stream === void 0 ? true : _options_stream;
20594
+ var transport;
20595
+ if (options.transport !== undefined) {
20596
+ transport = options.transport;
20597
+ } else {
20598
+ var prepareRequest = options.prepareRequest;
20599
+ transport = new DefaultTaskTransport({
20600
+ api: options.endpoint,
20601
+ headers: options.headers,
20602
+ fetch: options.fetch,
20603
+ prepareSendMessagesRequest: prepareRequest ? function(param) {
20604
+ var requestTask = param.task, requestKind = param.kind, input = param.input;
20605
+ return prepareRequest(_object_spread_props(_object_spread({}, requestTask === undefined ? {} : {
20606
+ task: requestTask
20607
+ }, requestKind === undefined ? {} : {
20608
+ kind: requestKind
20609
+ }), {
20610
+ input: input
20611
+ }));
20612
+ } : undefined
20613
+ });
20614
+ }
19731
20615
  return {
19732
- submit: function submit(variables) {
20616
+ submit: function submit(input) {
19733
20617
  var onData = (arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {}).onData;
19734
- var payload = buildTaskPayload({
20618
+ return transport.sendTask({
19735
20619
  task: task,
19736
- input: variables,
19737
- prepareRequest: prepareRequest
19738
- });
19739
- return fetchTask({
19740
- endpoint: endpoint,
19741
- headers: headers,
19742
- payload: payload,
20620
+ kind: kind,
20621
+ input: input,
19743
20622
  stream: stream,
19744
- onData: onData ? function(partial) {
19745
- return onData(unwrap(partial));
19746
- } : undefined
19747
- }).then(unwrap);
20623
+ onData: onData
20624
+ });
19748
20625
  }
19749
20626
  };
19750
20627
  }
@@ -19757,12 +20634,12 @@
19757
20634
  var unmountFn = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : noop;
19758
20635
  checkRendering(renderFn, withUsage$p());
19759
20636
  return function(widgetParams) {
19760
- var agentId = widgetParams.agentId, transport = widgetParams.transport, task = widgetParams.task, _widgetParams_stream = widgetParams.stream, stream = _widgetParams_stream === void 0 ? true : _widgetParams_stream;
20637
+ var agentId = widgetParams.agentId, transport = widgetParams.transport, task = widgetParams.task, kind = widgetParams.kind, _widgetParams_stream = widgetParams.stream, stream = _widgetParams_stream === void 0 ? true : _widgetParams_stream;
19761
20638
  if (!agentId && !transport) {
19762
20639
  throw new Error(withUsage$p('The `agentId` option is required unless a custom `transport` is provided.'));
19763
20640
  }
19764
- if (!task) {
19765
- throw new Error(withUsage$p('The `task` option is required.'));
20641
+ if (!task && !kind) {
20642
+ throw new Error(withUsage$p('Either the `task` or `kind` option is required.'));
19766
20643
  }
19767
20644
  var runner;
19768
20645
  var output;
@@ -19814,6 +20691,8 @@
19814
20691
  // Bump the request id so any in-flight request's callbacks see
19815
20692
  // `isStale()` and are ignored. The fetch itself is left to complete.
19816
20693
  requestId += 1;
20694
+ output = undefined;
20695
+ error = undefined;
19817
20696
  isLoading = false;
19818
20697
  triggerRender();
19819
20698
  };
@@ -19831,32 +20710,31 @@
19831
20710
  $$type: 'ais.tasks',
19832
20711
  init: function init(initOptions) {
19833
20712
  var instantSearchInstance = initOptions.instantSearchInstance;
19834
- if (transport) {
19835
- var resolved = resolveEndpoint({
19836
- transport: transport
19837
- });
19838
- runner = createTaskRunner({
19839
- endpoint: resolved.endpoint,
19840
- headers: resolved.headers,
19841
- task: task,
19842
- stream: stream,
19843
- prepareRequest: resolved.prepareSendMessagesRequest
19844
- });
19845
- } else {
20713
+ if (agentId) {
19846
20714
  var _getAppIdAndApiKey = _sliced_to_array(getAppIdAndApiKey(instantSearchInstance.client), 2), appId = _getAppIdAndApiKey[0], apiKey = _getAppIdAndApiKey[1];
19847
20715
  if (!appId || !apiKey) {
19848
20716
  throw new Error(withUsage$p('Could not extract Algolia credentials from the search client.'));
19849
20717
  }
19850
- var resolved1 = resolveEndpoint({
20718
+ var taskTransport = createTaskTransport({
20719
+ transport: transport,
19851
20720
  appId: appId,
19852
20721
  apiKey: apiKey,
19853
20722
  agentId: agentId,
19854
20723
  algoliaAgent: getAlgoliaAgent(instantSearchInstance.client)
19855
20724
  });
19856
20725
  runner = createTaskRunner({
19857
- endpoint: resolved1.endpoint,
19858
- headers: resolved1.headers,
20726
+ transport: taskTransport,
20727
+ task: task,
20728
+ kind: kind,
20729
+ stream: stream
20730
+ });
20731
+ } else {
20732
+ runner = createTaskRunner({
20733
+ transport: createTaskTransport({
20734
+ transport: transport
20735
+ }),
19859
20736
  task: task,
20737
+ kind: kind,
19860
20738
  stream: stream
19861
20739
  });
19862
20740
  }
@@ -19888,6 +20766,7 @@
19888
20766
  });
19889
20767
  var RENDER_STATE_KEY = 'promptSuggestions';
19890
20768
  var CHAT_RENDER_STATE_KEY = 'chat';
20769
+ var PROMPT_SUGGESTIONS_TASK_KIND = 'prompt_suggestions';
19891
20770
  var DEBOUNCE_MS = 300;
19892
20771
  function parseSuggestions(data) {
19893
20772
  var suggestions = data === null || data === void 0 ? void 0 : data.suggestions;
@@ -19959,12 +20838,10 @@
19959
20838
  if (!agentId && !transport) {
19960
20839
  throw new Error(withUsage$o('The `agentId` option is required unless a custom `transport` is provided.'));
19961
20840
  }
19962
- if (!configurationId) {
19963
- throw new Error(withUsage$o('The `configurationId` option is required.'));
19964
- }
19965
20841
  var tasksState;
19966
20842
  var suggestions = [];
19967
20843
  var isLoading = false;
20844
+ var error;
19968
20845
  var debounceTimer;
19969
20846
  var lastStateSignature = null;
19970
20847
  var latestRenderOptions = null;
@@ -20097,6 +20974,7 @@
20097
20974
  return {
20098
20975
  suggestions: transformed,
20099
20976
  isLoading: isLoading,
20977
+ error: error,
20100
20978
  onSuggestionClick: send,
20101
20979
  sendToChat: send,
20102
20980
  refresh: refresh,
@@ -20109,10 +20987,10 @@
20109
20987
  var handleInnerRender = function handleInnerRender(renderState) {
20110
20988
  tasksState = renderState;
20111
20989
  if (refetchPending) return;
20990
+ error = renderState.error;
20112
20991
  if (renderState.error) {
20113
20992
  // A failed task (including a mid-stream `error` event) must not leave
20114
- // any streamed partial visible. There's no error UI for now, so fall
20115
- // back to a blank suggestions state.
20993
+ // any streamed partial visible.
20116
20994
  suggestions = [];
20117
20995
  } else if (renderState.isLoading || renderState.output !== undefined) {
20118
20996
  // Only adopt the inner output once a request is loading or has
@@ -20123,14 +21001,26 @@
20123
21001
  if (!latestRenderOptions) return;
20124
21002
  renderOutward(latestRenderOptions);
20125
21003
  };
20126
- var tasksWidget = connectTasks(handleInnerRender, noop)(_object_spread_props(_object_spread({}, transport ? {
20127
- transport: transport
20128
- } : {
20129
- agentId: agentId
20130
- }), {
20131
- task: configurationId,
20132
- stream: true
20133
- }));
21004
+ var tasksParams;
21005
+ if (agentId) {
21006
+ tasksParams = {
21007
+ agentId: agentId,
21008
+ transport: transport,
21009
+ task: configurationId,
21010
+ kind: PROMPT_SUGGESTIONS_TASK_KIND,
21011
+ stream: true
21012
+ };
21013
+ } else if (transport) {
21014
+ tasksParams = {
21015
+ transport: transport,
21016
+ task: configurationId,
21017
+ kind: PROMPT_SUGGESTIONS_TASK_KIND,
21018
+ stream: true
21019
+ };
21020
+ } else {
21021
+ throw new Error(withUsage$o('The `agentId` option is required unless a custom `transport` is provided.'));
21022
+ }
21023
+ var tasksWidget = connectTasks(handleInnerRender, noop)(tasksParams);
20134
21024
  return {
20135
21025
  $$type: 'ais.promptSuggestions',
20136
21026
  init: function init(initOptions) {
@@ -20153,6 +21043,7 @@
20153
21043
  if (stateSignature !== lastStateSignature) {
20154
21044
  lastStateSignature = stateSignature;
20155
21045
  refetchPending = true;
21046
+ error = undefined;
20156
21047
  clearTimeout(debounceTimer);
20157
21048
  debounceTimer = setTimeout(function() {
20158
21049
  if (latestRenderOptions === null || latestRenderOptions === void 0 ? void 0 : latestRenderOptions.results) {
@@ -25431,6 +26322,202 @@
25431
26322
  return /*#__PURE__*/ React.createElement(Breadcrumb$1, _object_spread({}, props, uiProps));
25432
26323
  }
25433
26324
 
26325
+ var containersHeldInert = new WeakSet();
26326
+ var revealAnimationsHeldByContainer = new WeakMap();
26327
+ function getContainer(prompt) {
26328
+ var _ref;
26329
+ return (_ref = prompt === null || prompt === void 0 ? void 0 : prompt.closest('.ais-Chat-container')) !== null && _ref !== void 0 ? _ref : null;
26330
+ }
26331
+ function getActiveContainerAnimations(prompt) {
26332
+ return getActiveAnimations(getContainer(prompt));
26333
+ }
26334
+ function getActiveAnimations(container) {
26335
+ if (!container || typeof container.getAnimations !== 'function') {
26336
+ return [];
26337
+ }
26338
+ return container.getAnimations().filter(function(animation) {
26339
+ return animation.playState !== 'finished';
26340
+ }).map(function(animation) {
26341
+ return {
26342
+ animation: animation,
26343
+ currentTime: animation.currentTime,
26344
+ playState: animation.playState,
26345
+ startTime: animation.startTime
26346
+ };
26347
+ });
26348
+ }
26349
+ var revealProperties = [
26350
+ 'opacity',
26351
+ 'transform',
26352
+ 'translate',
26353
+ 'scale',
26354
+ 'rotate',
26355
+ 'visibility',
26356
+ 'clip',
26357
+ 'clipPath'
26358
+ ];
26359
+ function isRevealed(style, property) {
26360
+ if (property === 'opacity') {
26361
+ return style.opacity === '1';
26362
+ }
26363
+ if (property === 'transform') {
26364
+ return [
26365
+ 'none',
26366
+ 'matrix(1, 0, 0, 1, 0, 0)',
26367
+ 'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)'
26368
+ ].includes(style.transform);
26369
+ }
26370
+ if (property === 'translate') {
26371
+ return [
26372
+ 'none',
26373
+ '0px',
26374
+ '0px 0px',
26375
+ '0px 0px 0px'
26376
+ ].includes(style.translate);
26377
+ }
26378
+ if (property === 'scale') {
26379
+ return [
26380
+ 'none',
26381
+ '1',
26382
+ '1 1'
26383
+ ].includes(style.scale);
26384
+ }
26385
+ if (property === 'rotate') {
26386
+ return [
26387
+ 'none',
26388
+ '0deg'
26389
+ ].includes(style.rotate);
26390
+ }
26391
+ if (property === 'visibility') {
26392
+ return style.visibility === 'visible';
26393
+ }
26394
+ if (property === 'clip') {
26395
+ return [
26396
+ 'auto',
26397
+ 'rect(auto, auto, auto, auto)'
26398
+ ].includes(style.getPropertyValue('clip'));
26399
+ }
26400
+ return style.clipPath === 'none';
26401
+ }
26402
+ function getPendingRevealProperties(container) {
26403
+ if (!container || typeof getComputedStyle !== 'function') {
26404
+ return new Set(revealProperties);
26405
+ }
26406
+ var style = getComputedStyle(container);
26407
+ return new Set(revealProperties.filter(function(property) {
26408
+ return !isRevealed(style, property);
26409
+ }));
26410
+ }
26411
+ function affectsReveal(animation, pendingRevealProperties) {
26412
+ if (pendingRevealProperties.size === 0) {
26413
+ return false;
26414
+ }
26415
+ var effect = animation.effect;
26416
+ if (typeof (effect === null || effect === void 0 ? void 0 : effect.getKeyframes) !== 'function') {
26417
+ return true;
26418
+ }
26419
+ return effect.getKeyframes().some(function(keyframe) {
26420
+ return Array.from(pendingRevealProperties).some(function(property) {
26421
+ return Object.prototype.hasOwnProperty.call(keyframe, property);
26422
+ });
26423
+ });
26424
+ }
26425
+ function startedDuringReveal(current, animationsBeforeReveal) {
26426
+ var previous = animationsBeforeReveal.find(function(param) {
26427
+ var animation = param.animation;
26428
+ return animation === current.animation;
26429
+ });
26430
+ if (!previous) {
26431
+ return true;
26432
+ }
26433
+ if (previous.playState !== current.playState) {
26434
+ return true;
26435
+ }
26436
+ if (current.startTime !== null && previous.startTime !== current.startTime) {
26437
+ return true;
26438
+ }
26439
+ return typeof previous.currentTime === 'number' && typeof current.currentTime === 'number' && current.currentTime < previous.currentTime;
26440
+ }
26441
+ function holdContainerInertUntilReveal(prompt) {
26442
+ var container = getContainer(prompt);
26443
+ if (!(container === null || container === void 0 ? void 0 : container.classList.contains('ais-Chat-container--open')) || container.hasAttribute('inert')) {
26444
+ return;
26445
+ }
26446
+ container.setAttribute('inert', '');
26447
+ containersHeldInert.add(container);
26448
+ }
26449
+ function restoreContainerInertUntilReveal(prompt) {
26450
+ var container = getContainer(prompt);
26451
+ if (container && containersHeldInert.has(container) && getPendingRevealProperties(container).size > 0) {
26452
+ container.setAttribute('inert', '');
26453
+ }
26454
+ }
26455
+ function requestAnimationFrameOrRun(callback) {
26456
+ if (typeof requestAnimationFrame === 'function') {
26457
+ requestAnimationFrame(callback);
26458
+ } else {
26459
+ callback();
26460
+ }
26461
+ }
26462
+ function focusAfterReveal(prompt, animationsBeforeReveal, shouldFocus) {
26463
+ var shouldRelease = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : shouldFocus;
26464
+ var container = getContainer(prompt);
26465
+ var settle = function settle() {
26466
+ if (!shouldRelease()) {
26467
+ return;
26468
+ }
26469
+ if (container) {
26470
+ revealAnimationsHeldByContainer.delete(container);
26471
+ }
26472
+ if (container && containersHeldInert.has(container) && container.classList.contains('ais-Chat-container--open')) {
26473
+ container.removeAttribute('inert');
26474
+ containersHeldInert.delete(container);
26475
+ }
26476
+ if (prompt && shouldFocus()) {
26477
+ prompt.focus();
26478
+ }
26479
+ };
26480
+ var waitForReveal = function waitForReveal1() {
26481
+ var requestIsCurrent = shouldRelease();
26482
+ var pendingRevealProperties = getPendingRevealProperties(container);
26483
+ var heldRevealAnimations = container ? revealAnimationsHeldByContainer.get(container) : undefined;
26484
+ var activeAnimations = getActiveAnimations(container);
26485
+ var heldRevealIsActive = activeAnimations.some(function(param) {
26486
+ var animation = param.animation;
26487
+ return heldRevealAnimations === null || heldRevealAnimations === void 0 ? void 0 : heldRevealAnimations.has(animation);
26488
+ });
26489
+ var replacesInactiveHeldReveal = heldRevealAnimations !== undefined && !heldRevealIsActive;
26490
+ var revealAnimations = activeAnimations.filter(function(current) {
26491
+ var _current_animation_effect;
26492
+ return (startedDuringReveal(current, animationsBeforeReveal) || (heldRevealAnimations === null || heldRevealAnimations === void 0 ? void 0 : heldRevealAnimations.has(current.animation)) || replacesInactiveHeldReveal) && ((_current_animation_effect = current.animation.effect) === null || _current_animation_effect === void 0 ? void 0 : _current_animation_effect.getTiming().iterations) !== Infinity && affectsReveal(current.animation, pendingRevealProperties);
26493
+ });
26494
+ if (container && revealAnimations.length > 0 && (!heldRevealAnimations || requestIsCurrent || !heldRevealIsActive)) {
26495
+ revealAnimationsHeldByContainer.set(container, new Set(revealAnimations.map(function(param) {
26496
+ var animation = param.animation;
26497
+ return animation;
26498
+ })));
26499
+ }
26500
+ if (!requestIsCurrent) {
26501
+ if (container && !container.classList.contains('ais-Chat-container--open')) {
26502
+ revealAnimationsHeldByContainer.delete(container);
26503
+ containersHeldInert.delete(container);
26504
+ }
26505
+ return;
26506
+ }
26507
+ if (revealAnimations.length === 0) {
26508
+ settle();
26509
+ return;
26510
+ }
26511
+ Promise.all(revealAnimations.map(function(param) {
26512
+ var animation = param.animation;
26513
+ return animation.finished.catch(function() {});
26514
+ })).then(function() {
26515
+ return requestAnimationFrameOrRun(waitForReveal);
26516
+ });
26517
+ };
26518
+ waitForReveal();
26519
+ }
26520
+
25434
26521
  var useStickToBottom = createStickToBottom({
25435
26522
  useCallback: React.useCallback,
25436
26523
  useEffect: React.useEffect,
@@ -25576,11 +26663,24 @@
25576
26663
  createElement: React.createElement,
25577
26664
  Fragment: React.Fragment,
25578
26665
  useMemo: React.useMemo,
25579
- useState: React.useState
26666
+ useState: React.useState,
26667
+ useEffect: React.useEffect
25580
26668
  });
25581
26669
  function createDefaultTools(itemComponent, getSearchPageURL) {
25582
26670
  var _obj;
25583
- return _obj = {}, _define_property(_obj, SearchIndexToolType, createCarouselTool(true, itemComponent, getSearchPageURL)), _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;
26671
+ return _obj = {}, _define_property(_obj, SearchIndexToolType, _object_spread_props(_object_spread({}, createCarouselTool(true, itemComponent, getSearchPageURL)), {
26672
+ // The agent decides per turn whether the richer display-results tool
26673
+ // takes over the rendering of the search results.
26674
+ shouldRender: isDisplayResultsDisabled
26675
+ })), _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;
26676
+ }
26677
+ /**
26678
+ * Whether the search tool renders its own results, i.e. the agent did not hand
26679
+ * the turn to the display-results tool. Set on the message by the backend.
26680
+ */ function isDisplayResultsDisabled(param) {
26681
+ var parentMessage = param.parentMessage;
26682
+ var _parentMessage_metadata;
26683
+ return ((_parentMessage_metadata = parentMessage.metadata) === null || _parentMessage_metadata === void 0 ? void 0 : _parentMessage_metadata.displayResultsEnabled) !== true;
25584
26684
  }
25585
26685
  function mergeToolOptions(defaultTools, userTools) {
25586
26686
  if (!userTools) {
@@ -25588,22 +26688,62 @@
25588
26688
  }
25589
26689
  var tools = _object_spread({}, defaultTools, userTools);
25590
26690
  Object.keys(userTools).forEach(function(toolName) {
25591
- var _defaultTools_toolName;
25592
26691
  var userTool = userTools[toolName];
25593
- var defaultStreamInput = (_defaultTools_toolName = defaultTools[toolName]) === null || _defaultTools_toolName === void 0 ? void 0 : _defaultTools_toolName.streamInput;
26692
+ var defaultTool = defaultTools[toolName];
26693
+ var defaultStreamInput = defaultTool === null || defaultTool === void 0 ? void 0 : defaultTool.streamInput;
25594
26694
  if (userTool.layoutComponent !== undefined && userTool.streamInput === undefined && defaultStreamInput !== undefined) {
25595
- tools[toolName] = _object_spread_props(_object_spread({}, userTool), {
26695
+ tools[toolName] = _object_spread_props(_object_spread({}, tools[toolName]), {
25596
26696
  streamInput: defaultStreamInput
25597
26697
  });
25598
26698
  }
26699
+ // Overriding a tool's rendering shouldn't opt it out of the conditions
26700
+ // under which the default renders at all.
26701
+ if (userTool.shouldRender === undefined && (defaultTool === null || defaultTool === void 0 ? void 0 : defaultTool.shouldRender)) {
26702
+ tools[toolName] = _object_spread_props(_object_spread({}, tools[toolName]), {
26703
+ shouldRender: defaultTool.shouldRender
26704
+ });
26705
+ }
25599
26706
  });
25600
26707
  return tools;
25601
26708
  }
26709
+ var AnimationSnapshot = /*#__PURE__*/ function(_React_Component) {
26710
+ _inherits(AnimationSnapshot, _React_Component);
26711
+ function AnimationSnapshot() {
26712
+ _class_call_check(this, AnimationSnapshot);
26713
+ return _call_super(this, AnimationSnapshot, arguments);
26714
+ }
26715
+ _create_class(AnimationSnapshot, [
26716
+ {
26717
+ key: "getSnapshotBeforeUpdate",
26718
+ value: function getSnapshotBeforeUpdate() {
26719
+ return getActiveContainerAnimations(this.props.promptRef.current);
26720
+ }
26721
+ },
26722
+ {
26723
+ key: "componentDidUpdate",
26724
+ value: function componentDidUpdate(_previousProps, _previousState, animationsBeforeReveal) {
26725
+ this.props.animationsBeforeReveal.current = animationsBeforeReveal;
26726
+ if (!_previousProps.open && this.props.open) {
26727
+ holdContainerInertUntilReveal(this.props.promptRef.current);
26728
+ } else if (this.props.open) {
26729
+ restoreContainerInertUntilReveal(this.props.promptRef.current);
26730
+ }
26731
+ }
26732
+ },
26733
+ {
26734
+ key: "render",
26735
+ value: function render() {
26736
+ return null;
26737
+ }
26738
+ }
26739
+ ]);
26740
+ return AnimationSnapshot;
26741
+ }(React.Component);
25602
26742
  function ChatInner(_0, _1) {
25603
26743
  var _ref = [
25604
26744
  _0,
25605
26745
  _1
25606
- ], _ref1 = _to_array(_ref), _ref2 = _ref1[0], _rest = _ref1.slice(1), userTools = _ref2.tools, headerProps = _ref2.headerProps, messagesProps = _ref2.messagesProps, promptProps = _ref2.promptProps, itemComponent = _ref2.itemComponent, layoutComponent = _ref2.layoutComponent, headerComponent = _ref2.headerComponent, headerTitleIconComponent = _ref2.headerTitleIconComponent, headerCloseIconComponent = _ref2.headerCloseIconComponent, headerMinimizeIconComponent = _ref2.headerMinimizeIconComponent, headerMaximizeIconComponent = _ref2.headerMaximizeIconComponent, loaderComponent = _ref2.loaderComponent, messagesErrorComponent = _ref2.messagesErrorComponent, promptComponent = _ref2.promptComponent, promptHeaderComponent = _ref2.promptHeaderComponent, promptFooterComponent = _ref2.promptFooterComponent, assistantMessageLeadingComponent = _ref2.assistantMessageLeadingComponent, assistantMessageFooterComponent = _ref2.assistantMessageFooterComponent, userMessageLeadingComponent = _ref2.userMessageLeadingComponent, userMessageFooterComponent = _ref2.userMessageFooterComponent, emptyComponent = _ref2.emptyComponent, actionsComponent = _ref2.actionsComponent, suggestionsComponent = _ref2.suggestionsComponent, classNames = _ref2.classNames, _ref_translations = _ref2.translations, translations = _ref_translations === void 0 ? {} : _ref_translations, title = _ref2.title, getSearchPageURL = _ref2.getSearchPageURL, _ref_disableTriggerValidation = _ref2.disableTriggerValidation, disableTriggerValidation = _ref_disableTriggerValidation === void 0 ? false : _ref_disableTriggerValidation, showReasoning = _ref2.showReasoning, props = _object_without_properties(_ref2, [
26746
+ ], _ref1 = _to_array(_ref), _ref2 = _ref1[0], _rest = _ref1.slice(1), userTools = _ref2.tools, headerProps = _ref2.headerProps, messagesProps = _ref2.messagesProps, promptProps = _ref2.promptProps, itemComponent = _ref2.itemComponent, layoutComponent = _ref2.layoutComponent, headerComponent = _ref2.headerComponent, headerTitleIconComponent = _ref2.headerTitleIconComponent, headerCloseIconComponent = _ref2.headerCloseIconComponent, headerMinimizeIconComponent = _ref2.headerMinimizeIconComponent, headerMaximizeIconComponent = _ref2.headerMaximizeIconComponent, loaderComponent = _ref2.loaderComponent, loaderPosition = _ref2.loaderPosition, shouldShowLoader = _ref2.shouldShowLoader, loaderShowDelay = _ref2.loaderShowDelay, loaderMinDuration = _ref2.loaderMinDuration, messagesErrorComponent = _ref2.messagesErrorComponent, promptComponent = _ref2.promptComponent, promptHeaderComponent = _ref2.promptHeaderComponent, promptFooterComponent = _ref2.promptFooterComponent, assistantMessageLeadingComponent = _ref2.assistantMessageLeadingComponent, assistantMessageFooterComponent = _ref2.assistantMessageFooterComponent, userMessageLeadingComponent = _ref2.userMessageLeadingComponent, userMessageFooterComponent = _ref2.userMessageFooterComponent, emptyComponent = _ref2.emptyComponent, actionsComponent = _ref2.actionsComponent, suggestionsComponent = _ref2.suggestionsComponent, classNames = _ref2.classNames, _ref_translations = _ref2.translations, translations = _ref_translations === void 0 ? {} : _ref_translations, title = _ref2.title, getSearchPageURL = _ref2.getSearchPageURL, _ref_disableTriggerValidation = _ref2.disableTriggerValidation, disableTriggerValidation = _ref_disableTriggerValidation === void 0 ? false : _ref_disableTriggerValidation, showReasoning = _ref2.showReasoning, props = _object_without_properties(_ref2, [
25607
26747
  "tools",
25608
26748
  "headerProps",
25609
26749
  "messagesProps",
@@ -25616,6 +26756,10 @@
25616
26756
  "headerMinimizeIconComponent",
25617
26757
  "headerMaximizeIconComponent",
25618
26758
  "loaderComponent",
26759
+ "loaderPosition",
26760
+ "shouldShowLoader",
26761
+ "loaderShowDelay",
26762
+ "loaderMinDuration",
25619
26763
  "messagesErrorComponent",
25620
26764
  "promptComponent",
25621
26765
  "promptHeaderComponent",
@@ -25639,6 +26783,8 @@
25639
26783
  var _useInstantSearch = useInstantSearch(), indexUiState = _useInstantSearch.indexUiState, setIndexUiState = _useInstantSearch.setIndexUiState;
25640
26784
  var _useState = _sliced_to_array(React.useState(false), 2), maximized = _useState[0], setMaximized = _useState[1];
25641
26785
  var promptRef = React.useRef(null);
26786
+ var focusRequestId = React.useRef(0);
26787
+ var animationsBeforeReveal = React.useRef([]);
25642
26788
  var _useStickToBottom = useStickToBottom({
25643
26789
  initial: 'smooth',
25644
26790
  resize: 'smooth'
@@ -25660,7 +26806,7 @@
25660
26806
  tools: tools,
25661
26807
  disableTriggerValidation: effectiveDisableTriggerValidation
25662
26808
  }));
25663
- 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'];
26809
+ 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'];
25664
26810
  React.useImperativeHandle(ref, function() {
25665
26811
  return {
25666
26812
  setOpen: setOpen,
@@ -25671,10 +26817,21 @@
25671
26817
  };
25672
26818
  });
25673
26819
  React.useEffect(function() {
26820
+ if (!open) {
26821
+ focusRequestId.current++;
26822
+ return;
26823
+ }
25674
26824
  if (consumeInputFocus === null || consumeInputFocus === void 0 ? void 0 : consumeInputFocus()) {
26825
+ var currentFocusRequestId = ++focusRequestId.current;
26826
+ var previousAnimations = animationsBeforeReveal.current;
26827
+ holdContainerInertUntilReveal(promptRef.current);
25675
26828
  window.requestAnimationFrame(function() {
25676
- var _promptRef_current;
25677
- (_promptRef_current = promptRef.current) === null || _promptRef_current === void 0 ? void 0 : _promptRef_current.focus();
26829
+ var prompt = promptRef.current;
26830
+ focusAfterReveal(prompt, previousAnimations, function() {
26831
+ return focusRequestId.current === currentFocusRequestId && promptRef.current === prompt;
26832
+ }, function() {
26833
+ return focusRequestId.current === currentFocusRequestId;
26834
+ });
25678
26835
  });
25679
26836
  }
25680
26837
  });
@@ -25702,7 +26859,7 @@
25702
26859
  "assistantMessageProps",
25703
26860
  "userMessageProps"
25704
26861
  ]);
25705
- return /*#__PURE__*/ React.createElement(ChatUiComponent, {
26862
+ var chat = /*#__PURE__*/ React.createElement(ChatUiComponent, {
25706
26863
  title: title,
25707
26864
  open: open,
25708
26865
  maximized: maximized,
@@ -25754,6 +26911,10 @@
25754
26911
  contentRef: contentRef,
25755
26912
  onScrollToBottom: scrollToBottom,
25756
26913
  loaderComponent: loaderComponent,
26914
+ loaderPosition: loaderPosition,
26915
+ shouldShowLoader: shouldShowLoader,
26916
+ loaderShowDelay: loaderShowDelay,
26917
+ loaderMinDuration: loaderMinDuration,
25757
26918
  errorComponent: messagesErrorComponent,
25758
26919
  emptyComponent: emptyComponent,
25759
26920
  actionsComponent: actionsComponent,
@@ -25795,6 +26956,7 @@
25795
26956
  }),
25796
26957
  suggestionsProps: {
25797
26958
  suggestions: suggestions,
26959
+ isLoading: suggestionsStatus === 'loading',
25798
26960
  onSuggestionClick: function onSuggestionClick(suggestion) {
25799
26961
  sendMessage({
25800
26962
  text: suggestion
@@ -25803,6 +26965,11 @@
25803
26965
  },
25804
26966
  classNames: classNames
25805
26967
  });
26968
+ return /*#__PURE__*/ React.createElement(React.Fragment, null, /*#__PURE__*/ React.createElement(AnimationSnapshot, {
26969
+ promptRef: promptRef,
26970
+ animationsBeforeReveal: animationsBeforeReveal,
26971
+ open: open
26972
+ }), chat);
25806
26973
  }
25807
26974
  var Chat = /*#__PURE__*/ React.forwardRef(ChatInner);
25808
26975
 
@@ -25823,16 +26990,20 @@
25823
26990
  "context",
25824
26991
  "transformItems"
25825
26992
  ]);
25826
- var _usePromptSuggestions = usePromptSuggestions({
26993
+ var source = agentId !== undefined ? {
25827
26994
  agentId: agentId,
25828
- transport: transport,
26995
+ transport: transport
26996
+ } : {
26997
+ transport: transport
26998
+ };
26999
+ var _usePromptSuggestions = usePromptSuggestions(_object_spread_props(_object_spread({}, source), {
25829
27000
  configurationId: configurationId,
25830
27001
  transformHits: transformHits,
25831
27002
  context: context,
25832
27003
  transformItems: transformItems
25833
- }, {
27004
+ }), {
25834
27005
  $$widgetType: 'ais.promptSuggestions'
25835
- }), suggestions = _usePromptSuggestions.suggestions, isLoading = _usePromptSuggestions.isLoading, onSuggestionClick = _usePromptSuggestions.onSuggestionClick, isChatBusy = _usePromptSuggestions.isChatBusy, sendToChat = _usePromptSuggestions.sendToChat;
27006
+ }), suggestions = _usePromptSuggestions.suggestions, isLoading = _usePromptSuggestions.isLoading, error = _usePromptSuggestions.error, onSuggestionClick = _usePromptSuggestions.onSuggestionClick, isChatBusy = _usePromptSuggestions.isChatBusy, sendToChat = _usePromptSuggestions.sendToChat;
25836
27007
  var handleClick = onSuggestionClickOverride ? function(prompt) {
25837
27008
  return onSuggestionClickOverride(prompt, {
25838
27009
  sendToChat: sendToChat
@@ -25842,6 +27013,7 @@
25842
27013
  return /*#__PURE__*/ React.createElement(LayoutComponent, {
25843
27014
  suggestions: suggestions,
25844
27015
  isLoading: isLoading,
27016
+ error: error,
25845
27017
  onSuggestionClick: handleClick,
25846
27018
  isChatBusy: isChatBusy
25847
27019
  });