react-instantsearch-core 7.40.0 → 7.42.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 Core 7.40.0 | © Algolia, Inc. and contributors; MIT License | https://github.com/algolia/instantsearch */
1
+ /*! React InstantSearch Core 7.42.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.40.0';
27
+ var version$2 = '7.42.0';
28
28
 
29
29
  function _define_property(obj, key, value) {
30
30
  if (key in obj) {
@@ -3919,7 +3919,7 @@
3919
3919
  function requireVersion() {
3920
3920
  if (hasRequiredVersion) return version$1;
3921
3921
  hasRequiredVersion = 1;
3922
- version$1 = '3.29.2';
3922
+ version$1 = '3.29.3';
3923
3923
  return version$1;
3924
3924
  }
3925
3925
 
@@ -5980,7 +5980,7 @@
5980
5980
  }
5981
5981
  }
5982
5982
 
5983
- var withUsage$v = createDocumentationMessageGenerator({
5983
+ var withUsage$x = createDocumentationMessageGenerator({
5984
5984
  name: 'configure',
5985
5985
  connector: true
5986
5986
  });
@@ -5996,7 +5996,7 @@
5996
5996
  var renderFn = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : noop, unmountFn = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : noop;
5997
5997
  return function(widgetParams) {
5998
5998
  if (!widgetParams || !isPlainObject(widgetParams.searchParameters)) {
5999
- throw new Error(withUsage$v('The `searchParameters` option expects an object.'));
5999
+ throw new Error(withUsage$x('The `searchParameters` option expects an object.'));
6000
6000
  }
6001
6001
  var connectorState = {};
6002
6002
  function refine(helper) {
@@ -6280,6 +6280,38 @@
6280
6280
  return stableValue;
6281
6281
  }
6282
6282
 
6283
+ /**
6284
+ * Forwards the insights-related search parameters to every Recommend query.
6285
+ *
6286
+ * The insights middleware writes `userToken` and `clickAnalytics` on the main
6287
+ * helper's search state, which only feeds search queries: Recommend queries are
6288
+ * built from their own parameters and never read the search state. Without this,
6289
+ * recommendations can't be personalized, and their responses carry no `queryID`
6290
+ * for the connectors to attribute click and conversion events with.
6291
+ *
6292
+ * Parameters set on a widget win, so an explicit `queryParameters.userToken`
6293
+ * keeps overriding the middleware.
6294
+ */ function addInsightsToRecommendParameters(recommendParameters, param) {
6295
+ var userToken = param.userToken, clickAnalytics = param.clickAnalytics;
6296
+ if (userToken === undefined && clickAnalytics === undefined) {
6297
+ return recommendParameters;
6298
+ }
6299
+ return new algoliasearchHelper.RecommendParameters({
6300
+ params: recommendParameters.params.map(function(params) {
6301
+ // v4 `TrendingFacetsQuery` doesn't include `queryParameters`, but the v5
6302
+ // API and the helper support them, like `connectTrendingFacets` does.
6303
+ var queryParameters = params.queryParameters;
6304
+ return _object_spread_props(_object_spread({}, params), {
6305
+ queryParameters: _object_spread({}, clickAnalytics === undefined ? {} : {
6306
+ clickAnalytics: clickAnalytics
6307
+ }, userToken === undefined ? {} : {
6308
+ userToken: userToken
6309
+ }, queryParameters)
6310
+ });
6311
+ })
6312
+ });
6313
+ }
6314
+
6283
6315
  var id = 0;
