react-instantsearch 7.46.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.46.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.46.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.113.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) {
@@ -13989,27 +14166,132 @@
13989
14166
  * Resolves the tool a message part belongs to, from either a part type
13990
14167
  * (`tool-algolia_search_index`) or a bare tool name.
13991
14168
  *
13992
- * Generic over the tool shape so the renderer, the loader and the connector —
13993
- * which hold different subsets of the tool contract all resolve names the same
13994
- * way.
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.
13995
14176
  */ var findTool = function findTool(partType, tools) {
13996
14177
  var toolName = startsWith(partType, TOOL_PART_PREFIX) ? partType.slice(TOOL_PART_PREFIX.length) : partType;
13997
14178
  if (tools[toolName]) {
13998
14179
  return tools[toolName];
13999
14180
  }
14000
- // Compatibility shim for tool names suffixed by the index name, as the Algolia
14001
- // MCP Server does (`algolia_search_index_products`). The longest matching key
14002
- // wins, so registering both `foo` and `foo_bar` resolves `foo_bar_products` to
14003
- // `foo_bar` — otherwise the winner would depend on registration order.
14004
- var match;
14005
- Object.keys(tools).forEach(function(key) {
14006
- if (startsWith(toolName, "".concat(key, "_")) && (match === undefined || key.length > match.length)) {
14007
- match = key;
14008
- }
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);
14009
14192
  });
14010
- return match === undefined ? undefined : tools[match];
14193
+ return tools[claimants[0]];
14011
14194
  };
14012
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
+ };
14013
14295
  var hasQueries = function hasQueries(input) {
14014
14296
  return Array.isArray(input.queries);
14015
14297
  };
@@ -14028,18 +14310,41 @@
14028
14310
  }
14029
14311
  var facetFilters = Object.entries(query).reduce(function(acc, param) {
14030
14312
  var _param = _sliced_to_array(param, 2), key = _param[0], value = _param[1];
14031
- if (!startsWith(key, FACET_KEY_PREFIX) || !Array.isArray(value)) {
14313
+ if (!startsWith(key, FACET_KEY_PREFIX)) {
14032
14314
  return acc;
14033
14315
  }
14034
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
+ }
14035
14330
  var values = value.filter(function(item) {
14036
14331
  return typeof item === 'string';
14037
14332
  });
14038
- if (attribute && values.length > 0) {
14039
- acc.push(values.map(function(item) {
14040
- return "".concat(attribute, ":").concat(item);
14041
- }));
14333
+ if (values.length === 0) {
14334
+ return acc;
14042
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
+ }));
14043
14348
  return acc;
14044
14349
  }, []);
14045
14350
  return facetFilters.length > 0 ? facetFilters : undefined;
@@ -14052,8 +14357,24 @@
14052
14357
  * Algolia MCP Server search tool instead expresses refinements as individual
14053
14358
  * `facet_<attribute>` keys (e.g. `facet_categories: ['Books', 'Toys']`), which
14054
14359
  * are converted here into `[['attribute:value']]`.
14055
- */ 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) {
14056
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
+ }
14057
14378
  return {
14058
14379
  query: query === null || query === void 0 ? void 0 : query.query,
14059
14380
  facetFilters: getFacetFilters(query)
@@ -15772,7 +16093,7 @@
15772
16093
  createElement: createElement
15773
16094
  });
15774
16095
  return function HeaderComponent(param) {
15775
- 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;
15776
16097
  if (nbItems < 1) {
15777
16098
  return null;
15778
16099
  }
@@ -15787,7 +16108,7 @@
15787
16108
  size: "sm",
15788
16109
  onClick: function onClick() {
15789
16110
  if (!input || !applyFilters) return;
15790
- var params = applyFilters(getApplyFiltersParamsFromToolInput(input));
16111
+ var params = applyFilters(getApplyFiltersParamsFromToolInput(input, resolvedSearchParams));
15791
16112
  if (getSearchPageURL) {
15792
16113
  var searchPageURL = getSearchPageURL(params);
15793
16114
  var resolvedURL = new URL(searchPageURL, window.location.href);
@@ -15841,6 +16162,14 @@
15841
16162
  var message = context.message, applyFilters = context.applyFilters, insightsEventContext = context.insightsEventContext, sendEvent = context.sendEvent, onClose = context.onClose;
15842
16163
  var instantSearchStatus = (_ref = insightsEventContext === null || insightsEventContext === void 0 ? void 0 : insightsEventContext.instantSearchStatus) !== null && _ref !== void 0 ? _ref : 'idle';
15843
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
+ ]);
15844
16173
  var output = message === null || message === void 0 ? void 0 : message.output;
15845
16174
  var hits = (output === null || output === void 0 ? void 0 : output.hits) || [];
15846
16175
  var items = addQueryID(addAbsolutePosition(hits, 0, hits.length), output === null || output === void 0 ? void 0 : output.queryID);
@@ -15888,6 +16217,7 @@
15888
16217
  showViewAll: showViewAll,
15889
16218
  nbHits: output === null || output === void 0 ? void 0 : output.nbHits,
15890
16219
  input: input,
16220
+ resolvedSearchParams: resolvedSearchParams,
15891
16221
  applyFilters: applyFilters,
15892
16222
  getSearchPageURL: getSearchPageURL,
15893
16223
  onClose: onClose
@@ -15899,6 +16229,7 @@
15899
16229
  showViewAll: showViewAll,
15900
16230
  nbHits: output === null || output === void 0 ? void 0 : output.nbHits,
15901
16231
  input: input,
16232
+ resolvedSearchParams: resolvedSearchParams,
15902
16233
  applyFilters: applyFilters,
15903
16234
  getSearchPageURL: getSearchPageURL,
15904
16235
  onClose: onClose
@@ -15909,6 +16240,7 @@
15909
16240
  HeaderComponent,
15910
16241
  output === null || output === void 0 ? void 0 : output.nbHits,
15911
16242
  input,
16243
+ resolvedSearchParams,
15912
16244
  applyFilters,
15913
16245
  getSearchPageURL,
15914
16246
  onClose
@@ -17128,11 +17460,75 @@
17128
17460
  return Boolean(item && (typeof item === "undefined" ? "undefined" : _type_of(item)) === 'object' && item[PROMPT_SUGGESTION_FLAG]);
17129
17461
  }
17130
17462
 
17131
- function flat(arr) {
17132
- return arr.reduce(function(acc, array) {
17133
- return acc.concat(array);
17134
- }, []);
17135
- }
17463
+ var tryParseJson = function tryParseJson(value) {
17464
+ try {
17465
+ return JSON.parse(value);
17466
+ } catch (unused) {
17467
+ return undefined;
17468
+ }
17469
+ };
17470
+ var repairPartialJson = function repairPartialJson(value) {
17471
+ var repaired = value.trim();
17472
+ if (!repaired) {
17473
+ return repaired;
17474
+ }
17475
+ var inString = false;
17476
+ var isEscaped = false;
17477
+ var stack = [];
17478
+ for(var index = 0; index < repaired.length; index++){
17479
+ var char = repaired[index];
17480
+ if (inString) {
17481
+ if (isEscaped) {
17482
+ isEscaped = false;
17483
+ } else if (char === '\\') {
17484
+ isEscaped = true;
17485
+ } else if (char === '"') {
17486
+ inString = false;
17487
+ }
17488
+ continue;
17489
+ }
17490
+ if (char === '"') {
17491
+ inString = true;
17492
+ continue;
17493
+ }
17494
+ if (char === '{' || char === '[') {
17495
+ stack.push(char);
17496
+ continue;
17497
+ }
17498
+ if (char === '}' && stack[stack.length - 1] === '{') {
17499
+ stack.pop();
17500
+ continue;
17501
+ }
17502
+ if (char === ']' && stack[stack.length - 1] === '[') {
17503
+ stack.pop();
17504
+ }
17505
+ }
17506
+ if (inString && !isEscaped) {
17507
+ repaired += '"';
17508
+ }
17509
+ repaired = repaired.replace(RegExp(",\\s*$", "u"), '');
17510
+ if (stack.length > 0) {
17511
+ repaired += stack.reverse().map(function(opening) {
17512
+ return opening === '{' ? '}' : ']';
17513
+ }).join('');
17514
+ }
17515
+ return repaired.replace(RegExp(",\\s*([}\\]])", "gu"), '$1');
17516
+ };
17517
+ var parsePartialJson = function parsePartialJson(accumulatedRawJson, fallbackValue) {
17518
+ var normalized = accumulatedRawJson.trim();
17519
+ if (!normalized) {
17520
+ return fallbackValue;
17521
+ }
17522
+ var directParsed = tryParseJson(normalized);
17523
+ if (directParsed !== undefined) {
17524
+ return directParsed;
17525
+ }
17526
+ var repairedParsed = tryParseJson(repairPartialJson(normalized));
17527
+ if (repairedParsed !== undefined) {
17528
+ return repairedParsed;
17529
+ }
17530
+ return fallbackValue;
17531
+ };
17136
17532
 
