@framers/agentos-ext-web-search 1.1.0 → 1.1.1
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/README.md +31 -188
- package/dist/index.d.ts +14 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +52 -50
- package/dist/index.js.map +1 -1
- package/dist/services/searchProvider.d.ts +54 -2
- package/dist/services/searchProvider.d.ts.map +1 -1
- package/dist/services/searchProvider.js +168 -17
- package/dist/services/searchProvider.js.map +1 -1
- package/dist/tools/factCheck.d.ts +46 -88
- package/dist/tools/factCheck.d.ts.map +1 -1
- package/dist/tools/factCheck.js +134 -170
- package/dist/tools/factCheck.js.map +1 -1
- package/dist/tools/researchAggregator.d.ts +37 -91
- package/dist/tools/researchAggregator.d.ts.map +1 -1
- package/dist/tools/researchAggregator.js +134 -175
- package/dist/tools/researchAggregator.js.map +1 -1
- package/dist/tools/webSearch.d.ts +31 -59
- package/dist/tools/webSearch.d.ts.map +1 -1
- package/dist/tools/webSearch.js +69 -87
- package/dist/tools/webSearch.js.map +1 -1
- package/dist/types.js +1 -2
- package/dist/types.js.map +1 -1
- package/manifest.json +11 -6
- package/package.json +2 -2
- package/src/index.ts +64 -46
- package/src/services/searchProvider.ts +231 -25
- package/src/tools/factCheck.ts +206 -224
- package/src/tools/researchAggregator.ts +209 -217
- package/src/tools/webSearch.ts +103 -102
- package/test/integration.spec.ts +240 -39
- package/test/searchProvider.spec.ts +263 -18
- package/test/webSearch.spec.ts +129 -27
- package/tsconfig.json +7 -2
package/src/tools/factCheck.ts
CHANGED
|
@@ -1,173 +1,233 @@
|
|
|
1
|
-
import { ITool } from '@framers/agentos';
|
|
2
|
-
import { SearchProviderService } from '../services/searchProvider';
|
|
3
|
-
|
|
4
1
|
/**
|
|
5
|
-
* Fact
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
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
|
-
* ```
|
|
2
|
+
* Fact Check Tool — verify statements against web sources.
|
|
3
|
+
*
|
|
4
|
+
* Updated to conform to AgentOS `ITool` (inputSchema + ToolExecutionContext).
|
|
5
|
+
*
|
|
6
|
+
* @module @framers/agentos-ext-web-search
|
|
19
7
|
*/
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
8
|
+
|
|
9
|
+
import type { ITool, JSONSchemaObject, ToolExecutionContext, ToolExecutionResult } from '@framers/agentos';
|
|
10
|
+
import type { ProviderResponse, MultiSearchResponse } from '../services/searchProvider.js';
|
|
11
|
+
import { SearchProviderService } from '../services/searchProvider.js';
|
|
12
|
+
|
|
13
|
+
export interface FactCheckInput {
|
|
14
|
+
statement: string;
|
|
15
|
+
checkSources?: boolean;
|
|
16
|
+
confidence?: 'low' | 'medium' | 'high';
|
|
17
|
+
multiSearch?: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface FactCheckOutput {
|
|
21
|
+
statement: string;
|
|
22
|
+
verdict: 'TRUE' | 'FALSE' | 'UNVERIFIED' | 'PARTIALLY TRUE';
|
|
23
|
+
confidence: number;
|
|
24
|
+
confidenceLevel: 'low' | 'medium' | 'high';
|
|
25
|
+
explanation: string;
|
|
26
|
+
sources: Array<{ title: string; url: string; snippet: string; provider: string; query: string }>;
|
|
27
|
+
contradictingSources: string[];
|
|
28
|
+
supportingSources: string[];
|
|
29
|
+
meetsRequiredConfidence: boolean;
|
|
30
|
+
timestamp: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export class FactCheckTool implements ITool<FactCheckInput, FactCheckOutput> {
|
|
34
|
+
public readonly id = 'fact-check-v1';
|
|
35
|
+
/** Tool call name used by the LLM / ToolExecutor. */
|
|
36
|
+
public readonly name = 'fact_check';
|
|
37
|
+
public readonly displayName = 'Fact Check';
|
|
38
|
+
public readonly description = 'Verify a statement against web sources and return a verdict with confidence.';
|
|
39
|
+
public readonly category = 'research';
|
|
40
|
+
public readonly hasSideEffects = false;
|
|
41
|
+
|
|
42
|
+
public readonly inputSchema: JSONSchemaObject = {
|
|
43
|
+
type: 'object',
|
|
44
|
+
required: ['statement'],
|
|
45
|
+
properties: {
|
|
46
|
+
statement: {
|
|
47
|
+
type: 'string',
|
|
48
|
+
description: 'The statement to fact-check',
|
|
49
|
+
minLength: 5,
|
|
50
|
+
},
|
|
51
|
+
checkSources: {
|
|
52
|
+
type: 'boolean',
|
|
53
|
+
description: 'Whether to include source citations',
|
|
54
|
+
default: true,
|
|
55
|
+
},
|
|
56
|
+
confidence: {
|
|
57
|
+
type: 'string',
|
|
58
|
+
description: 'Required confidence level for the verdict',
|
|
59
|
+
enum: ['low', 'medium', 'high'],
|
|
60
|
+
default: 'medium',
|
|
61
|
+
},
|
|
62
|
+
multiSearch: {
|
|
63
|
+
type: 'boolean',
|
|
64
|
+
description:
|
|
65
|
+
'When true, each verification query fans out to ALL available providers in parallel for higher-confidence cross-provider consensus.',
|
|
66
|
+
default: false,
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
additionalProperties: false,
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
public readonly requiredCapabilities = ['capability:web_search'];
|
|
73
|
+
|
|
74
|
+
constructor(
|
|
75
|
+
private readonly searchService: SearchProviderService,
|
|
76
|
+
private readonly defaultMultiSearch: boolean = false,
|
|
77
|
+
) {}
|
|
78
|
+
|
|
79
|
+
async execute(input: FactCheckInput, _context: ToolExecutionContext): Promise<ToolExecutionResult<FactCheckOutput>> {
|
|
45
80
|
try {
|
|
46
81
|
const checkSources = input.checkSources !== false;
|
|
47
82
|
const requiredConfidence = input.confidence || 'medium';
|
|
48
|
-
|
|
49
|
-
|
|
83
|
+
const useMultiSearch = input.multiSearch ?? this.defaultMultiSearch;
|
|
84
|
+
|
|
50
85
|
const queries = this.generateFactCheckQueries(input.statement);
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
86
|
+
|
|
87
|
+
let searchResults: ProviderResponse[];
|
|
88
|
+
|
|
89
|
+
if (useMultiSearch) {
|
|
90
|
+
const multiPromises = queries.map((query) =>
|
|
91
|
+
this.searchService
|
|
92
|
+
.multiSearch(query, { maxResults: 5 })
|
|
93
|
+
.then((multi): ProviderResponse => ({
|
|
94
|
+
provider: 'multi',
|
|
95
|
+
results: multi.results,
|
|
96
|
+
metadata: { query, timestamp: multi.metadata.timestamp },
|
|
97
|
+
}))
|
|
98
|
+
.catch((err) => ({
|
|
99
|
+
provider: 'error',
|
|
100
|
+
results: [],
|
|
101
|
+
metadata: { query, error: err?.message || String(err), timestamp: new Date().toISOString() },
|
|
102
|
+
}))
|
|
103
|
+
);
|
|
104
|
+
searchResults = (await Promise.all(multiPromises)) as ProviderResponse[];
|
|
105
|
+
} else {
|
|
106
|
+
const searchPromises = queries.map((query) =>
|
|
107
|
+
this.searchService
|
|
108
|
+
.search(query, { maxResults: 5 })
|
|
109
|
+
.catch((err) => ({
|
|
110
|
+
provider: 'error',
|
|
111
|
+
results: [],
|
|
112
|
+
metadata: { query, error: err?.message || String(err), timestamp: new Date().toISOString() },
|
|
113
|
+
}))
|
|
114
|
+
);
|
|
115
|
+
searchResults = (await Promise.all(searchPromises)) as ProviderResponse[];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const analysis = this.analyzeFactCheckResults(input.statement, searchResults, requiredConfidence);
|
|
72
119
|
const sources = checkSources ? this.compileSources(searchResults) : [];
|
|
73
|
-
|
|
120
|
+
|
|
74
121
|
return {
|
|
75
122
|
success: true,
|
|
76
123
|
output: {
|
|
77
124
|
statement: input.statement,
|
|
78
125
|
verdict: analysis.verdict,
|
|
79
126
|
confidence: analysis.confidence,
|
|
127
|
+
confidenceLevel: analysis.confidenceLevel,
|
|
80
128
|
explanation: analysis.explanation,
|
|
81
|
-
sources
|
|
129
|
+
sources,
|
|
82
130
|
contradictingSources: analysis.contradictingSources,
|
|
83
131
|
supportingSources: analysis.supportingSources,
|
|
84
|
-
|
|
85
|
-
|
|
132
|
+
meetsRequiredConfidence: analysis.meetsRequiredConfidence,
|
|
133
|
+
timestamp: new Date().toISOString(),
|
|
134
|
+
},
|
|
86
135
|
};
|
|
87
136
|
} catch (error: any) {
|
|
88
|
-
return {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
137
|
+
return { success: false, error: error?.message || String(error) };
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
validateArgs(input: Record<string, any>): { isValid: boolean; errors?: any[] } {
|
|
142
|
+
const errors: string[] = [];
|
|
143
|
+
|
|
144
|
+
if (!input.statement) {
|
|
145
|
+
errors.push('Statement is required');
|
|
146
|
+
} else if (typeof input.statement !== 'string') {
|
|
147
|
+
errors.push('Statement must be a string');
|
|
148
|
+
} else if (input.statement.length < 5) {
|
|
149
|
+
errors.push('Statement must be at least 5 characters long');
|
|
92
150
|
}
|
|
151
|
+
|
|
152
|
+
if (input.confidence !== undefined) {
|
|
153
|
+
if (!['low', 'medium', 'high'].includes(input.confidence)) {
|
|
154
|
+
errors.push('Confidence must be low, medium, or high');
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (input.checkSources !== undefined && typeof input.checkSources !== 'boolean') {
|
|
159
|
+
errors.push('checkSources must be a boolean');
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (input.multiSearch !== undefined && typeof input.multiSearch !== 'boolean') {
|
|
163
|
+
errors.push('multiSearch must be a boolean');
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return errors.length === 0 ? { isValid: true } : { isValid: false, errors };
|
|
93
167
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
* @param {string} statement - The statement to check
|
|
100
|
-
* @returns {string[]} Array of search queries
|
|
101
|
-
*/
|
|
168
|
+
|
|
169
|
+
// ============================================================================
|
|
170
|
+
// Internals (ported from the previous implementation)
|
|
171
|
+
// ============================================================================
|
|
172
|
+
|
|
102
173
|
private generateFactCheckQueries(statement: string): string[] {
|
|
103
174
|
return [
|
|
104
|
-
statement,
|
|
105
|
-
`"${statement}" fact check`,
|
|
106
|
-
`${statement} true or false`,
|
|
107
|
-
`${statement} debunked myths`,
|
|
108
|
-
`is it true that ${statement}
|
|
175
|
+
statement,
|
|
176
|
+
`"${statement}" fact check`,
|
|
177
|
+
`${statement} true or false`,
|
|
178
|
+
`${statement} debunked myths`,
|
|
179
|
+
`is it true that ${statement}`,
|
|
109
180
|
];
|
|
110
181
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
* Analyzes search results to determine fact validity
|
|
114
|
-
*
|
|
115
|
-
* @private
|
|
116
|
-
* @param {string} statement - Original statement
|
|
117
|
-
* @param {any[]} searchResults - Search results to analyze
|
|
118
|
-
* @param {string} requiredConfidence - Required confidence level
|
|
119
|
-
* @returns {Object} Analysis results with verdict and confidence
|
|
120
|
-
*/
|
|
121
|
-
private analyzeFactCheckResults(
|
|
122
|
-
statement: string,
|
|
123
|
-
searchResults: any[],
|
|
124
|
-
requiredConfidence: string
|
|
125
|
-
): any {
|
|
182
|
+
|
|
183
|
+
private analyzeFactCheckResults(statement: string, searchResults: any[], requiredConfidence: string): any {
|
|
126
184
|
let supportingCount = 0;
|
|
127
185
|
let contradictingCount = 0;
|
|
128
186
|
let neutralCount = 0;
|
|
129
187
|
const supportingSources: string[] = [];
|
|
130
188
|
const contradictingSources: string[] = [];
|
|
131
|
-
|
|
189
|
+
|
|
132
190
|
const statementLower = statement.toLowerCase();
|
|
191
|
+
void statementLower; // retained for future use
|
|
192
|
+
|
|
133
193
|
const negativeIndicators = ['false', 'myth', 'debunked', 'incorrect', 'wrong', 'not true', 'fake'];
|
|
134
194
|
const positiveIndicators = ['true', 'correct', 'accurate', 'confirmed', 'verified', 'fact'];
|
|
135
|
-
|
|
195
|
+
|
|
136
196
|
for (const searchResult of searchResults) {
|
|
137
197
|
if (!searchResult.results) continue;
|
|
138
|
-
|
|
198
|
+
|
|
139
199
|
for (const result of searchResult.results) {
|
|
140
|
-
const contentLower = (result.title + ' ' + result.snippet).toLowerCase();
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
200
|
+
const contentLower = (String(result.title || '') + ' ' + String(result.snippet || '')).toLowerCase();
|
|
201
|
+
|
|
202
|
+
const isFactCheckSite =
|
|
203
|
+
String(result.url || '').includes('snopes') ||
|
|
204
|
+
String(result.url || '').includes('factcheck') ||
|
|
205
|
+
String(result.url || '').includes('politifact');
|
|
206
|
+
|
|
207
|
+
// Multi-search results with cross-provider agreement get extra weight
|
|
208
|
+
const agreementBonus = typeof result.agreementCount === 'number' ? Math.max(0, result.agreementCount - 1) : 0;
|
|
209
|
+
const weight = (isFactCheckSite ? 2 : 1) + agreementBonus;
|
|
210
|
+
|
|
211
|
+
const hasNegative = negativeIndicators.some((ind) => contentLower.includes(ind));
|
|
212
|
+
const hasPositive = positiveIndicators.some((ind) => contentLower.includes(ind));
|
|
213
|
+
|
|
153
214
|
if (hasNegative && !hasPositive) {
|
|
154
215
|
contradictingCount += weight;
|
|
155
|
-
contradictingSources.push(result.url);
|
|
216
|
+
if (result.url) contradictingSources.push(String(result.url));
|
|
156
217
|
} else if (hasPositive && !hasNegative) {
|
|
157
218
|
supportingCount += weight;
|
|
158
|
-
supportingSources.push(result.url);
|
|
219
|
+
if (result.url) supportingSources.push(String(result.url));
|
|
159
220
|
} else {
|
|
160
221
|
neutralCount += 1;
|
|
161
222
|
}
|
|
162
223
|
}
|
|
163
224
|
}
|
|
164
|
-
|
|
165
|
-
// Calculate confidence and verdict
|
|
225
|
+
|
|
166
226
|
const total = supportingCount + contradictingCount + neutralCount;
|
|
167
227
|
let confidence: number;
|
|
168
|
-
let verdict: '
|
|
228
|
+
let verdict: FactCheckOutput['verdict'];
|
|
169
229
|
let explanation: string;
|
|
170
|
-
|
|
230
|
+
|
|
171
231
|
if (total === 0) {
|
|
172
232
|
verdict = 'UNVERIFIED';
|
|
173
233
|
confidence = 0;
|
|
@@ -175,7 +235,7 @@ export class FactCheckTool implements ITool {
|
|
|
175
235
|
} else {
|
|
176
236
|
const supportRatio = supportingCount / total;
|
|
177
237
|
const contradictRatio = contradictingCount / total;
|
|
178
|
-
|
|
238
|
+
|
|
179
239
|
if (supportRatio > 0.7) {
|
|
180
240
|
verdict = 'TRUE';
|
|
181
241
|
confidence = supportRatio * 100;
|
|
@@ -187,17 +247,16 @@ export class FactCheckTool implements ITool {
|
|
|
187
247
|
} else if (supportRatio > 0.4 && contradictRatio > 0.4) {
|
|
188
248
|
verdict = 'PARTIALLY TRUE';
|
|
189
249
|
confidence = 50;
|
|
190
|
-
explanation =
|
|
250
|
+
explanation = 'Mixed evidence with both supporting and contradicting sources.';
|
|
191
251
|
} else {
|
|
192
252
|
verdict = 'UNVERIFIED';
|
|
193
253
|
confidence = Math.max(supportRatio, contradictRatio) * 100;
|
|
194
|
-
explanation =
|
|
254
|
+
explanation = 'Insufficient clear evidence to verify this statement.';
|
|
195
255
|
}
|
|
196
256
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
257
|
+
|
|
258
|
+
const confidenceLevel: 'low' | 'medium' | 'high' = confidence > 80 ? 'high' : confidence > 50 ? 'medium' : 'low';
|
|
259
|
+
|
|
201
260
|
return {
|
|
202
261
|
verdict,
|
|
203
262
|
confidence: Math.round(confidence),
|
|
@@ -205,114 +264,37 @@ export class FactCheckTool implements ITool {
|
|
|
205
264
|
explanation,
|
|
206
265
|
supportingSources: supportingSources.slice(0, 5),
|
|
207
266
|
contradictingSources: contradictingSources.slice(0, 5),
|
|
208
|
-
meetsRequiredConfidence: this.meetsConfidenceRequirement(confidenceLevel, requiredConfidence)
|
|
267
|
+
meetsRequiredConfidence: this.meetsConfidenceRequirement(confidenceLevel, requiredConfidence),
|
|
209
268
|
};
|
|
210
269
|
}
|
|
211
|
-
|
|
212
|
-
/**
|
|
213
|
-
* Checks if confidence level meets requirement
|
|
214
|
-
*
|
|
215
|
-
* @private
|
|
216
|
-
* @param {string} actual - Actual confidence level
|
|
217
|
-
* @param {string} required - Required confidence level
|
|
218
|
-
* @returns {boolean} True if requirement is met
|
|
219
|
-
*/
|
|
270
|
+
|
|
220
271
|
private meetsConfidenceRequirement(actual: string, required: string): boolean {
|
|
221
272
|
const levels = { low: 1, medium: 2, high: 3 };
|
|
222
273
|
return levels[actual as keyof typeof levels] >= levels[required as keyof typeof levels];
|
|
223
274
|
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
*
|
|
228
|
-
* @private
|
|
229
|
-
* @param {any[]} searchResults - Search results to compile from
|
|
230
|
-
* @returns {any[]} Compiled sources with metadata
|
|
231
|
-
*/
|
|
232
|
-
private compileSources(searchResults: any[]): any[] {
|
|
233
|
-
const sources: any[] = [];
|
|
275
|
+
|
|
276
|
+
private compileSources(searchResults: any[]): Array<{ title: string; url: string; snippet: string; provider: string; query: string }> {
|
|
277
|
+
const sources: Array<{ title: string; url: string; snippet: string; provider: string; query: string }> = [];
|
|
234
278
|
const seenUrls = new Set<string>();
|
|
235
|
-
|
|
279
|
+
|
|
236
280
|
for (const searchResult of searchResults) {
|
|
237
281
|
if (!searchResult.results) continue;
|
|
238
|
-
|
|
282
|
+
|
|
239
283
|
for (const result of searchResult.results) {
|
|
284
|
+
if (!result.url) continue;
|
|
240
285
|
if (seenUrls.has(result.url)) continue;
|
|
241
286
|
seenUrls.add(result.url);
|
|
242
|
-
|
|
287
|
+
|
|
243
288
|
sources.push({
|
|
244
|
-
title: result.title,
|
|
245
|
-
url: result.url,
|
|
246
|
-
snippet: result.snippet,
|
|
247
|
-
provider: searchResult.provider,
|
|
248
|
-
query: searchResult.metadata
|
|
289
|
+
title: String(result.title || ''),
|
|
290
|
+
url: String(result.url),
|
|
291
|
+
snippet: String(result.snippet || ''),
|
|
292
|
+
provider: String(searchResult.provider || 'unknown'),
|
|
293
|
+
query: String(searchResult.metadata?.query || ''),
|
|
249
294
|
});
|
|
250
295
|
}
|
|
251
296
|
}
|
|
252
|
-
|
|
253
|
-
return sources.slice(0, 10);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
/**
|
|
257
|
-
* Validates input parameters
|
|
258
|
-
*
|
|
259
|
-
* @param {any} input - Input to validate
|
|
260
|
-
* @returns {{valid: boolean, errors: string[]}} Validation result
|
|
261
|
-
*/
|
|
262
|
-
validate(input: any): { valid: boolean; errors: string[] } {
|
|
263
|
-
const errors: string[] = [];
|
|
264
|
-
|
|
265
|
-
if (!input.statement) {
|
|
266
|
-
errors.push('Statement is required');
|
|
267
|
-
} else if (typeof input.statement !== 'string') {
|
|
268
|
-
errors.push('Statement must be a string');
|
|
269
|
-
} else if (input.statement.length < 5) {
|
|
270
|
-
errors.push('Statement must be at least 5 characters long');
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
if (input.confidence !== undefined) {
|
|
274
|
-
if (!['low', 'medium', 'high'].includes(input.confidence)) {
|
|
275
|
-
errors.push('Confidence must be low, medium, or high');
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
if (input.checkSources !== undefined && typeof input.checkSources !== 'boolean') {
|
|
280
|
-
errors.push('checkSources must be a boolean');
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
return {
|
|
284
|
-
valid: errors.length === 0,
|
|
285
|
-
errors
|
|
286
|
-
};
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
/**
|
|
290
|
-
* Returns the JSON schema for the tool's input
|
|
291
|
-
*
|
|
292
|
-
* @returns {Object} JSON Schema object
|
|
293
|
-
*/
|
|
294
|
-
getSchema(): any {
|
|
295
|
-
return {
|
|
296
|
-
type: 'object',
|
|
297
|
-
required: ['statement'],
|
|
298
|
-
properties: {
|
|
299
|
-
statement: {
|
|
300
|
-
type: 'string',
|
|
301
|
-
description: 'The statement to fact-check',
|
|
302
|
-
minLength: 5
|
|
303
|
-
},
|
|
304
|
-
checkSources: {
|
|
305
|
-
type: 'boolean',
|
|
306
|
-
description: 'Whether to include source citations',
|
|
307
|
-
default: true
|
|
308
|
-
},
|
|
309
|
-
confidence: {
|
|
310
|
-
type: 'string',
|
|
311
|
-
description: 'Required confidence level for the verdict',
|
|
312
|
-
enum: ['low', 'medium', 'high'],
|
|
313
|
-
default: 'medium'
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
};
|
|
297
|
+
|
|
298
|
+
return sources.slice(0, 10);
|
|
317
299
|
}
|
|
318
|
-
}
|
|
300
|
+
}
|