webfox 4.9.0 → 4.10.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
@@ -144,6 +144,7 @@ Use different providers for different tasks:
144
144
  | [Exa] | ✔︎ | ✔︎ | ✔︎ | ✔︎ |
145
145
  | [Firecrawl] | ✔︎ | ✔︎ | ✔︎ | |
146
146
  | [Gemini] | | | ✔︎ | ✔︎ |
147
+ | [Keenable] | ✔︎ | | | |
147
148
  | [Linkup] | ✔︎ | ✔︎ | | ✔︎ |
148
149
  | [Ollama] | ✔︎ | ✔︎ | | |
149
150
  | [OpenAI] | ✔︎ | | ✔︎ | ✔︎ |
@@ -161,6 +162,7 @@ Use different providers for different tasks:
161
162
  [Exa]: ./docs/provider.md#exa
162
163
  [Firecrawl]: ./docs/provider.md#firecrawl
163
164
  [Gemini]: ./docs/provider.md#gemini
165
+ [Keenable]: ./docs/provider.md#keenable
164
166
  [Linkup]: ./docs/provider.md#linkup
165
167
  [Ollama]: ./docs/provider.md#ollama
166
168
  [OpenAI]: ./docs/provider.md#openai
@@ -2,11 +2,11 @@ import {
2
2
  SERPBASE_MODES,
3
3
  serpbaseProvider,
4
4
  validateOptions
5
- } from "./chunk-LTJOWNI2.js";
5
+ } from "./chunk-5FP7KNMC.js";
6
6
  import {
7
7
  trimSnippet
8
8
  } from "./chunk-FSTCLBSF.js";
9
- import "./chunk-GPACLYNT.js";
9
+ import "./chunk-57OOEOXI.js";
10
10
  import {
11
11
  WebfoxError,
12
12
  httpError
@@ -0,0 +1,91 @@
1
+ import {
2
+ joinUrl,
3
+ requestJson,
4
+ trimSnippet
5
+ } from "./chunk-FSTCLBSF.js";
6
+ import {
7
+ WebfoxError
8
+ } from "./chunk-U4BLULLV.js";
9
+
10
+ // src/providers/keenable/adapter.ts
11
+ var DEFAULT_BASE_URL = "https://api.keenable.ai";
12
+ var MAX_RESULTS = 50;
13
+ var FORWARDED_OPTIONS = [
14
+ "mode",
15
+ "site",
16
+ "published_after",
17
+ "published_before",
18
+ "acquired_after",
19
+ "acquired_before",
20
+ "query_time",
21
+ "snippet_max_length"
22
+ ];
23
+ var adapter = {
24
+ async search(request, config, context) {
25
+ const apiKey = config.credentials?.api;
26
+ if (!apiKey) throw new Error("Keenable search is missing an API key");
27
+ const maxResults = Math.max(
28
+ 1,
29
+ Math.min(MAX_RESULTS, Math.trunc(request.maxResults || 0))
30
+ );
31
+ const options = asRecord(request.options) ?? {};
32
+ const payload = asRecord(
33
+ await requestJson(
34
+ joinUrl(config.baseUrl ?? DEFAULT_BASE_URL, "v1/search"),
35
+ {
36
+ method: "POST",
37
+ headers: { "X-API-Key": apiKey, "X-Keenable-Title": "webfox" },
38
+ body: {
39
+ query: request.query,
40
+ max_results: maxResults,
41
+ ...Object.fromEntries(
42
+ FORWARDED_OPTIONS.flatMap(
43
+ (key) => options[key] === void 0 ? [] : [[key, options[key]]]
44
+ )
45
+ )
46
+ },
47
+ signal: context.signal
48
+ },
49
+ describeError
50
+ )
51
+ );
52
+ const entries = payload?.results;
53
+ if (!payload || !Array.isArray(entries)) {
54
+ throw new WebfoxError(
55
+ "PROVIDER_FAILURE",
56
+ "Keenable returned an invalid search response.",
57
+ { retryable: false }
58
+ );
59
+ }
60
+ const results = entries.map(toSearchResult).filter((result) => result !== void 0);
61
+ return { provider: "keenable", results: results.slice(0, maxResults) };
62
+ }
63
+ };
64
+ function describeError(payload, response) {
65
+ const record = asRecord(payload);
66
+ const detail = text(record?.detail) ?? text(record?.error) ?? text(record?.message) ?? (typeof payload === "string" ? text(payload) : void 0) ?? (record ? JSON.stringify(record) : void 0);
67
+ const trimmed = detail?.trim().slice(0, 500);
68
+ return `Keenable search failed (HTTP ${response.status})${trimmed ? `: ${trimmed}` : "."}`;
69
+ }
70
+ function toSearchResult(entry) {
71
+ const record = asRecord(entry);
72
+ const url = text(record?.url);
73
+ if (!record || !url) return void 0;
74
+ const { title, url: _url, description, snippet, ...metadata } = record;
75
+ const excerpt = text(snippet) ?? text(description);
76
+ return {
77
+ title: text(title) ?? url,
78
+ url,
79
+ snippet: excerpt ? trimSnippet(excerpt) : "",
80
+ ...Object.keys(metadata).length > 0 ? { metadata } : {}
81
+ };
82
+ }
83
+ function asRecord(value) {
84
+ return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
85
+ }
86
+ function text(value) {
87
+ return typeof value === "string" && value.trim() ? value : void 0;
88
+ }
89
+ export {
90
+ adapter
91
+ };
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-ZVTVERW5.js";
5
5
  import {
6
6
  WEBFOX_ERROR_CODES
7
- } from "./chunk-GPACLYNT.js";
7
+ } from "./chunk-57OOEOXI.js";
8
8
  import {
9
9
  WebfoxError
10
10
  } from "./chunk-U4BLULLV.js";
