pi-web-providers 3.1.0 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +17 -4
  2. package/dist/index.js +371 -2
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -66,9 +66,9 @@ reported when the tool is actually called.
66
66
  | **Brave** | ✔ | | ✔ | ✔ | `BRAVE_SEARCH_API_KEY` / `BRAVE_ANSWERS_API_KEY` |
67
67
  | **Cloudflare** | | ✔ | | | `CLOUDFLARE_API_TOKEN` + `CLOUDFLARE_ACCOUNT_ID` |
68
68
  | **Exa** | ✔ | ✔ | ✔ | ✔ | `EXA_API_KEY` |
69
- | **Firecrawl** | ✔ | ✔ | | | `FIRECRAWL_API_KEY` |
69
+ | **Firecrawl** | ✔ | ✔ || | `FIRECRAWL_API_KEY` |
70
70
  | **Gemini** | ✔ | | ✔ | ✔ | `GOOGLE_API_KEY` |
71
- | **Linkup** | ✔ | ✔ | | | `LINKUP_API_KEY` |
71
+ | **Linkup** | ✔ | ✔ | || `LINKUP_API_KEY` |
72
72
  | **Ollama** | ✔ | ✔ | | | `OLLAMA_API_KEY` |
73
73
  | **OpenAI** | ✔ | | ✔ | ✔ | `OPENAI_API_KEY` |
74
74
  | **Parallel** | ✔ | ✔ | | | `PARALLEL_API_KEY` |
@@ -315,13 +315,19 @@ scope, or account ID is usually wrong.
315
315
  <summary><strong>Firecrawl</strong></summary>
316
316
 
317
317
  - SDK: `@mendable/firecrawl-js`
318
- - Supports `web_search` and `web_contents`
318
+ - Supports `web_search`, `web_contents`, and page-scoped `web_answer`
319
319
  - Search can optionally include Firecrawl scrape-backed result enrichment
320
320
  - Contents extraction uses Firecrawl scrape with markdown-first defaults
321
+ - Answers use Firecrawl scrape's `question` format against one explicit page URL;
322
+ set `options.url` in the `web_answer` call or
323
+ `providers.firecrawl.options.answer.url` as a default
321
324
  - Exposes search options such as `lang`, `country`, `sources`, `categories`,
322
325
  `location`, `timeout`, and `scrapeOptions`
323
326
  - Exposes contents options such as `formats`, `onlyMainContent`, `includeTags`,
324
327
  `excludeTags`, `waitFor`, `headers`, `location`, `mobile`, and `proxy`
328
+ - Exposes answer options `url`, `onlyMainContent`, `includeTags`,
329
+ `excludeTags`, `waitFor`, `headers`, `location`, `mobile`, and `proxy`
330
+ - Firecrawl charges 5 credits per page for the `question` format
325
331
  - Optional `baseUrl` overrides are supported for self-hosted Firecrawl
326
332
  instances, proxies, and testing. API keys are required for Firecrawl Cloud,
327
333
  but can be omitted for self-hosted endpoints that do not enforce
@@ -352,10 +358,17 @@ scope, or account ID is usually wrong.
352
358
  - SDK: `linkup-sdk`
353
359
  - Supports `web_search` via Linkup Search with fixed `searchResults` output
354
360
  - Supports `web_contents` via Linkup Fetch and always returns markdown
361
+ - Supports `web_research` via Linkup's async Research API
355
362
  - Exposes search options `depth`, `includeImages`, `includeDomains`,
356
363
  `excludeDomains`, `fromDate`, and `toDate`
357
364
  - Exposes contents options `renderJs`, `includeRawHtml`, and `extractImages`
358
- - Good fit for a simple search-plus-markdown setup without extra provider wiring
365
+ - Exposes research options `outputType`, `mode`, `reasoningDepth`,
366
+ `includeDomains`, `excludeDomains`, `fromDate`, `toDate`, and
367
+ `structuredOutputSchema`
368
+ - Research defaults to `sourcedAnswer`; provide `structuredOutputSchema` for
369
+ structured output
370
+ - Good fit for search, markdown extraction, and long-running sourced research
371
+ without extra provider wiring
359
372
 
360
373
  </details>
361
374
 
