pi-web-providers 1.1.0 → 2.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 CHANGED
@@ -12,11 +12,11 @@ off entirely.
12
12
 
13
13
  ## ✨ Features
14
14
 
15
- - **Multiple providers** Claude, Codex, Custom CLI, Exa, Gemini,
16
- Perplexity, Parallel, Valyu
17
- - **Batched search and answers** run several related queries in a single
15
+ - **Multiple providers**: Claude, Cloudflare, Codex, Exa, Firecrawl,
16
+ Gemini, Perplexity, Parallel, [Tavily](https://tavily.com), Valyu
17
+ - **Batched search and answers**: run several related queries in a single
18
18
  `web_search` or `web_answer` call and get grouped results back in one response
19
- - **Async contents prefetch** optionally start background `web_contents`
19
+ - **Async contents prefetch**: optionally start background `web_contents`
20
20
  extraction from `web_search` results and reuse the cached pages later
21
21
 
22
22
  ## 📦 Install
@@ -34,39 +34,45 @@ Run:
34
34
  ```
35
35
 
36
36
  This edits the global config file `~/.pi/agent/web-providers.json`. The
37
- settings UI mirrors the three sections below: tools, providers, and generic
38
- settings.
37
+ settings UI mirrors the three sections below: tools, providers, and settings.
39
38
 
40
39
  Each tool can be routed to any compatible provider:
41
40
 
42
- | Provider | search | contents | answer | research | Auth |
43
- | -------------- | :----: | :------: | :----: | :------: | ---------------------- |
44
- | **Claude** | ✔ | | ✔ | | Local Claude Code auth |
45
- | **Codex** | | | | | Local Codex CLI auth |
46
- | **Exa** | ✔ |||| `EXA_API_KEY` |
47
- | **Gemini** | ✔ | | ✔ | ✔ | `GOOGLE_API_KEY` |
48
- | **Perplexity** | ✔ | | ✔ | ✔ | `PERPLEXITY_API_KEY` |
49
- | **Parallel** | ✔ | ✔ | | | `PARALLEL_API_KEY` |
50
- | **Valyu** | ✔ || ✔ | ✔ | `VALYU_API_KEY` |
51
-
52
- Advanced option: `custom-cli` is a configurable adapter provider that can route
41
+ | Provider | search | contents | answer | research | Auth |
42
+ | -------------- | :----: | :------: | :----: | :------: | ------------------------------------------------ |
43
+ | **Claude** | ✔ | | ✔ | | Local Claude Code auth |
44
+ | **Cloudflare** | | | | | `CLOUDFLARE_API_TOKEN` + `CLOUDFLARE_ACCOUNT_ID` |
45
+ | **Codex** | ✔ | | | | Local Codex CLI auth |
46
+ | **Exa** | ✔ || ✔ | ✔ | `EXA_API_KEY` |
47
+ | **Firecrawl** | ✔ | ✔ | | | `FIRECRAWL_API_KEY` |
48
+ | **Gemini** | | | ✔ | ✔ | `GOOGLE_API_KEY` |
49
+ | **Perplexity** | ✔ | | ✔ | ✔ | `PERPLEXITY_API_KEY` |
50
+ | **Parallel** | ✔ | ✔ | | | `PARALLEL_API_KEY` |
51
+ | **Tavily** | ✔ | ✔ | | | `TAVILY_API_KEY` |
52
+ | **Valyu** | ✔ | ✔ | ✔ | ✔ | `VALYU_API_KEY` |
53
+
54
+ Advanced option: `custom` is a configurable adapter provider that can route
53
55
  any managed tool through a local wrapper command using a JSON stdin/stdout
54
56
  contract.
55
57
 
56
- See [`example-config.json`](example-config.json) for a full default
58
+ See [`example-config.json`](example-config.json) for the minimal default
57
59
  configuration.
58
60
 
59
61
  ### Tools
60
62
 
61
- Each managed tool maps to one provider id or `null` for off under the top-level
62
- `tools` key. A tool is only exposed when it is mapped to a compatible provider
63
- and that provider is currently available. Tool-specific settings live under
64
- `toolSettings`; today this covers `toolSettings.search.prefetch`.
63
+ Each managed tool maps to one provider id under the top-level `tools` key.
64
+ Removing a tool mapping turns that tool off. A tool is only exposed when it is
65
+ mapped to a compatible provider and that provider is currently available.
66
+ Shared defaults and tool-specific settings live under `settings`; search-specific
67
+ settings live under `settings.search`, and async research uses
68
+ `settings.researchTimeoutMs`.
65
69
 
66
70
  #### `web_search`
67
71
 
68
72
  Search the public web for up to 10 queries in one call. It returns grouped
69
- titles, URLs, and snippets for each query.
73
+ titles, URLs, and snippets for each query. Batch related queries when grouped
74
+ comparison matters; use separate sibling `web_search` calls when independent
75
+ results should arrive as soon as they are ready.
70
76
 
71
77
  <details>
72
78
  <summary><strong>Parameters and behavior</strong></summary>
@@ -81,14 +87,16 @@ titles, URLs, and snippets for each query.
81
87
  SDK. It accepts `provider`, `maxUrls`, `ttlMs`, and `contentsOptions`, and
82
88
  starts a background page-extraction workflow only when `prefetch.provider` is
83
89
  set. `/web-providers` can also persist default search prefetch settings under
84
- `toolSettings.search.prefetch`.
90
+ `settings.search`.
85
91
 
86
92
  </details>
87
93
 
88
94
  #### `web_contents`
89
95
 
90
96
  Read the main text from one or more web pages. It reuses cached pages when they
91
- match and fetches only missing or stale URLs.
97
+ match and fetches only missing or stale URLs. Batch related pages when they are
98
+ meant to be read as one bundle; use separate sibling `web_contents` calls when
99
+ each page can be acted on independently.
92
100
 
93
101
  <details>
94
102
  <summary><strong>Parameters and behavior</strong></summary>
@@ -99,7 +107,7 @@ match and fetches only missing or stale URLs.
99
107
  | `options` | object | — | Provider-specific extraction options |
100
108
 
101
109
  `web_contents` reuses any matching cached pages already present in the local
102
- content store—whether they came from prefetch or an earlier read—and only
110
+ in-memory cache—whether they came from prefetch or an earlier read—and only
103
111
  fetches missing or stale URLs.
104
112
 
105
113
  </details>
@@ -107,7 +115,9 @@ fetches missing or stale URLs.
107
115
  #### `web_answer`
108
116
 
109
117
  Answer one or more questions using web-grounded evidence. When you ask more
110
- than one question, the response is grouped into per-question sections.
118
+ than one question, the response is grouped into per-question sections. Batch
119
+ related questions when the answers belong together; split them into sibling
120
+ calls when earlier independent answers can unblock the next step.
111
121
 
112
122
  <details>
113
123
  <summary><strong>Parameters and behavior</strong></summary>
@@ -124,9 +134,10 @@ provided.
124
134
 
125
135
  #### `web_research`
126
136
 
127
- Investigate a topic across web sources and produce a longer report. The
128
- provider-specific `options` stay native to each SDK, and runtime options
129
- override provider configuration when both are set.
137
+ Investigate a topic across web sources and produce a longer report.
138
+ `web_research` is always asynchronous: it starts a background run, returns a
139
+ short dispatch notice immediately, and later posts a completion message with a
140
+ saved report path.
130
141
 
131
142
  <details>
132
143
  <summary><strong>Parameters and behavior</strong></summary>
@@ -136,34 +147,15 @@ override provider configuration when both are set.
136
147
  | `input` | string | required | Research brief or question |
137
148
  | `options` | object | — | Provider-specific options |
138
149
 
139
- `options` are provider-native and provider-specific. Equivalent concepts can use
150
+ `options` are provider-specific. Equivalent concepts can use
140
151
  different field names across SDKs—for example Perplexity uses `country`, Exa
141
152
  uses `userLocation`, and Valyu uses `countryCode`. Runtime `options` override
142
- provider-native config, but managed tool inputs and tool wiring stay fixed.
153
+ provider config, but managed tool inputs and tool wiring stay fixed.
143
154
 
144
- </details>
145
-
146
- <details>
147
- <summary><strong>Timeout, retry, and delivery modes</strong></summary>
148
-
149
- The extension accepts local control fields for robustness: `requestTimeoutMs`,
150
- `retryCount`, and `retryDelayMs` on request/response tools, plus
151
- `pollIntervalMs`, `timeoutMs`, `maxConsecutivePollErrors`, and `resumeId` on
152
- `web_research` for lifecycle-based research providers. These fields are handled
153
- by the extension and are not forwarded into the provider SDK call.
154
-
155
- - Exa and Valyu research support polling, overall deadlines, and resume IDs
156
- but reject `requestTimeoutMs` and do not retry non-idempotent job creation.
157
- - Perplexity research runs in streaming foreground mode and only supports
158
- `requestTimeoutMs`, `retryCount`, and `retryDelayMs`.
159
-
160
- Providers deliver results in one of three modes:
161
-
162
- - **Silent foreground** — no intermediate output; result returned when done.
163
- - **Streaming foreground** — progress updates while running, but the result is
164
- still only usable after the tool finishes.
165
- - **Background research** — the provider runs in the background; if
166
- interrupted, the run can be resumed later via `resumeId`.
155
+ Unlike the other managed tools, `web_research` does not accept local timeout,
156
+ retry, polling, or resume controls. Research has one opinionated execution
157
+ style: pi starts it asynchronously, tracks it locally, and saves the final
158
+ report under `.pi/artifacts/research/`.
167
159
 
168
160
  </details>
169
161
 
@@ -177,19 +169,56 @@ The built-in providers below are thin adapters around official SDKs.
177
169
  - SDK: `@anthropic-ai/claude-agent-sdk`
178
170
  - Uses Claude Code's built-in `WebSearch` and `WebFetch` tools behind a
179
171
  structured JSON adapter
180
- - Runs in **silent foreground** mode
181
172
  - Supports request-shaping `options` such as `model`, `thinking`, `effort`, and
182
173
  `maxTurns`
183
174
  - Great for search plus grounded answers if you already use Claude Code locally
184
175
 
185
176
  </details>
186
177
 
178
+ <details>
179
+ <summary><strong>Cloudflare</strong></summary>
180
+
181
+ - SDK: `cloudflare`
182
+ - Supports `web_contents` via Cloudflare Browser Rendering's `/markdown`
183
+ endpoint
184
+ - Good for JavaScript-heavy pages that need a real browser render before
185
+ extraction
186
+ - Supports provider-specific markdown options such as `gotoOptions`,
187
+ `waitForSelector`, `waitForTimeout`, `cacheTTL`, and request filtering
188
+
189
+ **Setup**
190
+
191
+ 1. In the Cloudflare dashboard, create an API token.
192
+ 2. Grant it this permission:
193
+ - `Account | Browser Rendering | Edit`
194
+ 3. Scope it to the account you want to use.
195
+ 4. Copy that account's **Account ID** from the Cloudflare dashboard.
196
+ 5. Configure pi with both values:
197
+
198
+ ```json
199
+ {
200
+ "tools": {
201
+ "contents": "cloudflare"
202
+ },
203
+ "providers": {
204
+ "cloudflare": {
205
+ "apiToken": "CLOUDFLARE_API_TOKEN",
206
+ "accountId": "CLOUDFLARE_ACCOUNT_ID"
207
+ }
208
+ }
209
+ }
210
+ ```
211
+
212
+ If Cloudflare returns `401 Authentication error`, the token permission, token
213
+ scope, or account ID is usually wrong.
214
+
215
+ </details>
216
+
187
217
  <details>
188
218
  <summary><strong>Codex</strong></summary>
189
219
 
190
220
  - SDK: `@openai/codex-sdk`
191
221
  - Runs in read-only mode with web search enabled
192
- - Runs in **silent foreground** mode
193
222
  - Supports request-shaping `web_search.options` such as `model`,
194
223
  `modelReasoningEffort`, and `webSearchMode`
195
224
  - Best if you already use the local Codex CLI and auth flow
@@ -200,22 +229,37 @@ The built-in providers below are thin adapters around official SDKs.
200
229
  <summary><strong>Exa</strong></summary>
201
230
 
202
231
  - SDK: `exa-js`
203
- - Search, contents, and answer run in **silent foreground** mode
204
- - Research runs in **background research** mode and supports `resumeId`
232
+ - Supports `web_search`, `web_contents`, `web_answer`, and `web_research`
233
+ - `web_research` is exposed through pi's async research workflow
205
234
  - Neural, keyword, hybrid, and deep-research search modes
206
235
  - Inline text-content extraction on search results
207
236
 
208
237
  </details>
209
238
 
239
+ <details>
240
+ <summary><strong>Firecrawl</strong></summary>
241
+
242
+ - SDK: `@mendable/firecrawl-js`
243
+ - Supports `web_search` and `web_contents`
244
+ - Search can optionally include Firecrawl scrape-backed result enrichment
245
+ - Contents extraction uses Firecrawl scrape with markdown-first defaults
246
+ - Supports provider-specific `options.search` such as `sources`, `categories`,
247
+ `location`, `timeout`, and `scrapeOptions`
248
+ - Supports provider-specific `options.scrape` such as `formats`,
249
+ `onlyMainContent`, `waitFor`, `headers`, `location`, `mobile`, `proxy`, and
250
+ cache controls
251
+
252
+ </details>
253
+
210
254
  <details>
211
255
  <summary><strong>Gemini</strong></summary>
212
256
 
213
257
  - SDK: `@google/genai`
214
- - Search and answer run in **silent foreground** mode
215
- - Research runs in **background research** mode and supports `resumeId`
258
+ - Supports `web_search`, `web_answer`, and `web_research`
259
+ - `web_research` is exposed through pi's async research workflow
216
260
  - Google Search grounding for answers
217
261
  - Deep-research agents via Google's Gemini API
218
- - Supports provider-native request options such as `model`, `config`,
262
+ - Supports provider-specific request options such as `model`, `config`,
219
263
  `generation_config`, and `agent_config` depending on the tool
220
264
 
221
265
  </details>
@@ -224,8 +268,8 @@ The built-in providers below are thin adapters around official SDKs.
224
268
  <summary><strong>Perplexity</strong></summary>
225
269
 
226
270
  - SDK: `@perplexity-ai/perplexity_ai`
227
- - `web_search` and `web_answer` run in **silent foreground** mode
228
- - `web_research` runs in **streaming foreground** mode (no `resumeId` support)
271
+ - Supports `web_search`, `web_answer`, and `web_research`
272
+ - `web_research` is exposed through pi's async research workflow
229
273
  - Uses Perplexity Search for `web_search`
230
274
  - Uses Sonar for `web_answer` and `sonar-deep-research` for `web_research`
231
275
  - Supports provider-specific `web_search.options` such as `country`,
@@ -237,10 +281,25 @@ The built-in providers below are thin adapters around official SDKs.
237
281
  <summary><strong>Parallel</strong></summary>
238
282
 
239
283
  - SDK: `parallel-web`
240
- - Runs in **silent foreground** mode
241
284
  - Agentic and one-shot search modes
242
285
  - Page content extraction with excerpt and full-content toggles
243
- - Supports provider-native search and extraction options from the Parallel SDK
286
+ - Supports provider-specific search and extraction options from the Parallel SDK
287
+
288
+ </details>
289
+
290
+ <details>
291
+ <summary><strong>Tavily</strong></summary>
292
+
293
+ - SDK: `@tavily/core`
294
+ - Supports `web_search` via Tavily Search
295
+ - Supports `web_contents` via Tavily Extract
296
+ - Good for pairing LLM-oriented web search with lightweight page extraction
297
+ - Supports provider-specific `options.search` such as `searchDepth`, `topic`,
298
+ `timeRange`, `includeRawContent`, `includeDomains`, `excludeDomains`,
299
+ `country`, `exactMatch`, and `includeFavicon`
300
+ - Supports provider-specific `options.extract` such as `extractDepth`,
301
+ `format`, `includeImages`, `query`, `chunksPerSource`, and
302
+ `includeFavicon`
244
303
 
245
304
  </details>
246
305
 
@@ -248,23 +307,23 @@ The built-in providers below are thin adapters around official SDKs.
248
307
  <summary><strong>Valyu</strong></summary>
249
308
 
250
309
  - SDK: `valyu-js`
251
- - Search, contents, and answer run in **silent foreground** mode
252
- - Research runs in **background research** mode and supports `resumeId`
310
+ - Supports `web_search`, `web_contents`, `web_answer`, and `web_research`
311
+ - `web_research` is exposed through pi's async research workflow
253
312
  - Web, proprietary, and news search types
254
- - Supports provider-native options such as `countryCode`, `responseLength`, and
313
+ - Supports provider-specific options such as `countryCode`, `responseLength`, and
255
314
  search/source filters
256
315
  - Configurable response length for answers and research
257
316
 
258
317
  </details>
259
318
 
260
- ### Custom CLI provider
319
+ ### Custom provider
261
320
 
262
- The `custom-cli` provider lets you bring your own wrapper command for any
321
+ The `custom` provider lets you bring your own wrapper command for any
263
322
  managed tool. Each capability can point at a different local command under
264
- `providers["custom-cli"].native`.
323
+ `providers["custom"].options`.
265
324
 
266
325
  The repo includes actual wrapper examples under
267
- [`examples/custom-cli/wrappers/`](examples/custom-cli/wrappers/). They are
326
+ [`examples/custom/wrappers/`](examples/custom/wrappers/). They are
268
327
  small bash scripts that use `jq` for JSON handling. Each one uses a different
269
328
  backend pattern:
270
329
 
@@ -281,15 +340,14 @@ Copy the example wrappers into a local `./wrappers/` directory, then configure:
281
340
  ```json
282
341
  {
283
342
  "tools": {
284
- "search": "custom-cli",
285
- "contents": "custom-cli",
286
- "answer": "custom-cli",
287
- "research": "custom-cli"
343
+ "search": "custom",
344
+ "contents": "custom",
345
+ "answer": "custom",
346
+ "research": "custom"
288
347
  },
289
348
  "providers": {
290
- "custom-cli": {
291
- "enabled": true,
292
- "native": {
349
+ "custom": {
350
+ "options": {
293
351
  "search": {
294
352
  "argv": ["bash", "./wrappers/codex-search.sh"]
295
353
  },
@@ -316,9 +374,9 @@ one wrapper must run from a specific directory. Use `env` for per-command
316
374
  variables; each value can be a literal string, an environment variable name, or
317
375
  `!command`.
318
376
 
319
- `web_research` runs as a foreground wrapper command, so local polling controls
320
- (`pollIntervalMs`, `timeoutMs`, `maxConsecutivePollErrors`) and `resumeId` do
321
- not apply to `custom-cli`.
377
+ `web_research` uses the same async workflow as every other research provider:
378
+ pi starts the wrapper in the background, tracks the job locally, and writes the
379
+ final report to a file when it finishes.
322
380
 
323
381
  Wrapper contract:
324
382
 
@@ -326,31 +384,51 @@ Wrapper contract:
326
384
  inputs (`query`, `urls`, `input`, `maxResults`, `options`, `cwd`)
327
385
  - `stdout`: one JSON response object
328
386
  - `search`: `{ "results": [{ "title", "url", "snippet" }] }`
329
- - `contents` / `answer` / `research`: `{ "text": "...", "summary"?: "...", "itemCount"?: 1, "metadata"?: {} }`
387
+ - `contents`: `{ "answers": [{ "url", "content"?: "...", "summary"?: unknown, "metadata"?: {}, "error"?: "..." }] }`
388
+ - `answer` / `research`: `{ "text": "...", "summary"?: "...", "itemCount"?: 1, "metadata"?: {} }`
330
389
  - `stderr`: optional progress lines
331
390
  - exit code `0`: success
332
391
  - non-zero exit code: failure
333
392
 
334
393
  </details>
335
394
 
336
- See [`examples/custom-cli/README.md`](examples/custom-cli/README.md) for a
395
+ See [`examples/custom/README.md`](examples/custom/README.md) for a
337
396
  copy-and-pasteable setup, and see
338
- [`examples/custom-cli/wrappers/`](examples/custom-cli/wrappers/) for the actual
397
+ [`examples/custom/wrappers/`](examples/custom/wrappers/) for the actual
339
398
  wrapper files.
340
399
 
341
- ### Generic settings
400
+ ### Settings
342
401
 
343
- The `genericSettings` block sets shared execution defaults that apply to all
344
- providers unless overridden in a provider's `policy` block:
402
+ The `settings` block holds shared execution defaults that apply to all
403
+ providers unless overridden in a provider's own `settings` block:
404
+
405
+ | Field | Default | Description |
406
+ | ------------------- | --------- | ----------------------------------------------------------- |
407
+ | `requestTimeoutMs` | `30000` | Maximum time for a single provider request |
408
+ | `retryCount` | `3` | Retries for transient failures |
409
+ | `retryDelayMs` | `2000` | Initial delay before retrying |
410
+ | `researchTimeoutMs` | `1800000` | Maximum total time for an async `web_research` job (30 min) |
411
+
412
+ ## 🔎 Live smoke tests
413
+
414
+ Use the opt-in live smoke runner to validate the configured providers with the
415
+ same config-resolution and execution path the extension uses at runtime:
416
+
417
+ ```bash
418
+ npm run smoke:live
419
+ ```
420
+
421
+ Optional filters:
422
+
423
+ ```bash
424
+ npm run smoke:live -- --provider gemini
425
+ npm run smoke:live -- --tool contents
426
+ npm run smoke:live -- --include-research
427
+ ```
345
428
 
346
- | Field | Default | Description |
347
- | ---------------------------------- | ---------- | ---------------------------------------------- |
348
- | `requestTimeoutMs` | `30000` | Maximum time for a single provider request |
349
- | `retryCount` | `3` | Retries for transient failures |
350
- | `retryDelayMs` | `2000` | Initial delay before retrying |
351
- | `researchPollIntervalMs` | `3000` | How often to poll long-running research jobs |
352
- | `researchTimeoutMs` | `21600000` | Overall deadline for research before returning |
353
- | `researchMaxConsecutivePollErrors` | `3` | Consecutive poll failures before stopping |
429
+ The default run exercises `search`, `contents`, and `answer`. Research probes
430
+ are excluded unless you pass `--include-research`, because they are slower and
431
+ may incur higher provider cost.
354
432
 
355
433
  ## 📄 License
356
434