@@ -6,21 +6,21 @@ import {
6
6
  } from "./chunk-WCTOYZVB.js";
7
7
  import {
8
8
  configurationSchema
9
- } from "./chunk-HCYQF24V.js";
9
+ } from "./chunk-TGULKHB5.js";
10
10
  import {
11
11
  effectiveOptions,
12
12
  optionSchema,
13
13
  providers,
14
14
  selectProvider,
15
15
  validateConfiguredOptions
16
- } from "./chunk-LTJOWNI2.js";
16
+ } from "./chunk-5FP7KNMC.js";
17
17
  import {
18
18
  cancelProcessGroup,
19
19
  killProcessGroup
20
20
  } from "./chunk-ZVTVERW5.js";
21
21
  import {
22
22
  CAPABILITIES
23
- } from "./chunk-GPACLYNT.js";
23
+ } from "./chunk-57OOEOXI.js";
24
24
  import {
25
25
  WebfoxError,
26
26
  asWebfoxError
@@ -12,6 +12,7 @@ var PROVIDER_IDS = [
12
12
  "exa",
13
13
  "firecrawl",
14
14
  "gemini",
15
+ "keenable",
15
16
  "linkup",
16
17
  "ollama",
17
18
  "openai",
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  CAPABILITIES
3
- } from "./chunk-GPACLYNT.js";
3
+ } from "./chunk-57OOEOXI.js";
4
4
  import {
5
5
  WebfoxError
6
6
  } from "./chunk-U4BLULLV.js";
@@ -633,7 +633,7 @@ var customProvider = defineProvider({
633
633
  retrySafe: false
634
634
  }
635
635
  },
636
- load: async () => (await import("./adapter-VW4FMMJC.js")).adapter
636
+ load: async () => (await import("./adapter-ZYDUANQL.js")).adapter
637
637
  });
638
638
 
639
639
  // src/providers/exa/definition.ts
@@ -1278,6 +1278,73 @@ var geminiProvider = defineProvider({
1278
1278
  load: async () => (await import("./adapter-6EZAIE65.js")).adapter
1279
1279
  });
1280
1280
 