package/dist/index.js CHANGED
@@ -3097,6 +3097,8 @@ var exaProvider = defineProvider({
3097
3097
  import FirecrawlClient from "@mendable/firecrawl-js";
3098
3098
  import { Type as Type7 } from "typebox";
3099
3099
  var FIRECRAWL_CLOUD_HOST = "api.firecrawl.dev";
3100
+ var FIRECRAWL_DEFAULT_API_URL = "https://api.firecrawl.dev";
3101
+ var FIRECRAWL_QUESTION_LIMIT = 1e4;
3100
3102
  var firecrawlSearchOptionsSchema = Type7.Object(
3101
3103
  {
3102
3104
  lang: Type7.Optional(
@@ -3203,6 +3205,55 @@ var firecrawlScrapeOptionsSchema = Type7.Object(
3203
3205
  },
3204
3206
  { description: "Firecrawl scrape options." }
3205
3207
  );
3208
+ var firecrawlAnswerOptionsSchema = Type7.Object(
3209
+ {
3210
+ url: Type7.String({
3211
+ minLength: 1,
3212
+ description: "URL of the page to ask about."
3213
+ }),
3214
+ onlyMainContent: Type7.Optional(
3215
+ Type7.Boolean({ description: "Extract only the main content." })
3216
+ ),
3217
+ includeTags: Type7.Optional(
3218
+ Type7.Array(Type7.String(), { description: "CSS selectors to include." })
3219
+ ),
3220
+ excludeTags: Type7.Optional(
3221
+ Type7.Array(Type7.String(), { description: "CSS selectors to exclude." })
3222
+ ),
3223
+ waitFor: Type7.Optional(
3224
+ Type7.Integer({
3225
+ minimum: 0,
3226
+ description: "Milliseconds to wait before scraping."
3227
+ })
3228
+ ),
3229
+ headers: Type7.Optional(
3230
+ Type7.Record(Type7.String(), Type7.String(), {
3231
+ description: "Headers to send when scraping."
3232
+ })
3233
+ ),
3234
+ location: Type7.Optional(
3235
+ Type7.Object(
3236
+ {
3237
+ country: Type7.Optional(Type7.String({ description: "Country hint." })),
3238
+ region: Type7.Optional(Type7.String({ description: "Region hint." })),
3239
+ city: Type7.Optional(Type7.String({ description: "City hint." }))
3240
+ },
3241
+ { description: "Location hint for scraping." }
3242
+ )
3243
+ ),
3244
+ mobile: Type7.Optional(
3245
+ Type7.Boolean({ description: "Use a mobile browser profile." })
3246
+ ),
3247
+ proxy: Type7.Optional(
3248
+ Type7.String({
3249
+ description: "Proxy mode passed through to Firecrawl."
3250
+ })
3251
+ )
3252
+ },
3253
+ {
3254
+ description: "Firecrawl page-question options. The URL is required; the question comes from the web_answer query."
3255
+ }
3256
+ );
3206
3257
  var firecrawlImplementation = {
3207
3258
  id: "firecrawl",
3208
3259
  label: "Firecrawl",
@@ -3213,6 +3264,8 @@ var firecrawlImplementation = {
3213
3264
  return firecrawlSearchOptionsSchema;
3214
3265
  case "contents":
3215
3266
  return firecrawlScrapeOptionsSchema;
3267
+ case "answer":
3268
+ return firecrawlAnswerOptionsSchema;
3216
3269
  default:
3217
3270
  return void 0;
3218
3271
  }
@@ -3279,6 +3332,34 @@ var firecrawlImplementation = {
3279
3332
  })
3280
3333
  )
3281
3334
  };
3335
+ },
3336
+ async answer(query2, config, _context, options) {
3337
+ const question = validateQuestion(query2);
3338
+ const defaults = asJsonObject(config.options?.scrape);
3339
+ const answerDefaults = asJsonObject(config.options?.answer);
3340
+ const mergedOptions = {
3341
+ onlyMainContent: true,
3342
+ ...defaults,
3343
+ ...answerDefaults,
3344
+ ...options ?? {}
3345
+ };
3346
+ const url2 = validateUrl(mergedOptions.url);
3347
+ const scrapeOptions = stripAnswerOnlyOptions(mergedOptions);
3348
+ const response = await scrapeQuestion(config, url2, question, scrapeOptions);
3349
+ const document = getFirecrawlDocument(response);
3350
+ const answer = readString2(document.answer);
3351
+ if (!answer?.trim()) {
3352
+ throw new Error("No answer returned for this URL.");
3353
+ }
3354
+ return {
3355
+ provider: firecrawlImplementation.id,
3356
+ text: answer.trim(),
3357
+ itemCount: 1,
3358
+ metadata: {
3359
+ url: url2,
3360
+ ...asRecord(document.metadata) ? { metadata: document.metadata } : {}
3361
+ }
3362
+ };
3282
3363
  }
3283
3364
  };
