webfox 4.0.1 → 4.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 +6 -1
- package/dist/{adapter-MAG7X663.js → adapter-A7LV6L55.js} +1 -1
- package/dist/adapter-YOHLAGYM.js +124 -0
- package/dist/{chunk-GAWPRXAU.js → chunk-CIZXLW6C.js} +197 -5
- package/dist/{chunk-MVCCEPDF.js → chunk-KC6K6LCQ.js} +51 -18
- package/dist/{chunk-G2YAQEET.js → chunk-WVHMWLKU.js} +2 -1
- package/dist/cli.js +3 -3
- package/dist/config.schema.json +249 -2
- package/dist/domain.d.ts +1 -1
- package/dist/errors.d.ts +8 -0
- package/dist/index.js +3 -3
- package/dist/pi-diagnostics.d.ts +2 -0
- package/dist/pi.js +46 -11
- package/dist/providers/contract.d.ts +1 -0
- package/dist/providers/registry.d.ts +1 -0
- package/dist/providers/youcom/adapter.d.ts +5 -0
- package/dist/providers/youcom/definition.d.ts +1 -0
- package/dist/providers/youcom/types.d.ts +4 -0
- package/docs/provider.md +78 -0
- package/example-config.yaml +9 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -137,6 +137,7 @@ Use different providers for different tasks:
|
|
|
137
137
|
| [Serper] | ✔︎ | | | |
|
|
138
138
|
| [Tavily] | ✔︎ | ✔︎ | | |
|
|
139
139
|
| [Valyu] | ✔︎ | ✔︎ | ✔︎ | ✔︎ |
|
|
140
|
+
| [You.com] | ✔︎ | | | |
|
|
140
141
|
|
|
141
142
|
[Brave]: ./docs/provider.md#brave
|
|
142
143
|
[Cloudflare]: ./docs/provider.md#cloudflare
|
|
@@ -152,6 +153,7 @@ Use different providers for different tasks:
|
|
|
152
153
|
[Serper]: ./docs/provider.md#serper
|
|
153
154
|
[Tavily]: ./docs/provider.md#tavily
|
|
154
155
|
[Valyu]: ./docs/provider.md#valyu
|
|
156
|
+
[You.com]: ./docs/provider.md#youcom
|
|
155
157
|
|
|
156
158
|
See the [provider guide](./docs/provider.md) for credentials, examples, and caveats.
|
|
157
159
|
|
|
@@ -172,7 +174,7 @@ or, on Windows, `APPDATA`. Override it with `WEBFOX_CONFIG` or `--config <path>`
|
|
|
172
174
|
For example:
|
|
173
175
|
|
|
174
176
|
```yaml
|
|
175
|
-
$schema: https://unpkg.com/webfox@
|
|
177
|
+
$schema: https://unpkg.com/webfox@latest/dist/config.schema.json
|
|
176
178
|
defaults:
|
|
177
179
|
search:
|
|
178
180
|
provider: brave
|
|
@@ -250,6 +252,9 @@ configuration, progress, and errors.
|
|
|
250
252
|
`web config default <capability> <provider>`.
|
|
251
253
|
- **Missing credentials:** Run `web providers <id>` to check the required key
|
|
252
254
|
names, or see the [provider guide](./docs/provider.md).
|
|
255
|
+
- **Invalid configuration in pi:** Pi continues to start, but Webfox registers
|
|
256
|
+
no tools and reports the error (on stderr in print and JSON modes). Fix the
|
|
257
|
+
configuration, then restart Pi or run `/reload` to load the extension again.
|
|
253
258
|
- **No pi tools:** Select default providers in the shared configuration and
|
|
254
259
|
restart pi. Installing the extension or setting keys alone isn't enough.
|
|
255
260
|
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import {
|
|
2
|
+
trimSnippet
|
|
3
|
+
} from "./chunk-X6ZBIHZC.js";
|
|
4
|
+
import {
|
|
5
|
+
httpError
|
|
6
|
+
} from "./chunk-U4BLULLV.js";
|
|
7
|
+
|
|
8
|
+
// src/providers/youcom/adapter.ts
|
|
9
|
+
var DEFAULT_BASE_URL = "https://ydc-index.io";
|
|
10
|
+
var adapter = {
|
|
11
|
+
async search(request, config, context) {
|
|
12
|
+
const apiKey = config.credentials?.api;
|
|
13
|
+
if (!apiKey) throw new Error("You.com search is missing an API key");
|
|
14
|
+
const options = asRecord(request.options);
|
|
15
|
+
const response = await fetch(joinUrl(config.baseUrl), {
|
|
16
|
+
method: "POST",
|
|
17
|
+
headers: {
|
|
18
|
+
"content-type": "application/json",
|
|
19
|
+
"X-API-Key": apiKey
|
|
20
|
+
},
|
|
21
|
+
body: JSON.stringify({
|
|
22
|
+
query: request.query,
|
|
23
|
+
count: clamp(request.maxResults, 100),
|
|
24
|
+
...pickDefined(options, [
|
|
25
|
+
"freshness",
|
|
26
|
+
"country",
|
|
27
|
+
"language",
|
|
28
|
+
"safesearch",
|
|
29
|
+
"offset",
|
|
30
|
+
"include_domains",
|
|
31
|
+
"exclude_domains",
|
|
32
|
+
"boost_domains",
|
|
33
|
+
"livecrawl",
|
|
34
|
+
"livecrawl_formats",
|
|
35
|
+
"crawl_timeout"
|
|
36
|
+
])
|
|
37
|
+
}),
|
|
38
|
+
signal: context.signal
|
|
39
|
+
});
|
|
40
|
+
if (!response.ok) throw httpError(response, await buildHttpError(response));
|
|
41
|
+
const payload = asRecord(await response.json());
|
|
42
|
+
const searchMetadata = asRecord(payload.metadata);
|
|
43
|
+
const web = collectResults(
|
|
44
|
+
asRecord(payload.results).web,
|
|
45
|
+
"web",
|
|
46
|
+
searchMetadata
|
|
47
|
+
);
|
|
48
|
+
const news = collectResults(
|
|
49
|
+
asRecord(payload.results).news,
|
|
50
|
+
"news",
|
|
51
|
+
searchMetadata
|
|
52
|
+
);
|
|
53
|
+
const results = [];
|
|
54
|
+
for (let index = 0; index < Math.max(web.length, news.length); index++) {
|
|
55
|
+
if (web[index]) results.push(web[index]);
|
|
56
|
+
if (news[index]) results.push(news[index]);
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
provider: "youcom",
|
|
60
|
+
results: results.slice(0, clamp(request.maxResults, 100))
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
function joinUrl(baseUrl) {
|
|
65
|
+
return `${(baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "")}/v1/search`;
|
|
66
|
+
}
|
|
67
|
+
function collectResults(results, section, searchMetadata) {
|
|
68
|
+
return array(results).map((entry) => asRecord(entry)).filter((entry) => Object.keys(entry).length > 0).map((entry) => {
|
|
69
|
+
const url = string(entry.url) ?? "";
|
|
70
|
+
const title = string(entry.title) ?? string(entry.name) ?? (url || "Untitled");
|
|
71
|
+
return {
|
|
72
|
+
title,
|
|
73
|
+
url,
|
|
74
|
+
snippet: buildSnippet(entry, section),
|
|
75
|
+
metadata: buildMetadata(entry, section, searchMetadata)
|
|
76
|
+
};
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
function buildSnippet(entry, section) {
|
|
80
|
+
const contents = asRecord(entry.contents);
|
|
81
|
+
const snippets = arrayOfStrings(entry.snippets);
|
|
82
|
+
if (snippets.length > 0) return trimSnippet(snippets.join("\n\n"), 1200);
|
|
83
|
+
const text = string(entry.description) ?? string(contents.markdown) ?? string(contents.html) ?? (section === "news" ? string(entry.page_age) : void 0) ?? "";
|
|
84
|
+
return trimSnippet(text);
|
|
85
|
+
}
|
|
86
|
+
function buildMetadata(entry, section, searchMetadata) {
|
|
87
|
+
const metadata = {
|
|
88
|
+
section,
|
|
89
|
+
...searchMetadata ? { searchMetadata } : {},
|
|
90
|
+
...entry
|
|
91
|
+
};
|
|
92
|
+
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
93
|
+
}
|
|
94
|
+
function pickDefined(source, keys) {
|
|
95
|
+
return Object.fromEntries(
|
|
96
|
+
keys.flatMap(
|
|
97
|
+
(key) => source[key] === void 0 ? [] : [[key, source[key]]]
|
|
98
|
+
)
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
function clamp(value, max) {
|
|
102
|
+
return Math.max(1, Math.min(max, Math.trunc(value || 0)));
|
|
103
|
+
}
|
|
104
|
+
function array(value) {
|
|
105
|
+
return Array.isArray(value) ? value : [];
|
|
106
|
+
}
|
|
107
|
+
function arrayOfStrings(value) {
|
|
108
|
+
return array(value).flatMap(
|
|
109
|
+
(entry) => typeof entry === "string" ? [entry] : []
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
function asRecord(value) {
|
|
113
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
114
|
+
}
|
|
115
|
+
function string(value) {
|
|
116
|
+
return typeof value === "string" ? value : void 0;
|
|
117
|
+
}
|
|
118
|
+
async function buildHttpError(response) {
|
|
119
|
+
const body = (await response.text()).trim();
|
|
120
|
+
return `You.com search request failed (${response.status}${response.statusText ? ` ${response.statusText}` : ""})${body ? `: ${body}` : "."}`;
|
|
121
|
+
}
|
|
122
|
+
export {
|
|
123
|
+
adapter
|
|
124
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CAPABILITIES
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-WVHMWLKU.js";
|
|
4
4
|
import {
|
|
5
5
|
WebfoxError
|
|
6
6
|
} from "./chunk-U4BLULLV.js";
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
// package.json
|
|
9
9
|
var package_default = {
|
|
10
10
|
name: "webfox",
|
|
11
|
-
version: "4.0
|
|
11
|
+
version: "4.2.0",
|
|
12
12
|
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.",
|
|
13
13
|
type: "module",
|
|
14
14
|
files: [
|
|
@@ -138,7 +138,7 @@ var package_default = {
|
|
|
138
138
|
// src/package-metadata.ts
|
|
139
139
|
var PACKAGE_NAME = package_default.name;
|
|
140
140
|
var PACKAGE_VERSION = package_default.version;
|
|
141
|
-
var CONFIG_SCHEMA_URL = `https://unpkg.com/${PACKAGE_NAME}
|
|
141
|
+
var CONFIG_SCHEMA_URL = `https://unpkg.com/${PACKAGE_NAME}@latest/dist/config.schema.json`;
|
|
142
142
|
|
|
143
143
|
// src/configuration/planning.ts
|
|
144
144
|
import { Check, Errors } from "typebox/value";
|
|
@@ -746,7 +746,7 @@ var customProvider = defineProvider({
|
|
|
746
746
|
retrySafe: false
|
|
747
747
|
}
|
|
748
748
|
},
|
|
749
|
-
load: async () => (await import("./adapter-
|
|
749
|
+
load: async () => (await import("./adapter-A7LV6L55.js")).adapter
|
|
750
750
|
});
|
|
751
751
|
|
|
752
752
|
// src/providers/exa/definition.ts
|
|
@@ -2788,6 +2788,197 @@ var valyuProvider = defineProvider({
|
|
|
2788
2788
|
load: async () => (await import("./adapter-UAZNLDSS.js")).adapter
|
|
2789
2789
|
});
|
|
2790
2790
|
|
|
2791
|
+
// src/providers/youcom/definition.ts
|
|
2792
|
+
var domains = {
|
|
2793
|
+
type: "array",
|
|
2794
|
+
maxItems: 500,
|
|
2795
|
+
items: { type: "string", minLength: 1 }
|
|
2796
|
+
};
|
|
2797
|
+
var youcomProvider = defineProvider({
|
|
2798
|
+
id: "youcom",
|
|
2799
|
+
label: "You.com",
|
|
2800
|
+
docsUrl: "https://you.com/docs/api-reference/search/v1-search-post",
|
|
2801
|
+
local: false,
|
|
2802
|
+
credentials: [
|
|
2803
|
+
{
|
|
2804
|
+
name: "api",
|
|
2805
|
+
environmentVariable: "YDC_API_KEY",
|
|
2806
|
+
capabilities: ["search"]
|
|
2807
|
+
}
|
|
2808
|
+
],
|
|
2809
|
+
fields: ["credentials", "baseUrl", "options"],
|
|
2810
|
+
defaults: {},
|
|
2811
|
+
credentialDefaults: {},
|
|
2812
|
+
capabilities: {
|
|
2813
|
+
search: {
|
|
2814
|
+
options: {
|
|
2815
|
+
type: "object",
|
|
2816
|
+
properties: {
|
|
2817
|
+
freshness: {
|
|
2818
|
+
type: "string",
|
|
2819
|
+
description: "Freshness window: day, week, month, year, or YYYY-MM-DDtoYYYY-MM-DD. You.com uses the broader timeframe when the query also specifies one."
|
|
2820
|
+
},
|
|
2821
|
+
country: {
|
|
2822
|
+
type: "string",
|
|
2823
|
+
enum: [
|
|
2824
|
+
"AR",
|
|
2825
|
+
"AU",
|
|
2826
|
+
"AT",
|
|
2827
|
+
"BE",
|
|
2828
|
+
"BR",
|
|
2829
|
+
"CA",
|
|
2830
|
+
"CL",
|
|
2831
|
+
"DK",
|
|
2832
|
+
"FI",
|
|
2833
|
+
"FR",
|
|
2834
|
+
"DE",
|
|
2835
|
+
"HK",
|
|
2836
|
+
"IN",
|
|
2837
|
+
"ID",
|
|
2838
|
+
"IT",
|
|
2839
|
+
"JP",
|
|
2840
|
+
"KR",
|
|
2841
|
+
"MY",
|
|
2842
|
+
"MX",
|
|
2843
|
+
"NL",
|
|
2844
|
+
"NZ",
|
|
2845
|
+
"NO",
|
|
2846
|
+
"CN",
|
|
2847
|
+
"PL",
|
|
2848
|
+
"PT",
|
|
2849
|
+
"PH",
|
|
2850
|
+
"RU",
|
|
2851
|
+
"SA",
|
|
2852
|
+
"ZA",
|
|
2853
|
+
"ES",
|
|
2854
|
+
"SE",
|
|
2855
|
+
"CH",
|
|
2856
|
+
"TW",
|
|
2857
|
+
"TR",
|
|
2858
|
+
"GB",
|
|
2859
|
+
"US"
|
|
2860
|
+
],
|
|
2861
|
+
description: "Country code used to localize search results, for example US."
|
|
2862
|
+
},
|
|
2863
|
+
language: {
|
|
2864
|
+
type: "string",
|
|
2865
|
+
enum: [
|
|
2866
|
+
"AR",
|
|
2867
|
+
"EU",
|
|
2868
|
+
"BN",
|
|
2869
|
+
"BG",
|
|
2870
|
+
"CA",
|
|
2871
|
+
"ZH-HANS",
|
|
2872
|
+
"ZH-HANT",
|
|
2873
|
+
"HR",
|
|
2874
|
+
"CS",
|
|
2875
|
+
"DA",
|
|
2876
|
+
"NL",
|
|
2877
|
+
"EN",
|
|
2878
|
+
"EN-GB",
|
|
2879
|
+
"ET",
|
|
2880
|
+
"FI",
|
|
2881
|
+
"FR",
|
|
2882
|
+
"GL",
|
|
2883
|
+
"DE",
|
|
2884
|
+
"EL",
|
|
2885
|
+
"GU",
|
|
2886
|
+
"HE",
|
|
2887
|
+
"HI",
|
|
2888
|
+
"HU",
|
|
2889
|
+
"IS",
|
|
2890
|
+
"IT",
|
|
2891
|
+
"JA",
|
|
2892
|
+
"KN",
|
|
2893
|
+
"KO",
|
|
2894
|
+
"LV",
|
|
2895
|
+
"LT",
|
|
2896
|
+
"MS",
|
|
2897
|
+
"ML",
|
|
2898
|
+
"MR",
|
|
2899
|
+
"NB",
|
|
2900
|
+
"PL",
|
|
2901
|
+
"PT-BR",
|
|
2902
|
+
"PT-PT",
|
|
2903
|
+
"PA",
|
|
2904
|
+
"RO",
|
|
2905
|
+
"RU",
|
|
2906
|
+
"SR",
|
|
2907
|
+
"SK",
|
|
2908
|
+
"SL",
|
|
2909
|
+
"ES",
|
|
2910
|
+
"SV",
|
|
2911
|
+
"TA",
|
|
2912
|
+
"TE",
|
|
2913
|
+
"TH",
|
|
2914
|
+
"TR",
|
|
2915
|
+
"UK",
|
|
2916
|
+
"VI"
|
|
2917
|
+
],
|
|
2918
|
+
description: "Language of web results. Uses You.com's uppercase codes; defaults to EN."
|
|
2919
|
+
},
|
|
2920
|
+
safesearch: {
|
|
2921
|
+
type: "string",
|
|
2922
|
+
enum: ["moderate", "off", "strict"],
|
|
2923
|
+
description: "Safe-search filtering level. Defaults to moderate."
|
|
2924
|
+
},
|
|
2925
|
+
offset: {
|
|
2926
|
+
type: "integer",
|
|
2927
|
+
minimum: 0,
|
|
2928
|
+
maximum: 9,
|
|
2929
|
+
description: "Pagination offset in count-sized pages, separately for web and news. Count is maxResults capped at 100."
|
|
2930
|
+
},
|
|
2931
|
+
include_domains: {
|
|
2932
|
+
...domains,
|
|
2933
|
+
description: "Restrict results to these domains. Cannot be combined with exclude_domains or boost_domains."
|
|
2934
|
+
},
|
|
2935
|
+
exclude_domains: {
|
|
2936
|
+
...domains,
|
|
2937
|
+
description: "Exclude these domains. Cannot be combined with include_domains."
|
|
2938
|
+
},
|
|
2939
|
+
boost_domains: {
|
|
2940
|
+
...domains,
|
|
2941
|
+
description: "Boost these domains without excluding others. Can be combined with exclude_domains, but not include_domains."
|
|
2942
|
+
},
|
|
2943
|
+
livecrawl: {
|
|
2944
|
+
type: "string",
|
|
2945
|
+
enum: ["web", "news", "all"],
|
|
2946
|
+
description: "Fetch full page content for the selected sections. Adds latency and per-page charges, including results omitted by maxResults. Content is preserved in result metadata.contents."
|
|
2947
|
+
},
|
|
2948
|
+
livecrawl_formats: {
|
|
2949
|
+
type: "array",
|
|
2950
|
+
minItems: 1,
|
|
2951
|
+
maxItems: 2,
|
|
2952
|
+
uniqueItems: true,
|
|
2953
|
+
items: { type: "string", enum: ["html", "markdown"] },
|
|
2954
|
+
description: "Formats for livecrawled content. Defaults to html; requires livecrawl to enable crawling."
|
|
2955
|
+
},
|
|
2956
|
+
crawl_timeout: {
|
|
2957
|
+
type: "integer",
|
|
2958
|
+
minimum: 1,
|
|
2959
|
+
maximum: 60,
|
|
2960
|
+
description: "Seconds to wait for page content when livecrawl is enabled. Defaults to 10."
|
|
2961
|
+
}
|
|
2962
|
+
},
|
|
2963
|
+
// Property prohibitions also work for partial configured defaults:
|
|
2964
|
+
// unlike required-based exclusions, they survive partial validation.
|
|
2965
|
+
anyOf: [
|
|
2966
|
+
{ properties: { include_domains: false } },
|
|
2967
|
+
{ properties: { exclude_domains: false, boost_domains: false } }
|
|
2968
|
+
],
|
|
2969
|
+
description: "You.com search options. Results alternate web and news, starting with web, up to maxResults (capped at 100)."
|
|
2970
|
+
},
|
|
2971
|
+
promptGuidelines: [
|
|
2972
|
+
"Use You.com search for web and news results. Results alternate web and news, starting with web, within the overall result limit.",
|
|
2973
|
+
"Use include_domains to restrict sources, or exclude_domains and boost_domains to adjust source selection. Do not combine include_domains with either of the other domain controls.",
|
|
2974
|
+
"Search snippets already contain query-relevant passages. Enable livecrawl only when full page content is needed; it adds latency and per-page charges."
|
|
2975
|
+
],
|
|
2976
|
+
retrySafe: true
|
|
2977
|
+
}
|
|
2978
|
+
},
|
|
2979
|
+
load: async () => (await import("./adapter-YOHLAGYM.js")).adapter
|
|
2980
|
+
});
|
|
2981
|
+
|
|
2791
2982
|
// src/providers/registry.ts
|
|
2792
2983
|
var providers = {
|
|
2793
2984
|
brave: braveProvider,
|
|
@@ -2803,7 +2994,8 @@ var providers = {
|
|
|
2803
2994
|
perplexity: perplexityProvider,
|
|
2804
2995
|
serper: serperProvider,
|
|
2805
2996
|
tavily: tavilyProvider,
|
|
2806
|
-
valyu: valyuProvider
|
|
2997
|
+
valyu: valyuProvider,
|
|
2998
|
+
youcom: youcomProvider
|
|
2807
2999
|
};
|
|
2808
3000
|
|
|
2809
3001
|
// src/configuration/options-schema.ts
|
|
@@ -11,14 +11,14 @@ import {
|
|
|
11
11
|
providers,
|
|
12
12
|
selectProvider,
|
|
13
13
|
validateConfiguredOptions
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-CIZXLW6C.js";
|
|
15
15
|
import {
|
|
16
16
|
cancelProcessGroup,
|
|
17
17
|
killProcessGroup
|
|
18
18
|
} from "./chunk-ZVTVERW5.js";
|
|
19
19
|
import {
|
|
20
20
|
CAPABILITIES
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-WVHMWLKU.js";
|
|
22
22
|
import {
|
|
23
23
|
WebfoxError,
|
|
24
24
|
asWebfoxError
|
|
@@ -69,7 +69,13 @@ function readFailure(error, options, path) {
|
|
|
69
69
|
if (error instanceof WebfoxError) throw error;
|
|
70
70
|
throw new WebfoxError(
|
|
71
71
|
"INVALID_CONFIG",
|
|
72
|
-
`Could not read configuration: ${path}. Check the path and file permissions
|
|
72
|
+
`Could not read configuration: ${path}. Check the path and file permissions.`,
|
|
73
|
+
{
|
|
74
|
+
configuration: {
|
|
75
|
+
source: path,
|
|
76
|
+
issues: ["Could not read file. Check the path and permissions."]
|
|
77
|
+
}
|
|
78
|
+
}
|
|
73
79
|
);
|
|
74
80
|
}
|
|
75
81
|
function parseConfigDocument(text, source = "config.yaml") {
|
|
@@ -91,7 +97,15 @@ function parseConfigDocument(text, source = "config.yaml") {
|
|
|
91
97
|
} catch {
|
|
92
98
|
throw new WebfoxError(
|
|
93
99
|
"INVALID_CONFIG",
|
|
94
|
-
`Invalid YAML in ${source}. Use one YAML 1.2 document with unique keys, with string keys and finite numbers, without aliases or explicit tags
|
|
100
|
+
`Invalid YAML in ${source}. Use one YAML 1.2 document with unique keys, with string keys and finite numbers, without aliases or explicit tags.`,
|
|
101
|
+
{
|
|
102
|
+
configuration: {
|
|
103
|
+
source,
|
|
104
|
+
issues: [
|
|
105
|
+
"Invalid YAML. Use YAML 1.2 without duplicate keys, aliases, or explicit tags."
|
|
106
|
+
]
|
|
107
|
+
}
|
|
108
|
+
}
|
|
95
109
|
);
|
|
96
110
|
}
|
|
97
111
|
}
|
|
@@ -105,14 +119,30 @@ function parseConfig(text, source = "config.yaml") {
|
|
|
105
119
|
function validateConfig(value, source = "configuration") {
|
|
106
120
|
const schema = configurationSchema;
|
|
107
121
|
if (!Check(schema, value)) {
|
|
108
|
-
const
|
|
122
|
+
const errors = Errors(schema, value);
|
|
123
|
+
const detail = errors.slice(0, 3).map((error) => `${error.instancePath || "/"}: ${error.message}`).join("; ");
|
|
109
124
|
throw new WebfoxError(
|
|
110
125
|
"INVALID_CONFIG",
|
|
111
|
-
`Invalid ${source}: ${detail}. Provider options belong under providers.<id>.options.<capability
|
|
126
|
+
`Invalid ${source}: ${detail}. Provider options belong under providers.<id>.options.<capability>.`,
|
|
127
|
+
{ configuration: { source, issues: configurationIssues(errors) } }
|
|
112
128
|
);
|
|
113
129
|
}
|
|
114
130
|
return structuredClone(value);
|
|
115
131
|
}
|
|
132
|
+
function configurationIssues(errors) {
|
|
133
|
+
const issues = /* @__PURE__ */ new Map();
|
|
134
|
+
for (const error of errors) {
|
|
135
|
+
if (error.keyword === "additionalProperties") continue;
|
|
136
|
+
const path = error.instancePath || "/";
|
|
137
|
+
if (issues.has(path)) continue;
|
|
138
|
+
const unknownKey = error.keyword === "boolean" && error.schemaPath.endsWith("/additionalProperties");
|
|
139
|
+
const key = path.slice(1).split("/").map((part) => part.replaceAll("~1", "/").replaceAll("~0", "~")).join(".");
|
|
140
|
+
const message = unknownKey ? `Unknown key: ${key}` : error.keyword === "enum" || error.keyword === "const" ? `${path}: unsupported value` : `${path}: ${error.message}`;
|
|
141
|
+
issues.set(path, message);
|
|
142
|
+
if (issues.size === 3) break;
|
|
143
|
+
}
|
|
144
|
+
return issues.size ? [...issues.values()] : ["Invalid configuration structure."];
|
|
145
|
+
}
|
|
116
146
|
function redactConfig(config) {
|
|
117
147
|
const visit2 = (entry) => {
|
|
118
148
|
if (Array.isArray(entry)) return entry.map(visit2);
|
|
@@ -645,26 +675,29 @@ function createWebfox(options = {}) {
|
|
|
645
675
|
}
|
|
646
676
|
};
|
|
647
677
|
const definition = selectProvider(config, capability, selected);
|
|
648
|
-
|
|
678
|
+
const defaults = outward.value({
|
|
679
|
+
options: effectiveOptions(
|
|
680
|
+
config,
|
|
681
|
+
definition,
|
|
682
|
+
capability,
|
|
683
|
+
{},
|
|
684
|
+
"defaults"
|
|
685
|
+
),
|
|
686
|
+
...capability === "search" ? { maxResults: config.defaults?.search?.maxResults ?? 5 } : {}
|
|
687
|
+
});
|
|
688
|
+
return {
|
|
649
689
|
capability,
|
|
650
690
|
provider: selected,
|
|
651
691
|
configured: configured(definition, capability),
|
|
692
|
+
// Static provider schemas contain no credentials. Redacting property
|
|
693
|
+
// names such as maximum_number_of_tokens would invalidate the schema.
|
|
652
694
|
optionSchema: optionSchema(
|
|
653
695
|
definition,
|
|
654
696
|
capability,
|
|
655
697
|
"defaults"
|
|
656
698
|
),
|
|
657
|
-
defaults
|
|
658
|
-
|
|
659
|
-
config,
|
|
660
|
-
definition,
|
|
661
|
-
capability,
|
|
662
|
-
{},
|
|
663
|
-
"defaults"
|
|
664
|
-
),
|
|
665
|
-
...capability === "search" ? { maxResults: config.defaults?.search?.maxResults ?? 5 } : {}
|
|
666
|
-
}
|
|
667
|
-
});
|
|
699
|
+
defaults
|
|
700
|
+
};
|
|
668
701
|
}
|
|
669
702
|
};
|
|
670
703
|
}
|
package/dist/cli.js
CHANGED
|
@@ -11,17 +11,17 @@ import {
|
|
|
11
11
|
redactConfig,
|
|
12
12
|
resolveConfigPath,
|
|
13
13
|
setCapabilityDefault
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-KC6K6LCQ.js";
|
|
15
15
|
import "./chunk-WCTOYZVB.js";
|
|
16
16
|
import {
|
|
17
17
|
PACKAGE_VERSION,
|
|
18
18
|
validateConfiguredOptions
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-CIZXLW6C.js";
|
|
20
20
|
import "./chunk-ZVTVERW5.js";
|
|
21
21
|
import {
|
|
22
22
|
CAPABILITIES,
|
|
23
23
|
PROVIDER_IDS
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-WVHMWLKU.js";
|
|
25
25
|
import {
|
|
26
26
|
WebfoxError
|
|
27
27
|
} from "./chunk-U4BLULLV.js";
|
package/dist/config.schema.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"$id": "https://unpkg.com/webfox@
|
|
3
|
+
"$id": "https://unpkg.com/webfox@latest/dist/config.schema.json",
|
|
4
4
|
"title": "webfox configuration",
|
|
5
5
|
"type": "object",
|
|
6
6
|
"additionalProperties": false,
|
|
@@ -30,7 +30,8 @@
|
|
|
30
30
|
"perplexity",
|
|
31
31
|
"serper",
|
|
32
32
|
"tavily",
|
|
33
|
-
"valyu"
|
|
33
|
+
"valyu",
|
|
34
|
+
"youcom"
|
|
34
35
|
]
|
|
35
36
|
},
|
|
36
37
|
"maxResults": {
|
|
@@ -4263,6 +4264,252 @@
|
|
|
4263
4264
|
}
|
|
4264
4265
|
}
|
|
4265
4266
|
}
|
|
4267
|
+
},
|
|
4268
|
+
"youcom": {
|
|
4269
|
+
"type": "object",
|
|
4270
|
+
"additionalProperties": false,
|
|
4271
|
+
"properties": {
|
|
4272
|
+
"credentials": {
|
|
4273
|
+
"type": "object",
|
|
4274
|
+
"additionalProperties": false,
|
|
4275
|
+
"properties": {
|
|
4276
|
+
"api": {
|
|
4277
|
+
"oneOf": [
|
|
4278
|
+
{
|
|
4279
|
+
"type": "object",
|
|
4280
|
+
"additionalProperties": false,
|
|
4281
|
+
"properties": {
|
|
4282
|
+
"env": {
|
|
4283
|
+
"type": "string",
|
|
4284
|
+
"minLength": 1
|
|
4285
|
+
}
|
|
4286
|
+
},
|
|
4287
|
+
"required": ["env"]
|
|
4288
|
+
},
|
|
4289
|
+
{
|
|
4290
|
+
"type": "object",
|
|
4291
|
+
"additionalProperties": false,
|
|
4292
|
+
"properties": {
|
|
4293
|
+
"value": {
|
|
4294
|
+
"type": "string",
|
|
4295
|
+
"minLength": 1
|
|
4296
|
+
}
|
|
4297
|
+
},
|
|
4298
|
+
"required": ["value"]
|
|
4299
|
+
},
|
|
4300
|
+
{
|
|
4301
|
+
"type": "object",
|
|
4302
|
+
"additionalProperties": false,
|
|
4303
|
+
"properties": {
|
|
4304
|
+
"command": {
|
|
4305
|
+
"type": "array",
|
|
4306
|
+
"minItems": 1,
|
|
4307
|
+
"items": {
|
|
4308
|
+
"type": "string",
|
|
4309
|
+
"minLength": 1
|
|
4310
|
+
}
|
|
4311
|
+
}
|
|
4312
|
+
},
|
|
4313
|
+
"required": ["command"]
|
|
4314
|
+
}
|
|
4315
|
+
]
|
|
4316
|
+
}
|
|
4317
|
+
}
|
|
4318
|
+
},
|
|
4319
|
+
"baseUrl": {
|
|
4320
|
+
"type": "string",
|
|
4321
|
+
"minLength": 1
|
|
4322
|
+
},
|
|
4323
|
+
"options": {
|
|
4324
|
+
"type": "object",
|
|
4325
|
+
"additionalProperties": false,
|
|
4326
|
+
"properties": {
|
|
4327
|
+
"search": {
|
|
4328
|
+
"type": "object",
|
|
4329
|
+
"properties": {
|
|
4330
|
+
"freshness": {
|
|
4331
|
+
"type": "string",
|
|
4332
|
+
"description": "Freshness window: day, week, month, year, or YYYY-MM-DDtoYYYY-MM-DD. You.com uses the broader timeframe when the query also specifies one."
|
|
4333
|
+
},
|
|
4334
|
+
"country": {
|
|
4335
|
+
"type": "string",
|
|
4336
|
+
"enum": [
|
|
4337
|
+
"AR",
|
|
4338
|
+
"AU",
|
|
4339
|
+
"AT",
|
|
4340
|
+
"BE",
|
|
4341
|
+
"BR",
|
|
4342
|
+
"CA",
|
|
4343
|
+
"CL",
|
|
4344
|
+
"DK",
|
|
4345
|
+
"FI",
|
|
4346
|
+
"FR",
|
|
4347
|
+
"DE",
|
|
4348
|
+
"HK",
|
|
4349
|
+
"IN",
|
|
4350
|
+
"ID",
|
|
4351
|
+
"IT",
|
|
4352
|
+
"JP",
|
|
4353
|
+
"KR",
|
|
4354
|
+
"MY",
|
|
4355
|
+
"MX",
|
|
4356
|
+
"NL",
|
|
4357
|
+
"NZ",
|
|
4358
|
+
"NO",
|
|
4359
|
+
"CN",
|
|
4360
|
+
"PL",
|
|
4361
|
+
"PT",
|
|
4362
|
+
"PH",
|
|
4363
|
+
"RU",
|
|
4364
|
+
"SA",
|
|
4365
|
+
"ZA",
|
|
4366
|
+
"ES",
|
|
4367
|
+
"SE",
|
|
4368
|
+
"CH",
|
|
4369
|
+
"TW",
|
|
4370
|
+
"TR",
|
|
4371
|
+
"GB",
|
|
4372
|
+
"US"
|
|
4373
|
+
],
|
|
4374
|
+
"description": "Country code used to localize search results, for example US."
|
|
4375
|
+
},
|
|
4376
|
+
"language": {
|
|
4377
|
+
"type": "string",
|
|
4378
|
+
"enum": [
|
|
4379
|
+
"AR",
|
|
4380
|
+
"EU",
|
|
4381
|
+
"BN",
|
|
4382
|
+
"BG",
|
|
4383
|
+
"CA",
|
|
4384
|
+
"ZH-HANS",
|
|
4385
|
+
"ZH-HANT",
|
|
4386
|
+
"HR",
|
|
4387
|
+
"CS",
|
|
4388
|
+
"DA",
|
|
4389
|
+
"NL",
|
|
4390
|
+
"EN",
|
|
4391
|
+
"EN-GB",
|
|
4392
|
+
"ET",
|
|
4393
|
+
"FI",
|
|
4394
|
+
"FR",
|
|
4395
|
+
"GL",
|
|
4396
|
+
"DE",
|
|
4397
|
+
"EL",
|
|
4398
|
+
"GU",
|
|
4399
|
+
"HE",
|
|
4400
|
+
"HI",
|
|
4401
|
+
"HU",
|
|
4402
|
+
"IS",
|
|
4403
|
+
"IT",
|
|
4404
|
+
"JA",
|
|
4405
|
+
"KN",
|
|
4406
|
+
"KO",
|
|
4407
|
+
"LV",
|
|
4408
|
+
"LT",
|
|
4409
|
+
"MS",
|
|
4410
|
+
"ML",
|
|
4411
|
+
"MR",
|
|
4412
|
+
"NB",
|
|
4413
|
+
"PL",
|
|
4414
|
+
"PT-BR",
|
|
4415
|
+
"PT-PT",
|
|
4416
|
+
"PA",
|
|
4417
|
+
"RO",
|
|
4418
|
+
"RU",
|
|
4419
|
+
"SR",
|
|
4420
|
+
"SK",
|
|
4421
|
+
"SL",
|
|
4422
|
+
"ES",
|
|
4423
|
+
"SV",
|
|
4424
|
+
"TA",
|
|
4425
|
+
"TE",
|
|
4426
|
+
"TH",
|
|
4427
|
+
"TR",
|
|
4428
|
+
"UK",
|
|
4429
|
+
"VI"
|
|
4430
|
+
],
|
|
4431
|
+
"description": "Language of web results. Uses You.com's uppercase codes; defaults to EN."
|
|
4432
|
+
},
|
|
4433
|
+
"safesearch": {
|
|
4434
|
+
"type": "string",
|
|
4435
|
+
"enum": ["moderate", "off", "strict"],
|
|
4436
|
+
"description": "Safe-search filtering level. Defaults to moderate."
|
|
4437
|
+
},
|
|
4438
|
+
"offset": {
|
|
4439
|
+
"type": "integer",
|
|
4440
|
+
"minimum": 0,
|
|
4441
|
+
"maximum": 9,
|
|
4442
|
+
"description": "Pagination offset in count-sized pages, separately for web and news. Count is maxResults capped at 100."
|
|
4443
|
+
},
|
|
4444
|
+
"include_domains": {
|
|
4445
|
+
"type": "array",
|
|
4446
|
+
"maxItems": 500,
|
|
4447
|
+
"items": {
|
|
4448
|
+
"type": "string",
|
|
4449
|
+
"minLength": 1
|
|
4450
|
+
},
|
|
4451
|
+
"description": "Restrict results to these domains. Cannot be combined with exclude_domains or boost_domains."
|
|
4452
|
+
},
|
|
4453
|
+
"exclude_domains": {
|
|
4454
|
+
"type": "array",
|
|
4455
|
+
"maxItems": 500,
|
|
4456
|
+
"items": {
|
|
4457
|
+
"type": "string",
|
|
4458
|
+
"minLength": 1
|
|
4459
|
+
},
|
|
4460
|
+
"description": "Exclude these domains. Cannot be combined with include_domains."
|
|
4461
|
+
},
|
|
4462
|
+
"boost_domains": {
|
|
4463
|
+
"type": "array",
|
|
4464
|
+
"maxItems": 500,
|
|
4465
|
+
"items": {
|
|
4466
|
+
"type": "string",
|
|
4467
|
+
"minLength": 1
|
|
4468
|
+
},
|
|
4469
|
+
"description": "Boost these domains without excluding others. Can be combined with exclude_domains, but not include_domains."
|
|
4470
|
+
},
|
|
4471
|
+
"livecrawl": {
|
|
4472
|
+
"type": "string",
|
|
4473
|
+
"enum": ["web", "news", "all"],
|
|
4474
|
+
"description": "Fetch full page content for the selected sections. Adds latency and per-page charges, including results omitted by maxResults. Content is preserved in result metadata.contents."
|
|
4475
|
+
},
|
|
4476
|
+
"livecrawl_formats": {
|
|
4477
|
+
"type": "array",
|
|
4478
|
+
"minItems": 1,
|
|
4479
|
+
"maxItems": 2,
|
|
4480
|
+
"uniqueItems": true,
|
|
4481
|
+
"items": {
|
|
4482
|
+
"type": "string",
|
|
4483
|
+
"enum": ["html", "markdown"]
|
|
4484
|
+
},
|
|
4485
|
+
"description": "Formats for livecrawled content. Defaults to html; requires livecrawl to enable crawling."
|
|
4486
|
+
},
|
|
4487
|
+
"crawl_timeout": {
|
|
4488
|
+
"type": "integer",
|
|
4489
|
+
"minimum": 1,
|
|
4490
|
+
"maximum": 60,
|
|
4491
|
+
"description": "Seconds to wait for page content when livecrawl is enabled. Defaults to 10."
|
|
4492
|
+
}
|
|
4493
|
+
},
|
|
4494
|
+
"anyOf": [
|
|
4495
|
+
{
|
|
4496
|
+
"properties": {
|
|
4497
|
+
"include_domains": false
|
|
4498
|
+
}
|
|
4499
|
+
},
|
|
4500
|
+
{
|
|
4501
|
+
"properties": {
|
|
4502
|
+
"exclude_domains": false,
|
|
4503
|
+
"boost_domains": false
|
|
4504
|
+
}
|
|
4505
|
+
}
|
|
4506
|
+
],
|
|
4507
|
+
"description": "You.com search options. Results alternate web and news, starting with web, up to maxResults (capped at 100).",
|
|
4508
|
+
"additionalProperties": false
|
|
4509
|
+
}
|
|
4510
|
+
}
|
|
4511
|
+
}
|
|
4512
|
+
}
|
|
4266
4513
|
}
|
|
4267
4514
|
}
|
|
4268
4515
|
}
|
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", "serper", "tavily", "valyu"];
|
|
3
|
+
export declare const PROVIDER_IDS: readonly ["brave", "cloudflare", "custom", "exa", "firecrawl", "gemini", "linkup", "ollama", "openai", "parallel", "perplexity", "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/errors.d.ts
CHANGED
|
@@ -4,11 +4,19 @@ export declare class WebfoxError extends Error {
|
|
|
4
4
|
readonly options: {
|
|
5
5
|
cause?: unknown;
|
|
6
6
|
retryable?: boolean;
|
|
7
|
+
configuration?: {
|
|
8
|
+
source: string;
|
|
9
|
+
issues: string[];
|
|
10
|
+
};
|
|
7
11
|
};
|
|
8
12
|
readonly name = "WebfoxError";
|
|
9
13
|
constructor(code: WebfoxErrorCode, message: string, options?: {
|
|
10
14
|
cause?: unknown;
|
|
11
15
|
retryable?: boolean;
|
|
16
|
+
configuration?: {
|
|
17
|
+
source: string;
|
|
18
|
+
issues: string[];
|
|
19
|
+
};
|
|
12
20
|
});
|
|
13
21
|
toJSON(): SerializedError;
|
|
14
22
|
}
|
package/dist/index.js
CHANGED
|
@@ -6,18 +6,18 @@ import {
|
|
|
6
6
|
resolveConfigPath,
|
|
7
7
|
setCapabilityDefault,
|
|
8
8
|
validateConfig
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-KC6K6LCQ.js";
|
|
10
10
|
import "./chunk-WCTOYZVB.js";
|
|
11
11
|
import {
|
|
12
12
|
CONFIG_SCHEMA_URL,
|
|
13
13
|
validateConfiguredOptions
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-CIZXLW6C.js";
|
|
15
15
|
import "./chunk-ZVTVERW5.js";
|
|
16
16
|
import {
|
|
17
17
|
CAPABILITIES,
|
|
18
18
|
PROVIDER_IDS,
|
|
19
19
|
WEBFOX_ERROR_CODES
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-WVHMWLKU.js";
|
|
21
21
|
import {
|
|
22
22
|
WebfoxError
|
|
23
23
|
} from "./chunk-U4BLULLV.js";
|
package/dist/pi.js
CHANGED
|
@@ -2,15 +2,18 @@ import {
|
|
|
2
2
|
renderTextDocument
|
|
3
3
|
} from "./chunk-QRHDXM2L.js";
|
|
4
4
|
import {
|
|
5
|
-
createWebfox
|
|
6
|
-
|
|
5
|
+
createWebfox,
|
|
6
|
+
resolveConfigPath
|
|
7
|
+
} from "./chunk-KC6K6LCQ.js";
|
|
7
8
|
import "./chunk-WCTOYZVB.js";
|
|
8
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-CIZXLW6C.js";
|
|
9
10
|
import "./chunk-ZVTVERW5.js";
|
|
10
11
|
import {
|
|
11
12
|
CAPABILITIES
|
|
12
|
-
} from "./chunk-
|
|
13
|
-
import
|
|
13
|
+
} from "./chunk-WVHMWLKU.js";
|
|
14
|
+
import {
|
|
15
|
+
WebfoxError
|
|
16
|
+
} from "./chunk-U4BLULLV.js";
|
|
14
17
|
|
|
15
18
|
// src/pi.ts
|
|
16
19
|
import { mkdtemp, writeFile } from "node:fs/promises";
|
|
@@ -417,6 +420,24 @@ function prepareToolArguments(schema, args) {
|
|
|
417
420
|
return args;
|
|
418
421
|
}
|
|
419
422
|
|
|
423
|
+
// src/pi-diagnostics.ts
|
|
424
|
+
import { homedir } from "node:os";
|
|
425
|
+
import { sep } from "node:path";
|
|
426
|
+
function configurationDiagnostic(error) {
|
|
427
|
+
const diagnostic = error.options.configuration;
|
|
428
|
+
const source = diagnostic?.source ?? resolveConfigPath();
|
|
429
|
+
const home = homedir() + sep;
|
|
430
|
+
const path = source.startsWith(home) ? `~/${source.slice(home.length)}` : source;
|
|
431
|
+
const issues = diagnostic?.issues ?? [error.message];
|
|
432
|
+
return [
|
|
433
|
+
"Webfox disabled \u2014 invalid configuration",
|
|
434
|
+
` ${path}`,
|
|
435
|
+
...issues.map((issue) => ` ${issue}`),
|
|
436
|
+
"",
|
|
437
|
+
"Fix the configuration, then /reload."
|
|
438
|
+
].join("\n");
|
|
439
|
+
}
|
|
440
|
+
|
|
420
441
|
// src/pi.ts
|
|
421
442
|
function webExtension(pi) {
|
|
422
443
|
const clients = /* @__PURE__ */ new Map();
|
|
@@ -428,10 +449,24 @@ function webExtension(pi) {
|
|
|
428
449
|
}
|
|
429
450
|
return client;
|
|
430
451
|
};
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
452
|
+
let selected;
|
|
453
|
+
try {
|
|
454
|
+
const initial = clientFor(process.cwd());
|
|
455
|
+
selected = CAPABILITIES.map(
|
|
456
|
+
(capability) => initial.inspectCapability(capability)
|
|
457
|
+
).filter((inspection) => inspection.provider);
|
|
458
|
+
} catch (error) {
|
|
459
|
+
if (!(error instanceof WebfoxError) || !["INVALID_CONFIG", "INVALID_INPUT", "PROVIDER_UNAVAILABLE"].includes(
|
|
460
|
+
error.code
|
|
461
|
+
))
|
|
462
|
+
throw error;
|
|
463
|
+
const message = configurationDiagnostic(error);
|
|
464
|
+
pi.on("session_start", (_event, context) => {
|
|
465
|
+
if (context.hasUI) context.ui.notify(message, "error");
|
|
466
|
+
else console.error(message);
|
|
467
|
+
});
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
435
470
|
if (!selected.length)
|
|
436
471
|
pi.on("session_start", (_event, context) => {
|
|
437
472
|
if (context.hasUI)
|
|
@@ -440,8 +475,8 @@ function webExtension(pi) {
|
|
|
440
475
|
"warning"
|
|
441
476
|
);
|
|
442
477
|
});
|
|
443
|
-
for (const
|
|
444
|
-
const
|
|
478
|
+
for (const inspection of selected) {
|
|
479
|
+
const capability = inspection.capability;
|
|
445
480
|
const provider = inspection.provider;
|
|
446
481
|
const fields = capability === "contents" ? { urls: Type.Array(Type.String({ minLength: 1 }), { minItems: 1 }) } : capability === "research" ? { input: Type.String({ minLength: 1 }) } : {
|
|
447
482
|
queries: Type.Array(Type.String({ minLength: 1 }), {
|
|
@@ -84,5 +84,6 @@ export interface ProviderConfigMap {
|
|
|
84
84
|
serper: import("./serper/types.js").Serper;
|
|
85
85
|
tavily: import("./tavily/types.js").Tavily;
|
|
86
86
|
valyu: import("./valyu/types.js").Valyu;
|
|
87
|
+
youcom: import("./youcom/types.js").Youcom;
|
|
87
88
|
}
|
|
88
89
|
export type ProviderConfig<T extends ProviderId = ProviderId> = ProviderConfigMap[T];
|
|
@@ -13,4 +13,5 @@ export declare const providers: {
|
|
|
13
13
|
readonly serper: import("./definition.js").ProviderDefinitionFor<"serper">;
|
|
14
14
|
readonly tavily: import("./definition.js").ProviderDefinitionFor<"tavily">;
|
|
15
15
|
readonly valyu: import("./definition.js").ProviderDefinitionFor<"valyu">;
|
|
16
|
+
readonly youcom: import("./definition.js").ProviderDefinitionFor<"youcom">;
|
|
16
17
|
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ProviderContext, SearchResponse } from "../contract.js";
|
|
2
|
+
import type { Youcom } from "./types.js";
|
|
3
|
+
export declare const adapter: {
|
|
4
|
+
search(request: import("../contract.js").ProviderRequest<"search">, config: Youcom, context: ProviderContext): Promise<SearchResponse>;
|
|
5
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const youcomProvider: import("../definition.js").ProviderDefinitionFor<"youcom">;
|
package/docs/provider.md
CHANGED
|
@@ -160,6 +160,84 @@ Supports search. Set `SERPER_API_KEY`.
|
|
|
160
160
|
web search "Node.js release notes" --provider serper
|
|
161
161
|
```
|
|
162
162
|
|
|
163
|
+
## You.com
|
|
164
|
+
|
|
165
|
+
Supports search. Set `YDC_API_KEY`; the library, CLI, and Pi extension use the
|
|
166
|
+
same credential. No defaults change unless you select You.com.
|
|
167
|
+
|
|
168
|
+
```sh
|
|
169
|
+
web search "Node.js release notes" --provider youcom \
|
|
170
|
+
--freshness week --country US --language EN --include-domains nodejs.org
|
|
171
|
+
web config default search youcom
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
You.com returns separate web and news sections. Webfox alternates results from
|
|
175
|
+
these sections, starting with web and preserving each section's order, up to
|
|
176
|
+
`maxResults` (capped at 100 overall). If one section is exhausted, the other fills
|
|
177
|
+
the remaining slots. With `maxResults: 1`, web takes precedence. The `offset`
|
|
178
|
+
option selects pages from each section independently, using the capped
|
|
179
|
+
`maxResults` as the upstream page size.
|
|
180
|
+
|
|
181
|
+
Use `include_domains` to restrict sources, or combine `exclude_domains` with
|
|
182
|
+
`boost_domains` to exclude some sources and favor others. Don't combine
|
|
183
|
+
`include_domains` with either of the other domain lists. Each list supports up to
|
|
184
|
+
500 domains. Country and language codes use the API's uppercase spelling, such
|
|
185
|
+
as `US`, `EN`, and `EN-GB`. Run `web search --provider youcom --help` for supported
|
|
186
|
+
values and all native options.
|
|
187
|
+
|
|
188
|
+
Search snippets already contain query-relevant passages. For full page content,
|
|
189
|
+
enable live crawling:
|
|
190
|
+
|
|
191
|
+
```sh
|
|
192
|
+
web search "Node.js cancellation" --provider youcom \
|
|
193
|
+
--livecrawl web --livecrawl-formats markdown --crawl-timeout 10 --format json
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Live crawling adds latency and per-page charges, including pages that don't fit
|
|
197
|
+
within the final result limit. By default, it returns HTML; request `markdown` or
|
|
198
|
+
both formats as needed. Full content is preserved in each result's
|
|
199
|
+
`metadata.contents`; text output shows snippets rather than full pages. See
|
|
200
|
+
[You.com's API reference](https://you.com/docs/api-reference/search/v1-search-post)
|
|
201
|
+
for current pricing and filter behavior.
|
|
202
|
+
|
|
203
|
+
Provider-specific defaults belong under `providers.youcom.options.search`:
|
|
204
|
+
|
|
205
|
+
```yaml
|
|
206
|
+
defaults:
|
|
207
|
+
search:
|
|
208
|
+
provider: youcom
|
|
209
|
+
providers:
|
|
210
|
+
youcom:
|
|
211
|
+
options:
|
|
212
|
+
search:
|
|
213
|
+
country: US
|
|
214
|
+
language: EN
|
|
215
|
+
safesearch: moderate
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
`providers.youcom.baseUrl` optionally replaces the API origin for a proxy; webfox
|
|
219
|
+
appends `/v1/search`. Credential overrides use `providers.youcom.credentials.api`.
|
|
220
|
+
For example, `{env: MY_YOUCOM_KEY}` selects another environment variable.
|
|
221
|
+
|
|
222
|
+
The TypeScript library accepts the same native option names:
|
|
223
|
+
|
|
224
|
+
```ts
|
|
225
|
+
import { createWebfox } from "webfox";
|
|
226
|
+
|
|
227
|
+
const result = await createWebfox().search({
|
|
228
|
+
provider: "youcom",
|
|
229
|
+
queries: ["Node.js release notes"],
|
|
230
|
+
maxResults: 5,
|
|
231
|
+
options: { freshness: "week", include_domains: ["nodejs.org"] },
|
|
232
|
+
});
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
The provider uses the JSON POST API directly, like the HTTP-based Brave and
|
|
236
|
+
Serper providers. Option names follow the wire contract rather than the official
|
|
237
|
+
You.com SDK's camelCase names. Selecting You.com as the search default exposes
|
|
238
|
+
these options through the existing `web_search` Pi tool; no separate tool is
|
|
239
|
+
needed.
|
|
240
|
+
|
|
163
241
|
## Tavily
|
|
164
242
|
|
|
165
243
|
Supports search and page extraction. Set `TAVILY_API_KEY`.
|
package/example-config.yaml
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
$schema: https://unpkg.com/webfox@
|
|
1
|
+
$schema: https://unpkg.com/webfox@latest/dist/config.schema.json
|
|
2
2
|
defaults:
|
|
3
3
|
search:
|
|
4
4
|
provider: brave
|
|
@@ -34,3 +34,11 @@ providers:
|
|
|
34
34
|
credentials:
|
|
35
35
|
api:
|
|
36
36
|
env: GOOGLE_API_KEY
|
|
37
|
+
youcom:
|
|
38
|
+
credentials:
|
|
39
|
+
api:
|
|
40
|
+
env: YDC_API_KEY
|
|
41
|
+
options:
|
|
42
|
+
search:
|
|
43
|
+
language: EN
|
|
44
|
+
safesearch: moderate
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "webfox",
|
|
3
|
-
"version": "4.0
|
|
3
|
+
"version": "4.2.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": [
|