@framers/agentos-ext-web-search 1.1.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.
Files changed (41) hide show
  1. package/.eslintrc.json +21 -0
  2. package/CHANGELOG.md +16 -0
  3. package/LICENSE +21 -0
  4. package/README.md +218 -0
  5. package/dist/index.d.ts +58 -0
  6. package/dist/index.d.ts.map +1 -0
  7. package/dist/index.js +100 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/services/searchProvider.d.ts +160 -0
  10. package/dist/services/searchProvider.d.ts.map +1 -0
  11. package/dist/services/searchProvider.js +342 -0
  12. package/dist/services/searchProvider.js.map +1 -0
  13. package/dist/tools/factCheck.d.ts +99 -0
  14. package/dist/tools/factCheck.d.ts.map +1 -0
  15. package/dist/tools/factCheck.js +287 -0
  16. package/dist/tools/factCheck.js.map +1 -0
  17. package/dist/tools/researchAggregator.d.ts +101 -0
  18. package/dist/tools/researchAggregator.d.ts.map +1 -0
  19. package/dist/tools/researchAggregator.js +275 -0
  20. package/dist/tools/researchAggregator.js.map +1 -0
  21. package/dist/tools/webSearch.d.ts +66 -0
  22. package/dist/tools/webSearch.d.ts.map +1 -0
  23. package/dist/tools/webSearch.js +122 -0
  24. package/dist/tools/webSearch.js.map +1 -0
  25. package/dist/types.d.ts +38 -0
  26. package/dist/types.d.ts.map +1 -0
  27. package/dist/types.js +6 -0
  28. package/dist/types.js.map +1 -0
  29. package/manifest.json +65 -0
  30. package/package.json +73 -0
  31. package/src/index.ts +123 -0
  32. package/src/services/searchProvider.ts +416 -0
  33. package/src/tools/factCheck.ts +318 -0
  34. package/src/tools/researchAggregator.ts +297 -0
  35. package/src/tools/webSearch.ts +128 -0
  36. package/src/types.ts +41 -0
  37. package/test/integration.spec.ts +173 -0
  38. package/test/searchProvider.spec.ts +153 -0
  39. package/test/webSearch.spec.ts +128 -0
  40. package/tsconfig.json +21 -0
  41. package/vitest.config.ts +32 -0
