pi-web-providers 2.3.0 → 2.4.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 +33 -0
- package/dist/index.js +329 -69
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -13,6 +13,9 @@ off entirely.
|
|
|
13
13
|
|
|
14
14
|
## ✨ Features
|
|
15
15
|
|
|
16
|
+
- **Multiple providers**: Claude, Cloudflare, Codex, Exa, Firecrawl,
|
|
17
|
+
Gemini, Linkup, OpenAI, Perplexity, Parallel, Serper,
|
|
18
|
+
[Tavily](https://tavily.com), Valyu
|
|
16
19
|
- **Provider-aware tool options**: pi only exposes the provider settings that
|
|
17
20
|
actually apply to the backend you selected, so tool calls are easier to
|
|
18
21
|
discover and harder to get wrong
|
|
@@ -61,6 +64,7 @@ Each tool can be routed to any compatible provider:
|
|
|
61
64
|
| **OpenAI** | ✔ | | ✔ | ✔ | `OPENAI_API_KEY` |
|
|
62
65
|
| **Parallel** | ✔ | ✔ | | | `PARALLEL_API_KEY` |
|
|
63
66
|
| **Perplexity** | ✔ | | ✔ | ✔ | `PERPLEXITY_API_KEY` |
|
|
67
|
+
| **Serper** | ✔ | | | | `SERPER_API_KEY` |
|
|
64
68
|
| **Tavily** | ✔ | ✔ | | | `TAVILY_API_KEY` |
|
|
65
69
|
| **Valyu** | ✔ | ✔ | ✔ | ✔ | `VALYU_API_KEY` |
|
|
66
70
|
|
|
@@ -377,6 +381,35 @@ call.
|
|
|
377
381
|
|
|
378
382
|
</details>
|
|
379
383
|
|
|
384
|
+
<details>
|
|
385
|
+
<summary><strong>Serper</strong></summary>
|
|
386
|
+
|
|
387
|
+
- API: Serper HTTP API
|
|
388
|
+
- Supports `web_search` via Serper's Google search endpoint
|
|
389
|
+
- Good fit for fast, straightforward Google-style organic search results
|
|
390
|
+
- Exposes search options `gl`, `hl`, `location`, `page`, and `autocorrect`
|
|
391
|
+
- Preserves rich metadata from Serper responses, including ranking position,
|
|
392
|
+
sitelinks, attributes, and top-level response context such as
|
|
393
|
+
`knowledgeGraph`, `answerBox`, `peopleAlsoAsk`, and `relatedSearches`
|
|
394
|
+
- Optional `baseUrl` overrides are supported for proxies and testing
|
|
395
|
+
|
|
396
|
+
Minimal config:
|
|
397
|
+
|
|
398
|
+
```json
|
|
399
|
+
{
|
|
400
|
+
"tools": {
|
|
401
|
+
"search": "serper"
|
|
402
|
+
},
|
|
403
|
+
"providers": {
|
|
404
|
+
"serper": {
|
|
405
|
+
"apiKey": "SERPER_API_KEY"
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
</details>
|
|
412
|
+
|
|
380
413
|
<details>
|
|
381
414
|
<summary><strong>Tavily</strong></summary>
|
|
382
415
|
|
package/dist/index.js
CHANGED
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
visibleWidth,
|
|
24
24
|
wrapTextWithAnsi
|
|
25
25
|
} from "@mariozechner/pi-tui";
|
|
26
|
-
import { Type as
|
|
26
|
+
import { Type as Type16 } from "@sinclair/typebox";
|
|
27
27
|
|
|
28
28
|
// src/config.ts
|
|
29
29
|
import { execSync } from "node:child_process";
|
|
@@ -44,6 +44,7 @@ var PROVIDER_TOOLS_BY_ID = {
|
|
|
44
44
|
openai: ["search", "answer", "research"],
|
|
45
45
|
parallel: ["search", "contents"],
|
|
46
46
|
perplexity: ["search", "answer", "research"],
|
|
47
|
+
serper: ["search"],
|
|
47
48
|
tavily: ["search", "contents"],
|
|
48
49
|
valyu: ["search", "contents", "answer", "research"]
|
|
49
50
|
};
|
|
@@ -90,6 +91,7 @@ var PROVIDER_IDS = [
|
|
|
90
91
|
"openai",
|
|
91
92
|
"parallel",
|
|
92
93
|
"perplexity",
|
|
94
|
+
"serper",
|
|
93
95
|
"tavily",
|
|
94
96
|
"valyu"
|
|
95
97
|
];
|
|
@@ -289,6 +291,29 @@ function normalizeProvider(providerId, raw, source) {
|
|
|
289
291
|
case "linkup":
|
|
290
292
|
case "parallel":
|
|
291
293
|
case "perplexity":
|
|
294
|
+
return parseProviderWithShape(
|
|
295
|
+
raw,
|
|
296
|
+
source,
|
|
297
|
+
providerId,
|
|
298
|
+
{
|
|
299
|
+
apiKey: readOptionalString,
|
|
300
|
+
baseUrl: readOptionalString,
|
|
301
|
+
options: readOptionalObject,
|
|
302
|
+
settings: parseOptionalExecutionSettings
|
|
303
|
+
}
|
|
304
|
+
);
|
|
305
|
+
case "serper":
|
|
306
|
+
return parseProviderWithShape(raw, source, providerId, {
|
|
307
|
+
apiKey: readOptionalString,
|
|
308
|
+
baseUrl: readOptionalString,
|
|
309
|
+
options: (value, innerSource, field) => parseOptionalCapabilityOptions(
|
|
310
|
+
value,
|
|
311
|
+
innerSource,
|
|
312
|
+
field,
|
|
313
|
+
["search"]
|
|
314
|
+
),
|
|
315
|
+
settings: parseOptionalExecutionSettings
|
|
316
|
+
});
|
|
292
317
|
case "tavily":
|
|
293
318
|
return parseProviderWithShape(raw, source, providerId, {
|
|
294
319
|
apiKey: readOptionalString,
|
|
@@ -5107,56 +5132,287 @@ function buildRequestOptions4(context) {
|
|
|
5107
5132
|
return context.signal ? { signal: context.signal } : void 0;
|
|
5108
5133
|
}
|
|
5109
5134
|
|
|
5110
|
-
// src/providers/
|
|
5135
|
+
// src/providers/serper.ts
|
|
5111
5136
|
import { Type as Type13 } from "@sinclair/typebox";
|
|
5137
|
+
var DEFAULT_BASE_URL = "https://google.serper.dev";
|
|
5138
|
+
var serperSearchOptionsSchema = Type13.Object(
|
|
5139
|
+
{
|
|
5140
|
+
gl: Type13.Optional(
|
|
5141
|
+
Type13.String({
|
|
5142
|
+
description: "Country code hint for Google results (for example 'us')."
|
|
5143
|
+
})
|
|
5144
|
+
),
|
|
5145
|
+
hl: Type13.Optional(
|
|
5146
|
+
Type13.String({
|
|
5147
|
+
description: "Language code hint for Google results (for example 'en')."
|
|
5148
|
+
})
|
|
5149
|
+
),
|
|
5150
|
+
location: Type13.Optional(
|
|
5151
|
+
Type13.String({
|
|
5152
|
+
description: "Geographic location hint for Google results."
|
|
5153
|
+
})
|
|
5154
|
+
),
|
|
5155
|
+
page: Type13.Optional(
|
|
5156
|
+
Type13.Integer({
|
|
5157
|
+
minimum: 1,
|
|
5158
|
+
description: "1-based results page to request from Serper."
|
|
5159
|
+
})
|
|
5160
|
+
),
|
|
5161
|
+
autocorrect: Type13.Optional(
|
|
5162
|
+
Type13.Boolean({
|
|
5163
|
+
description: "Enable or disable Serper query autocorrection."
|
|
5164
|
+
})
|
|
5165
|
+
)
|
|
5166
|
+
},
|
|
5167
|
+
{ description: "Serper search options." }
|
|
5168
|
+
);
|
|
5169
|
+
var serperAdapter = {
|
|
5170
|
+
id: "serper",
|
|
5171
|
+
label: "Serper",
|
|
5172
|
+
docsUrl: "https://serper.dev/",
|
|
5173
|
+
tools: ["search"],
|
|
5174
|
+
getToolOptionsSchema(capability) {
|
|
5175
|
+
switch (capability) {
|
|
5176
|
+
case "search":
|
|
5177
|
+
return serperSearchOptionsSchema;
|
|
5178
|
+
default:
|
|
5179
|
+
return void 0;
|
|
5180
|
+
}
|
|
5181
|
+
},
|
|
5182
|
+
createTemplate() {
|
|
5183
|
+
return {
|
|
5184
|
+
apiKey: "SERPER_API_KEY",
|
|
5185
|
+
options: {}
|
|
5186
|
+
};
|
|
5187
|
+
},
|
|
5188
|
+
getConfigForCapability(capability, config) {
|
|
5189
|
+
switch (capability) {
|
|
5190
|
+
case "search":
|
|
5191
|
+
return {
|
|
5192
|
+
apiKey: config.apiKey,
|
|
5193
|
+
baseUrl: config.baseUrl,
|
|
5194
|
+
options: config.options?.search,
|
|
5195
|
+
settings: config.settings
|
|
5196
|
+
};
|
|
5197
|
+
default:
|
|
5198
|
+
return config;
|
|
5199
|
+
}
|
|
5200
|
+
},
|
|
5201
|
+
getCapabilityStatus(config) {
|
|
5202
|
+
return getApiKeyStatus(config?.apiKey);
|
|
5203
|
+
},
|
|
5204
|
+
buildPlan(request, config) {
|
|
5205
|
+
return buildProviderPlan({
|
|
5206
|
+
request,
|
|
5207
|
+
config,
|
|
5208
|
+
providerId: serperAdapter.id,
|
|
5209
|
+
providerLabel: serperAdapter.label,
|
|
5210
|
+
handlers: {
|
|
5211
|
+
search: {
|
|
5212
|
+
execute: (searchRequest, providerConfig, context) => serperAdapter.search(
|
|
5213
|
+
searchRequest.query,
|
|
5214
|
+
searchRequest.maxResults,
|
|
5215
|
+
providerConfig,
|
|
5216
|
+
context,
|
|
5217
|
+
searchRequest.options
|
|
5218
|
+
)
|
|
5219
|
+
}
|
|
5220
|
+
}
|
|
5221
|
+
});
|
|
5222
|
+
},
|
|
5223
|
+
async search(query2, maxResults, config, context, options) {
|
|
5224
|
+
const apiKey = resolveConfigValue(config.apiKey);
|
|
5225
|
+
if (!apiKey) {
|
|
5226
|
+
throw new Error("is missing an API key");
|
|
5227
|
+
}
|
|
5228
|
+
const defaults = stripLocalExecutionOptions(asJsonObject(config.options?.search)) ?? {};
|
|
5229
|
+
const runtimeOptions = stripLocalExecutionOptions(asJsonObject(options));
|
|
5230
|
+
const {
|
|
5231
|
+
q: _ignoredQuery,
|
|
5232
|
+
num: _ignoredNum,
|
|
5233
|
+
...providerOptions
|
|
5234
|
+
} = {
|
|
5235
|
+
...defaults,
|
|
5236
|
+
...runtimeOptions ?? {}
|
|
5237
|
+
};
|
|
5238
|
+
const response = await fetch(joinUrl(resolveConfigValue(config.baseUrl)), {
|
|
5239
|
+
method: "POST",
|
|
5240
|
+
headers: {
|
|
5241
|
+
"content-type": "application/json",
|
|
5242
|
+
"x-api-key": apiKey
|
|
5243
|
+
},
|
|
5244
|
+
body: JSON.stringify({
|
|
5245
|
+
q: query2,
|
|
5246
|
+
num: clampMaxResults(maxResults),
|
|
5247
|
+
...providerOptions
|
|
5248
|
+
}),
|
|
5249
|
+
signal: context.signal
|
|
5250
|
+
});
|
|
5251
|
+
if (!response.ok) {
|
|
5252
|
+
throw new Error(await buildHttpError(response));
|
|
5253
|
+
}
|
|
5254
|
+
const payload = await response.json();
|
|
5255
|
+
const responseRecord = asRecord3(payload) ?? {};
|
|
5256
|
+
const organic = asArray(responseRecord.organic) ?? [];
|
|
5257
|
+
const searchContext = buildSearchContext(responseRecord);
|
|
5258
|
+
return {
|
|
5259
|
+
provider: serperAdapter.id,
|
|
5260
|
+
results: organic.map((entry) => toSearchResult3(entry, searchContext)).filter(
|
|
5261
|
+
(result) => result !== null
|
|
5262
|
+
).slice(0, clampMaxResults(maxResults))
|
|
5263
|
+
};
|
|
5264
|
+
}
|
|
5265
|
+
};
|
|
5266
|
+
function joinUrl(baseUrl) {
|
|
5267
|
+
const base = (baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
5268
|
+
return `${base}/search`;
|
|
5269
|
+
}
|
|
5270
|
+
function clampMaxResults(value) {
|
|
5271
|
+
return Math.max(1, Math.min(20, Math.trunc(value || 0)));
|
|
5272
|
+
}
|
|
5273
|
+
async function buildHttpError(response) {
|
|
5274
|
+
const detail = await readErrorDetail(response);
|
|
5275
|
+
const status = `${response.status}${response.statusText ? ` ${response.statusText}` : ""}`;
|
|
5276
|
+
return detail ? `Serper API request failed (${status}): ${detail}` : `Serper API request failed (${status}).`;
|
|
5277
|
+
}
|
|
5278
|
+
async function readErrorDetail(response) {
|
|
5279
|
+
const text = (await response.text()).trim();
|
|
5280
|
+
if (!text) {
|
|
5281
|
+
return void 0;
|
|
5282
|
+
}
|
|
5283
|
+
try {
|
|
5284
|
+
const parsed = JSON.parse(text);
|
|
5285
|
+
const record = asRecord3(parsed);
|
|
5286
|
+
const detail = readString4(record?.message) ?? readString4(record?.error) ?? readString4(record?.detail);
|
|
5287
|
+
if (detail) {
|
|
5288
|
+
return detail;
|
|
5289
|
+
}
|
|
5290
|
+
return JSON.stringify(parsed);
|
|
5291
|
+
} catch {
|
|
5292
|
+
return text;
|
|
5293
|
+
}
|
|
5294
|
+
}
|
|
5295
|
+
function toSearchResult3(entry, searchContext) {
|
|
5296
|
+
const record = asRecord3(entry);
|
|
5297
|
+
if (!record) {
|
|
5298
|
+
return null;
|
|
5299
|
+
}
|
|
5300
|
+
const url = readString4(record.link) ?? "";
|
|
5301
|
+
const title = readString4(record.title) || url || "Untitled";
|
|
5302
|
+
const snippet = trimSnippet(
|
|
5303
|
+
readString4(record.snippet) ?? readString4(record.richSnippet) ?? readString4(record.date) ?? ""
|
|
5304
|
+
);
|
|
5305
|
+
const metadata = omitUndefined({
|
|
5306
|
+
source: "organic",
|
|
5307
|
+
position: readNumber(record.position),
|
|
5308
|
+
date: readString4(record.date),
|
|
5309
|
+
attributes: asRecord3(record.attributes),
|
|
5310
|
+
sitelinks: asArray(record.sitelinks),
|
|
5311
|
+
rating: readNumber(record.rating),
|
|
5312
|
+
ratingCount: readNumber(record.ratingCount),
|
|
5313
|
+
cid: readString4(record.cid),
|
|
5314
|
+
...extractExtraMetadata(record, ["title", "link", "snippet"]),
|
|
5315
|
+
...searchContext ? { searchContext } : {}
|
|
5316
|
+
});
|
|
5317
|
+
return {
|
|
5318
|
+
title,
|
|
5319
|
+
url,
|
|
5320
|
+
snippet,
|
|
5321
|
+
...Object.keys(metadata).length > 0 ? { metadata } : {}
|
|
5322
|
+
};
|
|
5323
|
+
}
|
|
5324
|
+
function buildSearchContext(response) {
|
|
5325
|
+
const context = omitUndefined({
|
|
5326
|
+
searchParameters: asRecord3(response.searchParameters),
|
|
5327
|
+
searchInformation: asRecord3(response.searchInformation),
|
|
5328
|
+
credits: readNumber(response.credits),
|
|
5329
|
+
answerBox: asRecord3(response.answerBox),
|
|
5330
|
+
knowledgeGraph: asRecord3(response.knowledgeGraph),
|
|
5331
|
+
peopleAlsoAsk: asArray(response.peopleAlsoAsk),
|
|
5332
|
+
relatedSearches: asArray(response.relatedSearches),
|
|
5333
|
+
topStories: asArray(response.topStories),
|
|
5334
|
+
news: asArray(response.news),
|
|
5335
|
+
images: asArray(response.images),
|
|
5336
|
+
videos: asArray(response.videos),
|
|
5337
|
+
places: asArray(response.places)
|
|
5338
|
+
});
|
|
5339
|
+
return Object.keys(context).length > 0 ? context : void 0;
|
|
5340
|
+
}
|
|
5341
|
+
function extractExtraMetadata(record, ignoredKeys) {
|
|
5342
|
+
return Object.fromEntries(
|
|
5343
|
+
Object.entries(record).filter(
|
|
5344
|
+
([key, value]) => !ignoredKeys.includes(key) && value !== void 0
|
|
5345
|
+
)
|
|
5346
|
+
);
|
|
5347
|
+
}
|
|
5348
|
+
function omitUndefined(value) {
|
|
5349
|
+
return Object.fromEntries(
|
|
5350
|
+
Object.entries(value).filter(([, entry]) => entry !== void 0)
|
|
5351
|
+
);
|
|
5352
|
+
}
|
|
5353
|
+
function asRecord3(value) {
|
|
5354
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
5355
|
+
}
|
|
5356
|
+
function asArray(value) {
|
|
5357
|
+
return Array.isArray(value) ? value : void 0;
|
|
5358
|
+
}
|
|
5359
|
+
function readString4(value) {
|
|
5360
|
+
return typeof value === "string" ? value : void 0;
|
|
5361
|
+
}
|
|
5362
|
+
function readNumber(value) {
|
|
5363
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
5364
|
+
}
|
|
5365
|
+
|
|
5366
|
+
// src/providers/tavily.ts
|
|
5367
|
+
import { Type as Type14 } from "@sinclair/typebox";
|
|
5112
5368
|
import {
|
|
5113
5369
|
tavily
|
|
5114
5370
|
} from "@tavily/core";
|
|
5115
|
-
var tavilySearchOptionsSchema =
|
|
5371
|
+
var tavilySearchOptionsSchema = Type14.Object(
|
|
5116
5372
|
{
|
|
5117
|
-
topic:
|
|
5373
|
+
topic: Type14.Optional(
|
|
5118
5374
|
literalUnion(["general", "news", "finance"], {
|
|
5119
5375
|
description: "Category of the search query."
|
|
5120
5376
|
})
|
|
5121
5377
|
),
|
|
5122
|
-
searchDepth:
|
|
5378
|
+
searchDepth: Type14.Optional(
|
|
5123
5379
|
literalUnion(["basic", "advanced"], {
|
|
5124
5380
|
description: "Depth of the search. 'advanced' is slower but more thorough."
|
|
5125
5381
|
})
|
|
5126
5382
|
),
|
|
5127
|
-
timeRange:
|
|
5128
|
-
|
|
5383
|
+
timeRange: Type14.Optional(
|
|
5384
|
+
Type14.String({ description: "Named time range filter." })
|
|
5129
5385
|
),
|
|
5130
|
-
country:
|
|
5131
|
-
|
|
5386
|
+
country: Type14.Optional(
|
|
5387
|
+
Type14.String({ description: "Country hint for search results." })
|
|
5132
5388
|
),
|
|
5133
|
-
exactMatch:
|
|
5134
|
-
|
|
5389
|
+
exactMatch: Type14.Optional(
|
|
5390
|
+
Type14.Boolean({ description: "Prefer exact matches." })
|
|
5135
5391
|
),
|
|
5136
|
-
includeAnswer:
|
|
5137
|
-
|
|
5392
|
+
includeAnswer: Type14.Optional(
|
|
5393
|
+
Type14.Boolean({ description: "Include a short AI-generated answer." })
|
|
5138
5394
|
),
|
|
5139
|
-
includeRawContent:
|
|
5140
|
-
|
|
5395
|
+
includeRawContent: Type14.Optional(
|
|
5396
|
+
Type14.Boolean({ description: "Include raw page content in results." })
|
|
5141
5397
|
),
|
|
5142
|
-
includeImages:
|
|
5143
|
-
|
|
5398
|
+
includeImages: Type14.Optional(
|
|
5399
|
+
Type14.Boolean({ description: "Include related images." })
|
|
5144
5400
|
),
|
|
5145
|
-
includeFavicon:
|
|
5146
|
-
|
|
5401
|
+
includeFavicon: Type14.Optional(
|
|
5402
|
+
Type14.Boolean({ description: "Include favicon URLs." })
|
|
5147
5403
|
),
|
|
5148
|
-
includeDomains:
|
|
5149
|
-
|
|
5404
|
+
includeDomains: Type14.Optional(
|
|
5405
|
+
Type14.Array(Type14.String(), {
|
|
5150
5406
|
description: "Restrict results to these domains."
|
|
5151
5407
|
})
|
|
5152
5408
|
),
|
|
5153
|
-
excludeDomains:
|
|
5154
|
-
|
|
5409
|
+
excludeDomains: Type14.Optional(
|
|
5410
|
+
Type14.Array(Type14.String(), {
|
|
5155
5411
|
description: "Exclude these domains from results."
|
|
5156
5412
|
})
|
|
5157
5413
|
),
|
|
5158
|
-
days:
|
|
5159
|
-
|
|
5414
|
+
days: Type14.Optional(
|
|
5415
|
+
Type14.Integer({
|
|
5160
5416
|
minimum: 1,
|
|
5161
5417
|
description: "Limit results to the last N days."
|
|
5162
5418
|
})
|
|
@@ -5164,27 +5420,27 @@ var tavilySearchOptionsSchema = Type13.Object(
|
|
|
5164
5420
|
},
|
|
5165
5421
|
{ description: "Tavily search options." }
|
|
5166
5422
|
);
|
|
5167
|
-
var tavilyExtractOptionsSchema =
|
|
5423
|
+
var tavilyExtractOptionsSchema = Type14.Object(
|
|
5168
5424
|
{
|
|
5169
|
-
extractDepth:
|
|
5170
|
-
|
|
5425
|
+
extractDepth: Type14.Optional(
|
|
5426
|
+
Type14.String({ description: "Depth setting for extraction." })
|
|
5171
5427
|
),
|
|
5172
|
-
format:
|
|
5428
|
+
format: Type14.Optional(
|
|
5173
5429
|
literalUnion(["markdown", "text"], {
|
|
5174
5430
|
description: "Output format for extracted content."
|
|
5175
5431
|
})
|
|
5176
5432
|
),
|
|
5177
|
-
includeImages:
|
|
5178
|
-
|
|
5433
|
+
includeImages: Type14.Optional(
|
|
5434
|
+
Type14.Boolean({ description: "Include extracted images." })
|
|
5179
5435
|
),
|
|
5180
|
-
query:
|
|
5181
|
-
|
|
5436
|
+
query: Type14.Optional(
|
|
5437
|
+
Type14.String({ description: "Optional query to focus extraction." })
|
|
5182
5438
|
),
|
|
5183
|
-
chunksPerSource:
|
|
5184
|
-
|
|
5439
|
+
chunksPerSource: Type14.Optional(
|
|
5440
|
+
Type14.Integer({ minimum: 1, description: "Maximum chunks per source." })
|
|
5185
5441
|
),
|
|
5186
|
-
includeFavicon:
|
|
5187
|
-
|
|
5442
|
+
includeFavicon: Type14.Optional(
|
|
5443
|
+
Type14.Boolean({ description: "Include favicon URLs." })
|
|
5188
5444
|
)
|
|
5189
5445
|
},
|
|
5190
5446
|
{ description: "Tavily extract options." }
|
|
@@ -5358,48 +5614,48 @@ function buildExtractMetadata(response, result) {
|
|
|
5358
5614
|
}
|
|
5359
5615
|
|
|
5360
5616
|
// src/providers/valyu.ts
|
|
5361
|
-
import { Type as
|
|
5617
|
+
import { Type as Type15 } from "@sinclair/typebox";
|
|
5362
5618
|
import { Valyu as ValyuClient } from "valyu-js";
|
|
5363
|
-
var valyuSearchOptionsSchema =
|
|
5619
|
+
var valyuSearchOptionsSchema = Type15.Object(
|
|
5364
5620
|
{
|
|
5365
|
-
searchType:
|
|
5621
|
+
searchType: Type15.Optional(
|
|
5366
5622
|
literalUnion(["all", "web", "proprietary", "news"], {
|
|
5367
5623
|
description: "Valyu search type."
|
|
5368
5624
|
})
|
|
5369
5625
|
),
|
|
5370
|
-
responseLength:
|
|
5626
|
+
responseLength: Type15.Optional(
|
|
5371
5627
|
literalUnion(["short", "medium", "large", "max"], {
|
|
5372
5628
|
description: "Response length."
|
|
5373
5629
|
})
|
|
5374
5630
|
),
|
|
5375
|
-
countryCode:
|
|
5376
|
-
|
|
5631
|
+
countryCode: Type15.Optional(
|
|
5632
|
+
Type15.String({ description: "Country code to scope search results." })
|
|
5377
5633
|
)
|
|
5378
5634
|
},
|
|
5379
5635
|
{ description: "Valyu search options." }
|
|
5380
5636
|
);
|
|
5381
|
-
var valyuAnswerOptionsSchema =
|
|
5637
|
+
var valyuAnswerOptionsSchema = Type15.Object(
|
|
5382
5638
|
{
|
|
5383
|
-
responseLength:
|
|
5639
|
+
responseLength: Type15.Optional(
|
|
5384
5640
|
literalUnion(["short", "medium", "large", "max"], {
|
|
5385
5641
|
description: "Response length for answers."
|
|
5386
5642
|
})
|
|
5387
5643
|
),
|
|
5388
|
-
countryCode:
|
|
5389
|
-
|
|
5644
|
+
countryCode: Type15.Optional(
|
|
5645
|
+
Type15.String({ description: "Country code to scope answer results." })
|
|
5390
5646
|
)
|
|
5391
5647
|
},
|
|
5392
5648
|
{ description: "Valyu answer options." }
|
|
5393
5649
|
);
|
|
5394
|
-
var valyuResearchOptionsSchema =
|
|
5650
|
+
var valyuResearchOptionsSchema = Type15.Object(
|
|
5395
5651
|
{
|
|
5396
|
-
responseLength:
|
|
5652
|
+
responseLength: Type15.Optional(
|
|
5397
5653
|
literalUnion(["short", "medium", "large", "max"], {
|
|
5398
5654
|
description: "Response length for research."
|
|
5399
5655
|
})
|
|
5400
5656
|
),
|
|
5401
|
-
countryCode:
|
|
5402
|
-
|
|
5657
|
+
countryCode: Type15.Optional(
|
|
5658
|
+
Type15.String({ description: "Country code to scope research results." })
|
|
5403
5659
|
)
|
|
5404
5660
|
},
|
|
5405
5661
|
{ description: "Valyu research options." }
|
|
@@ -5684,6 +5940,7 @@ var ADAPTERS_BY_ID = {
|
|
|
5684
5940
|
openai: openaiAdapter,
|
|
5685
5941
|
parallel: parallelAdapter,
|
|
5686
5942
|
perplexity: perplexityAdapter,
|
|
5943
|
+
serper: serperAdapter,
|
|
5687
5944
|
tavily: tavilyAdapter,
|
|
5688
5945
|
valyu: valyuAdapter
|
|
5689
5946
|
};
|
|
@@ -6780,7 +7037,7 @@ var PROVIDER_CONFIG_MANIFESTS = {
|
|
|
6780
7037
|
"deep-reasoning",
|
|
6781
7038
|
"deep-max"
|
|
6782
7039
|
],
|
|
6783
|
-
getValue: (config) =>
|
|
7040
|
+
getValue: (config) => readString5(getExaSearchOptions(config)?.type) ?? "default",
|
|
6784
7041
|
setValue: (config, value) => {
|
|
6785
7042
|
const options = ensureExaSearchOptions(config);
|
|
6786
7043
|
if (value === "default") {
|
|
@@ -7004,7 +7261,7 @@ var PROVIDER_CONFIG_MANIFESTS = {
|
|
|
7004
7261
|
label: "Search mode",
|
|
7005
7262
|
help: "Parallel search mode. 'default' uses the SDK default.",
|
|
7006
7263
|
values: ["default", "agentic", "one-shot"],
|
|
7007
|
-
getValue: (config) =>
|
|
7264
|
+
getValue: (config) => readString5(getParallelOptions(config)?.search?.mode) ?? "default",
|
|
7008
7265
|
setValue: (config, value) => {
|
|
7009
7266
|
const options = ensureParallelOptions(config);
|
|
7010
7267
|
options.search = asJsonObject2(options.search) ?? {};
|
|
@@ -7058,6 +7315,9 @@ var PROVIDER_CONFIG_MANIFESTS = {
|
|
|
7058
7315
|
})
|
|
7059
7316
|
]
|
|
7060
7317
|
},
|
|
7318
|
+
serper: {
|
|
7319
|
+
settings: [apiKeySetting(), baseUrlSetting()]
|
|
7320
|
+
},
|
|
7061
7321
|
tavily: {
|
|
7062
7322
|
settings: [apiKeySetting(), baseUrlSetting()]
|
|
7063
7323
|
},
|
|
@@ -7070,7 +7330,7 @@ var PROVIDER_CONFIG_MANIFESTS = {
|
|
|
7070
7330
|
label: "Search type",
|
|
7071
7331
|
help: "Valyu search type. 'default' uses the SDK default.",
|
|
7072
7332
|
values: ["default", "all", "web", "proprietary", "news"],
|
|
7073
|
-
getValue: (config) =>
|
|
7333
|
+
getValue: (config) => readString5(getValyuCapabilityOptions(config, "search")?.searchType) ?? "default",
|
|
7074
7334
|
setValue: (config, value) => {
|
|
7075
7335
|
const options = ensureValyuCapabilityOptions(config, "search");
|
|
7076
7336
|
if (value === "default") {
|
|
@@ -7086,7 +7346,7 @@ var PROVIDER_CONFIG_MANIFESTS = {
|
|
|
7086
7346
|
label: "Search response length",
|
|
7087
7347
|
help: "Valyu search response length. 'default' uses the SDK default.",
|
|
7088
7348
|
values: ["default", "short", "medium", "large", "max"],
|
|
7089
|
-
getValue: (config) =>
|
|
7349
|
+
getValue: (config) => readString5(
|
|
7090
7350
|
getValyuCapabilityOptions(config, "search")?.responseLength
|
|
7091
7351
|
) ?? "default",
|
|
7092
7352
|
setValue: (config, value) => {
|
|
@@ -7098,7 +7358,7 @@ var PROVIDER_CONFIG_MANIFESTS = {
|
|
|
7098
7358
|
label: "Answer response length",
|
|
7099
7359
|
help: "Valyu answer response length. 'default' uses the SDK default.",
|
|
7100
7360
|
values: ["default", "short", "medium", "large", "max"],
|
|
7101
|
-
getValue: (config) =>
|
|
7361
|
+
getValue: (config) => readString5(
|
|
7102
7362
|
getValyuCapabilityOptions(config, "answer")?.responseLength
|
|
7103
7363
|
) ?? "default",
|
|
7104
7364
|
setValue: (config, value) => {
|
|
@@ -7110,7 +7370,7 @@ var PROVIDER_CONFIG_MANIFESTS = {
|
|
|
7110
7370
|
label: "Research response length",
|
|
7111
7371
|
help: "Valyu research response length. 'default' uses the SDK default.",
|
|
7112
7372
|
values: ["default", "short", "medium", "large", "max"],
|
|
7113
|
-
getValue: (config) =>
|
|
7373
|
+
getValue: (config) => readString5(
|
|
7114
7374
|
getValyuCapabilityOptions(config, "research")?.responseLength
|
|
7115
7375
|
) ?? "default",
|
|
7116
7376
|
setValue: (config, value) => {
|
|
@@ -7202,7 +7462,7 @@ function getIntegerString(value) {
|
|
|
7202
7462
|
function getBooleanValue(value) {
|
|
7203
7463
|
return typeof value === "boolean" ? String(value) : "default";
|
|
7204
7464
|
}
|
|
7205
|
-
function
|
|
7465
|
+
function readString5(value) {
|
|
7206
7466
|
return typeof value === "string" ? value : void 0;
|
|
7207
7467
|
}
|
|
7208
7468
|
function asJsonObject2(value) {
|
|
@@ -7577,14 +7837,14 @@ function registerWebSearchTool(pi, providerIds) {
|
|
|
7577
7837
|
promptGuidelines: [
|
|
7578
7838
|
"Batch related searches when grouped comparison matters; use separate sibling web_search calls when independent results should surface as soon as they are ready."
|
|
7579
7839
|
],
|
|
7580
|
-
parameters:
|
|
7581
|
-
queries:
|
|
7840
|
+
parameters: Type16.Object({
|
|
7841
|
+
queries: Type16.Array(Type16.String({ minLength: 1 }), {
|
|
7582
7842
|
minItems: 1,
|
|
7583
7843
|
maxItems: MAX_SEARCH_QUERIES,
|
|
7584
7844
|
description: `One or more search queries to run in one call (max ${MAX_SEARCH_QUERIES})`
|
|
7585
7845
|
}),
|
|
7586
|
-
maxResults:
|
|
7587
|
-
|
|
7846
|
+
maxResults: Type16.Optional(
|
|
7847
|
+
Type16.Integer({
|
|
7588
7848
|
minimum: 1,
|
|
7589
7849
|
maximum: MAX_ALLOWED_RESULTS,
|
|
7590
7850
|
description: `Maximum number of results to return (default: ${DEFAULT_MAX_RESULTS})`
|
|
@@ -7633,8 +7893,8 @@ function registerWebContentsTool(pi, providerIds) {
|
|
|
7633
7893
|
name: "web_contents",
|
|
7634
7894
|
label: "Web Contents",
|
|
7635
7895
|
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.",
|
|
7636
|
-
parameters:
|
|
7637
|
-
urls:
|
|
7896
|
+
parameters: Type16.Object({
|
|
7897
|
+
urls: Type16.Array(Type16.String({ minLength: 1 }), {
|
|
7638
7898
|
minItems: 1,
|
|
7639
7899
|
description: "One or more URLs to extract"
|
|
7640
7900
|
}),
|
|
@@ -7684,8 +7944,8 @@ function registerWebAnswerTool(pi, providerIds) {
|
|
|
7684
7944
|
name: "web_answer",
|
|
7685
7945
|
label: "Web Answer",
|
|
7686
7946
|
description: `Answer one or more questions using web-grounded evidence (up to ${MAX_SEARCH_QUERIES} per call).`,
|
|
7687
|
-
parameters:
|
|
7688
|
-
queries:
|
|
7947
|
+
parameters: Type16.Object({
|
|
7948
|
+
queries: Type16.Array(Type16.String({ minLength: 1 }), {
|
|
7689
7949
|
minItems: 1,
|
|
7690
7950
|
maxItems: MAX_SEARCH_QUERIES,
|
|
7691
7951
|
description: `One or more questions to answer in one call (max ${MAX_SEARCH_QUERIES})`
|
|
@@ -7739,8 +7999,8 @@ function registerWebResearchTool(pi, webResearchLifecycle, providerIds) {
|
|
|
7739
7999
|
name: "web_research",
|
|
7740
8000
|
label: "Web Research",
|
|
7741
8001
|
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.",
|
|
7742
|
-
parameters:
|
|
7743
|
-
input:
|
|
8002
|
+
parameters: Type16.Object({
|
|
8003
|
+
input: Type16.String({ description: "Research brief or question" }),
|
|
7744
8004
|
...optionalField(
|
|
7745
8005
|
"options",
|
|
7746
8006
|
buildStructuredOptionsSchema("research", selectedProviderId)
|
|
@@ -7883,7 +8143,7 @@ function optionalField(name, schema) {
|
|
|
7883
8143
|
function buildStructuredOptionsSchema(capability, providerId) {
|
|
7884
8144
|
const providerSchema = resolveProviderOptionsSchema(capability, providerId);
|
|
7885
8145
|
const schema = buildToolOptionsSchema(capability, providerSchema);
|
|
7886
|
-
return schema ?
|
|
8146
|
+
return schema ? Type16.Optional(schema) : void 0;
|
|
7887
8147
|
}
|
|
7888
8148
|
function resolveProviderOptionsSchema(capability, providerId) {
|
|
7889
8149
|
if (!providerId) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-web-providers",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"description": "Configurable web access extension for pi with per-tool provider routing and explicit provider option schemas for search, contents, answers, and research.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"openai",
|
|
31
31
|
"parallel",
|
|
32
32
|
"perplexity",
|
|
33
|
+
"serper",
|
|
33
34
|
"tavily",
|
|
34
35
|
"valyu"
|
|
35
36
|
],
|