3284
3365
  function createClient3(config) {
@@ -3302,6 +3383,88 @@ function getFirecrawlCapabilityStatus(config, options) {
3302
3383
  function isFirecrawlCloudApiUrl(apiUrl) {
3303
3384
  return !apiUrl || apiUrl.includes(FIRECRAWL_CLOUD_HOST);
3304
3385
  }
3386
+ function validateQuestion(query2) {
3387
+ const question = query2.trim();
3388
+ if (!question) {
3389
+ throw new Error("question must be a non-empty string.");
3390
+ }
3391
+ if (question.length > FIRECRAWL_QUESTION_LIMIT) {
3392
+ throw new Error(
3393
+ `Firecrawl question must be at most ${FIRECRAWL_QUESTION_LIMIT} characters.`
3394
+ );
3395
+ }
3396
+ return question;
3397
+ }
3398
+ function validateUrl(value) {
3399
+ if (typeof value !== "string" || !value.trim()) {
3400
+ throw new Error("Firecrawl answer requires options.url.");
3401
+ }
3402
+ return value.trim();
3403
+ }
3404
+ function stripAnswerOnlyOptions(options) {
3405
+ const { url: _url, formats: _formats, ...scrapeOptions } = options;
3406
+ return scrapeOptions;
3407
+ }
3408
+ async function scrapeQuestion(config, url2, question, options) {
3409
+ const apiUrl = resolveConfigValue(config.baseUrl) ?? FIRECRAWL_DEFAULT_API_URL;
3410
+ const apiKey = resolveConfigValue(config.credentials?.api);
3411
+ if (isFirecrawlCloudApiUrl(apiUrl) && !apiKey) {
3412
+ throw new Error("is missing an API key");
3413
+ }
3414
+ const response = await fetch(joinUrl(apiUrl, "/v2/scrape"), {
3415
+ method: "POST",
3416
+ headers: {
3417
+ "Content-Type": "application/json",
3418
+ ...apiKey ? { Authorization: `Bearer ${apiKey}` } : {}
3419
+ },
3420
+ body: JSON.stringify({
3421
+ ...options,
3422
+ url: url2,
3423
+ formats: [{ type: "question", question }]
3424
+ })
3425
+ });
3426
+ const payload = await readJsonResponse(response);
3427
+ if (!response.ok) {
3428
+ throw new Error(readFirecrawlError(payload, response.statusText));
3429
+ }
3430
+ if (isFirecrawlFailure(payload)) {
3431
+ throw new Error(readFirecrawlError(payload, "Firecrawl scrape failed."));
3432
+ }
3433
+ return payload;
3434
+ }
3435
+ function joinUrl(baseUrl, path) {
3436
+ return `${baseUrl.replace(/\/+$/g, "")}/${path.replace(/^\/+/g, "")}`;
3437
+ }
3438
+ async function readJsonResponse(response) {
3439
+ const text = await response.text();
3440
+ if (!text) {
3441
+ return {};
3442
+ }
3443
+ try {
3444
+ return JSON.parse(text);
3445
+ } catch {
3446
+ return text;
3447
+ }
3448
+ }
3449
+ function isFirecrawlFailure(value) {
3450
+ const record = asRecord(value);
3451
+ return record?.success === false || record?.error !== void 0;
3452
+ }
3453
+ function readFirecrawlError(value, fallback) {
3454
+ const record = asRecord(value);
3455
+ return readString2(record?.error) ?? readString2(record?.message) ?? (typeof value === "string" ? value : void 0) ?? fallback;
3456
+ }
3457
+ function getFirecrawlDocument(value) {
3458
+ const record = asRecord(value);
3459
+ const data = asRecord(record?.data);
3460
+ if (data) {
3461
+ return data;
3462
+ }
3463
+ if (record) {
3464
+ return record;
3465
+ }
3466
+ throw new Error(`Unexpected Firecrawl response: ${formatJson(value)}`);
3467
+ }
3305
3468
  function flattenSearchResults(response) {
3306
3469
  return ["web", "news", "images"].flatMap(
3307
3470
  (source) => (response[source] ?? []).map((entry) => toSearchResult(source, entry)).filter((entry) => entry !== null)
@@ -3389,6 +3552,21 @@ var firecrawlProvider = defineProvider({
3389
3552
  input.options
3390
3553
  );
3391
3554
  }
3555
+ }),
3556
+ answer: defineCapability({
3557
+ options: firecrawlImplementation.getToolOptionsSchema?.("answer"),
3558
+ promptGuidelines: [
3559
+ "Firecrawl web_answer is page-scoped: set options.url to the specific page URL to ask about.",
3560
+ "Do not use Firecrawl web_answer for general multi-source answers; use web_search plus web_contents or web_research instead."
3561
+ ],
3562
+ async execute(input, ctx) {
3563
+ return await firecrawlImplementation.answer(
3564
+ input.query,
3565
+ ctx.config,
3566
+ ctx,
3567
+ input.options
3568
+ );
3569
+ }
3392
3570
  })
3393
3571
  }
3394
3572
  });
