pi-web-providers 3.1.0 → 3.2.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 +9 -2
- package/dist/index.js +191 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -68,7 +68,7 @@ reported when the tool is actually called.
|
|
|
68
68
|
| **Exa** | ✔ | ✔ | ✔ | ✔ | `EXA_API_KEY` |
|
|
69
69
|
| **Firecrawl** | ✔ | ✔ | | | `FIRECRAWL_API_KEY` |
|
|
70
70
|
| **Gemini** | ✔ | | ✔ | ✔ | `GOOGLE_API_KEY` |
|
|
71
|
-
| **Linkup** | ✔ | ✔ | |
|
|
71
|
+
| **Linkup** | ✔ | ✔ | | ✔ | `LINKUP_API_KEY` |
|
|
72
72
|
| **Ollama** | ✔ | ✔ | | | `OLLAMA_API_KEY` |
|
|
73
73
|
| **OpenAI** | ✔ | | ✔ | ✔ | `OPENAI_API_KEY` |
|
|
74
74
|
| **Parallel** | ✔ | ✔ | | | `PARALLEL_API_KEY` |
|
|
@@ -352,10 +352,17 @@ scope, or account ID is usually wrong.
|
|
|
352
352
|
- SDK: `linkup-sdk`
|
|
353
353
|
- Supports `web_search` via Linkup Search with fixed `searchResults` output
|
|
354
354
|
- Supports `web_contents` via Linkup Fetch and always returns markdown
|
|
355
|
+
- Supports `web_research` via Linkup's async Research API
|
|
355
356
|
- Exposes search options `depth`, `includeImages`, `includeDomains`,
|
|
356
357
|
`excludeDomains`, `fromDate`, and `toDate`
|
|
357
358
|
- Exposes contents options `renderJs`, `includeRawHtml`, and `extractImages`
|
|
358
|
-
-
|
|
359
|
+
- Exposes research options `outputType`, `mode`, `reasoningDepth`,
|
|
360
|
+
`includeDomains`, `excludeDomains`, `fromDate`, `toDate`, and
|
|
361
|
+
`structuredOutputSchema`
|
|
362
|
+
- Research defaults to `sourcedAnswer`; provide `structuredOutputSchema` for
|
|
363
|
+
structured output
|
|
364
|
+
- Good fit for search, markdown extraction, and long-running sourced research
|
|
365
|
+
without extra provider wiring
|
|
359
366
|
|
|
360
367
|
</details>
|
|
361
368
|
|
package/dist/index.js
CHANGED
|
@@ -4241,6 +4241,45 @@ var linkupContentsOptionsSchema = Type9.Object(
|
|
|
4241
4241
|
},
|
|
4242
4242
|
{ description: "Linkup fetch options." }
|
|
4243
4243
|
);
|
|
4244
|
+
var linkupResearchOptionsSchema = Type9.Object(
|
|
4245
|
+
{
|
|
4246
|
+
outputType: Type9.Optional(
|
|
4247
|
+
literalUnion(["sourcedAnswer", "structured"], {
|
|
4248
|
+
description: "Research output type. Defaults to 'sourcedAnswer' unless structuredOutputSchema is provided."
|
|
4249
|
+
})
|
|
4250
|
+
),
|
|
4251
|
+
mode: Type9.Optional(
|
|
4252
|
+
literalUnion(["answer", "auto", "investigate", "research"], {
|
|
4253
|
+
description: "Research mode. Use 'answer' for precise verified answers, 'investigate' for focused deep dives, 'research' for broad reports, or omit/auto to let Linkup classify the task."
|
|
4254
|
+
})
|
|
4255
|
+
),
|
|
4256
|
+
reasoningDepth: Type9.Optional(
|
|
4257
|
+
literalUnion(["S", "M", "L", "XL"], {
|
|
4258
|
+
description: "Reasoning depth. Higher values trade latency for more thorough investigation."
|
|
4259
|
+
})
|
|
4260
|
+
),
|
|
4261
|
+
includeDomains: Type9.Optional(
|
|
4262
|
+
Type9.Array(Type9.String(), {
|
|
4263
|
+
description: "Restrict research to these domains."
|
|
4264
|
+
})
|
|
4265
|
+
),
|
|
4266
|
+
excludeDomains: Type9.Optional(
|
|
4267
|
+
Type9.Array(Type9.String(), { description: "Exclude these domains." })
|
|
4268
|
+
),
|
|
4269
|
+
fromDate: Type9.Optional(
|
|
4270
|
+
Type9.String({ description: "ISO date string for earliest result date." })
|
|
4271
|
+
),
|
|
4272
|
+
toDate: Type9.Optional(
|
|
4273
|
+
Type9.String({ description: "ISO date string for latest result date." })
|
|
4274
|
+
),
|
|
4275
|
+
structuredOutputSchema: Type9.Optional(
|
|
4276
|
+
Type9.Record(Type9.String(), Type9.Any(), {
|
|
4277
|
+
description: "JSON schema object required when outputType is 'structured'."
|
|
4278
|
+
})
|
|
4279
|
+
)
|
|
4280
|
+
},
|
|
4281
|
+
{ description: "Linkup research options." }
|
|
4282
|
+
);
|
|
4244
4283
|
var linkupImplementation = {
|
|
4245
4284
|
id: "linkup",
|
|
4246
4285
|
label: "Linkup",
|
|
@@ -4251,6 +4290,8 @@ var linkupImplementation = {
|
|
|
4251
4290
|
return linkupSearchOptionsSchema;
|
|
4252
4291
|
case "contents":
|
|
4253
4292
|
return linkupContentsOptionsSchema;
|
|
4293
|
+
case "research":
|
|
4294
|
+
return linkupResearchOptionsSchema;
|
|
4254
4295
|
default:
|
|
4255
4296
|
return void 0;
|
|
4256
4297
|
}
|
|
@@ -4307,6 +4348,51 @@ var linkupImplementation = {
|
|
|
4307
4348
|
})
|
|
4308
4349
|
)
|
|
4309
4350
|
};
|
|
4351
|
+
},
|
|
4352
|
+
async research(input, config, context, options) {
|
|
4353
|
+
return await executeAsyncResearch({
|
|
4354
|
+
providerLabel: linkupImplementation.label,
|
|
4355
|
+
providerId: linkupImplementation.id,
|
|
4356
|
+
context,
|
|
4357
|
+
start: (researchContext) => linkupImplementation.startResearch(
|
|
4358
|
+
input,
|
|
4359
|
+
config,
|
|
4360
|
+
researchContext,
|
|
4361
|
+
options
|
|
4362
|
+
),
|
|
4363
|
+
poll: (id, researchContext) => linkupImplementation.pollResearch(id, config, researchContext)
|
|
4364
|
+
});
|
|
4365
|
+
},
|
|
4366
|
+
async startResearch(input, config, _context, options) {
|
|
4367
|
+
const client = createClient4(config);
|
|
4368
|
+
const defaults = asJsonObject(config.options?.research) ?? {};
|
|
4369
|
+
const task = await client.research(
|
|
4370
|
+
buildResearchParams(input, {
|
|
4371
|
+
...defaults,
|
|
4372
|
+
...options ?? {}
|
|
4373
|
+
})
|
|
4374
|
+
);
|
|
4375
|
+
return { id: task.id };
|
|
4376
|
+
},
|
|
4377
|
+
async pollResearch(id, config, _context) {
|
|
4378
|
+
const client = createClient4(config);
|
|
4379
|
+
const task = await client.getResearch(id);
|
|
4380
|
+
if (task.status === "completed") {
|
|
4381
|
+
return {
|
|
4382
|
+
status: "completed",
|
|
4383
|
+
output: formatResearchTaskOutput(task)
|
|
4384
|
+
};
|
|
4385
|
+
}
|
|
4386
|
+
if (task.status === "failed") {
|
|
4387
|
+
return {
|
|
4388
|
+
status: "failed",
|
|
4389
|
+
error: task.error ?? "research failed"
|
|
4390
|
+
};
|
|
4391
|
+
}
|
|
4392
|
+
return {
|
|
4393
|
+
status: "in_progress",
|
|
4394
|
+
statusText: task.status
|
|
4395
|
+
};
|
|
4310
4396
|
}
|
|
4311
4397
|
};
|
|
4312
4398
|
function buildSearchParams(query2, maxResults, options) {
|
|
@@ -4351,6 +4437,45 @@ function buildFetchParams(url2, options) {
|
|
|
4351
4437
|
...fetchOptions.extractImages !== void 0 ? { extractImages: fetchOptions.extractImages } : {}
|
|
4352
4438
|
};
|
|
4353
4439
|
}
|
|
4440
|
+
function buildResearchParams(input, options) {
|
|
4441
|
+
const researchOptions = options;
|
|
4442
|
+
if (researchOptions.q !== void 0 || researchOptions.query !== void 0 || researchOptions.input !== void 0) {
|
|
4443
|
+
throw new Error(
|
|
4444
|
+
"Linkup research options cannot override the managed input."
|
|
4445
|
+
);
|
|
4446
|
+
}
|
|
4447
|
+
const outputType = researchOptions.outputType ?? (researchOptions.structuredOutputSchema !== void 0 ? "structured" : "sourcedAnswer");
|
|
4448
|
+
if (outputType === "structured" && researchOptions.structuredOutputSchema === void 0) {
|
|
4449
|
+
throw new Error(
|
|
4450
|
+
"Linkup research outputType 'structured' requires structuredOutputSchema."
|
|
4451
|
+
);
|
|
4452
|
+
}
|
|
4453
|
+
if (outputType === "sourcedAnswer" && researchOptions.structuredOutputSchema !== void 0) {
|
|
4454
|
+
throw new Error(
|
|
4455
|
+
"Linkup research structuredOutputSchema requires outputType 'structured'."
|
|
4456
|
+
);
|
|
4457
|
+
}
|
|
4458
|
+
const commonParams = {
|
|
4459
|
+
query: input,
|
|
4460
|
+
...researchOptions.includeDomains !== void 0 ? { includeDomains: researchOptions.includeDomains } : {},
|
|
4461
|
+
...researchOptions.excludeDomains !== void 0 ? { excludeDomains: researchOptions.excludeDomains } : {},
|
|
4462
|
+
...researchOptions.fromDate !== void 0 ? { fromDate: toDate(researchOptions.fromDate, "fromDate") } : {},
|
|
4463
|
+
...researchOptions.toDate !== void 0 ? { toDate: toDate(researchOptions.toDate, "toDate") } : {},
|
|
4464
|
+
...researchOptions.mode !== void 0 ? { mode: researchOptions.mode } : {},
|
|
4465
|
+
...researchOptions.reasoningDepth !== void 0 ? { reasoningDepth: researchOptions.reasoningDepth } : {}
|
|
4466
|
+
};
|
|
4467
|
+
if (outputType === "structured") {
|
|
4468
|
+
return {
|
|
4469
|
+
...commonParams,
|
|
4470
|
+
outputType,
|
|
4471
|
+
structuredOutputSchema: researchOptions.structuredOutputSchema
|
|
4472
|
+
};
|
|
4473
|
+
}
|
|
4474
|
+
return {
|
|
4475
|
+
...commonParams,
|
|
4476
|
+
outputType
|
|
4477
|
+
};
|
|
4478
|
+
}
|
|
4354
4479
|
function createClient4(config) {
|
|
4355
4480
|
const apiKey = resolveConfigValue(config.credentials?.api);
|
|
4356
4481
|
if (!apiKey) {
|
|
@@ -4361,6 +4486,40 @@ function createClient4(config) {
|
|
|
4361
4486
|
baseUrl: resolveConfigValue(config.baseUrl)
|
|
4362
4487
|
});
|
|
4363
4488
|
}
|
|
4489
|
+
function formatResearchTaskOutput(task) {
|
|
4490
|
+
const output = task.output;
|
|
4491
|
+
if (!output) {
|
|
4492
|
+
return {
|
|
4493
|
+
provider: linkupImplementation.id,
|
|
4494
|
+
text: "Linkup research completed without textual output."
|
|
4495
|
+
};
|
|
4496
|
+
}
|
|
4497
|
+
const outputRecord = asRecord2(output);
|
|
4498
|
+
const inputRecord = asRecord2(task.input);
|
|
4499
|
+
const outputType = inputRecord ? readString3(inputRecord.outputType) : void 0;
|
|
4500
|
+
const answer = outputRecord ? readString3(outputRecord.answer) : void 0;
|
|
4501
|
+
const sources = outputRecord ? readSources(outputRecord.sources) : [];
|
|
4502
|
+
if (outputType !== "structured" && answer !== void 0) {
|
|
4503
|
+
const lines = [answer];
|
|
4504
|
+
if (sources.length > 0) {
|
|
4505
|
+
lines.push("");
|
|
4506
|
+
lines.push("Sources:");
|
|
4507
|
+
for (const [index, source] of sources.entries()) {
|
|
4508
|
+
lines.push(`${index + 1}. ${source.title}`);
|
|
4509
|
+
lines.push(` ${source.url}`);
|
|
4510
|
+
}
|
|
4511
|
+
}
|
|
4512
|
+
return {
|
|
4513
|
+
provider: linkupImplementation.id,
|
|
4514
|
+
text: lines.join("\n").trimEnd(),
|
|
4515
|
+
itemCount: sources.length
|
|
4516
|
+
};
|
|
4517
|
+
}
|
|
4518
|
+
return {
|
|
4519
|
+
provider: linkupImplementation.id,
|
|
4520
|
+
text: formatJson(output)
|
|
4521
|
+
};
|
|
4522
|
+
}
|
|
4364
4523
|
function toSearchResult2(value) {
|
|
4365
4524
|
const entry = asRecord2(value);
|
|
4366
4525
|
if (!entry) {
|
|
@@ -4382,6 +4541,27 @@ function toSearchResult2(value) {
|
|
|
4382
4541
|
metadata: Object.keys(metadata).length > 0 ? metadata : void 0
|
|
4383
4542
|
};
|
|
4384
4543
|
}
|
|
4544
|
+
function readSources(value) {
|
|
4545
|
+
if (!Array.isArray(value)) {
|
|
4546
|
+
return [];
|
|
4547
|
+
}
|
|
4548
|
+
return value.flatMap((entry) => {
|
|
4549
|
+
const source = asRecord2(entry);
|
|
4550
|
+
if (!source) {
|
|
4551
|
+
return [];
|
|
4552
|
+
}
|
|
4553
|
+
const url2 = readString3(source.url);
|
|
4554
|
+
if (!url2) {
|
|
4555
|
+
return [];
|
|
4556
|
+
}
|
|
4557
|
+
return [
|
|
4558
|
+
{
|
|
4559
|
+
title: readString3(source.name) ?? url2,
|
|
4560
|
+
url: url2
|
|
4561
|
+
}
|
|
4562
|
+
];
|
|
4563
|
+
});
|
|
4564
|
+
}
|
|
4385
4565
|
function asRecord2(value) {
|
|
4386
4566
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
4387
4567
|
}
|
|
@@ -4435,6 +4615,17 @@ var linkupProvider = defineProvider({
|
|
|
4435
4615
|
input.options
|
|
4436
4616
|
);
|
|
4437
4617
|
}
|
|
4618
|
+
}),
|
|
4619
|
+
research: defineCapability({
|
|
4620
|
+
options: linkupImplementation.getToolOptionsSchema?.("research"),
|
|
4621
|
+
async execute(input, ctx) {
|
|
4622
|
+
return await linkupImplementation.research(
|
|
4623
|
+
input.input,
|
|
4624
|
+
ctx.config,
|
|
4625
|
+
ctx,
|
|
4626
|
+
input.options
|
|
4627
|
+
);
|
|
4628
|
+
}
|
|
4438
4629
|
})
|
|
4439
4630
|
}
|
|
4440
4631
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-web-providers",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.0",
|
|
4
4
|
"description": "Configurable web access extension for pi with per-tool provider routing and explicit provider option schemas for search, contents, quick grounded answers, and research.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
"@tavily/core": "^0.7.3",
|
|
74
74
|
"cloudflare": "^5.2.0",
|
|
75
75
|
"exa-js": "^2.12.1",
|
|
76
|
-
"linkup-sdk": "^2.
|
|
76
|
+
"linkup-sdk": "^3.2.0",
|
|
77
77
|
"openai": "^6.35.0",
|
|
78
78
|
"parallel-web": "^0.4.1",
|
|
79
79
|
"valyu-js": "^2.7.14"
|