1281
+ // src/providers/keenable/definition.ts
1282
+ var timeFilter = (description) => ({
1283
+ type: "string",
1284
+ minLength: 1,
1285
+ description: `${description} Accepts YYYY-MM-DD, an ISO 8601 timestamp, or a relative delta such as 7d, 12h, or 30min.`
1286
+ });
1287
+ var keenableProvider = defineProvider({
1288
+ id: "keenable",
1289
+ label: "Keenable",
1290
+ docsUrl: "https://docs.keenable.ai/api-reference/search",
1291
+ local: false,
1292
+ credentials: [{ name: "api", environmentVariable: "KEENABLE_API_KEY" }],
1293
+ fields: ["credentials", "baseUrl", "options"],
1294
+ defaults: {},
1295
+ credentialDefaults: {},
1296
+ capabilities: {
1297
+ search: {
1298
+ options: {
1299
+ type: "object",
1300
+ properties: {
1301
+ mode: {
1302
+ type: "string",
1303
+ enum: ["pro", "realtime"],
1304
+ description: "Search mode: 'pro' (default) for deeper retrieval, 'realtime' for the fastest results. Each mode is billed separately."
1305
+ },
1306
+ site: {
1307
+ type: "string",
1308
+ minLength: 1,
1309
+ description: "Restrict results to one site, e.g. 'techcrunch.com'."
1310
+ },
1311
+ published_after: timeFilter(
1312
+ "Only pages published at or after this time."
1313
+ ),
1314
+ published_before: timeFilter(
1315
+ "Only pages published at or before this time."
1316
+ ),
1317
+ acquired_after: timeFilter(
1318
+ "Only pages indexed at or after this time."
1319
+ ),
1320
+ acquired_before: timeFilter(
1321
+ "Only pages indexed at or before this time."
1322
+ ),
1323
+ query_time: {
1324
+ type: "string",
1325
+ minLength: 1,
1326
+ description: "Search the index as it stood at this date or ISO 8601 timestamp; relative time filters resolve against it."
1327
+ },
1328
+ snippet_max_length: {
1329
+ type: "integer",
1330
+ minimum: 180,
1331
+ maximum: 1e4,
1332
+ description: "Maximum characters of the excerpt per result."
1333
+ }
1334
+ },
1335
+ description: "Keenable search options."
1336
+ },
1337
+ promptGuidelines: [
1338
+ "Keenable returns ranked web results with page excerpts; use web_contents to read selected sources in full.",
1339
+ "Use Keenable site to restrict results to one domain, and published_after/published_before (e.g. '7d') for recent or date-bounded results.",
1340
+ "Use Keenable mode='realtime' only when latency matters more than retrieval depth."
1341
+ ],
1342
+ retrySafe: true
1343
+ }
1344
+ },
1345
+ load: async () => (await import("./adapter-JJSMYZXG.js")).adapter
1346
+ });
1347
+
1281
1348
  // src/providers/linkup/definition.ts
1282
1349
  var linkupProvider = defineProvider({
1283
1350
  id: "linkup",
@@ -1991,7 +2058,7 @@ var serpbaseProvider = defineProvider({
1991
2058
  retrySafe: true
1992
2059
  }
1993
2060
  },
1994
- load: async () => (await import("./adapter-QIP32KA4.js")).adapter
2061
+ load: async () => (await import("./adapter-EIDSGLOP.js")).adapter
1995
2062
  });
1996
2063
 
1997
2064
  // src/providers/serper/definition.ts
@@ -2996,6 +3063,7 @@ var providers = {
2996
3063
  exa: exaProvider,
2997
3064
  firecrawl: firecrawlProvider,
2998
3065
  gemini: geminiProvider,
3066
+ keenable: keenableProvider,
2999
3067
  linkup: linkupProvider,
3000
3068
  ollama: ollamaProvider,
3001
3069
  openai: openaiProvider,
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  optionSchema,
3
3
  providers
4
- } from "./chunk-LTJOWNI2.js";
4
+ } from "./chunk-5FP7KNMC.js";
5
5
  import {
6
6
  CAPABILITIES
7
- } from "./chunk-GPACLYNT.js";
7
+ } from "./chunk-57OOEOXI.js";
8
8
 
9
9
  // package.json