@@ -4241,6 +4419,45 @@ var linkupContentsOptionsSchema = Type9.Object(
4241
4419
  },
4242
4420
  { description: "Linkup fetch options." }
4243
4421
  );
4422
+ var linkupResearchOptionsSchema = Type9.Object(
4423
+ {
4424
+ outputType: Type9.Optional(
4425
+ literalUnion(["sourcedAnswer", "structured"], {
4426
+ description: "Research output type. Defaults to 'sourcedAnswer' unless structuredOutputSchema is provided."
4427
+ })
4428
+ ),
4429
+ mode: Type9.Optional(
4430
+ literalUnion(["answer", "auto", "investigate", "research"], {
4431
+ 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."
4432
+ })
4433
+ ),
4434
+ reasoningDepth: Type9.Optional(
4435
+ literalUnion(["S", "M", "L", "XL"], {
4436
+ description: "Reasoning depth. Higher values trade latency for more thorough investigation."
4437
+ })
4438
+ ),
4439
+ includeDomains: Type9.Optional(
4440
+ Type9.Array(Type9.String(), {
4441
+ description: "Restrict research to these domains."
4442
+ })
4443
+ ),
4444
+ excludeDomains: Type9.Optional(
4445
+ Type9.Array(Type9.String(), { description: "Exclude these domains." })
4446
+ ),
4447
+ fromDate: Type9.Optional(
4448
+ Type9.String({ description: "ISO date string for earliest result date." })
4449
+ ),
4450
+ toDate: Type9.Optional(
4451
+ Type9.String({ description: "ISO date string for latest result date." })
4452
+ ),
4453
+ structuredOutputSchema: Type9.Optional(
4454
+ Type9.Record(Type9.String(), Type9.Any(), {
4455
+ description: "JSON schema object required when outputType is 'structured'."
4456
+ })
4457
+ )
4458
+ },
4459
+ { description: "Linkup research options." }
4460
+ );
4244
4461
  var linkupImplementation = {
4245
4462
  id: "linkup",
4246
4463
  label: "Linkup",
@@ -4251,6 +4468,8 @@ var linkupImplementation = {
4251
4468
  return linkupSearchOptionsSchema;
4252
4469
  case "contents":
4253
4470
  return linkupContentsOptionsSchema;
4471
+ case "research":
4472
+ return linkupResearchOptionsSchema;
4254
4473
  default:
4255
4474
  return void 0;
4256
4475
  }
@@ -4307,6 +4526,51 @@ var linkupImplementation = {
4307
4526
  })
4308
4527
  )
4309
4528
  };