@@ -0,0 +1,287 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FactCheckTool = void 0;
4
+ /**
5
+ * Fact checking tool that verifies statements against web sources
6
+ *
7
+ * @class FactCheckTool
8
+ * @implements {ITool}
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * const tool = new FactCheckTool(searchService);
13
+ * const result = await tool.execute({
14
+ * statement: 'The Earth orbits the Sun',
15
+ * checkSources: true,
16
+ * confidence: 'high'
17
+ * });
18
+ * ```
19
+ */
20
+ class FactCheckTool {
21
+ searchService;
22
+ id = 'factCheck';
23
+ name = 'Fact Check';
24
+ description = 'Verify facts and statements against web sources';
25
+ /**
26
+ * Creates an instance of FactCheckTool
27
+ * @param {SearchProviderService} searchService - The search provider service
28
+ */
29
+ constructor(searchService) {
30
+ this.searchService = searchService;
31
+ }
32
+ /**
33
+ * Executes fact checking on a statement
34
+ *
35
+ * @param {Object} input - The fact check parameters
36
+ * @param {string} input.statement - The statement to fact-check
37
+ * @param {boolean} [input.checkSources=true] - Whether to include source citations
38
+ * @param {string} [input.confidence='medium'] - Required confidence level
39
+ * @returns {Promise<{success: boolean, output?: any, error?: string}>} Fact check results
40
+ */
41
+ async execute(input) {
42
+ try {
43
+ const checkSources = input.checkSources !== false;
44
+ const requiredConfidence = input.confidence || 'medium';
45
+ // Search for information about the statement
46
+ const queries = this.generateFactCheckQueries(input.statement);
47
+ // Perform searches in parallel
48
+ const searchPromises = queries.map(query => this.searchService.search(query, { maxResults: 5 })
49
+ .catch(err => ({
50
+ provider: 'error',
51
+ results: [],
52
+ metadata: { query, error: err.message, timestamp: new Date().toISOString() }
53
+ })));
54
+ const searchResults = await Promise.all(searchPromises);
55
+ // Analyze results for fact verification
56
+ const analysis = this.analyzeFactCheckResults(input.statement, searchResults, requiredConfidence);
57
+ // Compile sources if requested
58
+ const sources = checkSources ? this.compileSources(searchResults) : [];
59
+ return {
60
+ success: true,
61
+ output: {
62
+ statement: input.statement,
63
+ verdict: analysis.verdict,
64
+ confidence: analysis.confidence,
65
+ explanation: analysis.explanation,
66
+ sources: sources,
67
+ contradictingSources: analysis.contradictingSources,
68
+ supportingSources: analysis.supportingSources,
69
+ timestamp: new Date().toISOString()
70
+ }
71
+ };
72
+ }
73
+ catch (error) {
74
+ return {
75
+ success: false,
76
+ error: error.message
77
+ };
78
+ }
79
+ }
80
+ /**
81
+ * Generates queries for fact-checking a statement
82
+ *
83
+ * @private
84
+ * @param {string} statement - The statement to check
85
+ * @returns {string[]} Array of search queries
86
+ */
87
+ generateFactCheckQueries(statement) {
88
+ return [
89
+ statement, // Original statement
90
+ `"${statement}" fact check`, // Exact match with fact check
91
+ `${statement} true or false`, // Truth verification
92
+ `${statement} debunked myths`, // Check for debunking
93
+ `is it true that ${statement}` // Question format
94
+ ];
95
+ }
96
+ /**
97
+ * Analyzes search results to determine fact validity
98
+ *
99
+ * @private
100
+ * @param {string} statement - Original statement
101
+ * @param {any[]} searchResults - Search results to analyze
102
+ * @param {string} requiredConfidence - Required confidence level
103
+ * @returns {Object} Analysis results with verdict and confidence
104
+ */
105
+ analyzeFactCheckResults(statement, searchResults, requiredConfidence) {
106
+ let supportingCount = 0;
107
+ let contradictingCount = 0;
108
+ let neutralCount = 0;
109
+ const supportingSources = [];
110
+ const contradictingSources = [];
111
+ const statementLower = statement.toLowerCase();
112
+ const negativeIndicators = ['false', 'myth', 'debunked', 'incorrect', 'wrong', 'not true', 'fake'];
113
+ const positiveIndicators = ['true', 'correct', 'accurate', 'confirmed', 'verified', 'fact'];
114
+ for (const searchResult of searchResults) {
115
+ if (!searchResult.results)
116
+ continue;
117
+ for (const result of searchResult.results) {
118
+ const contentLower = (result.title + ' ' + result.snippet).toLowerCase();
119
+ // Check for fact-checking sites
120
+ const isFactCheckSite = result.url.includes('snopes') ||
121
+ result.url.includes('factcheck') ||
122
+ result.url.includes('politifact');
123
+ const weight = isFactCheckSite ? 2 : 1; // Give more weight to fact-checking sites
124
+ // Analyze sentiment toward the statement
125
+ let hasNegative = negativeIndicators.some(ind => contentLower.includes(ind));
126
+ let hasPositive = positiveIndicators.some(ind => contentLower.includes(ind));
127
+ if (hasNegative && !hasPositive) {
128
+ contradictingCount += weight;
129
+ contradictingSources.push(result.url);
130
+ }
131
+ else if (hasPositive && !hasNegative) {
132
+ supportingCount += weight;
133
+ supportingSources.push(result.url);
134
+ }
135
+ else {
136
+ neutralCount += 1;
137
+ }
138
+ }
139
+ }
140
+ // Calculate confidence and verdict
141
+ const total = supportingCount + contradictingCount + neutralCount;
142
+ let confidence;
143
+ let verdict;
144
+ let explanation;
145
+ if (total === 0) {
146
+ verdict = 'UNVERIFIED';
147
+ confidence = 0;
148
+ explanation = 'No relevant sources found to verify this statement.';
149
+ }
150
+ else {
151
+ const supportRatio = supportingCount / total;
152
+ const contradictRatio = contradictingCount / total;
153
+ if (supportRatio > 0.7) {
154
+ verdict = 'TRUE';
155
+ confidence = supportRatio * 100;
156
+ explanation = `Strong evidence supports this statement (${supportingCount} supporting sources).`;
157
+ }
158
+ else if (contradictRatio > 0.7) {
159
+ verdict = 'FALSE';
160
+ confidence = contradictRatio * 100;
161
+ explanation = `Strong evidence contradicts this statement (${contradictingCount} contradicting sources).`;
162
+ }
163
+ else if (supportRatio > 0.4 && contradictRatio > 0.4) {
164
+ verdict = 'PARTIALLY TRUE';
165
+ confidence = 50;
166
+ explanation = `Mixed evidence with both supporting and contradicting sources.`;
167
+ }
168
+ else {
169
+ verdict = 'UNVERIFIED';
170
+ confidence = Math.max(supportRatio, contradictRatio) * 100;
171
+ explanation = `Insufficient clear evidence to verify this statement.`;
172
+ }
173
+ }
174
+ // Adjust confidence based on required level
175
+ const confidenceLevel = confidence > 80 ? 'high' : confidence > 50 ? 'medium' : 'low';
176
+ return {
177
+ verdict,
178
+ confidence: Math.round(confidence),
179
+ confidenceLevel,
180
+ explanation,
181
+ supportingSources: supportingSources.slice(0, 5),
182
+ contradictingSources: contradictingSources.slice(0, 5),
183
+ meetsRequiredConfidence: this.meetsConfidenceRequirement(confidenceLevel, requiredConfidence)
184
+ };
185
+ }
186
+ /**
187
+ * Checks if confidence level meets requirement
188
+ *
189
+ * @private
190
+ * @param {string} actual - Actual confidence level
191
+ * @param {string} required - Required confidence level
192
+ * @returns {boolean} True if requirement is met
193
+ */
194
+ meetsConfidenceRequirement(actual, required) {
195
+ const levels = { low: 1, medium: 2, high: 3 };
196
+ return levels[actual] >= levels[required];
197
+ }
198
+ /**
199
+ * Compiles relevant sources from search results
200
+ *
201
+ * @private
202
+ * @param {any[]} searchResults - Search results to compile from
203
+ * @returns {any[]} Compiled sources with metadata
204
+ */
205
+ compileSources(searchResults) {
206
+ const sources = [];
207
+ const seenUrls = new Set();
208
+ for (const searchResult of searchResults) {
209
+ if (!searchResult.results)
210
+ continue;
211
+ for (const result of searchResult.results) {
212
+ if (seenUrls.has(result.url))
213
+ continue;
214
+ seenUrls.add(result.url);
215
+ sources.push({
216
+ title: result.title,
217
+ url: result.url,
218
+ snippet: result.snippet,
219
+ provider: searchResult.provider,
220
+ query: searchResult.metadata.query
221
+ });
222
+ }
223
+ }
224
+ return sources.slice(0, 10); // Limit to top 10 sources
225
+ }
226
+ /**
227
+ * Validates input parameters
228
+ *
229
+ * @param {any} input - Input to validate
230
+ * @returns {{valid: boolean, errors: string[]}} Validation result
231
+ */
232
+ validate(input) {
233
+ const errors = [];
234
+ if (!input.statement) {
235
+ errors.push('Statement is required');
236
+ }
237
+ else if (typeof input.statement !== 'string') {
238
+ errors.push('Statement must be a string');
239
+ }
240
+ else if (input.statement.length < 5) {
241
+ errors.push('Statement must be at least 5 characters long');
242
+ }
243
+ if (input.confidence !== undefined) {
244
+ if (!['low', 'medium', 'high'].includes(input.confidence)) {
245
+ errors.push('Confidence must be low, medium, or high');
246
+ }
247
+ }
248
+ if (input.checkSources !== undefined && typeof input.checkSources !== 'boolean') {
249
+ errors.push('checkSources must be a boolean');
250
+ }
251
+ return {
252
+ valid: errors.length === 0,
253
+ errors
254
+ };
255
+ }
256
+ /**
257
+ * Returns the JSON schema for the tool's input
258
+ *
259
+ * @returns {Object} JSON Schema object
260
+ */
261
+ getSchema() {
262
+ return {
263
+ type: 'object',
264
+ required: ['statement'],
265
+ properties: {
266
+ statement: {
267
+ type: 'string',
268
+ description: 'The statement to fact-check',
269
+ minLength: 5
270
+ },
271
+ checkSources: {
272
+ type: 'boolean',
273
+ description: 'Whether to include source citations',
274
+ default: true
275
+ },
276
+ confidence: {
277
+ type: 'string',
278
+ description: 'Required confidence level for the verdict',
279
+ enum: ['low', 'medium', 'high'],
280
+ default: 'medium'
281
+ }
282
+ }
283
+ };
284
+ }
285
+ }
286
+ exports.FactCheckTool = FactCheckTool;
287
+ //# sourceMappingURL=factCheck.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factCheck.js","sourceRoot":"","sources":["../../src/tools/factCheck.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,101 @@
1
+ import { ITool } from '@framers/agentos';
2
+ import { SearchProviderService } from '../services/searchProvider';
3
+ /**
4
+ * Research aggregator tool that performs multiple searches and synthesizes results
5
+ *
6
+ * @class ResearchAggregatorTool
7
+ * @implements {ITool}
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * const tool = new ResearchAggregatorTool(searchService);
12
+ * const result = await tool.execute({
13
+ * topic: 'AI safety research',
14
+ * sources: 3,
15
+ * depth: 'comprehensive'
16
+ * });
17
+ * ```
18
+ */
19
+ export declare class ResearchAggregatorTool implements ITool {
20
+ private searchService;
21
+ readonly id = "researchAggregator";
22
+ readonly name = "Research Aggregator";
23
+ readonly description = "Aggregate research from multiple searches on a topic";
24
+ /**
25
+ * Creates an instance of ResearchAggregatorTool
26
+ * @param {SearchProviderService} searchService - The search provider service
27
+ */
28
+ constructor(searchService: SearchProviderService);
29
+ /**
30
+ * Executes research aggregation on a topic
31
+ *
32
+ * @param {Object} input - The research parameters
33
+ * @param {string} input.topic - The research topic
34
+ * @param {number} [input.sources=3] - Number of different search angles to explore
35
+ * @param {string} [input.depth='moderate'] - Research depth (quick, moderate, comprehensive)
36
+ * @returns {Promise<{success: boolean, output?: any, error?: string}>} Aggregated research results
37
+ */
38
+ execute(input: {
39
+ topic: string;
40
+ sources?: number;
41
+ depth?: 'quick' | 'moderate' | 'comprehensive';
42
+ }): Promise<{
43
+ success: boolean;
44
+ output?: any;
45
+ error?: string;
46
+ }>;
47
+ /**
48
+ * Generates diverse search queries for comprehensive research
49
+ *
50
+ * @private
51
+ * @param {string} topic - The research topic
52
+ * @param {number} count - Number of queries to generate
53
+ * @param {string} depth - Research depth level
54
+ * @returns {string[]} Array of search queries
55
+ */
56
+ private generateSearchQueries;
57
+ /**
58
+ * Aggregates and deduplicates search results
59
+ *
60
+ * @private
61
+ * @param {any[]} searchResults - Array of search results from different queries
62
+ * @param {string} topic - The original research topic
63
+ * @returns {Object} Aggregated and organized results
64
+ */
65
+ private aggregateResults;
66
+ /**
67
+ * Calculates relevance score for a search result
68
+ *
69
+ * @private
70
+ * @param {any} result - Search result object
71
+ * @param {string} topic - Original topic for comparison
72
+ * @returns {number} Relevance score (0-100)
73
+ */
74
+ private calculateRelevance;
75
+ /**
76
+ * Gets top results across all categories
77
+ *
78
+ * @private
79
+ * @param {any} categories - Categorized results
80
+ * @param {number} count - Number of top results to return
81
+ * @returns {any[]} Top results by relevance
82
+ */
83
+ private getTopResults;
84
+ /**
85
+ * Validates input parameters
86
+ *
87
+ * @param {any} input - Input to validate
88
+ * @returns {{valid: boolean, errors: string[]}} Validation result
89
+ */
90
+ validate(input: any): {
91
+ valid: boolean;
92
+ errors: string[];
93
+ };
94
+ /**
95
+ * Returns the JSON schema for the tool's input
96
+ *
97
+ * @returns {Object} JSON Schema object
98
+ */
99
+ getSchema(): any;
100
+ }
101
+ //# sourceMappingURL=researchAggregator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"researchAggregator.d.ts","sourceRoot":"","sources":["../../src/tools/researchAggregator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAEnE;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,sBAAuB,YAAW,KAAK;IAStC,OAAO,CAAC,aAAa;IARjC,SAAgB,EAAE,wBAAwB;IAC1C,SAAgB,IAAI,yBAAyB;IAC7C,SAAgB,WAAW,0DAA0D;IAErF;;;OAGG;gBACiB,aAAa,EAAE,qBAAqB;IAExD;;;;;;;;OAQG;IACG,OAAO,CAAC,KAAK,EAAE;QACnB,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,KAAK,CAAC,EAAE,OAAO,GAAG,UAAU,GAAG,eAAe,CAAC;KAChD,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,GAAG,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IA2C/D;;;;;;;;OAQG;IACH,OAAO,CAAC,qBAAqB;IA6B7B;;;;;;;OAOG;IACH,OAAO,CAAC,gBAAgB;IAoDxB;;;;;;;OAOG;IACH,OAAO,CAAC,kBAAkB;IAqB1B;;;;;;;OAOG;IACH,OAAO,CAAC,aAAa;IAYrB;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,EAAE,GAAG,GAAG;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE;IA2B1D;;;;OAIG;IACH,SAAS,IAAI,GAAG;CAyBjB"}
@@ -0,0 +1,275 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ResearchAggregatorTool = void 0;
4
+ /**
5
+ * Research aggregator tool that performs multiple searches and synthesizes results
6
+ *
7
+ * @class ResearchAggregatorTool
8
+ * @implements {ITool}
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * const tool = new ResearchAggregatorTool(searchService);
13
+ * const result = await tool.execute({
14
+ * topic: 'AI safety research',
15
+ * sources: 3,
16
+ * depth: 'comprehensive'
17
+ * });
18
+ * ```
19
+ */
20
+ class ResearchAggregatorTool {
21
+ searchService;
22
+ id = 'researchAggregator';
23
+ name = 'Research Aggregator';
24
+ description = 'Aggregate research from multiple searches on a topic';
25
+ /**
26
+ * Creates an instance of ResearchAggregatorTool
27
+ * @param {SearchProviderService} searchService - The search provider service
28
+ */
29
+ constructor(searchService) {
30
+ this.searchService = searchService;
31
+ }
32
+ /**
33
+ * Executes research aggregation on a topic
34
+ *
35
+ * @param {Object} input - The research parameters
36
+ * @param {string} input.topic - The research topic
37
+ * @param {number} [input.sources=3] - Number of different search angles to explore
38
+ * @param {string} [input.depth='moderate'] - Research depth (quick, moderate, comprehensive)
39
+ * @returns {Promise<{success: boolean, output?: any, error?: string}>} Aggregated research results
40
+ */
41
+ async execute(input) {
42
+ try {
43
+ const sources = input.sources || 3;
44
+ const depth = input.depth || 'moderate';
45
+ // Generate different search queries for comprehensive coverage
46
+ const queries = this.generateSearchQueries(input.topic, sources, depth);
47
+ // Perform searches in parallel
48
+ const searchPromises = queries.map(query => this.searchService.search(query, {
49
+ maxResults: depth === 'quick' ? 5 : depth === 'moderate' ? 10 : 15
50
+ }).catch(err => ({
51
+ provider: 'error',
52
+ results: [],
53
+ metadata: { query, error: err.message, timestamp: new Date().toISOString() }
54
+ })));
55
+ const searchResults = await Promise.all(searchPromises);
56
+ // Aggregate and deduplicate results
57
+ const aggregated = this.aggregateResults(searchResults, input.topic);
58
+ return {
59
+ success: true,
60
+ output: {
61
+ topic: input.topic,
62
+ sources: sources,
63
+ depth: depth,
64
+ queries: queries,
65
+ aggregatedResults: aggregated,
66
+ timestamp: new Date().toISOString()
67
+ }
68
+ };
69
+ }
70
+ catch (error) {
71
+ return {
72
+ success: false,
73
+ error: error.message
74
+ };
75
+ }
76
+ }
77
+ /**
78
+ * Generates diverse search queries for comprehensive research
79
+ *
80
+ * @private
81
+ * @param {string} topic - The research topic
82
+ * @param {number} count - Number of queries to generate
83
+ * @param {string} depth - Research depth level
84
+ * @returns {string[]} Array of search queries
85
+ */
86
+ generateSearchQueries(topic, count, depth) {
87
+ const queries = [topic]; // Start with the original topic
88
+ const modifiers = {
89
+ quick: ['overview', 'summary'],
90
+ moderate: ['overview', 'recent developments', 'key concepts', 'applications'],
91
+ comprehensive: [
92
+ 'overview',
93
+ 'recent research',
94
+ 'state of the art',
95
+ 'challenges',
96
+ 'future directions',
97
+ 'industry applications',
98
+ 'academic papers',
99
+ 'expert opinions'
100
+ ]
101
+ };
102
+ const selectedModifiers = modifiers[depth];
103
+ for (let i = 1; i < Math.min(count, selectedModifiers.length + 1); i++) {
104
+ if (selectedModifiers[i - 1]) {
105
+ queries.push(`${topic} ${selectedModifiers[i - 1]}`);
106
+ }
107
+ }
108
+ return queries;
109
+ }
110
+ /**
111
+ * Aggregates and deduplicates search results
112
+ *
113
+ * @private
114
+ * @param {any[]} searchResults - Array of search results from different queries
115
+ * @param {string} topic - The original research topic
116
+ * @returns {Object} Aggregated and organized results
117
+ */
118
+ aggregateResults(searchResults, topic) {
119
+ const seenUrls = new Set();
120
+ const categories = {
121
+ overview: [],
122
+ research: [],
123
+ applications: [],
124
+ resources: []
125
+ };
126
+ for (const searchResult of searchResults) {
127
+ if (!searchResult.results)
128
+ continue;
129
+ for (const result of searchResult.results) {
130
+ // Skip duplicates
131
+ if (seenUrls.has(result.url))
132
+ continue;
133
+ seenUrls.add(result.url);
134
+ // Categorize based on content
135
+ const lowerTitle = result.title.toLowerCase();
136
+ const lowerSnippet = result.snippet.toLowerCase();
137
+ if (lowerTitle.includes('overview') || lowerTitle.includes('introduction') ||
138
+ lowerTitle.includes('what is')) {
139
+ categories.overview.push(result);
140
+ }
141
+ else if (lowerTitle.includes('research') || lowerTitle.includes('study') ||
142
+ lowerTitle.includes('paper') || lowerTitle.includes('journal')) {
143
+ categories.research.push(result);
144
+ }
145
+ else if (lowerTitle.includes('application') || lowerTitle.includes('use case') ||
146
+ lowerTitle.includes('implementation')) {
147
+ categories.applications.push(result);
148
+ }
149
+ else {
150
+ categories.resources.push(result);
151
+ }
152
+ }
153
+ }
154
+ // Calculate relevance scores
155
+ const scoredCategories = Object.entries(categories).reduce((acc, [key, items]) => {
156
+ acc[key] = items.map((item) => ({
157
+ ...item,
158
+ relevanceScore: this.calculateRelevance(item, topic)
159
+ })).sort((a, b) => b.relevanceScore - a.relevanceScore);
160
+ return acc;
161
+ }, {});
162
+ return {
163
+ categories: scoredCategories,
164
+ totalResults: seenUrls.size,
165
+ topResults: this.getTopResults(scoredCategories, 10)
166
+ };
167
+ }
168
+ /**
169
+ * Calculates relevance score for a search result
170
+ *
171
+ * @private
172
+ * @param {any} result - Search result object
173
+ * @param {string} topic - Original topic for comparison
174
+ * @returns {number} Relevance score (0-100)
175
+ */
176
+ calculateRelevance(result, topic) {
177
+ let score = 50; // Base score
178
+ const topicWords = topic.toLowerCase().split(/\s+/);
179
+ const titleWords = result.title.toLowerCase();
180
+ const snippetWords = result.snippet.toLowerCase();
181
+ // Check title relevance
182
+ for (const word of topicWords) {
183
+ if (titleWords.includes(word))
184
+ score += 15;
185
+ if (snippetWords.includes(word))
186
+ score += 5;
187
+ }
188
+ // Boost for certain indicators
189
+ if (titleWords.includes('official'))
190
+ score += 10;
191
+ if (titleWords.includes('guide'))
192
+ score += 5;
193
+ if (titleWords.includes('tutorial'))
194
+ score += 5;
195
+ return Math.min(100, score);
196
+ }
197
+ /**
198
+ * Gets top results across all categories
199
+ *
200
+ * @private
201
+ * @param {any} categories - Categorized results
202
+ * @param {number} count - Number of top results to return
203
+ * @returns {any[]} Top results by relevance
204
+ */
205
+ getTopResults(categories, count) {
206
+ const allResults = [];
207
+ for (const items of Object.values(categories)) {
208
+ allResults.push(...items);
209
+ }
210
+ return allResults
211
+ .sort((a, b) => b.relevanceScore - a.relevanceScore)
212
+ .slice(0, count);
213
+ }
214
+ /**
215
+ * Validates input parameters
216
+ *
217
+ * @param {any} input - Input to validate
218
+ * @returns {{valid: boolean, errors: string[]}} Validation result
219
+ */
220
+ validate(input) {
221
+ const errors = [];
222
+ if (!input.topic) {
223
+ errors.push('Topic is required');
224
+ }
225
+ else if (typeof input.topic !== 'string') {
226
+ errors.push('Topic must be a string');
227
+ }
228
+ if (input.sources !== undefined) {
229
+ if (typeof input.sources !== 'number' || input.sources < 1 || input.sources > 10) {
230
+ errors.push('Sources must be a number between 1 and 10');
231
+ }
232
+ }
233
+ if (input.depth !== undefined) {
234
+ if (!['quick', 'moderate', 'comprehensive'].includes(input.depth)) {
235
+ errors.push('Depth must be quick, moderate, or comprehensive');
236
+ }
237
+ }
238
+ return {
239
+ valid: errors.length === 0,
240
+ errors
241
+ };
242
+ }
243
+ /**
244
+ * Returns the JSON schema for the tool's input
245
+ *
246
+ * @returns {Object} JSON Schema object
247
+ */
248
+ getSchema() {
249
+ return {
250
+ type: 'object',
251
+ required: ['topic'],
252
+ properties: {
253
+ topic: {
254
+ type: 'string',
255
+ description: 'The research topic to aggregate information about'
256
+ },
257
+ sources: {
258
+ type: 'number',
259
+ description: 'Number of different search angles to explore',
260
+ default: 3,
261
+ minimum: 1,
262
+ maximum: 10
263
+ },
264
+ depth: {
265
+ type: 'string',
266
+ description: 'Research depth level',
267
+ enum: ['quick', 'moderate', 'comprehensive'],
268
+ default: 'moderate'
269
+ }
270
+ }
271
+ };
272
+ }
273
+ }
274
+ exports.ResearchAggregatorTool = ResearchAggregatorTool;
275
+ //# sourceMappingURL=researchAggregator.js.map