webfox 0.0.0-test.0 → 4.0.1

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 (118) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +256 -3
  3. package/assets/webfox-lockup-dark.png +0 -0
  4. package/assets/webfox-lockup.png +0 -0
  5. package/dist/adapter-2YBFCBCZ.js +161 -0
  6. package/dist/adapter-67TIISDW.js +753 -0
  7. package/dist/adapter-AB7LKV7N.js +324 -0
  8. package/dist/adapter-AUYLTDPM.js +73 -0
  9. package/dist/adapter-HITGYUXN.js +494 -0
  10. package/dist/adapter-HPTMLH75.js +334 -0
  11. package/dist/adapter-I6OUKBZQ.js +492 -0
  12. package/dist/adapter-ISZQTZDP.js +166 -0
  13. package/dist/adapter-MAG7X663.js +230 -0
  14. package/dist/adapter-NEXSOHGT.js +232 -0
  15. package/dist/adapter-PADXKW43.js +162 -0
  16. package/dist/adapter-SDQX2533.js +123 -0
  17. package/dist/adapter-UAZNLDSS.js +237 -0
  18. package/dist/adapter-XBAQSK7I.js +282 -0
  19. package/dist/application-types.d.ts +34 -0
  20. package/dist/application.d.ts +2 -0
  21. package/dist/chunk-EF4VMDZL.js +85 -0
  22. package/dist/chunk-G2YAQEET.js +38 -0
  23. package/dist/chunk-GAWPRXAU.js +3051 -0
  24. package/dist/chunk-I2UIACY3.js +12 -0
  25. package/dist/chunk-MVCCEPDF.js +762 -0
  26. package/dist/chunk-QRHDXM2L.js +31 -0
  27. package/dist/chunk-U4BLULLV.js +52 -0
  28. package/dist/chunk-WCTOYZVB.js +85 -0
  29. package/dist/chunk-X6ZBIHZC.js +21 -0
  30. package/dist/chunk-YZXM4U2C.js +21 -0
  31. package/dist/chunk-ZVTVERW5.js +20 -0
  32. package/dist/cli.js +641 -0
  33. package/dist/config.schema.json +4270 -0
  34. package/dist/configuration/defaults.d.ts +3 -0
  35. package/dist/configuration/file.d.ts +17 -0
  36. package/dist/configuration/options-schema.d.ts +2 -0
  37. package/dist/configuration/planning.d.ts +10 -0
  38. package/dist/configuration/schema.d.ts +9 -0
  39. package/dist/configuration/types.d.ts +37 -0
  40. package/dist/contents.d.ts +19 -0
  41. package/dist/domain.d.ts +89 -0
  42. package/dist/errors.d.ts +17 -0
  43. package/dist/index.d.ts +8 -0
  44. package/dist/index.js +38 -0
  45. package/dist/package-metadata.d.ts +3 -0
  46. package/dist/pi-keybindings.d.ts +1 -0
  47. package/dist/pi-params.d.ts +3 -0
  48. package/dist/pi-render.d.ts +50 -0
  49. package/dist/pi-search-render.d.ts +4 -0
  50. package/dist/pi-text.d.ts +4 -0
  51. package/dist/pi-validation.d.ts +4 -0
  52. package/dist/pi.d.ts +2 -0
  53. package/dist/pi.js +563 -0
  54. package/dist/providers/brave/adapter.d.ts +7 -0
  55. package/dist/providers/brave/definition.d.ts +1 -0
  56. package/dist/providers/brave/types.d.ts +4 -0
  57. package/dist/providers/cli-json.d.ts +9 -0
  58. package/dist/providers/cloudflare/adapter.d.ts +5 -0
  59. package/dist/providers/cloudflare/definition.d.ts +1 -0
  60. package/dist/providers/cloudflare/types.d.ts +4 -0
  61. package/dist/providers/contract.d.ts +88 -0
  62. package/dist/providers/custom/adapter.d.ts +9 -0
  63. package/dist/providers/custom/definition.d.ts +1 -0
  64. package/dist/providers/custom/types.d.ts +9 -0
  65. package/dist/providers/definition.d.ts +32 -0
  66. package/dist/providers/exa/adapter.d.ts +8 -0
  67. package/dist/providers/exa/definition.d.ts +1 -0
  68. package/dist/providers/exa/types.d.ts +4 -0
  69. package/dist/providers/firecrawl/adapter.d.ts +7 -0
  70. package/dist/providers/firecrawl/definition.d.ts +1 -0
  71. package/dist/providers/firecrawl/types.d.ts +4 -0
  72. package/dist/providers/gemini/adapter.d.ts +14 -0
  73. package/dist/providers/gemini/definition.d.ts +1 -0
  74. package/dist/providers/gemini/types.d.ts +3 -0
  75. package/dist/providers/linkup/adapter.d.ts +7 -0
  76. package/dist/providers/linkup/definition.d.ts +1 -0
  77. package/dist/providers/linkup/types.d.ts +4 -0
  78. package/dist/providers/metadata.d.ts +15 -0
  79. package/dist/providers/ollama/adapter.d.ts +6 -0
  80. package/dist/providers/ollama/definition.d.ts +1 -0
  81. package/dist/providers/ollama/types.d.ts +4 -0
  82. package/dist/providers/openai/adapter.d.ts +7 -0
  83. package/dist/providers/openai/definition.d.ts +1 -0
  84. package/dist/providers/openai/types.d.ts +28 -0
  85. package/dist/providers/parallel/adapter.d.ts +6 -0
  86. package/dist/providers/parallel/definition.d.ts +1 -0
  87. package/dist/providers/parallel/types.d.ts +4 -0
  88. package/dist/providers/perplexity/adapter.d.ts +7 -0
  89. package/dist/providers/perplexity/definition.d.ts +1 -0
  90. package/dist/providers/perplexity/types.d.ts +4 -0
  91. package/dist/providers/registry.d.ts +16 -0
  92. package/dist/providers/serper/adapter.d.ts +5 -0
  93. package/dist/providers/serper/definition.d.ts +1 -0
  94. package/dist/providers/serper/types.d.ts +21 -0
  95. package/dist/providers/shared.d.ts +4 -0
  96. package/dist/providers/tavily/adapter.d.ts +6 -0
  97. package/dist/providers/tavily/definition.d.ts +1 -0
  98. package/dist/providers/tavily/types.d.ts +4 -0
  99. package/dist/providers/valyu/adapter.d.ts +8 -0
  100. package/dist/providers/valyu/definition.d.ts +1 -0
  101. package/dist/providers/valyu/types.d.ts +4 -0
  102. package/dist/render.d.ts +5 -0
  103. package/dist/runtime/credentials.d.ts +15 -0
  104. package/dist/runtime/duration.d.ts +2 -0
  105. package/dist/runtime/execute.d.ts +20 -0
  106. package/dist/runtime/lifecycle.d.ts +8 -0
  107. package/dist/runtime/outward.d.ts +11 -0
  108. package/dist/runtime/polling.d.ts +13 -0
  109. package/dist/runtime/process.d.ts +4 -0
  110. package/docs/cli-experience.md +177 -0
  111. package/docs/provider.md +177 -0
  112. package/docs/reference.md +181 -0
  113. package/example-config.yaml +36 -0
  114. package/examples/custom/README.md +57 -0
  115. package/examples/custom/provider.mjs +54 -0
  116. package/examples/custom/webfox.json +18 -0
  117. package/package.json +122 -8
  118. package/index.js +0 -2
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,5 +1,258 @@
1
- # webfox
1
+ <h1 align="center">
2
+ <picture>
3
+ <source media="(prefers-color-scheme: dark)" srcset="./assets/webfox-lockup-dark.png">
4
+ <img src="./assets/webfox-lockup.png" alt="webfox" width="520">
5
+ </picture>
6
+ </h1>
2
7
 