17137
17533
  /**
17138
17534
  * Stream parser for parsing SSE (Server-Sent Events) streams.
@@ -17424,301 +17820,41 @@
17424
17820
  return undefined;
17425
17821
  }
17426
17822
 
17427
- /**
17428
- * Reads a human-readable message from a failed HTTP response body when the
17429
- * server returns JSON such as `{ "message": "..." }` (the shared
17430
- * `ErrorResponse` shape used by every status code), falling back to the HTTP
17431
- * status line when the body is empty or not parseable.
17432
- */ function getHttpErrorMessage(response) {
17433
- var fallback = "HTTP error: ".concat(response.status, " ").concat(response.statusText);
17434
- return response.text().then(function(text) {
17435
- var _tryParseErrorMessage;
17436
- return (_tryParseErrorMessage = tryParseErrorMessage(text)) !== null && _tryParseErrorMessage !== void 0 ? _tryParseErrorMessage : fallback;
17437
- }).catch(function() {
17438
- return fallback;
17439
- });
17823
+ var _computedKey$1;
17824
+ var defaultGuardrailFallbackResponse = 'Sorry, we are not able to generate a response at the moment.';
17825
+ var TOOL_CALL_CANCELLED_ERROR_TEXT = 'The tool call was cancelled: the conversation moved on before a result was provided.';
17826
+ function getToolName(part) {
17827
+ if (part.type === 'dynamic-tool') {
17828
+ var _part_toolName;
17829
+ return (_part_toolName = part.toolName) !== null && _part_toolName !== void 0 ? _part_toolName : part.type;
17830
+ }
17831
+ return part.type.slice('tool-'.length);
17832
+ }
17833
+ function warnInvalidGlobalToolResult(toolCallId) {}
17834
+ // A tool call awaiting an output that the client owns. Provider-executed calls
17835
+ // are resolved server-side, so they are left alone.
17836
+ function isPendingToolPart(part) {
17837
+ var candidate = part;
17838
+ return typeof candidate.type === 'string' && typeof candidate.toolCallId === 'string' && (candidate.state === 'input-streaming' || candidate.state === 'input-available') && candidate.providerExecuted !== true;
17839
+ }
17840
+ // Drops the fields that only belong to the state being left behind:
17841
+ // `output-error` forbids `output`, and a committed output is not `preliminary`.
17842
+ function withTerminalToolState(part, terminalState) {
17843
+ // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
17844
+ part.preliminary; // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
17845
+ part.rawOutput; // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
17846
+ part.output; // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
17847
+ part.errorText;
17848
+ var retainedPart = _object_without_properties(part, [
17849
+ "preliminary",
17850
+ "rawOutput",
17851
+ "output",
17852
+ "errorText"
17853
+ ]);
17854
+ return _object_spread({}, retainedPart, terminalState);
17440
17855
  }
17441
- /**
17442
- * Abstract base class for HTTP-based chat transports.
17443
- */ var HttpChatTransport = /*#__PURE__*/ function() {
17444
- function HttpChatTransport(param) {
17445
- var _param_api = param.api, api = _param_api === void 0 ? '/api/chat' : _param_api, credentials = param.credentials, headers = param.headers, body = param.body, customFetch = param.fetch, prepareSendMessagesRequest = param.prepareSendMessagesRequest, prepareReconnectToStreamRequest = param.prepareReconnectToStreamRequest;
17446
- _class_call_check(this, HttpChatTransport);
17447
- _define_property(this, "api", void 0);
17448
- _define_property(this, "credentials", void 0);
17449
- _define_property(this, "headers", void 0);
17450
- _define_property(this, "body", void 0);
17451
- _define_property(this, "fetch", void 0);
17452
- _define_property(this, "prepareSendMessagesRequest", void 0);
17453
- _define_property(this, "prepareReconnectToStreamRequest", void 0);
17454
- this.api = api;
17455
- this.credentials = credentials;
17456
- this.headers = headers;
17457
- this.body = body;
17458
- this.fetch = customFetch;
17459
- this.prepareSendMessagesRequest = prepareSendMessagesRequest;
17460
- this.prepareReconnectToStreamRequest = prepareReconnectToStreamRequest;
17461
- }
17462
- _create_class(HttpChatTransport, [
17463
- {
17464
- key: "sendMessages",
17465
- value: function sendMessages(param) {
17466
- var _this = this;
17467
- var abortSignal = param.abortSignal, chatId = param.chatId, messages = param.messages, requestMetadata = param.requestMetadata, trigger = param.trigger, messageId = param.messageId, requestHeaders = param.headers, requestBody = param.body;
17468
- var _this_fetch;
17469
- var fetchFn = (_this_fetch = this.fetch) !== null && _this_fetch !== void 0 ? _this_fetch : fetch;
17470
- // Resolve configurable values
17471
- return Promise.all([
17472
- resolveValue(this.credentials),
17473
- resolveValue(this.headers),
17474
- resolveValue(this.body)
17475
- ]).then(function(param) {
17476
- var _param = _sliced_to_array(param, 3), resolvedCredentials = _param[0], resolvedHeaders = _param[1], resolvedBody = _param[2];
17477
- // Build default request options
17478
- var api = _this.api;
17479
- var body = _object_spread({
17480
- id: chatId,
17481
- messages: messages
17482
- }, resolvedBody, requestBody);
17483
- var headers = _object_spread({
17484
- 'Content-Type': 'application/json'
17485
- }, _instanceof(resolvedHeaders, Headers) ? Object.fromEntries(resolvedHeaders.entries()) : resolvedHeaders, _instanceof(requestHeaders, Headers) ? Object.fromEntries(requestHeaders.entries()) : requestHeaders);
17486
- var credentials = resolvedCredentials;
17487
- // Apply custom preparation if provided
17488
- var prepareRequestBody = _object_spread({}, resolvedBody, requestBody);
17489
- var preparePromise = _this.prepareSendMessagesRequest ? Promise.resolve(_this.prepareSendMessagesRequest({
17490
- id: chatId,
17491
- messages: messages,
17492
- requestMetadata: requestMetadata,
17493
- body: prepareRequestBody,
17494
- credentials: resolvedCredentials,
17495
- headers: resolvedHeaders,
17496
- api: _this.api,
17497
- trigger: trigger,
17498
- messageId: messageId
17499
- })) : Promise.resolve(null);
17500
- return preparePromise.then(function(prepared) {
17501
- if (prepared) {
17502
- body = prepared.body;
17503
- if (prepared.api) api = prepared.api;
17504
- if (prepared.headers) {
17505
- headers = _object_spread({
17506
- 'Content-Type': 'application/json'
17507
- }, _instanceof(prepared.headers, Headers) ? Object.fromEntries(prepared.headers.entries()) : prepared.headers);
17508
- }
17509
- if (prepared.credentials) credentials = prepared.credentials;
17510
- }
17511
- return fetchFn(api, {
17512
- method: 'POST',
17513
- headers: headers,
17514
- body: JSON.stringify(body),
17515
- signal: abortSignal,
17516
- credentials: credentials
17517
- }).then(function(response) {
17518
- if (!response.ok) {
17519
- return getHttpErrorMessage(response).then(function(message) {
17520
- throw new Error(message);
17521
- });
17522
- }
17523
- if (!response.body) {
17524
- throw new Error('Response body is empty');
17525
- }
17526
- return _this.processResponseStream(response.body);
17527
- });
17528
- });
17529
- });
17530
- }
17531
- },
17532
- {
17533
- key: "reconnectToStream",
17534
- value: function reconnectToStream(param) {
17535
- var _this = this;
17536
- var chatId = param.chatId, requestHeaders = param.headers, requestBody = param.body;
17537
- var _this_fetch;
17538
- var fetchFn = (_this_fetch = this.fetch) !== null && _this_fetch !== void 0 ? _this_fetch : fetch;
17539
- // Resolve configurable values
17540
- return Promise.all([
17541
- resolveValue(this.credentials),
17542
- resolveValue(this.headers),
17543
- resolveValue(this.body)
17544
- ]).then(function(param) {
17545
- var _param = _sliced_to_array(param, 3), resolvedCredentials = _param[0], resolvedHeaders = _param[1], resolvedBody = _param[2];
17546
- // Build default request options
17547
- var api = _this.api;
17548
- var headers = _object_spread({}, _instanceof(resolvedHeaders, Headers) ? Object.fromEntries(resolvedHeaders.entries()) : resolvedHeaders, _instanceof(requestHeaders, Headers) ? Object.fromEntries(requestHeaders.entries()) : requestHeaders);
17549
- var credentials = resolvedCredentials;
17550
- // Apply custom preparation if provided
17551
- var prepareRequestBody = _object_spread({}, resolvedBody, requestBody);
17552
- var preparePromise = _this.prepareReconnectToStreamRequest ? Promise.resolve(_this.prepareReconnectToStreamRequest({
17553
- id: chatId,
17554
- requestMetadata: undefined,
17555
- body: prepareRequestBody,
17556
- credentials: resolvedCredentials,
17557
- headers: resolvedHeaders,
17558
- api: _this.api
17559
- })) : Promise.resolve(null);
17560
- return preparePromise.then(function(prepared) {
17561
- if (prepared) {
17562
- if (prepared.api) api = prepared.api;
17563
- if (prepared.headers) {
17564
- headers = _instanceof(prepared.headers, Headers) ? Object.fromEntries(prepared.headers.entries()) : prepared.headers;
17565
- }
17566
- if (prepared.credentials) credentials = prepared.credentials;
17567
- }
17568
- // GET request for reconnection
17569
- return fetchFn("".concat(api, "?chatId=").concat(chatId), {
17570
- method: 'GET',
17571
- headers: headers,
17572
- credentials: credentials
17573
- }).then(function(response) {
17574
- if (!response.ok) {
17575
- // 404 means no stream to reconnect to, which is not an error
17576
- if (response.status === 404) {
17577
- return null;
17578
- }
17579
- return getHttpErrorMessage(response).then(function(message) {
17580
- throw new Error(message);
17581
- });
17582
- }
17583
- if (!response.body) {
17584
- return null;
17585
- }
17586
- return _this.processResponseStream(response.body);
17587
- });
17588
- });
17589
- });
17590
- }
17591
- }
17592
- ]);
17593
- return HttpChatTransport;
17594
- }();
17595
- /**
17596
- * Default chat transport implementation using NDJSON streaming.
17597
- */ var DefaultChatTransport = /*#__PURE__*/ function(HttpChatTransport) {
17598
- _inherits(DefaultChatTransport, HttpChatTransport);
17599
- function DefaultChatTransport() {
17600
- var options = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
17601
- _class_call_check(this, DefaultChatTransport);
17602
- return _call_super(this, DefaultChatTransport, [
17603
- options
17604
- ]);
17605
- }
17606
- _create_class(DefaultChatTransport, [
17607
- {
17608
- key: "processResponseStream",
17609
- value: function processResponseStream(stream) {
17610
- return parseJsonEventStream(stream);
17611
- }
17612
- }
17613
- ]);
17614
- return DefaultChatTransport;
17615
- }(HttpChatTransport);
17616
-
17617
- var tryParseJson = function tryParseJson(value) {
17618
- try {
17619
- return JSON.parse(value);
17620
- } catch (unused) {
17621
- return undefined;
17622
- }
17623
- };
17624
- var repairPartialJson = function repairPartialJson(value) {
17625
- var repaired = value.trim();
17626
- if (!repaired) {
17627
- return repaired;
17628
- }
17629
- var inString = false;
17630
- var isEscaped = false;
17631
- var stack = [];
17632
- for(var index = 0; index < repaired.length; index++){
17633
- var char = repaired[index];
17634
- if (inString) {
17635
- if (isEscaped) {
17636
- isEscaped = false;
17637
- } else if (char === '\\') {
17638
- isEscaped = true;
17639
- } else if (char === '"') {
17640
- inString = false;
17641
- }
17642
- continue;
17643
- }
17644
- if (char === '"') {
17645
- inString = true;
17646
- continue;
17647
- }
17648
- if (char === '{' || char === '[') {
17649
- stack.push(char);
17650
- continue;
17651
- }
17652
- if (char === '}' && stack[stack.length - 1] === '{') {
17653
- stack.pop();
17654
- continue;
17655
- }
17656
- if (char === ']' && stack[stack.length - 1] === '[') {
17657
- stack.pop();
17658
- }
17659
- }
17660
- if (inString && !isEscaped) {
17661
- repaired += '"';
17662
- }
17663
- repaired = repaired.replace(RegExp(",\\s*$", "u"), '');
17664
- if (stack.length > 0) {
17665
- repaired += stack.reverse().map(function(opening) {
17666
- return opening === '{' ? '}' : ']';
17667
- }).join('');
17668
- }
17669
- return repaired.replace(RegExp(",\\s*([}\\]])", "gu"), '$1');
17670
- };
17671
- var parsePartialJson = function parsePartialJson(accumulatedRawJson, fallbackValue) {
17672
- var normalized = accumulatedRawJson.trim();
17673
- if (!normalized) {
17674
- return fallbackValue;
17675
- }
17676
- var directParsed = tryParseJson(normalized);
17677
- if (directParsed !== undefined) {
17678
- return directParsed;
17679
- }
17680
- var repairedParsed = tryParseJson(repairPartialJson(normalized));
17681
- if (repairedParsed !== undefined) {
17682
- return repairedParsed;
17683
- }
17684
- return fallbackValue;
17685
- };
17686
-
17687
- var _computedKey$1;
17688
- var defaultGuardrailFallbackResponse = 'Sorry, we are not able to generate a response at the moment.';
17689
- var TOOL_CALL_CANCELLED_ERROR_TEXT = 'The tool call was cancelled: the conversation moved on before a result was provided.';
17690
- function getToolName(part) {
17691
- if (part.type === 'dynamic-tool') {
17692
- var _part_toolName;
17693
- return (_part_toolName = part.toolName) !== null && _part_toolName !== void 0 ? _part_toolName : part.type;
17694
- }
17695
- return part.type.slice('tool-'.length);
17696
- }
17697
- function warnInvalidGlobalToolResult(toolCallId) {}
17698
- // A tool call awaiting an output that the client owns. Provider-executed calls
17699
- // are resolved server-side, so they are left alone.
17700
- function isPendingToolPart(part) {
17701
- var candidate = part;
17702
- return typeof candidate.type === 'string' && typeof candidate.toolCallId === 'string' && (candidate.state === 'input-streaming' || candidate.state === 'input-available') && candidate.providerExecuted !== true;
17703
- }
17704
- // Drops the fields that only belong to the state being left behind:
17705
- // `output-error` forbids `output`, and a committed output is not `preliminary`.
17706
- function withTerminalToolState(part, terminalState) {
17707
- // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
17708
- part.preliminary; // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
17709
- part.rawOutput; // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
17710
- part.output; // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
17711
- part.errorText;
17712
- var retainedPart = _object_without_properties(part, [
17713
- "preliminary",
17714
- "rawOutput",
17715
- "output",
17716
- "errorText"
17717
- ]);
17718
- return _object_spread({}, retainedPart, terminalState);
17719
- }
17720
- _computedKey$1 = /** @internal */ '~addToolResultForMessage';
17721
- var _computedKey1$1 = _computedKey$1;
17856
+ _computedKey$1 = /** @internal */ '~addToolResultForMessage';
17857
+ var _computedKey1$1 = _computedKey$1;
17722
17858
  /**
17723
17859
  * Abstract base class for chat implementations.
17724
17860
  */ var AbstractChat = /*#__PURE__*/ function() {
@@ -19116,73 +19252,326 @@
19116
19252
  }
19117
19253
  });