6284
6316
  function addWidgetId(widget) {
6285
6317
  if (widget.dependsOn !== 'recommend') {
@@ -7788,13 +7820,13 @@
7788
7820
  return null;
7789
7821
  }
7790
7822
 
7791
- var withUsage$u = createDocumentationMessageGenerator({
7823
+ var withUsage$w = createDocumentationMessageGenerator({
7792
7824
  name: 'dynamic-widgets',
7793
7825
  connector: true
7794
7826
  });
7795
7827
  var connectDynamicWidgets = function connectDynamicWidgets(renderFn) {
7796
7828
  var unmountFn = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : noop;
7797
- checkRendering(renderFn, withUsage$u());
7829
+ checkRendering(renderFn, withUsage$w());
7798
7830
  return function(widgetParams) {
7799
7831
  var widgets = widgetParams.widgets, _widgetParams_maxValuesPerFacet = widgetParams.maxValuesPerFacet, maxValuesPerFacet = _widgetParams_maxValuesPerFacet === void 0 ? 20 : _widgetParams_maxValuesPerFacet, _widgetParams_facets = widgetParams.facets, facets = _widgetParams_facets === void 0 ? [
7800
7832
  '*'
@@ -7804,10 +7836,10 @@
7804
7836
  if (!(widgets && Array.isArray(widgets) && widgets.every(function(widget) {
7805
7837
  return (typeof widget === "undefined" ? "undefined" : _type_of(widget)) === 'object';
7806
7838
  }))) {
7807
- throw new Error(withUsage$u('The `widgets` option expects an array of widgets.'));
7839
+ throw new Error(withUsage$w('The `widgets` option expects an array of widgets.'));
7808
7840
  }
7809
7841
  if (!Array.isArray(facets)) {
7810
- throw new Error(withUsage$u("The `facets` option only accepts an array of facets, you passed ".concat(JSON.stringify(facets))));
7842
+ throw new Error(withUsage$w("The `facets` option only accepts an array of facets, you passed ".concat(JSON.stringify(facets))));
7811
7843
  }
7812
7844
  var localWidgets = new Map();
7813
7845
  return {
@@ -7909,7 +7941,7 @@
7909
7941
  results: results
7910
7942
  });
7911
7943
  if (!Array.isArray(attributesToRender)) {
7912
- throw new Error(withUsage$u('The `transformItems` option expects a function that returns an Array.'));
7944
+ throw new Error(withUsage$w('The `transformItems` option expects a function that returns an Array.'));
7913
7945
  }
7914
7946
  return {
7915
7947
  attributesToRender: attributesToRender,
@@ -8231,19 +8263,19 @@
8231
8263
  return toFeedSearchResults(lastResults._state, raw);
8232
8264
  });
8233
8265
  }
8234
- var withUsage$t = createDocumentationMessageGenerator({
8266
+ var withUsage$v = createDocumentationMessageGenerator({
8235
8267
  name: 'feeds',
8236
8268
  connector: true
8237
8269
  });
8238
8270
  var connectFeeds = function connectFeeds(renderFn) {
8239
8271
  var unmountFn = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : noop;
8240
- checkRendering(renderFn, withUsage$t());
8272
+ checkRendering(renderFn, withUsage$v());
8241
8273
  return function(widgetParams) {
8242
8274
  var isolated = widgetParams.isolated, _widgetParams_transformFeeds = widgetParams.transformFeeds, transformFeeds = _widgetParams_transformFeeds === void 0 ? function(feeds) {
8243
8275
  return feeds;
8244
8276
  } : _widgetParams_transformFeeds;
8245
8277
  if (isolated !== false) {
8246
- throw new Error(withUsage$t('The `isolated` option currently only supports `false`.'));
8278
+ throw new Error(withUsage$v('The `isolated` option currently only supports `false`.'));
8247
8279
  }
8248
8280
  return {
8249
8281
  $$type: 'ais.feeds',
@@ -8251,7 +8283,7 @@
8251
8283
  init: function init(initOptions) {
8252
8284
  var instantSearchInstance = initOptions.instantSearchInstance;
8253
8285
  if (!instantSearchInstance.compositionID) {
8254
- throw new Error(withUsage$t('The `feeds` widget requires a composition-based InstantSearch instance (compositionID must be set).'));
8286
+ throw new Error(withUsage$v('The `feeds` widget requires a composition-based InstantSearch instance (compositionID must be set).'));
8255
8287
  }
8256
8288
  hydrateFeedsFromInitialResultsIfNeeded(instantSearchInstance, initOptions.parent);
8257
8289
  renderFn(_object_spread_props(_object_spread({}, this.getWidgetRenderState(initOptions)), {
@@ -8297,12 +8329,12 @@
8297
8329
  ];
8298
8330
  feedIDs = transformFeeds(feedIDs);
8299
8331
  if (!Array.isArray(feedIDs)) {
8300
- throw new Error(withUsage$t('The `transformFeeds` option expects a function that returns an Array.'));
8332
+ throw new Error(withUsage$v('The `transformFeeds` option expects a function that returns an Array.'));
8301
8333
  }
8302
8334
  if (!feedIDs.every(function(feedID) {
8303
8335
  return typeof feedID === 'string';
8304
8336
  })) {
8305
- throw new Error(withUsage$t('The `transformFeeds` option expects a function that returns an array of feed IDs (strings).'));
8337
+ throw new Error(withUsage$v('The `transformFeeds` option expects a function that returns an array of feed IDs (strings).'));
8306
8338
  }
8307
8339
  return {
8308
8340
  feedIDs: feedIDs,
@@ -8413,7 +8445,7 @@
8413
8445
  }));
8414
8446
  }
8415
8447
 
8416
- var withUsage$s = createDocumentationMessageGenerator({
8448
+ var withUsage$u = createDocumentationMessageGenerator({
8417
8449
  name: 'index-widget'
8418
8450
  });
8419
8451
  /**
@@ -8539,12 +8571,13 @@
8539
8571
  instantSearchInstance._hasRecommendWidget = hasRecommendWidget;
8540
8572
  }
8541
8573
  var index = function index(widgetParams) {
8542
- if (widgetParams === undefined || widgetParams.indexName === undefined && !widgetParams.EXPERIMENTAL_isolated) {
8543
- throw new Error(withUsage$s('The `indexName` option is required.'));
8574
+ var _widgetParams_EXPERIMENTAL_isolated;
8575
+ if (widgetParams === undefined || widgetParams.indexName === undefined && !widgetParams.isolated && !widgetParams.EXPERIMENTAL_isolated) {
8576
+ throw new Error(withUsage$u('The `indexName` option is required.'));
8544
8577
  }
8545
8578
  // When isolated=true, we use an empty string as the default indexName.
8546
8579
  // This is intentional: isolated indices do not require a real index name.
8547
- var _widgetParams_indexName = widgetParams.indexName, indexName = _widgetParams_indexName === void 0 ? '' : _widgetParams_indexName, _widgetParams_indexId = widgetParams.indexId, indexId = _widgetParams_indexId === void 0 ? indexName : _widgetParams_indexId, tmp = widgetParams.EXPERIMENTAL_isolated, isolated = tmp === void 0 ? false : tmp;
8580
+ var _widgetParams_indexName = widgetParams.indexName, indexName = _widgetParams_indexName === void 0 ? '' : _widgetParams_indexName, _widgetParams_indexId = widgetParams.indexId, indexId = _widgetParams_indexId === void 0 ? indexName : _widgetParams_indexId, _widgetParams_isolated = widgetParams.isolated, isolated = _widgetParams_isolated === void 0 ? (_widgetParams_EXPERIMENTAL_isolated = widgetParams.EXPERIMENTAL_isolated) !== null && _widgetParams_EXPERIMENTAL_isolated !== void 0 ? _widgetParams_EXPERIMENTAL_isolated : false : _widgetParams_isolated;
8548
8581
  var localWidgets = [];
8549
8582
  var localUiState = {};
8550
8583
  var localInstantSearchInstance = null;
@@ -8633,7 +8666,7 @@
8633
8666
  addWidgets: function addWidgets(widgets) {
8634
8667
  var _this = this;
8635
8668
  if (!Array.isArray(widgets)) {
8636
- throw new Error(withUsage$s('The `addWidgets` method expects an array of widgets.'));
8669
+ throw new Error(withUsage$u('The `addWidgets` method expects an array of widgets.'));
8637
8670
  }
8638
8671
  var flatWidgets = widgets.reduce(function(acc, w) {
8639
8672
  return acc.concat(Array.isArray(w) ? w : [
@@ -8643,7 +8676,7 @@
8643
8676
  if (flatWidgets.some(function(widget) {
8644
8677
  return typeof widget.init !== 'function' && typeof widget.render !== 'function';
8645
8678
  })) {
8646
- throw new Error(withUsage$s('The widget definition expects a `render` and/or an `init` method.'));
8679
+ throw new Error(withUsage$u('The widget definition expects a `render` and/or an `init` method.'));
8647
8680
  }
8648
8681
  flatWidgets.forEach(function(widget) {
8649
8682
  widget.parent = _this;
@@ -8694,7 +8727,7 @@
8694
8727
  removeWidgets: function removeWidgets(widgets) {
8695
8728
  var _this = this;
8696
8729
  if (!Array.isArray(widgets)) {
8697
- throw new Error(withUsage$s('The `removeWidgets` method expects an array of widgets.'));
8730
+ throw new Error(withUsage$u('The `removeWidgets` method expects an array of widgets.'));
8698
8731
  }
8699
8732
  var flatWidgets = widgets.reduce(function(acc, w) {
8700
8733
  return acc.concat(Array.isArray(w) ? w : [
@@ -8704,7 +8737,7 @@
8704
8737
  if (flatWidgets.some(function(widget) {
8705
8738
  return typeof widget.dispose !== 'function';
8706
8739
  })) {
8707
- throw new Error(withUsage$s('The widget definition expects a `dispose` method.'));
8740
+ throw new Error(withUsage$u('The widget definition expects a `dispose` method.'));
8708
8741
  }
8709
8742
  localWidgets = localWidgets.filter(function(widget) {
8710
8743
  return flatWidgets.indexOf(widget) === -1;
@@ -8832,7 +8865,7 @@
8832
8865
  mainHelper.state
8833
8866
  ].concat(_to_consumable_array(resolveSearchParameters(_this))));
8834
8867
  }, function() {
8835
- return _this.getHelper().recommendState;
8868
+ return addInsightsToRecommendParameters(_this.getHelper().recommendState, mainHelper.state);
8836
8869
  });
8837
8870
  var indexInitialResults = (_instantSearchInstance__initialResults = instantSearchInstance._initialResults) === null || _instantSearchInstance__initialResults === void 0 ? void 0 : _instantSearchInstance__initialResults[this.getIndexId()];
8838
8871
  if (indexInitialResults === null || indexInitialResults === void 0 ? void 0 : indexInitialResults.results) {
@@ -9209,7 +9242,7 @@
9209
9242
  });
9210
9243
  }
9211
9244
 
9212
- var version = '4.107.0';
9245
+ var version = '4.109.0';
9213
9246
 
9214
9247
  var ANONYMOUS_TOKEN_COOKIE_KEY = '_ALGOLIA';
9215
9248
  function getCookie(name) {
@@ -9439,7 +9472,8 @@
9439
9472
  helper.overrideStateWithoutTriggeringChangeEvent(_object_spread_props(_object_spread({}, helper.state), {
9440
9473
  userToken: normalizedUserToken
9441
9474
  }));
9442
- if (existingToken && existingToken !== userToken) {
9475
+ if (existingToken && existingToken !== normalizedUserToken) {
9476
+ helper._recommendCache = {};
9443
9477
  instantSearchInstance.scheduleSearch();
9444
9478
  }
9445
9479
  }
@@ -9528,14 +9562,17 @@
9528
9562
  } else if (event.insightsMethod) {
9529
9563
  if (event.insightsMethod === 'viewedObjectIDs') {
9530
9564
  var payload = event.payload;
9565
+ var getViewEventKey = function getViewEventKey(objectID) {
9566
+ return payload.queryID ? "".concat(payload.queryID, ":").concat(objectID) : objectID;
9567
+ };
9531
9568
  var difference = payload.objectIDs.filter(function(objectID) {
9532
- return !viewedObjectIDs.has(objectID);
9569
+ return !viewedObjectIDs.has(getViewEventKey(objectID));
9533
9570
  });
9534
9571
  if (difference.length === 0) {
9535
9572
  return;
9536
9573
  }
9537
9574
  difference.forEach(function(objectID) {
9538
- return viewedObjectIDs.add(objectID);
9575
+ return viewedObjectIDs.add(getViewEventKey(objectID));
9539
9576
  });
9540
9577
  payload.objectIDs = difference;
9541
9578
  }
@@ -9643,10 +9680,10 @@
9643
9680
  * and the ability to set credentials via extra parameters when sending events.
9644
9681
  */ function isModernInsightsClient(client) {
9645
9682
  var _split_map = _sliced_to_array((client.version || '').split('.').map(Number), 2), major = _split_map[0], minor = _split_map[1];
9646
- /* eslint-disable instantsearch/naming-convention */ var v3 = major >= 3;
9683
+ /* oxlint-disable instantsearch/naming-convention */ var v3 = major >= 3;
9647
9684
  var v2_6 = major === 2 && minor >= 6;
9648
9685
  var v1_10 = major === 1 && minor >= 10;
9649
- /* eslint-enable instantsearch/naming-convention */ return v3 || v2_6 || v1_10;
9686
+ /* oxlint-enable instantsearch/naming-convention */ return v3 || v2_6 || v1_10;
9650
9687
  }
9651
9688
  /**
9652
9689
  * While `search-insights` supports both string and number user tokens,
@@ -11067,7 +11104,7 @@
11067
11104
  };
11068
11105
  }
11069
11106
 
11070
- var withUsage$r = createDocumentationMessageGenerator({
11107
+ var withUsage$t = createDocumentationMessageGenerator({
11071
11108
  name: 'instantsearch'
11072
11109
  });
11073
11110
  function defaultCreateURL() {
@@ -11130,7 +11167,7 @@
11130
11167
  _this.setMaxListeners(100);
11131
11168
  var _options_indexName = options.indexName, indexName = _options_indexName === void 0 ? '' : _options_indexName, compositionID = options.compositionID, numberLocale = options.numberLocale, _options_initialUiState = options.initialUiState, initialUiState = _options_initialUiState === void 0 ? {} : _options_initialUiState, _options_routing = options.routing, routing = _options_routing === void 0 ? null : _options_routing, _options_insights = options.insights, insights = _options_insights === void 0 ? undefined : _options_insights, searchFunction = options.searchFunction, _options_stalledSearchDelay = options.stalledSearchDelay, stalledSearchDelay = _options_stalledSearchDelay === void 0 ? 200 : _options_stalledSearchDelay, _options_searchClient = options.searchClient, searchClient = _options_searchClient === void 0 ? null : _options_searchClient, _options_insightsClient = options.insightsClient, insightsClient = _options_insightsClient === void 0 ? null : _options_insightsClient, _options_onStateChange = options.onStateChange, onStateChange = _options_onStateChange === void 0 ? null : _options_onStateChange, _options_future1 = options.future, future = _options_future1 === void 0 ? _object_spread({}, INSTANTSEARCH_FUTURE_DEFAULTS, options.future || {}) : _options_future1;
11132
11169
  if (searchClient === null) {
11133
- throw new Error(withUsage$r('The `searchClient` option is required.'));
11170
+ throw new Error(withUsage$t('The `searchClient` option is required.'));
11134
11171
  }
11135
11172
  if (typeof searchClient.search !== 'function') {
11136
11173
  throw new Error("The `searchClient` must implement a `search` method.\n\nSee: https://www.algolia.com/doc/guides/building-search-ui/going-further/backend-search/in-depth/backend-instantsearch/js/");
@@ -11139,7 +11176,7 @@
11139
11176
  searchClient.addAlgoliaAgent("instantsearch.js (".concat(version, ")"));
11140
11177
  }
11141
11178
  if (insightsClient && typeof insightsClient !== 'function') {
11142
- throw new Error(withUsage$r('The `insightsClient` option should be a function.'));
11179
+ throw new Error(withUsage$t('The `insightsClient` option should be a function.'));
11143
11180
  }
11144
11181
  _this._initialOptions = options;
11145
11182
  _this.client = searchClient;
@@ -11288,12 +11325,12 @@
11288
11325
  * @param widgets The array of widgets to add to InstantSearch.
11289
11326
  */ function addWidgets(widgets) {
11290
11327
  if (!Array.isArray(widgets)) {
11291
- throw new Error(withUsage$r('The `addWidgets` method expects an array of widgets. Please use `addWidget`.'));
11328
+ throw new Error(withUsage$t('The `addWidgets` method expects an array of widgets. Please use `addWidget`.'));
11292
11329
  }
11293
11330
  if (this.compositionID && widgets.some(function(w) {
11294
11331
  return !Array.isArray(w) && isIndexWidget(w) && !w._isolated;
11295
11332
  })) {
11296
- throw new Error(withUsage$r('The `index` widget cannot be used with a composition-based InstantSearch implementation.'));
11333
+ throw new Error(withUsage$t('The `index` widget cannot be used with a composition-based InstantSearch implementation.'));
11297
11334
  }
11298
11335
  this.mainIndex.addWidgets(widgets);
11299
11336
  return this;
@@ -11322,7 +11359,7 @@
11322
11359
  * The widgets must implement a `dispose()` method to clear their states.
11323
11360
  */ function removeWidgets(widgets) {
11324
11361
  if (!Array.isArray(widgets)) {
11325
- throw new Error(withUsage$r('The `removeWidgets` method expects an array of widgets. Please use `removeWidget`.'));
11362
+ throw new Error(withUsage$t('The `removeWidgets` method expects an array of widgets. Please use `removeWidget`.'));
11326
11363
  }
11327
11364
  this.mainIndex.removeWidgets(widgets);
11328
11365
  return this;
@@ -11336,7 +11373,7 @@
11336
11373
  */ function start() {
11337
11374
  var _this = this;
11338
11375
  if (this.started) {
11339
- throw new Error(withUsage$r('The `start` method has already been called once.'));
11376
+ throw new Error(withUsage$t('The `start` method has already been called once.'));
11340
11377
  }
11341
11378
  // This Helper is used for the queries, we don't care about its state. The
11342
11379
  // states are managed at the `index` level. We use this Helper to create
@@ -11544,7 +11581,7 @@
11544
11581
  var _this = this;
11545
11582
  var callOnStateChange = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : true;
11546
11583
  if (!this.mainHelper) {
11547
- throw new Error(withUsage$r('The `start` method needs to be called before `setUiState`.'));
11584
+ throw new Error(withUsage$t('The `start` method needs to be called before `setUiState`.'));
11548
11585
  }
11549
11586
  // We refresh the index UI state to update the local UI state that the
11550
11587
  // main index passes to the function form of `setUiState`.
@@ -11581,7 +11618,7 @@
11581
11618
  value: function createURL() {
11582
11619
  var nextState = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
11583
11620
  if (!this.started) {
11584
- throw new Error(withUsage$r('The `start` method needs to be called before `createURL`.'));
11621
+ throw new Error(withUsage$t('The `start` method needs to be called before `createURL`.'));
11585
11622
  }
11586
11623
  return this._createURL(nextState);
11587
11624
  }
@@ -11590,7 +11627,7 @@
11590
11627
  key: "refresh",
11591
11628
  value: function refresh() {
11592
11629
  if (!this.mainHelper) {
11593
- throw new Error(withUsage$r('The `start` method needs to be called before `refresh`.'));
11630
+ throw new Error(withUsage$t('The `start` method needs to be called before `refresh`.'));
11594
11631
  }
11595
11632
  this.mainHelper.clearCache().search();
11596
11633
  }
@@ -12116,13 +12153,13 @@
12116
12153
  }, children);
12117
12154
  }
12118
12155
 
12119
- var withUsage$q = createDocumentationMessageGenerator({
12156
+ var withUsage$s = createDocumentationMessageGenerator({
12120
12157
  name: 'autocomplete',
12121
12158
  connector: true
12122
12159
  });
12123
12160
  var connectAutocomplete = function connectAutocomplete(renderFn) {
12124
12161
  var unmountFn = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : noop;
12125
- checkRendering(renderFn, withUsage$q());
12162
+ checkRendering(renderFn, withUsage$s());
12126
12163
  return function(widgetParams) {
12127
12164
  var _ref = widgetParams || {}, _ref_escapeHTML = _ref.escapeHTML, escapeHTML = _ref_escapeHTML === void 0 ? true : _ref_escapeHTML, _ref_transformItems = _ref.transformItems, transformItems = _ref_transformItems === void 0 ? function(indices) {
12128
12165
  return indices;
@@ -12235,20 +12272,20 @@
12235
12272
  return useConnector(connectAutocomplete, props, additionalWidgetProperties);
12236
12273
  }
12237
12274
 
12238
- var withUsage$p = createDocumentationMessageGenerator({
12275
+ var withUsage$r = createDocumentationMessageGenerator({
12239
12276
  name: 'breadcrumb',
12240
12277
  connector: true
12241
12278
  });
12242
12279
  var connectBreadcrumb = function connectBreadcrumb(renderFn) {
12243
12280
  var unmountFn = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : noop;
12244
- checkRendering(renderFn, withUsage$p());
12281
+ checkRendering(renderFn, withUsage$r());
12245
12282
  var connectorState = {};
12246
12283
  return function(widgetParams) {
12247
12284
  var _ref = widgetParams || {}, attributes = _ref.attributes, _ref_separator = _ref.separator, separator = _ref_separator === void 0 ? ' > ' : _ref_separator, _ref_rootPath = _ref.rootPath, rootPath = _ref_rootPath === void 0 ? null : _ref_rootPath, _ref_transformItems = _ref.transformItems, transformItems = _ref_transformItems === void 0 ? function(items) {
12248
12285
  return items;
12249
12286
  } : _ref_transformItems;
12250
12287
  if (!attributes || !Array.isArray(attributes) || attributes.length === 0) {
12251
- throw new Error(withUsage$p('The `attributes` option expects an array of strings.'));
12288
+ throw new Error(withUsage$r('The `attributes` option expects an array of strings.'));
12252
12289
  }
12253
12290
  var _attributes = _sliced_to_array(attributes, 1), hierarchicalFacetName = _attributes[0];
12254
12291
  function getRefinedState(state, facetValue) {
@@ -12394,6 +12431,76 @@
12394
12431
  return useConnector(connectBreadcrumb, props, additionalWidgetProperties);
12395
12432
  }
12396
12433
 
12434
+ var tryParseJson = function tryParseJson(value) {
12435
+ try {
12436
+ return JSON.parse(value);
12437
+ } catch (unused) {
12438
+ return undefined;
12439
+ }
12440
+ };
12441
+ var repairPartialJson = function repairPartialJson(value) {
12442
+ var repaired = value.trim();
12443
+ if (!repaired) {
12444
+ return repaired;
12445
+ }
12446
+ var inString = false;
12447
+ var isEscaped = false;
12448
+ var stack = [];
12449
+ for(var index = 0; index < repaired.length; index++){
12450
+ var char = repaired[index];
12451
+ if (inString) {
12452
+ if (isEscaped) {
12453
+ isEscaped = false;
12454
+ } else if (char === '\\') {
12455
+ isEscaped = true;
12456
+ } else if (char === '"') {
12457
+ inString = false;
12458
+ }
12459
+ continue;
12460
+ }
12461
+ if (char === '"') {
12462
+ inString = true;
12463
+ continue;
12464
+ }
12465
+ if (char === '{' || char === '[') {
12466
+ stack.push(char);
12467
+ continue;
12468
+ }
12469
+ if (char === '}' && stack[stack.length - 1] === '{') {
12470
+ stack.pop();
12471
+ continue;
12472
+ }
12473
+ if (char === ']' && stack[stack.length - 1] === '[') {
12474
+ stack.pop();
12475
+ }
12476
+ }
12477
+ if (inString && !isEscaped) {
12478
+ repaired += '"';
12479
+ }
12480
+ repaired = repaired.replace(RegExp(",\\s*$", "u"), '');
12481
+ if (stack.length > 0) {
12482
+ repaired += stack.reverse().map(function(opening) {
12483
+ return opening === '{' ? '}' : ']';
12484
+ }).join('');
12485
+ }
12486
+ return repaired.replace(RegExp(",\\s*([}\\]])", "gu"), '$1');
12487
+ };
12488
+ var parsePartialJson = function parsePartialJson(accumulatedRawJson, fallbackValue) {
12489
+ var normalized = accumulatedRawJson.trim();
12490
+ if (!normalized) {
12491
+ return fallbackValue;
12492
+ }
12493
+ var directParsed = tryParseJson(normalized);
12494
+ if (directParsed !== undefined) {
12495
+ return directParsed;
12496
+ }
12497
+ var repairedParsed = tryParseJson(repairPartialJson(normalized));
12498
+ if (repairedParsed !== undefined) {
12499
+ return repairedParsed;
12500
+ }
12501
+ return fallbackValue;
12502
+ };
12503
+
12397
12504
  /**
12398
12505
  * Stream parser for parsing SSE (Server-Sent Events) streams.
12399
12506
  * The AI SDK 5 format uses SSE with JSON payloads prefixed by "data: ".
@@ -12674,76 +12781,10 @@
12674
12781
  return undefined;
12675
12782
  }
12676
12783
 
12677
- var tryParseJson = function tryParseJson(value) {
12678
- try {
12679
- return JSON.parse(value);
12680
- } catch (unused) {
12681
- return undefined;
12682
- }
12683
- };
12684
- var repairPartialJson = function repairPartialJson(value) {
12685
- var repaired = value.trim();
12686
- if (!repaired) {
12687
- return repaired;
12688
- }
12689
- var inString = false;
12690
- var isEscaped = false;
12691
- var stack = [];
12692
- for(var index = 0; index < repaired.length; index++){
12693
- var char = repaired[index];
12694
- if (inString) {
12695
- if (isEscaped) {
12696
- isEscaped = false;
12697
- } else if (char === '\\') {
12698
- isEscaped = true;
12699
- } else if (char === '"') {
12700
- inString = false;
12701
- }
12702
- continue;
12703
- }
12704
- if (char === '"') {
12705
- inString = true;
12706
- continue;
12707
- }
12708
- if (char === '{' || char === '[') {
12709
- stack.push(char);
12710
- continue;
12711
- }
12712
- if (char === '}' && stack[stack.length - 1] === '{') {
12713
- stack.pop();
12714
- continue;
12715
- }
12716
- if (char === ']' && stack[stack.length - 1] === '[') {
12717
- stack.pop();
12718
- }
12719
- }
12720
- if (inString && !isEscaped) {
12721
- repaired += '"';
12722
- }
12723
- repaired = repaired.replace(RegExp(",\\s*$", "u"), '');
12724
- if (stack.length > 0) {
12725
- repaired += stack.reverse().map(function(opening) {
12726
- return opening === '{' ? '}' : ']';
12727
- }).join('');
12728
- }
12729
- return repaired.replace(RegExp(",\\s*([}\\]])", "gu"), '$1');
12730
- };
12731
- var parseToolInputDelta = function parseToolInputDelta(accumulatedRawInput, fallbackInput) {
12732
- var normalized = accumulatedRawInput.trim();
12733
- if (!normalized) {
12734
- return fallbackInput;
12735
- }
12736
- var directParsed = tryParseJson(normalized);
12737
- if (directParsed !== undefined) {
12738
- return directParsed;
12739
- }
12740
- var repairedParsed = tryParseJson(repairPartialJson(normalized));
12741
- if (repairedParsed !== undefined) {
12742
- return repairedParsed;
12743
- }
12744
- return fallbackInput;
12745
- };
12784
+ var _computedKey$1;
12746
12785
  var defaultGuardrailFallbackResponse = 'Sorry, we are not able to generate a response at the moment.';
12786
+ _computedKey$1 = /** @internal */ '~addToolResultForMessage';
12787
+ var _computedKey1$1 = _computedKey$1;
12747
12788
  /**
12748
12789
  * Abstract base class for chat implementations.
12749
12790
  */ var AbstractChat = /*#__PURE__*/ function() {
@@ -12763,6 +12804,12 @@
12763
12804
  _define_property(this, "sendAutomaticallyWhen", void 0);
12764
12805
  _define_property(this, "shouldRepairToolInput", void 0);
12765
12806
  _define_property(this, "activeResponse", null);
12807
+ _define_property(this, "latestResponse", null);
12808
+ _define_property(this, "responsesByToolCallId", new Map());
12809
+ _define_property(this, "responseByMessage", new WeakMap());
12810
+ // Once tool ownership is discarded, an identifier-only result cannot prove
12811
+ // which response generation submitted it. Scoped submissions remain safe.
12812
+ _define_property(this, "acceptsIdentifierOnlyToolResults", true);
12766
12813
  _define_property(this, "jobExecutor", new SerialJobExecutor());
12767
12814
  /**
12768
12815
  * Appends or replaces a user message to the chat list. This triggers the API call to fetch
@@ -12848,13 +12895,13 @@
12848
12895
  // Find the message to regenerate from
12849
12896
  var targetIndex = -1;
12850
12897
  if (messageId) {
12851
- targetIndex = _this1.state.messages.findIndex(function(m) {
12898
+ targetIndex = _this1.messages.findIndex(function(m) {
12852
12899
  return m.id === messageId;
12853
12900
  });
12854
12901
  } else {
12855
12902
  // Find the last assistant message
12856
- for(var i = _this1.state.messages.length - 1; i >= 0; i--){
12857
- if (_this1.state.messages[i].role === 'assistant') {
12903
+ for(var i = _this1.messages.length - 1; i >= 0; i--){
12904
+ if (_this1.messages[i].role === 'assistant') {
12858
12905
  targetIndex = i;
12859
12906
  break;
12860
12907
  }
@@ -12862,7 +12909,7 @@
12862
12909
  }
12863
12910
  if (targetIndex >= 0) {
12864
12911
  // Remove the assistant message and all messages after it
12865
- _this1.state.messages = _this1.state.messages.slice(0, targetIndex);
12912
+ _this1.messages = _this1.messages.slice(0, targetIndex);
12866
12913
  }
12867
12914
  return _this1.makeRequest(_object_spread({
12868
12915
  trigger: 'regenerate-message',
@@ -12877,23 +12924,10 @@
12877
12924
  if (!_this.transport) {
12878
12925
  return Promise.reject(new Error('Transport is required for resuming stream. Please provide a transport when initializing the chat.'));
12879
12926
  }
12880
- _this.setStatus({
12881
- status: 'submitted'
12882
- });
12883
- return _this.transport.reconnectToStream(_object_spread({
12884
- chatId: _this.id
12885
- }, options)).then(function(stream) {
12886
- if (stream) {
12887
- return _this.processStreamWithCallbacks(stream);
12888
- } else {
12889
- _this.setStatus({
12890
- status: 'ready'
12891
- });
12892
- return Promise.resolve();
12893
- }
12894
- }, function(error) {
12895
- _this.handleError(error);
12896
- return Promise.resolve();
12927
+ return _this.consume(function() {
12928
+ return _this.transport.reconnectToStream(_object_spread({
12929
+ chatId: _this.id
12930
+ }, options));
12897
12931
  });
12898
12932
  });
12899
12933
  });
@@ -12909,53 +12943,57 @@
12909
12943
  });
12910
12944
  /**
12911
12945
  * Add a tool result for a tool call.
12912
- */ _define_property(this, "addToolResult", function(param) {
12913
- var tool = param.tool, toolCallId = param.toolCallId, output = param.output;
12914
- return _this.jobExecutor.run(function() {
12915
- // Find the message with this tool call
12916
- var messageIndex = _this.state.messages.findIndex(function(m) {
12917
- var _ref;
12918
- var _m_parts;
12919
- return (_ref = (_m_parts = m.parts) === null || _m_parts === void 0 ? void 0 : _m_parts.some(function(p) {
12920
- return 'toolCallId' in p && p.toolCallId === toolCallId || 'type' in p && p.type === "tool-".concat(String(tool));
12921
- })) !== null && _ref !== void 0 ? _ref : false;
12922
- });
12923
- if (messageIndex === -1) return Promise.resolve();
12924
- var message = _this.state.messages[messageIndex];
12925
- var updatedParts = message.parts.map(function(part) {
12926
- if ('toolCallId' in part && part.toolCallId === toolCallId && 'state' in part) {
12927
- return _object_spread_props(_object_spread({}, part), {
12928
- state: 'output-available',
12929
- output: output
12930
- });
12931
- }
12932
- return part;
12933
- });
12934
- _this.state.replaceMessage(messageIndex, _object_spread_props(_object_spread({}, message), {
12935
- parts: updatedParts
12936
- }));
12937
- // Check if we should auto-send based on sendAutomaticallyWhen
12938
- if (_this.sendAutomaticallyWhen) {
12939
- return Promise.resolve(_this.sendAutomaticallyWhen({
12940
- messages: _this.state.messages
12941
- })).then(function(shouldSend) {
12942
- if (shouldSend) {
12943
- return _this.makeRequest({
12944
- trigger: 'submit-message'
12945
- });
12946
- }
12947
- return Promise.resolve();
12946
+ */ _define_property(this, "addToolResult", function(options) {
12947
+ if (!_this.acceptsIdentifierOnlyToolResults) {
12948
+ return Promise.resolve();
12949
+ }
12950
+ var owners = _this.responsesByToolCallId.get(options.toolCallId);
12951
+ var response = (owners === null || owners === void 0 ? void 0 : owners.size) === 1 ? owners.values().next().value : undefined;
12952
+ if (response) return _this.submitToolResult(response, options);
12953
+ var findMatchingMessage = function findMatchingMessage() {
12954
+ var matchingMessages = _this.messages.filter(function(message) {
12955
+ var _message_parts;
12956
+ return (_message_parts = message.parts) === null || _message_parts === void 0 ? void 0 : _message_parts.some(function(part) {
12957
+ return 'toolCallId' in part && part.toolCallId === options.toolCallId;
12948
12958
  });
12959
+ });
12960
+ return matchingMessages.length === 1 ? matchingMessages[0] : undefined;
12961
+ };
12962
+ if (!findMatchingMessage()) return Promise.resolve();
12963
+ return _this.jobExecutor.run(function() {
12964
+ if (!_this.acceptsIdentifierOnlyToolResults) return Promise.resolve();
12965
+ var message = findMatchingMessage();
12966
+ if (!message || !_this.commit(options.toolCallId, options.output, message.id, undefined, message)) {
12967
+ return Promise.resolve();
12949
12968
  }
12950
- return Promise.resolve();
12969
+ return _this.continueResponse();
12951
12970
  });
12952
12971
  });
12972
+ _define_property(this, _computedKey1$1, function(message, options) {
12973
+ var hasToolCall = function hasToolCall(candidate) {
12974
+ var _candidate_parts;
12975
+ return ((_candidate_parts = candidate.parts) === null || _candidate_parts === void 0 ? void 0 : _candidate_parts.some(function(part) {
12976
+ return 'toolCallId' in part && part.toolCallId === options.toolCallId;
12977
+ })) === true;
12978
+ };
12979
+ if (!hasToolCall(message)) {
12980
+ return Promise.resolve();
12981
+ }
12982
+ var response = _this.responseByMessage.get(message);
12983
+ var currentMessage = _this.messages.includes(message) ? message : response && !response.isRetired ? _this.messages.find(function(candidate) {
12984
+ return candidate.id === message.id && _this.responseByMessage.get(candidate) === response && hasToolCall(candidate);
12985
+ }) : undefined;
12986
+ if (!currentMessage) return Promise.resolve();
12987
+ return _this.submitToolResult(response, options, currentMessage.id, currentMessage);
12988
+ });
12953
12989
  /**
12954
12990
  * Abort the current request immediately, keep the generated tokens if any.
12955
12991
  */ _define_property(this, "stop", function() {
12956
12992
  if (_this.activeResponse) {
12957
- _this.activeResponse.abortController.abort();
12993
+ var response = _this.activeResponse;
12994
+ response.outcome = 'aborted';
12958
12995
  _this.activeResponse = null;
12996
+ response.abortController.abort();
12959
12997
  }
12960
12998
  _this.setStatus({
12961
12999
  status: 'ready'
@@ -13017,6 +13055,14 @@
13017
13055
  * context.
13018
13056
  */ key: "resetConversationId",
13019
13057
  value: function resetConversationId() {
13058
+ if (this.responsesByToolCallId.size > 0 || this.messages.some(function(message) {
13059
+ var _message_parts;
13060
+ return (_message_parts = message.parts) === null || _message_parts === void 0 ? void 0 : _message_parts.some(function(part) {
13061
+ return 'toolCallId' in part;
13062
+ });
13063
+ })) {
13064
+ this.acceptsIdentifierOnlyToolResults = false;
13065
+ }
13020
13066
  this.conversationId = this.generateId();
13021
13067
  }
13022
13068
  },
@@ -13026,7 +13072,93 @@
13026
13072
  return this.state.messages;
13027
13073
  },
13028
13074
  set: function set(messages) {
13075
+ var _this = this;
13076
+ var getToolOccurrences = function getToolOccurrences(message) {
13077
+ return message.parts.filter(function(part) {
13078
+ return 'toolCallId' in part;
13079
+ }).map(function(part) {
13080
+ return {
13081
+ type: part.type,
13082
+ toolCallId: part.toolCallId,
13083
+ state: 'state' in part ? part.state : undefined,
13084
+ input: 'input' in part ? part.input : undefined,
13085
+ output: 'output' in part ? part.output : undefined,
13086
+ errorText: 'errorText' in part ? part.errorText : undefined,
13087
+ providerExecuted: 'providerExecuted' in part ? part.providerExecuted : undefined
13088
+ };
13089
+ });
13090
+ };
13091
+ var isEquivalentRehydration = function isEquivalentRehydration(message) {
13092
+ var replacements = messages.filter(function(candidate) {
13093
+ return candidate.id === message.id;
13094
+ });
13095
+ if (replacements.length !== 1) return false;
13096
+ var toolOccurrences = getToolOccurrences(message);
13097
+ var replacementToolOccurrences = getToolOccurrences(replacements[0]);
13098
+ return toolOccurrences.length > 0 || replacementToolOccurrences.length > 0 ? isEqual(toolOccurrences, replacementToolOccurrences) : isEqual(message.parts, replacements[0].parts);
13099
+ };
13100
+ var detachedResponses = new Set();
13101
+ this.state.messages.forEach(function(message) {
13102
+ if (!messages.includes(message)) {
13103
+ var response = _this.responseByMessage.get(message);
13104
+ if (response && !isEquivalentRehydration(message)) {
13105
+ detachedResponses.add(response);
13106
+ }
13107
+ }
13108
+ });
13109
+ var removedToolOwner = this.state.messages.some(function(message) {
13110
+ var _message_parts;
13111
+ return ((_message_parts = message.parts) === null || _message_parts === void 0 ? void 0 : _message_parts.some(function(part) {
13112
+ return 'toolCallId' in part;
13113
+ })) && !messages.includes(message) && !isEquivalentRehydration(message);
13114
+ });
13115
+ var toolCallIds = new Set();
13116
+ var hasDuplicateToolCallId = messages.some(function(message) {
13117
+ var _message_parts;
13118
+ return ((_message_parts = message.parts) === null || _message_parts === void 0 ? void 0 : _message_parts.some(function(part) {
13119
+ if (!('toolCallId' in part)) {
13120
+ return false;
13121
+ }
13122
+ if (toolCallIds.has(part.toolCallId)) {
13123
+ return true;
13124
+ }
13125
+ toolCallIds.add(part.toolCallId);
13126
+ return false;
13127
+ })) === true;
13128
+ });
13129
+ if (removedToolOwner || hasDuplicateToolCallId) {
13130
+ this.acceptsIdentifierOnlyToolResults = false;
13131
+ }
13029
13132
  this.state.messages = messages;
13133
+ var retainedMessageIds = new Set(messages.map(function(message) {
13134
+ return message.id;
13135
+ }));
13136
+ var responses = new Set();
13137
+ this.responsesByToolCallId.forEach(function(owners) {
13138
+ owners.forEach(function(response) {
13139
+ return responses.add(response);
13140
+ });
13141
+ });
13142
+ if (this.activeResponse) {
13143
+ responses.add(this.activeResponse);
13144
+ }
13145
+ detachedResponses.forEach(function(response) {
13146
+ responses.add(response);
13147
+ _this.retireResponse(response);
13148
+ });
13149
+ responses.forEach(function(response) {
13150
+ var message = response.messageId ? messages.find(function(candidate) {
13151
+ return candidate.id === response.messageId;
13152
+ }) : undefined;
13153
+ if (message && !response.isRetired && !detachedResponses.has(response)) {
13154
+ _this.responseByMessage.set(message, response);
13155
+ }
13156
+ });
13157
+ responses.forEach(function(response) {
13158
+ if (detachedResponses.has(response) || response.messageId && !retainedMessageIds.has(response.messageId)) {
13159
+ _this.pruneDetachedResponse(response);
13160
+ }
13161
+ });
13030
13162
  }
13031
13163
  },
13032
13164
  {
@@ -13036,76 +13168,363 @@
13036
13168
  }
13037
13169
  },
13038
13170
  {
13039
- key: "makeRequest",
13040
- value: function makeRequest(options) {
13041
- var _this = this;
13042
- if (!this.transport) {
13043
- return Promise.reject(new Error('Transport is required for sending messages. Please provide a transport when initializing the chat.'));
13044
- }
13045
- // Abort any existing request
13046
- if (this.activeResponse) {
13047
- this.activeResponse.abortController.abort();
13171
+ key: "replaceMessage",
13172
+ value: function replaceMessage(index, message, response) {
13173
+ var _this_messages_index;
13174
+ this.state.replaceMessage(index, message);
13175
+ var canonicalMessage = (_this_messages_index = this.messages[index]) !== null && _this_messages_index !== void 0 ? _this_messages_index : message;
13176
+ if (response && this.messages.includes(canonicalMessage)) {
13177
+ this.responseByMessage.set(canonicalMessage, response);
13048
13178
  }
13049
- var abortController = new AbortController();
13050
- this.activeResponse = {
13051
- abortController: abortController
13179
+ return canonicalMessage;
13180
+ }
13181
+ },
13182
+ {
13183
+ key: "commit",
13184
+ value: function commit(toolCallId, output, messageId, response, expectedMessage) {
13185
+ var isTargetPart = function isTargetPart(part) {
13186
+ return 'toolCallId' in part && part.toolCallId === toolCallId;
13052
13187
  };
13053
- this.setStatus({
13054
- status: 'submitted'
13188
+ var messageIndex = this.messages.findIndex(function(message) {
13189
+ return (!messageId || message.id === messageId) && (!expectedMessage || message === expectedMessage) && message.parts.some(isTargetPart);
13055
13190
  });
13056
- return this.transport.sendMessages({
13057
- chatId: this.id,
13058
- messages: this.state.messages,
13059
- abortSignal: abortController.signal,
13060
- trigger: options.trigger,
13061
- messageId: options.messageId,
13062
- headers: options.headers,
13063
- body: options.body,
13064
- requestMetadata: options.metadata
13065
- }).then(function(stream) {
13066
- _this.activeResponse.stream = stream;
13067
- return _this.processStreamWithCallbacks(stream);
13068
- }, function(error) {
13069
- if (error.name === 'AbortError') {
13070
- // Request was aborted, don't treat as error
13191
+ if (messageIndex === -1) return false;
13192
+ var message = this.messages[messageIndex];
13193
+ var partIndex = message.parts.findIndex(isTargetPart);
13194
+ var part = message.parts[partIndex];
13195
+ if (!('state' in part) || part.state === 'output-available' && !part.preliminary || part.state === 'output-error') {
13196
+ return false;
13197
+ }
13198
+ // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
13199
+ part.preliminary; // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
13200
+ part.rawOutput;
13201
+ var committedPart = _object_without_properties(part, [
13202
+ "preliminary",
13203
+ "rawOutput"
13204
+ ]);
13205
+ var updatedParts = _to_consumable_array(message.parts);
13206
+ updatedParts[partIndex] = _object_spread_props(_object_spread({}, committedPart), {
13207
+ state: 'output-available',
13208
+ output: output
13209
+ });
13210
+ var updatedMessage = _object_spread_props(_object_spread({}, message), {
13211
+ parts: updatedParts
13212
+ });
13213
+ this.replaceMessage(messageIndex, updatedMessage, response);
13214
+ return true;
13215
+ }
13216
+ },
13217
+ {
13218
+ key: "continueResponse",
13219
+ value: function continueResponse(response) {
13220
+ var _this = this;
13221
+ if (response) {
13222
+ this.pruneDetachedResponse(response);
13223
+ if (response.isRetired || response.outcome !== 'succeeded' || response.requiredToolCallIds.size === 0 || Array.from(response.requiredToolCallIds).some(function(toolCallId) {
13224
+ return !response.resolvedToolCallIds.has(toolCallId);
13225
+ }) || !response.didNotifyFinish || response.didEvaluateContinuation) {
13071
13226
  return Promise.resolve();
13072
13227
  }
13228
+ response.didEvaluateContinuation = true;
13229
+ }
13230
+ if (!this.sendAutomaticallyWhen) return Promise.resolve();
13231
+ return Promise.resolve().then(function() {
13232
+ return _this.sendAutomaticallyWhen({
13233
+ messages: _this.messages
13234
+ });
13235
+ }).then(function(shouldSend) {
13236
+ if (response) {
13237
+ _this.pruneDetachedResponse(response);
13238
+ if (response.isRetired) return undefined;
13239
+ }
13240
+ return shouldSend ? _this.makeRequest({
13241
+ trigger: 'submit-message'
13242
+ }) : undefined;
13243
+ }).catch(function(error) {
13244
+ if (response) {
13245
+ _this.pruneDetachedResponse(response);
13246
+ if (response.isRetired) return;
13247
+ _this.handleError(error, {
13248
+ updateState: _this.latestResponse === response
13249
+ });
13250
+ return;
13251
+ }
13073
13252
  _this.handleError(error);
13074
- return Promise.resolve();
13075
13253
  });
13076
13254
  }
13077
13255
  },
13078
13256
  {
13079
- key: "processStreamWithCallbacks",
13080
- value: function processStreamWithCallbacks(stream) {
13081
- var _this = this;
13082
- this.setStatus({
13257
+ key: "retireResponse",
13258
+ value: function retireResponse(response) {
13259
+ if (response.isRetired) return;
13260
+ response.isRetired = true;
13261
+ response.didEvaluateContinuation = true;
13262
+ if (this.activeResponse === response) {
13263
+ response.outcome = 'aborted';
13264
+ this.activeResponse = null;
13265
+ response.abortController.abort();
13266
+ this.setStatus({
13267
+ status: 'ready'
13268
+ });
13269
+ }
13270
+ }
13271
+ },
13272
+ {
13273
+ key: "pruneDetachedResponse",
13274
+ value: function pruneDetachedResponse(response) {
13275
+ var _this = this;
13276
+ if (!response.isRetired) {
13277
+ if (!response.messageId || this.messages.some(function(message) {
13278
+ return message.id === response.messageId;
13279
+ })) {
13280
+ return;
13281
+ }
13282
+ this.retireResponse(response);
13283
+ }
13284
+ // Keep a routing tombstone while a callback is running so public
13285
+ // addToolResult calls settle directly instead of entering the executor.
13286
+ if (response.pendingToolCallbacks > 0) return;
13287
+ this.responsesByToolCallId.forEach(function(owners, toolCallId) {
13288
+ owners.delete(response);
13289
+ if (owners.size === 0) {
13290
+ _this.responsesByToolCallId.delete(toolCallId);
13291
+ }
13292
+ });
13293
+ }
13294
+ },
13295
+ {
13296
+ key: "submitToolResult",
13297
+ value: function submitToolResult(response, param) {
13298
+ var _this = this;
13299
+ var toolCallId = param.toolCallId, output = param.output, messageId = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : response === null || response === void 0 ? void 0 : response.messageId, expectedMessage = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : messageId ? this.messages.find(function(message) {
13300
+ return message.id === messageId;
13301
+ }) : undefined;
13302
+ if (response === null || response === void 0 ? void 0 : response.isRetired) return Promise.resolve();
13303
+ var commitResult = function commitResult() {
13304
+ if (!_this.commit(toolCallId, output, messageId, response, expectedMessage)) {
13305
+ return Promise.resolve();
13306
+ }
13307
+ if (response === null || response === void 0 ? void 0 : response.requiredToolCallIds.has(toolCallId)) {
13308
+ response.resolvedToolCallIds.add(toolCallId);
13309
+ }
13310
+ return _this.continueResponse(response);
13311
+ };
13312
+ if (response && (this.activeResponse === response || response.outcome !== 'succeeded' || response.didEvaluateContinuation)) {
13313
+ return commitResult();
13314
+ }
13315
+ return this.jobExecutor.run(commitResult);
13316
+ }
13317
+ },
13318
+ {
13319
+ key: "makeRequest",
13320
+ value: function makeRequest(options) {
13321
+ var _this = this;
13322
+ if (!this.transport) {
13323
+ return Promise.reject(new Error('Transport is required for sending messages. Please provide a transport when initializing the chat.'));
13324
+ }
13325
+ return this.consume(function(abortSignal) {
13326
+ return _this.transport.sendMessages({
13327
+ chatId: _this.id,
13328
+ messages: _this.messages,
13329
+ abortSignal: abortSignal,
13330
+ trigger: options.trigger,
13331
+ messageId: options.messageId,
13332
+ headers: options.headers,
13333
+ body: options.body,
13334
+ requestMetadata: options.metadata
13335
+ });
13336
+ });
13337
+ }
13338
+ },
13339
+ {
13340
+ key: "consume",
13341
+ value: function consume(createStream) {
13342
+ var _this = this;
13343
+ if (this.activeResponse) {
13344
+ this.activeResponse.outcome = 'aborted';
13345
+ this.activeResponse.abortController.abort();
13346
+ }
13347
+ var response = {
13348
+ abortController: new AbortController(),
13349
+ outcome: 'active',
13350
+ isRetired: false,
13351
+ requiredToolCallIds: new Set(),
13352
+ resolvedToolCallIds: new Set(),
13353
+ returnedToolCallbacks: [],
13354
+ pendingToolCallbacks: 0,
13355
+ didNotifyFinish: false,
13356
+ didEvaluateContinuation: false
13357
+ };
13358
+ this.activeResponse = response;
13359
+ this.latestResponse = response;
13360
+ this.setStatus({
13361
+ status: 'submitted'
13362
+ });
13363
+ return createStream(response.abortController.signal).then(function(stream) {
13364
+ if (_this.activeResponse === response) {
13365
+ if (stream) return _this.processStream(stream, response);
13366
+ response.outcome = 'succeeded';
13367
+ _this.activeResponse = null;
13368
+ _this.setStatus({
13369
+ status: 'ready'
13370
+ });
13371
+ }
13372
+ return undefined;
13373
+ }, function(error) {
13374
+ if (_this.activeResponse !== response) return;
13375
+ _this.activeResponse = null;
13376
+ if (error.name === 'AbortError') {
13377
+ response.outcome = 'aborted';
13378
+ _this.setStatus({
13379
+ status: 'ready'
13380
+ });
13381
+ } else {
13382
+ response.outcome = 'failed';
13383
+ _this.handleError(error);
13384
+ }
13385
+ });
13386
+ }
13387
+ },
13388
+ {
13389
+ key: "processStream",
13390
+ value: function processStream1(stream, response) {
13391
+ var _this = this;
13392
+ this.setStatus({
13083
13393
  status: 'streaming'
13084
13394
  });
13085
13395
  var currentMessageId;
13086
13396
  var currentMessage;
13087
13397
  var currentMessageIndex = -1;
13088
13398
  var isAbort = false;
13089
- var isDisconnect = false;
13090
13399
  var isError = false;
13091
- // Track current text/reasoning part state
13092
- var currentTextPartId;
13093
- var currentReasoningPartId;
13094
13400
  var toolRawInputByCallId = {};
13095
13401
  var toolRawOutputByCallId = {};
13096
- // Promise chain for handling tool calls that return promises
13097
- var pendingToolCall = Promise.resolve();
13402
+ var findToolPart = function findToolPart(toolCallId) {
13403
+ return currentMessage.parts.findIndex(function(part) {
13404
+ return 'toolCallId' in part && part.toolCallId === toolCallId;
13405
+ });
13406
+ };
13407
+ var setPart = function setPart(index, part) {
13408
+ var parts = _to_consumable_array(currentMessage.parts);
13409
+ parts[index < 0 ? parts.length : index] = part;
13410
+ currentMessage = _object_spread_props(_object_spread({}, currentMessage), {
13411
+ parts: parts
13412
+ });
13413
+ currentMessage = _this.replaceMessage(currentMessageIndex, currentMessage, response);
13414
+ };
13415
+ var mergeCallProviderMetadata = function mergeCallProviderMetadata(toolCallId, metadata) {
13416
+ var toolIndex = findToolPart(toolCallId);
13417
+ if (toolIndex < 0) return;
13418
+ var existingPart = currentMessage.parts[toolIndex];
13419
+ setPart(toolIndex, _object_spread_props(_object_spread({}, existingPart), {
13420
+ callProviderMetadata: metadata !== null && metadata !== void 0 ? metadata : existingPart.callProviderMetadata
13421
+ }));
13422
+ };
13423
+ var getCanonicalMessage = function getCanonicalMessage() {
13424
+ var _this_messages_find;
13425
+ return response.messageId ? (_this_messages_find = _this.messages.find(function(message) {
13426
+ return message.id === response.messageId;
13427
+ })) !== null && _this_messages_find !== void 0 ? _this_messages_find : currentMessage : currentMessage;
13428
+ };
13429
+ var notifyFinish = function notifyFinish(param) {
13430
+ var isAbort = param.isAbort, isDisconnect = param.isDisconnect, isError = param.isError, message = param.message, _param_allowRetired = param.allowRetired, allowRetired = _param_allowRetired === void 0 ? false : _param_allowRetired;
13431
+ _this.pruneDetachedResponse(response);
13432
+ if (response.isRetired && !allowRetired || response.didNotifyFinish) {
13433
+ return;
13434
+ }
13435
+ response.didNotifyFinish = true;
13436
+ var canonicalMessage = message !== null && message !== void 0 ? message : getCanonicalMessage();
13437
+ if (_this.onFinish && canonicalMessage) {
13438
+ _this.onFinish({
13439
+ message: canonicalMessage,
13440
+ messages: _this.messages,
13441
+ isAbort: isAbort,
13442
+ isDisconnect: isDisconnect,
13443
+ isError: isError
13444
+ });
13445
+ }
13446
+ };
13447
+ var failToolCall = function failToolCall(reason) {
13448
+ if (response.outcome !== 'active') return;
13449
+ var message = getCanonicalMessage();
13450
+ var wasRetired = response.isRetired;
13451
+ var error = _instanceof(reason, Error) ? reason : new Error(String(reason));
13452
+ response.outcome = 'failed';
13453
+ response.abortController.abort();
13454
+ if (_this.activeResponse === response) {
13455
+ _this.activeResponse = null;
13456
+ _this.handleError(error);
13457
+ }
13458
+ notifyFinish({
13459
+ isAbort: false,
13460
+ isDisconnect: false,
13461
+ isError: true,
13462
+ message: message,
13463
+ allowRetired: !wasRetired
13464
+ });
13465
+ };
13466
+ var acceptServerToolResult = function acceptServerToolResult(toolCallId) {
13467
+ if (response.requiredToolCallIds.has(toolCallId)) {
13468
+ response.resolvedToolCallIds.add(toolCallId);
13469
+ }
13470
+ };
13098
13471
  return new Promise(function(resolve) {
13472
+ var finish = function finish(error) {
13473
+ if (response.outcome === 'failed') {
13474
+ resolve();
13475
+ return;
13476
+ }
13477
+ isAbort || (isAbort = response.outcome === 'aborted' || !!error && error.name === 'AbortError');
13478
+ response.outcome = isAbort ? 'aborted' : error ? 'failed' : 'succeeded';
13479
+ if (_this.activeResponse === response) {
13480
+ _this.activeResponse = null;
13481
+ if (error && !isAbort) {
13482
+ _this.handleError(error);
13483
+ } else {
13484
+ _this.setStatus({
13485
+ status: 'ready'
13486
+ });
13487
+ }
13488
+ }
13489
+ notifyFinish({
13490
+ isAbort: isAbort,
13491
+ isDisconnect: !!error && !isAbort,
13492
+ isError: isError
13493
+ });
13494
+ resolve(isAbort || error ? undefined : _this.continueResponse(response));
13495
+ };
13099
13496
  processStream(stream, function(chunk) {
13497
+ if (_this.activeResponse !== response || response.isRetired) return;
13498
+ if (currentMessageId) {
13499
+ var canonicalMessageIndex = _this.messages.findIndex(function(message) {
13500
+ return message.id === currentMessageId;
13501
+ });
13502
+ if (canonicalMessageIndex === -1) {
13503
+ _this.pruneDetachedResponse(response);
13504
+ return;
13505
+ }
13506
+ currentMessageIndex = canonicalMessageIndex;
13507
+ currentMessage = _this.messages[canonicalMessageIndex];
13508
+ _this.responseByMessage.set(currentMessage, response);
13509
+ }
13100
13510
  switch(chunk.type){
13101
13511
  case 'start':
13102
13512
  {
13103
13513
  currentMessageId = chunk.messageId || _this.generateId();
13514
+ response.messageId = currentMessageId;
13104
13515
  // Check if we're continuing an existing message or creating a new one
13105
13516
  var lastMessage = _this.lastMessage;
13106
13517
  if (lastMessage && lastMessage.role === 'assistant' && lastMessage.id === currentMessageId) {
13107
- currentMessage = lastMessage;
13108
- currentMessageIndex = _this.state.messages.length - 1;
13518
+ if (lastMessage.parts.some(function(part) {
13519
+ return 'toolCallId' in part;
13520
+ })) {
13521
+ _this.acceptsIdentifierOnlyToolResults = false;
13522
+ }
13523
+ currentMessage = _object_spread_props(_object_spread({}, lastMessage), {
13524
+ parts: _to_consumable_array(lastMessage.parts)
13525
+ });
13526
+ currentMessageIndex = _this.messages.length - 1;
13527
+ currentMessage = _this.replaceMessage(currentMessageIndex, currentMessage, response);
13109
13528
  } else {
13110
13529
  currentMessage = {
13111
13530
  id: currentMessageId,
@@ -13114,123 +13533,60 @@
13114
13533
  metadata: chunk.messageMetadata
13115
13534
  };
13116
13535
  _this.state.pushMessage(currentMessage);
13117
- currentMessageIndex = _this.state.messages.length - 1;
13536
+ currentMessageIndex = _this.messages.length - 1;
13537
+ _this.responseByMessage.set(currentMessage, response);
13118
13538
  }
13119
13539
  break;
13120
13540
  }
13121
13541
  case 'text-start':
13542
+ case 'reasoning-start':
13122
13543
  {
13123
13544
  if (!currentMessage) break;
13124
- currentTextPartId = chunk.id;
13125
- var textPart = {
13126
- type: 'text',
13545
+ var type = chunk.type === 'text-start' ? 'text' : 'reasoning';
13546
+ setPart(-1, {
13547
+ type: type,
13127
13548
  text: '',
13128
13549
  state: 'streaming',
13129
13550
  providerMetadata: chunk.providerMetadata
13130
- };
13131
- currentMessage = _object_spread_props(_object_spread({}, currentMessage), {
13132
- parts: _to_consumable_array(currentMessage.parts).concat([
13133
- textPart
13134
- ])
13135
13551
  });
13136
- _this.state.replaceMessage(currentMessageIndex, currentMessage);
13137
13552
  break;
13138
13553
  }
13139
13554
  case 'text-delta':
13555
+ case 'reasoning-delta':
13140
13556
  {
13141
- if (!currentMessage || !currentTextPartId) break;
13142
- var partIndex = currentMessage.parts.findIndex(function(p) {
13143
- return p.type === 'text' && p.state === 'streaming';
13557
+ var type1 = chunk.type === 'text-delta' ? 'text' : 'reasoning';
13558
+ if (!currentMessage) break;
13559
+ var partIndex = currentMessage.parts.findIndex(function(part) {
13560
+ return part.type === type1 && part.state === 'streaming';
13144
13561
  });
13145
13562
  if (partIndex === -1) break;
13146
- var updatedParts = _to_consumable_array(currentMessage.parts);
13147
- var textPart1 = updatedParts[partIndex];
13148
- updatedParts[partIndex] = _object_spread_props(_object_spread({}, textPart1), {
13149
- text: textPart1.text + chunk.delta
13150
- });
13151
- currentMessage = _object_spread_props(_object_spread({}, currentMessage), {
13152
- parts: updatedParts
13153
- });
13154
- _this.state.replaceMessage(currentMessageIndex, currentMessage);
13563
+ var part = currentMessage.parts[partIndex];
13564
+ setPart(partIndex, _object_spread_props(_object_spread({}, part), {
13565
+ text: part.text + chunk.delta
13566
+ }));
13155
13567
  break;
13156
13568
  }
13157
13569
  case 'text-end':
13158
- {
13159
- if (!currentMessage) break;
13160
- var partIndex1 = currentMessage.parts.findIndex(function(p) {
13161
- return p.type === 'text' && p.state === 'streaming';
13162
- });
13163
- if (partIndex1 === -1) break;
13164
- var updatedParts1 = _to_consumable_array(currentMessage.parts);
13165
- var textPart2 = updatedParts1[partIndex1];
13166
- updatedParts1[partIndex1] = _object_spread_props(_object_spread({}, textPart2), {
13167
- state: 'done'
13168
- });
13169
- currentMessage = _object_spread_props(_object_spread({}, currentMessage), {
13170
- parts: updatedParts1
13171
- });
13172
- _this.state.replaceMessage(currentMessageIndex, currentMessage);
13173
- currentTextPartId = undefined;
13174
- break;
13175
- }
13176
- case 'reasoning-start':
13177
- {
13178
- if (!currentMessage) break;
13179
- currentReasoningPartId = chunk.id;
13180
- var reasoningPart = {
13181
- type: 'reasoning',
13182
- text: '',
13183
- state: 'streaming',
13184
- providerMetadata: chunk.providerMetadata
13185
- };
13186
- currentMessage = _object_spread_props(_object_spread({}, currentMessage), {
13187
- parts: _to_consumable_array(currentMessage.parts).concat([
13188
- reasoningPart
13189
- ])
13190
- });
13191
- _this.state.replaceMessage(currentMessageIndex, currentMessage);
13192
- break;
13193
- }
13194
- case 'reasoning-delta':
13195
- {
13196
- if (!currentMessage || !currentReasoningPartId) break;
13197
- var partIndex2 = currentMessage.parts.findIndex(function(p) {
13198
- return p.type === 'reasoning' && p.state === 'streaming';
13199
- });
13200
- if (partIndex2 === -1) break;
13201
- var updatedParts2 = _to_consumable_array(currentMessage.parts);
13202
- var reasoningPart1 = updatedParts2[partIndex2];
13203
- updatedParts2[partIndex2] = _object_spread_props(_object_spread({}, reasoningPart1), {
13204
- text: reasoningPart1.text + chunk.delta
13205
- });
13206
- currentMessage = _object_spread_props(_object_spread({}, currentMessage), {
13207
- parts: updatedParts2
13208
- });
13209
- _this.state.replaceMessage(currentMessageIndex, currentMessage);
13210
- break;
13211
- }
13212
13570
  case 'reasoning-end':
13213
13571
  {
13214
13572
  if (!currentMessage) break;
13215
- var partIndex3 = currentMessage.parts.findIndex(function(p) {
13216
- return p.type === 'reasoning' && p.state === 'streaming';
13573
+ var type2 = chunk.type === 'text-end' ? 'text' : 'reasoning';
13574
+ var partIndex1 = currentMessage.parts.findIndex(function(part) {
13575
+ return part.type === type2 && part.state === 'streaming';
13217
13576
  });
13218
- if (partIndex3 === -1) break;
13219
- var updatedParts3 = _to_consumable_array(currentMessage.parts);
13220
- var reasoningPart2 = updatedParts3[partIndex3];
13221
- updatedParts3[partIndex3] = _object_spread_props(_object_spread({}, reasoningPart2), {
13577
+ if (partIndex1 === -1) break;
13578
+ setPart(partIndex1, _object_spread_props(_object_spread({}, currentMessage.parts[partIndex1]), {
13222
13579
  state: 'done'
13223
- });
13224
- currentMessage = _object_spread_props(_object_spread({}, currentMessage), {
13225
- parts: updatedParts3
13226
- });
13227
- _this.state.replaceMessage(currentMessageIndex, currentMessage);
13228
- currentReasoningPartId = undefined;
13580
+ }));
13229
13581
  break;
13230
13582
  }
13231
13583
  case 'tool-input-start':
13232
13584
  {
13233
13585
  if (!currentMessage) break;
13586
+ var completedPart = currentMessage.parts.find(function(part) {
13587
+ return 'toolCallId' in part && part.toolCallId === chunk.toolCallId && 'state' in part && (part.state === 'output-available' || part.state === 'output-error');
13588
+ });
13589
+ if (completedPart) break;
13234
13590
  var initialRawInput = typeof chunk.input === 'string' ? chunk.input : chunk.input !== undefined ? JSON.stringify(chunk.input) : '';
13235
13591
  toolRawInputByCallId[chunk.toolCallId] = initialRawInput;
13236
13592
  var toolPart = {
@@ -13241,12 +13597,7 @@
13241
13597
  rawInput: initialRawInput || undefined,
13242
13598
  providerExecuted: chunk.providerExecuted
13243
13599
  };
13244
- currentMessage = _object_spread_props(_object_spread({}, currentMessage), {
13245
- parts: _to_consumable_array(currentMessage.parts).concat([
13246
- toolPart
13247
- ])
13248
- });
13249
- _this.state.replaceMessage(currentMessageIndex, currentMessage);
13600
+ setPart(-1, toolPart);
13250
13601
  break;
13251
13602
  }
13252
13603
  case 'tool-input-delta':
@@ -13254,16 +13605,17 @@
13254
13605
  var _ref, _ref1, _chunk_toolName, _ref2;
13255
13606
  var _existingPart_type, _this_shouldRepairToolInput, _this1;
13256
13607
  if (!currentMessage) break;
13257
- var toolIndex = currentMessage.parts.findIndex(function(p) {
13258
- return 'toolCallId' in p && p.toolCallId === chunk.toolCallId;
13259
- });
13608
+ var toolIndex = findToolPart(chunk.toolCallId);
13260
13609
  var existingPart = toolIndex >= 0 ? currentMessage.parts[toolIndex] : null;
13610
+ if ((existingPart === null || existingPart === void 0 ? void 0 : existingPart.state) === 'output-available' || (existingPart === null || existingPart === void 0 ? void 0 : existingPart.state) === 'output-error') {
13611
+ break;
13612
+ }
13261
13613
  var previousRawInput = (_ref = (_ref1 = existingPart === null || existingPart === void 0 ? void 0 : existingPart.rawInput) !== null && _ref1 !== void 0 ? _ref1 : toolRawInputByCallId[chunk.toolCallId]) !== null && _ref !== void 0 ? _ref : '';
13262
13614
  var nextRawInput = "".concat(previousRawInput).concat(chunk.inputTextDelta);
13263
13615
  toolRawInputByCallId[chunk.toolCallId] = nextRawInput;
13264
13616
  var toolName = (_chunk_toolName = chunk.toolName) !== null && _chunk_toolName !== void 0 ? _chunk_toolName : existingPart === null || existingPart === void 0 ? void 0 : (_existingPart_type = existingPart.type) === null || _existingPart_type === void 0 ? void 0 : _existingPart_type.replace('tool-', '');
13265
13617
  var shouldRepair = toolName ? (_ref2 = (_this_shouldRepairToolInput = (_this1 = _this).shouldRepairToolInput) === null || _this_shouldRepairToolInput === void 0 ? void 0 : _this_shouldRepairToolInput.call(_this1, toolName)) !== null && _ref2 !== void 0 ? _ref2 : true : true;
13266
- var parsedInput = shouldRepair ? parseToolInputDelta(nextRawInput, existingPart === null || existingPart === void 0 ? void 0 : existingPart.input) : existingPart === null || existingPart === void 0 ? void 0 : existingPart.input;
13618
+ var parsedInput = shouldRepair ? parsePartialJson(nextRawInput, existingPart === null || existingPart === void 0 ? void 0 : existingPart.input) : existingPart === null || existingPart === void 0 ? void 0 : existingPart.input;
13267
13619
  var nextToolPart = _object_spread_props(_object_spread({}, existingPart !== null && existingPart !== void 0 ? existingPart : {
13268
13620
  type: "tool-".concat(chunk.toolName),
13269
13621
  toolCallId: chunk.toolCallId
@@ -13272,30 +13624,20 @@
13272
13624
  input: parsedInput,
13273
13625
  rawInput: nextRawInput
13274
13626
  });
13275
- if (toolIndex >= 0) {
13276
- var updatedParts4 = _to_consumable_array(currentMessage.parts);
13277
- updatedParts4[toolIndex] = nextToolPart;
13278
- currentMessage = _object_spread_props(_object_spread({}, currentMessage), {
13279
- parts: updatedParts4
13280
- });
13281
- } else {
13282
- currentMessage = _object_spread_props(_object_spread({}, currentMessage), {
13283
- parts: _to_consumable_array(currentMessage.parts).concat([
13284
- nextToolPart
13285
- ])
13286
- });
13287
- }
13288
- _this.state.replaceMessage(currentMessageIndex, currentMessage);
13627
+ setPart(toolIndex, nextToolPart);
13289
13628
  break;
13290
13629
  }
13291
13630
  case 'tool-input-available':
13292
13631
  {
13293
13632
  if (!currentMessage) break;
13633
+ if (response.requiredToolCallIds.has(chunk.toolCallId)) break;
13294
13634
  delete toolRawInputByCallId[chunk.toolCallId];
13295
13635
  // Find existing tool part or create new one
13296
- var existingIndex = currentMessage.parts.findIndex(function(p) {
13297
- return 'toolCallId' in p && p.toolCallId === chunk.toolCallId;
13298
- });
13636
+ var existingIndex = findToolPart(chunk.toolCallId);
13637
+ var existingPart1 = existingIndex >= 0 ? currentMessage.parts[existingIndex] : null;
13638
+ if ((existingPart1 === null || existingPart1 === void 0 ? void 0 : existingPart1.state) === 'output-available' || (existingPart1 === null || existingPart1 === void 0 ? void 0 : existingPart1.state) === 'output-error') {
13639
+ break;
13640
+ }
13299
13641
  var toolPart1 = {
13300
13642
  type: "tool-".concat(chunk.toolName),
13301
13643
  toolCallId: chunk.toolCallId,
@@ -13304,35 +13646,63 @@
13304
13646
  callProviderMetadata: chunk.callProviderMetadata,
13305
13647
  providerExecuted: chunk.providerExecuted
13306
13648
  };
13307
- if (existingIndex >= 0) {
13308
- var updatedParts5 = _to_consumable_array(currentMessage.parts);
13309
- updatedParts5[existingIndex] = toolPart1;
13310
- currentMessage = _object_spread_props(_object_spread({}, currentMessage), {
13311
- parts: updatedParts5
13312
- });
13313
- } else {
13314
- currentMessage = _object_spread_props(_object_spread({}, currentMessage), {
13315
- parts: _to_consumable_array(currentMessage.parts).concat([
13316
- toolPart1
13317
- ])
13318
- });
13649
+ setPart(existingIndex, toolPart1);
13650
+ if (_this.messages.some(function(message) {
13651
+ var _message_parts;
13652
+ return message !== currentMessage && ((_message_parts = message.parts) === null || _message_parts === void 0 ? void 0 : _message_parts.some(function(part) {
13653
+ return 'toolCallId' in part && part.toolCallId === chunk.toolCallId;
13654
+ }));
13655
+ })) {
13656
+ _this.acceptsIdentifierOnlyToolResults = false;
13319
13657
  }
13320
- _this.state.replaceMessage(currentMessageIndex, currentMessage);
13321
13658
  // Trigger onToolCall callback only for client-executed tools
13322
13659
  // (server-executed tools have providerExecuted: true and don't need client handling)
13323
13660
  if (_this.onToolCall && !chunk.providerExecuted) {
13324
- var result = _this.onToolCall({
13325
- toolCall: {
13326
- toolName: chunk.toolName,
13327
- toolCallId: chunk.toolCallId,
13328
- input: chunk.input,
13329
- dynamic: 'dynamic' in chunk ? chunk.dynamic : undefined
13330
- }
13661
+ var _this_responsesByToolCallId_get;
13662
+ var owners = (_this_responsesByToolCallId_get = _this.responsesByToolCallId.get(chunk.toolCallId)) !== null && _this_responsesByToolCallId_get !== void 0 ? _this_responsesByToolCallId_get : new Set();
13663
+ var existingOwners = Array.from(owners).filter(function(owner) {
13664
+ return owner !== response;
13331
13665
  });
13332
- if (result && typeof result.then === 'function') {
13333
- pendingToolCall = pendingToolCall.then(function() {
13334
- return result;
13666
+ if (existingOwners.length > 0) {
13667
+ _this.acceptsIdentifierOnlyToolResults = false;
13668
+ var conflictingOwner = existingOwners.find(function(owner) {
13669
+ return !owner.isRetired && (owner.outcome === 'active' || owner.outcome === 'succeeded' && (!owner.resolvedToolCallIds.has(chunk.toolCallId) || owner.pendingToolCallbacks > 0));
13335
13670
  });
13671
+ if (conflictingOwner) {
13672
+ // Neither response may continue once ownership is ambiguous.
13673
+ conflictingOwner.didEvaluateContinuation = true;
13674
+ failToolCall(new Error('Tool call "'.concat(chunk.toolCallId, '" is already owned by another response.')));
13675
+ break;
13676
+ }
13677
+ }
13678
+ response.requiredToolCallIds.add(chunk.toolCallId);
13679
+ owners.add(response);
13680
+ _this.responsesByToolCallId.set(chunk.toolCallId, owners);
13681
+ response.pendingToolCallbacks++;
13682
+ try {
13683
+ var result = _this.onToolCall({
13684
+ toolCall: {
13685
+ toolName: chunk.toolName,
13686
+ toolCallId: chunk.toolCallId,
13687
+ input: chunk.input,
13688
+ dynamic: 'dynamic' in chunk ? chunk.dynamic : undefined
13689
+ }
13690
+ }, function(options) {
13691
+ return response.isRetired ? Promise.resolve() : _this.submitToolResult(response, options);
13692
+ });
13693
+ if (result) {
13694
+ response.returnedToolCallbacks.push(Promise.resolve(result).catch(failToolCall).then(function() {
13695
+ response.pendingToolCallbacks--;
13696
+ _this.pruneDetachedResponse(response);
13697
+ }));
13698
+ } else {
13699
+ response.pendingToolCallbacks--;
13700
+ _this.pruneDetachedResponse(response);
13701
+ }
13702
+ } catch (error) {
13703
+ response.pendingToolCallbacks--;
13704
+ failToolCall(error);
13705
+ _this.pruneDetachedResponse(response);
13336
13706
  }
13337
13707
  }
13338
13708
  break;
@@ -13342,15 +13712,14 @@
13342
13712
  var _ref3, _ref4;
13343
13713
  if (!currentMessage) break;
13344
13714
  var _chunk_data = chunk.data, toolCallId = _chunk_data.toolCallId, toolName1 = _chunk_data.toolName, delta = _chunk_data.delta;
13345
- var toolIndex1 = currentMessage.parts.findIndex(function(p) {
13346
- return 'toolCallId' in p && p.toolCallId === toolCallId;
13347
- });
13348
- var existingPart1 = toolIndex1 >= 0 ? currentMessage.parts[toolIndex1] : null;
13349
- var previousRawOutput = (_ref3 = (_ref4 = existingPart1 === null || existingPart1 === void 0 ? void 0 : existingPart1.rawOutput) !== null && _ref4 !== void 0 ? _ref4 : toolRawOutputByCallId[toolCallId]) !== null && _ref3 !== void 0 ? _ref3 : '';
13715
+ if (response.resolvedToolCallIds.has(toolCallId)) break;
13716
+ var toolIndex1 = findToolPart(toolCallId);
13717
+ var existingPart2 = toolIndex1 >= 0 ? currentMessage.parts[toolIndex1] : null;
13718
+ var previousRawOutput = (_ref3 = (_ref4 = existingPart2 === null || existingPart2 === void 0 ? void 0 : existingPart2.rawOutput) !== null && _ref4 !== void 0 ? _ref4 : toolRawOutputByCallId[toolCallId]) !== null && _ref3 !== void 0 ? _ref3 : '';
13350
13719
  var nextRawOutput = "".concat(previousRawOutput).concat(delta);
13351
13720
  toolRawOutputByCallId[toolCallId] = nextRawOutput;
13352
- var parsedOutput = parseToolInputDelta(nextRawOutput, existingPart1 === null || existingPart1 === void 0 ? void 0 : existingPart1.output);
13353
- var nextToolPart1 = _object_spread_props(_object_spread({}, existingPart1 !== null && existingPart1 !== void 0 ? existingPart1 : {
13721
+ var parsedOutput = parsePartialJson(nextRawOutput, existingPart2 === null || existingPart2 === void 0 ? void 0 : existingPart2.output);
13722
+ var nextToolPart1 = _object_spread_props(_object_spread({}, existingPart2 !== null && existingPart2 !== void 0 ? existingPart2 : {
13354
13723
  type: "tool-".concat(toolName1),
13355
13724
  toolCallId: toolCallId,
13356
13725
  input: undefined
@@ -13360,47 +13729,34 @@
13360
13729
  rawOutput: nextRawOutput,
13361
13730
  preliminary: true
13362
13731
  });
13363
- if (toolIndex1 >= 0) {
13364
- var updatedParts6 = _to_consumable_array(currentMessage.parts);
13365
- updatedParts6[toolIndex1] = nextToolPart1;
13366
- currentMessage = _object_spread_props(_object_spread({}, currentMessage), {
13367
- parts: updatedParts6
13368
- });
13369
- } else {
13370
- currentMessage = _object_spread_props(_object_spread({}, currentMessage), {
13371
- parts: _to_consumable_array(currentMessage.parts).concat([
13372
- nextToolPart1
13373
- ])
13374
- });
13375
- }
13376
- _this.state.replaceMessage(currentMessageIndex, currentMessage);
13732
+ setPart(toolIndex1, nextToolPart1);
13377
13733
  break;
13378
13734
  }
13379
13735
  case 'tool-output-available':
13380
13736
  {
13381
13737
  if (!currentMessage) break;
13382
- var toolIndex2 = currentMessage.parts.findIndex(function(p) {
13383
- return 'toolCallId' in p && p.toolCallId === chunk.toolCallId;
13384
- });
13738
+ var toolIndex2 = findToolPart(chunk.toolCallId);
13385
13739
  if (toolIndex2 >= 0) {
13386
13740
  delete toolRawInputByCallId[chunk.toolCallId];
13387
13741
  delete toolRawOutputByCallId[chunk.toolCallId];
13388
- var updatedParts7 = _to_consumable_array(currentMessage.parts);
13389
- var existingPart2 = updatedParts7[toolIndex2];
13742
+ var existingPart3 = currentMessage.parts[toolIndex2];
13743
+ if (response.resolvedToolCallIds.has(chunk.toolCallId)) {
13744
+ mergeCallProviderMetadata(chunk.toolCallId, chunk.callProviderMetadata);
13745
+ break;
13746
+ }
13390
13747
  // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
13391
- var _ignored = existingPart2.rawOutput, rest = _object_without_properties(existingPart2, [
13748
+ var _ignored = existingPart3.rawOutput, rest = _object_without_properties(existingPart3, [
13392
13749
  "rawOutput"
13393
13750
  ]);
13394
- updatedParts7[toolIndex2] = _object_spread_props(_object_spread({}, rest), {
13751
+ setPart(toolIndex2, _object_spread_props(_object_spread({}, rest), {
13395
13752
  state: 'output-available',
13396
13753
  output: chunk.output,
13397
13754
  callProviderMetadata: chunk.callProviderMetadata,
13398
13755
  preliminary: chunk.preliminary
13399
- });
13400
- currentMessage = _object_spread_props(_object_spread({}, currentMessage), {
13401
- parts: updatedParts7
13402
- });
13403
- _this.state.replaceMessage(currentMessageIndex, currentMessage);
13756
+ }));
13757
+ if (!chunk.preliminary) {
13758
+ acceptServerToolResult(chunk.toolCallId);
13759
+ }
13404
13760
  }
13405
13761
  break;
13406
13762
  }
@@ -13408,13 +13764,15 @@
13408
13764
  {
13409
13765
  var _chunk_input, _chunk_providerExecuted, _chunk_providerMetadata;
13410
13766
  if (!currentMessage) break;
13767
+ if (response.resolvedToolCallIds.has(chunk.toolCallId)) {
13768
+ mergeCallProviderMetadata(chunk.toolCallId, chunk.providerMetadata);
13769
+ break;
13770
+ }
13411
13771
  delete toolRawInputByCallId[chunk.toolCallId];
13412
13772
  delete toolRawOutputByCallId[chunk.toolCallId];
13413
- var toolIndex3 = currentMessage.parts.findIndex(function(p) {
13414
- return 'toolCallId' in p && p.toolCallId === chunk.toolCallId;
13415
- });
13416
- var existingPart3 = toolIndex3 >= 0 ? currentMessage.parts[toolIndex3] : null;
13417
- var _ref5 = existingPart3 !== null && existingPart3 !== void 0 ? existingPart3 : {}, _ignoredOutput = _ref5.output, _ignoredRawOutput = _ref5.rawOutput, _ignoredPreliminary = _ref5.preliminary, carryOver = _object_without_properties(_ref5, [
13773
+ var toolIndex3 = findToolPart(chunk.toolCallId);
13774
+ var existingPart4 = toolIndex3 >= 0 ? currentMessage.parts[toolIndex3] : null;
13775
+ var _ref5 = existingPart4 !== null && existingPart4 !== void 0 ? existingPart4 : {}, _ignoredOutput = _ref5.output, _ignoredRawOutput = _ref5.rawOutput, _ignoredPreliminary = _ref5.preliminary, carryOver = _object_without_properties(_ref5, [
13418
13776
  "output",
13419
13777
  "rawOutput",
13420
13778
  "preliminary"
@@ -13429,49 +13787,35 @@
13429
13787
  providerExecuted: (_chunk_providerExecuted = chunk.providerExecuted) !== null && _chunk_providerExecuted !== void 0 ? _chunk_providerExecuted : carryOver.providerExecuted,
13430
13788
  callProviderMetadata: (_chunk_providerMetadata = chunk.providerMetadata) !== null && _chunk_providerMetadata !== void 0 ? _chunk_providerMetadata : carryOver.callProviderMetadata
13431
13789
  });
13432
- if (toolIndex3 >= 0) {
13433
- var updatedParts8 = _to_consumable_array(currentMessage.parts);
13434
- updatedParts8[toolIndex3] = nextToolPart2;
13435
- currentMessage = _object_spread_props(_object_spread({}, currentMessage), {
13436
- parts: updatedParts8
13437
- });
13438
- } else {
13439
- currentMessage = _object_spread_props(_object_spread({}, currentMessage), {
13440
- parts: _to_consumable_array(currentMessage.parts).concat([
13441
- nextToolPart2
13442
- ])
13443
- });
13444
- }
13445
- _this.state.replaceMessage(currentMessageIndex, currentMessage);
13790
+ setPart(toolIndex3, nextToolPart2);
13791
+ acceptServerToolResult(chunk.toolCallId);
13446
13792
  break;
13447
13793
  }
13448
13794
  case 'tool-output-error':
13449
13795
  {
13450
13796
  var _chunk_providerExecuted1, _chunk_providerMetadata1;
13451
13797
  if (!currentMessage) break;
13452
- var toolIndex4 = currentMessage.parts.findIndex(function(p) {
13453
- return 'toolCallId' in p && p.toolCallId === chunk.toolCallId;
13454
- });
13798
+ if (response.resolvedToolCallIds.has(chunk.toolCallId)) {
13799
+ mergeCallProviderMetadata(chunk.toolCallId, chunk.providerMetadata);
13800
+ break;
13801
+ }
13802
+ var toolIndex4 = findToolPart(chunk.toolCallId);
13455
13803
  if (toolIndex4 < 0) break;
13456
13804
  delete toolRawInputByCallId[chunk.toolCallId];
13457
13805
  delete toolRawOutputByCallId[chunk.toolCallId];
13458
- var updatedParts9 = _to_consumable_array(currentMessage.parts);
13459
- var existingPart4 = updatedParts9[toolIndex4];
13460
- var _ignoredRawOutput1 = existingPart4.rawOutput, _ignoredPreliminary1 = existingPart4.preliminary, _ignoredOutput1 = existingPart4.output, rest1 = _object_without_properties(existingPart4, [
13806
+ var existingPart5 = currentMessage.parts[toolIndex4];
13807
+ var _ignoredRawOutput1 = existingPart5.rawOutput, _ignoredPreliminary1 = existingPart5.preliminary, _ignoredOutput1 = existingPart5.output, rest1 = _object_without_properties(existingPart5, [
13461
13808
  "rawOutput",
13462
13809
  "preliminary",
13463
13810
  "output"
13464
13811
  ]);
13465
- updatedParts9[toolIndex4] = _object_spread_props(_object_spread({}, rest1), {
13812
+ setPart(toolIndex4, _object_spread_props(_object_spread({}, rest1), {
13466
13813
  state: 'output-error',
13467
13814
  errorText: chunk.errorText,
13468
13815
  providerExecuted: (_chunk_providerExecuted1 = chunk.providerExecuted) !== null && _chunk_providerExecuted1 !== void 0 ? _chunk_providerExecuted1 : rest1.providerExecuted,
13469
13816
  callProviderMetadata: (_chunk_providerMetadata1 = chunk.providerMetadata) !== null && _chunk_providerMetadata1 !== void 0 ? _chunk_providerMetadata1 : rest1.callProviderMetadata
13470
- });
13471
- currentMessage = _object_spread_props(_object_spread({}, currentMessage), {
13472
- parts: updatedParts9
13473
- });
13474
- _this.state.replaceMessage(currentMessageIndex, currentMessage);
13817
+ }));
13818
+ acceptServerToolResult(chunk.toolCallId);
13475
13819
  break;
13476
13820
  }
13477
13821
  case 'source-url':
@@ -13483,12 +13827,7 @@
13483
13827
  url: chunk.url,
13484
13828
  title: chunk.title
13485
13829
  };
13486
- currentMessage = _object_spread_props(_object_spread({}, currentMessage), {
13487
- parts: _to_consumable_array(currentMessage.parts).concat([
13488
- sourcePart
13489
- ])
13490
- });
13491
- _this.state.replaceMessage(currentMessageIndex, currentMessage);
13830
+ setPart(-1, sourcePart);
13492
13831
  break;
13493
13832
  }
13494
13833
  case 'source-document':
@@ -13502,12 +13841,7 @@
13502
13841
  filename: chunk.filename,
13503
13842
  providerMetadata: chunk.providerMetadata
13504
13843
  };
13505
- currentMessage = _object_spread_props(_object_spread({}, currentMessage), {
13506
- parts: _to_consumable_array(currentMessage.parts).concat([
13507
- docPart
13508
- ])
13509
- });
13510
- _this.state.replaceMessage(currentMessageIndex, currentMessage);
13844
+ setPart(-1, docPart);
13511
13845
  break;
13512
13846
  }
13513
13847
  case 'file':
@@ -13518,26 +13852,15 @@
13518
13852
  url: chunk.url,
13519
13853
  mediaType: chunk.mediaType
13520
13854
  };
13521
- currentMessage = _object_spread_props(_object_spread({}, currentMessage), {
13522
- parts: _to_consumable_array(currentMessage.parts).concat([
13523
- filePart
13524
- ])
13525
- });
13526
- _this.state.replaceMessage(currentMessageIndex, currentMessage);
13855
+ setPart(-1, filePart);
13527
13856
  break;
13528
13857
  }
13529
13858
  case 'start-step':
13530
13859
  {
13531
13860
  if (!currentMessage) break;
13532
- var stepPart = {
13861
+ setPart(-1, {
13533
13862
  type: 'step-start'
13534
- };
13535
- currentMessage = _object_spread_props(_object_spread({}, currentMessage), {
13536
- parts: _to_consumable_array(currentMessage.parts).concat([
13537
- stepPart
13538
- ])
13539
13863
  });
13540
- _this.state.replaceMessage(currentMessageIndex, currentMessage);
13541
13864
  break;
13542
13865
  }
13543
13866
  case 'message-metadata':
@@ -13546,7 +13869,7 @@
13546
13869
  currentMessage = _object_spread_props(_object_spread({}, currentMessage), {
13547
13870
  metadata: chunk.messageMetadata
13548
13871
  });
13549
- _this.state.replaceMessage(currentMessageIndex, currentMessage);
13872
+ currentMessage = _this.replaceMessage(currentMessageIndex, currentMessage, response);
13550
13873
  break;
13551
13874
  }
13552
13875
  case 'error':
@@ -13566,7 +13889,7 @@
13566
13889
  currentMessage = _object_spread_props(_object_spread({}, currentMessage), {
13567
13890
  metadata: chunk.messageMetadata
13568
13891
  });
13569
- _this.state.replaceMessage(currentMessageIndex, currentMessage);
13892
+ currentMessage = _this.replaceMessage(currentMessageIndex, currentMessage, response);
13570
13893
  }
13571
13894
  break;
13572
13895
  }
@@ -13592,14 +13915,13 @@
13592
13915
  ]
13593
13916
  };
13594
13917
  if (currentMessageIndex >= 0) {
13595
- _this.state.replaceMessage(currentMessageIndex, currentMessage);
13918
+ currentMessage = _this.replaceMessage(currentMessageIndex, currentMessage, response);
13596
13919
  } else {
13597
13920
  _this.state.pushMessage(currentMessage);
13598
- currentMessageIndex = _this.state.messages.length - 1;
13921
+ currentMessageIndex = _this.messages.length - 1;
13922
+ _this.responseByMessage.set(currentMessage, response);
13599
13923
  }
13600
13924
  currentMessageId = currentMessage.id;
13601
- currentTextPartId = undefined;
13602
- currentReasoningPartId = undefined;
13603
13925
  break;
13604
13926
  }
13605
13927
  default:
@@ -13612,12 +13934,7 @@
13612
13934
  id: chunk.id,
13613
13935
  data: chunk.data
13614
13936
  };
13615
- currentMessage = _object_spread_props(_object_spread({}, currentMessage), {
13616
- parts: _to_consumable_array(currentMessage.parts).concat([
13617
- dataPart
13618
- ])
13619
- });
13620
- _this.state.replaceMessage(currentMessageIndex, currentMessage);
13937
+ setPart(-1, dataPart);
13621
13938
  // Trigger onData callback
13622
13939
  if (_this.onData) {
13623
13940
  _this.onData(dataPart);
@@ -13626,49 +13943,11 @@
13626
13943
  }
13627
13944
  }
13628
13945
  }, function() {
13629
- // Wait for any pending tool calls to complete
13630
- pendingToolCall.then(function() {
13631
- // Stream finished successfully
13632
- _this.setStatus({
13633
- status: 'ready'
13634
- });
13635
- _this.activeResponse = null;
13636
- // Trigger onFinish callback
13637
- if (_this.onFinish && currentMessage) {
13638
- _this.onFinish({
13639
- message: currentMessage,
13640
- messages: _this.state.messages,
13641
- isAbort: isAbort,
13642
- isDisconnect: isDisconnect,
13643
- isError: isError
13644
- });
13645
- }
13646
- // Note: sendAutomaticallyWhen is only checked in addToolResult,
13647
- // not here. For server-executed tools, the server continues the
13648
- // conversation. For client-executed tools, addToolResult handles it.
13649
- resolve();
13946
+ return Promise.all(response.returnedToolCallbacks).then(function() {
13947
+ return finish();
13650
13948
  });
13651
13949
  }, function(error) {
13652
- if (error.name === 'AbortError') {
13653
- isAbort = true;
13654
- _this.setStatus({
13655
- status: 'ready'
13656
- });
13657
- } else {
13658
- isDisconnect = true;
13659
- _this.handleError(error);
13660
- }
13661
- // Still call onFinish even on error/abort
13662
- if (_this.onFinish && currentMessage) {
13663
- _this.onFinish({
13664
- message: currentMessage,
13665
- messages: _this.state.messages,
13666
- isAbort: isAbort,
13667
- isDisconnect: isDisconnect,
13668
- isError: isError
13669
- });
13670
- }
13671
- resolve();
13950
+ return finish(error);
13672
13951
  });
13673
13952
  });
13674
13953
  }
@@ -13676,10 +13955,13 @@
13676
13955
  {
13677
13956
  key: "handleError",
13678
13957
  value: function handleError(error) {
13679
- this.setStatus({
13680
- status: 'error',
13681
- error: error
13682
- });
13958
+ var _ref = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {}, _ref_updateState = _ref.updateState, updateState = _ref_updateState === void 0 ? true : _ref_updateState;
13959
+ if (updateState) {
13960
+ this.setStatus({
13961
+ status: 'error',
13962
+ error: error
13963
+ });
13964
+ }
13683
13965
  if (this.onError) {
13684
13966
  this.onError(error);
13685
13967
  }
@@ -13726,9 +14008,25 @@
13726
14008
 
13727
14009
  var _computedKey, _computedKey1, _computedKey2, _computedKey3, _computedKey4, _computedKey5;
13728
14010
  var CACHE_KEY = 'instantsearch-chat-initial-messages';
14011
+ // Message history is a browser concern, and a server render constructs a Chat
14012
+ // too. Reading storage there throws during rendering; the write below only
14013
+ // throws into its own `catch`, so gating it just stops a pointless attempt.
13729
14014
  function getDefaultInitialMessages(id) {
13730
- var initialMessages = sessionStorage.getItem(CACHE_KEY + (id ? "-".concat(id) : ''));
13731
- return initialMessages ? JSON.parse(initialMessages) : [];
14015
+ return safelyRunOnBrowser(function() {
14016
+ try {
14017
+ // `sessionStorage` is not available in every environment with a
14018
+ // `window` (e.g. React Native), and some browsers throw on access
14019
+ // when storage is disabled.
14020
+ var initialMessages = sessionStorage.getItem(CACHE_KEY + (id ? "-".concat(id) : ''));
14021
+ return initialMessages ? JSON.parse(initialMessages) : [];
14022
+ } catch (e) {
14023
+ return [];
14024
+ }
14025
+ }, {
14026
+ fallback: function fallback() {
14027
+ return [];
14028
+ }
14029
+ });
13732
14030
  }
13733
14031
  _computedKey = '~registerMessagesCallback', _computedKey1 = '~registerStatusCallback', _computedKey2 = '~registerErrorCallback';
13734
14032
  var _computedKey6 = _computedKey, _computedKey7 = _computedKey1, _computedKey8 = _computedKey2;
@@ -13807,11 +14105,13 @@
13807
14105
  }
13808
14106
  var saveMessagesInLocalStorage = function saveMessagesInLocalStorage() {
13809
14107
  if (_this.status === 'ready') {
13810
- try {
13811
- sessionStorage.setItem(CACHE_KEY + (id ? "-".concat(id) : ''), JSON.stringify(_this.messages));
13812
- } catch (e) {
13813
- // Do nothing if sessionStorage is not available or full
13814
- }
14108
+ safelyRunOnBrowser(function() {
14109
+ try {
14110
+ sessionStorage.setItem(CACHE_KEY + (id ? "-".concat(id) : ''), JSON.stringify(_this.messages));
14111
+ } catch (e) {
14112
+ // Do nothing if sessionStorage is not available or full
14113
+ }
14114
+ });
13815
14115
  }
13816
14116
  };
13817
14117
  this['~registerMessagesCallback'](saveMessagesInLocalStorage);
@@ -13887,7 +14187,7 @@
13887
14187
  // it is non-empty and the chat is not already processing a message.
13888
14188
  // Returns true when a message was submitted, so callers can clear their input.
13889
14189
  function openChat(chatRenderState) {
13890
- var _ref = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {}, message = _ref.message, referer = _ref.referer;
14190
+ var _ref = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {}, message = _ref.message, referer = _ref.referer, turnContext = _ref.turnContext;
13891
14191
  var _ref1;
13892
14192
  var _chatRenderState_setOpen;
13893
14193
  if (!chatRenderState) {
@@ -13903,9 +14203,13 @@
13903
14203
  if (isChatBusy(chatRenderState) || !chatRenderState.sendMessage) {
13904
14204
  return false;
13905
14205
  }
13906
- chatRenderState.sendMessage({
14206
+ chatRenderState.sendMessage(_object_spread({
13907
14207
  text: trimmed
13908
- }, referer ? {
14208
+ }, turnContext ? {
14209
+ metadata: {
14210
+ turnContext: turnContext
14211
+ }
14212
+ } : {}), referer ? {
13909
14213
  headers: {
13910
14214
  'x-algolia-referer': referer
13911
14215
  }
@@ -14114,7 +14418,7 @@
14114
14418
  return DefaultChatTransport;
14115
14419
  }(HttpChatTransport);
14116
14420
 
14117
- var withUsage$o = createDocumentationMessageGenerator({
14421
+ var withUsage$q = createDocumentationMessageGenerator({
14118
14422
  name: 'chat',
14119
14423
  connector: true
14120
14424
  });
@@ -14135,26 +14439,36 @@
14135
14439
  attributesToClear: attributesToClear
14136
14440
  }));
14137
14441
  if (params.facetFilters) {
14138
- var attributes = flat(params.facetFilters).map(function(filter) {
14139
- var _filter_split = _sliced_to_array(filter.split(':'), 2), attribute = _filter_split[0], value = _filter_split[1];
14140
- return {
14141
- attribute: attribute,
14142
- value: value
14143
- };
14144
- });
14145
- attributes.forEach(function(param) {
14442
+ var refinements = flat(params.facetFilters).reduce(function(acc, filter) {
14443
+ var separatorIndex = filter.indexOf(':');
14444
+ if (separatorIndex > 0) {
14445
+ acc.push({
14446
+ attribute: filter.slice(0, separatorIndex),
14447
+ value: filter.slice(separatorIndex + 1)
14448
+ });
14449
+ }
14450
+ return acc;
14451
+ }, []);
14452
+ var hierarchicalRefinements = new Map();
14453
+ refinements.forEach(function(param) {
14146
14454
  var attribute = param.attribute, value = param.value;
14147
- if (!helper.state.isConjunctiveFacet(attribute) && !helper.state.isHierarchicalFacet(attribute) && !helper.state.isDisjunctiveFacet(attribute)) {
14148
- var s = helper.state.addDisjunctiveFacet(attribute);
14149
- helper.setState(s);
14150
- helper.toggleFacetRefinement(attribute, value);
14151
- } else {
14152
- var _helper_state_hierarchicalFacets_find;
14153
- var attr = ((_helper_state_hierarchicalFacets_find = helper.state.hierarchicalFacets.find(function(facet) {
14154
- return facet.name === attribute;
14155
- })) === null || _helper_state_hierarchicalFacets_find === void 0 ? void 0 : _helper_state_hierarchicalFacets_find.name) || attribute;
14156
- helper.toggleFacetRefinement(attr, value);
14455
+ var hierarchicalFacet = helper.state.hierarchicalFacets.find(function(facet) {
14456
+ return facet.name === attribute || facet.attributes.includes(attribute);
14457
+ });
14458
+ if (hierarchicalFacet) {
14459
+ var currentValue = hierarchicalRefinements.get(hierarchicalFacet.name);
14460
+ if (currentValue === undefined || value.length > currentValue.length) {
14461
+ hierarchicalRefinements.set(hierarchicalFacet.name, value);
14462
+ }
14463
+ return;
14464
+ }
14465
+ if (!helper.state.isConjunctiveFacet(attribute) && !helper.state.isDisjunctiveFacet(attribute)) {
14466
+ helper.setState(helper.state.addDisjunctiveFacet(attribute));
14157
14467
  }
14468
+ helper.toggleFacetRefinement(attribute, value);
14469
+ });
14470
+ hierarchicalRefinements.forEach(function(value, name) {
14471
+ helper.toggleFacetRefinement(name, value);
14158
14472
  });
14159
14473
  }
14160
14474
  if (params.query) {
@@ -14165,7 +14479,7 @@
14165
14479
  }
14166
14480
  var connectChat = function connectChat(renderFn) {
14167
14481
  var unmountFn = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : noop;
14168
- checkRendering(renderFn, withUsage$o());
14482
+ checkRendering(renderFn, withUsage$q());
14169
14483
  return function(widgetParams) {
14170
14484
  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, 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, [
14171
14485
  "resume",
@@ -14243,6 +14557,11 @@
14243
14557
  hasValidatedEntryPoints = true;
14244
14558
  };
14245
14559
  var makeChatInstance = function makeChatInstance(instantSearchInstance) {
14560
+ // A caller supplied `chat` already owns its transport, so it bypasses the
14561
+ // connector's transport construction and validation below.
14562
+ if ('chat' in options) {
14563
+ return options.chat;
14564
+ }
14246
14565
  var transport;
14247
14566
  var client = instantSearchInstance.client;
14248
14567
  var _getAppIdAndApiKey = _sliced_to_array(getAppIdAndApiKey(client), 2), appId = _getAppIdAndApiKey[0], apiKey = _getAppIdAndApiKey[1];
@@ -14292,7 +14611,7 @@
14292
14611
  if ('agentId' in options && options.agentId) {
14293
14612
  var _options_requestOptions, _options_requestOptions1;
14294
14613
  if (!appId || !apiKey) {
14295
- throw new Error(withUsage$o('Could not extract Algolia credentials from the search client.'));
14614
+ throw new Error(withUsage$q('Could not extract Algolia credentials from the search client.'));
14296
14615
  }
14297
14616
  var createApi = function createApi() {
14298
14617
  var bypassCache = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : false;
@@ -14309,7 +14628,7 @@
14309
14628
  var baseApi = createApi();
14310
14629
  transport = new DefaultChatTransport({
14311
14630
  api: baseApi,
14312
- headers: _object_spread_props(_object_spread({}, _instanceof((_options_requestOptions = options.requestOptions) === null || _options_requestOptions === void 0 ? void 0 : _options_requestOptions.headers, Headers) ? Object.fromEntries(options.requestOptions.headers.entries()) : (_options_requestOptions1 = options.requestOptions) === null || _options_requestOptions1 === void 0 ? void 0 : _options_requestOptions1.headers), {
14631
+ headers: _object_spread_props(_object_spread({}, typeof Headers !== 'undefined' && _instanceof((_options_requestOptions = options.requestOptions) === null || _options_requestOptions === void 0 ? void 0 : _options_requestOptions.headers, Headers) ? Object.fromEntries(options.requestOptions.headers.entries()) : (_options_requestOptions1 = options.requestOptions) === null || _options_requestOptions1 === void 0 ? void 0 : _options_requestOptions1.headers), {
14313
14632
  // Preserve the required Algolia identity headers and chat agent
14314
14633
  // marker, even when requestOptions.headers contains the same keys.
14315
14634
  'x-algolia-application-id': appId,
@@ -14331,10 +14650,7 @@
14331
14650
  });
14332
14651
  }
14333
14652
  if (!transport) {
14334
- throw new Error(withUsage$o('You need to provide either an `agentId` or a `transport`.'));
14335
- }
14336
- if ('chat' in options) {
14337
- return options.chat;
14653
+ throw new Error(withUsage$q('You need to provide either an `agentId` or a `transport`.'));
14338
14654
  }
14339
14655
  return new Chat(_object_spread_props(_object_spread({}, options), {
14340
14656
  sendAutomaticallyWhen: sendAutomaticallyWhen,
@@ -14347,7 +14663,7 @@
14347
14663
  if (!tool) return true;
14348
14664
  return Boolean(tool.streamInput);
14349
14665
  },
14350
- onToolCall: function onToolCall(param) {
14666
+ onToolCall: function onToolCall(param, submitToolResult) {
14351
14667
  var toolCall = param.toolCall;
14352
14668
  var tool = tools[toolCall.toolName];
14353
14669
  // Compatibility shim with Algolia MCP Server search tool
@@ -14355,7 +14671,7 @@
14355
14671
  tool = tools[SearchIndexToolType];
14356
14672
  }
14357
14673
  if (!tool) {
14358
- return _chatInstance.addToolResult({
14674
+ return submitToolResult({
14359
14675
  output: 'No tool implemented for "'.concat(toolCall.toolName, '".'),
14360
14676
  tool: toolCall.toolName,
14361
14677
  toolCallId: toolCall.toolCallId
@@ -14364,7 +14680,7 @@
14364
14680
  if (tool.onToolCall) {
14365
14681
  var addToolResult = function addToolResult(param) {
14366
14682
  var output = param.output;
14367
- return _chatInstance.addToolResult({
14683
+ return submitToolResult({
14368
14684
  output: output,
14369
14685
  tool: toolCall.toolName,
14370
14686
  toolCallId: toolCall.toolCallId
@@ -14414,7 +14730,7 @@
14414
14730
  if (agentId && feedback) {
14415
14731
  var _getAppIdAndApiKey = _sliced_to_array(getAppIdAndApiKey(initOptions.instantSearchInstance.client), 2), appId = _getAppIdAndApiKey[0], apiKey = _getAppIdAndApiKey[1];
14416
14732
  if (!appId || !apiKey) {
14417
- throw new Error(withUsage$o('Could not extract Algolia credentials from the search client.'));
14733
+ throw new Error(withUsage$q('Could not extract Algolia credentials from the search client.'));
14418
14734
  }
14419
14735
  feedbackAbortController = new AbortController();
14420
14736
  _sendChatMessageFeedback = function _sendChatMessageFeedback(messageId, vote) {
@@ -14435,21 +14751,32 @@
14435
14751
  }
14436
14752
  var hasExistingMessages = _chatInstance.messages.length > 0;
14437
14753
  // Set initialMessages before registering callbacks to avoid
14438
- // triggering re-renders during init
14439
- if ((initialMessages === null || initialMessages === void 0 ? void 0 : initialMessages.length) && !resume && !hasExistingMessages) {
14440
- _chatInstance.messages = initialMessages;
14441
- }
14442
- _chatInstance['~registerErrorCallback'](render);
14443
- _chatInstance['~registerMessagesCallback'](render);
14444
- _chatInstance['~registerStatusCallback'](render);
14445
- if (resume) {
14446
- _chatInstance.resumeStream();
14447
- }
14448
- if (initialUserMessage && !resume && !hasExistingMessages) {
14449
- _chatInstance.sendMessage({
14450
- text: initialUserMessage
14451
- });
14452
- }
14754
+ // triggering re-renders during init. A server render owns no
14755
+ // conversation, so it leaves the instance empty.
14756
+ safelyRunOnBrowser(function() {
14757
+ if ((initialMessages === null || initialMessages === void 0 ? void 0 : initialMessages.length) && !resume && !hasExistingMessages) {
14758
+ _chatInstance.messages = initialMessages;
14759
+ }
14760
+ });
14761
+ safelyRunOnBrowser(function() {
14762
+ _chatInstance['~registerErrorCallback'](render);
14763
+ _chatInstance['~registerMessagesCallback'](render);
14764
+ _chatInstance['~registerStatusCallback'](render);
14765
+ });
14766
+ // Resuming and sending reach the network, which a server render must
14767
+ // not: the HTML pass repeats what `getServerState` already rendered, so
14768
+ // each send happens at least twice, and each failure resolves into chat
14769
+ // state well after the render that started it has finished.
14770
+ safelyRunOnBrowser(function() {
14771
+ if (resume) {
14772
+ _chatInstance.resumeStream();
14773
+ }
14774
+ if (initialUserMessage && !resume && !hasExistingMessages) {
14775
+ _chatInstance.sendMessage({
14776
+ text: initialUserMessage
14777
+ });
14778
+ }
14779
+ });
14453
14780
  renderFn(_object_spread_props(_object_spread({}, this.getWidgetRenderState(initOptions)), {
14454
14781
  instantSearchInstance: instantSearchInstance
14455
14782
  }), true);
@@ -14481,13 +14808,19 @@
14481
14808
  function applyFilters(params) {
14482
14809
  return updateStateFromSearchToolInput(params, helper);
14483
14810
  }
14811
+ var insightsEventContext = {
14812
+ agentId: agentId,
14813
+ instantSearchStatus: instantSearchInstance.status
14814
+ };
14484
14815
  var toolsWithAddToolResult = {};
14485
14816
  Object.entries(tools).forEach(function(param) {
14486
14817
  var _param = _sliced_to_array(param, 2), key = _param[0], tool = _param[1];
14487
14818
  var toolWithAddToolResult = _object_spread_props(_object_spread({}, tool), {
14488
14819
  addToolResult: _chatInstance.addToolResult,
14820
+ '~addToolResultForMessage': _chatInstance['~addToolResultForMessage'],
14489
14821
  applyFilters: applyFilters,
14490
- sendEvent: sendEvent
14822
+ sendEvent: sendEvent,
14823
+ insightsEventContext: insightsEventContext
14491
14824
  });
14492
14825
  toolsWithAddToolResult[key] = toolWithAddToolResult;
14493
14826
  });
@@ -14556,8 +14889,625 @@
14556
14889
  };
14557
14890
  };
14558
14891
 
14892
+ var subscribe = function subscribe() {
14893
+ return function() {};
14894
+ };
14895
+ var getClientSnapshot = function getClientSnapshot() {
14896
+ return true;
14897
+ };
14898
+ var getServerSnapshot = function getServerSnapshot() {
14899
+ return false;
14900
+ };
14901
+ function useNativeIsHydrated() {
14902
+ return React__namespace.useSyncExternalStore(subscribe, getClientSnapshot, getServerSnapshot);
14903
+ }
14904
+ // React 16 and 17 have no `useSyncExternalStore`, so the flip waits for an
14905
+ // effect and the render itself cannot tell hydration from a plain mount. These
14906
+ // contexts provide that signal for the supported `getServerState` and
14907
+ // `InstantSearchSSRProvider` flow: the server context covers state collection,
14908
+ // and the SSR context covers HTML rendering and hydration.
14909
+ //
14910
+ // This can cost an extra render: a mount inside a provider that carries server
14911
+ // state is withheld once even when there is no server markup to reproduce. A
14912
+ // mount outside both contexts is never withheld.
14913
+ //
14914
+ // The shim's React 16 and 17 fallback ignores the server snapshot, so using it
14915
+ // here would not change this limitation.
14916
+ function useLegacyIsHydrated() {
14917
+ var serverContext = useInstantSearchServerContext();
14918
+ var ssrContext = useInstantSearchSSRContext();
14919
+ var isServerRendered = serverContext !== null || ssrContext !== null;
14920
+ var _React_useState = _sliced_to_array(React__namespace.useState(!isServerRendered), 2), isHydrated = _React_useState[0], setIsHydrated = _React_useState[1];
14921
+ React__namespace.useEffect(function() {
14922
+ setIsHydrated(true);
14923
+ }, []);
14924
+ return isHydrated;
14925
+ }
14926
+ /**
14927
+ * Whether this render can use browser state, or has to reproduce the markup a
14928
+ * server produced without it.
14929
+ *
14930
+ * @internal
14931
+ */ var useIsHydrated = typeof React__namespace.useSyncExternalStore === 'function' ? useNativeIsHydrated : useLegacyIsHydrated;
14932
+
14559
14933
  function useChat(props, additionalWidgetProperties) {
14560
- return useConnector(connectChat, props, additionalWidgetProperties);
14934
+ var isHydrated = useIsHydrated();
14935
+ var chatState = useConnector(connectChat, props, additionalWidgetProperties);
14936
+ if (isHydrated) {
14937
+ return chatState;
14938
+ }
14939
+ // Server rendering only promises the closed Chat shell, so a render that has
14940
+ // to reproduce that markup shows no conversation either. `status` is pinned
14941
+ // with `messages` because it diverges two ways: a server render suppresses
14942
+ // `resumeStream()`, which the browser runs synchronously while initialising,
14943
+ // and a caller-owned chat can already be streaming. `error` is pinned because
14944
+ // a caller-owned chat can already have failed, which a connector-built one
14945
+ // cannot, since its failures arrive in a microtask. `suggestions` is pinned
14946
+ // because the connector derives them from those messages. Only an `id` given
14947
+ // as a connector option passes through, because that value is the same on
14948
+ // both sides. Anything else is withheld: the default is random per Chat, and
14949
+ // an `id` carried by a caller-owned instance is no safer, since the server and
14950
+ // the browser each construct their own.
14951
+ return _object_spread_props(_object_spread({}, chatState), {
14952
+ error: undefined,
14953
+ id: 'id' in props && props.id || '',
14954
+ messages: [],
14955
+ status: 'ready',
14956
+ suggestions: undefined
14957
+ });
14958
+ }
14959
+
14960
+ function buildEndpoint(param) {
14961
+ var appId = param.appId, agentId = param.agentId;
14962
+ return "https://".concat(appId, ".algolia.net/agent-studio/1/agents/").concat(agentId, "/tasks");
14963
+ }
14964
+ function resolveEndpoint(params) {
14965
+ if (params.transport) {
14966
+ return {
14967
+ endpoint: params.transport.api,
14968
+ headers: params.transport.headers || {},
14969
+ prepareSendMessagesRequest: params.transport.prepareSendMessagesRequest
14970
+ };
14971
+ }
14972
+ if (!params.appId || !params.apiKey || !params.agentId) {
14973
+ throw new Error('[tasks] Either `transport` or `{ appId, apiKey, agentId }` is required.');
14974
+ }
14975
+ var headers = {
14976
+ 'x-algolia-application-id': params.appId,
14977
+ 'x-algolia-api-key': params.apiKey
14978
+ };
14979
+ if (params.algoliaAgent) {
14980
+ headers['x-algolia-agent'] = "".concat(params.algoliaAgent, "; tasks");
14981
+ }
14982
+ return {
14983
+ endpoint: buildEndpoint({
14984
+ appId: params.appId,
14985
+ agentId: params.agentId
14986
+ }),
14987
+ headers: headers
14988
+ };
14989
+ }
14990
+
14991
+ function buildTaskPayload(param) {
14992
+ var task = param.task, input = param.input, prepareRequest = param.prepareRequest;
14993
+ var payload = {
14994
+ task: task,
14995
+ input: input
14996
+ };
14997
+ return prepareRequest ? prepareRequest(payload).body : payload;
14998
+ }
14999
+ function withStreamParam(url) {
15000
+ return url.includes('?') ? "".concat(url, "&stream=true") : "".concat(url, "?stream=true");
15001
+ }
15002
+ function resolveStreamedOutput(data, previous) {
15003
+ return typeof data === 'string' ? parsePartialJson(data, previous) : data;
15004
+ }
15005
+ function consumeTaskStream(body, onData) {
15006
+ return new Promise(function(resolve, reject) {
15007
+ var chunkStream = parseJsonEventStream(body);
15008
+ var latest;
15009
+ processStream(chunkStream, function(chunk) {
15010
+ if (!chunk) {
15011
+ return;
15012
+ }
15013
+ // A terminal `error` event aborts the task: reject rather than let the
15014
+ // stream close and resolve the last partial snapshot as a success.
15015
+ // Throwing here lets `processStream` release the reader and stop
15016
+ // consuming; the rejection propagates to the caller's `.catch`.
15017
+ if (chunk.type === 'error') {
15018
+ throw new Error(chunk.errorText || 'Task stream error');
15019
+ }
15020
+ if (chunk.type !== 'data-task-output') {
15021
+ return;
15022
+ }
15023
+ latest = resolveStreamedOutput(chunk.data, latest);
15024
+ if (onData) {
15025
+ onData(latest);
15026
+ }
15027
+ }, function() {
15028
+ return resolve(latest);
15029
+ }, reject);
15030
+ });
15031
+ }
15032
+ function fetchTask(param) {
15033
+ 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;
15034
+ return fetch(stream ? withStreamParam(endpoint) : endpoint, {
15035
+ method: 'POST',
15036
+ headers: _object_spread_props(_object_spread({}, headers), {
15037
+ 'Content-Type': 'application/json'
15038
+ }),
15039
+ body: JSON.stringify(payload)
15040
+ }).then(function(response) {
15041
+ var _response_headers_get, _response_headers;
15042
+ if (!response.ok) {
15043
+ throw new Error("HTTP error ".concat(response.status));
15044
+ }
15045
+ 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')) || '';
15046
+ if (stream && response.body && contentType.includes('text/event-stream')) {
15047
+ return consumeTaskStream(response.body, onData);
15048
+ }
15049
+ return response.json();
15050
+ });
15051
+ }
15052
+ function unwrap(envelope) {
15053
+ return envelope === null || envelope === void 0 ? void 0 : envelope.output;
15054
+ }
15055
+ function createTaskRunner(param) {
15056
+ 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;
15057
+ return {
15058
+ submit: function submit(variables) {
15059
+ var onData = (arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {}).onData;
15060
+ var payload = buildTaskPayload({
15061
+ task: task,
15062
+ input: variables,
15063
+ prepareRequest: prepareRequest
15064
+ });
15065
+ return fetchTask({
15066
+ endpoint: endpoint,
15067
+ headers: headers,
15068
+ payload: payload,
15069
+ stream: stream,
15070
+ onData: onData ? function(partial) {
15071
+ return onData(unwrap(partial));
15072
+ } : undefined
15073
+ }).then(unwrap);
15074
+ }
15075
+ };
15076
+ }
15077
+
15078
+ var withUsage$p = createDocumentationMessageGenerator({
15079
+ name: 'tasks',
15080
+ connector: true
15081
+ });
15082
+ var connectTasks = function connectTasks(renderFn) {
15083
+ var unmountFn = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : noop;
15084
+ checkRendering(renderFn, withUsage$p());
15085
+ return function(widgetParams) {
15086
+ var agentId = widgetParams.agentId, transport = widgetParams.transport, task = widgetParams.task, _widgetParams_stream = widgetParams.stream, stream = _widgetParams_stream === void 0 ? true : _widgetParams_stream;
15087
+ if (!agentId && !transport) {
15088
+ throw new Error(withUsage$p('The `agentId` option is required unless a custom `transport` is provided.'));
15089
+ }
15090
+ if (!task) {
15091
+ throw new Error(withUsage$p('The `task` option is required.'));
15092
+ }
15093
+ var runner;
15094
+ var output;
15095
+ var isLoading = false;
15096
+ var error;
15097
+ var disposed = false;
15098
+ var triggerRender = noop;
15099
+ var requestId = 0;
15100
+ var submit = function submit(variables) {
15101
+ if (disposed) return Promise.resolve(undefined);
15102
+ var currentRequestId = requestId += 1;
15103
+ var isStale = function isStale() {
15104
+ return disposed || currentRequestId !== requestId;
15105
+ };
15106
+ // Clear the previous output so consumers can show a loading state
15107
+ // rather than stale data while the new request is in flight.
15108
+ output = undefined;
15109
+ error = undefined;
15110
+ isLoading = true;
15111
+ triggerRender();
15112
+ return Promise.resolve().then(function() {
15113
+ return runner.submit(variables, {
15114
+ onData: stream ? function(partial) {
15115
+ if (isStale()) return;
15116
+ output = partial;
15117
+ triggerRender();
15118
+ } : undefined
15119
+ });
15120
+ }).then(function(next) {
15121
+ var result = next;
15122
+ if (!isStale()) {
15123
+ output = result;
15124
+ }
15125
+ return result;
15126
+ }).catch(function(err) {
15127
+ if (!isStale()) {
15128
+ output = undefined;
15129
+ error = _instanceof(err, Error) ? err : new Error(String(err));
15130
+ }
15131
+ return undefined;
15132
+ }).finally(function() {
15133
+ if (isStale()) return;
15134
+ isLoading = false;
15135
+ triggerRender();
15136
+ });
15137
+ };
15138
+ var invalidate = function invalidate() {
15139
+ if (disposed) return;
15140
+ // Bump the request id so any in-flight request's callbacks see
15141
+ // `isStale()` and are ignored. The fetch itself is left to complete.
15142
+ requestId += 1;
15143
+ isLoading = false;
15144
+ triggerRender();
15145
+ };
15146
+ var getWidgetRenderState = function getWidgetRenderState() {
15147
+ return {
15148
+ output: output,
15149
+ isLoading: isLoading,
15150
+ error: error,
15151
+ submit: submit,
15152
+ invalidate: invalidate,
15153
+ widgetParams: widgetParams
15154
+ };
15155
+ };
15156
+ return {
15157
+ $$type: 'ais.tasks',
15158
+ init: function init(initOptions) {
15159
+ var instantSearchInstance = initOptions.instantSearchInstance;
15160
+ if (transport) {
15161
+ var resolved = resolveEndpoint({
15162
+ transport: transport
15163
+ });
15164
+ runner = createTaskRunner({
15165
+ endpoint: resolved.endpoint,
15166
+ headers: resolved.headers,
15167
+ task: task,
15168
+ stream: stream,
15169
+ prepareRequest: resolved.prepareSendMessagesRequest
15170
+ });
15171
+ } else {
15172
+ var _getAppIdAndApiKey = _sliced_to_array(getAppIdAndApiKey(instantSearchInstance.client), 2), appId = _getAppIdAndApiKey[0], apiKey = _getAppIdAndApiKey[1];
15173
+ if (!appId || !apiKey) {
15174
+ throw new Error(withUsage$p('Could not extract Algolia credentials from the search client.'));
15175
+ }
15176
+ var resolved1 = resolveEndpoint({
15177
+ appId: appId,
15178
+ apiKey: apiKey,
15179
+ agentId: agentId,
15180
+ algoliaAgent: getAlgoliaAgent(instantSearchInstance.client)
15181
+ });
15182
+ runner = createTaskRunner({
15183
+ endpoint: resolved1.endpoint,
15184
+ headers: resolved1.headers,
15185
+ task: task,
15186
+ stream: stream
15187
+ });
15188
+ }
15189
+ triggerRender = function triggerRender() {
15190
+ renderFn(_object_spread_props(_object_spread({}, getWidgetRenderState()), {
15191
+ instantSearchInstance: instantSearchInstance
15192
+ }), false);
15193
+ };
15194
+ renderFn(_object_spread_props(_object_spread({}, getWidgetRenderState()), {
15195
+ instantSearchInstance: instantSearchInstance
15196
+ }), true);
15197
+ },
15198
+ render: function render(renderOptions) {
15199
+ renderFn(_object_spread_props(_object_spread({}, getWidgetRenderState()), {
15200
+ instantSearchInstance: renderOptions.instantSearchInstance
15201
+ }), false);
15202
+ },
15203
+ dispose: function dispose() {
15204
+ disposed = true;
15205
+ unmountFn();
15206
+ }
15207
+ };
15208
+ };
15209
+ };
15210
+
15211
+ var withUsage$o = createDocumentationMessageGenerator({
15212
+ name: 'prompt-suggestions',
15213
+ connector: true
15214
+ });
15215
+ var RENDER_STATE_KEY = 'promptSuggestions';
15216
+ var CHAT_RENDER_STATE_KEY = 'chat';
15217
+ var DEBOUNCE_MS = 300;
15218
+ function parseSuggestions(data) {
15219
+ var suggestions = data === null || data === void 0 ? void 0 : data.suggestions;
15220
+ if (!Array.isArray(suggestions)) {
15221
+ return [];
15222
+ }
15223
+ return suggestions.filter(function(s) {
15224
+ return typeof s === 'string';
15225
+ });
15226
+ }
15227
+ function buildSuggestionMessage(suggestion) {
15228
+ return "The user clicked this on-page suggestion. Use the current page context first, then search only if needed.\n\nSuggestion: ".concat(suggestion);
15229
+ }
15230
+ function stripInternalHitMetadata(hit) {
15231
+ var clean = {};
15232
+ Object.keys(hit).forEach(function(key) {
15233
+ // Strip internal metadata, which is `_`-prefixed
15234
+ // (`_highlightResult`, `_rankingInfo`, `__position`, …).
15235
+ if (!key.startsWith('_')) {
15236
+ clean[key] = hit[key];
15237
+ }
15238
+ });
15239
+ return clean;
15240
+ }
15241
+ var DEFAULT_TRANSFORM_HITS = function DEFAULT_TRANSFORM_HITS(hits) {
15242
+ return hits.slice(0, 5).map(stripInternalHitMetadata);
15243
+ };
15244
+ function buildFilters(results) {
15245
+ var state = results._state;
15246
+ if (!state) {
15247
+ return undefined;
15248
+ }
15249
+ var groups = [];
15250
+ var disjunctiveGroups = {};
15251
+ getRefinements(results, state).forEach(function(refinement) {
15252
+ if (refinement.type === 'numeric') {
15253
+ groups.push([
15254
+ "".concat(refinement.attribute).concat(refinement.operator).concat(refinement.numericValue)
15255
+ ]);
15256
+ return;
15257
+ }
15258
+ var value = refinement.type === 'exclude' ? "".concat(refinement.attribute, ":-").concat(refinement.name) : "".concat(refinement.attribute, ":").concat(refinement.name);
15259
+ if (refinement.type === 'disjunctive') {
15260
+ var group = disjunctiveGroups[refinement.attribute];
15261
+ if (group) {
15262
+ group.push(value);
15263
+ } else {
15264
+ var newGroup = [
15265
+ value
15266
+ ];
15267
+ disjunctiveGroups[refinement.attribute] = newGroup;
15268
+ groups.push(newGroup);
15269
+ }
15270
+ return;
15271
+ }
15272
+ groups.push([
15273
+ value
15274
+ ]);
15275
+ });
15276
+ return groups.length > 0 ? groups : undefined;
15277
+ }
15278
+ var connectPromptSuggestions = function connectPromptSuggestions(renderFn) {
15279
+ var unmountFn = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : noop;
15280
+ checkRendering(renderFn, withUsage$o());
15281
+ return function(widgetParams) {
15282
+ var agentId = widgetParams.agentId, configurationId = widgetParams.configurationId, _widgetParams_transformHits = widgetParams.transformHits, transformHits = _widgetParams_transformHits === void 0 ? DEFAULT_TRANSFORM_HITS : _widgetParams_transformHits, context = widgetParams.context, _widgetParams_transformItems = widgetParams.transformItems, transformItems = _widgetParams_transformItems === void 0 ? function(items) {
15283
+ return items;
15284
+ } : _widgetParams_transformItems, transport = widgetParams.transport;
15285
+ if (!agentId && !transport) {
15286
+ throw new Error(withUsage$o('The `agentId` option is required unless a custom `transport` is provided.'));
15287
+ }
15288
+ if (!configurationId) {
15289
+ throw new Error(withUsage$o('The `configurationId` option is required.'));
15290
+ }
15291
+ var tasksState;
15292
+ var suggestions = [];
15293
+ var isLoading = false;
15294
+ var debounceTimer;
15295
+ var lastStateSignature = null;
15296
+ var latestRenderOptions = null;
15297
+ // Set in `dispose()`. A debounced or in-flight `fetch()` can resolve after
15298
+ // the widget is unmounted; this guard stops those late callbacks from
15299
+ // calling `renderFn` into a torn-down container.
15300
+ var disposed = false;
15301
+ // True between a state-signature change and the debounced refetch that
15302
+ // follows it. While pending, the search state has already moved on, so a
15303
+ // still-in-flight request from the previous state must not paint its
15304
+ // suggestions, its inner render is ignored until the new `submit` starts.
15305
+ var refetchPending = false;
15306
+ var getStateSignature = function getStateSignature(results) {
15307
+ var _buildFilters;
15308
+ if (results.queryID) {
15309
+ return results.queryID;
15310
+ }
15311
+ var query = results.query || '';
15312
+ var filters = JSON.stringify((_buildFilters = buildFilters(results)) !== null && _buildFilters !== void 0 ? _buildFilters : []);
15313
+ var hitIds = (results.hits || []).map(function(hit) {
15314
+ return hit.objectID;
15315
+ }).join(',');
15316
+ return "".concat(query, "|").concat(filters, "|").concat(hitIds);
15317
+ };
15318
+ var getChatRenderState = function getChatRenderState(renderOptions) {
15319
+ var _instantSearchInstance_renderState;
15320
+ var instantSearchInstance = renderOptions.instantSearchInstance, parent = renderOptions.parent;
15321
+ var indexId = parent ? parent.getIndexId() : '';
15322
+ if (!indexId || !((_instantSearchInstance_renderState = instantSearchInstance.renderState) === null || _instantSearchInstance_renderState === void 0 ? void 0 : _instantSearchInstance_renderState[indexId])) {
15323
+ return undefined;
15324
+ }
15325
+ return instantSearchInstance.renderState[indexId][CHAT_RENDER_STATE_KEY];
15326
+ };
15327
+ var sendToChat = function sendToChat(renderOptions) {
15328
+ return function(prompt) {
15329
+ var _ref, _ref1;
15330
+ var chatRenderState = getChatRenderState(renderOptions);
15331
+ if (!chatRenderState || !chatRenderState.sendMessage) {
15332
+ return false;
15333
+ }
15334
+ var results = (_ref = (_ref1 = latestRenderOptions === null || latestRenderOptions === void 0 ? void 0 : latestRenderOptions.results) !== null && _ref1 !== void 0 ? _ref1 : 'results' in renderOptions ? renderOptions.results : null) !== null && _ref !== void 0 ? _ref : null;
15335
+ return openChat(chatRenderState, {
15336
+ message: buildSuggestionMessage(prompt),
15337
+ referer: 'prompt-suggestions-widget',
15338
+ turnContext: buildTurnContext(results)
15339
+ });
15340
+ };
15341
+ };
15342
+ var resolvePageContext = function resolvePageContext(results) {
15343
+ var resolvedContext = typeof context === 'function' ? context() : context;
15344
+ // Explicit context replaces auto-extraction; otherwise derive it from
15345
+ // the current search state. The task's server-owned instructions decide
15346
+ // how to interpret the shape — the client doesn't label it.
15347
+ if (resolvedContext) {
15348
+ return _object_spread({}, resolvedContext);
15349
+ }
15350
+ if (!results) {
15351
+ return undefined;
15352
+ }
15353
+ var filters = buildFilters(results);
15354
+ return _object_spread_props(_object_spread({
15355
+ query: results.query || ''
15356
+ }, filters ? {
15357
+ filters: filters
15358
+ } : {}), {
15359
+ hitsSample: transformHits(results.hits)
15360
+ });
15361
+ };
15362
+ var buildInput = function buildInput(results) {
15363
+ var _resolvePageContext;
15364
+ return (_resolvePageContext = resolvePageContext(results)) !== null && _resolvePageContext !== void 0 ? _resolvePageContext : {};
15365
+ };
15366
+ // The same page context, flattened for the chat handoff: `turnContext` is
15367
+ // a flat `Record<string, string>` per the Agent Studio contract, so
15368
+ // non-string values (e.g. `hitsSample`) are serialized.
15369
+ var buildTurnContext = function buildTurnContext(results) {
15370
+ var pageContext = resolvePageContext(results);
15371
+ if (!pageContext) {
15372
+ return undefined;
15373
+ }
15374
+ var entries = Object.entries(pageContext).map(function(param) {
15375
+ var _param = _sliced_to_array(param, 2), key = _param[0], value = _param[1];
15376
+ return [
15377
+ key,
15378
+ typeof value === 'string' ? value : JSON.stringify(value)
15379
+ ];
15380
+ }).filter(function(param) {
15381
+ var _param = _sliced_to_array(param, 2), value = _param[1];
15382
+ return value.trim() !== '';
15383
+ });
15384
+ return entries.length > 0 ? Object.fromEntries(entries) : undefined;
15385
+ };
15386
+ var renderOutward = function renderOutward(renderOptions) {
15387
+ if (disposed) return;
15388
+ renderFn(_object_spread_props(_object_spread({}, getWidgetRenderState(renderOptions)), {
15389
+ instantSearchInstance: renderOptions.instantSearchInstance
15390
+ }), false);
15391
+ };
15392
+ var fetchAndRender = function fetchAndRender(results, renderOptions) {
15393
+ var _results_hits;
15394
+ if (disposed || !tasksState) return;
15395
+ refetchPending = false;
15396
+ var hasContext = context !== undefined;
15397
+ if (!hasContext && !(results === null || results === void 0 ? void 0 : (_results_hits = results.hits) === null || _results_hits === void 0 ? void 0 : _results_hits.length)) {
15398
+ tasksState.invalidate();
15399
+ suggestions = [];
15400
+ isLoading = false;
15401
+ renderOutward(renderOptions);
15402
+ return;
15403
+ }
15404
+ tasksState.submit(buildInput(results));
15405
+ };
15406
+ var refresh = function refresh() {
15407
+ if (isLoading) return;
15408
+ var results = latestRenderOptions === null || latestRenderOptions === void 0 ? void 0 : latestRenderOptions.results;
15409
+ if (!results || !latestRenderOptions) return;
15410
+ clearTimeout(debounceTimer);
15411
+ lastStateSignature = getStateSignature(results);
15412
+ fetchAndRender(results, latestRenderOptions);
15413
+ };
15414
+ var getWidgetRenderState = function getWidgetRenderState(renderOptions) {
15415
+ var results = 'results' in renderOptions ? renderOptions.results : undefined;
15416
+ var transformed = transformItems(suggestions, {
15417
+ query: (results === null || results === void 0 ? void 0 : results.query) || '',
15418
+ results: results || null
15419
+ });
15420
+ var chatRenderState = getChatRenderState(renderOptions);
15421
+ var isChatBusy$1 = chatRenderState ? !chatRenderState.sendMessage || isChatBusy(chatRenderState) : false;
15422
+ var send = sendToChat(renderOptions);
15423
+ return {
15424
+ suggestions: transformed,
15425
+ isLoading: isLoading,
15426
+ onSuggestionClick: send,
15427
+ sendToChat: send,
15428
+ refresh: refresh,
15429
+ isChatBusy: isChatBusy$1,
15430
+ widgetParams: widgetParams
15431
+ };
15432
+ };
15433
+ // Mirrors each inner render (submit start → skeleton, stream partials,
15434
+ // resolve/error) into this widget's state and re-renders on the client.
15435
+ var handleInnerRender = function handleInnerRender(renderState) {
15436
+ tasksState = renderState;
15437
+ if (refetchPending) return;
15438
+ if (renderState.error) {
15439
+ // A failed task (including a mid-stream `error` event) must not leave
15440
+ // any streamed partial visible. There's no error UI for now, so fall
15441
+ // back to a blank suggestions state.
15442
+ suggestions = [];
15443
+ } else if (renderState.isLoading || renderState.output !== undefined) {
15444
+ // Only adopt the inner output once a request is loading or has
15445
+ // produced one, so the initial no-op render doesn't clobber pills.
15446
+ suggestions = parseSuggestions(renderState.output);
15447
+ }
15448
+ isLoading = renderState.isLoading;
15449
+ if (!latestRenderOptions) return;
15450
+ renderOutward(latestRenderOptions);
15451
+ };
15452
+ var tasksWidget = connectTasks(handleInnerRender, noop)(_object_spread_props(_object_spread({}, transport ? {
15453
+ transport: transport
15454
+ } : {
15455
+ agentId: agentId
15456
+ }), {
15457
+ task: configurationId,
15458
+ stream: true
15459
+ }));
15460
+ return {
15461
+ $$type: 'ais.promptSuggestions',
15462
+ init: function init(initOptions) {
15463
+ var instantSearchInstance = initOptions.instantSearchInstance;
15464
+ tasksWidget.init(initOptions);
15465
+ renderFn(_object_spread_props(_object_spread({}, getWidgetRenderState(initOptions)), {
15466
+ instantSearchInstance: instantSearchInstance
15467
+ }), true);
15468
+ },
15469
+ render: function render(renderOptions) {
15470
+ var results = renderOptions.results, instantSearchInstance = renderOptions.instantSearchInstance;
15471
+ latestRenderOptions = renderOptions;
15472
+ if (!results) {
15473
+ renderFn(_object_spread_props(_object_spread({}, getWidgetRenderState(renderOptions)), {
15474
+ instantSearchInstance: instantSearchInstance
15475
+ }), false);
15476
+ return;
15477
+ }
15478
+ var stateSignature = getStateSignature(results);
15479
+ if (stateSignature !== lastStateSignature) {
15480
+ lastStateSignature = stateSignature;
15481
+ refetchPending = true;
15482
+ clearTimeout(debounceTimer);
15483
+ debounceTimer = setTimeout(function() {
15484
+ if (latestRenderOptions === null || latestRenderOptions === void 0 ? void 0 : latestRenderOptions.results) {
15485
+ fetchAndRender(latestRenderOptions.results, latestRenderOptions);
15486
+ }
15487
+ }, DEBOUNCE_MS);
15488
+ }
15489
+ renderFn(_object_spread_props(_object_spread({}, getWidgetRenderState(renderOptions)), {
15490
+ instantSearchInstance: instantSearchInstance
15491
+ }), false);
15492
+ },
15493
+ dispose: function dispose(disposeOptions) {
15494
+ disposed = true;
15495
+ clearTimeout(debounceTimer);
15496
+ tasksWidget.dispose(disposeOptions);
15497
+ unmountFn();
15498
+ },
15499
+ getRenderState: function getRenderState(renderState, renderOptions) {
15500
+ return _object_spread_props(_object_spread({}, renderState), _define_property({}, RENDER_STATE_KEY, this.getWidgetRenderState(renderOptions)));
15501
+ },
15502
+ getWidgetRenderState: function getWidgetRenderState1(renderOptions) {
15503
+ return getWidgetRenderState(renderOptions);
15504
+ }
15505
+ };
15506
+ };
15507
+ };
15508
+
15509
+ function usePromptSuggestions(props, additionalWidgetProperties) {
15510
+ return useConnector(connectPromptSuggestions, props, additionalWidgetProperties);
14561
15511
  }
14562
15512
 
14563
15513
  var withUsage$n = createDocumentationMessageGenerator({
@@ -18802,6 +19752,7 @@
18802
19752
  exports.useNumericMenu = useNumericMenu;
18803
19753
  exports.usePagination = usePagination;
18804
19754
  exports.usePoweredBy = usePoweredBy;
19755
+ exports.usePromptSuggestions = usePromptSuggestions;
18805
19756
  exports.useQueryRules = useQueryRules;
18806
19757
  exports.useRSCContext = useRSCContext;
18807
19758
  exports.useRange = useRange;