4529
+ },
4530
+ async research(input, config, context, options) {
4531
+ return await executeAsyncResearch({
4532
+ providerLabel: linkupImplementation.label,
4533
+ providerId: linkupImplementation.id,
4534
+ context,
4535
+ start: (researchContext) => linkupImplementation.startResearch(
4536
+ input,
4537
+ config,
4538
+ researchContext,
4539
+ options
4540
+ ),
4541
+ poll: (id, researchContext) => linkupImplementation.pollResearch(id, config, researchContext)
4542
+ });
4543
+ },
4544
+ async startResearch(input, config, _context, options) {
4545
+ const client = createClient4(config);
4546
+ const defaults = asJsonObject(config.options?.research) ?? {};
4547
+ const task = await client.research(
4548
+ buildResearchParams(input, {
4549
+ ...defaults,
4550
+ ...options ?? {}
4551
+ })
4552
+ );
4553
+ return { id: task.id };
4554
+ },
4555
+ async pollResearch(id, config, _context) {
4556
+ const client = createClient4(config);
4557
+ const task = await client.getResearch(id);
4558
+ if (task.status === "completed") {
4559
+ return {
4560
+ status: "completed",
4561
+ output: formatResearchTaskOutput(task)
4562
+ };
4563
+ }
4564
+ if (task.status === "failed") {
4565
+ return {
4566
+ status: "failed",
4567
+ error: task.error ?? "research failed"
4568
+ };
4569
+ }
4570
+ return {
4571
+ status: "in_progress",
4572
+ statusText: task.status
4573
+ };
4310
4574
  }
4311
4575
  };
4312
4576
  function buildSearchParams(query2, maxResults, options) {
@@ -4351,6 +4615,45 @@ function buildFetchParams(url2, options) {
4351
4615
  ...fetchOptions.extractImages !== void 0 ? { extractImages: fetchOptions.extractImages } : {}
4352
4616
  };
4353
4617
  }
4618
+ function buildResearchParams(input, options) {
4619
+ const researchOptions = options;
4620
+ if (researchOptions.q !== void 0 || researchOptions.query !== void 0 || researchOptions.input !== void 0) {
4621
+ throw new Error(
4622
+ "Linkup research options cannot override the managed input."
4623
+ );
4624
+ }
4625
+ const outputType = researchOptions.outputType ?? (researchOptions.structuredOutputSchema !== void 0 ? "structured" : "sourcedAnswer");
4626
+ if (outputType === "structured" && researchOptions.structuredOutputSchema === void 0) {
4627
+ throw new Error(
4628
+ "Linkup research outputType 'structured' requires structuredOutputSchema."
4629
+ );
4630
+ }
4631
+ if (outputType === "sourcedAnswer" && researchOptions.structuredOutputSchema !== void 0) {
4632
+ throw new Error(
4633
+ "Linkup research structuredOutputSchema requires outputType 'structured'."
4634
+ );
4635
+ }
4636
+ const commonParams = {
4637
+ query: input,
4638
+ ...researchOptions.includeDomains !== void 0 ? { includeDomains: researchOptions.includeDomains } : {},
4639
+ ...researchOptions.excludeDomains !== void 0 ? { excludeDomains: researchOptions.excludeDomains } : {},
4640
+ ...researchOptions.fromDate !== void 0 ? { fromDate: toDate(researchOptions.fromDate, "fromDate") } : {},
4641
+ ...researchOptions.toDate !== void 0 ? { toDate: toDate(researchOptions.toDate, "toDate") } : {},
4642
+ ...researchOptions.mode !== void 0 ? { mode: researchOptions.mode } : {},
4643
+ ...researchOptions.reasoningDepth !== void 0 ? { reasoningDepth: researchOptions.reasoningDepth } : {}
4644
+ };
4645
+ if (outputType === "structured") {
4646
+ return {
4647
+ ...commonParams,
4648
+ outputType,
4649
+ structuredOutputSchema: researchOptions.structuredOutputSchema
4650
+ };
4651
+ }
4652
+ return {
4653
+ ...commonParams,
4654
+ outputType
4655
+ };
4656
+ }
4354
4657
  function createClient4(config) {
4355
4658
  const apiKey = resolveConfigValue(config.credentials?.api);
4356
4659
  if (!apiKey) {
@@ -4361,6 +4664,40 @@ function createClient4(config) {
4361
4664
  baseUrl: resolveConfigValue(config.baseUrl)
4362
4665
  });
4363
4666
  }
