pi-web-providers 2.5.0 → 3.0.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.
- package/README.md +50 -5
- package/dist/index.js +1833 -645
- package/package.json +8 -7
package/dist/index.js
CHANGED
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
visibleWidth,
|
|
23
23
|
wrapTextWithAnsi
|
|
24
24
|
} from "@mariozechner/pi-tui";
|
|
25
|
-
import { Type as
|
|
25
|
+
import { Type as Type16 } from "typebox";
|
|
26
26
|
|
|
27
27
|
// src/config.ts
|
|
28
28
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
@@ -42,107 +42,1219 @@ function resolveConfigValue(reference) {
|
|
|
42
42
|
}
|
|
43
43
|
return cached.value;
|
|
44
44
|
}
|
|
45
|
-
try {
|
|
46
|
-
const output = execSync(reference.slice(1), {
|
|
47
|
-
encoding: "utf-8",
|
|
48
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
49
|
-
}).trim();
|
|
50
|
-
const value = output.length > 0 ? output : void 0;
|
|
51
|
-
commandValueCache.set(reference, { value });
|
|
52
|
-
return value;
|
|
53
|
-
} catch (error) {
|
|
54
|
-
const errorMessage = error.message;
|
|
55
|
-
commandValueCache.set(reference, { errorMessage });
|
|
56
|
-
throw error;
|
|
45
|
+
try {
|
|
46
|
+
const output = execSync(reference.slice(1), {
|
|
47
|
+
encoding: "utf-8",
|
|
48
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
49
|
+
}).trim();
|
|
50
|
+
const value = output.length > 0 ? output : void 0;
|
|
51
|
+
commandValueCache.set(reference, { value });
|
|
52
|
+
return value;
|
|
53
|
+
} catch (error) {
|
|
54
|
+
const errorMessage = error.message;
|
|
55
|
+
commandValueCache.set(reference, { errorMessage });
|
|
56
|
+
throw error;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const envValue = process.env[reference];
|
|
60
|
+
if (envValue !== void 0) {
|
|
61
|
+
return envValue;
|
|
62
|
+
}
|
|
63
|
+
if (/^[A-Z][A-Z0-9_]*$/.test(reference)) {
|
|
64
|
+
return void 0;
|
|
65
|
+
}
|
|
66
|
+
return reference;
|
|
67
|
+
}
|
|
68
|
+
function resolveEnvMap(envMap) {
|
|
69
|
+
if (!envMap) return void 0;
|
|
70
|
+
const resolved = Object.fromEntries(
|
|
71
|
+
Object.entries(envMap).map(([key, value]) => [key, resolveConfigValue(value)]).filter(
|
|
72
|
+
(entry) => typeof entry[1] === "string"
|
|
73
|
+
)
|
|
74
|
+
);
|
|
75
|
+
return Object.keys(resolved).length > 0 ? resolved : void 0;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// src/providers/brave.ts
|
|
79
|
+
import { Type } from "typebox";
|
|
80
|
+
|
|
81
|
+
// src/providers/definition.ts
|
|
82
|
+
function defineCapability(definition) {
|
|
83
|
+
return definition;
|
|
84
|
+
}
|
|
85
|
+
function defineProvider(definition) {
|
|
86
|
+
return definition;
|
|
87
|
+
}
|
|
88
|
+
function defineProviders(providers) {
|
|
89
|
+
return providers;
|
|
90
|
+
}
|
|
91
|
+
async function executeProviderCapability(definition, capability, input, context) {
|
|
92
|
+
const handler = definition.capabilities[capability];
|
|
93
|
+
if (!handler) {
|
|
94
|
+
throw new Error(
|
|
95
|
+
`Provider '${definition.id}' does not support '${capability}'.`
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
return await handler.execute(input, context);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// src/providers/shared.ts
|
|
102
|
+
function trimSnippet(input, maxLength = 300) {
|
|
103
|
+
const text = (input ?? "").replace(/\s+/g, " ").trim();
|
|
104
|
+
if (text.length <= maxLength) return text;
|
|
105
|
+
return `${text.slice(0, maxLength - 1)}\u2026`;
|
|
106
|
+
}
|
|
107
|
+
function normalizeContentText(input) {
|
|
108
|
+
const text = (input ?? "").replace(/\r/g, "").trim();
|
|
109
|
+
if (!text) {
|
|
110
|
+
return "";
|
|
111
|
+
}
|
|
112
|
+
return text.split("\n").map((line) => line.replace(/[ \t]+$/g, "")).join("\n").replace(/\n{3,}/g, "\n\n");
|
|
113
|
+
}
|
|
114
|
+
function asJsonObject(value) {
|
|
115
|
+
return value ? { ...value } : {};
|
|
116
|
+
}
|
|
117
|
+
function formatJson(value) {
|
|
118
|
+
return JSON.stringify(value, null, 2);
|
|
119
|
+
}
|
|
120
|
+
function getApiKeyStatus(apiKeyReference) {
|
|
121
|
+
try {
|
|
122
|
+
return resolveConfigValue(apiKeyReference) ? { state: "ready" } : { state: "missing_api_key" };
|
|
123
|
+
} catch (error) {
|
|
124
|
+
return {
|
|
125
|
+
state: "invalid_config",
|
|
126
|
+
detail: formatConfigValueError(error)
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
function formatConfigValueError(error) {
|
|
131
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
132
|
+
return message.replace(/\s+/g, " ").trim() || "Failed to resolve config value";
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// src/providers/brave.ts
|
|
136
|
+
var DEFAULT_BASE_URL = "https://api.search.brave.com";
|
|
137
|
+
var BRAVE_API_VERSION = void 0;
|
|
138
|
+
var countryOption = Type.Optional(
|
|
139
|
+
Type.String({
|
|
140
|
+
description: "Country code used to localize Brave results, for example 'US'."
|
|
141
|
+
})
|
|
142
|
+
);
|
|
143
|
+
var searchLangOption = Type.Optional(
|
|
144
|
+
Type.String({
|
|
145
|
+
description: "Content language for Brave results, for example 'en'."
|
|
146
|
+
})
|
|
147
|
+
);
|
|
148
|
+
var uiLangOption = Type.Optional(
|
|
149
|
+
Type.String({
|
|
150
|
+
description: "UI language for response metadata, for example 'en-US'."
|
|
151
|
+
})
|
|
152
|
+
);
|
|
153
|
+
var freshnessOption = Type.Optional(
|
|
154
|
+
Type.String({
|
|
155
|
+
description: "Freshness filter such as 'pd' (24h), 'pw' (7d), 'pm' (31d), 'py' (year), or a Brave date range."
|
|
156
|
+
})
|
|
157
|
+
);
|
|
158
|
+
var safesearchOption = Type.Optional(
|
|
159
|
+
Type.Enum({ off: "off", moderate: "moderate", strict: "strict" }, {
|
|
160
|
+
description: "Safe-search filtering level."
|
|
161
|
+
})
|
|
162
|
+
);
|
|
163
|
+
var spellcheckOption = Type.Optional(
|
|
164
|
+
Type.Boolean({ description: "Whether Brave may spellcheck the query." })
|
|
165
|
+
);
|
|
166
|
+
var countOption = Type.Optional(
|
|
167
|
+
Type.Integer({
|
|
168
|
+
minimum: 1,
|
|
169
|
+
maximum: 50,
|
|
170
|
+
description: "Mode-specific result count override. Prefer top-level maxResults unless Brave-specific pagination is needed."
|
|
171
|
+
})
|
|
172
|
+
);
|
|
173
|
+
var offsetOption = Type.Optional(
|
|
174
|
+
Type.Integer({
|
|
175
|
+
minimum: 0,
|
|
176
|
+
description: "Brave result page offset for paginated requests."
|
|
177
|
+
})
|
|
178
|
+
);
|
|
179
|
+
var gogglesOption = Type.Optional(
|
|
180
|
+
Type.String({ description: "Brave Goggles URL or inline definition." })
|
|
181
|
+
);
|
|
182
|
+
var extraSnippetsOption = Type.Optional(
|
|
183
|
+
Type.Boolean({ description: "Whether to ask Brave for extra snippets." })
|
|
184
|
+
);
|
|
185
|
+
var braveSearchOptionsSchema = Type.Object(
|
|
186
|
+
{
|
|
187
|
+
mode: Type.Optional(
|
|
188
|
+
Type.Enum(
|
|
189
|
+
{
|
|
190
|
+
web: "web",
|
|
191
|
+
llm_context: "llm_context",
|
|
192
|
+
news: "news",
|
|
193
|
+
videos: "videos",
|
|
194
|
+
images: "images",
|
|
195
|
+
places: "places"
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
description: "Brave search mode. Use 'news' for recent journalism or current events, 'videos' for clips/tutorials, 'images' for visual references, 'places' for local businesses, venues, cafes, restaurants, hotels, shops, or near/in-location searches, and 'llm_context' for retrieval context."
|
|
199
|
+
}
|
|
200
|
+
)
|
|
201
|
+
),
|
|
202
|
+
common: Type.Optional(
|
|
203
|
+
Type.Object(
|
|
204
|
+
{
|
|
205
|
+
country: countryOption,
|
|
206
|
+
search_lang: searchLangOption,
|
|
207
|
+
ui_lang: uiLangOption
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
description: "Common Brave query options merged into the selected mode's options."
|
|
211
|
+
}
|
|
212
|
+
)
|
|
213
|
+
),
|
|
214
|
+
web: Type.Optional(
|
|
215
|
+
Type.Object(
|
|
216
|
+
{
|
|
217
|
+
country: countryOption,
|
|
218
|
+
search_lang: searchLangOption,
|
|
219
|
+
ui_lang: uiLangOption,
|
|
220
|
+
freshness: freshnessOption,
|
|
221
|
+
safesearch: safesearchOption,
|
|
222
|
+
spellcheck: spellcheckOption,
|
|
223
|
+
goggles: gogglesOption,
|
|
224
|
+
extra_snippets: extraSnippetsOption,
|
|
225
|
+
offset: offsetOption,
|
|
226
|
+
enable_rich_callback: Type.Optional(
|
|
227
|
+
Type.Boolean({
|
|
228
|
+
description: "Whether to enable Brave rich callback metadata."
|
|
229
|
+
})
|
|
230
|
+
)
|
|
231
|
+
},
|
|
232
|
+
{ description: "Options for Brave Web Search mode." }
|
|
233
|
+
)
|
|
234
|
+
),
|
|
235
|
+
llmContext: Type.Optional(
|
|
236
|
+
Type.Object(
|
|
237
|
+
{
|
|
238
|
+
count: countOption,
|
|
239
|
+
maximum_number_of_urls: Type.Optional(
|
|
240
|
+
Type.Integer({ minimum: 1, description: "Maximum source URLs." })
|
|
241
|
+
),
|
|
242
|
+
maximum_number_of_tokens: Type.Optional(
|
|
243
|
+
Type.Integer({
|
|
244
|
+
minimum: 1,
|
|
245
|
+
description: "Maximum context tokens."
|
|
246
|
+
})
|
|
247
|
+
),
|
|
248
|
+
maximum_number_of_snippets: Type.Optional(
|
|
249
|
+
Type.Integer({ minimum: 1, description: "Maximum snippets." })
|
|
250
|
+
),
|
|
251
|
+
maximum_number_of_tokens_per_url: Type.Optional(
|
|
252
|
+
Type.Integer({
|
|
253
|
+
minimum: 1,
|
|
254
|
+
description: "Maximum context tokens per URL."
|
|
255
|
+
})
|
|
256
|
+
),
|
|
257
|
+
maximum_number_of_snippets_per_url: Type.Optional(
|
|
258
|
+
Type.Integer({
|
|
259
|
+
minimum: 1,
|
|
260
|
+
description: "Maximum snippets per URL."
|
|
261
|
+
})
|
|
262
|
+
),
|
|
263
|
+
context_threshold_mode: Type.Optional(
|
|
264
|
+
Type.String({ description: "Brave LLM Context threshold mode." })
|
|
265
|
+
),
|
|
266
|
+
enable_local: Type.Optional(
|
|
267
|
+
Type.Boolean({ description: "Whether to include local results." })
|
|
268
|
+
),
|
|
269
|
+
enable_source_metadata: Type.Optional(
|
|
270
|
+
Type.Boolean({
|
|
271
|
+
description: "Whether to include source metadata in grounding."
|
|
272
|
+
})
|
|
273
|
+
),
|
|
274
|
+
country: countryOption,
|
|
275
|
+
search_lang: searchLangOption,
|
|
276
|
+
ui_lang: uiLangOption,
|
|
277
|
+
freshness: freshnessOption,
|
|
278
|
+
safesearch: safesearchOption,
|
|
279
|
+
spellcheck: spellcheckOption,
|
|
280
|
+
goggles: gogglesOption
|
|
281
|
+
},
|
|
282
|
+
{ description: "Options for Brave LLM Context mode." }
|
|
283
|
+
)
|
|
284
|
+
),
|
|
285
|
+
news: Type.Optional(
|
|
286
|
+
Type.Object(
|
|
287
|
+
{
|
|
288
|
+
country: countryOption,
|
|
289
|
+
search_lang: searchLangOption,
|
|
290
|
+
ui_lang: uiLangOption,
|
|
291
|
+
freshness: freshnessOption,
|
|
292
|
+
safesearch: safesearchOption,
|
|
293
|
+
spellcheck: spellcheckOption,
|
|
294
|
+
goggles: gogglesOption,
|
|
295
|
+
extra_snippets: extraSnippetsOption,
|
|
296
|
+
offset: offsetOption,
|
|
297
|
+
count: countOption
|
|
298
|
+
},
|
|
299
|
+
{ description: "Options for Brave News Search mode." }
|
|
300
|
+
)
|
|
301
|
+
),
|
|
302
|
+
videos: Type.Optional(
|
|
303
|
+
Type.Object(
|
|
304
|
+
{
|
|
305
|
+
country: countryOption,
|
|
306
|
+
search_lang: searchLangOption,
|
|
307
|
+
ui_lang: uiLangOption,
|
|
308
|
+
freshness: freshnessOption,
|
|
309
|
+
safesearch: safesearchOption,
|
|
310
|
+
spellcheck: spellcheckOption,
|
|
311
|
+
offset: offsetOption,
|
|
312
|
+
count: countOption
|
|
313
|
+
},
|
|
314
|
+
{ description: "Options for Brave Video Search mode." }
|
|
315
|
+
)
|
|
316
|
+
),
|
|
317
|
+
images: Type.Optional(
|
|
318
|
+
Type.Object(
|
|
319
|
+
{
|
|
320
|
+
country: countryOption,
|
|
321
|
+
search_lang: searchLangOption,
|
|
322
|
+
ui_lang: uiLangOption,
|
|
323
|
+
safesearch: safesearchOption,
|
|
324
|
+
spellcheck: spellcheckOption,
|
|
325
|
+
count: countOption
|
|
326
|
+
},
|
|
327
|
+
{ description: "Options for Brave Image Search mode." }
|
|
328
|
+
)
|
|
329
|
+
),
|
|
330
|
+
places: Type.Optional(
|
|
331
|
+
Type.Object(
|
|
332
|
+
{
|
|
333
|
+
country: countryOption,
|
|
334
|
+
search_lang: searchLangOption,
|
|
335
|
+
ui_lang: uiLangOption,
|
|
336
|
+
latitude: Type.Optional(
|
|
337
|
+
Type.Number({ description: "Latitude for local place search." })
|
|
338
|
+
),
|
|
339
|
+
longitude: Type.Optional(
|
|
340
|
+
Type.Number({ description: "Longitude for local place search." })
|
|
341
|
+
),
|
|
342
|
+
location: Type.Optional(
|
|
343
|
+
Type.String({
|
|
344
|
+
description: "Human-readable local search location, e.g. 'Eppendorf, Hamburg, Germany'. Use with mode='places' for neighborhood or near-me style searches."
|
|
345
|
+
})
|
|
346
|
+
),
|
|
347
|
+
radius: Type.Optional(
|
|
348
|
+
Type.Number({ description: "Local search radius." })
|
|
349
|
+
),
|
|
350
|
+
units: Type.Optional(
|
|
351
|
+
Type.String({ description: "Distance units for local search." })
|
|
352
|
+
),
|
|
353
|
+
safesearch: safesearchOption,
|
|
354
|
+
spellcheck: spellcheckOption,
|
|
355
|
+
geoloc: Type.Optional(
|
|
356
|
+
Type.String({
|
|
357
|
+
description: "Optional geolocation token used to refine results."
|
|
358
|
+
})
|
|
359
|
+
),
|
|
360
|
+
count: countOption,
|
|
361
|
+
includeDetails: Type.Optional(
|
|
362
|
+
Type.Boolean({
|
|
363
|
+
description: "Places mode only. Fetch detailed POI metadata when the task needs contact info, opening hours, ratings/review counts, photos, profiles, or richer address/distance data. Leave off for simple place listings to avoid extra latency and quota usage."
|
|
364
|
+
})
|
|
365
|
+
),
|
|
366
|
+
includeDescriptions: Type.Optional(
|
|
367
|
+
Type.Boolean({
|
|
368
|
+
description: "Places mode only. Fetch AI-generated POI descriptions when the task needs qualitative summaries or short explanations of places. Leave off for simple nearby/place listing queries to avoid extra latency and quota usage."
|
|
369
|
+
})
|
|
370
|
+
)
|
|
371
|
+
},
|
|
372
|
+
{ description: "Options for Brave Local Place Search mode." }
|
|
373
|
+
)
|
|
374
|
+
)
|
|
375
|
+
},
|
|
376
|
+
{ description: "Brave search options." }
|
|
377
|
+
);
|
|
378
|
+
var braveSearchPromptGuidelines = [
|
|
379
|
+
"Use Brave places mode for direct point-of-interest listings such as restaurants, cafes, hotels, shops, landmarks, or venues.",
|
|
380
|
+
"Prefer Brave places mode over llm_context when the user asks for nearby businesses or wants names, addresses, ratings, opening hours, categories, or contact details.",
|
|
381
|
+
"In Brave places mode, set places.includeDetails when the task needs POI attributes beyond the basic result list, such as contact info, opening hours, ratings/review counts, photos, profiles, or richer address/distance metadata.",
|
|
382
|
+
"In Brave places mode, set places.includeDescriptions when the task needs qualitative summaries or short explanations of places. Leave it off for simple nearby/place listing queries to avoid extra latency and quota usage.",
|
|
383
|
+
"Use Brave llm_context mode when the agent needs extracted source context for reasoning, synthesis, RAG-style grounding, or source-material collection.",
|
|
384
|
+
"In Brave llm_context mode, set llmContext.enable_local=true for local or near-me queries where POI/map grounding may be useful."
|
|
385
|
+
];
|
|
386
|
+
var braveAnswerOptionsSchema = Type.Object(
|
|
387
|
+
{
|
|
388
|
+
country: Type.Optional(Type.String()),
|
|
389
|
+
language: Type.Optional(Type.String()),
|
|
390
|
+
enable_citations: Type.Optional(Type.Boolean()),
|
|
391
|
+
enable_entities: Type.Optional(Type.Boolean()),
|
|
392
|
+
max_completion_tokens: Type.Optional(Type.Integer({ minimum: 1 }))
|
|
393
|
+
},
|
|
394
|
+
{ description: "Brave answer options." }
|
|
395
|
+
);
|
|
396
|
+
var braveResearchOptionsSchema = Type.Object(
|
|
397
|
+
{
|
|
398
|
+
country: Type.Optional(Type.String()),
|
|
399
|
+
language: Type.Optional(Type.String()),
|
|
400
|
+
enable_entities: Type.Optional(Type.Boolean()),
|
|
401
|
+
enable_citations: Type.Optional(
|
|
402
|
+
Type.Boolean({
|
|
403
|
+
description: "Accepted for compatibility but forced to false for Brave research mode."
|
|
404
|
+
})
|
|
405
|
+
),
|
|
406
|
+
max_completion_tokens: Type.Optional(Type.Integer({ minimum: 1 })),
|
|
407
|
+
research_allow_thinking: Type.Optional(Type.Boolean()),
|
|
408
|
+
research_maximum_number_of_tokens_per_query: Type.Optional(
|
|
409
|
+
Type.Integer({ minimum: 1 })
|
|
410
|
+
),
|
|
411
|
+
research_maximum_number_of_queries: Type.Optional(
|
|
412
|
+
Type.Integer({ minimum: 1 })
|
|
413
|
+
),
|
|
414
|
+
research_maximum_number_of_iterations: Type.Optional(
|
|
415
|
+
Type.Integer({ minimum: 1 })
|
|
416
|
+
),
|
|
417
|
+
research_maximum_number_of_seconds: Type.Optional(
|
|
418
|
+
Type.Integer({ minimum: 1 })
|
|
419
|
+
),
|
|
420
|
+
research_maximum_number_of_results_per_query: Type.Optional(
|
|
421
|
+
Type.Integer({ minimum: 1 })
|
|
422
|
+
)
|
|
423
|
+
},
|
|
424
|
+
{ description: "Brave research options." }
|
|
425
|
+
);
|
|
426
|
+
var braveImplementation = {
|
|
427
|
+
id: "brave",
|
|
428
|
+
label: "Brave",
|
|
429
|
+
docsUrl: "https://api-dashboard.search.brave.com/app/documentation",
|
|
430
|
+
getToolOptionsSchema(capability) {
|
|
431
|
+
switch (capability) {
|
|
432
|
+
case "search":
|
|
433
|
+
return braveSearchOptionsSchema;
|
|
434
|
+
case "answer":
|
|
435
|
+
return braveAnswerOptionsSchema;
|
|
436
|
+
case "research":
|
|
437
|
+
return braveResearchOptionsSchema;
|
|
438
|
+
default:
|
|
439
|
+
return void 0;
|
|
440
|
+
}
|
|
441
|
+
},
|
|
442
|
+
createTemplate() {
|
|
443
|
+
return {
|
|
444
|
+
credentials: {
|
|
445
|
+
search: "BRAVE_SEARCH_API_KEY",
|
|
446
|
+
answers: "BRAVE_ANSWERS_API_KEY"
|
|
447
|
+
},
|
|
448
|
+
options: {}
|
|
449
|
+
};
|
|
450
|
+
},
|
|
451
|
+
getCapabilityStatus(config, _cwd, tool) {
|
|
452
|
+
const key = tool === "answer" || tool === "research" ? config?.credentials?.answers : config?.credentials?.search;
|
|
453
|
+
try {
|
|
454
|
+
if (tool)
|
|
455
|
+
return resolveConfigValue(key) ? { state: "ready" } : { state: "missing_api_key" };
|
|
456
|
+
return [
|
|
457
|
+
config?.credentials?.search,
|
|
458
|
+
config?.credentials?.answers,
|
|
459
|
+
config?.credentials?.autosuggest
|
|
460
|
+
].some((v) => resolveConfigValue(v)) ? { state: "ready" } : { state: "missing_api_key" };
|
|
461
|
+
} catch (error) {
|
|
462
|
+
return { state: "invalid_config", detail: formatConfigValueError(error) };
|
|
463
|
+
}
|
|
464
|
+
},
|
|
465
|
+
async search(query2, maxResults, config, context, options) {
|
|
466
|
+
const apiKey = requireKey(config.credentials?.search, "Brave search");
|
|
467
|
+
const defaults = asJsonObject(
|
|
468
|
+
config.options?.search
|
|
469
|
+
);
|
|
470
|
+
const callOptions = { ...defaults, ...options ?? {} };
|
|
471
|
+
const mode = readMode(callOptions.mode);
|
|
472
|
+
if (mode === "llm_context")
|
|
473
|
+
return await llmContext(
|
|
474
|
+
query2,
|
|
475
|
+
maxResults,
|
|
476
|
+
config,
|
|
477
|
+
context,
|
|
478
|
+
apiKey,
|
|
479
|
+
callOptions
|
|
480
|
+
);
|
|
481
|
+
if (mode === "news")
|
|
482
|
+
return await news(
|
|
483
|
+
query2,
|
|
484
|
+
maxResults,
|
|
485
|
+
config,
|
|
486
|
+
context,
|
|
487
|
+
apiKey,
|
|
488
|
+
callOptions
|
|
489
|
+
);
|
|
490
|
+
if (mode === "videos")
|
|
491
|
+
return await videos(
|
|
492
|
+
query2,
|
|
493
|
+
maxResults,
|
|
494
|
+
config,
|
|
495
|
+
context,
|
|
496
|
+
apiKey,
|
|
497
|
+
callOptions
|
|
498
|
+
);
|
|
499
|
+
if (mode === "images")
|
|
500
|
+
return await images(
|
|
501
|
+
query2,
|
|
502
|
+
maxResults,
|
|
503
|
+
config,
|
|
504
|
+
context,
|
|
505
|
+
apiKey,
|
|
506
|
+
callOptions
|
|
507
|
+
);
|
|
508
|
+
if (mode === "places")
|
|
509
|
+
return await places(
|
|
510
|
+
query2,
|
|
511
|
+
maxResults,
|
|
512
|
+
config,
|
|
513
|
+
context,
|
|
514
|
+
apiKey,
|
|
515
|
+
callOptions
|
|
516
|
+
);
|
|
517
|
+
return await web(query2, maxResults, config, context, apiKey, callOptions);
|
|
518
|
+
},
|
|
519
|
+
async answer(query2, config, context, options) {
|
|
520
|
+
const raw = {
|
|
521
|
+
...asJsonObject(
|
|
522
|
+
config.options?.answer
|
|
523
|
+
),
|
|
524
|
+
...options ?? {}
|
|
525
|
+
};
|
|
526
|
+
return await completion(query2, config, context, buildAnswerRequest(raw));
|
|
527
|
+
},
|
|
528
|
+
async research(input, config, context, options) {
|
|
529
|
+
const raw = {
|
|
530
|
+
...asJsonObject(
|
|
531
|
+
config.options?.research
|
|
532
|
+
),
|
|
533
|
+
...options ?? {}
|
|
534
|
+
};
|
|
535
|
+
return await completion(input, config, context, buildResearchRequest(raw));
|
|
536
|
+
}
|
|
537
|
+
};
|
|
538
|
+
function requireKey(ref, label) {
|
|
539
|
+
const key = resolveConfigValue(ref);
|
|
540
|
+
if (!key) throw new Error(`${label} is missing an API key`);
|
|
541
|
+
return key;
|
|
542
|
+
}
|
|
543
|
+
function base(config) {
|
|
544
|
+
return (resolveConfigValue(config.baseUrl) ?? DEFAULT_BASE_URL).replace(
|
|
545
|
+
/\/+$/,
|
|
546
|
+
""
|
|
547
|
+
);
|
|
548
|
+
}
|
|
549
|
+
function clamp(n, max = 20) {
|
|
550
|
+
return Math.max(1, Math.min(max, Math.trunc(n || 0)));
|
|
551
|
+
}
|
|
552
|
+
function readMode(v) {
|
|
553
|
+
return v === "llm_context" || v === "news" || v === "videos" || v === "images" || v === "places" ? v : "web";
|
|
554
|
+
}
|
|
555
|
+
function obj(v) {
|
|
556
|
+
return typeof v === "object" && v !== null && !Array.isArray(v) ? v : {};
|
|
557
|
+
}
|
|
558
|
+
function arr(v) {
|
|
559
|
+
return Array.isArray(v) ? v : [];
|
|
560
|
+
}
|
|
561
|
+
function str(v) {
|
|
562
|
+
return typeof v === "string" ? v : void 0;
|
|
563
|
+
}
|
|
564
|
+
function num(v) {
|
|
565
|
+
return typeof v === "number" && Number.isFinite(v) ? v : void 0;
|
|
566
|
+
}
|
|
567
|
+
function pick(source, allowed) {
|
|
568
|
+
return Object.fromEntries(
|
|
569
|
+
allowed.filter((k) => source[k] !== void 0).map((k) => [k, source[k]])
|
|
570
|
+
);
|
|
571
|
+
}
|
|
572
|
+
function mergeOptions(options, key, allowed) {
|
|
573
|
+
return pick({ ...obj(options.common), ...obj(options[key]) }, allowed);
|
|
574
|
+
}
|
|
575
|
+
function headers(key, json = false) {
|
|
576
|
+
const result = { "X-Subscription-Token": key };
|
|
577
|
+
if (BRAVE_API_VERSION) {
|
|
578
|
+
result["Api-Version"] = BRAVE_API_VERSION;
|
|
579
|
+
}
|
|
580
|
+
if (json) {
|
|
581
|
+
result["content-type"] = "application/json";
|
|
582
|
+
}
|
|
583
|
+
return result;
|
|
584
|
+
}
|
|
585
|
+
function url(config, path, params) {
|
|
586
|
+
const u = new URL(`${base(config)}${path}`);
|
|
587
|
+
for (const [k, v] of Object.entries(params))
|
|
588
|
+
if (v !== void 0)
|
|
589
|
+
u.searchParams.set(k, Array.isArray(v) ? v.join(",") : String(v));
|
|
590
|
+
return u;
|
|
591
|
+
}
|
|
592
|
+
async function httpError(response) {
|
|
593
|
+
const text = (await response.text()).trim();
|
|
594
|
+
return `Brave API request failed (${response.status}${response.statusText ? ` ${response.statusText}` : ""})${text ? `: ${text}` : "."}`;
|
|
595
|
+
}
|
|
596
|
+
async function web(query2, maxResults, config, context, key, options) {
|
|
597
|
+
const params = {
|
|
598
|
+
q: query2,
|
|
599
|
+
count: clamp(maxResults),
|
|
600
|
+
text_decorations: false,
|
|
601
|
+
...mergeOptions(options, "web", [
|
|
602
|
+
"country",
|
|
603
|
+
"search_lang",
|
|
604
|
+
"ui_lang",
|
|
605
|
+
"freshness",
|
|
606
|
+
"safesearch",
|
|
607
|
+
"spellcheck",
|
|
608
|
+
"goggles",
|
|
609
|
+
"extra_snippets",
|
|
610
|
+
"offset",
|
|
611
|
+
"enable_rich_callback"
|
|
612
|
+
])
|
|
613
|
+
};
|
|
614
|
+
const r = await fetch(url(config, "/res/v1/web/search", params), {
|
|
615
|
+
headers: headers(key),
|
|
616
|
+
signal: context.signal
|
|
617
|
+
});
|
|
618
|
+
if (!r.ok) throw new Error(await httpError(r));
|
|
619
|
+
const p = obj(await r.json());
|
|
620
|
+
return {
|
|
621
|
+
provider: "brave",
|
|
622
|
+
results: arr(obj(p.web).results).map((e) => {
|
|
623
|
+
const x = obj(e);
|
|
624
|
+
const u = str(x.url) ?? "";
|
|
625
|
+
return {
|
|
626
|
+
title: str(x.title) || u || "Untitled",
|
|
627
|
+
url: u,
|
|
628
|
+
snippet: trimSnippet(
|
|
629
|
+
str(x.description) ?? arr(x.extra_snippets).join(" ")
|
|
630
|
+
),
|
|
631
|
+
metadata: x
|
|
632
|
+
};
|
|
633
|
+
}).slice(0, clamp(maxResults))
|
|
634
|
+
};
|
|
635
|
+
}
|
|
636
|
+
async function llmContext(query2, maxResults, config, context, key, options) {
|
|
637
|
+
const params = {
|
|
638
|
+
q: query2,
|
|
639
|
+
count: clamp(maxResults),
|
|
640
|
+
maximum_number_of_urls: clamp(maxResults),
|
|
641
|
+
maximum_number_of_tokens: 8192,
|
|
642
|
+
enable_source_metadata: true,
|
|
643
|
+
...mergeOptions(options, "llmContext", [
|
|
644
|
+
"count",
|
|
645
|
+
"maximum_number_of_urls",
|
|
646
|
+
"maximum_number_of_tokens",
|
|
647
|
+
"maximum_number_of_snippets",
|
|
648
|
+
"maximum_number_of_tokens_per_url",
|
|
649
|
+
"maximum_number_of_snippets_per_url",
|
|
650
|
+
"context_threshold_mode",
|
|
651
|
+
"enable_local",
|
|
652
|
+
"enable_source_metadata",
|
|
653
|
+
"country",
|
|
654
|
+
"search_lang",
|
|
655
|
+
"ui_lang",
|
|
656
|
+
"freshness",
|
|
657
|
+
"safesearch",
|
|
658
|
+
"spellcheck",
|
|
659
|
+
"goggles"
|
|
660
|
+
])
|
|
661
|
+
};
|
|
662
|
+
const r = await fetch(url(config, "/res/v1/llm/context", params), {
|
|
663
|
+
headers: headers(key),
|
|
664
|
+
signal: context.signal
|
|
665
|
+
});
|
|
666
|
+
if (!r.ok) throw new Error(await httpError(r));
|
|
667
|
+
const p = obj(await r.json());
|
|
668
|
+
return {
|
|
669
|
+
provider: "brave",
|
|
670
|
+
results: collectLlmContextEntries(obj(p.grounding)).map((e) => {
|
|
671
|
+
const x = obj(e);
|
|
672
|
+
const snippets = arr(x.snippets).map(String);
|
|
673
|
+
const source = obj(x.source);
|
|
674
|
+
const u = str(x.url) ?? str(source.url) ?? "";
|
|
675
|
+
return {
|
|
676
|
+
title: str(x.title) ?? str(x.name) ?? str(source.title) ?? (u || "Untitled"),
|
|
677
|
+
url: u,
|
|
678
|
+
snippet: trimSnippet(snippets.join("\n\n"), 1200),
|
|
679
|
+
metadata: x
|
|
680
|
+
};
|
|
681
|
+
}).slice(0, clamp(maxResults))
|
|
682
|
+
};
|
|
683
|
+
}
|
|
684
|
+
function collectLlmContextEntries(grounding) {
|
|
685
|
+
const entries = [];
|
|
686
|
+
for (const value of [grounding.generic, grounding.map]) {
|
|
687
|
+
entries.push(...arr(value).map(obj));
|
|
688
|
+
}
|
|
689
|
+
const poiEntries = Array.isArray(grounding.poi) ? grounding.poi.map(obj) : [obj(grounding.poi)];
|
|
690
|
+
entries.push(...poiEntries.filter((entry) => Object.keys(entry).length > 0));
|
|
691
|
+
return entries;
|
|
692
|
+
}
|
|
693
|
+
async function news(query2, maxResults, config, context, key, options) {
|
|
694
|
+
const params = {
|
|
695
|
+
q: query2,
|
|
696
|
+
count: clamp(maxResults, 50),
|
|
697
|
+
...mergeOptions(options, "news", [
|
|
698
|
+
"country",
|
|
699
|
+
"search_lang",
|
|
700
|
+
"ui_lang",
|
|
701
|
+
"freshness",
|
|
702
|
+
"safesearch",
|
|
703
|
+
"spellcheck",
|
|
704
|
+
"goggles",
|
|
705
|
+
"extra_snippets",
|
|
706
|
+
"offset",
|
|
707
|
+
"count"
|
|
708
|
+
])
|
|
709
|
+
};
|
|
710
|
+
const r = await fetch(url(config, "/res/v1/news/search", params), {
|
|
711
|
+
headers: headers(key),
|
|
712
|
+
signal: context.signal
|
|
713
|
+
});
|
|
714
|
+
if (!r.ok) throw new Error(await httpError(r));
|
|
715
|
+
const p = obj(await r.json());
|
|
716
|
+
return {
|
|
717
|
+
provider: "brave",
|
|
718
|
+
results: arr(p.results).map((e) => {
|
|
719
|
+
const x = obj(e);
|
|
720
|
+
const u = str(x.url) ?? "";
|
|
721
|
+
const source = str(x.source) ?? str(x.source_name);
|
|
722
|
+
return {
|
|
723
|
+
title: str(x.title) || u || "Untitled",
|
|
724
|
+
url: u,
|
|
725
|
+
snippet: trimSnippet(
|
|
726
|
+
[
|
|
727
|
+
str(x.description) ?? arr(x.extra_snippets).join(" "),
|
|
728
|
+
source,
|
|
729
|
+
str(x.age) ?? str(x.page_age)
|
|
730
|
+
].filter(Boolean).join(" \u2014 ")
|
|
731
|
+
),
|
|
732
|
+
metadata: x
|
|
733
|
+
};
|
|
734
|
+
}).slice(0, clamp(maxResults, 50))
|
|
735
|
+
};
|
|
736
|
+
}
|
|
737
|
+
async function videos(query2, maxResults, config, context, key, options) {
|
|
738
|
+
const params = {
|
|
739
|
+
q: query2,
|
|
740
|
+
count: clamp(maxResults, 50),
|
|
741
|
+
...mergeOptions(options, "videos", [
|
|
742
|
+
"country",
|
|
743
|
+
"search_lang",
|
|
744
|
+
"ui_lang",
|
|
745
|
+
"freshness",
|
|
746
|
+
"safesearch",
|
|
747
|
+
"spellcheck",
|
|
748
|
+
"offset",
|
|
749
|
+
"count"
|
|
750
|
+
])
|
|
751
|
+
};
|
|
752
|
+
const r = await fetch(url(config, "/res/v1/videos/search", params), {
|
|
753
|
+
headers: headers(key),
|
|
754
|
+
signal: context.signal
|
|
755
|
+
});
|
|
756
|
+
if (!r.ok) throw new Error(await httpError(r));
|
|
757
|
+
const p = obj(await r.json());
|
|
758
|
+
return {
|
|
759
|
+
provider: "brave",
|
|
760
|
+
results: arr(p.results).map((e) => {
|
|
761
|
+
const x = obj(e);
|
|
762
|
+
const u = str(x.url) ?? "";
|
|
763
|
+
const video = obj(x.video);
|
|
764
|
+
return {
|
|
765
|
+
title: str(x.title) || u || "Untitled",
|
|
766
|
+
url: u,
|
|
767
|
+
snippet: trimSnippet(
|
|
768
|
+
[
|
|
769
|
+
str(x.description),
|
|
770
|
+
str(video.creator) ?? str(x.creator),
|
|
771
|
+
str(video.duration) ?? str(x.duration),
|
|
772
|
+
num(video.views) ? `${num(video.views)} views` : void 0,
|
|
773
|
+
str(x.age) ?? str(x.page_age)
|
|
774
|
+
].filter(Boolean).join(" \u2014 ")
|
|
775
|
+
),
|
|
776
|
+
metadata: x
|
|
777
|
+
};
|
|
778
|
+
}).slice(0, clamp(maxResults, 50))
|
|
779
|
+
};
|
|
780
|
+
}
|
|
781
|
+
async function images(query2, maxResults, config, context, key, options) {
|
|
782
|
+
const params = {
|
|
783
|
+
q: query2,
|
|
784
|
+
count: clamp(maxResults),
|
|
785
|
+
...mergeOptions(options, "images", [
|
|
786
|
+
"country",
|
|
787
|
+
"search_lang",
|
|
788
|
+
"ui_lang",
|
|
789
|
+
"safesearch",
|
|
790
|
+
"spellcheck",
|
|
791
|
+
"count"
|
|
792
|
+
])
|
|
793
|
+
};
|
|
794
|
+
const r = await fetch(url(config, "/res/v1/images/search", params), {
|
|
795
|
+
headers: headers(key),
|
|
796
|
+
signal: context.signal
|
|
797
|
+
});
|
|
798
|
+
if (!r.ok) throw new Error(await httpError(r));
|
|
799
|
+
const p = obj(await r.json());
|
|
800
|
+
return {
|
|
801
|
+
provider: "brave",
|
|
802
|
+
results: arr(p.results).map((e) => {
|
|
803
|
+
const x = obj(e);
|
|
804
|
+
const props = obj(x.properties);
|
|
805
|
+
const page = str(x.url) ?? str(x.source) ?? str(props.url) ?? "";
|
|
806
|
+
const image = str(props.url);
|
|
807
|
+
return {
|
|
808
|
+
title: str(x.title) || page || "Untitled",
|
|
809
|
+
url: page || image || "",
|
|
810
|
+
snippet: trimSnippet(
|
|
811
|
+
[str(x.description), str(x.publisher), image].filter(Boolean).join(" \u2014 ")
|
|
812
|
+
),
|
|
813
|
+
metadata: x
|
|
814
|
+
};
|
|
815
|
+
}).slice(0, clamp(maxResults))
|
|
816
|
+
};
|
|
817
|
+
}
|
|
818
|
+
async function places(query2, maxResults, config, context, key, options) {
|
|
819
|
+
const placeOptions = obj(options.places);
|
|
820
|
+
const params = {
|
|
821
|
+
q: query2,
|
|
822
|
+
count: clamp(maxResults),
|
|
823
|
+
...mergeOptions(options, "places", [
|
|
824
|
+
"country",
|
|
825
|
+
"search_lang",
|
|
826
|
+
"ui_lang",
|
|
827
|
+
"latitude",
|
|
828
|
+
"longitude",
|
|
829
|
+
"location",
|
|
830
|
+
"radius",
|
|
831
|
+
"units",
|
|
832
|
+
"safesearch",
|
|
833
|
+
"spellcheck",
|
|
834
|
+
"geoloc",
|
|
835
|
+
"count"
|
|
836
|
+
])
|
|
837
|
+
};
|
|
838
|
+
const r = await fetch(url(config, "/res/v1/local/place_search", params), {
|
|
839
|
+
headers: headers(key),
|
|
840
|
+
signal: context.signal
|
|
841
|
+
});
|
|
842
|
+
if (!r.ok) throw new Error(await httpError(r));
|
|
843
|
+
const p = obj(await r.json());
|
|
844
|
+
const rows = arr(p.results).slice(0, clamp(maxResults));
|
|
845
|
+
const ids = rows.map((e) => str(obj(e).id)).filter((id) => id !== void 0);
|
|
846
|
+
const [detailsById, descriptionsById] = await Promise.all([
|
|
847
|
+
placeOptions.includeDetails && ids.length > 0 ? fetchPlaceDetails(
|
|
848
|
+
config,
|
|
849
|
+
context,
|
|
850
|
+
key,
|
|
851
|
+
ids,
|
|
852
|
+
pick(params, ["search_lang", "ui_lang", "units"])
|
|
853
|
+
) : Promise.resolve(/* @__PURE__ */ new Map()),
|
|
854
|
+
placeOptions.includeDescriptions && ids.length > 0 ? fetchPlaceDescriptions(config, context, key, ids) : Promise.resolve(/* @__PURE__ */ new Map())
|
|
855
|
+
]);
|
|
856
|
+
return {
|
|
857
|
+
provider: "brave",
|
|
858
|
+
results: rows.map((e) => {
|
|
859
|
+
const x = obj(e);
|
|
860
|
+
const id = str(x.id);
|
|
861
|
+
const details = id ? detailsById.get(id) : void 0;
|
|
862
|
+
const description = id ? descriptionsById.get(id) : void 0;
|
|
863
|
+
const u = str(x.url) ?? str(x.provider_url) ?? "";
|
|
864
|
+
return {
|
|
865
|
+
title: str(x.title) || u || "Untitled",
|
|
866
|
+
url: u,
|
|
867
|
+
snippet: trimSnippet(
|
|
868
|
+
[
|
|
869
|
+
placeDescriptionText(description) ?? str(x.description),
|
|
870
|
+
placeAddress(x, details),
|
|
871
|
+
arr(x.categories).join(", "),
|
|
872
|
+
placeRating(x, details)
|
|
873
|
+
].filter(Boolean).join(" \u2014 ")
|
|
874
|
+
),
|
|
875
|
+
metadata: {
|
|
876
|
+
...x,
|
|
877
|
+
...details ? { poiDetails: details } : {},
|
|
878
|
+
...description ? { poiDescription: description } : {}
|
|
879
|
+
}
|
|
880
|
+
};
|
|
881
|
+
})
|
|
882
|
+
};
|
|
883
|
+
}
|
|
884
|
+
async function fetchPlaceDetails(config, context, key, ids, options) {
|
|
885
|
+
const r = await fetch(
|
|
886
|
+
urlWithRepeatedArrays(config, "/res/v1/local/pois", {
|
|
887
|
+
ids: ids.slice(0, 20),
|
|
888
|
+
...options
|
|
889
|
+
}),
|
|
890
|
+
{
|
|
891
|
+
headers: headers(key),
|
|
892
|
+
signal: context.signal
|
|
893
|
+
}
|
|
894
|
+
);
|
|
895
|
+
if (!r.ok) throw new Error(await httpError(r));
|
|
896
|
+
return indexById(arr(obj(await r.json()).results));
|
|
897
|
+
}
|
|
898
|
+
async function fetchPlaceDescriptions(config, context, key, ids) {
|
|
899
|
+
const r = await fetch(
|
|
900
|
+
urlWithRepeatedArrays(config, "/res/v1/local/descriptions", {
|
|
901
|
+
ids: ids.slice(0, 20)
|
|
902
|
+
}),
|
|
903
|
+
{
|
|
904
|
+
headers: headers(key),
|
|
905
|
+
signal: context.signal
|
|
906
|
+
}
|
|
907
|
+
);
|
|
908
|
+
if (!r.ok) throw new Error(await httpError(r));
|
|
909
|
+
return indexById(arr(obj(await r.json()).results));
|
|
910
|
+
}
|
|
911
|
+
function urlWithRepeatedArrays(config, path, params) {
|
|
912
|
+
const u = new URL(`${base(config)}${path}`);
|
|
913
|
+
for (const [k, v] of Object.entries(params)) {
|
|
914
|
+
if (v === void 0) continue;
|
|
915
|
+
if (Array.isArray(v)) {
|
|
916
|
+
for (const item of v) {
|
|
917
|
+
u.searchParams.append(k, String(item));
|
|
918
|
+
}
|
|
919
|
+
} else {
|
|
920
|
+
u.searchParams.set(k, String(v));
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
return u;
|
|
924
|
+
}
|
|
925
|
+
function indexById(values) {
|
|
926
|
+
const result = /* @__PURE__ */ new Map();
|
|
927
|
+
for (const value of values) {
|
|
928
|
+
const entry = obj(value);
|
|
929
|
+
const id = str(entry.id);
|
|
930
|
+
if (id) {
|
|
931
|
+
result.set(id, entry);
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
return result;
|
|
935
|
+
}
|
|
936
|
+
function placeDescriptionText(description) {
|
|
937
|
+
if (!description) return void 0;
|
|
938
|
+
return str(description.description) ?? str(description.text) ?? str(description.summary) ?? str(obj(description.description).text);
|
|
939
|
+
}
|
|
940
|
+
function placeAddress(place, details) {
|
|
941
|
+
return str(place.address) ?? str(obj(place.postal_address).displayAddress) ?? str(details?.address) ?? str(obj(details?.postal_address).displayAddress);
|
|
942
|
+
}
|
|
943
|
+
function placeRating(place, details) {
|
|
944
|
+
const rating = num(place.rating) ?? num(obj(place.rating).ratingValue) ?? num(details?.rating) ?? num(obj(details?.rating).ratingValue);
|
|
945
|
+
return rating === void 0 ? void 0 : `Rating: ${rating}`;
|
|
946
|
+
}
|
|
947
|
+
function buildAnswerRequest(raw) {
|
|
948
|
+
const answerOptions = pick(raw, [
|
|
949
|
+
"country",
|
|
950
|
+
"language",
|
|
951
|
+
"safesearch",
|
|
952
|
+
"enable_entities",
|
|
953
|
+
"enable_citations"
|
|
954
|
+
]);
|
|
955
|
+
if (answerOptions.enable_citations === void 0) {
|
|
956
|
+
answerOptions.enable_citations = true;
|
|
957
|
+
}
|
|
958
|
+
const stream = answerOptions.enable_citations === true || answerOptions.enable_entities === true;
|
|
959
|
+
return {
|
|
960
|
+
stream,
|
|
961
|
+
...pick(raw, ["max_completion_tokens", "metadata", "seed"]),
|
|
962
|
+
...answerOptions
|
|
963
|
+
};
|
|
964
|
+
}
|
|
965
|
+
function buildResearchRequest(raw) {
|
|
966
|
+
const researchOptions = pick(raw, [
|
|
967
|
+
"country",
|
|
968
|
+
"language",
|
|
969
|
+
"safesearch",
|
|
970
|
+
"enable_entities",
|
|
971
|
+
"research_allow_thinking",
|
|
972
|
+
"research_maximum_number_of_tokens_per_query",
|
|
973
|
+
"research_maximum_number_of_queries",
|
|
974
|
+
"research_maximum_number_of_iterations",
|
|
975
|
+
"research_maximum_number_of_seconds",
|
|
976
|
+
"research_maximum_number_of_results_per_query"
|
|
977
|
+
]);
|
|
978
|
+
return {
|
|
979
|
+
stream: true,
|
|
980
|
+
...pick(raw, ["max_completion_tokens", "metadata", "seed"]),
|
|
981
|
+
...researchOptions,
|
|
982
|
+
enable_research: true,
|
|
983
|
+
enable_citations: false
|
|
984
|
+
};
|
|
985
|
+
}
|
|
986
|
+
async function completion(input, config, context, request) {
|
|
987
|
+
const key = requireKey(config.credentials?.answers, "Brave Answers");
|
|
988
|
+
const body = {
|
|
989
|
+
model: "brave",
|
|
990
|
+
messages: [{ role: "user", content: input }],
|
|
991
|
+
...request
|
|
992
|
+
};
|
|
993
|
+
const r = await fetch(`${base(config)}/res/v1/chat/completions`, {
|
|
994
|
+
method: "POST",
|
|
995
|
+
headers: headers(key, true),
|
|
996
|
+
body: JSON.stringify(body),
|
|
997
|
+
signal: context.signal
|
|
998
|
+
});
|
|
999
|
+
if (!r.ok) throw new Error(await httpError(r));
|
|
1000
|
+
const text = await r.text();
|
|
1001
|
+
const parsed = body.stream === false ? parseAnswerJson(text) : parseAnswerStream(text);
|
|
1002
|
+
const lines = [parsed.answer.trim() || text.trim()];
|
|
1003
|
+
if (parsed.citations.length) {
|
|
1004
|
+
lines.push("", "Sources:");
|
|
1005
|
+
parsed.citations.forEach((c, i) => {
|
|
1006
|
+
lines.push(`${i + 1}. ${c.title ?? c.url ?? "Source"}`);
|
|
1007
|
+
if (c.url) lines.push(` ${c.url}`);
|
|
1008
|
+
});
|
|
1009
|
+
}
|
|
1010
|
+
const metadata = buildAnswerMetadata(parsed);
|
|
1011
|
+
return {
|
|
1012
|
+
provider: "brave",
|
|
1013
|
+
text: lines.join("\n").trimEnd(),
|
|
1014
|
+
itemCount: parsed.citations.length,
|
|
1015
|
+
...metadata ? { metadata } : {}
|
|
1016
|
+
};
|
|
1017
|
+
}
|
|
1018
|
+
function buildAnswerMetadata(parsed) {
|
|
1019
|
+
const metadata = {};
|
|
1020
|
+
if (parsed.usage) {
|
|
1021
|
+
metadata.usage = parsed.usage;
|
|
1022
|
+
}
|
|
1023
|
+
if (parsed.entities.length) {
|
|
1024
|
+
metadata.entities = parsed.entities;
|
|
1025
|
+
}
|
|
1026
|
+
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
1027
|
+
}
|
|
1028
|
+
function parseAnswerJson(text) {
|
|
1029
|
+
const payload = obj(JSON.parse(text));
|
|
1030
|
+
const choice = obj(arr(payload.choices)[0]);
|
|
1031
|
+
const message = obj(choice.message);
|
|
1032
|
+
const content = str(message.content) ?? "";
|
|
1033
|
+
const tags = extractBraveTags(content);
|
|
1034
|
+
return {
|
|
1035
|
+
answer: tags.text,
|
|
1036
|
+
citations: dedupeCitations(tags.citations),
|
|
1037
|
+
entities: tags.entities,
|
|
1038
|
+
usage: payload.usage ?? tags.usage
|
|
1039
|
+
};
|
|
1040
|
+
}
|
|
1041
|
+
function parseAnswerStream(text) {
|
|
1042
|
+
let rawAnswer = "";
|
|
1043
|
+
for (const line of text.split(/\r?\n/)) {
|
|
1044
|
+
const data = line.startsWith("data:") ? line.slice(5).trim() : line.trim();
|
|
1045
|
+
if (!data || data === "[DONE]") continue;
|
|
1046
|
+
try {
|
|
1047
|
+
const parsed = obj(JSON.parse(data));
|
|
1048
|
+
const choice = obj(arr(parsed.choices)[0]);
|
|
1049
|
+
const delta = str(obj(choice.delta).content);
|
|
1050
|
+
if (delta) {
|
|
1051
|
+
rawAnswer += delta;
|
|
1052
|
+
}
|
|
1053
|
+
} catch {
|
|
1054
|
+
rawAnswer += data;
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
const tags = extractBraveTags(rawAnswer);
|
|
1058
|
+
return {
|
|
1059
|
+
answer: tags.text,
|
|
1060
|
+
citations: dedupeCitations(tags.citations),
|
|
1061
|
+
entities: tags.entities,
|
|
1062
|
+
usage: tags.usage
|
|
1063
|
+
};
|
|
1064
|
+
}
|
|
1065
|
+
function extractBraveTags(text) {
|
|
1066
|
+
const citations = [];
|
|
1067
|
+
const entities = [];
|
|
1068
|
+
let usage;
|
|
1069
|
+
let cleaned = "";
|
|
1070
|
+
let offset = 0;
|
|
1071
|
+
while (offset < text.length) {
|
|
1072
|
+
const tagStart = text.indexOf("<", offset);
|
|
1073
|
+
if (tagStart === -1) {
|
|
1074
|
+
cleaned += text.slice(offset);
|
|
1075
|
+
break;
|
|
1076
|
+
}
|
|
1077
|
+
const parsedTag = readBraveTagStart(text, tagStart);
|
|
1078
|
+
if (!parsedTag) {
|
|
1079
|
+
cleaned += text.slice(offset, tagStart + 1);
|
|
1080
|
+
offset = tagStart + 1;
|
|
1081
|
+
continue;
|
|
1082
|
+
}
|
|
1083
|
+
const jsonEnd = findJsonValueEnd(text, parsedTag.jsonStart);
|
|
1084
|
+
if (jsonEnd === -1) {
|
|
1085
|
+
cleaned += text.slice(offset);
|
|
1086
|
+
break;
|
|
1087
|
+
}
|
|
1088
|
+
cleaned += text.slice(offset, tagStart);
|
|
1089
|
+
const json = text.slice(parsedTag.jsonStart, jsonEnd + 1);
|
|
1090
|
+
try {
|
|
1091
|
+
const parsed = JSON.parse(json);
|
|
1092
|
+
if (parsedTag.tag === "answer") {
|
|
1093
|
+
cleaned += str(parsed.answer) ?? str(parsed.text) ?? "";
|
|
1094
|
+
} else if (parsedTag.tag === "citation") {
|
|
1095
|
+
citations.push({
|
|
1096
|
+
title: str(parsed.title),
|
|
1097
|
+
url: str(parsed.url)
|
|
1098
|
+
});
|
|
1099
|
+
} else if (parsedTag.tag === "enum_item") {
|
|
1100
|
+
const item = obj(parsed);
|
|
1101
|
+
entities.push(item);
|
|
1102
|
+
cleaned += str(item.original_tokens) ?? str(item.name) ?? str(item.href) ?? "";
|
|
1103
|
+
} else if (parsedTag.tag === "usage") {
|
|
1104
|
+
usage = parsed;
|
|
1105
|
+
}
|
|
1106
|
+
} catch {
|
|
1107
|
+
}
|
|
1108
|
+
const closing = `</${parsedTag.tag}>`;
|
|
1109
|
+
const abbreviatedClosing = `</${parsedTag.tag}`;
|
|
1110
|
+
if (text.startsWith(closing, jsonEnd + 1)) {
|
|
1111
|
+
offset = jsonEnd + 1 + closing.length;
|
|
1112
|
+
} else if (text.startsWith(abbreviatedClosing, jsonEnd + 1)) {
|
|
1113
|
+
offset = jsonEnd + 1 + abbreviatedClosing.length;
|
|
1114
|
+
} else {
|
|
1115
|
+
offset = jsonEnd + 1;
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
return { text: cleaned, citations, entities, usage };
|
|
1119
|
+
}
|
|
1120
|
+
var BRAVE_STRUCTURED_TAGS = /* @__PURE__ */ new Set([
|
|
1121
|
+
"analyzing",
|
|
1122
|
+
"answer",
|
|
1123
|
+
"blindspots",
|
|
1124
|
+
"citation",
|
|
1125
|
+
"enum_item",
|
|
1126
|
+
"progress",
|
|
1127
|
+
"queries",
|
|
1128
|
+
"thinking",
|
|
1129
|
+
"usage"
|
|
1130
|
+
]);
|
|
1131
|
+
function readBraveTagStart(text, tagStart) {
|
|
1132
|
+
const match = /^<([A-Za-z_][A-Za-z0-9_-]*)(>)?[{[]/.exec(
|
|
1133
|
+
text.slice(tagStart)
|
|
1134
|
+
);
|
|
1135
|
+
if (!match) return void 0;
|
|
1136
|
+
const tag = match[1];
|
|
1137
|
+
if (!BRAVE_STRUCTURED_TAGS.has(tag)) return void 0;
|
|
1138
|
+
return {
|
|
1139
|
+
tag,
|
|
1140
|
+
jsonStart: tagStart + match[0].length - 1
|
|
1141
|
+
};
|
|
1142
|
+
}
|
|
1143
|
+
function findJsonValueEnd(text, start) {
|
|
1144
|
+
const first = text[start];
|
|
1145
|
+
const closing = first === "{" ? "}" : first === "[" ? "]" : void 0;
|
|
1146
|
+
if (!closing) return -1;
|
|
1147
|
+
const stack = [];
|
|
1148
|
+
let inString = false;
|
|
1149
|
+
let escaped = false;
|
|
1150
|
+
for (let index = start; index < text.length; index++) {
|
|
1151
|
+
const char = text[index];
|
|
1152
|
+
if (escaped) {
|
|
1153
|
+
escaped = false;
|
|
1154
|
+
continue;
|
|
1155
|
+
}
|
|
1156
|
+
if (char === "\\") {
|
|
1157
|
+
escaped = true;
|
|
1158
|
+
continue;
|
|
1159
|
+
}
|
|
1160
|
+
if (char === '"') {
|
|
1161
|
+
inString = !inString;
|
|
1162
|
+
continue;
|
|
1163
|
+
}
|
|
1164
|
+
if (inString) continue;
|
|
1165
|
+
if (char === "{") {
|
|
1166
|
+
stack.push("}");
|
|
1167
|
+
} else if (char === "[") {
|
|
1168
|
+
stack.push("]");
|
|
1169
|
+
} else if (char === "}" || char === "]") {
|
|
1170
|
+
if (stack.pop() !== char) return -1;
|
|
1171
|
+
if (stack.length === 0) return index;
|
|
57
1172
|
}
|
|
58
1173
|
}
|
|
59
|
-
|
|
60
|
-
if (envValue !== void 0) {
|
|
61
|
-
return envValue;
|
|
62
|
-
}
|
|
63
|
-
if (/^[A-Z][A-Z0-9_]*$/.test(reference)) {
|
|
64
|
-
return void 0;
|
|
65
|
-
}
|
|
66
|
-
return reference;
|
|
1174
|
+
return -1;
|
|
67
1175
|
}
|
|
68
|
-
function
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
|
|
1176
|
+
function dedupeCitations(citations) {
|
|
1177
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1178
|
+
return citations.filter((citation) => {
|
|
1179
|
+
const key = citation.url ?? citation.title;
|
|
1180
|
+
if (!key) return false;
|
|
1181
|
+
if (seen.has(key)) return false;
|
|
1182
|
+
seen.add(key);
|
|
1183
|
+
return true;
|
|
1184
|
+
});
|
|
76
1185
|
}
|
|
1186
|
+
var braveProvider = defineProvider({
|
|
1187
|
+
id: "brave",
|
|
1188
|
+
label: braveImplementation.label,
|
|
1189
|
+
docsUrl: braveImplementation.docsUrl,
|
|
1190
|
+
config: {
|
|
1191
|
+
createTemplate: () => braveImplementation.createTemplate(),
|
|
1192
|
+
fields: ["credentials", "baseUrl", "options", "settings"],
|
|
1193
|
+
credentials: {
|
|
1194
|
+
search: "BRAVE_SEARCH_API_KEY",
|
|
1195
|
+
answers: "BRAVE_ANSWERS_API_KEY",
|
|
1196
|
+
autosuggest: "BRAVE_AUTOSUGGEST_API_KEY"
|
|
1197
|
+
},
|
|
1198
|
+
optionCapabilities: ["search", "answer", "research"]
|
|
1199
|
+
},
|
|
1200
|
+
getCapabilityStatus: (config, cwd, tool) => braveImplementation.getCapabilityStatus(
|
|
1201
|
+
config,
|
|
1202
|
+
cwd,
|
|
1203
|
+
tool
|
|
1204
|
+
),
|
|
1205
|
+
capabilities: {
|
|
1206
|
+
search: defineCapability({
|
|
1207
|
+
options: braveImplementation.getToolOptionsSchema("search"),
|
|
1208
|
+
promptGuidelines: braveSearchPromptGuidelines,
|
|
1209
|
+
async execute(input, ctx) {
|
|
1210
|
+
return await braveImplementation.search(
|
|
1211
|
+
input.query,
|
|
1212
|
+
input.maxResults,
|
|
1213
|
+
ctx.config,
|
|
1214
|
+
ctx,
|
|
1215
|
+
input.options
|
|
1216
|
+
);
|
|
1217
|
+
}
|
|
1218
|
+
}),
|
|
1219
|
+
answer: defineCapability({
|
|
1220
|
+
options: braveImplementation.getToolOptionsSchema("answer"),
|
|
1221
|
+
async execute(input, ctx) {
|
|
1222
|
+
return await braveImplementation.answer(
|
|
1223
|
+
input.query,
|
|
1224
|
+
ctx.config,
|
|
1225
|
+
ctx,
|
|
1226
|
+
input.options
|
|
1227
|
+
);
|
|
1228
|
+
}
|
|
1229
|
+
}),
|
|
1230
|
+
research: defineCapability({
|
|
1231
|
+
options: braveImplementation.getToolOptionsSchema("research"),
|
|
1232
|
+
async execute(input, ctx) {
|
|
1233
|
+
return await braveImplementation.research(
|
|
1234
|
+
input.input,
|
|
1235
|
+
ctx.config,
|
|
1236
|
+
ctx,
|
|
1237
|
+
input.options
|
|
1238
|
+
);
|
|
1239
|
+
}
|
|
1240
|
+
})
|
|
1241
|
+
}
|
|
1242
|
+
});
|
|
77
1243
|
|
|
78
1244
|
// src/providers/claude.ts
|
|
79
1245
|
import { existsSync } from "node:fs";
|
|
80
1246
|
import { query } from "@anthropic-ai/claude-agent-sdk";
|
|
81
|
-
import { Type as
|
|
1247
|
+
import { Type as Type3 } from "typebox";
|
|
82
1248
|
|
|
83
1249
|
// src/providers/schema.ts
|
|
84
|
-
import { Type } from "typebox";
|
|
1250
|
+
import { Type as Type2 } from "typebox";
|
|
85
1251
|
function literalUnion(values, options) {
|
|
86
|
-
return
|
|
87
|
-
values.map((value) =>
|
|
1252
|
+
return Type2.Union(
|
|
1253
|
+
values.map((value) => Type2.Literal(value)),
|
|
88
1254
|
options
|
|
89
1255
|
);
|
|
90
1256
|
}
|
|
91
1257
|
|
|
92
|
-
// src/providers/shared.ts
|
|
93
|
-
function trimSnippet(input, maxLength = 300) {
|
|
94
|
-
const text = (input ?? "").replace(/\s+/g, " ").trim();
|
|
95
|
-
if (text.length <= maxLength) return text;
|
|
96
|
-
return `${text.slice(0, maxLength - 1)}\u2026`;
|
|
97
|
-
}
|
|
98
|
-
function normalizeContentText(input) {
|
|
99
|
-
const text = (input ?? "").replace(/\r/g, "").trim();
|
|
100
|
-
if (!text) {
|
|
101
|
-
return "";
|
|
102
|
-
}
|
|
103
|
-
return text.split("\n").map((line) => line.replace(/[ \t]+$/g, "")).join("\n").replace(/\n{3,}/g, "\n\n");
|
|
104
|
-
}
|
|
105
|
-
function asJsonObject(value) {
|
|
106
|
-
return value ? { ...value } : {};
|
|
107
|
-
}
|
|
108
|
-
function formatJson(value) {
|
|
109
|
-
return JSON.stringify(value, null, 2);
|
|
110
|
-
}
|
|
111
|
-
function getApiKeyStatus(apiKeyReference) {
|
|
112
|
-
try {
|
|
113
|
-
return resolveConfigValue(apiKeyReference) ? { state: "ready" } : { state: "missing_api_key" };
|
|
114
|
-
} catch (error) {
|
|
115
|
-
return {
|
|
116
|
-
state: "invalid_config",
|
|
117
|
-
detail: formatConfigValueError(error)
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
function formatConfigValueError(error) {
|
|
122
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
123
|
-
return message.replace(/\s+/g, " ").trim() || "Failed to resolve config value";
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// src/providers/definition.ts
|
|
127
|
-
function defineCapability(definition) {
|
|
128
|
-
return definition;
|
|
129
|
-
}
|
|
130
|
-
function defineProvider(definition) {
|
|
131
|
-
return definition;
|
|
132
|
-
}
|
|
133
|
-
function defineProviders(providers) {
|
|
134
|
-
return providers;
|
|
135
|
-
}
|
|
136
|
-
async function executeProviderCapability(definition, capability, input, context) {
|
|
137
|
-
const handler = definition.capabilities[capability];
|
|
138
|
-
if (!handler) {
|
|
139
|
-
throw new Error(
|
|
140
|
-
`Provider '${definition.id}' does not support '${capability}'.`
|
|
141
|
-
);
|
|
142
|
-
}
|
|
143
|
-
return await handler.execute(input, context);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
1258
|
// src/providers/claude.ts
|
|
147
1259
|
var SEARCH_OUTPUT_SCHEMA = {
|
|
148
1260
|
type: "object",
|
|
@@ -184,36 +1296,36 @@ var ANSWER_OUTPUT_SCHEMA = {
|
|
|
184
1296
|
},
|
|
185
1297
|
required: ["answer", "sources"]
|
|
186
1298
|
};
|
|
187
|
-
var claudeOptionsSchema =
|
|
1299
|
+
var claudeOptionsSchema = Type3.Object(
|
|
188
1300
|
{
|
|
189
|
-
model:
|
|
190
|
-
|
|
1301
|
+
model: Type3.Optional(
|
|
1302
|
+
Type3.String({ description: "Claude model override." })
|
|
191
1303
|
),
|
|
192
|
-
effort:
|
|
1304
|
+
effort: Type3.Optional(
|
|
193
1305
|
literalUnion(["low", "medium", "high", "max"], {
|
|
194
1306
|
description: "How much effort Claude should use."
|
|
195
1307
|
})
|
|
196
1308
|
),
|
|
197
|
-
maxTurns:
|
|
198
|
-
|
|
1309
|
+
maxTurns: Type3.Optional(
|
|
1310
|
+
Type3.Integer({
|
|
199
1311
|
minimum: 1,
|
|
200
1312
|
description: "Maximum number of Claude turns."
|
|
201
1313
|
})
|
|
202
1314
|
),
|
|
203
|
-
maxThinkingTokens:
|
|
204
|
-
|
|
1315
|
+
maxThinkingTokens: Type3.Optional(
|
|
1316
|
+
Type3.Integer({ minimum: 0, description: "Maximum thinking tokens." })
|
|
205
1317
|
),
|
|
206
|
-
maxBudgetUsd:
|
|
207
|
-
|
|
1318
|
+
maxBudgetUsd: Type3.Optional(
|
|
1319
|
+
Type3.Number({
|
|
208
1320
|
exclusiveMinimum: 0,
|
|
209
1321
|
description: "Maximum budget in USD."
|
|
210
1322
|
})
|
|
211
1323
|
),
|
|
212
|
-
thinking:
|
|
213
|
-
|
|
1324
|
+
thinking: Type3.Optional(
|
|
1325
|
+
Type3.Object(
|
|
214
1326
|
{
|
|
215
|
-
type:
|
|
216
|
-
|
|
1327
|
+
type: Type3.Optional(
|
|
1328
|
+
Type3.String({ description: "Claude thinking mode." })
|
|
217
1329
|
)
|
|
218
1330
|
},
|
|
219
1331
|
{
|
|
@@ -508,13 +1620,13 @@ var claudeProvider = defineProvider({
|
|
|
508
1620
|
|
|
509
1621
|
// src/providers/cloudflare.ts
|
|
510
1622
|
import CloudflareClient from "cloudflare";
|
|
511
|
-
import { Type as
|
|
512
|
-
var cloudflareContentsOptionsSchema =
|
|
1623
|
+
import { Type as Type4 } from "typebox";
|
|
1624
|
+
var cloudflareContentsOptionsSchema = Type4.Object(
|
|
513
1625
|
{
|
|
514
|
-
gotoOptions:
|
|
515
|
-
|
|
1626
|
+
gotoOptions: Type4.Optional(
|
|
1627
|
+
Type4.Object(
|
|
516
1628
|
{
|
|
517
|
-
waitUntil:
|
|
1629
|
+
waitUntil: Type4.Optional(
|
|
518
1630
|
literalUnion(
|
|
519
1631
|
["load", "domcontentloaded", "networkidle0", "networkidle2"],
|
|
520
1632
|
{ description: "When to consider navigation complete." }
|
|
@@ -545,7 +1657,7 @@ var cloudflareImplementation = {
|
|
|
545
1657
|
},
|
|
546
1658
|
createTemplate() {
|
|
547
1659
|
return {
|
|
548
|
-
|
|
1660
|
+
credentials: { api: "CLOUDFLARE_API_TOKEN" },
|
|
549
1661
|
accountId: "CLOUDFLARE_ACCOUNT_ID",
|
|
550
1662
|
options: {
|
|
551
1663
|
gotoOptions: {
|
|
@@ -555,7 +1667,7 @@ var cloudflareImplementation = {
|
|
|
555
1667
|
};
|
|
556
1668
|
},
|
|
557
1669
|
getCapabilityStatus(config) {
|
|
558
|
-
const apiTokenStatus = getApiKeyStatus(config?.
|
|
1670
|
+
const apiTokenStatus = getApiKeyStatus(config?.credentials?.api);
|
|
559
1671
|
if (apiTokenStatus.state !== "ready") {
|
|
560
1672
|
return apiTokenStatus;
|
|
561
1673
|
}
|
|
@@ -579,24 +1691,24 @@ var cloudflareImplementation = {
|
|
|
579
1691
|
}
|
|
580
1692
|
const defaults = asJsonObject(config.options);
|
|
581
1693
|
const answers = await Promise.all(
|
|
582
|
-
urls.map(async (
|
|
1694
|
+
urls.map(async (url2) => {
|
|
583
1695
|
try {
|
|
584
1696
|
const markdown = await client.browserRendering.markdown.create(
|
|
585
1697
|
{
|
|
586
1698
|
...defaults ?? {},
|
|
587
1699
|
...options ?? {},
|
|
588
1700
|
account_id: accountId,
|
|
589
|
-
url
|
|
1701
|
+
url: url2
|
|
590
1702
|
},
|
|
591
1703
|
buildRequestOptions(context)
|
|
592
1704
|
);
|
|
593
1705
|
return {
|
|
594
|
-
url,
|
|
1706
|
+
url: url2,
|
|
595
1707
|
content: markdown
|
|
596
1708
|
};
|
|
597
1709
|
} catch (error) {
|
|
598
1710
|
return {
|
|
599
|
-
url,
|
|
1711
|
+
url: url2,
|
|
600
1712
|
error: error instanceof Error ? error.message : String(error)
|
|
601
1713
|
};
|
|
602
1714
|
}
|
|
@@ -609,7 +1721,7 @@ var cloudflareImplementation = {
|
|
|
609
1721
|
}
|
|
610
1722
|
};
|
|
611
1723
|
function createClient(config) {
|
|
612
|
-
const apiToken = resolveConfigValue(config.
|
|
1724
|
+
const apiToken = resolveConfigValue(config.credentials?.api);
|
|
613
1725
|
if (!apiToken) {
|
|
614
1726
|
throw new Error("is missing an API token");
|
|
615
1727
|
}
|
|
@@ -626,7 +1738,7 @@ var cloudflareProvider = defineProvider({
|
|
|
626
1738
|
docsUrl: cloudflareImplementation.docsUrl,
|
|
627
1739
|
config: {
|
|
628
1740
|
createTemplate: () => cloudflareImplementation.createTemplate(),
|
|
629
|
-
fields: ["
|
|
1741
|
+
fields: ["credentials", "accountId", "options", "settings"]
|
|
630
1742
|
},
|
|
631
1743
|
getCapabilityStatus: (config, cwd, tool) => cloudflareImplementation.getCapabilityStatus(
|
|
632
1744
|
config,
|
|
@@ -650,15 +1762,15 @@ var cloudflareProvider = defineProvider({
|
|
|
650
1762
|
|
|
651
1763
|
// src/providers/codex.ts
|
|
652
1764
|
import { Codex as CodexClient } from "@openai/codex-sdk";
|
|
653
|
-
import { Type as
|
|
654
|
-
var codexOutputSchema =
|
|
1765
|
+
import { Type as Type5 } from "typebox";
|
|
1766
|
+
var codexOutputSchema = Type5.Object(
|
|
655
1767
|
{
|
|
656
|
-
sources:
|
|
657
|
-
|
|
1768
|
+
sources: Type5.Array(
|
|
1769
|
+
Type5.Object(
|
|
658
1770
|
{
|
|
659
|
-
title:
|
|
660
|
-
url:
|
|
661
|
-
snippet:
|
|
1771
|
+
title: Type5.String(),
|
|
1772
|
+
url: Type5.String(),
|
|
1773
|
+
snippet: Type5.String()
|
|
662
1774
|
},
|
|
663
1775
|
{ additionalProperties: false }
|
|
664
1776
|
)
|
|
@@ -666,29 +1778,31 @@ var codexOutputSchema = Type4.Object(
|
|
|
666
1778
|
},
|
|
667
1779
|
{ additionalProperties: false }
|
|
668
1780
|
);
|
|
669
|
-
var codexSearchOptionsSchema =
|
|
1781
|
+
var codexSearchOptionsSchema = Type5.Object(
|
|
670
1782
|
{
|
|
671
|
-
model:
|
|
672
|
-
modelReasoningEffort:
|
|
673
|
-
|
|
1783
|
+
model: Type5.Optional(Type5.String({ description: "Codex model override." })),
|
|
1784
|
+
modelReasoningEffort: Type5.Optional(
|
|
1785
|
+
Type5.Union(
|
|
674
1786
|
[
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
1787
|
+
Type5.Literal("minimal"),
|
|
1788
|
+
Type5.Literal("low"),
|
|
1789
|
+
Type5.Literal("medium"),
|
|
1790
|
+
Type5.Literal("high"),
|
|
1791
|
+
Type5.Literal("xhigh")
|
|
680
1792
|
],
|
|
681
1793
|
{ description: "Reasoning depth for Codex." }
|
|
682
1794
|
)
|
|
683
1795
|
),
|
|
684
|
-
webSearchMode:
|
|
685
|
-
|
|
1796
|
+
webSearchMode: Type5.Optional(
|
|
1797
|
+
Type5.Union(
|
|
686
1798
|
[
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
1799
|
+
Type5.Literal("disabled"),
|
|
1800
|
+
Type5.Literal("cached"),
|
|
1801
|
+
Type5.Literal("live")
|
|
690
1802
|
],
|
|
691
|
-
{
|
|
1803
|
+
{
|
|
1804
|
+
description: "How Codex should source web results. Use 'live' for current information, 'cached' when freshness is less important, and 'disabled' only when web access should not be used."
|
|
1805
|
+
}
|
|
692
1806
|
)
|
|
693
1807
|
)
|
|
694
1808
|
},
|
|
@@ -734,7 +1848,7 @@ var codexImplementation = {
|
|
|
734
1848
|
const codex = new CodexClient({
|
|
735
1849
|
codexPathOverride: config.codexPath,
|
|
736
1850
|
baseUrl: config.baseUrl,
|
|
737
|
-
apiKey: resolveConfigValue(config.
|
|
1851
|
+
apiKey: resolveConfigValue(config.credentials?.api),
|
|
738
1852
|
config: config.config,
|
|
739
1853
|
env: resolveEnvMap(config.env)
|
|
740
1854
|
});
|
|
@@ -859,7 +1973,7 @@ var codexProvider = defineProvider({
|
|
|
859
1973
|
fields: [
|
|
860
1974
|
"codexPath",
|
|
861
1975
|
"baseUrl",
|
|
862
|
-
"
|
|
1976
|
+
"credentials",
|
|
863
1977
|
"env",
|
|
864
1978
|
"config",
|
|
865
1979
|
"options",
|
|
@@ -1159,7 +2273,7 @@ function parseContentsAnswer(entry, index) {
|
|
|
1159
2273
|
entry,
|
|
1160
2274
|
`contents answer at index ${index} must be a JSON object`
|
|
1161
2275
|
);
|
|
1162
|
-
const
|
|
2276
|
+
const url2 = readRequiredString(value.url, `answers[${index}].url`);
|
|
1163
2277
|
const content = readOptionalString(
|
|
1164
2278
|
value.content,
|
|
1165
2279
|
`answers[${index}].content`
|
|
@@ -1176,7 +2290,7 @@ function parseContentsAnswer(entry, index) {
|
|
|
1176
2290
|
);
|
|
1177
2291
|
}
|
|
1178
2292
|
return {
|
|
1179
|
-
url,
|
|
2293
|
+
url: url2,
|
|
1180
2294
|
...content !== void 0 ? { content } : {},
|
|
1181
2295
|
...summary !== void 0 ? { summary } : {},
|
|
1182
2296
|
...metadata !== void 0 ? { metadata } : {},
|
|
@@ -1291,7 +2405,7 @@ var customProvider = defineProvider({
|
|
|
1291
2405
|
|
|
1292
2406
|
// src/providers/exa.ts
|
|
1293
2407
|
import { Exa as ExaClient } from "exa-js";
|
|
1294
|
-
import { Type as
|
|
2408
|
+
import { Type as Type6 } from "typebox";
|
|
1295
2409
|
|
|
1296
2410
|
// src/execution-policy-defaults.ts
|
|
1297
2411
|
var DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
|
|
@@ -1656,9 +2770,9 @@ function normalizeError(error) {
|
|
|
1656
2770
|
}
|
|
1657
2771
|
|
|
1658
2772
|
// src/providers/exa.ts
|
|
1659
|
-
var exaSearchOptionsSchema =
|
|
2773
|
+
var exaSearchOptionsSchema = Type6.Object(
|
|
1660
2774
|
{
|
|
1661
|
-
type:
|
|
2775
|
+
type: Type6.Optional(
|
|
1662
2776
|
literalUnion(
|
|
1663
2777
|
[
|
|
1664
2778
|
"keyword",
|
|
@@ -1674,41 +2788,41 @@ var exaSearchOptionsSchema = Type5.Object(
|
|
|
1674
2788
|
{ description: "Exa search mode." }
|
|
1675
2789
|
)
|
|
1676
2790
|
),
|
|
1677
|
-
category:
|
|
1678
|
-
|
|
2791
|
+
category: Type6.Optional(
|
|
2792
|
+
Type6.String({
|
|
1679
2793
|
description: "Filter by category (e.g., 'company', 'research paper')."
|
|
1680
2794
|
})
|
|
1681
2795
|
),
|
|
1682
|
-
includeDomains:
|
|
1683
|
-
|
|
2796
|
+
includeDomains: Type6.Optional(
|
|
2797
|
+
Type6.Array(Type6.String(), {
|
|
1684
2798
|
description: "Restrict results to these domains."
|
|
1685
2799
|
})
|
|
1686
2800
|
),
|
|
1687
|
-
excludeDomains:
|
|
1688
|
-
|
|
2801
|
+
excludeDomains: Type6.Optional(
|
|
2802
|
+
Type6.Array(Type6.String(), { description: "Exclude these domains." })
|
|
1689
2803
|
),
|
|
1690
|
-
startPublishedDate:
|
|
1691
|
-
|
|
2804
|
+
startPublishedDate: Type6.Optional(
|
|
2805
|
+
Type6.String({
|
|
1692
2806
|
description: "ISO date string for earliest publish date."
|
|
1693
2807
|
})
|
|
1694
2808
|
),
|
|
1695
|
-
endPublishedDate:
|
|
1696
|
-
|
|
2809
|
+
endPublishedDate: Type6.Optional(
|
|
2810
|
+
Type6.String({ description: "ISO date string for latest publish date." })
|
|
1697
2811
|
),
|
|
1698
|
-
userLocation:
|
|
1699
|
-
|
|
2812
|
+
userLocation: Type6.Optional(
|
|
2813
|
+
Type6.Object(
|
|
1700
2814
|
{
|
|
1701
|
-
country:
|
|
1702
|
-
|
|
2815
|
+
country: Type6.Optional(
|
|
2816
|
+
Type6.String({ description: "Country hint for the user location." })
|
|
1703
2817
|
),
|
|
1704
|
-
region:
|
|
1705
|
-
|
|
2818
|
+
region: Type6.Optional(
|
|
2819
|
+
Type6.String({ description: "Region hint for the user location." })
|
|
1706
2820
|
),
|
|
1707
|
-
city:
|
|
1708
|
-
|
|
2821
|
+
city: Type6.Optional(
|
|
2822
|
+
Type6.String({ description: "City hint for the user location." })
|
|
1709
2823
|
),
|
|
1710
|
-
timezone:
|
|
1711
|
-
|
|
2824
|
+
timezone: Type6.Optional(
|
|
2825
|
+
Type6.String({
|
|
1712
2826
|
description: "Timezone hint for the user location."
|
|
1713
2827
|
})
|
|
1714
2828
|
)
|
|
@@ -1718,17 +2832,17 @@ var exaSearchOptionsSchema = Type5.Object(
|
|
|
1718
2832
|
}
|
|
1719
2833
|
)
|
|
1720
2834
|
),
|
|
1721
|
-
contents:
|
|
1722
|
-
|
|
2835
|
+
contents: Type6.Optional(
|
|
2836
|
+
Type6.Object(
|
|
1723
2837
|
{
|
|
1724
|
-
text:
|
|
1725
|
-
|
|
2838
|
+
text: Type6.Optional(
|
|
2839
|
+
Type6.Boolean({ description: "Include text content." })
|
|
1726
2840
|
),
|
|
1727
|
-
highlights:
|
|
1728
|
-
|
|
2841
|
+
highlights: Type6.Optional(
|
|
2842
|
+
Type6.Boolean({ description: "Include highlighted excerpts." })
|
|
1729
2843
|
),
|
|
1730
|
-
summary:
|
|
1731
|
-
|
|
2844
|
+
summary: Type6.Optional(
|
|
2845
|
+
Type6.Boolean({ description: "Include AI-generated summary." })
|
|
1732
2846
|
)
|
|
1733
2847
|
},
|
|
1734
2848
|
{ description: "What content to include in results." }
|
|
@@ -1751,7 +2865,7 @@ var exaImplementation = {
|
|
|
1751
2865
|
},
|
|
1752
2866
|
createTemplate() {
|
|
1753
2867
|
return {
|
|
1754
|
-
|
|
2868
|
+
credentials: { api: "EXA_API_KEY" },
|
|
1755
2869
|
options: {
|
|
1756
2870
|
search: {
|
|
1757
2871
|
type: "auto",
|
|
@@ -1763,7 +2877,7 @@ var exaImplementation = {
|
|
|
1763
2877
|
};
|
|
1764
2878
|
},
|
|
1765
2879
|
getCapabilityStatus(config) {
|
|
1766
|
-
return getApiKeyStatus(config?.
|
|
2880
|
+
return getApiKeyStatus(config?.credentials?.api);
|
|
1767
2881
|
},
|
|
1768
2882
|
async search(query2, maxResults, config, _context, searchOptions) {
|
|
1769
2883
|
const client = createClient2(config);
|
|
@@ -1791,16 +2905,16 @@ var exaImplementation = {
|
|
|
1791
2905
|
const results = response.results ?? [];
|
|
1792
2906
|
return {
|
|
1793
2907
|
provider: exaImplementation.id,
|
|
1794
|
-
answers: urls.map((
|
|
2908
|
+
answers: urls.map((url2, index) => {
|
|
1795
2909
|
const result = results[index];
|
|
1796
2910
|
if (!result) {
|
|
1797
2911
|
return {
|
|
1798
|
-
url,
|
|
2912
|
+
url: url2,
|
|
1799
2913
|
error: "No content returned for this URL."
|
|
1800
2914
|
};
|
|
1801
2915
|
}
|
|
1802
2916
|
return {
|
|
1803
|
-
url,
|
|
2917
|
+
url: url2,
|
|
1804
2918
|
...typeof result.text === "string" ? { content: result.text } : {},
|
|
1805
2919
|
...result.summary !== void 0 ? { summary: result.summary } : {},
|
|
1806
2920
|
metadata: result
|
|
@@ -1883,7 +2997,7 @@ var exaImplementation = {
|
|
|
1883
2997
|
}
|
|
1884
2998
|
};
|
|
1885
2999
|
function createClient2(config) {
|
|
1886
|
-
const apiKey = resolveConfigValue(config.
|
|
3000
|
+
const apiKey = resolveConfigValue(config.credentials?.api);
|
|
1887
3001
|
if (!apiKey) {
|
|
1888
3002
|
throw new Error("is missing an API key");
|
|
1889
3003
|
}
|
|
@@ -1895,7 +3009,7 @@ var exaProvider = defineProvider({
|
|
|
1895
3009
|
docsUrl: exaImplementation.docsUrl,
|
|
1896
3010
|
config: {
|
|
1897
3011
|
createTemplate: () => exaImplementation.createTemplate(),
|
|
1898
|
-
fields: ["
|
|
3012
|
+
fields: ["credentials", "baseUrl", "options", "settings"],
|
|
1899
3013
|
optionCapabilities: ["search"]
|
|
1900
3014
|
},
|
|
1901
3015
|
getCapabilityStatus: (config, cwd, tool) => exaImplementation.getCapabilityStatus(
|
|
@@ -1955,55 +3069,55 @@ var exaProvider = defineProvider({
|
|
|
1955
3069
|
|
|
1956
3070
|
// src/providers/firecrawl.ts
|
|
1957
3071
|
import FirecrawlClient from "@mendable/firecrawl-js";
|
|
1958
|
-
import { Type as
|
|
1959
|
-
var firecrawlSearchOptionsSchema =
|
|
3072
|
+
import { Type as Type7 } from "typebox";
|
|
3073
|
+
var firecrawlSearchOptionsSchema = Type7.Object(
|
|
1960
3074
|
{
|
|
1961
|
-
lang:
|
|
1962
|
-
|
|
3075
|
+
lang: Type7.Optional(
|
|
3076
|
+
Type7.String({
|
|
1963
3077
|
description: "Language code for search results (for example 'en')."
|
|
1964
3078
|
})
|
|
1965
3079
|
),
|
|
1966
|
-
country:
|
|
1967
|
-
|
|
3080
|
+
country: Type7.Optional(
|
|
3081
|
+
Type7.String({
|
|
1968
3082
|
description: "Country code for search results (for example 'us')."
|
|
1969
3083
|
})
|
|
1970
3084
|
),
|
|
1971
|
-
sources:
|
|
1972
|
-
|
|
3085
|
+
sources: Type7.Optional(
|
|
3086
|
+
Type7.Array(Type7.String(), {
|
|
1973
3087
|
description: "Search source groups to include."
|
|
1974
3088
|
})
|
|
1975
3089
|
),
|
|
1976
|
-
categories:
|
|
1977
|
-
|
|
3090
|
+
categories: Type7.Optional(
|
|
3091
|
+
Type7.Array(Type7.String(), {
|
|
1978
3092
|
description: "Search categories to include."
|
|
1979
3093
|
})
|
|
1980
3094
|
),
|
|
1981
|
-
location:
|
|
1982
|
-
|
|
3095
|
+
location: Type7.Optional(
|
|
3096
|
+
Type7.Object(
|
|
1983
3097
|
{
|
|
1984
|
-
country:
|
|
1985
|
-
region:
|
|
1986
|
-
city:
|
|
3098
|
+
country: Type7.Optional(Type7.String({ description: "Country hint." })),
|
|
3099
|
+
region: Type7.Optional(Type7.String({ description: "Region hint." })),
|
|
3100
|
+
city: Type7.Optional(Type7.String({ description: "City hint." }))
|
|
1987
3101
|
},
|
|
1988
3102
|
{ description: "Location hint for search." }
|
|
1989
3103
|
)
|
|
1990
3104
|
),
|
|
1991
|
-
timeout:
|
|
1992
|
-
|
|
3105
|
+
timeout: Type7.Optional(
|
|
3106
|
+
Type7.Integer({
|
|
1993
3107
|
minimum: 0,
|
|
1994
3108
|
description: "Request timeout in milliseconds."
|
|
1995
3109
|
})
|
|
1996
3110
|
),
|
|
1997
|
-
scrapeOptions:
|
|
1998
|
-
|
|
3111
|
+
scrapeOptions: Type7.Optional(
|
|
3112
|
+
Type7.Object(
|
|
1999
3113
|
{
|
|
2000
|
-
formats:
|
|
2001
|
-
|
|
3114
|
+
formats: Type7.Optional(
|
|
3115
|
+
Type7.Array(literalUnion(["markdown", "html", "rawHtml"]), {
|
|
2002
3116
|
description: "Output formats."
|
|
2003
3117
|
})
|
|
2004
3118
|
),
|
|
2005
|
-
onlyMainContent:
|
|
2006
|
-
|
|
3119
|
+
onlyMainContent: Type7.Optional(
|
|
3120
|
+
Type7.Boolean({ description: "Extract only the main content." })
|
|
2007
3121
|
)
|
|
2008
3122
|
},
|
|
2009
3123
|
{
|
|
@@ -2014,48 +3128,48 @@ var firecrawlSearchOptionsSchema = Type6.Object(
|
|
|
2014
3128
|
},
|
|
2015
3129
|
{ description: "Firecrawl search options." }
|
|
2016
3130
|
);
|
|
2017
|
-
var firecrawlScrapeOptionsSchema =
|
|
3131
|
+
var firecrawlScrapeOptionsSchema = Type7.Object(
|
|
2018
3132
|
{
|
|
2019
|
-
formats:
|
|
2020
|
-
|
|
3133
|
+
formats: Type7.Optional(
|
|
3134
|
+
Type7.Array(literalUnion(["markdown", "html", "rawHtml"]), {
|
|
2021
3135
|
description: "Output formats for scraping."
|
|
2022
3136
|
})
|
|
2023
3137
|
),
|
|
2024
|
-
onlyMainContent:
|
|
2025
|
-
|
|
3138
|
+
onlyMainContent: Type7.Optional(
|
|
3139
|
+
Type7.Boolean({ description: "Extract only the main content." })
|
|
2026
3140
|
),
|
|
2027
|
-
includeTags:
|
|
2028
|
-
|
|
3141
|
+
includeTags: Type7.Optional(
|
|
3142
|
+
Type7.Array(Type7.String(), { description: "CSS selectors to include." })
|
|
2029
3143
|
),
|
|
2030
|
-
excludeTags:
|
|
2031
|
-
|
|
3144
|
+
excludeTags: Type7.Optional(
|
|
3145
|
+
Type7.Array(Type7.String(), { description: "CSS selectors to exclude." })
|
|
2032
3146
|
),
|
|
2033
|
-
waitFor:
|
|
2034
|
-
|
|
3147
|
+
waitFor: Type7.Optional(
|
|
3148
|
+
Type7.Integer({
|
|
2035
3149
|
minimum: 0,
|
|
2036
3150
|
description: "Milliseconds to wait before scraping."
|
|
2037
3151
|
})
|
|
2038
3152
|
),
|
|
2039
|
-
headers:
|
|
2040
|
-
|
|
3153
|
+
headers: Type7.Optional(
|
|
3154
|
+
Type7.Record(Type7.String(), Type7.String(), {
|
|
2041
3155
|
description: "Headers to send when scraping."
|
|
2042
3156
|
})
|
|
2043
3157
|
),
|
|
2044
|
-
location:
|
|
2045
|
-
|
|
3158
|
+
location: Type7.Optional(
|
|
3159
|
+
Type7.Object(
|
|
2046
3160
|
{
|
|
2047
|
-
country:
|
|
2048
|
-
region:
|
|
2049
|
-
city:
|
|
3161
|
+
country: Type7.Optional(Type7.String({ description: "Country hint." })),
|
|
3162
|
+
region: Type7.Optional(Type7.String({ description: "Region hint." })),
|
|
3163
|
+
city: Type7.Optional(Type7.String({ description: "City hint." }))
|
|
2050
3164
|
},
|
|
2051
3165
|
{ description: "Location hint for scraping." }
|
|
2052
3166
|
)
|
|
2053
3167
|
),
|
|
2054
|
-
mobile:
|
|
2055
|
-
|
|
3168
|
+
mobile: Type7.Optional(
|
|
3169
|
+
Type7.Boolean({ description: "Use a mobile browser profile." })
|
|
2056
3170
|
),
|
|
2057
|
-
proxy:
|
|
2058
|
-
|
|
3171
|
+
proxy: Type7.Optional(
|
|
3172
|
+
Type7.String({
|
|
2059
3173
|
description: "Proxy mode passed through to the Firecrawl SDK."
|
|
2060
3174
|
})
|
|
2061
3175
|
)
|
|
@@ -2078,7 +3192,7 @@ var firecrawlImplementation = {
|
|
|
2078
3192
|
},
|
|
2079
3193
|
createTemplate() {
|
|
2080
3194
|
return {
|
|
2081
|
-
|
|
3195
|
+
credentials: { api: "FIRECRAWL_API_KEY" },
|
|
2082
3196
|
options: {
|
|
2083
3197
|
scrape: {
|
|
2084
3198
|
formats: ["markdown"],
|
|
@@ -2088,7 +3202,7 @@ var firecrawlImplementation = {
|
|
|
2088
3202
|
};
|
|
2089
3203
|
},
|
|
2090
3204
|
getCapabilityStatus(config) {
|
|
2091
|
-
return getApiKeyStatus(config?.
|
|
3205
|
+
return getApiKeyStatus(config?.credentials?.api);
|
|
2092
3206
|
},
|
|
2093
3207
|
async search(query2, maxResults, config, _context, options) {
|
|
2094
3208
|
const client = createClient3(config);
|
|
@@ -2115,23 +3229,23 @@ var firecrawlImplementation = {
|
|
|
2115
3229
|
return {
|
|
2116
3230
|
provider: firecrawlImplementation.id,
|
|
2117
3231
|
answers: await Promise.all(
|
|
2118
|
-
urls.map(async (
|
|
3232
|
+
urls.map(async (url2) => {
|
|
2119
3233
|
try {
|
|
2120
|
-
const document = await client.scrape(
|
|
3234
|
+
const document = await client.scrape(url2, scrapeOptions);
|
|
2121
3235
|
const content = getDocumentContent(document);
|
|
2122
3236
|
return content ? {
|
|
2123
|
-
url,
|
|
3237
|
+
url: url2,
|
|
2124
3238
|
content,
|
|
2125
3239
|
...document.metadata ? {
|
|
2126
3240
|
metadata: document.metadata
|
|
2127
3241
|
} : {}
|
|
2128
3242
|
} : {
|
|
2129
|
-
url,
|
|
3243
|
+
url: url2,
|
|
2130
3244
|
error: "No content returned for this URL."
|
|
2131
3245
|
};
|
|
2132
3246
|
} catch (error) {
|
|
2133
3247
|
return {
|
|
2134
|
-
url,
|
|
3248
|
+
url: url2,
|
|
2135
3249
|
error: error instanceof Error ? error.message : String(error)
|
|
2136
3250
|
};
|
|
2137
3251
|
}
|
|
@@ -2141,7 +3255,7 @@ var firecrawlImplementation = {
|
|
|
2141
3255
|
}
|
|
2142
3256
|
};
|
|
2143
3257
|
function createClient3(config) {
|
|
2144
|
-
const apiKey = resolveConfigValue(config.
|
|
3258
|
+
const apiKey = resolveConfigValue(config.credentials?.api);
|
|
2145
3259
|
if (!apiKey) {
|
|
2146
3260
|
throw new Error("is missing an API key");
|
|
2147
3261
|
}
|
|
@@ -2161,8 +3275,8 @@ function toSearchResult(source, value) {
|
|
|
2161
3275
|
return null;
|
|
2162
3276
|
}
|
|
2163
3277
|
const metadata = asRecord(entry.metadata);
|
|
2164
|
-
const
|
|
2165
|
-
const title = readString2(entry.title) ?? readString2(metadata?.title) ??
|
|
3278
|
+
const url2 = readString2(entry.url) ?? readString2(metadata?.sourceURL) ?? readString2(entry.imageUrl) ?? "";
|
|
3279
|
+
const title = readString2(entry.title) ?? readString2(metadata?.title) ?? url2;
|
|
2166
3280
|
const snippet = trimSnippet(
|
|
2167
3281
|
readString2(entry.description) ?? readString2(entry.snippet) ?? readString2(entry.markdown) ?? readString2(metadata?.description) ?? ""
|
|
2168
3282
|
);
|
|
@@ -2176,7 +3290,7 @@ function toSearchResult(source, value) {
|
|
|
2176
3290
|
};
|
|
2177
3291
|
return {
|
|
2178
3292
|
title: title || "Untitled",
|
|
2179
|
-
url,
|
|
3293
|
+
url: url2,
|
|
2180
3294
|
snippet,
|
|
2181
3295
|
metadata: Object.keys(resultMetadata).length > 1 ? resultMetadata : void 0
|
|
2182
3296
|
};
|
|
@@ -2205,7 +3319,7 @@ var firecrawlProvider = defineProvider({
|
|
|
2205
3319
|
docsUrl: firecrawlImplementation.docsUrl,
|
|
2206
3320
|
config: {
|
|
2207
3321
|
createTemplate: () => firecrawlImplementation.createTemplate(),
|
|
2208
|
-
fields: ["
|
|
3322
|
+
fields: ["credentials", "baseUrl", "options", "settings"]
|
|
2209
3323
|
},
|
|
2210
3324
|
getCapabilityStatus: (config, cwd, tool) => firecrawlImplementation.getCapabilityStatus(
|
|
2211
3325
|
config,
|
|
@@ -2242,29 +3356,29 @@ var firecrawlProvider = defineProvider({
|
|
|
2242
3356
|
|
|
2243
3357
|
// src/providers/gemini.ts
|
|
2244
3358
|
import { GoogleGenAI } from "@google/genai";
|
|
2245
|
-
import { Type as
|
|
3359
|
+
import { Type as Type8 } from "typebox";
|
|
2246
3360
|
var DEFAULT_SEARCH_MODEL = "gemini-2.5-flash";
|
|
2247
3361
|
var DEFAULT_ANSWER_MODEL = "gemini-2.5-flash";
|
|
2248
3362
|
var DEFAULT_RESEARCH_AGENT = "deep-research-pro-preview-12-2025";
|
|
2249
|
-
var geminiGenerationConfigSchema =
|
|
3363
|
+
var geminiGenerationConfigSchema = Type8.Object(
|
|
2250
3364
|
{
|
|
2251
|
-
temperature:
|
|
2252
|
-
|
|
3365
|
+
temperature: Type8.Optional(
|
|
3366
|
+
Type8.Number({ description: "Sampling temperature." })
|
|
2253
3367
|
),
|
|
2254
|
-
topP:
|
|
2255
|
-
topK:
|
|
2256
|
-
|
|
3368
|
+
topP: Type8.Optional(Type8.Number({ description: "Top-p sampling value." })),
|
|
3369
|
+
topK: Type8.Optional(
|
|
3370
|
+
Type8.Integer({ minimum: 0, description: "Top-k sampling value." })
|
|
2257
3371
|
),
|
|
2258
|
-
candidateCount:
|
|
2259
|
-
|
|
3372
|
+
candidateCount: Type8.Optional(
|
|
3373
|
+
Type8.Integer({
|
|
2260
3374
|
minimum: 1,
|
|
2261
3375
|
description: "Number of candidates to generate."
|
|
2262
3376
|
})
|
|
2263
3377
|
),
|
|
2264
|
-
maxOutputTokens:
|
|
2265
|
-
|
|
3378
|
+
maxOutputTokens: Type8.Optional(
|
|
3379
|
+
Type8.Integer({ minimum: 1, description: "Maximum output tokens." })
|
|
2266
3380
|
),
|
|
2267
|
-
tool_choice:
|
|
3381
|
+
tool_choice: Type8.Optional(
|
|
2268
3382
|
literalUnion(["auto", "any", "none"], {
|
|
2269
3383
|
description: "Tool choice mode for Gemini search interactions."
|
|
2270
3384
|
})
|
|
@@ -2272,35 +3386,35 @@ var geminiGenerationConfigSchema = Type7.Object(
|
|
|
2272
3386
|
},
|
|
2273
3387
|
{ description: "Gemini generation configuration." }
|
|
2274
3388
|
);
|
|
2275
|
-
var geminiAnswerConfigSchema =
|
|
3389
|
+
var geminiAnswerConfigSchema = Type8.Object(
|
|
2276
3390
|
{
|
|
2277
|
-
labels:
|
|
2278
|
-
|
|
3391
|
+
labels: Type8.Optional(
|
|
3392
|
+
Type8.Record(Type8.String(), Type8.String(), {
|
|
2279
3393
|
description: "Request labels to attach to the Gemini call."
|
|
2280
3394
|
})
|
|
2281
3395
|
),
|
|
2282
|
-
temperature:
|
|
2283
|
-
|
|
3396
|
+
temperature: Type8.Optional(
|
|
3397
|
+
Type8.Number({ description: "Sampling temperature." })
|
|
2284
3398
|
),
|
|
2285
|
-
topP:
|
|
2286
|
-
topK:
|
|
2287
|
-
|
|
3399
|
+
topP: Type8.Optional(Type8.Number({ description: "Top-p sampling value." })),
|
|
3400
|
+
topK: Type8.Optional(
|
|
3401
|
+
Type8.Integer({ minimum: 0, description: "Top-k sampling value." })
|
|
2288
3402
|
),
|
|
2289
|
-
candidateCount:
|
|
2290
|
-
|
|
3403
|
+
candidateCount: Type8.Optional(
|
|
3404
|
+
Type8.Integer({
|
|
2291
3405
|
minimum: 1,
|
|
2292
3406
|
description: "Number of candidates to generate."
|
|
2293
3407
|
})
|
|
2294
3408
|
),
|
|
2295
|
-
maxOutputTokens:
|
|
2296
|
-
|
|
3409
|
+
maxOutputTokens: Type8.Optional(
|
|
3410
|
+
Type8.Integer({ minimum: 1, description: "Maximum output tokens." })
|
|
2297
3411
|
)
|
|
2298
3412
|
},
|
|
2299
3413
|
{ description: "Gemini generate-content config overrides." }
|
|
2300
3414
|
);
|
|
2301
|
-
var geminiAgentConfigSchema =
|
|
3415
|
+
var geminiAgentConfigSchema = Type8.Object(
|
|
2302
3416
|
{
|
|
2303
|
-
thinking_summaries:
|
|
3417
|
+
thinking_summaries: Type8.Optional(
|
|
2304
3418
|
literalUnion(["auto", "none"], {
|
|
2305
3419
|
description: "Whether to include thought summaries in the response."
|
|
2306
3420
|
})
|
|
@@ -2311,31 +3425,31 @@ var geminiAgentConfigSchema = Type7.Object(
|
|
|
2311
3425
|
description: "Safe Gemini deep-research agent configuration. The provider adds the required type field."
|
|
2312
3426
|
}
|
|
2313
3427
|
);
|
|
2314
|
-
var geminiSearchOptionsSchema =
|
|
3428
|
+
var geminiSearchOptionsSchema = Type8.Object(
|
|
2315
3429
|
{
|
|
2316
|
-
model:
|
|
2317
|
-
|
|
3430
|
+
model: Type8.Optional(
|
|
3431
|
+
Type8.String({
|
|
2318
3432
|
description: "Gemini model for search (for example 'gemini-2.5-flash')."
|
|
2319
3433
|
})
|
|
2320
3434
|
),
|
|
2321
|
-
generation_config:
|
|
3435
|
+
generation_config: Type8.Optional(geminiGenerationConfigSchema)
|
|
2322
3436
|
},
|
|
2323
3437
|
{ description: "Gemini search options." }
|
|
2324
3438
|
);
|
|
2325
|
-
var geminiAnswerOptionsSchema =
|
|
3439
|
+
var geminiAnswerOptionsSchema = Type8.Object(
|
|
2326
3440
|
{
|
|
2327
|
-
model:
|
|
2328
|
-
|
|
3441
|
+
model: Type8.Optional(
|
|
3442
|
+
Type8.String({
|
|
2329
3443
|
description: "Gemini model for answers (for example 'gemini-2.5-flash')."
|
|
2330
3444
|
})
|
|
2331
3445
|
),
|
|
2332
|
-
config:
|
|
3446
|
+
config: Type8.Optional(geminiAnswerConfigSchema)
|
|
2333
3447
|
},
|
|
2334
3448
|
{ description: "Gemini answer options." }
|
|
2335
3449
|
);
|
|
2336
|
-
var geminiResearchOptionsSchema =
|
|
3450
|
+
var geminiResearchOptionsSchema = Type8.Object(
|
|
2337
3451
|
{
|
|
2338
|
-
agent_config:
|
|
3452
|
+
agent_config: Type8.Optional(geminiAgentConfigSchema)
|
|
2339
3453
|
},
|
|
2340
3454
|
{ additionalProperties: false, description: "Gemini research options." }
|
|
2341
3455
|
);
|
|
@@ -2357,7 +3471,7 @@ var geminiImplementation = {
|
|
|
2357
3471
|
},
|
|
2358
3472
|
createTemplate() {
|
|
2359
3473
|
return {
|
|
2360
|
-
|
|
3474
|
+
credentials: { api: "GOOGLE_API_KEY" },
|
|
2361
3475
|
options: {
|
|
2362
3476
|
searchModel: DEFAULT_SEARCH_MODEL,
|
|
2363
3477
|
answerModel: DEFAULT_ANSWER_MODEL,
|
|
@@ -2366,7 +3480,7 @@ var geminiImplementation = {
|
|
|
2366
3480
|
};
|
|
2367
3481
|
},
|
|
2368
3482
|
getCapabilityStatus(config) {
|
|
2369
|
-
return getApiKeyStatus(config?.
|
|
3483
|
+
return getApiKeyStatus(config?.credentials?.api);
|
|
2370
3484
|
},
|
|
2371
3485
|
async search(query2, maxResults, config, context, options) {
|
|
2372
3486
|
const ai = this.createClient(config);
|
|
@@ -2505,7 +3619,7 @@ var geminiImplementation = {
|
|
|
2505
3619
|
return status === "in_progress" ? { status: "in_progress" } : { status: "in_progress", statusText: status };
|
|
2506
3620
|
},
|
|
2507
3621
|
createClient(config) {
|
|
2508
|
-
const apiKey = resolveConfigValue(config.
|
|
3622
|
+
const apiKey = resolveConfigValue(config.credentials?.api);
|
|
2509
3623
|
if (!apiKey) {
|
|
2510
3624
|
throw new Error("is missing an API key");
|
|
2511
3625
|
}
|
|
@@ -2649,11 +3763,11 @@ function normalizeHtmlAttributeValue(value) {
|
|
|
2649
3763
|
return readNonEmptyString3(value);
|
|
2650
3764
|
}
|
|
2651
3765
|
function normalizeSearchUrl(value) {
|
|
2652
|
-
const
|
|
2653
|
-
if (!
|
|
3766
|
+
const url2 = normalizeHtmlAttributeValue(value);
|
|
3767
|
+
if (!url2 || url2.startsWith("#") || /^javascript:/i.test(url2)) {
|
|
2654
3768
|
return void 0;
|
|
2655
3769
|
}
|
|
2656
|
-
return
|
|
3770
|
+
return url2;
|
|
2657
3771
|
}
|
|
2658
3772
|
function decodeHtmlEntities(text) {
|
|
2659
3773
|
return text.replace(
|
|
@@ -2688,20 +3802,20 @@ function extractGroundingSources(chunks) {
|
|
|
2688
3802
|
return sources;
|
|
2689
3803
|
}
|
|
2690
3804
|
for (const chunk of chunks) {
|
|
2691
|
-
const
|
|
2692
|
-
if (!
|
|
2693
|
-
const rawUrl = typeof
|
|
3805
|
+
const web2 = typeof chunk === "object" && chunk !== null && "web" in chunk && typeof chunk.web === "object" && chunk.web !== null ? chunk.web : void 0;
|
|
3806
|
+
if (!web2) continue;
|
|
3807
|
+
const rawUrl = typeof web2.uri === "string" ? web2.uri : "";
|
|
2694
3808
|
const title = formatGroundingSourceTitle(
|
|
2695
|
-
typeof
|
|
3809
|
+
typeof web2.title === "string" ? web2.title : rawUrl,
|
|
2696
3810
|
rawUrl
|
|
2697
3811
|
);
|
|
2698
|
-
const
|
|
2699
|
-
const key = [title.toLowerCase(),
|
|
3812
|
+
const url2 = formatGroundingSourceUrl(rawUrl);
|
|
3813
|
+
const key = [title.toLowerCase(), url2.toLowerCase()].join("::");
|
|
2700
3814
|
if (seen.has(key)) continue;
|
|
2701
3815
|
seen.add(key);
|
|
2702
3816
|
sources.push({
|
|
2703
3817
|
title,
|
|
2704
|
-
url
|
|
3818
|
+
url: url2
|
|
2705
3819
|
});
|
|
2706
3820
|
if (sources.length >= maxSources) {
|
|
2707
3821
|
break;
|
|
@@ -2724,32 +3838,32 @@ function formatInteractionOutputs(outputs) {
|
|
|
2724
3838
|
}
|
|
2725
3839
|
return lines.join("\n\n").trim();
|
|
2726
3840
|
}
|
|
2727
|
-
function formatGroundingSourceTitle(title,
|
|
3841
|
+
function formatGroundingSourceTitle(title, url2) {
|
|
2728
3842
|
const trimmedTitle = title?.trim();
|
|
2729
3843
|
if (trimmedTitle) {
|
|
2730
3844
|
return trimmedTitle;
|
|
2731
3845
|
}
|
|
2732
|
-
if (
|
|
3846
|
+
if (url2) {
|
|
2733
3847
|
try {
|
|
2734
|
-
return new URL(
|
|
3848
|
+
return new URL(url2).hostname;
|
|
2735
3849
|
} catch {
|
|
2736
|
-
return
|
|
3850
|
+
return url2;
|
|
2737
3851
|
}
|
|
2738
3852
|
}
|
|
2739
3853
|
return "Untitled";
|
|
2740
3854
|
}
|
|
2741
|
-
function formatGroundingSourceUrl(
|
|
2742
|
-
if (!
|
|
3855
|
+
function formatGroundingSourceUrl(url2) {
|
|
3856
|
+
if (!url2) {
|
|
2743
3857
|
return "";
|
|
2744
3858
|
}
|
|
2745
|
-
if (isGoogleGroundingRedirect(
|
|
3859
|
+
if (isGoogleGroundingRedirect(url2)) {
|
|
2746
3860
|
return "";
|
|
2747
3861
|
}
|
|
2748
|
-
return
|
|
3862
|
+
return url2;
|
|
2749
3863
|
}
|
|
2750
|
-
function isGoogleGroundingRedirect(
|
|
3864
|
+
function isGoogleGroundingRedirect(url2) {
|
|
2751
3865
|
try {
|
|
2752
|
-
const parsed = new URL(
|
|
3866
|
+
const parsed = new URL(url2);
|
|
2753
3867
|
return parsed.hostname === "vertexaisearch.cloud.google.com" && parsed.pathname.startsWith("/grounding-api-redirect/");
|
|
2754
3868
|
} catch {
|
|
2755
3869
|
return false;
|
|
@@ -2870,22 +3984,22 @@ function isBuiltInToolChoiceError(error) {
|
|
|
2870
3984
|
}
|
|
2871
3985
|
return false;
|
|
2872
3986
|
}
|
|
2873
|
-
async function resolveGoogleSearchUrl(
|
|
2874
|
-
if (!
|
|
3987
|
+
async function resolveGoogleSearchUrl(url2, signal) {
|
|
3988
|
+
if (!url2) {
|
|
2875
3989
|
return void 0;
|
|
2876
3990
|
}
|
|
2877
|
-
if (!isGoogleGroundingRedirect(
|
|
2878
|
-
return
|
|
3991
|
+
if (!isGoogleGroundingRedirect(url2)) {
|
|
3992
|
+
return url2;
|
|
2879
3993
|
}
|
|
2880
3994
|
try {
|
|
2881
|
-
const response = await fetch(
|
|
3995
|
+
const response = await fetch(url2, {
|
|
2882
3996
|
method: "HEAD",
|
|
2883
3997
|
redirect: "manual",
|
|
2884
3998
|
signal
|
|
2885
3999
|
});
|
|
2886
|
-
return response.headers.get("location") ||
|
|
4000
|
+
return response.headers.get("location") || url2;
|
|
2887
4001
|
} catch {
|
|
2888
|
-
return
|
|
4002
|
+
return url2;
|
|
2889
4003
|
}
|
|
2890
4004
|
}
|
|
2891
4005
|
function buildGeminiSearchRequest(query2, defaultModel, options) {
|
|
@@ -2993,7 +4107,7 @@ var geminiProvider = defineProvider({
|
|
|
2993
4107
|
docsUrl: geminiImplementation.docsUrl,
|
|
2994
4108
|
config: {
|
|
2995
4109
|
createTemplate: () => geminiImplementation.createTemplate(),
|
|
2996
|
-
fields: ["
|
|
4110
|
+
fields: ["credentials", "options", "settings"]
|
|
2997
4111
|
},
|
|
2998
4112
|
getCapabilityStatus: (config, cwd, tool) => geminiImplementation.getCapabilityStatus(
|
|
2999
4113
|
config,
|
|
@@ -3043,46 +4157,46 @@ var geminiProvider = defineProvider({
|
|
|
3043
4157
|
import {
|
|
3044
4158
|
LinkupClient
|
|
3045
4159
|
} from "linkup-sdk";
|
|
3046
|
-
import { Type as
|
|
3047
|
-
var linkupSearchOptionsSchema =
|
|
4160
|
+
import { Type as Type9 } from "typebox";
|
|
4161
|
+
var linkupSearchOptionsSchema = Type9.Object(
|
|
3048
4162
|
{
|
|
3049
|
-
depth:
|
|
4163
|
+
depth: Type9.Optional(
|
|
3050
4164
|
literalUnion(["standard", "deep"], {
|
|
3051
4165
|
description: "Search depth. 'deep' is slower but more thorough."
|
|
3052
4166
|
})
|
|
3053
4167
|
),
|
|
3054
|
-
includeImages:
|
|
3055
|
-
|
|
4168
|
+
includeImages: Type9.Optional(
|
|
4169
|
+
Type9.Boolean({ description: "Include images in search results." })
|
|
3056
4170
|
),
|
|
3057
|
-
includeDomains:
|
|
3058
|
-
|
|
4171
|
+
includeDomains: Type9.Optional(
|
|
4172
|
+
Type9.Array(Type9.String(), {
|
|
3059
4173
|
description: "Restrict results to these domains."
|
|
3060
4174
|
})
|
|
3061
4175
|
),
|
|
3062
|
-
excludeDomains:
|
|
3063
|
-
|
|
4176
|
+
excludeDomains: Type9.Optional(
|
|
4177
|
+
Type9.Array(Type9.String(), { description: "Exclude these domains." })
|
|
3064
4178
|
),
|
|
3065
|
-
fromDate:
|
|
3066
|
-
|
|
4179
|
+
fromDate: Type9.Optional(
|
|
4180
|
+
Type9.String({ description: "ISO date string for earliest result date." })
|
|
3067
4181
|
),
|
|
3068
|
-
toDate:
|
|
3069
|
-
|
|
4182
|
+
toDate: Type9.Optional(
|
|
4183
|
+
Type9.String({ description: "ISO date string for latest result date." })
|
|
3070
4184
|
)
|
|
3071
4185
|
},
|
|
3072
4186
|
{ description: "Linkup search options." }
|
|
3073
4187
|
);
|
|
3074
|
-
var linkupContentsOptionsSchema =
|
|
4188
|
+
var linkupContentsOptionsSchema = Type9.Object(
|
|
3075
4189
|
{
|
|
3076
|
-
renderJs:
|
|
3077
|
-
|
|
4190
|
+
renderJs: Type9.Optional(
|
|
4191
|
+
Type9.Boolean({
|
|
3078
4192
|
description: "Render JavaScript before extracting content."
|
|
3079
4193
|
})
|
|
3080
4194
|
),
|
|
3081
|
-
includeRawHtml:
|
|
3082
|
-
|
|
4195
|
+
includeRawHtml: Type9.Optional(
|
|
4196
|
+
Type9.Boolean({ description: "Include raw HTML in the response." })
|
|
3083
4197
|
),
|
|
3084
|
-
extractImages:
|
|
3085
|
-
|
|
4198
|
+
extractImages: Type9.Optional(
|
|
4199
|
+
Type9.Boolean({ description: "Extract images from the page." })
|
|
3086
4200
|
)
|
|
3087
4201
|
},
|
|
3088
4202
|
{ description: "Linkup fetch options." }
|
|
@@ -3103,11 +4217,11 @@ var linkupImplementation = {
|
|
|
3103
4217
|
},
|
|
3104
4218
|
createTemplate() {
|
|
3105
4219
|
return {
|
|
3106
|
-
|
|
4220
|
+
credentials: { api: "LINKUP_API_KEY" }
|
|
3107
4221
|
};
|
|
3108
4222
|
},
|
|
3109
4223
|
getCapabilityStatus(config) {
|
|
3110
|
-
return getApiKeyStatus(config?.
|
|
4224
|
+
return getApiKeyStatus(config?.credentials?.api);
|
|
3111
4225
|
},
|
|
3112
4226
|
async search(query2, maxResults, config, _context, options) {
|
|
3113
4227
|
const client = createClient4(config);
|
|
@@ -3129,24 +4243,24 @@ var linkupImplementation = {
|
|
|
3129
4243
|
return {
|
|
3130
4244
|
provider: linkupImplementation.id,
|
|
3131
4245
|
answers: await Promise.all(
|
|
3132
|
-
urls.map(async (
|
|
4246
|
+
urls.map(async (url2) => {
|
|
3133
4247
|
try {
|
|
3134
4248
|
const response = await client.fetch(
|
|
3135
|
-
buildFetchParams(
|
|
4249
|
+
buildFetchParams(url2, {
|
|
3136
4250
|
...defaults,
|
|
3137
4251
|
...options ?? {}
|
|
3138
4252
|
})
|
|
3139
4253
|
);
|
|
3140
4254
|
return response.markdown ? {
|
|
3141
|
-
url,
|
|
4255
|
+
url: url2,
|
|
3142
4256
|
content: response.markdown
|
|
3143
4257
|
} : {
|
|
3144
|
-
url,
|
|
4258
|
+
url: url2,
|
|
3145
4259
|
error: "No content returned for this URL."
|
|
3146
4260
|
};
|
|
3147
4261
|
} catch (error) {
|
|
3148
4262
|
return {
|
|
3149
|
-
url,
|
|
4263
|
+
url: url2,
|
|
3150
4264
|
error: error instanceof Error ? error.message : String(error)
|
|
3151
4265
|
};
|
|
3152
4266
|
}
|
|
@@ -3185,20 +4299,20 @@ function buildSearchParams(query2, maxResults, options) {
|
|
|
3185
4299
|
...searchOptions.toDate !== void 0 ? { toDate: toDate(searchOptions.toDate, "toDate") } : {}
|
|
3186
4300
|
};
|
|
3187
4301
|
}
|
|
3188
|
-
function buildFetchParams(
|
|
4302
|
+
function buildFetchParams(url2, options) {
|
|
3189
4303
|
const fetchOptions = options;
|
|
3190
4304
|
if (fetchOptions.url !== void 0) {
|
|
3191
4305
|
throw new Error("Linkup fetch options cannot override the managed URL.");
|
|
3192
4306
|
}
|
|
3193
4307
|
return {
|
|
3194
|
-
url,
|
|
4308
|
+
url: url2,
|
|
3195
4309
|
...fetchOptions.renderJs !== void 0 ? { renderJs: fetchOptions.renderJs } : {},
|
|
3196
4310
|
...fetchOptions.includeRawHtml !== void 0 ? { includeRawHtml: fetchOptions.includeRawHtml } : {},
|
|
3197
4311
|
...fetchOptions.extractImages !== void 0 ? { extractImages: fetchOptions.extractImages } : {}
|
|
3198
4312
|
};
|
|
3199
4313
|
}
|
|
3200
4314
|
function createClient4(config) {
|
|
3201
|
-
const apiKey = resolveConfigValue(config.
|
|
4315
|
+
const apiKey = resolveConfigValue(config.credentials?.api);
|
|
3202
4316
|
if (!apiKey) {
|
|
3203
4317
|
throw new Error("is missing an API key");
|
|
3204
4318
|
}
|
|
@@ -3212,8 +4326,8 @@ function toSearchResult2(value) {
|
|
|
3212
4326
|
if (!entry) {
|
|
3213
4327
|
return null;
|
|
3214
4328
|
}
|
|
3215
|
-
const
|
|
3216
|
-
const title = readString3(entry.name) ?? (
|
|
4329
|
+
const url2 = readString3(entry.url) ?? "";
|
|
4330
|
+
const title = readString3(entry.name) ?? (url2 || "Untitled");
|
|
3217
4331
|
const type = readString3(entry.type);
|
|
3218
4332
|
const favicon = readString3(entry.favicon);
|
|
3219
4333
|
const snippet = type === "text" ? trimSnippet(readString3(entry.content) ?? "") : "";
|
|
@@ -3223,7 +4337,7 @@ function toSearchResult2(value) {
|
|
|
3223
4337
|
};
|
|
3224
4338
|
return {
|
|
3225
4339
|
title,
|
|
3226
|
-
url,
|
|
4340
|
+
url: url2,
|
|
3227
4341
|
snippet,
|
|
3228
4342
|
metadata: Object.keys(metadata).length > 0 ? metadata : void 0
|
|
3229
4343
|
};
|
|
@@ -3249,7 +4363,7 @@ var linkupProvider = defineProvider({
|
|
|
3249
4363
|
docsUrl: linkupImplementation.docsUrl,
|
|
3250
4364
|
config: {
|
|
3251
4365
|
createTemplate: () => linkupImplementation.createTemplate(),
|
|
3252
|
-
fields: ["
|
|
4366
|
+
fields: ["credentials", "baseUrl", "options", "settings"]
|
|
3253
4367
|
},
|
|
3254
4368
|
getCapabilityStatus: (config, cwd, tool) => linkupImplementation.getCapabilityStatus(
|
|
3255
4369
|
config,
|
|
@@ -3285,7 +4399,7 @@ var linkupProvider = defineProvider({
|
|
|
3285
4399
|
});
|
|
3286
4400
|
|
|
3287
4401
|
// src/providers/ollama.ts
|
|
3288
|
-
var
|
|
4402
|
+
var DEFAULT_BASE_URL2 = "https://ollama.com";
|
|
3289
4403
|
var WEB_SEARCH_PATH = "/api/web_search";
|
|
3290
4404
|
var WEB_FETCH_PATH = "/api/web_fetch";
|
|
3291
4405
|
var ollamaProvider = defineProvider({
|
|
@@ -3295,13 +4409,13 @@ var ollamaProvider = defineProvider({
|
|
|
3295
4409
|
config: {
|
|
3296
4410
|
createTemplate() {
|
|
3297
4411
|
return {
|
|
3298
|
-
|
|
4412
|
+
credentials: { api: "OLLAMA_API_KEY" }
|
|
3299
4413
|
};
|
|
3300
4414
|
},
|
|
3301
|
-
fields: ["
|
|
4415
|
+
fields: ["credentials", "baseUrl", "settings"]
|
|
3302
4416
|
},
|
|
3303
4417
|
getCapabilityStatus(config) {
|
|
3304
|
-
return getApiKeyStatus(config?.
|
|
4418
|
+
return getApiKeyStatus(config?.credentials?.api);
|
|
3305
4419
|
},
|
|
3306
4420
|
capabilities: {
|
|
3307
4421
|
search: defineCapability({
|
|
@@ -3355,19 +4469,19 @@ async function fetchOllamaContents(urls, config, context) {
|
|
|
3355
4469
|
return {
|
|
3356
4470
|
provider: ollamaProvider.id,
|
|
3357
4471
|
answers: await Promise.all(
|
|
3358
|
-
urls.map(async (
|
|
4472
|
+
urls.map(async (url2) => {
|
|
3359
4473
|
try {
|
|
3360
4474
|
const response = await fetch(endpoint, {
|
|
3361
4475
|
method: "POST",
|
|
3362
4476
|
headers: buildHeaders(apiKey),
|
|
3363
4477
|
body: JSON.stringify({
|
|
3364
|
-
url
|
|
4478
|
+
url: url2
|
|
3365
4479
|
}),
|
|
3366
4480
|
signal: context.signal
|
|
3367
4481
|
});
|
|
3368
4482
|
if (!response.ok) {
|
|
3369
4483
|
return {
|
|
3370
|
-
url,
|
|
4484
|
+
url: url2,
|
|
3371
4485
|
error: await buildHttpError(response)
|
|
3372
4486
|
};
|
|
3373
4487
|
}
|
|
@@ -3375,19 +4489,19 @@ async function fetchOllamaContents(urls, config, context) {
|
|
|
3375
4489
|
const content = normalizeContentText(data.content);
|
|
3376
4490
|
if (!content) {
|
|
3377
4491
|
return {
|
|
3378
|
-
url,
|
|
4492
|
+
url: url2,
|
|
3379
4493
|
error: "No content returned for this URL."
|
|
3380
4494
|
};
|
|
3381
4495
|
}
|
|
3382
4496
|
const metadata = buildFetchMetadata(data);
|
|
3383
4497
|
return {
|
|
3384
|
-
url,
|
|
4498
|
+
url: url2,
|
|
3385
4499
|
content,
|
|
3386
4500
|
...metadata ? { metadata } : {}
|
|
3387
4501
|
};
|
|
3388
4502
|
} catch (error) {
|
|
3389
4503
|
return {
|
|
3390
|
-
url,
|
|
4504
|
+
url: url2,
|
|
3391
4505
|
error: error instanceof Error ? error.message : String(error)
|
|
3392
4506
|
};
|
|
3393
4507
|
}
|
|
@@ -3396,7 +4510,7 @@ async function fetchOllamaContents(urls, config, context) {
|
|
|
3396
4510
|
};
|
|
3397
4511
|
}
|
|
3398
4512
|
function resolveApiKey(config) {
|
|
3399
|
-
const apiKey = resolveConfigValue(config.
|
|
4513
|
+
const apiKey = resolveConfigValue(config.credentials?.api);
|
|
3400
4514
|
if (!apiKey) {
|
|
3401
4515
|
throw new Error("is missing an API key");
|
|
3402
4516
|
}
|
|
@@ -3409,16 +4523,16 @@ function buildHeaders(apiKey) {
|
|
|
3409
4523
|
};
|
|
3410
4524
|
}
|
|
3411
4525
|
function resolveEndpoint(baseUrlReference, endpointPath) {
|
|
3412
|
-
const baseUrl = resolveConfigValue(baseUrlReference) ??
|
|
3413
|
-
const
|
|
4526
|
+
const baseUrl = resolveConfigValue(baseUrlReference) ?? DEFAULT_BASE_URL2;
|
|
4527
|
+
const base2 = baseUrl.replace(/\/+$/, "");
|
|
3414
4528
|
const apiPath = endpointPath.replace(/^\/api\//, "");
|
|
3415
|
-
if (
|
|
3416
|
-
return
|
|
4529
|
+
if (base2.endsWith(endpointPath)) {
|
|
4530
|
+
return base2;
|
|
3417
4531
|
}
|
|
3418
|
-
if (
|
|
3419
|
-
return `${
|
|
4532
|
+
if (base2.endsWith("/api")) {
|
|
4533
|
+
return `${base2}/${apiPath}`;
|
|
3420
4534
|
}
|
|
3421
|
-
return `${
|
|
4535
|
+
return `${base2}${endpointPath}`;
|
|
3422
4536
|
}
|
|
3423
4537
|
function clampMaxResults(value) {
|
|
3424
4538
|
return Math.max(1, Math.min(10, Math.trunc(value || 0)));
|
|
@@ -3457,55 +4571,55 @@ function buildFetchMetadata(data) {
|
|
|
3457
4571
|
}
|
|
3458
4572
|
|
|
3459
4573
|
// src/providers/openai.ts
|
|
3460
|
-
import { Type as
|
|
4574
|
+
import { Type as Type10 } from "typebox";
|
|
3461
4575
|
import OpenAI from "openai";
|
|
3462
4576
|
var DEFAULT_SEARCH_MODEL2 = "gpt-4.1";
|
|
3463
4577
|
var DEFAULT_ANSWER_MODEL2 = "gpt-4.1";
|
|
3464
4578
|
var DEFAULT_RESEARCH_MODEL = "o4-mini-deep-research";
|
|
3465
|
-
var openaiSearchOptionsSchema =
|
|
4579
|
+
var openaiSearchOptionsSchema = Type10.Object(
|
|
3466
4580
|
{
|
|
3467
|
-
model:
|
|
3468
|
-
|
|
4581
|
+
model: Type10.Optional(
|
|
4582
|
+
Type10.String({
|
|
3469
4583
|
description: "OpenAI model to use for web search (for example 'gpt-4.1')."
|
|
3470
4584
|
})
|
|
3471
4585
|
),
|
|
3472
|
-
instructions:
|
|
3473
|
-
|
|
4586
|
+
instructions: Type10.Optional(
|
|
4587
|
+
Type10.String({
|
|
3474
4588
|
description: "Optional instructions that shape source selection and result style."
|
|
3475
4589
|
})
|
|
3476
4590
|
)
|
|
3477
4591
|
},
|
|
3478
4592
|
{ description: "OpenAI search options." }
|
|
3479
4593
|
);
|
|
3480
|
-
var openaiAnswerOptionsSchema =
|
|
4594
|
+
var openaiAnswerOptionsSchema = Type10.Object(
|
|
3481
4595
|
{
|
|
3482
|
-
model:
|
|
3483
|
-
|
|
4596
|
+
model: Type10.Optional(
|
|
4597
|
+
Type10.String({
|
|
3484
4598
|
description: "OpenAI model to use for grounded answers (for example 'gpt-4.1')."
|
|
3485
4599
|
})
|
|
3486
4600
|
),
|
|
3487
|
-
instructions:
|
|
3488
|
-
|
|
4601
|
+
instructions: Type10.Optional(
|
|
4602
|
+
Type10.String({
|
|
3489
4603
|
description: "Optional instructions that shape the answer structure, tone, and source selection."
|
|
3490
4604
|
})
|
|
3491
4605
|
)
|
|
3492
4606
|
},
|
|
3493
4607
|
{ description: "OpenAI answer options." }
|
|
3494
4608
|
);
|
|
3495
|
-
var openaiResearchOptionsSchema =
|
|
4609
|
+
var openaiResearchOptionsSchema = Type10.Object(
|
|
3496
4610
|
{
|
|
3497
|
-
model:
|
|
3498
|
-
|
|
4611
|
+
model: Type10.Optional(
|
|
4612
|
+
Type10.String({
|
|
3499
4613
|
description: "OpenAI deep research model to use (for example 'o4-mini-deep-research')."
|
|
3500
4614
|
})
|
|
3501
4615
|
),
|
|
3502
|
-
instructions:
|
|
3503
|
-
|
|
4616
|
+
instructions: Type10.Optional(
|
|
4617
|
+
Type10.String({
|
|
3504
4618
|
description: "Optional instructions that shape the report structure, tone, and source selection."
|
|
3505
4619
|
})
|
|
3506
4620
|
),
|
|
3507
|
-
max_tool_calls:
|
|
3508
|
-
|
|
4621
|
+
max_tool_calls: Type10.Optional(
|
|
4622
|
+
Type10.Integer({
|
|
3509
4623
|
minimum: 1,
|
|
3510
4624
|
description: "Maximum number of built-in tool calls the model may make during the research run."
|
|
3511
4625
|
})
|
|
@@ -3551,7 +4665,7 @@ var openaiImplementation = {
|
|
|
3551
4665
|
},
|
|
3552
4666
|
createTemplate() {
|
|
3553
4667
|
return {
|
|
3554
|
-
|
|
4668
|
+
credentials: { api: "OPENAI_API_KEY" },
|
|
3555
4669
|
options: {
|
|
3556
4670
|
search: {
|
|
3557
4671
|
model: DEFAULT_SEARCH_MODEL2
|
|
@@ -3566,7 +4680,7 @@ var openaiImplementation = {
|
|
|
3566
4680
|
};
|
|
3567
4681
|
},
|
|
3568
4682
|
getCapabilityStatus(config) {
|
|
3569
|
-
return getApiKeyStatus(config?.
|
|
4683
|
+
return getApiKeyStatus(config?.credentials?.api);
|
|
3570
4684
|
},
|
|
3571
4685
|
async search(query2, maxResults, config, context, options) {
|
|
3572
4686
|
const client = createClient5(config);
|
|
@@ -3645,7 +4759,7 @@ var openaiImplementation = {
|
|
|
3645
4759
|
}
|
|
3646
4760
|
};
|
|
3647
4761
|
function createClient5(config) {
|
|
3648
|
-
const apiKey = resolveConfigValue(config.
|
|
4762
|
+
const apiKey = resolveConfigValue(config.credentials?.api);
|
|
3649
4763
|
if (!apiKey) {
|
|
3650
4764
|
throw new Error("is missing an API key");
|
|
3651
4765
|
}
|
|
@@ -3835,15 +4949,15 @@ function extractUrlCitations(response) {
|
|
|
3835
4949
|
continue;
|
|
3836
4950
|
}
|
|
3837
4951
|
const title = readNonEmptyString4(annotation.title);
|
|
3838
|
-
const
|
|
4952
|
+
const url2 = readNonEmptyString4(annotation.url);
|
|
3839
4953
|
const startIndex = readInteger(annotation.start_index);
|
|
3840
4954
|
const endIndex = readInteger(annotation.end_index);
|
|
3841
|
-
if (!title || !
|
|
4955
|
+
if (!title || !url2 || startIndex === void 0 || endIndex === void 0) {
|
|
3842
4956
|
continue;
|
|
3843
4957
|
}
|
|
3844
4958
|
const citation = {
|
|
3845
4959
|
title,
|
|
3846
|
-
url,
|
|
4960
|
+
url: url2,
|
|
3847
4961
|
startIndex,
|
|
3848
4962
|
endIndex
|
|
3849
4963
|
};
|
|
@@ -3882,18 +4996,18 @@ function parseSearchPayload(text) {
|
|
|
3882
4996
|
}
|
|
3883
4997
|
const entry = source;
|
|
3884
4998
|
const title = readNonEmptyString4(entry.title);
|
|
3885
|
-
const
|
|
4999
|
+
const url2 = readNonEmptyString4(entry.url);
|
|
3886
5000
|
const snippet = readNonEmptyString4(entry.snippet);
|
|
3887
5001
|
if (!title) {
|
|
3888
5002
|
throw new Error(`search source at index ${index} is missing title`);
|
|
3889
5003
|
}
|
|
3890
|
-
if (!
|
|
5004
|
+
if (!url2) {
|
|
3891
5005
|
throw new Error(`search source at index ${index} is missing url`);
|
|
3892
5006
|
}
|
|
3893
5007
|
if (!snippet) {
|
|
3894
5008
|
throw new Error(`search source at index ${index} is missing snippet`);
|
|
3895
5009
|
}
|
|
3896
|
-
return { title, url, snippet };
|
|
5010
|
+
return { title, url: url2, snippet };
|
|
3897
5011
|
})
|
|
3898
5012
|
};
|
|
3899
5013
|
}
|
|
@@ -3919,7 +5033,7 @@ var openaiProvider = defineProvider({
|
|
|
3919
5033
|
docsUrl: openaiImplementation.docsUrl,
|
|
3920
5034
|
config: {
|
|
3921
5035
|
createTemplate: () => openaiImplementation.createTemplate(),
|
|
3922
|
-
fields: ["
|
|
5036
|
+
fields: ["credentials", "baseUrl", "options", "settings"],
|
|
3923
5037
|
optionCapabilities: ["search", "answer", "research"]
|
|
3924
5038
|
},
|
|
3925
5039
|
getCapabilityStatus: (config, cwd, tool) => openaiImplementation.getCapabilityStatus(
|
|
@@ -3967,25 +5081,25 @@ var openaiProvider = defineProvider({
|
|
|
3967
5081
|
});
|
|
3968
5082
|
|
|
3969
5083
|
// src/providers/parallel.ts
|
|
3970
|
-
import { Type as Type10 } from "typebox";
|
|
3971
5084
|
import ParallelClient from "parallel-web";
|
|
3972
|
-
|
|
5085
|
+
import { Type as Type11 } from "typebox";
|
|
5086
|
+
var parallelSearchOptionsSchema = Type11.Object(
|
|
3973
5087
|
{
|
|
3974
|
-
mode:
|
|
5088
|
+
mode: Type11.Optional(
|
|
3975
5089
|
literalUnion(["agentic", "one-shot"], {
|
|
3976
|
-
description: "Parallel search mode."
|
|
5090
|
+
description: "Parallel search mode. Use 'agentic' for exploratory or multi-step source discovery and 'one-shot' for direct, simple searches."
|
|
3977
5091
|
})
|
|
3978
5092
|
)
|
|
3979
5093
|
},
|
|
3980
5094
|
{ description: "Parallel search options." }
|
|
3981
5095
|
);
|
|
3982
|
-
var parallelExtractOptionsSchema =
|
|
5096
|
+
var parallelExtractOptionsSchema = Type11.Object(
|
|
3983
5097
|
{
|
|
3984
|
-
excerpts:
|
|
3985
|
-
|
|
5098
|
+
excerpts: Type11.Optional(
|
|
5099
|
+
Type11.Boolean({ description: "Include excerpts in extraction results." })
|
|
3986
5100
|
),
|
|
3987
|
-
full_content:
|
|
3988
|
-
|
|
5101
|
+
full_content: Type11.Optional(
|
|
5102
|
+
Type11.Boolean({
|
|
3989
5103
|
description: "Include full page content in extraction results."
|
|
3990
5104
|
})
|
|
3991
5105
|
)
|
|
@@ -4008,7 +5122,7 @@ var parallelImplementation = {
|
|
|
4008
5122
|
},
|
|
4009
5123
|
createTemplate() {
|
|
4010
5124
|
return {
|
|
4011
|
-
|
|
5125
|
+
credentials: { api: "PARALLEL_API_KEY" },
|
|
4012
5126
|
options: {
|
|
4013
5127
|
search: {
|
|
4014
5128
|
mode: "agentic"
|
|
@@ -4021,7 +5135,7 @@ var parallelImplementation = {
|
|
|
4021
5135
|
};
|
|
4022
5136
|
},
|
|
4023
5137
|
getCapabilityStatus(config) {
|
|
4024
|
-
return getApiKeyStatus(config?.
|
|
5138
|
+
return getApiKeyStatus(config?.credentials?.api);
|
|
4025
5139
|
},
|
|
4026
5140
|
async search(query2, maxResults, config, context, options) {
|
|
4027
5141
|
const client = createClient6(config);
|
|
@@ -4063,21 +5177,21 @@ var parallelImplementation = {
|
|
|
4063
5177
|
);
|
|
4064
5178
|
return {
|
|
4065
5179
|
provider: parallelImplementation.id,
|
|
4066
|
-
answers: urls.map((
|
|
4067
|
-
const result = resultsByUrl.get(
|
|
5180
|
+
answers: urls.map((url2) => {
|
|
5181
|
+
const result = resultsByUrl.get(url2);
|
|
4068
5182
|
if (result) {
|
|
4069
5183
|
return {
|
|
4070
|
-
url,
|
|
5184
|
+
url: url2,
|
|
4071
5185
|
content: result.full_content ?? result.excerpts?.join("\n\n") ?? void 0,
|
|
4072
5186
|
metadata: result
|
|
4073
5187
|
};
|
|
4074
5188
|
}
|
|
4075
|
-
const error = errorsByUrl.get(
|
|
5189
|
+
const error = errorsByUrl.get(url2);
|
|
4076
5190
|
return error ? {
|
|
4077
|
-
url,
|
|
5191
|
+
url: url2,
|
|
4078
5192
|
error: formatJson(error)
|
|
4079
5193
|
} : {
|
|
4080
|
-
url,
|
|
5194
|
+
url: url2,
|
|
4081
5195
|
error: "No content returned for this URL."
|
|
4082
5196
|
};
|
|
4083
5197
|
})
|
|
@@ -4085,7 +5199,7 @@ var parallelImplementation = {
|
|
|
4085
5199
|
}
|
|
4086
5200
|
};
|
|
4087
5201
|
function createClient6(config) {
|
|
4088
|
-
const apiKey = resolveConfigValue(config.
|
|
5202
|
+
const apiKey = resolveConfigValue(config.credentials?.api);
|
|
4089
5203
|
if (!apiKey) {
|
|
4090
5204
|
throw new Error("is missing an API key");
|
|
4091
5205
|
}
|
|
@@ -4103,7 +5217,7 @@ var parallelProvider = defineProvider({
|
|
|
4103
5217
|
docsUrl: parallelImplementation.docsUrl,
|
|
4104
5218
|
config: {
|
|
4105
5219
|
createTemplate: () => parallelImplementation.createTemplate(),
|
|
4106
|
-
fields: ["
|
|
5220
|
+
fields: ["credentials", "baseUrl", "options", "settings"]
|
|
4107
5221
|
},
|
|
4108
5222
|
getCapabilityStatus: (config, cwd, tool) => parallelImplementation.getCapabilityStatus(
|
|
4109
5223
|
config,
|
|
@@ -4140,42 +5254,44 @@ var parallelProvider = defineProvider({
|
|
|
4140
5254
|
|
|
4141
5255
|
// src/providers/perplexity.ts
|
|
4142
5256
|
import PerplexityClient from "@perplexity-ai/perplexity_ai";
|
|
4143
|
-
import { Type as
|
|
5257
|
+
import { Type as Type12 } from "typebox";
|
|
4144
5258
|
var DEFAULT_ANSWER_MODEL3 = "sonar";
|
|
4145
5259
|
var DEFAULT_RESEARCH_MODEL2 = "sonar-deep-research";
|
|
4146
|
-
var perplexitySearchOptionsSchema =
|
|
5260
|
+
var perplexitySearchOptionsSchema = Type12.Object(
|
|
4147
5261
|
{
|
|
4148
|
-
country:
|
|
4149
|
-
|
|
5262
|
+
country: Type12.Optional(
|
|
5263
|
+
Type12.String({ description: "Country hint for search results." })
|
|
4150
5264
|
),
|
|
4151
|
-
search_mode:
|
|
4152
|
-
|
|
5265
|
+
search_mode: Type12.Optional(
|
|
5266
|
+
Type12.String({
|
|
5267
|
+
description: "Perplexity search mode. Choose the provider mode that best matches the user's intent, such as broad web search versus academic or other specialized retrieval modes supported by Perplexity."
|
|
5268
|
+
})
|
|
4153
5269
|
),
|
|
4154
|
-
search_domain_filter:
|
|
4155
|
-
|
|
5270
|
+
search_domain_filter: Type12.Optional(
|
|
5271
|
+
Type12.Array(Type12.String(), {
|
|
4156
5272
|
description: "Restrict search results to these domains."
|
|
4157
5273
|
})
|
|
4158
5274
|
),
|
|
4159
|
-
search_recency_filter:
|
|
4160
|
-
|
|
5275
|
+
search_recency_filter: Type12.Optional(
|
|
5276
|
+
Type12.String({ description: "Recency filter for search results." })
|
|
4161
5277
|
)
|
|
4162
5278
|
},
|
|
4163
5279
|
{ description: "Perplexity search options." }
|
|
4164
5280
|
);
|
|
4165
|
-
var perplexityAnswerOptionsSchema =
|
|
5281
|
+
var perplexityAnswerOptionsSchema = Type12.Object(
|
|
4166
5282
|
{
|
|
4167
|
-
model:
|
|
4168
|
-
|
|
5283
|
+
model: Type12.Optional(
|
|
5284
|
+
Type12.String({
|
|
4169
5285
|
description: "Perplexity model to use (for example 'sonar' or 'sonar-pro')."
|
|
4170
5286
|
})
|
|
4171
5287
|
)
|
|
4172
5288
|
},
|
|
4173
5289
|
{ description: "Perplexity answer options." }
|
|
4174
5290
|
);
|
|
4175
|
-
var perplexityResearchOptionsSchema =
|
|
5291
|
+
var perplexityResearchOptionsSchema = Type12.Object(
|
|
4176
5292
|
{
|
|
4177
|
-
model:
|
|
4178
|
-
|
|
5293
|
+
model: Type12.Optional(
|
|
5294
|
+
Type12.String({
|
|
4179
5295
|
description: "Perplexity model to use (for example 'sonar-deep-research')."
|
|
4180
5296
|
})
|
|
4181
5297
|
)
|
|
@@ -4200,7 +5316,7 @@ var perplexityImplementation = {
|
|
|
4200
5316
|
},
|
|
4201
5317
|
createTemplate() {
|
|
4202
5318
|
return {
|
|
4203
|
-
|
|
5319
|
+
credentials: { api: "PERPLEXITY_API_KEY" },
|
|
4204
5320
|
options: {
|
|
4205
5321
|
answer: {
|
|
4206
5322
|
model: DEFAULT_ANSWER_MODEL3
|
|
@@ -4212,7 +5328,7 @@ var perplexityImplementation = {
|
|
|
4212
5328
|
};
|
|
4213
5329
|
},
|
|
4214
5330
|
getCapabilityStatus(config) {
|
|
4215
|
-
return getApiKeyStatus(config?.
|
|
5331
|
+
return getApiKeyStatus(config?.credentials?.api);
|
|
4216
5332
|
},
|
|
4217
5333
|
async search(query2, maxResults, config, context, options) {
|
|
4218
5334
|
const client = createClient7(config);
|
|
@@ -4335,7 +5451,7 @@ async function runStreamingForegroundChatTool(input, config, context, fallbackMo
|
|
|
4335
5451
|
};
|
|
4336
5452
|
}
|
|
4337
5453
|
function createClient7(config) {
|
|
4338
|
-
const apiKey = resolveConfigValue(config.
|
|
5454
|
+
const apiKey = resolveConfigValue(config.credentials?.api);
|
|
4339
5455
|
if (!apiKey) {
|
|
4340
5456
|
throw new Error("is missing an API key");
|
|
4341
5457
|
}
|
|
@@ -4386,29 +5502,29 @@ function dedupeSources(sources) {
|
|
|
4386
5502
|
const unique = [];
|
|
4387
5503
|
for (const source of sources) {
|
|
4388
5504
|
const title = source.title.trim() || source.url.trim() || "Untitled";
|
|
4389
|
-
const
|
|
4390
|
-
if (!
|
|
4391
|
-
const key = `${title.toLowerCase()}::${
|
|
5505
|
+
const url2 = source.url.trim();
|
|
5506
|
+
if (!url2) continue;
|
|
5507
|
+
const key = `${title.toLowerCase()}::${url2.toLowerCase()}`;
|
|
4392
5508
|
if (seen.has(key)) continue;
|
|
4393
5509
|
seen.add(key);
|
|
4394
|
-
unique.push({ title, url });
|
|
5510
|
+
unique.push({ title, url: url2 });
|
|
4395
5511
|
}
|
|
4396
5512
|
return unique;
|
|
4397
5513
|
}
|
|
4398
5514
|
function extractSources(response) {
|
|
4399
5515
|
const searchResults = response.search_results?.flatMap((result) => {
|
|
4400
|
-
const
|
|
4401
|
-
if (!
|
|
5516
|
+
const url2 = result.url?.trim() ?? "";
|
|
5517
|
+
if (!url2) {
|
|
4402
5518
|
return [];
|
|
4403
5519
|
}
|
|
4404
|
-
return [{ title: result.title?.trim() ??
|
|
5520
|
+
return [{ title: result.title?.trim() ?? url2, url: url2 }];
|
|
4405
5521
|
}) ?? [];
|
|
4406
5522
|
if (searchResults.length > 0) {
|
|
4407
5523
|
return searchResults;
|
|
4408
5524
|
}
|
|
4409
5525
|
return response.citations?.flatMap((citation) => {
|
|
4410
|
-
const
|
|
4411
|
-
return
|
|
5526
|
+
const url2 = citation?.trim() ?? "";
|
|
5527
|
+
return url2 ? [{ title: url2, url: url2 }] : [];
|
|
4412
5528
|
}) ?? [];
|
|
4413
5529
|
}
|
|
4414
5530
|
function buildRequestOptions4(context) {
|
|
@@ -4420,7 +5536,7 @@ var perplexityProvider = defineProvider({
|
|
|
4420
5536
|
docsUrl: perplexityImplementation.docsUrl,
|
|
4421
5537
|
config: {
|
|
4422
5538
|
createTemplate: () => perplexityImplementation.createTemplate(),
|
|
4423
|
-
fields: ["
|
|
5539
|
+
fields: ["credentials", "baseUrl", "options", "settings"]
|
|
4424
5540
|
},
|
|
4425
5541
|
getCapabilityStatus: (config, cwd, tool) => perplexityImplementation.getCapabilityStatus(
|
|
4426
5542
|
config,
|
|
@@ -4467,33 +5583,33 @@ var perplexityProvider = defineProvider({
|
|
|
4467
5583
|
});
|
|
4468
5584
|
|
|
4469
5585
|
// src/providers/serper.ts
|
|
4470
|
-
import { Type as
|
|
4471
|
-
var
|
|
4472
|
-
var serperSearchOptionsSchema =
|
|
5586
|
+
import { Type as Type13 } from "typebox";
|
|
5587
|
+
var DEFAULT_BASE_URL3 = "https://google.serper.dev";
|
|
5588
|
+
var serperSearchOptionsSchema = Type13.Object(
|
|
4473
5589
|
{
|
|
4474
|
-
gl:
|
|
4475
|
-
|
|
5590
|
+
gl: Type13.Optional(
|
|
5591
|
+
Type13.String({
|
|
4476
5592
|
description: "Country code hint for Google results (for example 'us')."
|
|
4477
5593
|
})
|
|
4478
5594
|
),
|
|
4479
|
-
hl:
|
|
4480
|
-
|
|
5595
|
+
hl: Type13.Optional(
|
|
5596
|
+
Type13.String({
|
|
4481
5597
|
description: "Language code hint for Google results (for example 'en')."
|
|
4482
5598
|
})
|
|
4483
5599
|
),
|
|
4484
|
-
location:
|
|
4485
|
-
|
|
5600
|
+
location: Type13.Optional(
|
|
5601
|
+
Type13.String({
|
|
4486
5602
|
description: "Geographic location hint for Google results."
|
|
4487
5603
|
})
|
|
4488
5604
|
),
|
|
4489
|
-
page:
|
|
4490
|
-
|
|
5605
|
+
page: Type13.Optional(
|
|
5606
|
+
Type13.Integer({
|
|
4491
5607
|
minimum: 1,
|
|
4492
5608
|
description: "1-based results page to request from Serper."
|
|
4493
5609
|
})
|
|
4494
5610
|
),
|
|
4495
|
-
autocorrect:
|
|
4496
|
-
|
|
5611
|
+
autocorrect: Type13.Optional(
|
|
5612
|
+
Type13.Boolean({
|
|
4497
5613
|
description: "Enable or disable Serper query autocorrection."
|
|
4498
5614
|
})
|
|
4499
5615
|
)
|
|
@@ -4514,15 +5630,15 @@ var serperImplementation = {
|
|
|
4514
5630
|
},
|
|
4515
5631
|
createTemplate() {
|
|
4516
5632
|
return {
|
|
4517
|
-
|
|
5633
|
+
credentials: { api: "SERPER_API_KEY" },
|
|
4518
5634
|
options: {}
|
|
4519
5635
|
};
|
|
4520
5636
|
},
|
|
4521
5637
|
getCapabilityStatus(config) {
|
|
4522
|
-
return getApiKeyStatus(config?.
|
|
5638
|
+
return getApiKeyStatus(config?.credentials?.api);
|
|
4523
5639
|
},
|
|
4524
5640
|
async search(query2, maxResults, config, context, options) {
|
|
4525
|
-
const apiKey = resolveConfigValue(config.
|
|
5641
|
+
const apiKey = resolveConfigValue(config.credentials?.api);
|
|
4526
5642
|
if (!apiKey) {
|
|
4527
5643
|
throw new Error("is missing an API key");
|
|
4528
5644
|
}
|
|
@@ -4565,8 +5681,8 @@ var serperImplementation = {
|
|
|
4565
5681
|
}
|
|
4566
5682
|
};
|
|
4567
5683
|
function joinUrl(baseUrl) {
|
|
4568
|
-
const
|
|
4569
|
-
return `${
|
|
5684
|
+
const base2 = (baseUrl ?? DEFAULT_BASE_URL3).replace(/\/+$/, "");
|
|
5685
|
+
return `${base2}/search`;
|
|
4570
5686
|
}
|
|
4571
5687
|
function clampMaxResults2(value) {
|
|
4572
5688
|
return Math.max(1, Math.min(20, Math.trunc(value || 0)));
|
|
@@ -4598,8 +5714,8 @@ function toSearchResult3(entry, searchContext) {
|
|
|
4598
5714
|
if (!record) {
|
|
4599
5715
|
return null;
|
|
4600
5716
|
}
|
|
4601
|
-
const
|
|
4602
|
-
const title = readString4(record.title) ||
|
|
5717
|
+
const url2 = readString4(record.link) ?? "";
|
|
5718
|
+
const title = readString4(record.title) || url2 || "Untitled";
|
|
4603
5719
|
const snippet = trimSnippet(
|
|
4604
5720
|
readString4(record.snippet) ?? readString4(record.richSnippet) ?? readString4(record.date) ?? ""
|
|
4605
5721
|
);
|
|
@@ -4617,7 +5733,7 @@ function toSearchResult3(entry, searchContext) {
|
|
|
4617
5733
|
});
|
|
4618
5734
|
return {
|
|
4619
5735
|
title,
|
|
4620
|
-
url,
|
|
5736
|
+
url: url2,
|
|
4621
5737
|
snippet,
|
|
4622
5738
|
...Object.keys(metadata).length > 0 ? { metadata } : {}
|
|
4623
5739
|
};
|
|
@@ -4669,7 +5785,7 @@ var serperProvider = defineProvider({
|
|
|
4669
5785
|
docsUrl: serperImplementation.docsUrl,
|
|
4670
5786
|
config: {
|
|
4671
5787
|
createTemplate: () => serperImplementation.createTemplate(),
|
|
4672
|
-
fields: ["
|
|
5788
|
+
fields: ["credentials", "baseUrl", "options", "settings"],
|
|
4673
5789
|
optionCapabilities: ["search"]
|
|
4674
5790
|
},
|
|
4675
5791
|
getCapabilityStatus: (config, cwd, tool) => serperImplementation.getCapabilityStatus(
|
|
@@ -4695,55 +5811,55 @@ var serperProvider = defineProvider({
|
|
|
4695
5811
|
});
|
|
4696
5812
|
|
|
4697
5813
|
// src/providers/tavily.ts
|
|
4698
|
-
import { Type as Type13 } from "typebox";
|
|
4699
5814
|
import {
|
|
4700
5815
|
tavily
|
|
4701
5816
|
} from "@tavily/core";
|
|
4702
|
-
|
|
5817
|
+
import { Type as Type14 } from "typebox";
|
|
5818
|
+
var tavilySearchOptionsSchema = Type14.Object(
|
|
4703
5819
|
{
|
|
4704
|
-
topic:
|
|
5820
|
+
topic: Type14.Optional(
|
|
4705
5821
|
literalUnion(["general", "news", "finance"], {
|
|
4706
|
-
description: "Category of the search query."
|
|
5822
|
+
description: "Category of the search query. Use 'news' for recent journalism or current events, 'finance' for markets or company financial data, and 'general' for broad web search."
|
|
4707
5823
|
})
|
|
4708
5824
|
),
|
|
4709
|
-
searchDepth:
|
|
5825
|
+
searchDepth: Type14.Optional(
|
|
4710
5826
|
literalUnion(["basic", "advanced"], {
|
|
4711
5827
|
description: "Depth of the search. 'advanced' is slower but more thorough."
|
|
4712
5828
|
})
|
|
4713
5829
|
),
|
|
4714
|
-
timeRange:
|
|
4715
|
-
|
|
5830
|
+
timeRange: Type14.Optional(
|
|
5831
|
+
Type14.String({ description: "Named time range filter." })
|
|
4716
5832
|
),
|
|
4717
|
-
country:
|
|
4718
|
-
|
|
5833
|
+
country: Type14.Optional(
|
|
5834
|
+
Type14.String({ description: "Country hint for search results." })
|
|
4719
5835
|
),
|
|
4720
|
-
exactMatch:
|
|
4721
|
-
|
|
5836
|
+
exactMatch: Type14.Optional(
|
|
5837
|
+
Type14.Boolean({ description: "Prefer exact matches." })
|
|
4722
5838
|
),
|
|
4723
|
-
includeAnswer:
|
|
4724
|
-
|
|
5839
|
+
includeAnswer: Type14.Optional(
|
|
5840
|
+
Type14.Boolean({ description: "Include a short AI-generated answer." })
|
|
4725
5841
|
),
|
|
4726
|
-
includeRawContent:
|
|
4727
|
-
|
|
5842
|
+
includeRawContent: Type14.Optional(
|
|
5843
|
+
Type14.Boolean({ description: "Include raw page content in results." })
|
|
4728
5844
|
),
|
|
4729
|
-
includeImages:
|
|
4730
|
-
|
|
5845
|
+
includeImages: Type14.Optional(
|
|
5846
|
+
Type14.Boolean({ description: "Include related images." })
|
|
4731
5847
|
),
|
|
4732
|
-
includeFavicon:
|
|
4733
|
-
|
|
5848
|
+
includeFavicon: Type14.Optional(
|
|
5849
|
+
Type14.Boolean({ description: "Include favicon URLs." })
|
|
4734
5850
|
),
|
|
4735
|
-
includeDomains:
|
|
4736
|
-
|
|
5851
|
+
includeDomains: Type14.Optional(
|
|
5852
|
+
Type14.Array(Type14.String(), {
|
|
4737
5853
|
description: "Restrict results to these domains."
|
|
4738
5854
|
})
|
|
4739
5855
|
),
|
|
4740
|
-
excludeDomains:
|
|
4741
|
-
|
|
5856
|
+
excludeDomains: Type14.Optional(
|
|
5857
|
+
Type14.Array(Type14.String(), {
|
|
4742
5858
|
description: "Exclude these domains from results."
|
|
4743
5859
|
})
|
|
4744
5860
|
),
|
|
4745
|
-
days:
|
|
4746
|
-
|
|
5861
|
+
days: Type14.Optional(
|
|
5862
|
+
Type14.Integer({
|
|
4747
5863
|
minimum: 1,
|
|
4748
5864
|
description: "Limit results to the last N days."
|
|
4749
5865
|
})
|
|
@@ -4751,27 +5867,27 @@ var tavilySearchOptionsSchema = Type13.Object(
|
|
|
4751
5867
|
},
|
|
4752
5868
|
{ description: "Tavily search options." }
|
|
4753
5869
|
);
|
|
4754
|
-
var tavilyExtractOptionsSchema =
|
|
5870
|
+
var tavilyExtractOptionsSchema = Type14.Object(
|
|
4755
5871
|
{
|
|
4756
|
-
extractDepth:
|
|
4757
|
-
|
|
5872
|
+
extractDepth: Type14.Optional(
|
|
5873
|
+
Type14.String({ description: "Depth setting for extraction." })
|
|
4758
5874
|
),
|
|
4759
|
-
format:
|
|
5875
|
+
format: Type14.Optional(
|
|
4760
5876
|
literalUnion(["markdown", "text"], {
|
|
4761
5877
|
description: "Output format for extracted content."
|
|
4762
5878
|
})
|
|
4763
5879
|
),
|
|
4764
|
-
includeImages:
|
|
4765
|
-
|
|
5880
|
+
includeImages: Type14.Optional(
|
|
5881
|
+
Type14.Boolean({ description: "Include extracted images." })
|
|
4766
5882
|
),
|
|
4767
|
-
query:
|
|
4768
|
-
|
|
5883
|
+
query: Type14.Optional(
|
|
5884
|
+
Type14.String({ description: "Optional query to focus extraction." })
|
|
4769
5885
|
),
|
|
4770
|
-
chunksPerSource:
|
|
4771
|
-
|
|
5886
|
+
chunksPerSource: Type14.Optional(
|
|
5887
|
+
Type14.Integer({ minimum: 1, description: "Maximum chunks per source." })
|
|
4772
5888
|
),
|
|
4773
|
-
includeFavicon:
|
|
4774
|
-
|
|
5889
|
+
includeFavicon: Type14.Optional(
|
|
5890
|
+
Type14.Boolean({ description: "Include favicon URLs." })
|
|
4775
5891
|
)
|
|
4776
5892
|
},
|
|
4777
5893
|
{ description: "Tavily extract options." }
|
|
@@ -4792,7 +5908,7 @@ var tavilyImplementation = {
|
|
|
4792
5908
|
},
|
|
4793
5909
|
createTemplate() {
|
|
4794
5910
|
return {
|
|
4795
|
-
|
|
5911
|
+
credentials: { api: "TAVILY_API_KEY" },
|
|
4796
5912
|
options: {
|
|
4797
5913
|
search: {
|
|
4798
5914
|
includeFavicon: true
|
|
@@ -4805,7 +5921,7 @@ var tavilyImplementation = {
|
|
|
4805
5921
|
};
|
|
4806
5922
|
},
|
|
4807
5923
|
getCapabilityStatus(config) {
|
|
4808
|
-
return getApiKeyStatus(config?.
|
|
5924
|
+
return getApiKeyStatus(config?.credentials?.api);
|
|
4809
5925
|
},
|
|
4810
5926
|
async search(query2, maxResults, config, _context, options) {
|
|
4811
5927
|
const client = createClient8(config);
|
|
@@ -4841,24 +5957,24 @@ var tavilyImplementation = {
|
|
|
4841
5957
|
);
|
|
4842
5958
|
return {
|
|
4843
5959
|
provider: tavilyImplementation.id,
|
|
4844
|
-
answers: urls.map((
|
|
4845
|
-
const result = resultsByUrl.get(
|
|
5960
|
+
answers: urls.map((url2) => {
|
|
5961
|
+
const result = resultsByUrl.get(url2);
|
|
4846
5962
|
if (result) {
|
|
4847
5963
|
return {
|
|
4848
|
-
url,
|
|
5964
|
+
url: url2,
|
|
4849
5965
|
...typeof result.rawContent === "string" ? { content: result.rawContent } : {},
|
|
4850
5966
|
metadata: buildExtractMetadata(response, result)
|
|
4851
5967
|
};
|
|
4852
5968
|
}
|
|
4853
|
-
const failedResult = failedResultsByUrl.get(
|
|
5969
|
+
const failedResult = failedResultsByUrl.get(url2);
|
|
4854
5970
|
if (failedResult) {
|
|
4855
5971
|
return {
|
|
4856
|
-
url,
|
|
5972
|
+
url: url2,
|
|
4857
5973
|
error: failedResult.error || "Content extraction failed."
|
|
4858
5974
|
};
|
|
4859
5975
|
}
|
|
4860
5976
|
return {
|
|
4861
|
-
url,
|
|
5977
|
+
url: url2,
|
|
4862
5978
|
error: "No content returned for this URL."
|
|
4863
5979
|
};
|
|
4864
5980
|
})
|
|
@@ -4866,7 +5982,7 @@ var tavilyImplementation = {
|
|
|
4866
5982
|
}
|
|
4867
5983
|
};
|
|
4868
5984
|
function createClient8(config) {
|
|
4869
|
-
const apiKey = resolveConfigValue(config.
|
|
5985
|
+
const apiKey = resolveConfigValue(config.credentials?.api);
|
|
4870
5986
|
if (!apiKey) {
|
|
4871
5987
|
throw new Error("is missing an API key");
|
|
4872
5988
|
}
|
|
@@ -4901,7 +6017,7 @@ var tavilyProvider = defineProvider({
|
|
|
4901
6017
|
docsUrl: tavilyImplementation.docsUrl,
|
|
4902
6018
|
config: {
|
|
4903
6019
|
createTemplate: () => tavilyImplementation.createTemplate(),
|
|
4904
|
-
fields: ["
|
|
6020
|
+
fields: ["credentials", "baseUrl", "options", "settings"]
|
|
4905
6021
|
},
|
|
4906
6022
|
getCapabilityStatus: (config, cwd, tool) => tavilyImplementation.getCapabilityStatus(
|
|
4907
6023
|
config,
|
|
@@ -4937,48 +6053,48 @@ var tavilyProvider = defineProvider({
|
|
|
4937
6053
|
});
|
|
4938
6054
|
|
|
4939
6055
|
// src/providers/valyu.ts
|
|
4940
|
-
import { Type as
|
|
6056
|
+
import { Type as Type15 } from "typebox";
|
|
4941
6057
|
import { Valyu as ValyuClient } from "valyu-js";
|
|
4942
|
-
var valyuSearchOptionsSchema =
|
|
6058
|
+
var valyuSearchOptionsSchema = Type15.Object(
|
|
4943
6059
|
{
|
|
4944
|
-
searchType:
|
|
6060
|
+
searchType: Type15.Optional(
|
|
4945
6061
|
literalUnion(["all", "web", "proprietary", "news"], {
|
|
4946
|
-
description: "Valyu search type."
|
|
6062
|
+
description: "Valyu search type. Use 'news' for recent journalism or current events, 'web' for public web results, 'proprietary' for Valyu proprietary sources, and 'all' when both public and proprietary sources are useful."
|
|
4947
6063
|
})
|
|
4948
6064
|
),
|
|
4949
|
-
responseLength:
|
|
6065
|
+
responseLength: Type15.Optional(
|
|
4950
6066
|
literalUnion(["short", "medium", "large", "max"], {
|
|
4951
6067
|
description: "Response length."
|
|
4952
6068
|
})
|
|
4953
6069
|
),
|
|
4954
|
-
countryCode:
|
|
4955
|
-
|
|
6070
|
+
countryCode: Type15.Optional(
|
|
6071
|
+
Type15.String({ description: "Country code to scope search results." })
|
|
4956
6072
|
)
|
|
4957
6073
|
},
|
|
4958
6074
|
{ description: "Valyu search options." }
|
|
4959
6075
|
);
|
|
4960
|
-
var valyuAnswerOptionsSchema =
|
|
6076
|
+
var valyuAnswerOptionsSchema = Type15.Object(
|
|
4961
6077
|
{
|
|
4962
|
-
responseLength:
|
|
6078
|
+
responseLength: Type15.Optional(
|
|
4963
6079
|
literalUnion(["short", "medium", "large", "max"], {
|
|
4964
6080
|
description: "Response length for answers."
|
|
4965
6081
|
})
|
|
4966
6082
|
),
|
|
4967
|
-
countryCode:
|
|
4968
|
-
|
|
6083
|
+
countryCode: Type15.Optional(
|
|
6084
|
+
Type15.String({ description: "Country code to scope answer results." })
|
|
4969
6085
|
)
|
|
4970
6086
|
},
|
|
4971
6087
|
{ description: "Valyu answer options." }
|
|
4972
6088
|
);
|
|
4973
|
-
var valyuResearchOptionsSchema =
|
|
6089
|
+
var valyuResearchOptionsSchema = Type15.Object(
|
|
4974
6090
|
{
|
|
4975
|
-
responseLength:
|
|
6091
|
+
responseLength: Type15.Optional(
|
|
4976
6092
|
literalUnion(["short", "medium", "large", "max"], {
|
|
4977
6093
|
description: "Response length for research."
|
|
4978
6094
|
})
|
|
4979
6095
|
),
|
|
4980
|
-
countryCode:
|
|
4981
|
-
|
|
6096
|
+
countryCode: Type15.Optional(
|
|
6097
|
+
Type15.String({ description: "Country code to scope research results." })
|
|
4982
6098
|
)
|
|
4983
6099
|
},
|
|
4984
6100
|
{ description: "Valyu research options." }
|
|
@@ -5001,7 +6117,7 @@ var valyuImplementation = {
|
|
|
5001
6117
|
},
|
|
5002
6118
|
createTemplate() {
|
|
5003
6119
|
return {
|
|
5004
|
-
|
|
6120
|
+
credentials: { api: "VALYU_API_KEY" },
|
|
5005
6121
|
options: {
|
|
5006
6122
|
search: {
|
|
5007
6123
|
searchType: "all",
|
|
@@ -5011,7 +6127,7 @@ var valyuImplementation = {
|
|
|
5011
6127
|
};
|
|
5012
6128
|
},
|
|
5013
6129
|
getCapabilityStatus(config) {
|
|
5014
|
-
return getApiKeyStatus(config?.
|
|
6130
|
+
return getApiKeyStatus(config?.credentials?.api);
|
|
5015
6131
|
},
|
|
5016
6132
|
async search(query2, maxResults, config, _context, searchOptions) {
|
|
5017
6133
|
const client = createClient9(config);
|
|
@@ -5050,19 +6166,19 @@ var valyuImplementation = {
|
|
|
5050
6166
|
);
|
|
5051
6167
|
return {
|
|
5052
6168
|
provider: valyuImplementation.id,
|
|
5053
|
-
answers: urls.map((
|
|
5054
|
-
const result = resultsByUrl.get(
|
|
6169
|
+
answers: urls.map((url2) => {
|
|
6170
|
+
const result = resultsByUrl.get(url2);
|
|
5055
6171
|
if (!result) {
|
|
5056
6172
|
return {
|
|
5057
|
-
url,
|
|
6173
|
+
url: url2,
|
|
5058
6174
|
error: "No content returned for this URL."
|
|
5059
6175
|
};
|
|
5060
6176
|
}
|
|
5061
6177
|
return result.status === "failed" ? {
|
|
5062
|
-
url,
|
|
6178
|
+
url: url2,
|
|
5063
6179
|
error: result.error ?? formatJson(result)
|
|
5064
6180
|
} : {
|
|
5065
|
-
url,
|
|
6181
|
+
url: url2,
|
|
5066
6182
|
...typeof result.content === "string" || typeof result.content === "number" ? { content: String(result.content) } : {},
|
|
5067
6183
|
...result.summary !== void 0 ? { summary: result.summary } : {},
|
|
5068
6184
|
metadata: result
|
|
@@ -5171,7 +6287,7 @@ var valyuImplementation = {
|
|
|
5171
6287
|
}
|
|
5172
6288
|
};
|
|
5173
6289
|
function createClient9(config) {
|
|
5174
|
-
const apiKey = resolveConfigValue(config.
|
|
6290
|
+
const apiKey = resolveConfigValue(config.credentials?.api);
|
|
5175
6291
|
if (!apiKey) {
|
|
5176
6292
|
throw new Error("is missing an API key");
|
|
5177
6293
|
}
|
|
@@ -5183,7 +6299,7 @@ var valyuProvider = defineProvider({
|
|
|
5183
6299
|
docsUrl: valyuImplementation.docsUrl,
|
|
5184
6300
|
config: {
|
|
5185
6301
|
createTemplate: () => valyuImplementation.createTemplate(),
|
|
5186
|
-
fields: ["
|
|
6302
|
+
fields: ["credentials", "baseUrl", "options", "settings"],
|
|
5187
6303
|
optionCapabilities: ["search", "answer", "research"]
|
|
5188
6304
|
},
|
|
5189
6305
|
getCapabilityStatus: (config, cwd, tool) => valyuImplementation.getCapabilityStatus(
|
|
@@ -5243,6 +6359,7 @@ var valyuProvider = defineProvider({
|
|
|
5243
6359
|
|
|
5244
6360
|
// src/providers/index.ts
|
|
5245
6361
|
var PROVIDERS = defineProviders({
|
|
6362
|
+
brave: braveProvider,
|
|
5246
6363
|
claude: claudeProvider,
|
|
5247
6364
|
codex: codexProvider,
|
|
5248
6365
|
cloudflare: cloudflareProvider,
|
|
@@ -5312,7 +6429,13 @@ async function loadConfig() {
|
|
|
5312
6429
|
async function readConfigFile(path) {
|
|
5313
6430
|
try {
|
|
5314
6431
|
const content = await readFile(path, "utf-8");
|
|
5315
|
-
|
|
6432
|
+
const raw = parseJson(content, path);
|
|
6433
|
+
const migrated = migrateLegacyCredentialConfig(raw);
|
|
6434
|
+
const config = normalizeConfig(migrated.config, path);
|
|
6435
|
+
if (migrated.changed) {
|
|
6436
|
+
await writeFile(path, serializeConfig(config), "utf-8");
|
|
6437
|
+
}
|
|
6438
|
+
return config;
|
|
5316
6439
|
} catch (error) {
|
|
5317
6440
|
if (error.code === "ENOENT") {
|
|
5318
6441
|
return {};
|
|
@@ -5328,9 +6451,6 @@ async function writeConfigFile(config) {
|
|
|
5328
6451
|
await writeFile(path, serializeConfig(cleaned), "utf-8");
|
|
5329
6452
|
return path;
|
|
5330
6453
|
}
|
|
5331
|
-
function parseConfig(text, source = CONFIG_FILE_NAME) {
|
|
5332
|
-
return normalizeConfig(parseJson(text, source), source);
|
|
5333
|
-
}
|
|
5334
6454
|
function serializeConfig(config) {
|
|
5335
6455
|
return `${JSON.stringify(toPublicConfig(config), null, 2)}
|
|
5336
6456
|
`;
|
|
@@ -5342,6 +6462,32 @@ function parseJson(text, source) {
|
|
|
5342
6462
|
throw new Error(`Invalid JSON in ${source}: ${error.message}`);
|
|
5343
6463
|
}
|
|
5344
6464
|
}
|
|
6465
|
+
function migrateLegacyCredentialConfig(raw) {
|
|
6466
|
+
if (!isPlainObject3(raw) || !isPlainObject3(raw.providers)) {
|
|
6467
|
+
return { config: raw, changed: false };
|
|
6468
|
+
}
|
|
6469
|
+
let changed = false;
|
|
6470
|
+
const config = structuredClone(raw);
|
|
6471
|
+
const providers = config.providers;
|
|
6472
|
+
for (const [providerId, provider] of Object.entries(providers)) {
|
|
6473
|
+
if (!isPlainObject3(provider)) {
|
|
6474
|
+
continue;
|
|
6475
|
+
}
|
|
6476
|
+
const legacyKey = providerId === "cloudflare" ? "apiToken" : "apiKey";
|
|
6477
|
+
const legacyValue = provider[legacyKey];
|
|
6478
|
+
if (legacyValue === void 0) {
|
|
6479
|
+
continue;
|
|
6480
|
+
}
|
|
6481
|
+
const credentials = isPlainObject3(provider.credentials) ? { ...provider.credentials } : {};
|
|
6482
|
+
if (credentials.api === void 0) {
|
|
6483
|
+
credentials.api = legacyValue;
|
|
6484
|
+
}
|
|
6485
|
+
provider.credentials = credentials;
|
|
6486
|
+
delete provider[legacyKey];
|
|
6487
|
+
changed = true;
|
|
6488
|
+
}
|
|
6489
|
+
return { config, changed };
|
|
6490
|
+
}
|
|
5345
6491
|
function normalizeConfig(raw, source) {
|
|
5346
6492
|
const configObject = requireObject2(
|
|
5347
6493
|
raw,
|
|
@@ -5407,8 +6553,6 @@ function toProviderConfigKey(field) {
|
|
|
5407
6553
|
function getProviderConfigFieldParser(field, optionCapabilities) {
|
|
5408
6554
|
switch (field) {
|
|
5409
6555
|
case "accountId":
|
|
5410
|
-
case "apiKey":
|
|
5411
|
-
case "apiToken":
|
|
5412
6556
|
case "baseUrl":
|
|
5413
6557
|
case "codexPath":
|
|
5414
6558
|
case "pathToClaudeCodeExecutable":
|
|
@@ -5417,6 +6561,7 @@ function getProviderConfigFieldParser(field, optionCapabilities) {
|
|
|
5417
6561
|
return readOptionalObject;
|
|
5418
6562
|
case "customOptions":
|
|
5419
6563
|
return parseOptionalCustomProviderOptions;
|
|
6564
|
+
case "credentials":
|
|
5420
6565
|
case "env":
|
|
5421
6566
|
return readOptionalStringMap;
|
|
5422
6567
|
case "options":
|
|
@@ -5701,8 +6846,7 @@ function toPublicProviderConfig(provider) {
|
|
|
5701
6846
|
} : {},
|
|
5702
6847
|
..."codexPath" in provider && provider.codexPath !== void 0 ? { codexPath: provider.codexPath } : {},
|
|
5703
6848
|
..."baseUrl" in provider && provider.baseUrl !== void 0 ? { baseUrl: provider.baseUrl } : {},
|
|
5704
|
-
...
|
|
5705
|
-
..."apiToken" in provider && provider.apiToken !== void 0 ? { apiToken: provider.apiToken } : {},
|
|
6849
|
+
...provider.credentials ? { credentials: provider.credentials } : {},
|
|
5706
6850
|
..."accountId" in provider && provider.accountId !== void 0 ? { accountId: provider.accountId } : {},
|
|
5707
6851
|
..."env" in provider && provider.env !== void 0 ? { env: provider.env } : {},
|
|
5708
6852
|
..."config" in provider && provider.config !== void 0 ? { config: provider.config } : {},
|
|
@@ -5945,6 +7089,10 @@ function getEffectiveProviderConfig(config, providerId) {
|
|
|
5945
7089
|
const resolved = {
|
|
5946
7090
|
...defaults,
|
|
5947
7091
|
...overrides,
|
|
7092
|
+
credentials: mergeNestedObjects(
|
|
7093
|
+
defaults.credentials,
|
|
7094
|
+
overrides.credentials
|
|
7095
|
+
),
|
|
5948
7096
|
options: mergeNestedObjects(defaults.options, overrides.options)
|
|
5949
7097
|
};
|
|
5950
7098
|
const effectiveSettings = mergeExecutionSettings(
|
|
@@ -5958,26 +7106,26 @@ function getEffectiveProviderConfig(config, providerId) {
|
|
|
5958
7106
|
}
|
|
5959
7107
|
return resolved;
|
|
5960
7108
|
}
|
|
5961
|
-
function mergeExecutionSettings(
|
|
7109
|
+
function mergeExecutionSettings(base2, overrides) {
|
|
5962
7110
|
const merged = {
|
|
5963
|
-
requestTimeoutMs: overrides?.requestTimeoutMs ??
|
|
5964
|
-
retryCount: overrides?.retryCount ??
|
|
5965
|
-
retryDelayMs: overrides?.retryDelayMs ??
|
|
5966
|
-
researchTimeoutMs: overrides?.researchTimeoutMs ??
|
|
7111
|
+
requestTimeoutMs: overrides?.requestTimeoutMs ?? base2?.requestTimeoutMs,
|
|
7112
|
+
retryCount: overrides?.retryCount ?? base2?.retryCount,
|
|
7113
|
+
retryDelayMs: overrides?.retryDelayMs ?? base2?.retryDelayMs,
|
|
7114
|
+
researchTimeoutMs: overrides?.researchTimeoutMs ?? base2?.researchTimeoutMs
|
|
5967
7115
|
};
|
|
5968
7116
|
return Object.values(merged).some((value) => value !== void 0) ? merged : void 0;
|
|
5969
7117
|
}
|
|
5970
|
-
function mergeNestedObjects(
|
|
5971
|
-
if (
|
|
7118
|
+
function mergeNestedObjects(base2, overrides) {
|
|
7119
|
+
if (base2 === void 0) {
|
|
5972
7120
|
return overrides;
|
|
5973
7121
|
}
|
|
5974
7122
|
if (overrides === void 0) {
|
|
5975
|
-
return
|
|
7123
|
+
return base2;
|
|
5976
7124
|
}
|
|
5977
|
-
if (!isPlainObject4(
|
|
7125
|
+
if (!isPlainObject4(base2) || !isPlainObject4(overrides)) {
|
|
5978
7126
|
return overrides;
|
|
5979
7127
|
}
|
|
5980
|
-
const result = { ...
|
|
7128
|
+
const result = { ...base2 };
|
|
5981
7129
|
for (const [key, value] of Object.entries(overrides)) {
|
|
5982
7130
|
const baseValue = result[key];
|
|
5983
7131
|
result[key] = isPlainObject4(baseValue) && isPlainObject4(value) ? mergeNestedObjects(baseValue, value) : value;
|
|
@@ -6013,9 +7161,9 @@ function getProviderSetupState(config, providerId) {
|
|
|
6013
7161
|
return Object.keys(providerConfig).length > 0 ? "configured" : "none";
|
|
6014
7162
|
}
|
|
6015
7163
|
if (providerId === "cloudflare") {
|
|
6016
|
-
return providerConfig.
|
|
7164
|
+
return providerConfig.credentials !== void 0 || providerConfig.accountId !== void 0 ? "configured" : "none";
|
|
6017
7165
|
}
|
|
6018
|
-
return providerConfig.
|
|
7166
|
+
return providerConfig.credentials !== void 0 ? "configured" : "none";
|
|
6019
7167
|
}
|
|
6020
7168
|
function formatProviderCapabilityStatus(status, providerId, tool) {
|
|
6021
7169
|
switch (status.state) {
|
|
@@ -6242,8 +7390,8 @@ async function startContentsPrefetch({
|
|
|
6242
7390
|
const ttlMs = clampTtlMs(options.ttlMs);
|
|
6243
7391
|
void Promise.allSettled(
|
|
6244
7392
|
selectedUrls.map(
|
|
6245
|
-
(
|
|
6246
|
-
url,
|
|
7393
|
+
(url2) => ensureContentsStored({
|
|
7394
|
+
url: url2,
|
|
6247
7395
|
providerId: provider.id,
|
|
6248
7396
|
config,
|
|
6249
7397
|
cwd,
|
|
@@ -6269,7 +7417,7 @@ async function resolveContentsFromStore({
|
|
|
6269
7417
|
onProgress
|
|
6270
7418
|
}) {
|
|
6271
7419
|
cleanupExpiredEntries();
|
|
6272
|
-
if (urls.length <= 1 || urls.some((
|
|
7420
|
+
if (urls.length <= 1 || urls.some((url2) => hasReusableContents(url2, providerId, options))) {
|
|
6273
7421
|
return await resolvePerUrlContents({
|
|
6274
7422
|
urls,
|
|
6275
7423
|
providerId,
|
|
@@ -6316,8 +7464,8 @@ async function resolvePerUrlContents({
|
|
|
6316
7464
|
}) {
|
|
6317
7465
|
const settled = await Promise.allSettled(
|
|
6318
7466
|
urls.map(
|
|
6319
|
-
(
|
|
6320
|
-
url,
|
|
7467
|
+
(url2) => ensureContentsStored({
|
|
7468
|
+
url: url2,
|
|
6321
7469
|
providerId,
|
|
6322
7470
|
config,
|
|
6323
7471
|
cwd,
|
|
@@ -6408,7 +7556,7 @@ async function fetchBatchContents({
|
|
|
6408
7556
|
};
|
|
6409
7557
|
}
|
|
6410
7558
|
async function ensureContentsStored({
|
|
6411
|
-
url,
|
|
7559
|
+
url: url2,
|
|
6412
7560
|
providerId,
|
|
6413
7561
|
config,
|
|
6414
7562
|
cwd,
|
|
@@ -6418,7 +7566,7 @@ async function ensureContentsStored({
|
|
|
6418
7566
|
ttlMs = DEFAULT_CONTENT_TTL_MS,
|
|
6419
7567
|
generation = contentStoreGeneration
|
|
6420
7568
|
}) {
|
|
6421
|
-
const canonicalUrl = canonicalizeUrl(
|
|
7569
|
+
const canonicalUrl = canonicalizeUrl(url2);
|
|
6422
7570
|
const key = buildContentsCacheKey(canonicalUrl, providerId, options);
|
|
6423
7571
|
const cached = getCachedContents(key);
|
|
6424
7572
|
if (cached) {
|
|
@@ -6501,8 +7649,8 @@ function cleanupExpiredEntries(now = Date.now()) {
|
|
|
6501
7649
|
}
|
|
6502
7650
|
}
|
|
6503
7651
|
}
|
|
6504
|
-
function hasReusableContents(
|
|
6505
|
-
const key = buildContentsCacheKey(canonicalizeUrl(
|
|
7652
|
+
function hasReusableContents(url2, providerId, options) {
|
|
7653
|
+
const key = buildContentsCacheKey(canonicalizeUrl(url2), providerId, options);
|
|
6506
7654
|
return getCachedContents(key) !== void 0 || inFlightContents.has(key);
|
|
6507
7655
|
}
|
|
6508
7656
|
function getCachedContents(key) {
|
|
@@ -6521,8 +7669,8 @@ function setCachedContents(key, value, generation) {
|
|
|
6521
7669
|
contentCache.set(key, value);
|
|
6522
7670
|
}
|
|
6523
7671
|
}
|
|
6524
|
-
function findAnswerForUrl(answers,
|
|
6525
|
-
return answers.find((answer) => canonicalizeUrl(answer.url) ===
|
|
7672
|
+
function findAnswerForUrl(answers, url2) {
|
|
7673
|
+
return answers.find((answer) => canonicalizeUrl(answer.url) === url2);
|
|
6526
7674
|
}
|
|
6527
7675
|
function toStoredContentItem(answer) {
|
|
6528
7676
|
return {
|
|
@@ -6550,8 +7698,8 @@ function orderContentsForRequest(answers, urls) {
|
|
|
6550
7698
|
}
|
|
6551
7699
|
}
|
|
6552
7700
|
const ordered = [];
|
|
6553
|
-
for (const
|
|
6554
|
-
const bucket = byUrl.get(canonicalizeUrl(
|
|
7701
|
+
for (const url2 of urls) {
|
|
7702
|
+
const bucket = byUrl.get(canonicalizeUrl(url2));
|
|
6555
7703
|
const next = bucket?.shift();
|
|
6556
7704
|
if (next) {
|
|
6557
7705
|
ordered.push(next);
|
|
@@ -6563,12 +7711,12 @@ function orderContentsForRequest(answers, urls) {
|
|
|
6563
7711
|
ordered.push(...extras);
|
|
6564
7712
|
return ordered.length > 0 ? ordered : answers;
|
|
6565
7713
|
}
|
|
6566
|
-
function buildContentsCacheKey(
|
|
7714
|
+
function buildContentsCacheKey(url2, providerId, options) {
|
|
6567
7715
|
return [
|
|
6568
7716
|
"web-contents",
|
|
6569
7717
|
`v${CONTENT_CACHE_VERSION}`,
|
|
6570
7718
|
providerId,
|
|
6571
|
-
hashString(
|
|
7719
|
+
hashString(url2),
|
|
6572
7720
|
hashOptions(options)
|
|
6573
7721
|
].join(":");
|
|
6574
7722
|
}
|
|
@@ -6594,24 +7742,24 @@ function resolveContentsProvider(config, cwd, explicitProvider) {
|
|
|
6594
7742
|
);
|
|
6595
7743
|
return isProviderCapabilityReady(status) ? provider : void 0;
|
|
6596
7744
|
}
|
|
6597
|
-
function canonicalizeUrl(
|
|
7745
|
+
function canonicalizeUrl(url2) {
|
|
6598
7746
|
try {
|
|
6599
|
-
const parsed = new URL(
|
|
7747
|
+
const parsed = new URL(url2);
|
|
6600
7748
|
parsed.hash = "";
|
|
6601
7749
|
return parsed.toString();
|
|
6602
7750
|
} catch {
|
|
6603
|
-
return
|
|
7751
|
+
return url2.trim();
|
|
6604
7752
|
}
|
|
6605
7753
|
}
|
|
6606
7754
|
function normalizeBatchUrls(urls) {
|
|
6607
|
-
return [...new Set(urls.map((
|
|
7755
|
+
return [...new Set(urls.map((url2) => canonicalizeUrl(url2)).filter(Boolean))].filter((url2) => /^https?:\/\//i.test(url2)).sort();
|
|
6608
7756
|
}
|
|
6609
7757
|
function selectPrefetchUrls(urls, maxUrls) {
|
|
6610
7758
|
const limit = clampPrefetchUrlCount(maxUrls);
|
|
6611
7759
|
const seen = /* @__PURE__ */ new Set();
|
|
6612
7760
|
const selected = [];
|
|
6613
|
-
for (const
|
|
6614
|
-
const canonical = canonicalizeUrl(
|
|
7761
|
+
for (const url2 of urls) {
|
|
7762
|
+
const canonical = canonicalizeUrl(url2);
|
|
6615
7763
|
if (!/^https?:\/\//i.test(canonical) || seen.has(canonical)) {
|
|
6616
7764
|
continue;
|
|
6617
7765
|
}
|
|
@@ -6664,6 +7812,23 @@ function isContentsAnswer(value) {
|
|
|
6664
7812
|
|
|
6665
7813
|
// src/provider-config-manifests.ts
|
|
6666
7814
|
var PROVIDER_SETTINGS = {
|
|
7815
|
+
brave: {
|
|
7816
|
+
settings: [
|
|
7817
|
+
credentialSetting({
|
|
7818
|
+
id: "credentials.search",
|
|
7819
|
+
name: "search",
|
|
7820
|
+
label: "Search API key",
|
|
7821
|
+
help: "Brave Search API key. You can use a literal value, an env var name like BRAVE_SEARCH_API_KEY, or !command."
|
|
7822
|
+
}),
|
|
7823
|
+
credentialSetting({
|
|
7824
|
+
id: "credentials.answers",
|
|
7825
|
+
name: "answers",
|
|
7826
|
+
label: "Answers API key",
|
|
7827
|
+
help: "Brave Answers API key. You can use a literal value, an env var name like BRAVE_ANSWERS_API_KEY, or !command."
|
|
7828
|
+
}),
|
|
7829
|
+
baseUrlSetting()
|
|
7830
|
+
]
|
|
7831
|
+
},
|
|
6667
7832
|
claude: {
|
|
6668
7833
|
settings: [
|
|
6669
7834
|
stringSetting({
|
|
@@ -6724,19 +7889,10 @@ var PROVIDER_SETTINGS = {
|
|
|
6724
7889
|
},
|
|
6725
7890
|
cloudflare: {
|
|
6726
7891
|
settings: [
|
|
6727
|
-
|
|
6728
|
-
id: "
|
|
7892
|
+
credentialSetting({
|
|
7893
|
+
id: "credentials.api",
|
|
6729
7894
|
label: "API token",
|
|
6730
|
-
help: "Cloudflare API token for Browser Rendering. The token needs the permission `Account | Browser Rendering | Edit`. You can use a literal value, an env var name like CLOUDFLARE_API_TOKEN, or !command."
|
|
6731
|
-
secret: true,
|
|
6732
|
-
getValue: (config) => config?.apiToken,
|
|
6733
|
-
setValue: (config, value) => {
|
|
6734
|
-
assignOptionalString(
|
|
6735
|
-
config,
|
|
6736
|
-
"apiToken",
|
|
6737
|
-
value
|
|
6738
|
-
);
|
|
6739
|
-
}
|
|
7895
|
+
help: "Cloudflare API token for Browser Rendering. The token needs the permission `Account | Browser Rendering | Edit`. You can use a literal value, an env var name like CLOUDFLARE_API_TOKEN, or !command."
|
|
6740
7896
|
}),
|
|
6741
7897
|
stringSetting({
|
|
6742
7898
|
id: "accountId",
|
|
@@ -6963,7 +8119,7 @@ var PROVIDER_SETTINGS = {
|
|
|
6963
8119
|
},
|
|
6964
8120
|
exa: {
|
|
6965
8121
|
settings: [
|
|
6966
|
-
|
|
8122
|
+
credentialSetting(),
|
|
6967
8123
|
baseUrlSetting(),
|
|
6968
8124
|
valuesSetting({
|
|
6969
8125
|
id: "exaSearchType",
|
|
@@ -7020,11 +8176,11 @@ var PROVIDER_SETTINGS = {
|
|
|
7020
8176
|
]
|
|
7021
8177
|
},
|
|
7022
8178
|
firecrawl: {
|
|
7023
|
-
settings: [
|
|
8179
|
+
settings: [credentialSetting(), baseUrlSetting()]
|
|
7024
8180
|
},
|
|
7025
8181
|
gemini: {
|
|
7026
8182
|
settings: [
|
|
7027
|
-
|
|
8183
|
+
credentialSetting(),
|
|
7028
8184
|
valuesSetting({
|
|
7029
8185
|
id: "geminiApiVersion",
|
|
7030
8186
|
label: "API version",
|
|
@@ -7086,14 +8242,14 @@ var PROVIDER_SETTINGS = {
|
|
|
7086
8242
|
]
|
|
7087
8243
|
},
|
|
7088
8244
|
linkup: {
|
|
7089
|
-
settings: [
|
|
8245
|
+
settings: [credentialSetting(), baseUrlSetting()]
|
|
7090
8246
|
},
|
|
7091
8247
|
ollama: {
|
|
7092
|
-
settings: [
|
|
8248
|
+
settings: [credentialSetting(), baseUrlSetting()]
|
|
7093
8249
|
},
|
|
7094
8250
|
openai: {
|
|
7095
8251
|
settings: [
|
|
7096
|
-
|
|
8252
|
+
credentialSetting(),
|
|
7097
8253
|
baseUrlSetting(),
|
|
7098
8254
|
stringSetting({
|
|
7099
8255
|
id: "openaiSearchModel",
|
|
@@ -7197,11 +8353,11 @@ var PROVIDER_SETTINGS = {
|
|
|
7197
8353
|
]
|
|
7198
8354
|
},
|
|
7199
8355
|
perplexity: {
|
|
7200
|
-
settings: [
|
|
8356
|
+
settings: [credentialSetting(), baseUrlSetting()]
|
|
7201
8357
|
},
|
|
7202
8358
|
parallel: {
|
|
7203
8359
|
settings: [
|
|
7204
|
-
|
|
8360
|
+
credentialSetting(),
|
|
7205
8361
|
baseUrlSetting(),
|
|
7206
8362
|
valuesSetting({
|
|
7207
8363
|
id: "parallelSearchMode",
|
|
@@ -7263,14 +8419,14 @@ var PROVIDER_SETTINGS = {
|
|
|
7263
8419
|
]
|
|
7264
8420
|
},
|
|
7265
8421
|
serper: {
|
|
7266
|
-
settings: [
|
|
8422
|
+
settings: [credentialSetting(), baseUrlSetting()]
|
|
7267
8423
|
},
|
|
7268
8424
|
tavily: {
|
|
7269
|
-
settings: [
|
|
8425
|
+
settings: [credentialSetting(), baseUrlSetting()]
|
|
7270
8426
|
},
|
|
7271
8427
|
valyu: {
|
|
7272
8428
|
settings: [
|
|
7273
|
-
|
|
8429
|
+
credentialSetting(),
|
|
7274
8430
|
baseUrlSetting(),
|
|
7275
8431
|
valuesSetting({
|
|
7276
8432
|
id: "valyuSearchType",
|
|
@@ -7353,19 +8509,22 @@ function valuesSetting(setting) {
|
|
|
7353
8509
|
...setting
|
|
7354
8510
|
};
|
|
7355
8511
|
}
|
|
7356
|
-
function
|
|
8512
|
+
function credentialSetting(options = {}) {
|
|
8513
|
+
const name = options.name ?? "api";
|
|
7357
8514
|
return stringSetting({
|
|
7358
|
-
id:
|
|
7359
|
-
label: "API key",
|
|
7360
|
-
help: "Provider
|
|
8515
|
+
id: options.id ?? `credentials.${name}`,
|
|
8516
|
+
label: options.label ?? "API key",
|
|
8517
|
+
help: options.help ?? "Provider credential. You can use a literal value, an env var name like EXA_API_KEY, or !command.",
|
|
7361
8518
|
secret: true,
|
|
7362
|
-
getValue: (config) => config?.
|
|
8519
|
+
getValue: (config) => config?.credentials?.[name],
|
|
7363
8520
|
setValue: (config, value) => {
|
|
7364
|
-
|
|
7365
|
-
|
|
7366
|
-
|
|
7367
|
-
|
|
7368
|
-
|
|
8521
|
+
const trimmed = value.trim();
|
|
8522
|
+
if (!trimmed) {
|
|
8523
|
+
delete config.credentials?.[name];
|
|
8524
|
+
} else {
|
|
8525
|
+
config.credentials = { ...config.credentials ?? {}, [name]: trimmed };
|
|
8526
|
+
}
|
|
8527
|
+
cleanupEmpty(config, "credentials");
|
|
7369
8528
|
}
|
|
7370
8529
|
});
|
|
7371
8530
|
}
|
|
@@ -7776,18 +8935,18 @@ function registerWebSearchTool(pi, providerIds) {
|
|
|
7776
8935
|
name: "web_search",
|
|
7777
8936
|
label: "Web Search",
|
|
7778
8937
|
description: `Find likely sources on the public web for up to ${MAX_SEARCH_QUERIES} queries in a single call and return titles, URLs, and snippets grouped by query. Output is truncated to ${DEFAULT_MAX_LINES} lines or ${formatSize(DEFAULT_MAX_BYTES)} when needed.`,
|
|
7779
|
-
promptGuidelines: [
|
|
8938
|
+
promptGuidelines: buildPromptGuidelines("search", selectedProviderId, [
|
|
7780
8939
|
"Batch related searches when grouped comparison matters; use separate sibling web_search calls when independent results should surface as soon as they are ready."
|
|
7781
|
-
],
|
|
7782
|
-
parameters:
|
|
8940
|
+
]),
|
|
8941
|
+
parameters: Type16.Object(
|
|
7783
8942
|
{
|
|
7784
|
-
queries:
|
|
8943
|
+
queries: Type16.Array(Type16.String({ minLength: 1 }), {
|
|
7785
8944
|
minItems: 1,
|
|
7786
8945
|
maxItems: MAX_SEARCH_QUERIES,
|
|
7787
8946
|
description: `One or more search queries to run in one call (max ${MAX_SEARCH_QUERIES})`
|
|
7788
8947
|
}),
|
|
7789
|
-
maxResults:
|
|
7790
|
-
|
|
8948
|
+
maxResults: Type16.Optional(
|
|
8949
|
+
Type16.Integer({
|
|
7791
8950
|
minimum: 1,
|
|
7792
8951
|
maximum: maxAllowedResults,
|
|
7793
8952
|
description: `Maximum number of results to return (default: ${DEFAULT_MAX_RESULTS})`
|
|
@@ -7838,9 +8997,9 @@ function registerWebContentsTool(pi, providerIds) {
|
|
|
7838
8997
|
name: "web_contents",
|
|
7839
8998
|
label: "Web Contents",
|
|
7840
8999
|
description: "Read and extract the main contents of one or more web pages. Batch related pages together, or use separate sibling calls when each page can be acted on independently.",
|
|
7841
|
-
parameters:
|
|
9000
|
+
parameters: Type16.Object(
|
|
7842
9001
|
{
|
|
7843
|
-
urls:
|
|
9002
|
+
urls: Type16.Array(Type16.String({ minLength: 1 }), {
|
|
7844
9003
|
minItems: 1,
|
|
7845
9004
|
description: "One or more URLs to extract"
|
|
7846
9005
|
}),
|
|
@@ -7851,6 +9010,7 @@ function registerWebContentsTool(pi, providerIds) {
|
|
|
7851
9010
|
},
|
|
7852
9011
|
{ additionalProperties: false }
|
|
7853
9012
|
),
|
|
9013
|
+
promptGuidelines: buildPromptGuidelines("contents", selectedProviderId, []),
|
|
7854
9014
|
async execute(_toolCallId, params, signal, onUpdate, ctx) {
|
|
7855
9015
|
return executeProviderTool({
|
|
7856
9016
|
config: await loadConfig(),
|
|
@@ -7892,9 +9052,9 @@ function registerWebAnswerTool(pi, providerIds) {
|
|
|
7892
9052
|
name: "web_answer",
|
|
7893
9053
|
label: "Web Answer",
|
|
7894
9054
|
description: `Answer one or more simple factual questions using web-grounded evidence (up to ${MAX_SEARCH_QUERIES} per call). Prefer web_search plus web_contents when source selection matters, and web_research for multi-step investigations.`,
|
|
7895
|
-
parameters:
|
|
9055
|
+
parameters: Type16.Object(
|
|
7896
9056
|
{
|
|
7897
|
-
queries:
|
|
9057
|
+
queries: Type16.Array(Type16.String({ minLength: 1 }), {
|
|
7898
9058
|
minItems: 1,
|
|
7899
9059
|
maxItems: MAX_SEARCH_QUERIES,
|
|
7900
9060
|
description: `One or more simple factual questions to answer in one call (max ${MAX_SEARCH_QUERIES})`
|
|
@@ -7906,11 +9066,11 @@ function registerWebAnswerTool(pi, providerIds) {
|
|
|
7906
9066
|
},
|
|
7907
9067
|
{ additionalProperties: false }
|
|
7908
9068
|
),
|
|
7909
|
-
promptGuidelines: [
|
|
9069
|
+
promptGuidelines: buildPromptGuidelines("answer", selectedProviderId, [
|
|
7910
9070
|
"Use web_answer as a quick grounded-answer shortcut for simple factual questions, not as a replacement for inspecting sources or doing deeper research.",
|
|
7911
9071
|
"Prefer web_search plus web_contents when source selection matters or primary sources need direct inspection; prefer web_research for open-ended, controversial, or multi-step investigations.",
|
|
7912
9072
|
"Batch related questions when the answers belong together; use separate sibling web_answer calls when earlier independent answers can unblock the next step."
|
|
7913
|
-
],
|
|
9073
|
+
]),
|
|
7914
9074
|
async execute(_toolCallId, params, signal, onUpdate, ctx) {
|
|
7915
9075
|
return executeAnswerTool({
|
|
7916
9076
|
config: await loadConfig(),
|
|
@@ -7952,9 +9112,9 @@ function registerWebResearchTool(pi, webResearchLifecycle, providerIds) {
|
|
|
7952
9112
|
name: "web_research",
|
|
7953
9113
|
label: "Web Research",
|
|
7954
9114
|
description: "Start a long-running web research job. Returns immediately with a dispatch notice; the final report is saved to a file and posted later as a custom message.",
|
|
7955
|
-
parameters:
|
|
9115
|
+
parameters: Type16.Object(
|
|
7956
9116
|
{
|
|
7957
|
-
input:
|
|
9117
|
+
input: Type16.String({ description: "Research brief or question" }),
|
|
7958
9118
|
...optionalField(
|
|
7959
9119
|
"options",
|
|
7960
9120
|
buildStructuredOptionsSchema("research", selectedProviderId)
|
|
@@ -7962,10 +9122,11 @@ function registerWebResearchTool(pi, webResearchLifecycle, providerIds) {
|
|
|
7962
9122
|
},
|
|
7963
9123
|
{ additionalProperties: false }
|
|
7964
9124
|
),
|
|
7965
|
-
promptGuidelines: [
|
|
9125
|
+
promptGuidelines: buildPromptGuidelines("research", selectedProviderId, [
|
|
7966
9126
|
"Use this tool for deep investigations that can finish asynchronously.",
|
|
9127
|
+
"Pass only input unless the user explicitly requests provider options.",
|
|
7967
9128
|
"Do not expect the final report in the same turn; tell the user that web research has started and wait for the completion message with the saved report path."
|
|
7968
|
-
],
|
|
9129
|
+
]),
|
|
7969
9130
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
7970
9131
|
return dispatchWebResearch({
|
|
7971
9132
|
pi,
|
|
@@ -8092,13 +9253,23 @@ function getSearchMaxResultsLimit(providerId) {
|
|
|
8092
9253
|
const capabilities = PROVIDERS_BY_ID[providerId].capabilities;
|
|
8093
9254
|
return capabilities.search?.limits?.maxResults ?? MAX_ALLOWED_RESULTS;
|
|
8094
9255
|
}
|
|
9256
|
+
function buildPromptGuidelines(capability, providerId, baseGuidelines) {
|
|
9257
|
+
return [
|
|
9258
|
+
...baseGuidelines,
|
|
9259
|
+
...getProviderCapabilityPromptGuidelines(capability, providerId)
|
|
9260
|
+
];
|
|
9261
|
+
}
|
|
9262
|
+
function getProviderCapabilityPromptGuidelines(capability, providerId) {
|
|
9263
|
+
const capabilities = PROVIDERS_BY_ID[providerId].capabilities;
|
|
9264
|
+
return capabilities[capability]?.promptGuidelines ?? [];
|
|
9265
|
+
}
|
|
8095
9266
|
function optionalField(name, schema) {
|
|
8096
9267
|
return schema ? { [name]: schema } : {};
|
|
8097
9268
|
}
|
|
8098
9269
|
function buildStructuredOptionsSchema(capability, providerId) {
|
|
8099
9270
|
const providerSchema = resolveProviderOptionsSchema(capability, providerId);
|
|
8100
9271
|
const schema = buildToolOptionsSchema(capability, providerSchema);
|
|
8101
|
-
return schema ?
|
|
9272
|
+
return schema ? Type16.Optional(schema) : void 0;
|
|
8102
9273
|
}
|
|
8103
9274
|
function resolveProviderOptionsSchema(capability, providerId) {
|
|
8104
9275
|
if (!providerId) {
|
|
@@ -8447,8 +9618,11 @@ function formatAnswerResponses(outcomes) {
|
|
|
8447
9618
|
).join("\n\n");
|
|
8448
9619
|
}
|
|
8449
9620
|
function formatAnswerOutcomeSection(outcome, index, total) {
|
|
8450
|
-
const heading = total > 1 ? `## Question ${index + 1}: ${formatAnswerHeading(outcome.query)}` : `## ${formatAnswerHeading(outcome.query)}`;
|
|
8451
9621
|
const body = outcome.response ? outcome.response.text : `Answer failed: ${outcome.error ?? "Unknown error."}`;
|
|
9622
|
+
if (total === 1) {
|
|
9623
|
+
return body;
|
|
9624
|
+
}
|
|
9625
|
+
const heading = `## Question ${index + 1}: ${formatAnswerHeading(outcome.query)}`;
|
|
8452
9626
|
return `${heading}
|
|
8453
9627
|
|
|
8454
9628
|
${body}`;
|
|
@@ -8501,7 +9675,7 @@ async function executeProviderOperation({
|
|
|
8501
9675
|
`Fetching contents via ${provider.label} for ${(urls ?? []).length} URL(s)`
|
|
8502
9676
|
);
|
|
8503
9677
|
} else if (capability === "answer") {
|
|
8504
|
-
onProgress?.(`Answering via ${provider.label}
|
|
9678
|
+
onProgress?.(`Answering via ${provider.label}`);
|
|
8505
9679
|
} else if (capability === "research") {
|
|
8506
9680
|
onProgress?.(`Researching via ${provider.label}`);
|
|
8507
9681
|
}
|
|
@@ -8922,7 +10096,7 @@ async function executeBatchedContentsTool({
|
|
|
8922
10096
|
batchProgress.start();
|
|
8923
10097
|
const settled = await Promise.allSettled(
|
|
8924
10098
|
urls.map(
|
|
8925
|
-
(
|
|
10099
|
+
(url2, index) => executeProviderOperation({
|
|
8926
10100
|
capability: "contents",
|
|
8927
10101
|
config,
|
|
8928
10102
|
provider,
|
|
@@ -8930,7 +10104,7 @@ async function executeBatchedContentsTool({
|
|
|
8930
10104
|
ctx,
|
|
8931
10105
|
signal,
|
|
8932
10106
|
options,
|
|
8933
|
-
urls: [
|
|
10107
|
+
urls: [url2],
|
|
8934
10108
|
onProgress: void 0,
|
|
8935
10109
|
executionOverride: executionOverrides?.[index]
|
|
8936
10110
|
}).then(
|
|
@@ -8989,9 +10163,9 @@ async function executeBatchedContentsTool({
|
|
|
8989
10163
|
}
|
|
8990
10164
|
return {
|
|
8991
10165
|
provider: successful[0]?.response.provider ?? provider.id,
|
|
8992
|
-
answers: urls.map((
|
|
8993
|
-
return answersByUrl.get(
|
|
8994
|
-
url,
|
|
10166
|
+
answers: urls.map((url2) => {
|
|
10167
|
+
return answersByUrl.get(url2) ?? {
|
|
10168
|
+
url: url2,
|
|
8995
10169
|
error: "No content returned for this URL."
|
|
8996
10170
|
};
|
|
8997
10171
|
})
|
|
@@ -9094,13 +10268,21 @@ function renderListCallHeader(toolName, items, theme, suffix, options = {}) {
|
|
|
9094
10268
|
headerLine + " ".repeat(Math.max(0, width - visibleWidth(headerLine)))
|
|
9095
10269
|
);
|
|
9096
10270
|
for (const item of normalizedItems) {
|
|
9097
|
-
const
|
|
9098
|
-
|
|
9099
|
-
width
|
|
9100
|
-
)
|
|
9101
|
-
|
|
9102
|
-
|
|
9103
|
-
|
|
10271
|
+
const itemLines = options.forceMultiline ? wrapTextWithAnsi(
|
|
10272
|
+
theme.fg("accent", item),
|
|
10273
|
+
Math.max(1, width - 2)
|
|
10274
|
+
).map((line) => ` ${line}`) : [
|
|
10275
|
+
truncateToWidth(
|
|
10276
|
+
` ${theme.fg("accent", truncateInline(item, 120))}`,
|
|
10277
|
+
width
|
|
10278
|
+
)
|
|
10279
|
+
];
|
|
10280
|
+
for (const itemLine of itemLines) {
|
|
10281
|
+
const line = truncateToWidth(itemLine, width);
|
|
10282
|
+
lines.push(
|
|
10283
|
+
line + " ".repeat(Math.max(0, width - visibleWidth(line)))
|
|
10284
|
+
);
|
|
10285
|
+
}
|
|
9104
10286
|
}
|
|
9105
10287
|
return lines;
|
|
9106
10288
|
}
|
|
@@ -9124,15 +10306,7 @@ function renderQuestionCallHeader(params, theme) {
|
|
|
9124
10306
|
);
|
|
9125
10307
|
}
|
|
9126
10308
|
function renderResearchCallHeader(params, theme) {
|
|
9127
|
-
return renderListCallHeader(
|
|
9128
|
-
"web_research",
|
|
9129
|
-
[params.input],
|
|
9130
|
-
theme,
|
|
9131
|
-
void 0,
|
|
9132
|
-
{
|
|
9133
|
-
forceMultiline: true
|
|
9134
|
-
}
|
|
9135
|
-
);
|
|
10309
|
+
return renderListCallHeader("web_research", [params.input], theme);
|
|
9136
10310
|
}
|
|
9137
10311
|
function renderSearchToolResult(result, expanded, isPartial, theme) {
|
|
9138
10312
|
const text = extractTextContent(result.content);
|
|
@@ -9153,7 +10327,18 @@ function renderWebResearchDispatchResult(result, expanded, theme) {
|
|
|
9153
10327
|
const text = extractTextContent(result.content) ?? "Started web research.";
|
|
9154
10328
|
const details = isWebResearchRequest(result.details) ? result.details : void 0;
|
|
9155
10329
|
if (expanded) {
|
|
9156
|
-
|
|
10330
|
+
const expandedText = details ? [
|
|
10331
|
+
text,
|
|
10332
|
+
"",
|
|
10333
|
+
"## Research brief",
|
|
10334
|
+
"",
|
|
10335
|
+
details.input,
|
|
10336
|
+
"",
|
|
10337
|
+
"## Report path",
|
|
10338
|
+
"",
|
|
10339
|
+
`\`${details.outputPath}\``
|
|
10340
|
+
].join("\n") : text;
|
|
10341
|
+
return renderMarkdownBlock(expandedText);
|
|
9157
10342
|
}
|
|
9158
10343
|
const summary = details ? `Started web research via ${PROVIDERS_BY_ID[details.provider]?.label ?? details.provider}` : text;
|
|
9159
10344
|
let summaryText = theme.fg("success", summary);
|
|
@@ -10410,17 +11595,17 @@ function renderCollapsedSearchSummary(details, text, theme) {
|
|
|
10410
11595
|
const resultCount = typeof details?.resultCount === "number" ? details.resultCount : inferSearchResultCount(text);
|
|
10411
11596
|
const failedQueryCount = typeof details?.failedQueryCount === "number" ? details.failedQueryCount : inferSearchFailureCount(text);
|
|
10412
11597
|
const providerLabel = typeof details?.provider === "string" ? PROVIDERS_BY_ID[details.provider]?.label ?? details.provider : void 0;
|
|
10413
|
-
let
|
|
11598
|
+
let base2 = buildSearchSummaryText({
|
|
10414
11599
|
queryCount,
|
|
10415
11600
|
resultCount
|
|
10416
11601
|
});
|
|
10417
11602
|
if (providerLabel) {
|
|
10418
|
-
|
|
11603
|
+
base2 = `${base2} via ${providerLabel}`;
|
|
10419
11604
|
}
|
|
10420
11605
|
if (failedQueryCount && failedQueryCount > 0) {
|
|
10421
|
-
|
|
11606
|
+
base2 += `, ${failedQueryCount} failed`;
|
|
10422
11607
|
}
|
|
10423
|
-
let summary = theme.fg("success",
|
|
11608
|
+
let summary = theme.fg("success", base2);
|
|
10424
11609
|
summary += theme.fg("muted", ` (${getExpandHint()})`);
|
|
10425
11610
|
return new Text(summary, 0, 0);
|
|
10426
11611
|
}
|
|
@@ -10500,8 +11685,11 @@ function formatSearchResponses(outcomes, prefetch) {
|
|
|
10500
11685
|
Background contents prefetch started via ${prefetch.provider} for ${prefetch.urlCount} URL(s).`;
|
|
10501
11686
|
}
|
|
10502
11687
|
function formatSearchOutcomeSection(outcome, index, total) {
|
|
10503
|
-
const heading = total > 1 ? `## Query ${index + 1}: ${formatSearchHeading(outcome.query)}` : `## ${formatSearchHeading(outcome.query)}`;
|
|
10504
11688
|
const body = outcome.response ? formatSearchResponseMarkdown(outcome.response) : `Search failed: ${outcome.error ?? "Unknown error."}`;
|
|
11689
|
+
if (total === 1) {
|
|
11690
|
+
return body;
|
|
11691
|
+
}
|
|
11692
|
+
const heading = `## Query ${index + 1}: ${formatSearchHeading(outcome.query)}`;
|
|
10505
11693
|
return `${heading}
|
|
10506
11694
|
|
|
10507
11695
|
${body}`;
|
|
@@ -10531,8 +11719,8 @@ function formatSearchResponseMarkdown(response) {
|
|
|
10531
11719
|
return lines.join("\n");
|
|
10532
11720
|
}).join("\n\n");
|
|
10533
11721
|
}
|
|
10534
|
-
function formatMarkdownLink(label,
|
|
10535
|
-
return `[${escapeMarkdownLinkLabel(label)}](<${
|
|
11722
|
+
function formatMarkdownLink(label, url2) {
|
|
11723
|
+
return `[${escapeMarkdownLinkLabel(label)}](<${url2}>)`;
|
|
10536
11724
|
}
|
|
10537
11725
|
function escapeMarkdownLinkLabel(text) {
|
|
10538
11726
|
return cleanSingleLine(text).replaceAll("\\", "\\\\").replaceAll("]", "\\]");
|