19118
19254
  }
19119
- };
19120
- this['~registerMessagesCallback'](saveMessagesInLocalStorage);
19121
- this['~registerStatusCallback'](saveMessagesInLocalStorage);
19122
- }
19123
- _create_class(ChatState, [
19124
- {
19125
- key: "status",
19126
- get: function get() {
19127
- return this._status;
19128
- },
19129
- set: function set(newStatus) {
19130
- this._status = newStatus;
19131
- this._callStatusCallbacks();
19132
- }
19133
- },
19134
- {
19135
- key: "error",
19136
- get: function get() {
19137
- return this._error;
19138
- },
19139
- set: function set(newError) {
19140
- this._error = newError;
19141
- this._callErrorCallbacks();
19142
- }
19255
+ };
19256
+ this['~registerMessagesCallback'](saveMessagesInLocalStorage);
19257
+ this['~registerStatusCallback'](saveMessagesInLocalStorage);
19258
+ }
19259
+ _create_class(ChatState, [
19260
+ {
19261
+ key: "status",
19262
+ get: function get() {
19263
+ return this._status;
19264
+ },
19265
+ set: function set(newStatus) {
19266
+ this._status = newStatus;
19267
+ this._callStatusCallbacks();
19268
+ }
19269
+ },
19270
+ {
19271
+ key: "error",
19272
+ get: function get() {
19273
+ return this._error;
19274
+ },
19275
+ set: function set(newError) {
19276
+ this._error = newError;
19277
+ this._callErrorCallbacks();
19278
+ }
19279
+ },
19280
+ {
19281
+ key: "messages",
19282
+ get: function get() {
19283
+ return this._messages;
19284
+ },
19285
+ set: function set(newMessages) {
19286
+ this._messages = _to_consumable_array(newMessages);
19287
+ this._callMessagesCallbacks();
19288
+ }
19289
+ }
19290
+ ]);
19291
+ return ChatState;
19292
+ }();
19293
+ _computedKey3 = '~registerMessagesCallback', _computedKey4 = '~registerStatusCallback', _computedKey5 = '~registerErrorCallback';
19294
+ var _computedKey9 = _computedKey3, _computedKey10 = _computedKey4, _computedKey11 = _computedKey5;
19295
+ var Chat$1 = /*#__PURE__*/ function(AbstractChat) {
19296
+ _inherits(Chat, AbstractChat);
19297
+ function Chat(_0) {
19298
+ _class_call_check(this, Chat);
19299
+ var _this;
19300
+ var messages = _0.messages, agentId = _0.agentId, _0_persistence = _0.persistence, persistence = _0_persistence === void 0 ? true : _0_persistence, init = _object_without_properties(_0, [
19301
+ "messages",
19302
+ "agentId",
19303
+ "persistence"
19304
+ ]);
19305
+ var state = new ChatState(agentId, messages, persistence);
19306
+ _this = _call_super(this, Chat, [
19307
+ _object_spread_props(_object_spread({}, init), {
19308
+ state: state
19309
+ })
19310
+ ]), _define_property(_this, "_state", void 0), _define_property(_this, _computedKey9, function(onChange) {
19311
+ return _this._state['~registerMessagesCallback'](onChange);
19312
+ }), _define_property(_this, _computedKey10, function(onChange) {
19313
+ return _this._state['~registerStatusCallback'](onChange);
19314
+ }), _define_property(_this, _computedKey11, function(onChange) {
19315
+ return _this._state['~registerErrorCallback'](onChange);
19316
+ });
19317
+ _this._state = state;
19318
+ return _this;
19319
+ }
19320
+ return Chat;
19321
+ }(AbstractChat);
19322
+
19323
+ // Centralizes the "open the chat from an entry point" behavior shared by the
19324
+ // SearchBox AI button, the Autocomplete AI button, prompt suggestions, and any
19325
+ // future entry point. The chat is always opened; the message is only sent when
19326
+ // it is non-empty and the chat is not already processing a message.
19327
+ // Returns true when a message was submitted, so callers can clear their input.
19328
+ function openChat(chatRenderState) {
19329
+ var _ref = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {}, message = _ref.message, referer = _ref.referer, turnContext = _ref.turnContext;
19330
+ var _ref1;
19331
+ var _chatRenderState_setOpen;
19332
+ if (!chatRenderState) {
19333
+ return false;
19334
+ }
19335
+ var trimmed = (_ref1 = message === null || message === void 0 ? void 0 : message.trim()) !== null && _ref1 !== void 0 ? _ref1 : '';
19336
+ if (!trimmed) {
19337
+ if (chatRenderState.focusInput) {
19338
+ chatRenderState.focusInput();
19339
+ } else {
19340
+ var _chatRenderState_setOpen1;
19341
+ (_chatRenderState_setOpen1 = chatRenderState.setOpen) === null || _chatRenderState_setOpen1 === void 0 ? void 0 : _chatRenderState_setOpen1.call(chatRenderState, true);
19342
+ }
19343
+ return false;
19344
+ }
19345
+ (_chatRenderState_setOpen = chatRenderState.setOpen) === null || _chatRenderState_setOpen === void 0 ? void 0 : _chatRenderState_setOpen.call(chatRenderState, true);
19346
+ if (isChatBusy(chatRenderState) || !chatRenderState.sendMessage) {
19347
+ return false;
19348
+ }
19349
+ chatRenderState.sendMessage(_object_spread({
19350
+ text: trimmed
19351
+ }, turnContext ? {
19352
+ metadata: {
19353
+ turnContext: turnContext
19354
+ }
19355
+ } : {}), referer ? {
19356
+ headers: {
19357
+ 'x-algolia-referer': referer
19358
+ }
19359
+ } : undefined);
19360
+ return true;
19361
+ }
19362
+ function isChatBusy(chatRenderState) {
19363
+ return (chatRenderState === null || chatRenderState === void 0 ? void 0 : chatRenderState.status) === 'submitted' || (chatRenderState === null || chatRenderState === void 0 ? void 0 : chatRenderState.status) === 'streaming';
19364
+ }
19365
+
19366
+ var SearchIndexToolType = 'algolia_search_index';
19367
+ var RecommendToolType = 'algolia_recommend';
19368
+ var MemorizeToolType = 'algolia_memorize';
19369
+ var MemorySearchToolType = 'algolia_memory_search';
19370
+ var PonderToolType = 'algolia_ponder';
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
+ };
19379
+
19380
+ function flat(arr) {
19381
+ return arr.reduce(function(acc, array) {
19382
+ return acc.concat(array);
19383
+ }, []);
19384
+ }
19385
+
19386
+ /**
19387
+ * Reads a human-readable message from a failed HTTP response body when the
19388
+ * server returns JSON such as `{ "message": "..." }` (the shared
19389
+ * `ErrorResponse` shape used by every status code), falling back to the HTTP
19390
+ * status line when the body is empty or not parseable.
19391
+ */ function getHttpErrorMessage(response) {
19392
+ var fallback = "HTTP error: ".concat(response.status, " ").concat(response.statusText);
19393
+ return response.text().then(function(text) {
19394
+ var _tryParseErrorMessage;
19395
+ return (_tryParseErrorMessage = tryParseErrorMessage(text)) !== null && _tryParseErrorMessage !== void 0 ? _tryParseErrorMessage : fallback;
19396
+ }).catch(function() {
19397
+ return fallback;
19398
+ });
19399
+ }
19400
+ /**
19401
+ * Abstract base class for HTTP-based chat transports.
19402
+ */ var HttpChatTransport = /*#__PURE__*/ function() {
19403
+ function HttpChatTransport(param) {
19404
+ var _param_api = param.api, api = _param_api === void 0 ? '/api/chat' : _param_api, credentials = param.credentials, headers = param.headers, body = param.body, customFetch = param.fetch, prepareSendMessagesRequest = param.prepareSendMessagesRequest, prepareReconnectToStreamRequest = param.prepareReconnectToStreamRequest;
19405
+ _class_call_check(this, HttpChatTransport);
19406
+ _define_property(this, "api", void 0);
19407
+ _define_property(this, "credentials", void 0);
19408
+ _define_property(this, "headers", void 0);
19409
+ _define_property(this, "body", void 0);
19410
+ _define_property(this, "fetch", void 0);
19411
+ _define_property(this, "prepareSendMessagesRequest", void 0);
19412
+ _define_property(this, "prepareReconnectToStreamRequest", void 0);
19413
+ this.api = api;
19414
+ this.credentials = credentials;
19415
+ this.headers = headers;
19416
+ this.body = body;
19417
+ this.fetch = customFetch;
19418
+ this.prepareSendMessagesRequest = prepareSendMessagesRequest;
19419
+ this.prepareReconnectToStreamRequest = prepareReconnectToStreamRequest;
19420
+ }
19421
+ _create_class(HttpChatTransport, [
19422
+ {
19423
+ key: "sendMessages",
19424
+ value: function sendMessages(param) {
19425
+ var _this = this;
19426
+ var abortSignal = param.abortSignal, chatId = param.chatId, messages = param.messages, requestMetadata = param.requestMetadata, trigger = param.trigger, messageId = param.messageId, requestHeaders = param.headers, requestBody = param.body;
19427
+ var _this_fetch;
19428
+ var fetchFn = (_this_fetch = this.fetch) !== null && _this_fetch !== void 0 ? _this_fetch : fetch;
19429
+ // Resolve configurable values
19430
+ return Promise.all([
19431
+ resolveValue(this.credentials),
19432
+ resolveValue(this.headers),
19433
+ resolveValue(this.body)
19434
+ ]).then(function(param) {
19435
+ var _param = _sliced_to_array(param, 3), resolvedCredentials = _param[0], resolvedHeaders = _param[1], resolvedBody = _param[2];
19436
+ // Build default request options
19437
+ var api = _this.api;
19438
+ var body = _object_spread({
19439
+ id: chatId,
19440
+ messages: messages
19441
+ }, resolvedBody, requestBody);
19442
+ var headers = _object_spread({
19443
+ 'Content-Type': 'application/json'
19444
+ }, _instanceof(resolvedHeaders, Headers) ? Object.fromEntries(resolvedHeaders.entries()) : resolvedHeaders, _instanceof(requestHeaders, Headers) ? Object.fromEntries(requestHeaders.entries()) : requestHeaders);
19445
+ var credentials = resolvedCredentials;
19446
+ // Apply custom preparation if provided
19447
+ var prepareRequestBody = _object_spread({}, resolvedBody, requestBody);
19448
+ var preparePromise = _this.prepareSendMessagesRequest ? Promise.resolve(_this.prepareSendMessagesRequest({
19449
+ id: chatId,
19450
+ messages: messages,
19451
+ requestMetadata: requestMetadata,
19452
+ body: prepareRequestBody,
19453
+ credentials: resolvedCredentials,
19454
+ headers: resolvedHeaders,
19455
+ api: _this.api,
19456
+ trigger: trigger,
19457
+ messageId: messageId
19458
+ })) : Promise.resolve(null);
19459
+ return preparePromise.then(function(prepared) {
19460
+ if (prepared) {
19461
+ body = prepared.body;
19462
+ if (prepared.api) api = prepared.api;
19463
+ if (prepared.headers) {
19464
+ headers = _object_spread({
19465
+ 'Content-Type': 'application/json'
19466
+ }, _instanceof(prepared.headers, Headers) ? Object.fromEntries(prepared.headers.entries()) : prepared.headers);
19467
+ }
19468
+ if (prepared.credentials) credentials = prepared.credentials;
19469
+ }
19470
+ return fetchFn(api, {
19471
+ method: 'POST',
19472
+ headers: headers,
19473
+ body: JSON.stringify(body),
19474
+ signal: abortSignal,
19475
+ credentials: credentials
19476
+ }).then(function(response) {
19477
+ if (!response.ok) {
19478
+ return getHttpErrorMessage(response).then(function(message) {
19479
+ throw new Error(message);
19480
+ });
19481
+ }
19482
+ if (!response.body) {
19483
+ throw new Error('Response body is empty');
19484
+ }
19485
+ return _this.processResponseStream(response.body);
19486
+ });
19487
+ });
19488
+ });
19489
+ }
19143
19490
  },
19144
19491
  {
19145
- key: "messages",
19146
- get: function get() {
19147
- return this._messages;
19148
- },
19149
- set: function set(newMessages) {
19150
- this._messages = _to_consumable_array(newMessages);
19151
- this._callMessagesCallbacks();
19492
+ key: "reconnectToStream",
19493
+ value: function reconnectToStream(param) {
19494
+ var _this = this;
19495
+ var chatId = param.chatId, requestHeaders = param.headers, requestBody = param.body;
19496
+ var _this_fetch;
19497
+ var fetchFn = (_this_fetch = this.fetch) !== null && _this_fetch !== void 0 ? _this_fetch : fetch;
19498
+ // Resolve configurable values
19499
+ return Promise.all([
19500
+ resolveValue(this.credentials),
19501
+ resolveValue(this.headers),
19502
+ resolveValue(this.body)
19503
+ ]).then(function(param) {
19504
+ var _param = _sliced_to_array(param, 3), resolvedCredentials = _param[0], resolvedHeaders = _param[1], resolvedBody = _param[2];
19505
+ // Build default request options
19506
+ var api = _this.api;
19507
+ var headers = _object_spread({}, _instanceof(resolvedHeaders, Headers) ? Object.fromEntries(resolvedHeaders.entries()) : resolvedHeaders, _instanceof(requestHeaders, Headers) ? Object.fromEntries(requestHeaders.entries()) : requestHeaders);
19508
+ var credentials = resolvedCredentials;
19509
+ // Apply custom preparation if provided
19510
+ var prepareRequestBody = _object_spread({}, resolvedBody, requestBody);
19511
+ var preparePromise = _this.prepareReconnectToStreamRequest ? Promise.resolve(_this.prepareReconnectToStreamRequest({
19512
+ id: chatId,
19513
+ requestMetadata: undefined,
19514
+ body: prepareRequestBody,
19515
+ credentials: resolvedCredentials,
19516
+ headers: resolvedHeaders,
19517
+ api: _this.api
19518
+ })) : Promise.resolve(null);
19519
+ return preparePromise.then(function(prepared) {
19520
+ if (prepared) {
19521
+ if (prepared.api) api = prepared.api;
19522
+ if (prepared.headers) {
19523
+ headers = _instanceof(prepared.headers, Headers) ? Object.fromEntries(prepared.headers.entries()) : prepared.headers;
19524
+ }
19525
+ if (prepared.credentials) credentials = prepared.credentials;
19526
+ }
19527
+ // GET request for reconnection
19528
+ return fetchFn("".concat(api, "?chatId=").concat(chatId), {
19529
+ method: 'GET',
19530
+ headers: headers,
19531
+ credentials: credentials
19532
+ }).then(function(response) {
19533
+ if (!response.ok) {
19534
+ // 404 means no stream to reconnect to, which is not an error
19535
+ if (response.status === 404) {
19536
+ return null;
19537
+ }
19538
+ return getHttpErrorMessage(response).then(function(message) {
19539
+ throw new Error(message);
19540
+ });
19541
+ }
19542
+ if (!response.body) {
19543
+ return null;
19544
+ }
19545
+ return _this.processResponseStream(response.body);
19546
+ });
19547
+ });
19548
+ });
19152
19549
  }
19153
19550
  }
19154
19551
  ]);
19155
- return ChatState;
19552
+ return HttpChatTransport;
19156
19553
  }();
19157
- _computedKey3 = '~registerMessagesCallback', _computedKey4 = '~registerStatusCallback', _computedKey5 = '~registerErrorCallback';
19158
- var _computedKey9 = _computedKey3, _computedKey10 = _computedKey4, _computedKey11 = _computedKey5;
19159
- var Chat$1 = /*#__PURE__*/ function(AbstractChat) {
19160
- _inherits(Chat, AbstractChat);
19161
- function Chat(_0) {
19162
- _class_call_check(this, Chat);
19163
- var _this;
19164
- var messages = _0.messages, agentId = _0.agentId, _0_persistence = _0.persistence, persistence = _0_persistence === void 0 ? true : _0_persistence, init = _object_without_properties(_0, [
19165
- "messages",
19166
- "agentId",
19167
- "persistence"
19554
+ /**
19555
+ * Default chat transport implementation using NDJSON streaming.
19556
+ */ var DefaultChatTransport = /*#__PURE__*/ function(HttpChatTransport) {
19557
+ _inherits(DefaultChatTransport, HttpChatTransport);
19558
+ function DefaultChatTransport() {
19559
+ var options = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
19560
+ _class_call_check(this, DefaultChatTransport);
19561
+ return _call_super(this, DefaultChatTransport, [
19562
+ options
19168
19563
  ]);
19169
- var state = new ChatState(agentId, messages, persistence);
19170
- _this = _call_super(this, Chat, [
19171
- _object_spread_props(_object_spread({}, init), {
19172
- state: state
19173
- })
19174
- ]), _define_property(_this, "_state", void 0), _define_property(_this, _computedKey9, function(onChange) {
19175
- return _this._state['~registerMessagesCallback'](onChange);
19176
- }), _define_property(_this, _computedKey10, function(onChange) {
19177
- return _this._state['~registerStatusCallback'](onChange);
19178
- }), _define_property(_this, _computedKey11, function(onChange) {
19179
- return _this._state['~registerErrorCallback'](onChange);
19180
- });
19181
- _this._state = state;
19182
- return _this;
19183
19564
  }
19184
- return Chat;
19185
- }(AbstractChat);
19565
+ _create_class(DefaultChatTransport, [
19566
+ {
19567
+ key: "processResponseStream",
19568
+ value: function processResponseStream(stream) {
19569
+ return parseJsonEventStream(stream);
19570
+ }
19571
+ }
19572
+ ]);
19573
+ return DefaultChatTransport;
19574
+ }(HttpChatTransport);
19186
19575
 
19187
19576
  var withUsage$q = createDocumentationMessageGenerator({
19188
19577
  name: 'chat',
@@ -19246,6 +19635,11 @@
19246
19635
  return refinement.attribute;
19247
19636
  }));
19248
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+)?)$/;
19249
19643
  function updateStateFromSearchToolInput(params, helper) {
19250
19644
  // clear all filters first
19251
19645
  var attributesToClear = getAttributesToClear$1({
@@ -19289,6 +19683,16 @@
19289
19683
  helper.toggleFacetRefinement(name, value);
19290
19684
  });
19291
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
+ }
19292
19696
  if (params.query) {
19293
19697
  helper.setQuery(params.query);
19294
19698
  }
@@ -19299,7 +19703,7 @@
19299
19703
  var unmountFn = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : noop;
19300
19704
  checkRendering(renderFn, withUsage$q());
19301
19705
  return function(widgetParams) {
19302
- 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, [
19303
19707
  "resume",
19304
19708
  "tools",
19305
19709
  "type",
@@ -19312,6 +19716,12 @@
19312
19716
  "requiresSearch"
19313
19717
  ]);
19314
19718
  var normalizedPersistence = normalizePersistence(persistence, 'chat' in options);
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_;
19315
19725
  var _chatInstance;
19316
19726
  var input = '';
19317
19727
  var open = false;
@@ -19593,7 +20003,8 @@
19593
20003
  // `open` is read by sibling widgets (e.g. `chatTrigger`) via the
19594
20004
  // shared `renderState`. Schedule a full re-render so they pick up
19595
20005
  // the new value instead of staying frozen on their initial state.
19596
- initOptions.instantSearchInstance.scheduleRender();
20006
+ // No search runs here, so it must not settle the main search.
20007
+ initOptions.instantSearchInstance.scheduleRender(false);
19597
20008
  };
