@blotoutio/providers-evo-search-sdk 1.62.1 → 1.63.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/hooks.d.ts +4 -0
- package/index.cjs.js +100 -19
- package/index.js +100 -19
- package/index.mjs +100 -19
- package/package.json +1 -1
package/hooks.d.ts
CHANGED
|
@@ -65,6 +65,10 @@ declare module '@blotoutio/providers-evo-search-sdk/hooks' {
|
|
|
65
65
|
export type AskConfigResponse = {
|
|
66
66
|
askAiEnabled: boolean
|
|
67
67
|
askStarters?: string[]
|
|
68
|
+
brandName?: string
|
|
69
|
+
brandVoice?: string
|
|
70
|
+
storeDescription?: string
|
|
71
|
+
outOfStock: 'show' | 'hide' | 'demote'
|
|
68
72
|
}
|
|
69
73
|
|
|
70
74
|
export type EvoSearchUserAPI = {
|
package/index.cjs.js
CHANGED
|
@@ -606,7 +606,7 @@ const setStoredSearchMode = (mode) => {
|
|
|
606
606
|
const searchSessionKeyName = 'evoSearchSession';
|
|
607
607
|
const SEARCH_SESSION_VERSION = 1;
|
|
608
608
|
const getStoredSearchSession = () => {
|
|
609
|
-
var _a, _b, _c, _d, _e, _f;
|
|
609
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
610
610
|
try {
|
|
611
611
|
const raw = sessionStorage.getItem(searchSessionKeyName);
|
|
612
612
|
if (!raw) {
|
|
@@ -631,6 +631,7 @@ const getStoredSearchSession = () => {
|
|
|
631
631
|
askAnswer: (_d = parsed.askAnswer) !== null && _d !== void 0 ? _d : '',
|
|
632
632
|
askEvidence: (_e = parsed.askEvidence) !== null && _e !== void 0 ? _e : null,
|
|
633
633
|
askFollowUps: (_f = parsed.askFollowUps) !== null && _f !== void 0 ? _f : [],
|
|
634
|
+
askCitedTitles: (_g = parsed.askCitedTitles) !== null && _g !== void 0 ? _g : [],
|
|
634
635
|
};
|
|
635
636
|
}
|
|
636
637
|
catch {
|
|
@@ -6345,7 +6346,7 @@ const u=(e,s,t)=>{const r=new Map;for(let l=s;l<=t;l++)r.set(e[l],l);return r},c
|
|
|
6345
6346
|
// Pure tokenizer kept out of `highlight.ts` so Jest can spec it without
|
|
6346
6347
|
// pulling in `lit`'s ESM bundle. The renderer wraps these tokens in
|
|
6347
6348
|
// <mark> via a Lit template — see `highlight.ts`.
|
|
6348
|
-
const escapeRegex = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
6349
|
+
const escapeRegex$1 = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
6349
6350
|
// Compiling a `RegExp` per call is hot under autocomplete (every result row
|
|
6350
6351
|
// + collection card + suggestion item, all sharing the same query). Keep a
|
|
6351
6352
|
// single-slot memo keyed on the trimmed query.
|
|
@@ -6356,7 +6357,7 @@ const patternFor = (needle) => {
|
|
|
6356
6357
|
return cachedPattern;
|
|
6357
6358
|
}
|
|
6358
6359
|
cachedNeedle = needle;
|
|
6359
|
-
cachedPattern = new RegExp(escapeRegex(needle), 'ig');
|
|
6360
|
+
cachedPattern = new RegExp(escapeRegex$1(needle), 'ig');
|
|
6360
6361
|
return cachedPattern;
|
|
6361
6362
|
};
|
|
6362
6363
|
const splitMatches = (text, query) => {
|
|
@@ -7422,6 +7423,71 @@ const buildRailSections = ({ searchQuery, suggestions, trendingSearches, recents
|
|
|
7422
7423
|
return sections;
|
|
7423
7424
|
};
|
|
7424
7425
|
|
|
7426
|
+
// Pure tokenizer for the Ask AI answer, kept out of the Lit component so Jest
|
|
7427
|
+
// can spec it without pulling in `lit`'s ESM bundle. The widget wraps the
|
|
7428
|
+
// `bold` segments in <strong> — see `renderAskAnswerText`.
|
|
7429
|
+
//
|
|
7430
|
+
// Highlighting is driven by the cited product/collection titles (the items the
|
|
7431
|
+
// model actually selected), not by whether the model remembered to wrap them
|
|
7432
|
+
// in `**` markers. We still honor any server-validated `**bold**` spans, then
|
|
7433
|
+
// additionally bold every cited title the model named in plain prose — so a
|
|
7434
|
+
// referred product is highlighted even when the model omits the markers.
|
|
7435
|
+
const escapeRegex = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
7436
|
+
// One alternation of all cited titles, longest-first so the most specific
|
|
7437
|
+
// title wins when one is a prefix of another (regex alternation is leftmost,
|
|
7438
|
+
// not longest). Wrapped in Unicode-aware boundary lookarounds so a short title
|
|
7439
|
+
// never matches inside a larger word. Null when there are no titles to
|
|
7440
|
+
// highlight.
|
|
7441
|
+
const buildTitlePattern = (titles) => {
|
|
7442
|
+
const needles = Array.from(new Set(titles.map((title) => title.trim()).filter((title) => title.length))).sort((a, b) => b.length - a.length);
|
|
7443
|
+
if (!needles.length) {
|
|
7444
|
+
return null;
|
|
7445
|
+
}
|
|
7446
|
+
const alternation = needles.map(escapeRegex).join('|');
|
|
7447
|
+
return new RegExp(`(?<![\\p{L}\\p{N}])(?:${alternation})(?![\\p{L}\\p{N}])`, 'giu');
|
|
7448
|
+
};
|
|
7449
|
+
const pushTitleMatches = (segment, pattern, out) => {
|
|
7450
|
+
var _a;
|
|
7451
|
+
if (!pattern) {
|
|
7452
|
+
out.push({ text: segment, bold: false });
|
|
7453
|
+
return;
|
|
7454
|
+
}
|
|
7455
|
+
pattern.lastIndex = 0;
|
|
7456
|
+
let cursor = 0;
|
|
7457
|
+
for (const match of segment.matchAll(pattern)) {
|
|
7458
|
+
const start = (_a = match.index) !== null && _a !== void 0 ? _a : cursor;
|
|
7459
|
+
if (start > cursor) {
|
|
7460
|
+
out.push({ text: segment.slice(cursor, start), bold: false });
|
|
7461
|
+
}
|
|
7462
|
+
out.push({ text: match[0], bold: true });
|
|
7463
|
+
cursor = start + match[0].length;
|
|
7464
|
+
}
|
|
7465
|
+
if (cursor < segment.length) {
|
|
7466
|
+
out.push({ text: segment.slice(cursor), bold: false });
|
|
7467
|
+
}
|
|
7468
|
+
};
|
|
7469
|
+
const splitAnswerHighlights = (text, titles) => {
|
|
7470
|
+
const haystack = (text !== null && text !== void 0 ? text : '').trim();
|
|
7471
|
+
if (!haystack) {
|
|
7472
|
+
return [];
|
|
7473
|
+
}
|
|
7474
|
+
const pattern = buildTitlePattern(titles);
|
|
7475
|
+
const out = [];
|
|
7476
|
+
// Odd-indexed split parts are the inside of a model-emitted `**…**` span.
|
|
7477
|
+
haystack.split('**').forEach((segment, i) => {
|
|
7478
|
+
if (!segment) {
|
|
7479
|
+
return;
|
|
7480
|
+
}
|
|
7481
|
+
if (i % 2 === 1) {
|
|
7482
|
+
out.push({ text: segment, bold: true });
|
|
7483
|
+
}
|
|
7484
|
+
else {
|
|
7485
|
+
pushTitleMatches(segment, pattern, out);
|
|
7486
|
+
}
|
|
7487
|
+
});
|
|
7488
|
+
return out;
|
|
7489
|
+
};
|
|
7490
|
+
|
|
7425
7491
|
const renderErrorState = (css, onAction) => b `
|
|
7426
7492
|
<evs-state-block
|
|
7427
7493
|
.css=${css}
|
|
@@ -8233,11 +8299,9 @@ const isCancelled = (error) => error instanceof Error &&
|
|
|
8233
8299
|
// Default "Try asking" prompts shown on the Ask AI empty state when the
|
|
8234
8300
|
// merchant hasn't configured their own via `uiPreferences.askStarters`.
|
|
8235
8301
|
const FALLBACK_ASK_STARTERS = [
|
|
8236
|
-
|
|
8302
|
+
'Help me find a gift',
|
|
8237
8303
|
'Gift ideas under $50',
|
|
8238
|
-
'
|
|
8239
|
-
'Recommend something for my mom',
|
|
8240
|
-
'Show me your bestsellers',
|
|
8304
|
+
"I'm not sure what to get",
|
|
8241
8305
|
];
|
|
8242
8306
|
class SearchWidget extends ElementWithStylesheet {
|
|
8243
8307
|
constructor() {
|
|
@@ -8260,6 +8324,10 @@ class SearchWidget extends ElementWithStylesheet {
|
|
|
8260
8324
|
this.lastAskedQuery = '';
|
|
8261
8325
|
this.askAnswer = '';
|
|
8262
8326
|
this.askEvidence = null;
|
|
8327
|
+
// Titles of the products/collections the model actually cited, used to
|
|
8328
|
+
// highlight their names in the answer prose regardless of whether the model
|
|
8329
|
+
// wrapped them in `**` markers. Populated from the `citations` event.
|
|
8330
|
+
this.askCitedTitles = [];
|
|
8263
8331
|
this.askFollowUps = [];
|
|
8264
8332
|
this.askLoading = false;
|
|
8265
8333
|
this.askAbort = null;
|
|
@@ -8451,6 +8519,7 @@ class SearchWidget extends ElementWithStylesheet {
|
|
|
8451
8519
|
this.answerFlushHandle = null;
|
|
8452
8520
|
}
|
|
8453
8521
|
this.pendingAnswerChunk = '';
|
|
8522
|
+
this.askCitedTitles = [];
|
|
8454
8523
|
}
|
|
8455
8524
|
async submitAsk(query) {
|
|
8456
8525
|
var _a, _b;
|
|
@@ -8478,6 +8547,7 @@ class SearchWidget extends ElementWithStylesheet {
|
|
|
8478
8547
|
this.scheduleAnswerFlush();
|
|
8479
8548
|
}
|
|
8480
8549
|
else if (event.type === 'citations') {
|
|
8550
|
+
this.askCitedTitles = event.citations.resolved.map((c) => c.title);
|
|
8481
8551
|
this.reorderEvidenceByCitations(event.citations);
|
|
8482
8552
|
}
|
|
8483
8553
|
else if (event.type === 'follow-ups') {
|
|
@@ -8591,8 +8661,8 @@ class SearchWidget extends ElementWithStylesheet {
|
|
|
8591
8661
|
// just submitted — same affordance as typing it themselves.
|
|
8592
8662
|
this.searchQuery = trimmed;
|
|
8593
8663
|
this.lastAskedQuery = trimmed;
|
|
8594
|
-
// The answer is the surface now — collapse the typeahead hints
|
|
8595
|
-
//
|
|
8664
|
+
// The answer is the surface now — collapse the pre-submit typeahead hints.
|
|
8665
|
+
// (Search-mode suggestions stay visible; this is ask-only.)
|
|
8596
8666
|
this.showSuggestions = false;
|
|
8597
8667
|
// Treat ask submissions as query history so the Recent rail surfaces
|
|
8598
8668
|
// them on the next visit, identical to how typed searches behave.
|
|
@@ -8692,9 +8762,8 @@ class SearchWidget extends ElementWithStylesheet {
|
|
|
8692
8762
|
if (this.hasError || !this.debouncedQuery || this.mode !== 'search') {
|
|
8693
8763
|
return;
|
|
8694
8764
|
}
|
|
8695
|
-
//
|
|
8696
|
-
//
|
|
8697
|
-
this.showSuggestions = false;
|
|
8765
|
+
// Suggestions stay visible above the results until the query is cleared
|
|
8766
|
+
// (no settle-time collapse).
|
|
8698
8767
|
// Collections are first-class results on the unified surface — a
|
|
8699
8768
|
// collections-only match must not be reported as zero-result.
|
|
8700
8769
|
this.markQueryFinalized(this.debouncedQuery, this.searchProducts.length + this.searchCollections.length);
|
|
@@ -8869,6 +8938,9 @@ class SearchWidget extends ElementWithStylesheet {
|
|
|
8869
8938
|
// a terminal action, though: finalize the query now (or as soon as the
|
|
8870
8939
|
// in-flight debounce/fetch renders). The pending debounce timer must NOT
|
|
8871
8940
|
// be cleared here — cancelling it would strand `loading = true` forever.
|
|
8941
|
+
// Enter also collapses the typeahead — a terminal action, unlike the
|
|
8942
|
+
// settle pause which now leaves the suggestions in place.
|
|
8943
|
+
this.showSuggestions = false;
|
|
8872
8944
|
const trimmed = query.trim();
|
|
8873
8945
|
if (trimmed.length >= MIN_QUERY_LENGTH) {
|
|
8874
8946
|
if (this.hasError) {
|
|
@@ -9040,6 +9112,7 @@ class SearchWidget extends ElementWithStylesheet {
|
|
|
9040
9112
|
askAnswer: this.askAnswer,
|
|
9041
9113
|
askEvidence: this.askEvidence,
|
|
9042
9114
|
askFollowUps: this.askFollowUps,
|
|
9115
|
+
askCitedTitles: this.askCitedTitles,
|
|
9043
9116
|
});
|
|
9044
9117
|
}
|
|
9045
9118
|
// Restore the last snapshot on mount. Sets state directly — no network — so
|
|
@@ -9069,6 +9142,7 @@ class SearchWidget extends ElementWithStylesheet {
|
|
|
9069
9142
|
this.askAnswer = snap.askAnswer;
|
|
9070
9143
|
this.askEvidence = snap.askEvidence;
|
|
9071
9144
|
this.askFollowUps = snap.askFollowUps;
|
|
9145
|
+
this.askCitedTitles = snap.askCitedTitles;
|
|
9072
9146
|
}
|
|
9073
9147
|
this.mode = snap.mode === 'ask' && hasAnswer ? 'ask' : 'search';
|
|
9074
9148
|
}
|
|
@@ -9117,14 +9191,17 @@ class SearchWidget extends ElementWithStylesheet {
|
|
|
9117
9191
|
}
|
|
9118
9192
|
return b ``;
|
|
9119
9193
|
}
|
|
9120
|
-
// Bold the
|
|
9194
|
+
// Bold the part of the suggestion that matches the shopper's query;
|
|
9195
|
+
// leave the rest unstyled. Matches anywhere in the phrase, not just the
|
|
9196
|
+
// prefix, since completions aren't always prefix matches of the query.
|
|
9121
9197
|
renderPredicted(value) {
|
|
9122
9198
|
const q = this.searchQuery.trim();
|
|
9123
|
-
if (q
|
|
9124
|
-
return b
|
|
9125
|
-
><b>${value.slice(q.length)}</b>`;
|
|
9199
|
+
if (!q) {
|
|
9200
|
+
return b `${value}`;
|
|
9126
9201
|
}
|
|
9127
|
-
|
|
9202
|
+
const escaped = q.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
9203
|
+
const parts = value.split(new RegExp(`(${escaped})`, 'gi'));
|
|
9204
|
+
return b `${parts.map((part, i) => i % 2 === 1 ? b `<b>${part}</b>` : b `${part}`)}`;
|
|
9128
9205
|
}
|
|
9129
9206
|
renderSuggestions(section) {
|
|
9130
9207
|
if (!section.items.length) {
|
|
@@ -9339,8 +9416,8 @@ class SearchWidget extends ElementWithStylesheet {
|
|
|
9339
9416
|
`;
|
|
9340
9417
|
}
|
|
9341
9418
|
renderAskAnswerText(text) {
|
|
9342
|
-
const
|
|
9343
|
-
return b `${
|
|
9419
|
+
const segments = splitAnswerHighlights(text, this.askCitedTitles);
|
|
9420
|
+
return b `${segments.map((segment) => segment.bold ? b `<strong>${segment.text}</strong>` : segment.text)}`;
|
|
9344
9421
|
}
|
|
9345
9422
|
renderAskPane() {
|
|
9346
9423
|
// Once the LLM has finished talking, show the centered starter chips
|
|
@@ -9747,6 +9824,10 @@ __decorate([
|
|
|
9747
9824
|
r$1(),
|
|
9748
9825
|
__metadata("design:type", Object)
|
|
9749
9826
|
], SearchWidget.prototype, "askEvidence", void 0);
|
|
9827
|
+
__decorate([
|
|
9828
|
+
r$1(),
|
|
9829
|
+
__metadata("design:type", Array)
|
|
9830
|
+
], SearchWidget.prototype, "askCitedTitles", void 0);
|
|
9750
9831
|
__decorate([
|
|
9751
9832
|
r$1(),
|
|
9752
9833
|
__metadata("design:type", Array)
|
package/index.js
CHANGED
|
@@ -607,7 +607,7 @@ var ProvidersEvoSearchSdk = (function () {
|
|
|
607
607
|
const searchSessionKeyName = 'evoSearchSession';
|
|
608
608
|
const SEARCH_SESSION_VERSION = 1;
|
|
609
609
|
const getStoredSearchSession = () => {
|
|
610
|
-
var _a, _b, _c, _d, _e, _f;
|
|
610
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
611
611
|
try {
|
|
612
612
|
const raw = sessionStorage.getItem(searchSessionKeyName);
|
|
613
613
|
if (!raw) {
|
|
@@ -632,6 +632,7 @@ var ProvidersEvoSearchSdk = (function () {
|
|
|
632
632
|
askAnswer: (_d = parsed.askAnswer) !== null && _d !== void 0 ? _d : '',
|
|
633
633
|
askEvidence: (_e = parsed.askEvidence) !== null && _e !== void 0 ? _e : null,
|
|
634
634
|
askFollowUps: (_f = parsed.askFollowUps) !== null && _f !== void 0 ? _f : [],
|
|
635
|
+
askCitedTitles: (_g = parsed.askCitedTitles) !== null && _g !== void 0 ? _g : [],
|
|
635
636
|
};
|
|
636
637
|
}
|
|
637
638
|
catch {
|
|
@@ -6346,7 +6347,7 @@ var ProvidersEvoSearchSdk = (function () {
|
|
|
6346
6347
|
// Pure tokenizer kept out of `highlight.ts` so Jest can spec it without
|
|
6347
6348
|
// pulling in `lit`'s ESM bundle. The renderer wraps these tokens in
|
|
6348
6349
|
// <mark> via a Lit template — see `highlight.ts`.
|
|
6349
|
-
const escapeRegex = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
6350
|
+
const escapeRegex$1 = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
6350
6351
|
// Compiling a `RegExp` per call is hot under autocomplete (every result row
|
|
6351
6352
|
// + collection card + suggestion item, all sharing the same query). Keep a
|
|
6352
6353
|
// single-slot memo keyed on the trimmed query.
|
|
@@ -6357,7 +6358,7 @@ var ProvidersEvoSearchSdk = (function () {
|
|
|
6357
6358
|
return cachedPattern;
|
|
6358
6359
|
}
|
|
6359
6360
|
cachedNeedle = needle;
|
|
6360
|
-
cachedPattern = new RegExp(escapeRegex(needle), 'ig');
|
|
6361
|
+
cachedPattern = new RegExp(escapeRegex$1(needle), 'ig');
|
|
6361
6362
|
return cachedPattern;
|
|
6362
6363
|
};
|
|
6363
6364
|
const splitMatches = (text, query) => {
|
|
@@ -7423,6 +7424,71 @@ var ProvidersEvoSearchSdk = (function () {
|
|
|
7423
7424
|
return sections;
|
|
7424
7425
|
};
|
|
7425
7426
|
|
|
7427
|
+
// Pure tokenizer for the Ask AI answer, kept out of the Lit component so Jest
|
|
7428
|
+
// can spec it without pulling in `lit`'s ESM bundle. The widget wraps the
|
|
7429
|
+
// `bold` segments in <strong> — see `renderAskAnswerText`.
|
|
7430
|
+
//
|
|
7431
|
+
// Highlighting is driven by the cited product/collection titles (the items the
|
|
7432
|
+
// model actually selected), not by whether the model remembered to wrap them
|
|
7433
|
+
// in `**` markers. We still honor any server-validated `**bold**` spans, then
|
|
7434
|
+
// additionally bold every cited title the model named in plain prose — so a
|
|
7435
|
+
// referred product is highlighted even when the model omits the markers.
|
|
7436
|
+
const escapeRegex = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
7437
|
+
// One alternation of all cited titles, longest-first so the most specific
|
|
7438
|
+
// title wins when one is a prefix of another (regex alternation is leftmost,
|
|
7439
|
+
// not longest). Wrapped in Unicode-aware boundary lookarounds so a short title
|
|
7440
|
+
// never matches inside a larger word. Null when there are no titles to
|
|
7441
|
+
// highlight.
|
|
7442
|
+
const buildTitlePattern = (titles) => {
|
|
7443
|
+
const needles = Array.from(new Set(titles.map((title) => title.trim()).filter((title) => title.length))).sort((a, b) => b.length - a.length);
|
|
7444
|
+
if (!needles.length) {
|
|
7445
|
+
return null;
|
|
7446
|
+
}
|
|
7447
|
+
const alternation = needles.map(escapeRegex).join('|');
|
|
7448
|
+
return new RegExp(`(?<![\\p{L}\\p{N}])(?:${alternation})(?![\\p{L}\\p{N}])`, 'giu');
|
|
7449
|
+
};
|
|
7450
|
+
const pushTitleMatches = (segment, pattern, out) => {
|
|
7451
|
+
var _a;
|
|
7452
|
+
if (!pattern) {
|
|
7453
|
+
out.push({ text: segment, bold: false });
|
|
7454
|
+
return;
|
|
7455
|
+
}
|
|
7456
|
+
pattern.lastIndex = 0;
|
|
7457
|
+
let cursor = 0;
|
|
7458
|
+
for (const match of segment.matchAll(pattern)) {
|
|
7459
|
+
const start = (_a = match.index) !== null && _a !== void 0 ? _a : cursor;
|
|
7460
|
+
if (start > cursor) {
|
|
7461
|
+
out.push({ text: segment.slice(cursor, start), bold: false });
|
|
7462
|
+
}
|
|
7463
|
+
out.push({ text: match[0], bold: true });
|
|
7464
|
+
cursor = start + match[0].length;
|
|
7465
|
+
}
|
|
7466
|
+
if (cursor < segment.length) {
|
|
7467
|
+
out.push({ text: segment.slice(cursor), bold: false });
|
|
7468
|
+
}
|
|
7469
|
+
};
|
|
7470
|
+
const splitAnswerHighlights = (text, titles) => {
|
|
7471
|
+
const haystack = (text !== null && text !== void 0 ? text : '').trim();
|
|
7472
|
+
if (!haystack) {
|
|
7473
|
+
return [];
|
|
7474
|
+
}
|
|
7475
|
+
const pattern = buildTitlePattern(titles);
|
|
7476
|
+
const out = [];
|
|
7477
|
+
// Odd-indexed split parts are the inside of a model-emitted `**…**` span.
|
|
7478
|
+
haystack.split('**').forEach((segment, i) => {
|
|
7479
|
+
if (!segment) {
|
|
7480
|
+
return;
|
|
7481
|
+
}
|
|
7482
|
+
if (i % 2 === 1) {
|
|
7483
|
+
out.push({ text: segment, bold: true });
|
|
7484
|
+
}
|
|
7485
|
+
else {
|
|
7486
|
+
pushTitleMatches(segment, pattern, out);
|
|
7487
|
+
}
|
|
7488
|
+
});
|
|
7489
|
+
return out;
|
|
7490
|
+
};
|
|
7491
|
+
|
|
7426
7492
|
const renderErrorState = (css, onAction) => b `
|
|
7427
7493
|
<evs-state-block
|
|
7428
7494
|
.css=${css}
|
|
@@ -8234,11 +8300,9 @@ var ProvidersEvoSearchSdk = (function () {
|
|
|
8234
8300
|
// Default "Try asking" prompts shown on the Ask AI empty state when the
|
|
8235
8301
|
// merchant hasn't configured their own via `uiPreferences.askStarters`.
|
|
8236
8302
|
const FALLBACK_ASK_STARTERS = [
|
|
8237
|
-
|
|
8303
|
+
'Help me find a gift',
|
|
8238
8304
|
'Gift ideas under $50',
|
|
8239
|
-
'
|
|
8240
|
-
'Recommend something for my mom',
|
|
8241
|
-
'Show me your bestsellers',
|
|
8305
|
+
"I'm not sure what to get",
|
|
8242
8306
|
];
|
|
8243
8307
|
class SearchWidget extends ElementWithStylesheet {
|
|
8244
8308
|
constructor() {
|
|
@@ -8261,6 +8325,10 @@ var ProvidersEvoSearchSdk = (function () {
|
|
|
8261
8325
|
this.lastAskedQuery = '';
|
|
8262
8326
|
this.askAnswer = '';
|
|
8263
8327
|
this.askEvidence = null;
|
|
8328
|
+
// Titles of the products/collections the model actually cited, used to
|
|
8329
|
+
// highlight their names in the answer prose regardless of whether the model
|
|
8330
|
+
// wrapped them in `**` markers. Populated from the `citations` event.
|
|
8331
|
+
this.askCitedTitles = [];
|
|
8264
8332
|
this.askFollowUps = [];
|
|
8265
8333
|
this.askLoading = false;
|
|
8266
8334
|
this.askAbort = null;
|
|
@@ -8452,6 +8520,7 @@ var ProvidersEvoSearchSdk = (function () {
|
|
|
8452
8520
|
this.answerFlushHandle = null;
|
|
8453
8521
|
}
|
|
8454
8522
|
this.pendingAnswerChunk = '';
|
|
8523
|
+
this.askCitedTitles = [];
|
|
8455
8524
|
}
|
|
8456
8525
|
async submitAsk(query) {
|
|
8457
8526
|
var _a, _b;
|
|
@@ -8479,6 +8548,7 @@ var ProvidersEvoSearchSdk = (function () {
|
|
|
8479
8548
|
this.scheduleAnswerFlush();
|
|
8480
8549
|
}
|
|
8481
8550
|
else if (event.type === 'citations') {
|
|
8551
|
+
this.askCitedTitles = event.citations.resolved.map((c) => c.title);
|
|
8482
8552
|
this.reorderEvidenceByCitations(event.citations);
|
|
8483
8553
|
}
|
|
8484
8554
|
else if (event.type === 'follow-ups') {
|
|
@@ -8592,8 +8662,8 @@ var ProvidersEvoSearchSdk = (function () {
|
|
|
8592
8662
|
// just submitted — same affordance as typing it themselves.
|
|
8593
8663
|
this.searchQuery = trimmed;
|
|
8594
8664
|
this.lastAskedQuery = trimmed;
|
|
8595
|
-
// The answer is the surface now — collapse the typeahead hints
|
|
8596
|
-
//
|
|
8665
|
+
// The answer is the surface now — collapse the pre-submit typeahead hints.
|
|
8666
|
+
// (Search-mode suggestions stay visible; this is ask-only.)
|
|
8597
8667
|
this.showSuggestions = false;
|
|
8598
8668
|
// Treat ask submissions as query history so the Recent rail surfaces
|
|
8599
8669
|
// them on the next visit, identical to how typed searches behave.
|
|
@@ -8693,9 +8763,8 @@ var ProvidersEvoSearchSdk = (function () {
|
|
|
8693
8763
|
if (this.hasError || !this.debouncedQuery || this.mode !== 'search') {
|
|
8694
8764
|
return;
|
|
8695
8765
|
}
|
|
8696
|
-
//
|
|
8697
|
-
//
|
|
8698
|
-
this.showSuggestions = false;
|
|
8766
|
+
// Suggestions stay visible above the results until the query is cleared
|
|
8767
|
+
// (no settle-time collapse).
|
|
8699
8768
|
// Collections are first-class results on the unified surface — a
|
|
8700
8769
|
// collections-only match must not be reported as zero-result.
|
|
8701
8770
|
this.markQueryFinalized(this.debouncedQuery, this.searchProducts.length + this.searchCollections.length);
|
|
@@ -8870,6 +8939,9 @@ var ProvidersEvoSearchSdk = (function () {
|
|
|
8870
8939
|
// a terminal action, though: finalize the query now (or as soon as the
|
|
8871
8940
|
// in-flight debounce/fetch renders). The pending debounce timer must NOT
|
|
8872
8941
|
// be cleared here — cancelling it would strand `loading = true` forever.
|
|
8942
|
+
// Enter also collapses the typeahead — a terminal action, unlike the
|
|
8943
|
+
// settle pause which now leaves the suggestions in place.
|
|
8944
|
+
this.showSuggestions = false;
|
|
8873
8945
|
const trimmed = query.trim();
|
|
8874
8946
|
if (trimmed.length >= MIN_QUERY_LENGTH) {
|
|
8875
8947
|
if (this.hasError) {
|
|
@@ -9041,6 +9113,7 @@ var ProvidersEvoSearchSdk = (function () {
|
|
|
9041
9113
|
askAnswer: this.askAnswer,
|
|
9042
9114
|
askEvidence: this.askEvidence,
|
|
9043
9115
|
askFollowUps: this.askFollowUps,
|
|
9116
|
+
askCitedTitles: this.askCitedTitles,
|
|
9044
9117
|
});
|
|
9045
9118
|
}
|
|
9046
9119
|
// Restore the last snapshot on mount. Sets state directly — no network — so
|
|
@@ -9070,6 +9143,7 @@ var ProvidersEvoSearchSdk = (function () {
|
|
|
9070
9143
|
this.askAnswer = snap.askAnswer;
|
|
9071
9144
|
this.askEvidence = snap.askEvidence;
|
|
9072
9145
|
this.askFollowUps = snap.askFollowUps;
|
|
9146
|
+
this.askCitedTitles = snap.askCitedTitles;
|
|
9073
9147
|
}
|
|
9074
9148
|
this.mode = snap.mode === 'ask' && hasAnswer ? 'ask' : 'search';
|
|
9075
9149
|
}
|
|
@@ -9118,14 +9192,17 @@ var ProvidersEvoSearchSdk = (function () {
|
|
|
9118
9192
|
}
|
|
9119
9193
|
return b ``;
|
|
9120
9194
|
}
|
|
9121
|
-
// Bold the
|
|
9195
|
+
// Bold the part of the suggestion that matches the shopper's query;
|
|
9196
|
+
// leave the rest unstyled. Matches anywhere in the phrase, not just the
|
|
9197
|
+
// prefix, since completions aren't always prefix matches of the query.
|
|
9122
9198
|
renderPredicted(value) {
|
|
9123
9199
|
const q = this.searchQuery.trim();
|
|
9124
|
-
if (q
|
|
9125
|
-
return b
|
|
9126
|
-
><b>${value.slice(q.length)}</b>`;
|
|
9200
|
+
if (!q) {
|
|
9201
|
+
return b `${value}`;
|
|
9127
9202
|
}
|
|
9128
|
-
|
|
9203
|
+
const escaped = q.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
9204
|
+
const parts = value.split(new RegExp(`(${escaped})`, 'gi'));
|
|
9205
|
+
return b `${parts.map((part, i) => i % 2 === 1 ? b `<b>${part}</b>` : b `${part}`)}`;
|
|
9129
9206
|
}
|
|
9130
9207
|
renderSuggestions(section) {
|
|
9131
9208
|
if (!section.items.length) {
|
|
@@ -9340,8 +9417,8 @@ var ProvidersEvoSearchSdk = (function () {
|
|
|
9340
9417
|
`;
|
|
9341
9418
|
}
|
|
9342
9419
|
renderAskAnswerText(text) {
|
|
9343
|
-
const
|
|
9344
|
-
return b `${
|
|
9420
|
+
const segments = splitAnswerHighlights(text, this.askCitedTitles);
|
|
9421
|
+
return b `${segments.map((segment) => segment.bold ? b `<strong>${segment.text}</strong>` : segment.text)}`;
|
|
9345
9422
|
}
|
|
9346
9423
|
renderAskPane() {
|
|
9347
9424
|
// Once the LLM has finished talking, show the centered starter chips
|
|
@@ -9748,6 +9825,10 @@ var ProvidersEvoSearchSdk = (function () {
|
|
|
9748
9825
|
r$1(),
|
|
9749
9826
|
__metadata("design:type", Object)
|
|
9750
9827
|
], SearchWidget.prototype, "askEvidence", void 0);
|
|
9828
|
+
__decorate([
|
|
9829
|
+
r$1(),
|
|
9830
|
+
__metadata("design:type", Array)
|
|
9831
|
+
], SearchWidget.prototype, "askCitedTitles", void 0);
|
|
9751
9832
|
__decorate([
|
|
9752
9833
|
r$1(),
|
|
9753
9834
|
__metadata("design:type", Array)
|
package/index.mjs
CHANGED
|
@@ -604,7 +604,7 @@ const setStoredSearchMode = (mode) => {
|
|
|
604
604
|
const searchSessionKeyName = 'evoSearchSession';
|
|
605
605
|
const SEARCH_SESSION_VERSION = 1;
|
|
606
606
|
const getStoredSearchSession = () => {
|
|
607
|
-
var _a, _b, _c, _d, _e, _f;
|
|
607
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
608
608
|
try {
|
|
609
609
|
const raw = sessionStorage.getItem(searchSessionKeyName);
|
|
610
610
|
if (!raw) {
|
|
@@ -629,6 +629,7 @@ const getStoredSearchSession = () => {
|
|
|
629
629
|
askAnswer: (_d = parsed.askAnswer) !== null && _d !== void 0 ? _d : '',
|
|
630
630
|
askEvidence: (_e = parsed.askEvidence) !== null && _e !== void 0 ? _e : null,
|
|
631
631
|
askFollowUps: (_f = parsed.askFollowUps) !== null && _f !== void 0 ? _f : [],
|
|
632
|
+
askCitedTitles: (_g = parsed.askCitedTitles) !== null && _g !== void 0 ? _g : [],
|
|
632
633
|
};
|
|
633
634
|
}
|
|
634
635
|
catch {
|
|
@@ -6343,7 +6344,7 @@ const u=(e,s,t)=>{const r=new Map;for(let l=s;l<=t;l++)r.set(e[l],l);return r},c
|
|
|
6343
6344
|
// Pure tokenizer kept out of `highlight.ts` so Jest can spec it without
|
|
6344
6345
|
// pulling in `lit`'s ESM bundle. The renderer wraps these tokens in
|
|
6345
6346
|
// <mark> via a Lit template — see `highlight.ts`.
|
|
6346
|
-
const escapeRegex = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
6347
|
+
const escapeRegex$1 = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
6347
6348
|
// Compiling a `RegExp` per call is hot under autocomplete (every result row
|
|
6348
6349
|
// + collection card + suggestion item, all sharing the same query). Keep a
|
|
6349
6350
|
// single-slot memo keyed on the trimmed query.
|
|
@@ -6354,7 +6355,7 @@ const patternFor = (needle) => {
|
|
|
6354
6355
|
return cachedPattern;
|
|
6355
6356
|
}
|
|
6356
6357
|
cachedNeedle = needle;
|
|
6357
|
-
cachedPattern = new RegExp(escapeRegex(needle), 'ig');
|
|
6358
|
+
cachedPattern = new RegExp(escapeRegex$1(needle), 'ig');
|
|
6358
6359
|
return cachedPattern;
|
|
6359
6360
|
};
|
|
6360
6361
|
const splitMatches = (text, query) => {
|
|
@@ -7420,6 +7421,71 @@ const buildRailSections = ({ searchQuery, suggestions, trendingSearches, recents
|
|
|
7420
7421
|
return sections;
|
|
7421
7422
|
};
|
|
7422
7423
|
|
|
7424
|
+
// Pure tokenizer for the Ask AI answer, kept out of the Lit component so Jest
|
|
7425
|
+
// can spec it without pulling in `lit`'s ESM bundle. The widget wraps the
|
|
7426
|
+
// `bold` segments in <strong> — see `renderAskAnswerText`.
|
|
7427
|
+
//
|
|
7428
|
+
// Highlighting is driven by the cited product/collection titles (the items the
|
|
7429
|
+
// model actually selected), not by whether the model remembered to wrap them
|
|
7430
|
+
// in `**` markers. We still honor any server-validated `**bold**` spans, then
|
|
7431
|
+
// additionally bold every cited title the model named in plain prose — so a
|
|
7432
|
+
// referred product is highlighted even when the model omits the markers.
|
|
7433
|
+
const escapeRegex = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
7434
|
+
// One alternation of all cited titles, longest-first so the most specific
|
|
7435
|
+
// title wins when one is a prefix of another (regex alternation is leftmost,
|
|
7436
|
+
// not longest). Wrapped in Unicode-aware boundary lookarounds so a short title
|
|
7437
|
+
// never matches inside a larger word. Null when there are no titles to
|
|
7438
|
+
// highlight.
|
|
7439
|
+
const buildTitlePattern = (titles) => {
|
|
7440
|
+
const needles = Array.from(new Set(titles.map((title) => title.trim()).filter((title) => title.length))).sort((a, b) => b.length - a.length);
|
|
7441
|
+
if (!needles.length) {
|
|
7442
|
+
return null;
|
|
7443
|
+
}
|
|
7444
|
+
const alternation = needles.map(escapeRegex).join('|');
|
|
7445
|
+
return new RegExp(`(?<![\\p{L}\\p{N}])(?:${alternation})(?![\\p{L}\\p{N}])`, 'giu');
|
|
7446
|
+
};
|
|
7447
|
+
const pushTitleMatches = (segment, pattern, out) => {
|
|
7448
|
+
var _a;
|
|
7449
|
+
if (!pattern) {
|
|
7450
|
+
out.push({ text: segment, bold: false });
|
|
7451
|
+
return;
|
|
7452
|
+
}
|
|
7453
|
+
pattern.lastIndex = 0;
|
|
7454
|
+
let cursor = 0;
|
|
7455
|
+
for (const match of segment.matchAll(pattern)) {
|
|
7456
|
+
const start = (_a = match.index) !== null && _a !== void 0 ? _a : cursor;
|
|
7457
|
+
if (start > cursor) {
|
|
7458
|
+
out.push({ text: segment.slice(cursor, start), bold: false });
|
|
7459
|
+
}
|
|
7460
|
+
out.push({ text: match[0], bold: true });
|
|
7461
|
+
cursor = start + match[0].length;
|
|
7462
|
+
}
|
|
7463
|
+
if (cursor < segment.length) {
|
|
7464
|
+
out.push({ text: segment.slice(cursor), bold: false });
|
|
7465
|
+
}
|
|
7466
|
+
};
|
|
7467
|
+
const splitAnswerHighlights = (text, titles) => {
|
|
7468
|
+
const haystack = (text !== null && text !== void 0 ? text : '').trim();
|
|
7469
|
+
if (!haystack) {
|
|
7470
|
+
return [];
|
|
7471
|
+
}
|
|
7472
|
+
const pattern = buildTitlePattern(titles);
|
|
7473
|
+
const out = [];
|
|
7474
|
+
// Odd-indexed split parts are the inside of a model-emitted `**…**` span.
|
|
7475
|
+
haystack.split('**').forEach((segment, i) => {
|
|
7476
|
+
if (!segment) {
|
|
7477
|
+
return;
|
|
7478
|
+
}
|
|
7479
|
+
if (i % 2 === 1) {
|
|
7480
|
+
out.push({ text: segment, bold: true });
|
|
7481
|
+
}
|
|
7482
|
+
else {
|
|
7483
|
+
pushTitleMatches(segment, pattern, out);
|
|
7484
|
+
}
|
|
7485
|
+
});
|
|
7486
|
+
return out;
|
|
7487
|
+
};
|
|
7488
|
+
|
|
7423
7489
|
const renderErrorState = (css, onAction) => b `
|
|
7424
7490
|
<evs-state-block
|
|
7425
7491
|
.css=${css}
|
|
@@ -8231,11 +8297,9 @@ const isCancelled = (error) => error instanceof Error &&
|
|
|
8231
8297
|
// Default "Try asking" prompts shown on the Ask AI empty state when the
|
|
8232
8298
|
// merchant hasn't configured their own via `uiPreferences.askStarters`.
|
|
8233
8299
|
const FALLBACK_ASK_STARTERS = [
|
|
8234
|
-
|
|
8300
|
+
'Help me find a gift',
|
|
8235
8301
|
'Gift ideas under $50',
|
|
8236
|
-
'
|
|
8237
|
-
'Recommend something for my mom',
|
|
8238
|
-
'Show me your bestsellers',
|
|
8302
|
+
"I'm not sure what to get",
|
|
8239
8303
|
];
|
|
8240
8304
|
class SearchWidget extends ElementWithStylesheet {
|
|
8241
8305
|
constructor() {
|
|
@@ -8258,6 +8322,10 @@ class SearchWidget extends ElementWithStylesheet {
|
|
|
8258
8322
|
this.lastAskedQuery = '';
|
|
8259
8323
|
this.askAnswer = '';
|
|
8260
8324
|
this.askEvidence = null;
|
|
8325
|
+
// Titles of the products/collections the model actually cited, used to
|
|
8326
|
+
// highlight their names in the answer prose regardless of whether the model
|
|
8327
|
+
// wrapped them in `**` markers. Populated from the `citations` event.
|
|
8328
|
+
this.askCitedTitles = [];
|
|
8261
8329
|
this.askFollowUps = [];
|
|
8262
8330
|
this.askLoading = false;
|
|
8263
8331
|
this.askAbort = null;
|
|
@@ -8449,6 +8517,7 @@ class SearchWidget extends ElementWithStylesheet {
|
|
|
8449
8517
|
this.answerFlushHandle = null;
|
|
8450
8518
|
}
|
|
8451
8519
|
this.pendingAnswerChunk = '';
|
|
8520
|
+
this.askCitedTitles = [];
|
|
8452
8521
|
}
|
|
8453
8522
|
async submitAsk(query) {
|
|
8454
8523
|
var _a, _b;
|
|
@@ -8476,6 +8545,7 @@ class SearchWidget extends ElementWithStylesheet {
|
|
|
8476
8545
|
this.scheduleAnswerFlush();
|
|
8477
8546
|
}
|
|
8478
8547
|
else if (event.type === 'citations') {
|
|
8548
|
+
this.askCitedTitles = event.citations.resolved.map((c) => c.title);
|
|
8479
8549
|
this.reorderEvidenceByCitations(event.citations);
|
|
8480
8550
|
}
|
|
8481
8551
|
else if (event.type === 'follow-ups') {
|
|
@@ -8589,8 +8659,8 @@ class SearchWidget extends ElementWithStylesheet {
|
|
|
8589
8659
|
// just submitted — same affordance as typing it themselves.
|
|
8590
8660
|
this.searchQuery = trimmed;
|
|
8591
8661
|
this.lastAskedQuery = trimmed;
|
|
8592
|
-
// The answer is the surface now — collapse the typeahead hints
|
|
8593
|
-
//
|
|
8662
|
+
// The answer is the surface now — collapse the pre-submit typeahead hints.
|
|
8663
|
+
// (Search-mode suggestions stay visible; this is ask-only.)
|
|
8594
8664
|
this.showSuggestions = false;
|
|
8595
8665
|
// Treat ask submissions as query history so the Recent rail surfaces
|
|
8596
8666
|
// them on the next visit, identical to how typed searches behave.
|
|
@@ -8690,9 +8760,8 @@ class SearchWidget extends ElementWithStylesheet {
|
|
|
8690
8760
|
if (this.hasError || !this.debouncedQuery || this.mode !== 'search') {
|
|
8691
8761
|
return;
|
|
8692
8762
|
}
|
|
8693
|
-
//
|
|
8694
|
-
//
|
|
8695
|
-
this.showSuggestions = false;
|
|
8763
|
+
// Suggestions stay visible above the results until the query is cleared
|
|
8764
|
+
// (no settle-time collapse).
|
|
8696
8765
|
// Collections are first-class results on the unified surface — a
|
|
8697
8766
|
// collections-only match must not be reported as zero-result.
|
|
8698
8767
|
this.markQueryFinalized(this.debouncedQuery, this.searchProducts.length + this.searchCollections.length);
|
|
@@ -8867,6 +8936,9 @@ class SearchWidget extends ElementWithStylesheet {
|
|
|
8867
8936
|
// a terminal action, though: finalize the query now (or as soon as the
|
|
8868
8937
|
// in-flight debounce/fetch renders). The pending debounce timer must NOT
|
|
8869
8938
|
// be cleared here — cancelling it would strand `loading = true` forever.
|
|
8939
|
+
// Enter also collapses the typeahead — a terminal action, unlike the
|
|
8940
|
+
// settle pause which now leaves the suggestions in place.
|
|
8941
|
+
this.showSuggestions = false;
|
|
8870
8942
|
const trimmed = query.trim();
|
|
8871
8943
|
if (trimmed.length >= MIN_QUERY_LENGTH) {
|
|
8872
8944
|
if (this.hasError) {
|
|
@@ -9038,6 +9110,7 @@ class SearchWidget extends ElementWithStylesheet {
|
|
|
9038
9110
|
askAnswer: this.askAnswer,
|
|
9039
9111
|
askEvidence: this.askEvidence,
|
|
9040
9112
|
askFollowUps: this.askFollowUps,
|
|
9113
|
+
askCitedTitles: this.askCitedTitles,
|
|
9041
9114
|
});
|
|
9042
9115
|
}
|
|
9043
9116
|
// Restore the last snapshot on mount. Sets state directly — no network — so
|
|
@@ -9067,6 +9140,7 @@ class SearchWidget extends ElementWithStylesheet {
|
|
|
9067
9140
|
this.askAnswer = snap.askAnswer;
|
|
9068
9141
|
this.askEvidence = snap.askEvidence;
|
|
9069
9142
|
this.askFollowUps = snap.askFollowUps;
|
|
9143
|
+
this.askCitedTitles = snap.askCitedTitles;
|
|
9070
9144
|
}
|
|
9071
9145
|
this.mode = snap.mode === 'ask' && hasAnswer ? 'ask' : 'search';
|
|
9072
9146
|
}
|
|
@@ -9115,14 +9189,17 @@ class SearchWidget extends ElementWithStylesheet {
|
|
|
9115
9189
|
}
|
|
9116
9190
|
return b ``;
|
|
9117
9191
|
}
|
|
9118
|
-
// Bold the
|
|
9192
|
+
// Bold the part of the suggestion that matches the shopper's query;
|
|
9193
|
+
// leave the rest unstyled. Matches anywhere in the phrase, not just the
|
|
9194
|
+
// prefix, since completions aren't always prefix matches of the query.
|
|
9119
9195
|
renderPredicted(value) {
|
|
9120
9196
|
const q = this.searchQuery.trim();
|
|
9121
|
-
if (q
|
|
9122
|
-
return b
|
|
9123
|
-
><b>${value.slice(q.length)}</b>`;
|
|
9197
|
+
if (!q) {
|
|
9198
|
+
return b `${value}`;
|
|
9124
9199
|
}
|
|
9125
|
-
|
|
9200
|
+
const escaped = q.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
9201
|
+
const parts = value.split(new RegExp(`(${escaped})`, 'gi'));
|
|
9202
|
+
return b `${parts.map((part, i) => i % 2 === 1 ? b `<b>${part}</b>` : b `${part}`)}`;
|
|
9126
9203
|
}
|
|
9127
9204
|
renderSuggestions(section) {
|
|
9128
9205
|
if (!section.items.length) {
|
|
@@ -9337,8 +9414,8 @@ class SearchWidget extends ElementWithStylesheet {
|
|
|
9337
9414
|
`;
|
|
9338
9415
|
}
|
|
9339
9416
|
renderAskAnswerText(text) {
|
|
9340
|
-
const
|
|
9341
|
-
return b `${
|
|
9417
|
+
const segments = splitAnswerHighlights(text, this.askCitedTitles);
|
|
9418
|
+
return b `${segments.map((segment) => segment.bold ? b `<strong>${segment.text}</strong>` : segment.text)}`;
|
|
9342
9419
|
}
|
|
9343
9420
|
renderAskPane() {
|
|
9344
9421
|
// Once the LLM has finished talking, show the centered starter chips
|
|
@@ -9745,6 +9822,10 @@ __decorate([
|
|
|
9745
9822
|
r$1(),
|
|
9746
9823
|
__metadata("design:type", Object)
|
|
9747
9824
|
], SearchWidget.prototype, "askEvidence", void 0);
|
|
9825
|
+
__decorate([
|
|
9826
|
+
r$1(),
|
|
9827
|
+
__metadata("design:type", Array)
|
|
9828
|
+
], SearchWidget.prototype, "askCitedTitles", void 0);
|
|
9748
9829
|
__decorate([
|
|
9749
9830
|
r$1(),
|
|
9750
9831
|
__metadata("design:type", Array)
|