@librechat/agents 2.4.31 → 2.4.34

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.
Files changed (115) hide show
  1. package/dist/cjs/events.cjs +3 -3
  2. package/dist/cjs/events.cjs.map +1 -1
  3. package/dist/cjs/graphs/Graph.cjs +2 -1
  4. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  5. package/dist/cjs/main.cjs +5 -2
  6. package/dist/cjs/main.cjs.map +1 -1
  7. package/dist/cjs/messages/ids.cjs +23 -0
  8. package/dist/cjs/messages/ids.cjs.map +1 -0
  9. package/dist/cjs/splitStream.cjs +2 -1
  10. package/dist/cjs/splitStream.cjs.map +1 -1
  11. package/dist/cjs/stream.cjs +87 -154
  12. package/dist/cjs/stream.cjs.map +1 -1
  13. package/dist/cjs/tools/ToolNode.cjs +14 -3
  14. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  15. package/dist/cjs/tools/handlers.cjs +144 -0
  16. package/dist/cjs/tools/handlers.cjs.map +1 -0
  17. package/dist/cjs/tools/search/content.cjs +140 -0
  18. package/dist/cjs/tools/search/content.cjs.map +1 -0
  19. package/dist/cjs/tools/search/firecrawl.cjs +23 -41
  20. package/dist/cjs/tools/search/firecrawl.cjs.map +1 -1
  21. package/dist/cjs/tools/search/format.cjs +161 -74
  22. package/dist/cjs/tools/search/format.cjs.map +1 -1
  23. package/dist/cjs/tools/search/highlights.cjs +64 -12
  24. package/dist/cjs/tools/search/highlights.cjs.map +1 -1
  25. package/dist/cjs/tools/search/rerankers.cjs +35 -50
  26. package/dist/cjs/tools/search/rerankers.cjs.map +1 -1
  27. package/dist/cjs/tools/search/schema.cjs +70 -0
  28. package/dist/cjs/tools/search/schema.cjs.map +1 -0
  29. package/dist/cjs/tools/search/search.cjs +153 -69
  30. package/dist/cjs/tools/search/search.cjs.map +1 -1
  31. package/dist/cjs/tools/search/tool.cjs +247 -58
  32. package/dist/cjs/tools/search/tool.cjs.map +1 -1
  33. package/dist/cjs/tools/search/utils.cjs +66 -0
  34. package/dist/cjs/tools/search/utils.cjs.map +1 -0
  35. package/dist/esm/events.mjs +1 -1
  36. package/dist/esm/events.mjs.map +1 -1
  37. package/dist/esm/graphs/Graph.mjs +2 -1
  38. package/dist/esm/graphs/Graph.mjs.map +1 -1
  39. package/dist/esm/main.mjs +3 -1
  40. package/dist/esm/main.mjs.map +1 -1
  41. package/dist/esm/messages/ids.mjs +21 -0
  42. package/dist/esm/messages/ids.mjs.map +1 -0
  43. package/dist/esm/splitStream.mjs +2 -1
  44. package/dist/esm/splitStream.mjs.map +1 -1
  45. package/dist/esm/stream.mjs +87 -152
  46. package/dist/esm/stream.mjs.map +1 -1
  47. package/dist/esm/tools/ToolNode.mjs +14 -3
  48. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  49. package/dist/esm/tools/handlers.mjs +141 -0
  50. package/dist/esm/tools/handlers.mjs.map +1 -0
  51. package/dist/esm/tools/search/content.mjs +119 -0
  52. package/dist/esm/tools/search/content.mjs.map +1 -0
  53. package/dist/esm/tools/search/firecrawl.mjs +24 -41
  54. package/dist/esm/tools/search/firecrawl.mjs.map +1 -1
  55. package/dist/esm/tools/search/format.mjs +161 -74
  56. package/dist/esm/tools/search/format.mjs.map +1 -1
  57. package/dist/esm/tools/search/highlights.mjs +64 -12
  58. package/dist/esm/tools/search/highlights.mjs.map +1 -1
  59. package/dist/esm/tools/search/rerankers.mjs +35 -50
  60. package/dist/esm/tools/search/rerankers.mjs.map +1 -1
  61. package/dist/esm/tools/search/schema.mjs +61 -0
  62. package/dist/esm/tools/search/schema.mjs.map +1 -0
  63. package/dist/esm/tools/search/search.mjs +153 -69
  64. package/dist/esm/tools/search/search.mjs.map +1 -1
  65. package/dist/esm/tools/search/tool.mjs +246 -57
  66. package/dist/esm/tools/search/tool.mjs.map +1 -1
  67. package/dist/esm/tools/search/utils.mjs +61 -0
  68. package/dist/esm/tools/search/utils.mjs.map +1 -0
  69. package/dist/types/graphs/Graph.d.ts +1 -1
  70. package/dist/types/index.d.ts +1 -0
  71. package/dist/types/messages/ids.d.ts +3 -0
  72. package/dist/types/messages/index.d.ts +1 -0
  73. package/dist/types/stream.d.ts +0 -8
  74. package/dist/types/tools/ToolNode.d.ts +6 -0
  75. package/dist/types/tools/example.d.ts +23 -3
  76. package/dist/types/tools/handlers.d.ts +8 -0
  77. package/dist/types/tools/search/content.d.ts +4 -0
  78. package/dist/types/tools/search/firecrawl.d.ts +7 -86
  79. package/dist/types/tools/search/format.d.ts +4 -1
  80. package/dist/types/tools/search/highlights.d.ts +1 -1
  81. package/dist/types/tools/search/rerankers.d.ts +8 -5
  82. package/dist/types/tools/search/schema.d.ts +16 -0
  83. package/dist/types/tools/search/search.d.ts +2 -2
  84. package/dist/types/tools/search/test.d.ts +1 -0
  85. package/dist/types/tools/search/tool.d.ts +25 -4
  86. package/dist/types/tools/search/types.d.ts +443 -53
  87. package/dist/types/tools/search/utils.d.ts +10 -0
  88. package/package.json +9 -7
  89. package/src/events.ts +49 -15
  90. package/src/graphs/Graph.ts +6 -2
  91. package/src/index.ts +1 -0
  92. package/src/messages/ids.ts +26 -0
  93. package/src/messages/index.ts +1 -0
  94. package/src/scripts/search.ts +8 -3
  95. package/src/splitStream.test.ts +132 -71
  96. package/src/splitStream.ts +2 -1
  97. package/src/stream.ts +94 -183
  98. package/src/tools/ToolNode.ts +37 -14
  99. package/src/tools/handlers.ts +167 -0
  100. package/src/tools/search/content.test.ts +173 -0
  101. package/src/tools/search/content.ts +147 -0
  102. package/src/tools/search/firecrawl.ts +36 -148
  103. package/src/tools/search/format.ts +205 -74
  104. package/src/tools/search/highlights.ts +99 -16
  105. package/src/tools/search/output.md +2775 -0
  106. package/src/tools/search/rerankers.ts +50 -62
  107. package/src/tools/search/schema.ts +63 -0
  108. package/src/tools/search/search.ts +232 -116
  109. package/src/tools/search/test.html +884 -0
  110. package/src/tools/search/test.md +643 -0
  111. package/src/tools/search/test.ts +159 -0
  112. package/src/tools/search/tool.ts +363 -87
  113. package/src/tools/search/types.ts +503 -61
  114. package/src/tools/search/utils.ts +79 -0
  115. package/src/utils/llmConfig.ts +1 -1
