webfox 4.2.1 → 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/adapter-RL7JNB22.js +183 -0
- package/dist/{adapter-A7LV6L55.js → adapter-VW4FMMJC.js} +1 -1
- package/dist/application-types.d.ts +1 -0
- package/dist/chunk-4SX4TI7A.js +244 -0
- package/dist/{chunk-SGHBA2PZ.js → chunk-5H6OAJCS.js} +11 -4
- package/dist/{chunk-QRHDXM2L.js → chunk-BTWECET5.js} +1 -1
- package/dist/{chunk-WVHMWLKU.js → chunk-GPACLYNT.js} +1 -0
- package/dist/{chunk-TJWQTB6W.js → chunk-VYMIR35R.js} +140 -236
- package/dist/cli.js +7 -5
- package/dist/config.schema.json +196 -0
- package/dist/domain.d.ts +1 -1
- package/dist/index.js +6 -4
- package/dist/pi.js +12 -6
- package/dist/providers/contract.d.ts +1 -0
- package/dist/providers/definition.d.ts +4 -0
- package/dist/providers/registry.d.ts +1 -0
- package/dist/providers/serpbase/adapter.d.ts +5 -0
- package/dist/providers/serpbase/definition.d.ts +1 -0
- package/dist/providers/serpbase/types.d.ts +37 -0
- package/docs/provider.md +102 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -134,6 +134,7 @@ Use different providers for different tasks:
|
|
|
134
134
|
| [OpenAI] | ✔︎ | | ✔︎ | ✔︎ |
|
|
135
135
|
| [Parallel] | ✔︎ | ✔︎ | | |
|
|
136
136
|
| [Perplexity] | ✔︎ | | ✔︎ | ✔︎ |
|
|
137
|
+
| [SerpBase] | ✔︎ | | | |
|
|
137
138
|
| [Serper] | ✔︎ | | | |
|
|
138
139
|
| [Tavily] | ✔︎ | ✔︎ | | |
|
|
139
140
|
| [Valyu] | ✔︎ | ✔︎ | ✔︎ | ✔︎ |
|
|
@@ -150,6 +151,7 @@ Use different providers for different tasks:
|
|
|
150
151
|
[OpenAI]: ./docs/provider.md#openai
|
|
151
152
|
[Parallel]: ./docs/provider.md#parallel
|
|
152
153
|
[Perplexity]: ./docs/provider.md#perplexity
|
|
154
|
+
[SerpBase]: ./docs/provider.md#serpbase
|
|
153
155
|
[Serper]: ./docs/provider.md#serper
|
|
154
156
|
[Tavily]: ./docs/provider.md#tavily
|
|
155
157
|
[Valyu]: ./docs/provider.md#valyu
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SERPBASE_MODES,
|
|
3
|
+
serpbaseProvider,
|
|
4
|
+
validateOptions
|
|
5
|
+
} from "./chunk-VYMIR35R.js";
|
|
6
|
+
import "./chunk-GPACLYNT.js";
|
|
7
|
+
import {
|
|
8
|
+
trimSnippet
|
|
9
|
+
} from "./chunk-X6ZBIHZC.js";
|
|
10
|
+
import {
|
|
11
|
+
WebfoxError,
|
|
12
|
+
httpError
|
|
13
|
+
} from "./chunk-U4BLULLV.js";
|
|
14
|
+
|
|
15
|
+
// src/providers/serpbase/adapter.ts
|
|
16
|
+
var DEFAULT_BASE_URL = "https://api.serpbase.dev";
|
|
17
|
+
var RETRYABLE_STATUSES = /* @__PURE__ */ new Set([1029, 1500, 1502, 1503, 1504]);
|
|
18
|
+
var FEATURE_ID = /^0x[0-9a-f]+:0x[0-9a-f]+$/i;
|
|
19
|
+
var adapter = {
|
|
20
|
+
async search(request, config, context) {
|
|
21
|
+
const options = {
|
|
22
|
+
...request.options,
|
|
23
|
+
mode: request.options?.mode ?? "search"
|
|
24
|
+
};
|
|
25
|
+
validateOptions(serpbaseProvider, "search", options);
|
|
26
|
+
const mode = options.mode;
|
|
27
|
+
const endpoint = SERPBASE_MODES[mode];
|
|
28
|
+
if (mode === "maps-detail" && !FEATURE_ID.test(request.query)) {
|
|
29
|
+
throw new WebfoxError(
|
|
30
|
+
"INVALID_INPUT",
|
|
31
|
+
"SerpBase maps-detail requires a feature_id (0x...:0x...) in each queries entry. First use mode maps and copy the returned feature_id; names, place_id, CID, and Maps URLs are not accepted."
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
const apiKey = config.credentials?.api;
|
|
35
|
+
if (!apiKey) throw new Error("SerpBase search is missing an API key");
|
|
36
|
+
const response = await fetch(
|
|
37
|
+
`${(config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "")}/google/${endpoint.path}`,
|
|
38
|
+
{
|
|
39
|
+
method: "POST",
|
|
40
|
+
headers: { "content-type": "application/json", "X-API-Key": apiKey },
|
|
41
|
+
body: JSON.stringify({
|
|
42
|
+
...mode === "maps-detail" ? { feature_id: request.query } : { q: request.query },
|
|
43
|
+
...Object.fromEntries(
|
|
44
|
+
endpoint.options.flatMap(
|
|
45
|
+
(key) => options[key] === void 0 ? [] : [[key, options[key]]]
|
|
46
|
+
)
|
|
47
|
+
)
|
|
48
|
+
}),
|
|
49
|
+
signal: context.signal
|
|
50
|
+
}
|
|
51
|
+
);
|
|
52
|
+
const body = await response.text();
|
|
53
|
+
let payload;
|
|
54
|
+
try {
|
|
55
|
+
payload = asRecord(JSON.parse(body));
|
|
56
|
+
} catch {
|
|
57
|
+
}
|
|
58
|
+
const status = payload?.status;
|
|
59
|
+
const apiFailure = typeof status === "number" && status !== 0;
|
|
60
|
+
if (!response.ok || apiFailure) {
|
|
61
|
+
const detail = (text(payload?.error) ?? body.trim()).slice(0, 500);
|
|
62
|
+
const message = `SerpBase ${mode} request failed (HTTP ${response.status}${apiFailure ? `, status ${status}` : ""})${detail ? `: ${detail}` : "."}`;
|
|
63
|
+
if (apiFailure) {
|
|
64
|
+
throw new WebfoxError("PROVIDER_FAILURE", message, {
|
|
65
|
+
retryable: RETRYABLE_STATUSES.has(status)
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
throw httpError(response, message);
|
|
69
|
+
}
|
|
70
|
+
const collection = payload?.[endpoint.result];
|
|
71
|
+
if (!payload || status !== 0 || collection !== void 0 && (mode === "maps-detail" ? !asRecord(collection) : !Array.isArray(collection))) {
|
|
72
|
+
throw new WebfoxError(
|
|
73
|
+
"PROVIDER_FAILURE",
|
|
74
|
+
`SerpBase returned an invalid ${mode} response.`,
|
|
75
|
+
{ retryable: false }
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
const searchContext = { ...payload };
|
|
79
|
+
for (const { result } of Object.values(SERPBASE_MODES))
|
|
80
|
+
delete searchContext[result];
|
|
81
|
+
const entries = mode === "maps-detail" ? collection === void 0 ? [] : [collection] : collection ?? [];
|
|
82
|
+
const results = entries.map((entry) => toSearchResult(entry, searchContext, mode)).filter((result) => result !== void 0);
|
|
83
|
+
return {
|
|
84
|
+
provider: "serpbase",
|
|
85
|
+
// No upstream count parameter or automatic pagination: one page or place.
|
|
86
|
+
results: results.slice(
|
|
87
|
+
0,
|
|
88
|
+
Math.max(1, Math.trunc(request.maxResults || 0))
|
|
89
|
+
)
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
function toSearchResult(entry, searchContext, mode) {
|
|
94
|
+
const record = asRecord(entry);
|
|
95
|
+
if (!record || mode === "images" && isNavigationImage(record))
|
|
96
|
+
return void 0;
|
|
97
|
+
const isPlace = mode === "maps" || mode === "maps-detail";
|
|
98
|
+
const featureId = text(record.feature_id);
|
|
99
|
+
const url = isPlace ? text(record.google_maps_url) ?? text(record.url) ?? text(record.website) ?? (featureId && FEATURE_ID.test(featureId) ? `https://www.google.com/maps?ftid=${encodeURIComponent(featureId)}` : void 0) : text(record.link) ?? text(record.url) ?? (mode === "images" ? text(record.image_url) : void 0);
|
|
100
|
+
if (!url) return void 0;
|
|
101
|
+
const { title, link: _link, url: _url, snippet, ...metadata } = record;
|
|
102
|
+
return {
|
|
103
|
+
title: text(title) ?? text(record.name) ?? url,
|
|
104
|
+
url,
|
|
105
|
+
snippet: resultSnippet(record, mode),
|
|
106
|
+
metadata: { ...metadata, mode, searchContext }
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function resultSnippet(record, mode) {
|
|
110
|
+
const lines = [];
|
|
111
|
+
const excerpt = text(record.snippet) ?? text(record.short_description) ?? text(record.description);
|
|
112
|
+
if (excerpt && !(mode === "videos" && /^\s*Duration:\s*Posted:\s*$/i.test(excerpt)))
|
|
113
|
+
lines.push(trimSnippet(excerpt));
|
|
114
|
+
const add = (label, value, limit = 600) => {
|
|
115
|
+
if (typeof value === "number" && Number.isFinite(value))
|
|
116
|
+
value = String(value);
|
|
117
|
+
if (text(value))
|
|
118
|
+
lines.push(`${label}: ${trimSnippet(value, limit)}`);
|
|
119
|
+
};
|
|
120
|
+
const json = (label, value) => {
|
|
121
|
+
if (value && typeof value === "object")
|
|
122
|
+
add(label, JSON.stringify(value), 1200);
|
|
123
|
+
};
|
|
124
|
+
if (mode === "images") {
|
|
125
|
+
add("Image URL", record.image_url, Infinity);
|
|
126
|
+
add("Source page", text(record.link) ?? text(record.url), Infinity);
|
|
127
|
+
add(
|
|
128
|
+
"Thumbnail",
|
|
129
|
+
text(record.thumbnail_url) ?? text(record.thumbnail),
|
|
130
|
+
Infinity
|
|
131
|
+
);
|
|
132
|
+
add("Source", text(record.source) ?? text(record.domain));
|
|
133
|
+
} else if (mode === "news" || mode === "videos") {
|
|
134
|
+
add("Source", record.source);
|
|
135
|
+
const published = text(record.published_at) ?? text(record.time);
|
|
136
|
+
add(
|
|
137
|
+
published && /^\d{1,3}:\d{2}(?::\d{2})?$/.test(published.trim()) ? "Time (upstream)" : "Published",
|
|
138
|
+
published
|
|
139
|
+
);
|
|
140
|
+
if (mode === "videos") add("Duration", record.duration);
|
|
141
|
+
add(
|
|
142
|
+
"Thumbnail",
|
|
143
|
+
text(record.thumbnail_url) ?? text(record.thumbnail),
|
|
144
|
+
Infinity
|
|
145
|
+
);
|
|
146
|
+
} else if (mode === "maps" || mode === "maps-detail") {
|
|
147
|
+
add("feature_id", record.feature_id, Infinity);
|
|
148
|
+
add("Address", record.address);
|
|
149
|
+
add("Rating", record.rating);
|
|
150
|
+
add("Reviews", record.review_count);
|
|
151
|
+
add("Phone", text(record.phone_international) ?? text(record.phone));
|
|
152
|
+
add("Website", record.website, Infinity);
|
|
153
|
+
if (typeof record.latitude === "number" && typeof record.longitude === "number")
|
|
154
|
+
add("Coordinates", `${record.latitude}, ${record.longitude}`);
|
|
155
|
+
if (Array.isArray(record.types))
|
|
156
|
+
add(
|
|
157
|
+
"Categories",
|
|
158
|
+
record.types.filter((item) => typeof item === "string").join(", ")
|
|
159
|
+
);
|
|
160
|
+
json("Hours", record.hours);
|
|
161
|
+
json("Open status", record.open_status);
|
|
162
|
+
if (mode === "maps-detail") json("Attributes", record.attributes);
|
|
163
|
+
}
|
|
164
|
+
return lines.join("\n");
|
|
165
|
+
}
|
|
166
|
+
function isNavigationImage(record) {
|
|
167
|
+
try {
|
|
168
|
+
const image = new URL(String(record.image_url));
|
|
169
|
+
const source = new URL(String(record.link ?? record.url));
|
|
170
|
+
return image.hostname === "www.gstatic.com" && image.pathname === "/m/images/icons/googleg.gif" && (source.hostname === "www.google.com" || source.hostname === "google.com") && (source.pathname === "/" || source.pathname === "/search");
|
|
171
|
+
} catch {
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
function asRecord(value) {
|
|
176
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
177
|
+
}
|
|
178
|
+
function text(value) {
|
|
179
|
+
return typeof value === "string" && value.trim() ? value : void 0;
|
|
180
|
+
}
|
|
181
|
+
export {
|
|
182
|
+
adapter
|
|
183
|
+
};
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import {
|
|
2
|
+
optionSchema,
|
|
3
|
+
providers
|
|
4
|
+
} from "./chunk-VYMIR35R.js";
|
|
5
|
+
import {
|
|
6
|
+
CAPABILITIES
|
|
7
|
+
} from "./chunk-GPACLYNT.js";
|
|
8
|
+
|
|
9
|
+
// package.json
|
|
10
|
+
var package_default = {
|
|
11
|
+
name: "webfox",
|
|
12
|
+
version: "4.3.0",
|
|
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
|
+
type: "module",
|
|
15
|
+
files: [
|
|
16
|
+
"dist",
|
|
17
|
+
"README.md",
|
|
18
|
+
"assets/webfox-lockup.png",
|
|
19
|
+
"assets/webfox-lockup-dark.png",
|
|
20
|
+
"docs/cli-experience.md",
|
|
21
|
+
"docs/provider.md",
|
|
22
|
+
"docs/reference.md",
|
|
23
|
+
"LICENSE",
|
|
24
|
+
"example-config.yaml",
|
|
25
|
+
"examples"
|
|
26
|
+
],
|
|
27
|
+
keywords: [
|
|
28
|
+
"webfox",
|
|
29
|
+
"web-cli",
|
|
30
|
+
"typescript-library",
|
|
31
|
+
"pi-package",
|
|
32
|
+
"pi-extension",
|
|
33
|
+
"coding-agent",
|
|
34
|
+
"web-search",
|
|
35
|
+
"web-contents",
|
|
36
|
+
"web-answer",
|
|
37
|
+
"web-research",
|
|
38
|
+
"provider-routing",
|
|
39
|
+
"brave",
|
|
40
|
+
"cloudflare",
|
|
41
|
+
"custom",
|
|
42
|
+
"exa",
|
|
43
|
+
"firecrawl",
|
|
44
|
+
"gemini",
|
|
45
|
+
"linkup",
|
|
46
|
+
"ollama",
|
|
47
|
+
"openai",
|
|
48
|
+
"parallel",
|
|
49
|
+
"perplexity",
|
|
50
|
+
"serper",
|
|
51
|
+
"tavily",
|
|
52
|
+
"valyu"
|
|
53
|
+
],
|
|
54
|
+
author: "mavam",
|
|
55
|
+
license: "MIT",
|
|
56
|
+
repository: {
|
|
57
|
+
type: "git",
|
|
58
|
+
url: "git+https://github.com/mavam/webfox.git"
|
|
59
|
+
},
|
|
60
|
+
engines: {
|
|
61
|
+
node: ">=22.0.0"
|
|
62
|
+
},
|
|
63
|
+
publishConfig: {
|
|
64
|
+
access: "public"
|
|
65
|
+
},
|
|
66
|
+
pi: {
|
|
67
|
+
extensions: [
|
|
68
|
+
"./dist/pi.js"
|
|
69
|
+
]
|
|
70
|
+
},
|
|
71
|
+
bin: {
|
|
72
|
+
web: "./dist/cli.js"
|
|
73
|
+
},
|
|
74
|
+
main: "./dist/index.js",
|
|
75
|
+
types: "./dist/index.d.ts",
|
|
76
|
+
exports: {
|
|
77
|
+
".": {
|
|
78
|
+
types: "./dist/index.d.ts",
|
|
79
|
+
import: "./dist/index.js"
|
|
80
|
+
},
|
|
81
|
+
"./pi": {
|
|
82
|
+
types: "./dist/pi.d.ts",
|
|
83
|
+
import: "./dist/pi.js"
|
|
84
|
+
},
|
|
85
|
+
"./config.schema.json": "./dist/config.schema.json"
|
|
86
|
+
},
|
|
87
|
+
scripts: {
|
|
88
|
+
build: "rm -rf dist && esbuild index=src/index.ts cli=src/cli.ts pi=src/pi.ts generate-schema=scripts/generate-schema.ts --bundle --splitting --format=esm --platform=node --target=node22 --packages=external --outdir=dist && node dist/generate-schema.js && biome format --write src/config.schema.json >&2 && rm dist/generate-schema.js && tsc --project tsconfig.build.json && cp src/config.schema.json dist/config.schema.json && chmod +x dist/cli.js",
|
|
89
|
+
prepare: "npm run build",
|
|
90
|
+
prepack: "npm run build",
|
|
91
|
+
check: "tsc --noEmit",
|
|
92
|
+
format: "biome format --write .",
|
|
93
|
+
"format:check": "biome format .",
|
|
94
|
+
"smoke:live": "npm run build && node scripts/live-smoke.mjs",
|
|
95
|
+
"smoke:package": "node scripts/package-smoke.mjs",
|
|
96
|
+
test: "vitest run",
|
|
97
|
+
"test:watch": "vitest"
|
|
98
|
+
},
|
|
99
|
+
dependencies: {
|
|
100
|
+
"@mendable/firecrawl-js": "^4.38.0",
|
|
101
|
+
"@perplexity-ai/perplexity_ai": "^0.38.5",
|
|
102
|
+
"@tavily/core": "^0.7.9",
|
|
103
|
+
cloudflare: "^7.1.0",
|
|
104
|
+
commander: "^14.0.3",
|
|
105
|
+
"exa-js": "^2.19.0",
|
|
106
|
+
"linkup-sdk": "^3.6.0",
|
|
107
|
+
openai: "^7.10.0",
|
|
108
|
+
"parallel-web": "^1.3.3",
|
|
109
|
+
picocolors: "^1.1.1",
|
|
110
|
+
typebox: "^1.3.6",
|
|
111
|
+
"valyu-js": "^2.10.1",
|
|
112
|
+
yaml: "^2.9.0"
|
|
113
|
+
},
|
|
114
|
+
devDependencies: {
|
|
115
|
+
"@biomejs/biome": "^2.5.4",
|
|
116
|
+
"@earendil-works/pi-ai": "^0.85.1",
|
|
117
|
+
"@earendil-works/pi-coding-agent": "^0.85.1",
|
|
118
|
+
"@earendil-works/pi-tui": "^0.85.1",
|
|
119
|
+
"@types/node": "^26.1.1",
|
|
120
|
+
esbuild: "^0.28.1",
|
|
121
|
+
typescript: "^7.0.2",
|
|
122
|
+
vitest: "^4.1.10"
|
|
123
|
+
},
|
|
124
|
+
peerDependencies: {
|
|
125
|
+
"@earendil-works/pi-coding-agent": "*",
|
|
126
|
+
"@earendil-works/pi-tui": "*"
|
|
127
|
+
},
|
|
128
|
+
peerDependenciesMeta: {
|
|
129
|
+
"@earendil-works/pi-coding-agent": {
|
|
130
|
+
optional: true
|
|
131
|
+
},
|
|
132
|
+
"@earendil-works/pi-tui": {
|
|
133
|
+
optional: true
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
// src/package-metadata.ts
|
|
139
|
+
var PACKAGE_NAME = package_default.name;
|
|
140
|
+
var PACKAGE_VERSION = package_default.version;
|
|
141
|
+
var CONFIG_SCHEMA_URL = `https://unpkg.com/${PACKAGE_NAME}@latest/dist/config.schema.json`;
|
|
142
|
+
|
|
143
|
+
// src/configuration/schema.ts
|
|
144
|
+
var text = { type: "string", minLength: 1 };
|
|
145
|
+
var object = (properties) => ({
|
|
146
|
+
type: "object",
|
|
147
|
+
additionalProperties: false,
|
|
148
|
+
properties
|
|
149
|
+
});
|
|
150
|
+
var source = {
|
|
151
|
+
oneOf: ["env", "value", "command"].map((key) => ({
|
|
152
|
+
...object({
|
|
153
|
+
[key]: key === "command" ? { type: "array", minItems: 1, items: text } : text
|
|
154
|
+
}),
|
|
155
|
+
required: [key]
|
|
156
|
+
}))
|
|
157
|
+
};
|
|
158
|
+
var sourceMap = { type: "object", additionalProperties: source };
|
|
159
|
+
var command = {
|
|
160
|
+
...object({
|
|
161
|
+
argv: { type: "array", minItems: 1, items: text },
|
|
162
|
+
cwd: text,
|
|
163
|
+
env: sourceMap
|
|
164
|
+
}),
|
|
165
|
+
required: ["argv"]
|
|
166
|
+
};
|
|
167
|
+
var positive = { type: "integer", minimum: 1 };
|
|
168
|
+
var timeout = { ...positive, maximum: 2147483647 };
|
|
169
|
+
var fields = {
|
|
170
|
+
credentials: sourceMap,
|
|
171
|
+
baseUrl: text,
|
|
172
|
+
accountId: source,
|
|
173
|
+
commands: object(
|
|
174
|
+
Object.fromEntries(CAPABILITIES.map((capability) => [capability, command]))
|
|
175
|
+
)
|
|
176
|
+
};
|
|
177
|
+
var configurationSchema = {
|
|
178
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
179
|
+
$id: CONFIG_SCHEMA_URL,
|
|
180
|
+
title: "webfox configuration",
|
|
181
|
+
...object({
|
|
182
|
+
$schema: text,
|
|
183
|
+
defaults: object(
|
|
184
|
+
Object.fromEntries(
|
|
185
|
+
CAPABILITIES.map((capability) => [
|
|
186
|
+
capability,
|
|
187
|
+
object({
|
|
188
|
+
provider: {
|
|
189
|
+
enum: Object.values(providers).filter((provider) => provider.capabilities[capability]).map((provider) => provider.id)
|
|
190
|
+
},
|
|
191
|
+
...capability === "search" ? { maxResults: positive } : {}
|
|
192
|
+
})
|
|
193
|
+
])
|
|
194
|
+
)
|
|
195
|
+
),
|
|
196
|
+
execution: object({
|
|
197
|
+
timeoutMs: timeout,
|
|
198
|
+
researchTimeoutMs: timeout,
|
|
199
|
+
retries: { type: "integer", minimum: 0 },
|
|
200
|
+
retryDelayMs: { type: "integer", minimum: 0 },
|
|
201
|
+
concurrency: positive
|
|
202
|
+
}),
|
|
203
|
+
providers: object(
|
|
204
|
+
Object.fromEntries(
|
|
205
|
+
Object.values(providers).map((provider) => [
|
|
206
|
+
provider.id,
|
|
207
|
+
object(
|
|
208
|
+
Object.fromEntries(
|
|
209
|
+
provider.fields.map((field) => [
|
|
210
|
+
field,
|
|
211
|
+
field === "options" ? object(
|
|
212
|
+
Object.fromEntries(
|
|
213
|
+
CAPABILITIES.filter(
|
|
214
|
+
(capability) => provider.capabilities[capability]
|
|
215
|
+
).map((capability) => [
|
|
216
|
+
capability,
|
|
217
|
+
optionSchema(provider, capability, "defaults") ?? {
|
|
218
|
+
type: "object",
|
|
219
|
+
additionalProperties: provider.id === "custom"
|
|
220
|
+
}
|
|
221
|
+
])
|
|
222
|
+
)
|
|
223
|
+
) : field === "credentials" ? object(
|
|
224
|
+
Object.fromEntries(
|
|
225
|
+
provider.credentials.map((credential) => [
|
|
226
|
+
credential.name,
|
|
227
|
+
source
|
|
228
|
+
])
|
|
229
|
+
)
|
|
230
|
+
) : fields[field]
|
|
231
|
+
])
|
|
232
|
+
)
|
|
233
|
+
)
|
|
234
|
+
])
|
|
235
|
+
)
|
|
236
|
+
)
|
|
237
|
+
})
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
export {
|
|
241
|
+
PACKAGE_VERSION,
|
|
242
|
+
CONFIG_SCHEMA_URL,
|
|
243
|
+
configurationSchema
|
|
244
|
+
};
|
|
@@ -5,20 +5,22 @@ import {
|
|
|
5
5
|
withSignal
|
|
6
6
|
} from "./chunk-WCTOYZVB.js";
|
|
7
7
|
import {
|
|
8
|
-
configurationSchema
|
|
8
|
+
configurationSchema
|
|
9
|
+
} from "./chunk-4SX4TI7A.js";
|
|
10
|
+
import {
|
|
9
11
|
effectiveOptions,
|
|
10
12
|
optionSchema,
|
|
11
13
|
providers,
|
|
12
14
|
selectProvider,
|
|
13
15
|
validateConfiguredOptions
|
|
14
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-VYMIR35R.js";
|
|
15
17
|
import {
|
|
16
18
|
cancelProcessGroup,
|
|
17
19
|
killProcessGroup
|
|
18
20
|
} from "./chunk-ZVTVERW5.js";
|
|
19
21
|
import {
|
|
20
22
|
CAPABILITIES
|
|
21
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-GPACLYNT.js";
|
|
22
24
|
import {
|
|
23
25
|
WebfoxError,
|
|
24
26
|
asWebfoxError
|
|
@@ -361,7 +363,7 @@ var ExecutionRuntime = class {
|
|
|
361
363
|
credentials;
|
|
362
364
|
async execute(plan, request) {
|
|
363
365
|
const { capability, definition, inputs } = plan;
|
|
364
|
-
const timeoutMs = request.timeoutMs ?? (capability === "research" ? plan.policy.researchTimeoutMs
|
|
366
|
+
const timeoutMs = request.timeoutMs ?? (capability === "research" ? plan.policy.researchTimeoutMs : plan.policy.timeoutMs) ?? definition.capabilities[capability]?.defaultTimeoutMs ?? (capability === "research" ? 18e5 : 3e4);
|
|
365
367
|
if (!Number.isSafeInteger(timeoutMs) || timeoutMs <= 0 || timeoutMs > 2147483647)
|
|
366
368
|
throw new WebfoxError(
|
|
367
369
|
"INVALID_INPUT",
|
|
@@ -689,6 +691,11 @@ function createWebfox(options = {}) {
|
|
|
689
691
|
capability,
|
|
690
692
|
provider: selected,
|
|
691
693
|
configured: configured(definition, capability),
|
|
694
|
+
...definition.capabilities[capability]?.promptGuidelines ? {
|
|
695
|
+
promptGuidelines: [
|
|
696
|
+
...definition.capabilities[capability].promptGuidelines
|
|
697
|
+
]
|
|
698
|
+
} : {},
|
|
692
699
|
// Static provider schemas contain no credentials. Redacting property
|
|
693
700
|
// names such as maximum_number_of_tokens would invalidate the schema.
|
|
694
701
|
optionSchema: optionSchema(
|
|
@@ -9,7 +9,7 @@ function renderTextDocument(document, { includeErrors = true } = {}) {
|
|
|
9
9
|
body = entry.value.results.length ? entry.value.results.map(
|
|
10
10
|
(result, i) => `${i + 1}. ${result.title}
|
|
11
11
|
${result.url}
|
|
12
|
-
${result.snippet}`
|
|
12
|
+
${result.snippet.replaceAll("\n", "\n ")}`
|
|
13
13
|
).join("\n\n") : "No results found.";
|
|
14
14
|
else if ("text" in entry.value) body = entry.value.text;
|
|
15
15
|
else body = renderContents(entry.value);
|