4667
+ function formatResearchTaskOutput(task) {
4668
+ const output = task.output;
4669
+ if (!output) {
4670
+ return {
4671
+ provider: linkupImplementation.id,
4672
+ text: "Linkup research completed without textual output."
4673
+ };
4674
+ }
4675
+ const outputRecord = asRecord2(output);
4676
+ const inputRecord = asRecord2(task.input);
4677
+ const outputType = inputRecord ? readString3(inputRecord.outputType) : void 0;
4678
+ const answer = outputRecord ? readString3(outputRecord.answer) : void 0;
4679
+ const sources = outputRecord ? readSources(outputRecord.sources) : [];
4680
+ if (outputType !== "structured" && answer !== void 0) {
4681
+ const lines = [answer];
4682
+ if (sources.length > 0) {
4683
+ lines.push("");
4684
+ lines.push("Sources:");
4685
+ for (const [index, source] of sources.entries()) {
4686
+ lines.push(`${index + 1}. ${source.title}`);
4687
+ lines.push(` ${source.url}`);
4688
+ }
4689
+ }
4690
+ return {
4691
+ provider: linkupImplementation.id,
4692
+ text: lines.join("\n").trimEnd(),
4693
+ itemCount: sources.length
4694
+ };
4695
+ }
4696
+ return {
4697
+ provider: linkupImplementation.id,
4698
+ text: formatJson(output)
4699
+ };
4700
+ }
4364
4701
  function toSearchResult2(value) {
4365
4702
  const entry = asRecord2(value);
4366
4703
  if (!entry) {
@@ -4382,6 +4719,27 @@ function toSearchResult2(value) {
4382
4719
  metadata: Object.keys(metadata).length > 0 ? metadata : void 0
4383
4720
  };
4384
4721
  }
4722
+ function readSources(value) {
4723
+ if (!Array.isArray(value)) {
4724
+ return [];
4725
+ }
4726
+ return value.flatMap((entry) => {
4727
+ const source = asRecord2(entry);
4728
+ if (!source) {
4729
+ return [];
4730
+ }
4731
+ const url2 = readString3(source.url);
4732
+ if (!url2) {
4733
+ return [];
4734
+ }
4735
+ return [
4736
+ {
4737
+ title: readString3(source.name) ?? url2,
4738
+ url: url2
4739
+ }
4740
+ ];
4741
+ });
4742
+ }
4385
4743
  function asRecord2(value) {
4386
4744
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
4387
4745
  }
@@ -4435,6 +4793,17 @@ var linkupProvider = defineProvider({
4435
4793
  input.options
4436
4794
  );
4437
4795
  }
4796
+ }),
4797
+ research: defineCapability({
4798
+ options: linkupImplementation.getToolOptionsSchema?.("research"),
4799
+ async execute(input, ctx) {
4800
+ return await linkupImplementation.research(
4801
+ input.input,
4802
+ ctx.config,
4803
+ ctx,
4804
+ input.options
4805
+ );
4806
+ }
4438
4807
  })
4439
4808
  }
4440
4809
  });
@@ -5849,7 +6218,7 @@ var serperImplementation = {
5849
6218
  requestOptions
5850
6219
  );
5851
6220
  const response = await fetch(
5852
- joinUrl(resolveConfigValue(config.baseUrl), requestOptions.mode),
6221
+ joinUrl2(resolveConfigValue(config.baseUrl), requestOptions.mode),
5853
6222
  {
5854
6223
  method: "POST",
5855
6224
  headers: {
@@ -5884,7 +6253,7 @@ var serperImplementation = {
5884
6253
  };
5885
6254
  }
5886
6255
  };
5887
- function joinUrl(baseUrl, mode = "search") {
6256
+ function joinUrl2(baseUrl, mode = "search") {
5888
6257
  const base2 = (baseUrl ?? DEFAULT_BASE_URL3).replace(/\/+$/, "");
5889
6258
  if (mode === "webpage" && base2 === DEFAULT_BASE_URL3) {
5890
6259
  return DEFAULT_SCRAPE_URL;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-web-providers",
3
- "version": "3.1.0",
3
+ "version": "3.3.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.7.0",
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"