@@ -1,121 +1,252 @@
1
1
  import type * as t from './types';
2
+ import { getDomainName, fileExtRegex } from './utils';
2
3
 
3
- export function formatResultsForLLM(results: t.SearchResultData): string {
4
- let output = '';
4
+ function addHighlightSection(): string[] {
5
+ return ['\n## Highlights', ''];
6
+ }
7
+
8
+ // Helper function to format a source (organic or top story)
9
+ function formatSource(
10
+ source: t.ValidSource,
11
+ index: number,
12
+ turn: number,
13
+ sourceType: 'search' | 'news',
14
+ references: t.ResultReference[]
15
+ ): string {
16
+ /** Array of all lines to include in the output */
17
+ const outputLines: string[] = [];
18
+
19
+ // Add the title
20
+ outputLines.push(
21
+ `# ${sourceType.charAt(0).toUpperCase() + sourceType.slice(1)} ${index}: ${source.title != null && source.title ? `"${source.title}"` : '(no title)'}`
22
+ );
23
+ outputLines.push(`\nAnchor: \\ue202turn${turn}${sourceType}${index}`);
24
+ outputLines.push(`URL: ${source.link}`);
25
+
26
+ // Add optional fields
27
+ if ('snippet' in source && source.snippet != null) {
28
+ outputLines.push(`Summary: ${source.snippet}`);
29
+ }
30
+
31
+ if (source.date != null) {
32
+ outputLines.push(`Date: ${source.date}`);
33
+ }
34
+
35
+ if (source.attribution != null) {
36
+ outputLines.push(`Source: ${source.attribution}`);
37
+ }
38
+
39
+ // Add highlight section or empty line
40
+ if ((source.highlights?.length ?? 0) > 0) {
41
+ outputLines.push(...addHighlightSection());
42
+ } else {
43
+ outputLines.push('');
44
+ }
45
+
46
+ // Process highlights if they exist
47
+ (source.highlights ?? [])
48
+ .filter((h) => h.text.trim().length > 0)
49
+ .forEach((h, hIndex) => {
50
+ outputLines.push(
51
+ `### Highlight ${hIndex + 1} [Relevance: ${h.score.toFixed(2)}]`
52
+ );
53
+ outputLines.push('');
54
+ outputLines.push('```text');
55
+ outputLines.push(h.text.trim());
56
+ outputLines.push('```');
57
+ outputLines.push('');
58
+
59
+ if (h.references != null && h.references.length) {
60
+ let hasHeader = false;
61
+ const refLines: string[] = [];
62
+
63
+ for (let j = 0; j < h.references.length; j++) {
64
+ const ref = h.references[j];
65
+ if (ref.reference.originalUrl.includes('mailto:')) {
66
+ continue;
67
+ }
68
+ references.push({
69
+ type: ref.type,
70
+ link: ref.reference.originalUrl,
71
+ attribution: getDomainName(ref.reference.originalUrl),
72
+ title: (
73
+ ((ref.reference.title ?? '') || ref.reference.text) ??
74
+ ''
75
+ ).split('\n')[0],
76
+ });
77
+
78
+ if (ref.type !== 'link') {
79
+ continue;
80
+ }
81
+
82
+ if (fileExtRegex.test(ref.reference.originalUrl)) {
83
+ continue;
84
+ }
85
+
86
+ if (!hasHeader) {
87
+ refLines.push('Core References:');
88
+ hasHeader = true;
89
+ }
90
+
91
+ refLines.push(
92
+ `- ${ref.type}#${ref.originalIndex + 1}: ${ref.reference.originalUrl}`
93
+ );
94
+ refLines.push(
95
+ `\t- Anchor: \\ue202turn${turn}ref${references.length - 1}`
96
+ );
97
+ }
98
+
99
+ if (hasHeader) {
100
+ outputLines.push(...refLines);
101
+ outputLines.push('');
102
+ }
103
+ }
104
+
105
+ if (hIndex < (source.highlights?.length ?? 0) - 1) {
106
+ outputLines.push('---');
107
+ outputLines.push('');
108
+ }
109
+ });
110
+
111
+ outputLines.push('');
112
+ return outputLines.join('\n');
113
+ }
114
+
115
+ export function formatResultsForLLM(
116
+ turn: number,
117
+ results: t.SearchResultData
118
+ ): { output: string; references: t.ResultReference[] } {
119
+ /** Array to collect all output lines */
120
+ const outputLines: string[] = [];
5
121
 
6
122
  const addSection = (title: string): void => {
7
- output += `\n=== ${title} ===\n`;
123
+ outputLines.push('');
124
+ outputLines.push(`=== ${title} ===`);
125
+ outputLines.push('');
8
126
  };
9
127
 
128
+ const references: t.ResultReference[] = [];
129
+
10
130
  // Organic (web) results
11
- const organic = results.organic ?? [];
12
- if (organic.length) {
13
- addSection('Web Results');
14
- organic.forEach((r, i) => {
15
- output += [
16
- `Source ${i + 1}: ${r.title ?? '(no title)'}`,
17
- `Citation Anchor: \\ue202turn0search${i + 1}`,
18
- `URL: ${r.link}`,
19
- r.snippet != null ? `Summary: ${r.snippet}` : '',
20
- r.date != null ? `Date: ${r.date}` : '',
21
- r.attribution != null ? `Source: ${r.attribution}` : '',
22
- '',
23
- '--- Content Highlights ---',
24
- ...(r.highlights ?? [])
25
- .filter((h) => h.text.trim().length > 0)
26
- .map((h) => `[Relevance: ${h.score.toFixed(2)}]\n${h.text.trim()}`),
27
- '',
28
- ]
29
- .filter(Boolean)
30
- .join('\n');
31
- });
131
+ if (results.organic?.length != null && results.organic.length > 0) {
132
+ addSection(`Web Results, Turn ${turn}`);
133
+ for (let i = 0; i < results.organic.length; i++) {
134
+ const r = results.organic[i];
135
+ outputLines.push(formatSource(r, i, turn, 'search', references));
136
+ delete results.organic[i].highlights;
137
+ }
32
138
  }
33
139
 
34
- // Ignoring these sections for now
35
- // // Top stories (news)
36
- // const topStores = results.topStories ?? [];
37
- // if (topStores.length) {
38
- // addSection('News Results');
39
- // topStores.forEach((r, i) => {
40
- // output += [
41
- // `Anchor: \ue202turn0news${i + 1}`,
42
- // `Title: ${r.title ?? '(no title)'}`,
43
- // `URL: ${r.link}`,
44
- // r.snippet != null ? `Snippet: ${r.snippet}` : '',
45
- // r.date != null ? `Date: ${r.date}` : '',
46
- // r.attribution != null ? `Source: ${r.attribution}` : '',
47
- // ''
48
- // ].filter(Boolean).join('\n');
49
- // });
50
- // }
140
+ // Top stories (news)
141
+ const topStories = results.topStories ?? [];
142
+ if (topStories.length) {
143
+ addSection('News Results');
144
+ for (let i = 0; i < topStories.length; i++) {
145
+ const r = topStories[i];
146
+ outputLines.push(formatSource(r, i, turn, 'news', references));
147
+ if (results.topStories?.[i]?.highlights) {
148
+ delete results.topStories[i].highlights;
149
+ }
150
+ }
151
+ }
51
152
 
52
153
  // // Images
53
154
  // const images = results.images ?? [];
54
155
  // if (images.length) {
55
156
  // addSection('Image Results');
56
- // images.forEach((img, i) => {
57
- // output += [
58
- // `Anchor: \ue202turn0image${i + 1}`,
59
- // `Title: ${img.title ?? '(no title)'}`,
60
- // `Image URL: ${img.imageUrl}`,
61
- // ''
62
- // ].join('\n');
63
- // });
157
+ // const imageLines = images.map((img, i) => [
158
+ // `Anchor: \ue202turn0image${i}`,
159
+ // `Title: ${img.title ?? '(no title)'}`,
160
+ // `Image URL: ${img.imageUrl}`,
161
+ // ''
162
+ // ].join('\n'));
163
+ // outputLines.push(imageLines.join('\n'));
64
164
  // }
65
165
 
66
166
  // Knowledge Graph
67
167
  if (results.knowledgeGraph != null) {
68
168
  addSection('Knowledge Graph');
69
- output += [
70
- `Title: ${results.knowledgeGraph.title ?? '(no title)'}`,
169
+ const kgLines = [
170
+ `**Title:** ${results.knowledgeGraph.title ?? '(no title)'}`,
171
+ results.knowledgeGraph.type != null
172
+ ? `**Type:** ${results.knowledgeGraph.type}`
173
+ : '',
71
174
  results.knowledgeGraph.description != null
72
- ? `Description: ${results.knowledgeGraph.description}`
175
+ ? `**Description:** ${results.knowledgeGraph.description}`
73
176
  : '',
74
- results.knowledgeGraph.type != null
75
- ? `Type: ${results.knowledgeGraph.type}`
177
+ results.knowledgeGraph.descriptionSource != null
178
+ ? `**Description Source:** ${results.knowledgeGraph.descriptionSource}`
179
+ : '',
180
+ results.knowledgeGraph.descriptionLink != null
181
+ ? `**Description Link:** ${results.knowledgeGraph.descriptionLink}`
76
182
  : '',
77
183
  results.knowledgeGraph.imageUrl != null
78
- ? `Image URL: ${results.knowledgeGraph.imageUrl}`
184
+ ? `**Image URL:** ${results.knowledgeGraph.imageUrl}`
185
+ : '',
186
+ results.knowledgeGraph.website != null
187
+ ? `**Website:** ${results.knowledgeGraph.website}`
79
188
  : '',
80
189
  results.knowledgeGraph.attributes != null
81
- ? `Attributes: ${JSON.stringify(results.knowledgeGraph.attributes, null, 2)}`
190
+ ? `**Attributes:**\n\`\`\`json\n${JSON.stringify(
191
+ results.knowledgeGraph.attributes,
192
+ null,
193
+ 2
194
+ )}\n\`\`\``
82
195
  : '',
83
196
  '',
84
- ]
85
- .filter(Boolean)
86
- .join('\n');
197
+ ].filter(Boolean);
198
+
199
+ outputLines.push(kgLines.join('\n\n'));
87
200
  }
88
201
 
89
202
  // Answer Box
90
203
  if (results.answerBox != null) {
91
204
  addSection('Answer Box');
92
- output += [
205
+ const abLines = [
93
206
  results.answerBox.title != null
94
- ? `Title: ${results.answerBox.title}`
95
- : '',
96
- results.answerBox.answer != null
97
- ? `Answer: ${results.answerBox.answer}`
207
+ ? `**Title:** ${results.answerBox.title}`
98
208
  : '',
99
209
  results.answerBox.snippet != null
100
- ? `Snippet: ${results.answerBox.snippet}`
210
+ ? `**Snippet:** ${results.answerBox.snippet}`
211
+ : '',
212
+ results.answerBox.snippetHighlighted != null
213
+ ? `**Snippet Highlighted:** ${results.answerBox.snippetHighlighted
214
+ .map((s) => `\`${s}\``)
215
+ .join(' ')}`
216
+ : '',
217
+ results.answerBox.link != null
218
+ ? `**Link:** ${results.answerBox.link}`
101
219
  : '',
102
- results.answerBox.date != null ? `Date: ${results.answerBox.date}` : '',
103
220
  '',
104
- ]
105
- .filter(Boolean)
106
- .join('\n');
221
+ ].filter(Boolean);
222
+
223
+ outputLines.push(abLines.join('\n\n'));
107
224
  }
108
225
 
109
226
  // People also ask
110
227
  const peopleAlsoAsk = results.peopleAlsoAsk ?? [];
111
228
  if (peopleAlsoAsk.length) {
112
229
  addSection('People Also Ask');
113
- peopleAlsoAsk.forEach((p, _i) => {
114
- output += [`Q: ${p.question}`, `A: ${p.answer}`, '']
115
- .filter(Boolean)
116
- .join('\n');
230
+
231
+ const paaLines: string[] = [];
232
+ peopleAlsoAsk.forEach((p, i) => {
233
+ const questionLines = [
234
+ `### Question ${i + 1}:`,
235
+ `"${p.question}"`,
236
+ `${p.snippet != null && p.snippet ? `Snippet: ${p.snippet}` : ''}`,
237
+ `${p.title != null && p.title ? `Title: ${p.title}` : ''}`,
238
+ `${p.link != null && p.link ? `Link: ${p.link}` : ''}`,
239
+ '',
240
+ ].filter(Boolean);
241
+
242
+ paaLines.push(questionLines.join('\n\n'));
117
243
  });
244
+
245
+ outputLines.push(paaLines.join(''));
118
246
  }