10
10
  var package_default = {
11
11
  name: "webfox",
12
- version: "4.9.0",
12
+ version: "4.10.0",
13
13
  description: "Search the web, extract pages, get grounded answers, and run deep research with the web CLI, a TypeScript library, and a pi extension. Bring your own providers and API keys.",
14
14
  type: "module",
15
15
  files: [
package/dist/cli.js CHANGED
@@ -11,19 +11,19 @@ import {
11
11
  redactConfig,
12
12
  resolveConfigPath,
13
13
  setCapabilityDefault
14
- } from "./chunk-QZFN2747.js";
14
+ } from "./chunk-3WBE6UEW.js";
15
15
  import "./chunk-WCTOYZVB.js";
16
16
  import {
17
17
  PACKAGE_VERSION
18
- } from "./chunk-HCYQF24V.js";
18
+ } from "./chunk-TGULKHB5.js";
19
19
  import {
20
20
  validateConfiguredOptions
21
- } from "./chunk-LTJOWNI2.js";
21
+ } from "./chunk-5FP7KNMC.js";
22
22
  import "./chunk-ZVTVERW5.js";
23
23
  import {
24
24
  CAPABILITIES,
25
25
  PROVIDER_IDS
26
- } from "./chunk-GPACLYNT.js";
26
+ } from "./chunk-57OOEOXI.js";
27
27
  import {
28
28
  WebfoxError
29
29
  } from "./chunk-U4BLULLV.js";
@@ -23,6 +23,7 @@
23
23
  "custom",
24
24
  "exa",
25
25
  "firecrawl",
26
+ "keenable",
26
27
  "linkup",
27
28
  "ollama",
28
29
  "openai",
@@ -2197,6 +2198,117 @@
2197
2198
  }
2198
2199
  }
2199
2200
  },