19598
20009
  setOpen = function setOpen(nextOpen) {
19599
20010
  updateOpen(nextOpen, nextOpen && !open);
@@ -19646,14 +20057,15 @@
19646
20057
  // disable themselves, so a transition has to escape this widget's own
19647
20058
  // render. Message deltas deliberately don't: they stay local to keep
19648
20059
  // streaming cheap. The `status` setter notifies on every write, hence
19649
- // the comparison.
20060
+ // the comparison. A chat turn is not a search, so the render it
20061
+ // schedules must not settle the main search.
19650
20062
  var lastStatus = _chatInstance.status;
19651
20063
  var renderOnStatusChange = function renderOnStatusChange() {
19652
20064
  var statusChanged = _chatInstance.status !== lastStatus;
19653
20065
  lastStatus = _chatInstance.status;
19654
20066
  render();
19655
20067
  if (statusChanged) {
19656
- initOptions.instantSearchInstance.scheduleRender();
20068
+ initOptions.instantSearchInstance.scheduleRender(false);
19657
20069
  }
19658
20070
  };
19659
20071
  safelyRunOnBrowser(function() {
@@ -19683,8 +20095,10 @@
19683
20095
  renderFn(_object_spread_props(_object_spread({}, this.getWidgetRenderState(initOptions)), {
19684
20096
  instantSearchInstance: instantSearchInstance
19685
20097
  }), true);
20098
+ // A restored open panel is new to the sibling entry points, but it is
20099
+ // not a search result.
19686
20100
  if (open) {
19687
- instantSearchInstance.scheduleRender();
20101
+ instantSearchInstance.scheduleRender(false);
19688
20102
  }
19689
20103
  },
19690
20104
  render: function render(renderOptions) {
@@ -19851,7 +20265,11 @@
19851
20265
 
19852
20266
  function useChat(props, additionalWidgetProperties) {
19853
20267
  var isHydrated = useIsHydrated();
20268
+ React.useRef(props);
20269
+ React.useRef(null);
20270
+ useIsomorphicLayoutEffect(function() {});
19854
20271
  var chatState = useConnector(connectChat, props, additionalWidgetProperties);
20272
+ useIsomorphicLayoutEffect(function() {});
19855
20273
  if (isHydrated) {
19856
20274
  return chatState;
19857
20275
  }
@@ -19905,9 +20323,6 @@
19905
20323
  function withStreamParam(url) {
19906
20324
  return url.includes('?') ? "".concat(url, "&stream=true") : "".concat(url, "?stream=true");
19907
20325
  }
19908
- function resolveStreamedOutput(data, previous) {
19909
- return typeof data === 'string' ? parsePartialJson(data, previous) : data;
19910
- }
19911
20326
  function createTaskPreparationContext(context) {
19912
20327
  function hideProperty(key) {
19913
20328
  var value = context[key];
@@ -19942,27 +20357,56 @@
19942
20357
  }
19943
20358
  return undefined;
19944
20359
  }
19945
- function consumeTaskStream(body, onData) {
20360
+ function consumeTaskTextStream(body, onData) {
19946
20361
  return new Promise(function(resolve, reject) {
19947
- var chunkStream = parseJsonEventStream(body);
20362
+ var decoder = new TextDecoder();
20363
+ var reader = body.getReader();
20364
+ var accumulatedText = '';
19948
20365
  var latest;
19949
- processStream(chunkStream, function(chunk) {
19950
- if (!chunk) {
19951
- return;
19952
- }
19953
- if (chunk.type === 'error') {
19954
- throw new Error(chunk.errorText || 'Task stream error');
19955
- }
19956
- if (chunk.type !== 'data-task-output') {
19957
- return;
19958
- }
19959
- latest = resolveStreamedOutput(chunk.data, latest);
19960
- if (onData) {
19961
- onData(latest);
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
+ });
19962
20372
  }
19963
- }, function() {
19964
- return resolve(latest);
19965
- }, reject);
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();
19966
20410
  });
19967
20411
  }
19968
20412
  /** Default HTTP transport for named Tasks requests and task-output streams. */ var DefaultTaskTransport = /*#__PURE__*/ function() {
@@ -19986,9 +20430,10 @@
19986
20430
  {
19987
20431
  key: "sendTask",
19988
20432
  value: function sendTask(param) {
19989
- var task = param.task, input = param.input, stream = param.stream, onData = param.onData;
20433
+ var task = param.task, kind = param.kind, input = param.input, stream = param.stream, onData = param.onData;
19990
20434
  return this.sendTaskRequest({
19991
20435
  task: task,
20436
+ kind: kind,
19992
20437
  input: input,
19993
20438
  stream: stream,
19994
20439
  onData: onData ? function(data) {
@@ -20001,7 +20446,7 @@
20001
20446
  /** @internal */ key: "sendTaskRequest",
20002
20447
  value: function sendTaskRequest(param) {
20003
20448
  var _this = this;
20004
- var task = param.task, input = param.input, stream = param.stream, onData = param.onData;
20449
+ var task = param.task, kind = param.kind, input = param.input, stream = param.stream, onData = param.onData;
20005
20450
  var _this_fetch;
20006
20451
  var fetchFn = (_this_fetch = this.fetch) !== null && _this_fetch !== void 0 ? _this_fetch : fetch;
20007
20452
  return Promise.all([
@@ -20013,13 +20458,17 @@
20013
20458
  var api = _this.api;
20014
20459
  var credentials = resolvedCredentials;
20015
20460
  var headers = withJsonContentType(resolvedHeaders);
20016
- var body = _object_spread({
20017
- task: task,
20461
+ var body = _object_spread(_object_spread_props(_object_spread({}, task === undefined ? {} : {
20462
+ task: task
20463
+ }, kind === undefined ? {} : {
20464
+ kind: kind
20465
+ }), {
20018
20466
  input: input
20019
- }, resolvedBody);
20467
+ }), resolvedBody);
20020
20468
  var preparedBody = resolvedBody ? _object_spread({}, resolvedBody) : undefined;
20021
20469
  var preparePromise = _this.prepareSendMessagesRequest ? Promise.resolve(_this.prepareSendMessagesRequest(createTaskPreparationContext({
20022
20470
  task: task,
20471
+ kind: kind,
20023
20472
  input: input,
20024
20473
  stream: stream,
20025
20474
  body: preparedBody,
@@ -20054,8 +20503,11 @@
20054
20503
  throw new Error("HTTP error ".concat(response.status));
20055
20504
  }
20056
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')) || '';
20057
- if (stream && response.body && contentType.includes('text/event-stream')) {
20058
- return consumeTaskStream(response.body, onData);
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);
20059
20511
  }
20060
20512
  return response.json();
20061
20513
  });
@@ -20138,7 +20590,7 @@
20138
20590
  }
20139
20591
 
20140
20592
  function createTaskRunner(options) {
20141
- var task = options.task, _options_stream = options.stream, stream = _options_stream === void 0 ? true : _options_stream;
20593
+ var task = options.task, kind = options.kind, _options_stream = options.stream, stream = _options_stream === void 0 ? true : _options_stream;
20142
20594
  var transport;
20143
20595
  if (options.transport !== undefined) {
20144
20596
  transport = options.transport;
@@ -20149,11 +20601,14 @@
20149
20601
  headers: options.headers,
20150
20602
  fetch: options.fetch,
20151
20603
  prepareSendMessagesRequest: prepareRequest ? function(param) {
20152
- var requestTask = param.task, input = param.input;
20153
- return prepareRequest({
20154
- task: requestTask,
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
+ }), {
20155
20610
  input: input
20156
- });
20611
+ }));
20157
20612
  } : undefined
20158
20613
  });
20159
20614
  }
@@ -20162,6 +20617,7 @@
20162
20617
  var onData = (arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {}).onData;
20163
20618
  return transport.sendTask({
20164
20619
  task: task,
20620
+ kind: kind,
20165
20621
  input: input,
20166
20622
  stream: stream,
20167
20623
  onData: onData
@@ -20178,12 +20634,12 @@
20178
20634
  var unmountFn = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : noop;
20179
20635
  checkRendering(renderFn, withUsage$p());
20180
20636
  return function(widgetParams) {
20181
- 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;
20182
20638
  if (!agentId && !transport) {
20183
20639
  throw new Error(withUsage$p('The `agentId` option is required unless a custom `transport` is provided.'));
20184
20640
  }
20185
- if (!task) {
20186
- 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.'));
20187
20643
  }
20188
20644
  var runner;
20189
20645
  var output;
@@ -20235,6 +20691,8 @@
20235
20691
  // Bump the request id so any in-flight request's callbacks see
20236
20692
  // `isStale()` and are ignored. The fetch itself is left to complete.
20237
20693
  requestId += 1;
20694
+ output = undefined;
20695
+ error = undefined;
20238
20696
  isLoading = false;
20239
20697
  triggerRender();
20240
20698
  };
@@ -20267,6 +20725,7 @@
20267
20725
  runner = createTaskRunner({
20268
20726
  transport: taskTransport,
20269
20727
  task: task,
20728
+ kind: kind,
20270
20729
  stream: stream
20271
20730
  });
20272
20731
  } else {
@@ -20275,6 +20734,7 @@
20275
20734
  transport: transport
20276
20735
  }),
20277
20736
  task: task,
20737
+ kind: kind,
20278
20738
  stream: stream
20279
20739
  });
20280
20740
  }
@@ -20300,55 +20760,13 @@
20300
20760
  };
20301
20761
  };
20302
20762
 
20303
- // Centralizes the "open the chat from an entry point" behavior shared by the
20304
- // SearchBox AI button, the Autocomplete AI button, prompt suggestions, and any
20305
- // future entry point. The chat is always opened; the message is only sent when
20306
- // it is non-empty and the chat is not already processing a message.
20307
- // Returns true when a message was submitted, so callers can clear their input.
20308
- function openChat(chatRenderState) {
20309
- var _ref = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {}, message = _ref.message, referer = _ref.referer, turnContext = _ref.turnContext;
20310
- var _ref1;
20311
- var _chatRenderState_setOpen;
20312
- if (!chatRenderState) {
20313
- return false;
20314
- }
20315
- var trimmed = (_ref1 = message === null || message === void 0 ? void 0 : message.trim()) !== null && _ref1 !== void 0 ? _ref1 : '';
20316
- if (!trimmed) {
20317
- if (chatRenderState.focusInput) {
20318
- chatRenderState.focusInput();
20319
- } else {
20320
- var _chatRenderState_setOpen1;
20321
- (_chatRenderState_setOpen1 = chatRenderState.setOpen) === null || _chatRenderState_setOpen1 === void 0 ? void 0 : _chatRenderState_setOpen1.call(chatRenderState, true);
20322
- }
20323
- return false;
20324
- }
20325
- (_chatRenderState_setOpen = chatRenderState.setOpen) === null || _chatRenderState_setOpen === void 0 ? void 0 : _chatRenderState_setOpen.call(chatRenderState, true);
20326
- if (isChatBusy(chatRenderState) || !chatRenderState.sendMessage) {
20327
- return false;
20328
- }
20329
- chatRenderState.sendMessage(_object_spread({
20330
- text: trimmed
20331
- }, turnContext ? {
20332
- metadata: {
20333
- turnContext: turnContext
20334
- }
20335
- } : {}), referer ? {
20336
- headers: {
20337
- 'x-algolia-referer': referer
20338
- }
20339
- } : undefined);
20340
- return true;
20341
- }
20342
- function isChatBusy(chatRenderState) {
20343
- return (chatRenderState === null || chatRenderState === void 0 ? void 0 : chatRenderState.status) === 'submitted' || (chatRenderState === null || chatRenderState === void 0 ? void 0 : chatRenderState.status) === 'streaming';
20344
- }
20345
-
20346
20763
  var withUsage$o = createDocumentationMessageGenerator({
20347
20764
  name: 'prompt-suggestions',
20348
20765
  connector: true
20349
20766
  });
20350
20767
  var RENDER_STATE_KEY = 'promptSuggestions';
20351
20768
  var CHAT_RENDER_STATE_KEY = 'chat';
20769
+ var PROMPT_SUGGESTIONS_TASK_KIND = 'prompt_suggestions';
20352
20770
  var DEBOUNCE_MS = 300;
20353
20771
  function parseSuggestions(data) {
20354
20772
  var suggestions = data === null || data === void 0 ? void 0 : data.suggestions;
@@ -20420,12 +20838,10 @@
20420
20838
  if (!agentId && !transport) {
20421
20839
  throw new Error(withUsage$o('The `agentId` option is required unless a custom `transport` is provided.'));
20422
20840
  }
20423
- if (!configurationId) {
20424
- throw new Error(withUsage$o('The `configurationId` option is required.'));
20425
- }
20426
20841
  var tasksState;
20427
20842
  var suggestions = [];
20428
20843
  var isLoading = false;
20844
+ var error;
20429
20845
  var debounceTimer;
20430
20846
  var lastStateSignature = null;
20431
20847
  var latestRenderOptions = null;
@@ -20558,6 +20974,7 @@
20558
20974
  return {
20559
20975
  suggestions: transformed,
20560
20976
  isLoading: isLoading,
20977
+ error: error,
20561
20978
  onSuggestionClick: send,
20562
20979
  sendToChat: send,
20563
20980
  refresh: refresh,
@@ -20570,10 +20987,10 @@
20570
20987
  var handleInnerRender = function handleInnerRender(renderState) {
20571
20988
  tasksState = renderState;
20572
20989
  if (refetchPending) return;
20990
+ error = renderState.error;
20573
20991
  if (renderState.error) {
20574
20992
  // A failed task (including a mid-stream `error` event) must not leave
20575
- // any streamed partial visible. There's no error UI for now, so fall
20576
- // back to a blank suggestions state.
20993
+ // any streamed partial visible.
20577
20994
  suggestions = [];
20578
20995
  } else if (renderState.isLoading || renderState.output !== undefined) {
20579
20996
  // Only adopt the inner output once a request is loading or has
@@ -20590,12 +21007,14 @@
20590
21007
  agentId: agentId,
20591
21008
  transport: transport,
20592
21009
  task: configurationId,
21010
+ kind: PROMPT_SUGGESTIONS_TASK_KIND,
20593
21011
  stream: true
20594
21012
  };
20595
21013
  } else if (transport) {
20596
21014
  tasksParams = {
20597
21015
  transport: transport,
20598
21016
  task: configurationId,
21017
+ kind: PROMPT_SUGGESTIONS_TASK_KIND,
20599
21018
  stream: true
20600
21019
  };
20601
21020
  } else {
@@ -20624,6 +21043,7 @@
20624
21043
  if (stateSignature !== lastStateSignature) {
20625
21044
  lastStateSignature = stateSignature;
20626
21045
  refetchPending = true;
21046
+ error = undefined;
20627
21047
  clearTimeout(debounceTimer);
20628
21048
  debounceTimer = setTimeout(function() {
20629
21049
  if (latestRenderOptions === null || latestRenderOptions === void 0 ? void 0 : latestRenderOptions.results) {
@@ -24868,13 +25288,6 @@
24868
25288
  });
24869
25289
  }
24870
25290
 
24871
- var SearchIndexToolType = 'algolia_search_index';
24872
- var RecommendToolType = 'algolia_recommend';
24873
- var MemorizeToolType = 'algolia_memorize';
24874
- var MemorySearchToolType = 'algolia_memory_search';
24875
- var PonderToolType = 'algolia_ponder';
24876
- var DisplayResultsToolType = 'algolia_display_results';
24877
-
24878
25291
  var AutocompleteSearchComponent = createAutocompleteSearchComponent({
24879
25292
  createElement: React.createElement,
24880
25293
  Fragment: React.Fragment
@@ -26590,7 +27003,7 @@
26590
27003
  transformItems: transformItems
26591
27004
  }), {
26592
27005
  $$widgetType: 'ais.promptSuggestions'
26593
- }), 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;
26594
27007
  var handleClick = onSuggestionClickOverride ? function(prompt) {
26595
27008
  return onSuggestionClickOverride(prompt, {
26596
27009
  sendToChat: sendToChat
@@ -26600,6 +27013,7 @@
26600
27013
  return /*#__PURE__*/ React.createElement(LayoutComponent, {
26601
27014
  suggestions: suggestions,
26602
27015
  isLoading: isLoading,
27016
+ error: error,
26603
27017
  onSuggestionClick: handleClick,
26604
27018
  isChatBusy: isChatBusy
26605
27019
  });