119
247
 
120
- return output.trim();
248
+ return {
249
+ output: outputLines.join('\n').trim(),
250
+ references,
251
+ };
121
252
  }
@@ -122,6 +122,89 @@ function findBestBoundary(text: string, direction = 'backward'): number {
122
122
  return direction === 'backward' ? text.length : 0;
123
123
  }
124
124
 
125
+ /**
126
+ * Tracks references used in a highlight without changing their numbers
127
+ */
128
+ function trackReferencesInHighlight(
129
+ text: string,
130
+ sourceResult: t.ValidSource // Source containing the original references
131
+ ): {
132
+ references: {
133
+ type: 'link' | 'image' | 'video';
134
+ originalIndex: number;
135
+ reference: t.MediaReference; // Original reference object
136
+ }[];
137
+ } {
138
+ // Track used references
139
+ const references: {
140
+ type: 'link' | 'image' | 'video';
141
+ originalIndex: number;
142
+ reference: t.MediaReference;
143
+ }[] = [];
144
+
145
+ if (!text || text.length === 0 || !text.includes('#')) {
146
+ return { references }; // Early return
147
+ }
148
+
149
+ // Quick check for reference markers
150
+ if (
151
+ !text.includes('link#') &&
152
+ !text.includes('image#') &&
153
+ !text.includes('video#')
154
+ ) {
155
+ return { references };
156
+ }
157
+
158
+ // Get references from the source if available
159
+ const sourceRefs = sourceResult.references || {
160
+ links: [],
161
+ images: [],
162
+ videos: [],
163
+ };
164
+
165
+ // Find references but don't modify text
166
+ const refRegex = /\((link|image|video)#(\d+)(?:\s+"([^"]*)")?\)/g;
167
+ let match;
168
+
169
+ while ((match = refRegex.exec(text)) !== null) {
170
+ const [, type, indexStr] = match;
171
+ const originalIndex = parseInt(indexStr, 10) - 1; // Convert to 0-based
172
+
173
+ // Get the source array for this type
174
+ const refType = type as 'link' | 'image' | 'video';
175
+ const sourceArray = sourceRefs[`${refType}s`] as
176
+ | t.MediaReference[]
177
+ | undefined;
178
+
179
+ // Skip if invalid reference
180
+ if (
181
+ !sourceArray ||
182
+ originalIndex < 0 ||
183
+ originalIndex >= sourceArray.length
184
+ ) {
185
+ continue; // Skip invalid references
186
+ }
187
+
188
+ // Get original reference
189
+ const reference = sourceArray[originalIndex];
190
+
191
+ // Track if not already tracked
192
+ const alreadyTracked = references.some(
193
+ (ref) => ref.type === refType && ref.originalIndex === originalIndex
194
+ );
195
+
196
+ if (!alreadyTracked) {
197
+ references.push({
198
+ type: refType,
199
+ originalIndex,
200
+ reference,
201
+ });
202
+ }
203
+ }
204
+
205
+ return { references };
206
+ }
207
+
125
208
  /**
126
209
  * Expand highlights in search results using smart boundary detection.
127
210
  *
@@ -131,25 +214,19 @@ function findBestBoundary(text: string, direction = 'backward'): number {
131
214
  * @param searchResults - Search results object
132
215
  * @param mainExpandBy - Primary expansion size on each side (default: 300)
133
216
  * @param separatorExpandBy - Additional range to look for separators (default: 150)
134
- * @returns Copy of search results with expanded highlights
217
+ * @returns Copy of search results with expanded highlights and tracked references
135
218
  */
136
219
  export function expandHighlights(
137
220
  searchResults: t.SearchResultData,
138
221
  mainExpandBy = 300,
139
222
  separatorExpandBy = 150
140
223
  ): t.SearchResultData {
141
- // 1. Avoid full deep copy - only copy what we modify
224
+ // Avoid deep copy - only copy what we modify
142
225
  const resultCopy = { ...searchResults };
226
+ if (resultCopy.organic) resultCopy.organic = [...resultCopy.organic];
227
+ if (resultCopy.topStories) resultCopy.topStories = [...resultCopy.topStories];
143
228
 
144
- // Only deep copy the relevant arrays
145
- if (resultCopy.organic) {
146
- resultCopy.organic = [...resultCopy.organic];
147
- }
148
- if (resultCopy.topStories) {
149
- resultCopy.topStories = [...resultCopy.topStories];
150
- }
151
-
152
- // 5. Process the results efficiently
229
+ // Process the results efficiently
153
230
  const processResultTypes = ['organic', 'topStories'] as const;
154
231
 
155
232
  for (const resultType of processResultTypes) {
@@ -170,23 +247,26 @@ export function expandHighlights(
170
247
  const resultCopy = { ...result };
171
248
  const content = result.content;
172
249
  const highlights = [];
173
-
174
250
  // Process each highlight
175
251
  for (const highlight of result.highlights) {
176
- const highlightText = highlight.text;
252
+ const { references } = trackReferencesInHighlight(
253
+ highlight.text,
254
+ result
255
+ );
177
256
 
178
- let startPos = content.indexOf(highlightText);
179
- let highlightLen = highlightText.length;
257
+ let startPos = content.indexOf(highlight.text);
258
+ let highlightLen = highlight.text.length;
180
259
 
181
260
  if (startPos === -1) {
182
261
  // Try with stripped whitespace
183
- const strippedHighlight = highlightText.trim();
262
+ const strippedHighlight = highlight.text.trim();
184
263
  startPos = content.indexOf(strippedHighlight);
185
264
 
186
265
  if (startPos === -1) {
187
266
  highlights.push({
188
267
  text: highlight.text,
189
268
  score: highlight.score,
269
+ references,
190
270
  });
191
271
  continue;
192
272
  }
@@ -225,10 +305,13 @@ export function expandHighlights(
225
305
  highlights.push({
226
306
  text: expandedHighlightText,
227
307
  score: highlight.score,
308
+ references,
228
309
  });
229
310
  }
230
311
 
231
312
  resultCopy.highlights = highlights;
313
+ delete resultCopy.content;
314
+ delete resultCopy.references;
232
315
  return resultCopy;
233
316
  });
234
317
  }