3
- Publication-test prerelease. This package does not yet implement the planned web CLI or library.
8
+ **The web, from your terminal.**
4
9
 
5
- Do not use this prerelease in production.
10
+ Search the web, extract pages, get grounded answers, and run deep research with
11
+ one command: `web`. Choose your providers, bring your API keys, and use the same
12
+ configuration in your terminal, TypeScript applications, and pi.
13
+
14
+ > [!IMPORTANT]
15
+ > **Coming from pi-web-providers?** Webfox continues the project as **v4.0.0**.
16
+ > Replace the old Pi package:
17
+ >
18
+ > ```sh
19
+ > pi remove npm:pi-web-providers
20
+ > pi install npm:webfox
21
+ > ```
22
+ >
23
+ > Recreate your provider defaults in the [Webfox configuration](./docs/reference.md#configuration)
24
+ > and restart pi. The old `~/.pi/agent/web-providers.json` settings aren't imported.
25
+
26
+ ## 🚀 Installation
27
+
28
+ - **Terminal:** Install the `web` command:
29
+
30
+ ```sh
31
+ npm install -g webfox
32
+ ```
33
+ - **TypeScript:** Add `webfox` as an application dependency.
34
+ - **Pi:** Install the extension:
35
+
36
+ ```sh
37
+ pi install npm:webfox
38
+ ```
39
+
40
+ Then follow [Use with Pi](#-use-with-pi) to select a web provider and supply its
41
+ API key.
42
+
43
+ ## ✨ Usage
44
+
45
+ Set an API key and make your first request. For example, with Brave Search:
46
+
47
+ ```sh
48
+ export BRAVE_SEARCH_API_KEY=…
49
+ web search "Node.js release notes" --provider brave
50
+ ```
51
+
52
+ Save your provider choice so you don't need to repeat it:
53
+
54
+ ```sh
55
+ web config default search brave
56
+ web search "TypeBox validation"
57
+ ```
58
+
59
+ Choose a provider for each capability, or override it with `--provider`. API keys
60
+ alone never select a provider.
61
+
62
+ ### Four commands
63
+
64
+ ```sh
65
+ web search "Node.js cancellation" "Bun cancellation"
66
+ web contents https://example.com/a https://example.com/b --provider tavily
67
+ web answer "What is MCP?" --provider openai --model gpt-6-astra
68
+ web research "Compare databases for an analytics service" --provider gemini --timeout 20m
69
+ ```
70
+
71
+ Each provider needs its own credentials. Research runs in the foreground and
72
+ shows progress while you wait. Ctrl-C stops waiting, but may not cancel an
73
+ already-running, billable research job at the provider.
74
+
75
+ ### Find providers and options
76
+
77
+ ```sh
78
+ web providers
79
+ web providers openai
80
+ web search --help
81
+ web search --provider openai --help
82
+ ```
83
+
84
+ Provider-specific help lists the options available for that provider, such as
85
+ models, source filters, and page extraction settings.
86
+
87
+ ### Use pipes and scripts
88
+
89
+ Quote each independent query or question. Search and answer accept up to ten
90
+ inputs; research accepts one brief. Omit the input to read from a pipe or file:
91
+
92
+ ```sh
93
+ # Read from files
94
+ web search < query.txt
95
+ web answer --provider openai < question.txt
96
+ web research --provider gemini < brief.md
97
+ web contents --provider tavily < urls.txt
98
+
99
+ # Pipe input
100
+ echo "What is MCP?" | web answer --provider openai
101
+ echo "https://example.com" | web contents --provider tavily
102
+
103
+ # Save or process JSON results
104
+ web search "TypeBox" --format json > results.json
105
+ web search "TypeBox" --format json | jq -r '.results[] | select(.ok) | .value.results[].url'
106
+ ```
107
+
108
+ Contents reads one URL per line. The other commands read the entire stdin stream
109
+ as one input. Positional arguments take precedence over stdin; `-` is optional.
110
+ Text is the default, including when piped. Use `--format json` for structured
111
+ results; the last example uses `jq` to extract result URLs.
112
+
113
+ Results go to stdout; progress and errors go to stderr. `--quiet` hides progress
114
+ and success notices, not errors. Use `--timeout 30s` or `--timeout 20m` to set a
115
+ deadline, and `--no-color` or `NO_COLOR` to disable colors.
116
+
117
+ See the [CLI reference](./docs/cli-experience.md) for output formats, exit codes,
118
+ and scripting details.
119
+
120
+ ## 🔌 Providers
121
+
122
+ Use different providers for different tasks:
123
+
124
+ | Provider | Search | Contents | Answer | Research |
125
+ | ------------ | :----: | :------: | :----: | :------: |
126
+ | [Brave] | ✔︎ | | ✔︎ | ✔︎ |
127
+ | [Cloudflare] | | ✔︎ | | |
128
+ | [Custom] | ✔︎ | ✔︎ | ✔︎ | ✔︎ |
129
+ | [Exa] | ✔︎ | ✔︎ | ✔︎ | ✔︎ |
130
+ | [Firecrawl] | ✔︎ | ✔︎ | ✔︎ | |
131
+ | [Gemini] | | | ✔︎ | ✔︎ |
132
+ | [Linkup] | ✔︎ | ✔︎ | | ✔︎ |
133
+ | [Ollama] | ✔︎ | ✔︎ | | |
134
+ | [OpenAI] | ✔︎ | | ✔︎ | ✔︎ |
135
+ | [Parallel] | ✔︎ | ✔︎ | | |
136
+ | [Perplexity] | ✔︎ | | ✔︎ | ✔︎ |
137
+ | [Serper] | ✔︎ | | | |
138
+ | [Tavily] | ✔︎ | ✔︎ | | |
139
+ | [Valyu] | ✔︎ | ✔︎ | ✔︎ | ✔︎ |
140
+
141
+ [Brave]: ./docs/provider.md#brave
142
+ [Cloudflare]: ./docs/provider.md#cloudflare
143
+ [Custom]: ./docs/provider.md#custom
144
+ [Exa]: ./docs/provider.md#exa
145
+ [Firecrawl]: ./docs/provider.md#firecrawl
146
+ [Gemini]: ./docs/provider.md#gemini
147
+ [Linkup]: ./docs/provider.md#linkup
148
+ [Ollama]: ./docs/provider.md#ollama
149
+ [OpenAI]: ./docs/provider.md#openai
150
+ [Parallel]: ./docs/provider.md#parallel
151
+ [Perplexity]: ./docs/provider.md#perplexity
152
+ [Serper]: ./docs/provider.md#serper
153
+ [Tavily]: ./docs/provider.md#tavily
154
+ [Valyu]: ./docs/provider.md#valyu
155
+
156
+ See the [provider guide](./docs/provider.md) for credentials, examples, and caveats.
157
+
158
+ ## ⚙️ Configuration
159
+
160
+ Save choices with `web config default`, or edit YAML for more control:
161
+
162
+ ```sh
163
+ web config path
164
+ web config show
165
+ web config validate
166
+ ```
167
+
168
+ `show` hides credentials. `validate` checks your settings without making requests.
169
+ The default file is `~/.config/webfox/config.yaml`, respecting `XDG_CONFIG_HOME`
170
+ or, on Windows, `APPDATA`. Override it with `WEBFOX_CONFIG` or `--config <path>`.
171
+
172
+ For example:
173
+
174
+ ```yaml
175
+ $schema: https://unpkg.com/webfox@4.0.0/dist/config.schema.json
176
+ defaults:
177
+ search:
178
+ provider: brave
179
+ maxResults: 5
180
+ answer:
181
+ provider: openai
182
+ providers:
183
+ openai:
184
+ options:
185
+ answer:
186
+ model: gpt-6-astra
187
+ ```
188
+
189
+ Standard API key environment variables work without a credentials section. Run
190
+ `web providers <id>` to find the names for your provider. You can also read keys
191
+ from a password manager rather than store them in the file.
192
+
193
+ See the [example configuration](./example-config.yaml) and
194
+ [configuration reference](./docs/reference.md#configuration) for credential
195
+ commands, timeouts, retries, and provider defaults.
196
+
197
+ ## 🤖 Use with Pi
198
+
199
+ Install the [Pi](https://pi.dev) extension:
200
+
201
+ ```sh
202
+ pi install npm:webfox
203
+ ```
204
+
205
+ Add to `~/.config/webfox/config.yaml`:
206
+
207
+ ```yaml
208
+ defaults:
209
+ search:
210
+ provider: brave
211
+ ```
212
+
213
+ Start Pi with your API key:
214
+
215
+ ```sh
216
+ export BRAVE_SEARCH_API_KEY=…
217
+ pi
218
+ ```
219
+
220
+ Ask Pi: **Search the web for the latest Node.js release notes.**
221
+
222
+ Add `contents`, `answer`, or `research` defaults for more tools.
223
+ Restart Pi after changing defaults.
224
+
225
+ ## 📚 Use with TypeScript
226
+
227
+ ```ts
228
+ import { createWebfox } from "webfox";
229
+
230
+ const web = createWebfox();
231
+ const document = await web.search({
232
+ provider: "brave",
233
+ queries: ["Node.js AbortSignal"],
234
+ maxResults: 5,
235
+ });
236
+
237
+ for (const result of document.results) {
238
+ if (result.ok) console.log(result.value.results);
239
+ else console.error(result.error.message);
240
+ }
241
+ ```
242
+
243
+ The client also provides `contents`, `answer`, and `research`. See the
244
+ [library reference](./docs/reference.md#typescript-library) for request controls,
245
+ configuration, progress, and errors.
246
+
247
+ ## 🩺 Troubleshooting
248
+
249
+ - **No provider selected:** Pass `--provider <id>` or save a default with
250
+ `web config default <capability> <provider>`.
251
+ - **Missing credentials:** Run `web providers <id>` to check the required key
252
+ names, or see the [provider guide](./docs/provider.md).
253
+ - **No pi tools:** Select default providers in the shared configuration and
254
+ restart pi. Installing the extension or setting keys alone isn't enough.
255
+
256
+ ## 📄 License
257
+
258
+ [MIT](LICENSE)
Binary file
Binary file
@@ -0,0 +1,161 @@
1
+ import {
2
+ formatJson,
3
+ trimSnippet
4
+ } from "./chunk-X6ZBIHZC.js";
5
+ import {
6
+ orderedContents
7
+ } from "./chunk-YZXM4U2C.js";
8
+ import "./chunk-U4BLULLV.js";
9
+
10
+ // src/providers/parallel/adapter.ts
11
+ import ParallelClient from "parallel-web";
12
+ var parallelImplementation = {
13
+ async search(query, maxResults, config, context, options) {
14
+ const client = createClient(config);
15
+ const response = await client.search(
16
+ buildParallelSearchParams(query, maxResults, {
17
+ ...options ?? {}
18
+ }),
19
+ buildRequestOptions(context)
20
+ );
21
+ return {
22
+ provider: "parallel",
23
+ results: response.results.slice(0, maxResults).map((result) => ({
24
+ title: result.title ?? result.url,
25
+ url: result.url,
26
+ snippet: trimSnippet(result.excerpts?.join(" ") ?? "")
27
+ }))
28
+ };
29
+ },
30
+ async contents(urls, config, context, options) {
31
+ const client = createClient(config);
32
+ const response = await client.extract(
33
+ buildParallelExtractParams(urls, {
34
+ ...options ?? {}
35
+ }),
36
+ buildRequestOptions(context)
37
+ );
38
+ const resultsByUrl = new Map(
39
+ response.results.map((result) => [result.url, result])
40
+ );
41
+ const errorsByUrl = new Map(
42
+ response.errors.map((error) => [error.url, error])
43
+ );
44
+ return {
45
+ provider: "parallel",
46
+ answers: urls.map((url) => {
47
+ const result = resultsByUrl.get(url) ?? (urls.length === 1 && response.results.length === 1 ? response.results[0] : void 0);
48
+ if (result) {
49
+ return {
50
+ url: result.url,
51
+ content: result.full_content ?? result.excerpts?.join("\n\n") ?? void 0,
52
+ metadata: result
53
+ };
54
+ }
55
+ const error = errorsByUrl.get(url) ?? (urls.length === 1 && response.errors.length === 1 ? response.errors[0] : void 0);
56
+ return error ? {
57
+ url,
58
+ error: formatJson(error)
59
+ } : {
60
+ url,
61
+ error: "No content returned for this URL."
62
+ };
63
+ })
64
+ };
65
+ }
66
+ };
67
+ function buildParallelSearchParams(query, maxResults, options) {
68
+ const {
69
+ advanced_settings: advancedSettingsValue,
70
+ max_results: _legacyMaxResults,
71
+ mode: modeValue,
72
+ objective: objectiveValue,
73
+ search_queries: _searchQueries,
74
+ ...rest
75
+ } = options;
76
+ const advancedSettings = readObjectOption(advancedSettingsValue);
77
+ const mode = normalizeParallelSearchMode(modeValue);
78
+ const objective = typeof objectiveValue === "string" && objectiveValue.trim() ? objectiveValue.trim() : query;
79
+ return {
80
+ ...rest,
81
+ search_queries: [query],
82
+ objective,
83
+ ...mode ? { mode } : {},
84
+ advanced_settings: {
85
+ ...advancedSettings,
86
+ max_results: maxResults
87
+ }
88
+ };
89
+ }
90
+ function buildParallelExtractParams(urls, options) {
91
+ const {
92
+ advanced_settings: advancedSettingsValue,
93
+ excerpts: excerptsValue,
94
+ full_content: fullContentValue,
95
+ ...rest
96
+ } = options;
97
+ const advancedSettings = readObjectOption(advancedSettingsValue);
98
+ if (typeof fullContentValue === "boolean") {
99
+ advancedSettings.full_content = fullContentValue;
100
+ }
101
+ if (typeof excerptsValue === "boolean" && advancedSettings.excerpt_settings === void 0) {
102
+ advancedSettings.excerpt_settings = excerptsValue ? {} : { max_chars_per_result: 0 };
103
+ }
104
+ return {
105
+ ...rest,
106
+ urls,
107
+ advanced_settings: advancedSettings
108
+ };
109
+ }
110
+ function normalizeParallelSearchMode(value) {
111
+ switch (value) {
112
+ case "advanced":
113
+ case "basic":
114
+ case "fast":
115
+ case "turbo":
116
+ return value;
117
+ default:
118
+ return void 0;
119
+ }
120
+ }
121
+ function readObjectOption(value) {
122
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? { ...value } : {};
123
+ }
124
+ function createClient(config) {
125
+ const apiKey = config.credentials?.api;
126
+ if (!apiKey) {
127
+ throw new Error("is missing an API key");
128
+ }
129
+ return new ParallelClient({
130
+ maxRetries: 0,
131
+ apiKey,
132
+ baseURL: config.baseUrl
133
+ });
134
+ }
135
+ function buildRequestOptions(context) {
136
+ return context.signal ? { signal: context.signal } : void 0;
137
+ }
138
+ var adapter = {
139
+ async search(input, config, context) {
140
+ return await parallelImplementation.search(
141
+ input.query,
142
+ input.maxResults,
143
+ config,
144
+ context,
145
+ input.options
146
+ );
147
+ },
148
+ async contents(input, config, context) {
149
+ return orderedContents(
150
+ await parallelImplementation.contents(
151
+ input.urls,
152
+ config,
153
+ context,
154
+ input.options
155
+ )
156
+ );
157
+ }
158
+ };
159
+ export {
160
+ adapter
161
+ };