2201
+ "keenable": {
2202
+ "type": "object",
2203
+ "additionalProperties": false,
2204
+ "properties": {
2205
+ "credentials": {
2206
+ "type": "object",
2207
+ "additionalProperties": false,
2208
+ "properties": {
2209
+ "api": {
2210
+ "oneOf": [
2211
+ {
2212
+ "type": "object",
2213
+ "additionalProperties": false,
2214
+ "properties": {
2215
+ "env": {
2216
+ "type": "string",
2217
+ "minLength": 1
2218
+ }
2219
+ },
2220
+ "required": ["env"]
2221
+ },
2222
+ {
2223
+ "type": "object",
2224
+ "additionalProperties": false,
2225
+ "properties": {
2226
+ "value": {
2227
+ "type": "string",
2228
+ "minLength": 1
2229
+ }
2230
+ },
2231
+ "required": ["value"]
2232
+ },
2233
+ {
2234
+ "type": "object",
2235
+ "additionalProperties": false,
2236
+ "properties": {
2237
+ "command": {
2238
+ "type": "array",
2239
+ "minItems": 1,
2240
+ "items": {
2241
+ "type": "string",
2242
+ "minLength": 1
2243
+ }
2244
+ }
2245
+ },
2246
+ "required": ["command"]
2247
+ }
2248
+ ]
2249
+ }
2250
+ }
2251
+ },
2252
+ "baseUrl": {
2253
+ "type": "string",
2254
+ "minLength": 1
2255
+ },
2256
+ "options": {
2257
+ "type": "object",
2258
+ "additionalProperties": false,
2259
+ "properties": {
2260
+ "search": {
2261
+ "type": "object",
2262
+ "properties": {
2263
+ "mode": {
2264
+ "type": "string",
2265
+ "enum": ["pro", "realtime"],
2266
+ "description": "Search mode: 'pro' (default) for deeper retrieval, 'realtime' for the fastest results. Each mode is billed separately."
2267
+ },
2268
+ "site": {
2269
+ "type": "string",
2270
+ "minLength": 1,
2271
+ "description": "Restrict results to one site, e.g. 'techcrunch.com'."
2272
+ },
2273
+ "published_after": {
2274
+ "type": "string",
2275
+ "minLength": 1,
2276
+ "description": "Only pages published at or after this time. Accepts YYYY-MM-DD, an ISO 8601 timestamp, or a relative delta such as 7d, 12h, or 30min."
2277
+ },
2278
+ "published_before": {
2279
+ "type": "string",
2280
+ "minLength": 1,
2281
+ "description": "Only pages published at or before this time. Accepts YYYY-MM-DD, an ISO 8601 timestamp, or a relative delta such as 7d, 12h, or 30min."
2282
+ },
2283
+ "acquired_after": {
2284
+ "type": "string",
2285
+ "minLength": 1,
2286
+ "description": "Only pages indexed at or after this time. Accepts YYYY-MM-DD, an ISO 8601 timestamp, or a relative delta such as 7d, 12h, or 30min."
2287
+ },
2288
+ "acquired_before": {
2289
+ "type": "string",
2290
+ "minLength": 1,
2291
+ "description": "Only pages indexed at or before this time. Accepts YYYY-MM-DD, an ISO 8601 timestamp, or a relative delta such as 7d, 12h, or 30min."
2292
+ },
2293
+ "query_time": {
2294
+ "type": "string",
2295
+ "minLength": 1,
2296
+ "description": "Search the index as it stood at this date or ISO 8601 timestamp; relative time filters resolve against it."
2297
+ },
2298
+ "snippet_max_length": {
2299
+ "type": "integer",
2300
+ "minimum": 180,
2301
+ "maximum": 10000,
2302
+ "description": "Maximum characters of the excerpt per result."
2303
+ }
2304
+ },
2305
+ "description": "Keenable search options.",
2306
+ "additionalProperties": false
2307
+ }
2308
+ }
2309
+ }
2310
+ }
2311
+ },
2200
2312
  "linkup": {
2201
2313
  "type": "object",
2202
2314
  "additionalProperties": false,
@@ -8,7 +8,7 @@ export declare const DOCUMENT_SCHEMAS: {
8
8
  readonly search: Type.TObject<{
9
9
  schemaVersion: Type.TLiteral<1>;
10
10
  capability: Type.TLiteral<"search">;
11
- provider: Type.TEnum<["brave", "cloudflare", "custom", "exa", "firecrawl", "gemini", "linkup", "ollama", "openai", "parallel", "perplexity", "serpbase", "serper", "tavily", "valyu", "youcom"]>;
11
+ provider: Type.TEnum<["brave", "cloudflare", "custom", "exa", "firecrawl", "gemini", "keenable", "linkup", "ollama", "openai", "parallel", "perplexity", "serpbase", "serper", "tavily", "valyu", "youcom"]>;
12
12
  status: Type.TEnum<["ok", "partial"]>;
13
13
  results: Type.TArray<Type.TUnion<[Type.TObject<{
14
14
  input: Type.TString;
@@ -35,7 +35,7 @@ export declare const DOCUMENT_SCHEMAS: {
35
35
  readonly contents: Type.TObject<{
36
36
  schemaVersion: Type.TLiteral<1>;
37
37
  capability: Type.TLiteral<"contents">;
38
- provider: Type.TEnum<["brave", "cloudflare", "custom", "exa", "firecrawl", "gemini", "linkup", "ollama", "openai", "parallel", "perplexity", "serpbase", "serper", "tavily", "valyu", "youcom"]>;
38
+ provider: Type.TEnum<["brave", "cloudflare", "custom", "exa", "firecrawl", "gemini", "keenable", "linkup", "ollama", "openai", "parallel", "perplexity", "serpbase", "serper", "tavily", "valyu", "youcom"]>;
39
39
  status: Type.TEnum<["ok", "partial"]>;
40
40
  results: Type.TArray<Type.TUnion<[Type.TObject<{
41
41
  input: Type.TString;
@@ -59,7 +59,7 @@ export declare const DOCUMENT_SCHEMAS: {
59
59
  readonly answer: Type.TObject<{
60
60
  schemaVersion: Type.TLiteral<1>;
61
61
  capability: Type.TLiteral<"answer">;
62
- provider: Type.TEnum<["brave", "cloudflare", "custom", "exa", "firecrawl", "gemini", "linkup", "ollama", "openai", "parallel", "perplexity", "serpbase", "serper", "tavily", "valyu", "youcom"]>;
62
+ provider: Type.TEnum<["brave", "cloudflare", "custom", "exa", "firecrawl", "gemini", "keenable", "linkup", "ollama", "openai", "parallel", "perplexity", "serpbase", "serper", "tavily", "valyu", "youcom"]>;
63
63
  status: Type.TEnum<["ok", "partial"]>;
64
64
  results: Type.TArray<Type.TUnion<[Type.TObject<{
65
65
  input: Type.TString;
@@ -82,7 +82,7 @@ export declare const DOCUMENT_SCHEMAS: {
82
82
  readonly research: Type.TObject<{
83
83
  schemaVersion: Type.TLiteral<1>;
84
84
  capability: Type.TLiteral<"research">;
85
- provider: Type.TEnum<["brave", "cloudflare", "custom", "exa", "firecrawl", "gemini", "linkup", "ollama", "openai", "parallel", "perplexity", "serpbase", "serper", "tavily", "valyu", "youcom"]>;
85
+ provider: Type.TEnum<["brave", "cloudflare", "custom", "exa", "firecrawl", "gemini", "keenable", "linkup", "ollama", "openai", "parallel", "perplexity", "serpbase", "serper", "tavily", "valyu", "youcom"]>;
86
86
  status: Type.TEnum<["ok", "partial"]>;
87
87
  results: Type.TArray<Type.TUnion<[Type.TObject<{
88
88
  input: Type.TString;
package/dist/domain.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export declare const CAPABILITIES: readonly ["search", "contents", "answer", "research"];
2
2
  export type Capability = (typeof CAPABILITIES)[number];
3
- export declare const PROVIDER_IDS: readonly ["brave", "cloudflare", "custom", "exa", "firecrawl", "gemini", "linkup", "ollama", "openai", "parallel", "perplexity", "serpbase", "serper", "tavily", "valyu", "youcom"];
3
+ export declare const PROVIDER_IDS: readonly ["brave", "cloudflare", "custom", "exa", "firecrawl", "gemini", "keenable", "linkup", "ollama", "openai", "parallel", "perplexity", "serpbase", "serper", "tavily", "valyu", "youcom"];
4
4
  export type ProviderId = (typeof PROVIDER_IDS)[number];
5
5
  export declare const WEBFOX_ERROR_CODES: readonly ["INVALID_CONFIG", "INVALID_INPUT", "PROVIDER_UNAVAILABLE", "PROVIDER_FAILURE", "PARTIAL_BATCH", "TIMEOUT", "CANCELLED"];
6
6
  export type WebfoxErrorCode = (typeof WEBFOX_ERROR_CODES)[number];
package/dist/durable.js CHANGED
@@ -8,14 +8,14 @@ import {
8
8
  } from "./chunk-BTWECET5.js";
9
9
  import {
10
10
  createWebfox
11
- } from "./chunk-QZFN2747.js";
11
+ } from "./chunk-3WBE6UEW.js";
12
12
  import "./chunk-WCTOYZVB.js";
13
- import "./chunk-HCYQF24V.js";
14
- import "./chunk-LTJOWNI2.js";
13
+ import "./chunk-TGULKHB5.js";
14
+ import "./chunk-5FP7KNMC.js";
15
15
  import "./chunk-ZVTVERW5.js";
16
16
  import {
17
17
  CAPABILITIES
18
- } from "./chunk-GPACLYNT.js";
18
+ } from "./chunk-57OOEOXI.js";
19
19
  import "./chunk-U4BLULLV.js";
20
20
 
21
21
  // src/durable.ts
package/dist/index.js CHANGED
@@ -6,20 +6,20 @@ import {
6
6
  resolveConfigPath,
7
7
  setCapabilityDefault,
8
8
  validateConfig
9
- } from "./chunk-QZFN2747.js";
9
+ } from "./chunk-3WBE6UEW.js";
10
10
  import "./chunk-WCTOYZVB.js";
11
11
  import {
12
12
  CONFIG_SCHEMA_URL
13
- } from "./chunk-HCYQF24V.js";
13
+ } from "./chunk-TGULKHB5.js";
14
14
  import {
15
15
  validateConfiguredOptions
16
- } from "./chunk-LTJOWNI2.js";
16
+ } from "./chunk-5FP7KNMC.js";
17
17
  import "./chunk-ZVTVERW5.js";
18
18
  import {
19
19
  CAPABILITIES,
20
20
  PROVIDER_IDS,
21
21
  WEBFOX_ERROR_CODES
22
- } from "./chunk-GPACLYNT.js";
22
+ } from "./chunk-57OOEOXI.js";
23
23
  import {
24
24
  WebfoxError
25
25
  } from "./chunk-U4BLULLV.js";
package/dist/pi.js CHANGED
@@ -9,16 +9,16 @@ import {
9
9
  import {
10
10
  createWebfox,
11
11
  resolveConfigPath
12
- } from "./chunk-QZFN2747.js";
12
+ } from "./chunk-3WBE6UEW.js";
13
13
  import "./chunk-WCTOYZVB.js";
14
- import "./chunk-HCYQF24V.js";
15
- import "./chunk-LTJOWNI2.js";
14
+ import "./chunk-TGULKHB5.js";
15
+ import "./chunk-5FP7KNMC.js";
16
16
  import "./chunk-ZVTVERW5.js";
17
17
  import {
18
18
  CAPABILITIES,
19
19
  PROVIDER_IDS,
20
20
  WEBFOX_ERROR_CODES
21
- } from "./chunk-GPACLYNT.js";
21
+ } from "./chunk-57OOEOXI.js";
22
22
  import {
23
23
  WebfoxError
24
24
  } from "./chunk-U4BLULLV.js";
@@ -76,6 +76,7 @@ export interface ProviderConfigMap {
76
76
  exa: import("./exa/types.js").Exa;
77
77
  firecrawl: import("./firecrawl/types.js").Firecrawl;
78
78
  gemini: import("./gemini/types.js").Gemini;
79
+ keenable: import("./keenable/types.js").Keenable;
79
80
  linkup: import("./linkup/types.js").Linkup;
80
81
  ollama: import("./ollama/types.js").Ollama;
81
82
  openai: import("./openai/types.js").OpenAI;
@@ -0,0 +1,5 @@
1
+ import type { ProviderContext, ProviderRequest, SearchResponse } from "../contract.js";
2
+ import type { Keenable } from "./types.js";
3
+ export declare const adapter: {
4
+ search(request: ProviderRequest<"search">, config: Keenable, context: ProviderContext): Promise<SearchResponse>;
5
+ };
@@ -0,0 +1 @@
1
+ export declare const keenableProvider: import("../definition.js").ProviderDefinitionFor<"keenable">;
@@ -0,0 +1,4 @@
1
+ import type { Provider } from "../contract.js";
2
+ export interface Keenable extends Provider {
3
+ baseUrl?: string;
4
+ }
@@ -5,6 +5,7 @@ export declare const providers: {
5
5
  readonly exa: import("./definition.js").ProviderDefinitionFor<"exa">;
6
6
  readonly firecrawl: import("./definition.js").ProviderDefinitionFor<"firecrawl">;
7
7
  readonly gemini: import("./definition.js").ProviderDefinitionFor<"gemini">;
8
+ readonly keenable: import("./definition.js").ProviderDefinitionFor<"keenable">;
8
9
  readonly linkup: import("./definition.js").ProviderDefinitionFor<"linkup">;
9
10
  readonly ollama: import("./definition.js").ProviderDefinitionFor<"ollama">;
10
11
  readonly openai: import("./definition.js").ProviderDefinitionFor<"openai">;
package/docs/provider.md CHANGED
@@ -123,6 +123,23 @@ The research agent is fixed; answer model settings don't affect it.
123
123
  If you previously selected Gemini for search, choose a search-capable provider
124
124
  and remove `providers.gemini.options.search` from your configuration.
125
125
 
126
+ ## Keenable
127
+
128
+ Supports search. Set `KEENABLE_API_KEY`, or configure
129
+ `providers.keenable.credentials.api` with a credential source. No defaults change
130
+ unless you select Keenable.
131
+
132
+ ```sh
133
+ web search "Node.js release notes" --provider keenable \
134
+ --site nodejs.org --published-after 30d
135
+ web config default search keenable
136
+ ```
137
+
138
+ Keenable caps `maxResults` at 50. Native options include `mode` (`pro` or
139
+ `realtime`), `site`, `published_after`/`published_before`,
140
+ `acquired_after`/`acquired_before`, `query_time`, and `snippet_max_length`.
141
+ Time filters accept dates, ISO 8601 timestamps, or relative deltas such as `7d`.
142
+
126
143
  ## Linkup
127
144
 
128
145
  Supports search, page extraction, and research. Set `LINKUP_API_KEY`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webfox",
3
- "version": "4.9.0",
3
+ "version": "4.10.0",
4
4
  "description": "Search the web, extract pages, get grounded answers, and run deep research with the web CLI, a TypeScript library, and a pi extension. Bring your own providers and API keys.",
5
5
  "type": "module",
6
6
  "files": [