webfox 4.10.0 → 4.11.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 -12
- package/dist/{adapter-UIFBJKKF.js → adapter-44ZBIK47.js} +4 -6
- package/dist/{adapter-HTMXAJTU.js → adapter-57MELLYI.js} +2 -8
- package/dist/{adapter-VMMS4YQG.js → adapter-BZO5UEI6.js} +3 -15
- package/dist/{adapter-OK2PTP6R.js → adapter-D4EXZEDL.js} +16 -48
- package/dist/{adapter-G3I7JEO5.js → adapter-DJCTEEOA.js} +3 -5
- package/dist/{adapter-764OQFKY.js → adapter-DLNMW34W.js} +8 -35
- package/dist/{adapter-HRI5ZMGK.js → adapter-GFXYSHKP.js} +9 -43
- package/dist/{adapter-2UVAARTV.js → adapter-GJOUFE2U.js} +1 -1
- package/dist/{adapter-C2VZHFUB.js → adapter-MZ7USB6Q.js} +3 -4
- package/dist/adapter-ODDFBGJG.js +167 -0
- package/dist/{adapter-K6AMSUCR.js → adapter-QQZFHUOP.js} +14 -37
- package/dist/{adapter-AUYLTDPM.js → adapter-RR55EZAW.js} +1 -1
- package/dist/{adapter-JJSMYZXG.js → adapter-SZMVKAMC.js} +1 -1
- package/dist/{adapter-6EZAIE65.js → adapter-VXT4C6RZ.js} +16 -66
- package/dist/{adapter-L6BFKWGX.js → adapter-WXEVTCM3.js} +7 -14
- package/dist/{adapter-ZYDUANQL.js → adapter-XSQX3GAI.js} +13 -5
- package/dist/{adapter-EIDSGLOP.js → adapter-XU2APKPC.js} +3 -3
- package/dist/{adapter-A5WYGGZI.js → adapter-YVZ4YBK5.js} +8 -16
- package/dist/chunk-6RQGO727.js +71 -0
- package/dist/{chunk-TGULKHB5.js → chunk-KMUCUJVN.js} +3 -3
- package/dist/{chunk-EF4VMDZL.js → chunk-LDVDVA4Z.js} +1 -4
- package/dist/{chunk-57OOEOXI.js → chunk-NENL6L6N.js} +1 -0
- package/dist/{chunk-5FP7KNMC.js → chunk-PVNWACMT.js} +132 -18
- package/dist/{chunk-YZXM4U2C.js → chunk-TYJ6RHKB.js} +10 -0
- package/dist/{chunk-3WBE6UEW.js → chunk-YILOS4E7.js} +23 -9
- package/dist/cli.js +5 -5
- package/dist/config.schema.json +187 -0
- package/dist/contents.d.ts +5 -0
- package/dist/document-schema.d.ts +17 -5
- package/dist/domain.d.ts +14 -2
- package/dist/durable.js +5 -5
- package/dist/index.js +4 -4
- package/dist/pi.js +33 -14
- package/dist/providers/contract.d.ts +11 -1
- package/dist/providers/registry.d.ts +1 -0
- package/dist/providers/sofya/adapter.d.ts +8 -0
- package/dist/providers/sofya/definition.d.ts +1 -0
- package/dist/providers/sofya/types.d.ts +4 -0
- package/dist/render.d.ts +8 -2
- package/docs/provider.md +27 -0
- package/examples/custom/README.md +9 -3
- package/package.json +1 -1
- package/dist/chunk-BTWECET5.js +0 -31
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
executeAsyncResearch
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-LDVDVA4Z.js";
|
|
4
4
|
import "./chunk-I2UIACY3.js";
|
|
5
5
|
import "./chunk-WCTOYZVB.js";
|
|
6
6
|
import {
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
} from "./chunk-FSTCLBSF.js";
|
|
13
13
|
import {
|
|
14
14
|
orderedContents
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-TYJ6RHKB.js";
|
|
16
16
|
import {
|
|
17
17
|
WebfoxError,
|
|
18
18
|
asWebfoxError
|
|
@@ -54,13 +54,10 @@ var linkupImplementation = {
|
|
|
54
54
|
].includes(key) && value !== void 0
|
|
55
55
|
)
|
|
56
56
|
);
|
|
57
|
-
return
|
|
57
|
+
return {
|
|
58
58
|
url,
|
|
59
|
-
content: response.markdown,
|
|
59
|
+
...response.markdown ? { content: response.markdown } : {},
|
|
60
60
|
...Object.keys(metadata).length ? { metadata } : {}
|
|
61
|
-
} : {
|
|
62
|
-
url,
|
|
63
|
-
error: "No content returned for this URL."
|
|
64
61
|
};
|
|
65
62
|
} catch (error) {
|
|
66
63
|
return {
|
|
@@ -251,37 +248,17 @@ function linkupError(response, payload) {
|
|
|
251
248
|
}
|
|
252
249
|
function formatResearchTaskOutput(task) {
|
|
253
250
|
const output = task.output;
|
|
254
|
-
if (
|
|
251
|
+
if (output == null) return { provider: "linkup", text: "" };
|
|
252
|
+
if (typeof output === "string") return { provider: "linkup", text: output };
|
|
253
|
+
const outputType = readString(asRecord(task.input)?.outputType);
|
|
254
|
+
const record = asRecord(output);
|
|
255
|
+
if (outputType !== "structured" && record && ("answer" in record || "sources" in record))
|
|
255
256
|
return {
|
|
256
257
|
provider: "linkup",
|
|
257
|
-
text:
|
|
258
|
+
text: readString(record.answer) ?? "",
|
|
259
|
+
sources: readSources(record.sources)
|
|
258
260
|
};
|
|
259
|
-
}
|
|
260
|
-
const outputRecord = asRecord(output);
|
|
261
|
-
const inputRecord = asRecord(task.input);
|
|
262
|
-
const outputType = inputRecord ? readString(inputRecord.outputType) : void 0;
|
|
263
|
-
const answer = outputRecord ? readString(outputRecord.answer) : void 0;
|
|
264
|
-
const sources = outputRecord ? readSources(outputRecord.sources) : [];
|
|
265
|
-
if (outputType !== "structured" && answer !== void 0) {
|
|
266
|
-
const lines = [answer];
|
|
267
|
-
if (sources.length > 0) {
|
|
268
|
-
lines.push("");
|
|
269
|
-
lines.push("Sources:");
|
|
270
|
-
for (const [index, source] of sources.entries()) {
|
|
271
|
-
lines.push(`${index + 1}. ${source.title}`);
|
|
272
|
-
lines.push(` ${source.url}`);
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
return {
|
|
276
|
-
provider: "linkup",
|
|
277
|
-
text: lines.join("\n").trimEnd(),
|
|
278
|
-
itemCount: sources.length
|
|
279
|
-
};
|
|
280
|
-
}
|
|
281
|
-
return {
|
|
282
|
-
provider: "linkup",
|
|
283
|
-
text: formatJson(output)
|
|
284
|
-
};
|
|
261
|
+
return { provider: "linkup", text: formatJson(output) };
|
|
285
262
|
}
|
|
286
263
|
function toSearchResult(value) {
|
|
287
264
|
const entry = asRecord(value);
|
|
@@ -289,7 +266,7 @@ function toSearchResult(value) {
|
|
|
289
266
|
return null;
|
|
290
267
|
}
|
|
291
268
|
const url = readString(entry.url) ?? "";
|
|
292
|
-
const title = readString(entry.name)
|
|
269
|
+
const title = readString(entry.name);
|
|
293
270
|
const type = readString(entry.type);
|
|
294
271
|
const favicon = readString(entry.favicon);
|
|
295
272
|
const snippet = type === "text" ? trimSnippet(readString(entry.content) ?? "") : "";
|
|
@@ -319,7 +296,7 @@ function readSources(value) {
|
|
|
319
296
|
}
|
|
320
297
|
return [
|
|
321
298
|
{
|
|
322
|
-
title: readString(source.name)
|
|
299
|
+
title: readString(source.name),
|
|
323
300
|
url
|
|
324
301
|
}
|
|
325
302
|
];
|
|
@@ -74,7 +74,7 @@ function toSearchResult(entry) {
|
|
|
74
74
|
const { title, url: _url, description, snippet, ...metadata } = record;
|
|
75
75
|
const excerpt = text(snippet) ?? text(description);
|
|
76
76
|
return {
|
|
77
|
-
title: text(title)
|
|
77
|
+
title: text(title),
|
|
78
78
|
url,
|
|
79
79
|
snippet: excerpt ? trimSnippet(excerpt) : "",
|
|
80
80
|
...Object.keys(metadata).length > 0 ? { metadata } : {}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
executeAsyncResearch
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-LDVDVA4Z.js";
|
|
4
4
|
import "./chunk-I2UIACY3.js";
|
|
5
5
|
import "./chunk-WCTOYZVB.js";
|
|
6
6
|
import {
|
|
@@ -29,24 +29,12 @@ var geminiImplementation = {
|
|
|
29
29
|
const text = Array.isArray(parts) ? parts.filter(
|
|
30
30
|
(part) => isPlainObject(part) && !part.thought && typeof part.text === "string"
|
|
31
31
|
).map((part) => part.text).join("").trim() : "";
|
|
32
|
-
const lines = [text || "No answer returned."];
|
|
33
|
-
const sources = extractGroundingSources(
|
|
34
|
-
asRecord(candidate.groundingMetadata).groundingChunks
|
|
35
|
-
);
|
|
36
|
-
if (sources.length > 0) {
|
|
37
|
-
lines.push("");
|
|
38
|
-
lines.push("Sources:");
|
|
39
|
-
for (const [index, source] of sources.entries()) {
|
|
40
|
-
lines.push(`${index + 1}. ${source.title}`);
|
|
41
|
-
if (source.url) {
|
|
42
|
-
lines.push(` ${source.url}`);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
32
|
return {
|
|
47
33
|
provider: "gemini",
|
|
48
|
-
text
|
|
49
|
-
|
|
34
|
+
text,
|
|
35
|
+
sources: extractGroundingSources(
|
|
36
|
+
asRecord(candidate.groundingMetadata).groundingChunks
|
|
37
|
+
)
|
|
50
38
|
};
|
|
51
39
|
},
|
|
52
40
|
async research(input, config, context, options) {
|
|
@@ -91,7 +79,7 @@ var geminiImplementation = {
|
|
|
91
79
|
status: "completed",
|
|
92
80
|
output: {
|
|
93
81
|
provider: "gemini",
|
|
94
|
-
text
|
|
82
|
+
text
|
|
95
83
|
}
|
|
96
84
|
};
|
|
97
85
|
}
|
|
@@ -165,33 +153,18 @@ function readInteractionSteps(interaction) {
|
|
|
165
153
|
return typeof interaction === "object" && interaction !== null ? interaction.steps : void 0;
|
|
166
154
|
}
|
|
167
155
|
function extractGroundingSources(chunks) {
|
|
156
|
+
if (!Array.isArray(chunks)) return [];
|
|
168
157
|
const seen = /* @__PURE__ */ new Set();
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
if (!web) continue;
|
|
177
|
-
const rawUrl = typeof web.uri === "string" ? web.uri : "";
|
|
178
|
-
const title = formatGroundingSourceTitle(
|
|
179
|
-
typeof web.title === "string" ? web.title : rawUrl,
|
|
180
|
-
rawUrl
|
|
181
|
-
);
|
|
182
|
-
const url = formatGroundingSourceUrl(rawUrl);
|
|
183
|
-
const key = [title.toLowerCase(), url.toLowerCase()].join("::");
|
|
184
|
-
if (seen.has(key)) continue;
|
|
158
|
+
return chunks.flatMap((chunk) => {
|
|
159
|
+
const web = asRecord(asRecord(chunk).web);
|
|
160
|
+
const title = typeof web.title === "string" ? web.title : void 0;
|
|
161
|
+
const uri = typeof web.uri === "string" ? web.uri : void 0;
|
|
162
|
+
const url = uri && !isGoogleGroundingRedirect(uri) ? uri : void 0;
|
|
163
|
+
const key = `${title?.toLowerCase() ?? ""}::${url?.toLowerCase() ?? ""}`;
|
|
164
|
+
if (seen.has(key)) return [];
|
|
185
165
|
seen.add(key);
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
url
|
|
189
|
-
});
|
|
190
|
-
if (sources.length >= maxSources) {
|
|
191
|
-
break;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
return sources;
|
|
166
|
+
return [{ title, url }];
|
|
167
|
+
});
|
|
195
168
|
}
|
|
196
169
|
function formatInteractionSteps(steps) {
|
|
197
170
|
const lines = [];
|
|
@@ -213,29 +186,6 @@ function formatInteractionSteps(steps) {
|
|
|
213
186
|
}
|
|
214
187
|
return lines.join("\n\n").trim();
|
|
215
188
|
}
|
|
216
|
-
function formatGroundingSourceTitle(title, url) {
|
|
217
|
-
const trimmedTitle = title?.trim();
|
|
218
|
-
if (trimmedTitle) {
|
|
219
|
-
return trimmedTitle;
|
|
220
|
-
}
|
|
221
|
-
if (url) {
|
|
222
|
-
try {
|
|
223
|
-
return new URL(url).hostname;
|
|
224
|
-
} catch {
|
|
225
|
-
return url;
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
return "Untitled";
|
|
229
|
-
}
|
|
230
|
-
function formatGroundingSourceUrl(url) {
|
|
231
|
-
if (!url) {
|
|
232
|
-
return "";
|
|
233
|
-
}
|
|
234
|
-
if (isGoogleGroundingRedirect(url)) {
|
|
235
|
-
return "";
|
|
236
|
-
}
|
|
237
|
-
return url;
|
|
238
|
-
}
|
|
239
189
|
function isGoogleGroundingRedirect(url) {
|
|
240
190
|
try {
|
|
241
191
|
const parsed = new URL(url);
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
} from "./chunk-FSTCLBSF.js";
|
|
7
7
|
import {
|
|
8
8
|
orderedContents
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-TYJ6RHKB.js";
|
|
10
10
|
import {
|
|
11
11
|
WebfoxError,
|
|
12
12
|
asWebfoxError
|
|
@@ -56,15 +56,12 @@ var firecrawlImplementation = {
|
|
|
56
56
|
);
|
|
57
57
|
const document = asRecord(response.data) ?? {};
|
|
58
58
|
const content = getDocumentContent(document);
|
|
59
|
-
return
|
|
59
|
+
return {
|
|
60
60
|
url,
|
|
61
|
-
content,
|
|
61
|
+
...content ? { content } : {},
|
|
62
62
|
...asRecord(document.metadata) ? {
|
|
63
63
|
metadata: document.metadata
|
|
64
64
|
} : {}
|
|
65
|
-
} : {
|
|
66
|
-
url,
|
|
67
|
-
error: "No content returned for this URL."
|
|
68
65
|
};
|
|
69
66
|
} catch (error) {
|
|
70
67
|
return {
|
|
@@ -92,14 +89,10 @@ var firecrawlImplementation = {
|
|
|
92
89
|
context.signal
|
|
93
90
|
);
|
|
94
91
|
const document = getFirecrawlDocument(response);
|
|
95
|
-
const answer = readString(document.answer);
|
|
96
|
-
if (!answer?.trim()) {
|
|
97
|
-
throw new Error("No answer returned for this URL.");
|
|
98
|
-
}
|
|
99
92
|
return {
|
|
100
93
|
provider: "firecrawl",
|
|
101
|
-
text: answer
|
|
102
|
-
|
|
94
|
+
text: readString(document.answer) ?? "",
|
|
95
|
+
sources: [{ url }],
|
|
103
96
|
metadata: {
|
|
104
97
|
url,
|
|
105
98
|
...asRecord(document.metadata) ? { metadata: document.metadata } : {}
|
|
@@ -209,7 +202,7 @@ function toSearchResult(source, value) {
|
|
|
209
202
|
}
|
|
210
203
|
const metadata = asRecord(entry.metadata);
|
|
211
204
|
const url = readString(entry.url) ?? readString(metadata?.sourceURL) ?? readString(entry.imageUrl) ?? "";
|
|
212
|
-
const title = readString(entry.title) ?? readString(metadata?.title)
|
|
205
|
+
const title = readString(entry.title) ?? readString(metadata?.title);
|
|
213
206
|
const snippet = trimSnippet(
|
|
214
207
|
readString(entry.description) ?? readString(entry.snippet) ?? readString(entry.markdown) ?? readString(metadata?.description) ?? ""
|
|
215
208
|
);
|
|
@@ -222,7 +215,7 @@ function toSearchResult(source, value) {
|
|
|
222
215
|
...metadata ?? {}
|
|
223
216
|
};
|
|
224
217
|
return {
|
|
225
|
-
title
|
|
218
|
+
title,
|
|
226
219
|
url,
|
|
227
220
|
snippet,
|
|
228
221
|
metadata: Object.keys(resultMetadata).length > 1 ? resultMetadata : void 0
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from "./chunk-ZVTVERW5.js";
|
|
5
5
|
import {
|
|
6
6
|
WEBFOX_ERROR_CODES
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-NENL6L6N.js";
|
|
8
8
|
import {
|
|
9
9
|
WebfoxError
|
|
10
10
|
} from "./chunk-U4BLULLV.js";
|
|
@@ -145,7 +145,7 @@ var adapter = {
|
|
|
145
145
|
results: output.results.map((entry) => {
|
|
146
146
|
const result = object(entry, "Search results must be objects.");
|
|
147
147
|
return {
|
|
148
|
-
title: string(result.title, "title"),
|
|
148
|
+
...result.title === void 0 ? {} : { title: string(result.title, "title") },
|
|
149
149
|
url: string(result.url, "url"),
|
|
150
150
|
snippet: string(result.snippet, "snippet"),
|
|
151
151
|
...typeof result.score === "number" ? { score: result.score } : {},
|
|
@@ -169,8 +169,6 @@ var adapter = {
|
|
|
169
169
|
"Every custom contents answer requires inputIndex (the zero-based requested URL index)."
|
|
170
170
|
);
|
|
171
171
|
const error = answer.error === void 0 ? void 0 : parseError(answer.error);
|
|
172
|
-
if (answer.content === void 0 && answer.summary === void 0 && error === void 0)
|
|
173
|
-
invalid("Contents answers require content, summary, or error.");
|
|
174
172
|
return {
|
|
175
173
|
inputIndex: answer.inputIndex,
|
|
176
174
|
url: string(answer.url, "url"),
|
|
@@ -195,10 +193,20 @@ function textOutput(output) {
|
|
|
195
193
|
return {
|
|
196
194
|
provider: "custom",
|
|
197
195
|
text: string(output.text, "text"),
|
|
198
|
-
...
|
|
196
|
+
...output.sources === void 0 ? {} : { sources: parseSources(output.sources) },
|
|
199
197
|
...output.metadata ? { metadata: object(output.metadata, "metadata must be an object") } : {}
|
|
200
198
|
};
|
|
201
199
|
}
|
|
200
|
+
function parseSources(value) {
|
|
201
|
+
if (!Array.isArray(value)) invalid("Custom output sources must be an array.");
|
|
202
|
+
return value.map((entry) => {
|
|
203
|
+
const source = object(entry, "Custom output sources must be objects.");
|
|
204
|
+
return {
|
|
205
|
+
...source.url === void 0 ? {} : { url: string(source.url, "sources[].url") },
|
|
206
|
+
...source.title === void 0 ? {} : { title: string(source.title, "sources[].title") }
|
|
207
|
+
};
|
|
208
|
+
});
|
|
209
|
+
}
|
|
202
210
|
function parseError(value) {
|
|
203
211
|
const error = object(
|
|
204
212
|
value,
|
|
@@ -2,11 +2,11 @@ import {
|
|
|
2
2
|
SERPBASE_MODES,
|
|
3
3
|
serpbaseProvider,
|
|
4
4
|
validateOptions
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-PVNWACMT.js";
|
|
6
6
|
import {
|
|
7
7
|
trimSnippet
|
|
8
8
|
} from "./chunk-FSTCLBSF.js";
|
|
9
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-NENL6L6N.js";
|
|
10
10
|
import {
|
|
11
11
|
WebfoxError,
|
|
12
12
|
httpError
|
|
@@ -100,7 +100,7 @@ function toSearchResult(entry, searchContext, mode) {
|
|
|
100
100
|
if (!url) return void 0;
|
|
101
101
|
const { title, link: _link, url: _url, snippet, ...metadata } = record;
|
|
102
102
|
return {
|
|
103
|
-
title: text(title) ?? text(record.name)
|
|
103
|
+
title: text(title) ?? text(record.name),
|
|
104
104
|
url,
|
|
105
105
|
snippet: resultSnippet(record, mode),
|
|
106
106
|
metadata: { ...metadata, mode, searchContext }
|
|
@@ -161,7 +161,7 @@ async function web(query, maxResults, config, context, key, options) {
|
|
|
161
161
|
const x = obj(e);
|
|
162
162
|
const u = str(x.url) ?? "";
|
|
163
163
|
return {
|
|
164
|
-
title: str(x.title)
|
|
164
|
+
title: str(x.title),
|
|
165
165
|
url: u,
|
|
166
166
|
snippet: trimSnippet(
|
|
167
167
|
str(x.description) ?? arr(x.extra_snippets).join(" ")
|
|
@@ -211,7 +211,7 @@ async function llmContext(query, maxResults, config, context, key, options) {
|
|
|
211
211
|
const source = obj(x.source);
|
|
212
212
|
const u = str(x.url) ?? str(source.url) ?? "";
|
|
213
213
|
return {
|
|
214
|
-
title: str(x.title) ?? str(x.name) ?? str(source.title)
|
|
214
|
+
title: str(x.title) ?? str(x.name) ?? str(source.title),
|
|
215
215
|
url: u,
|
|
216
216
|
snippet: trimSnippet(snippets.join("\n\n"), 1200),
|
|
217
217
|
metadata: x
|
|
@@ -258,7 +258,7 @@ async function news(query, maxResults, config, context, key, options) {
|
|
|
258
258
|
const u = str(x.url) ?? "";
|
|
259
259
|
const source = str(x.source) ?? str(x.source_name);
|
|
260
260
|
return {
|
|
261
|
-
title: str(x.title)
|
|
261
|
+
title: str(x.title),
|
|
262
262
|
url: u,
|
|
263
263
|
snippet: trimSnippet(
|
|
264
264
|
[
|
|
@@ -300,7 +300,7 @@ async function videos(query, maxResults, config, context, key, options) {
|
|
|
300
300
|
const u = str(x.url) ?? "";
|
|
301
301
|
const video = obj(x.video);
|
|
302
302
|
return {
|
|
303
|
-
title: str(x.title)
|
|
303
|
+
title: str(x.title),
|
|
304
304
|
url: u,
|
|
305
305
|
snippet: trimSnippet(
|
|
306
306
|
[
|
|
@@ -343,7 +343,7 @@ async function images(query, maxResults, config, context, key, options) {
|
|
|
343
343
|
const page = str(x.url) ?? str(x.source) ?? str(props.url) ?? "";
|
|
344
344
|
const image = str(props.url);
|
|
345
345
|
return {
|
|
346
|
-
title: str(x.title)
|
|
346
|
+
title: str(x.title),
|
|
347
347
|
url: page || image || "",
|
|
348
348
|
snippet: trimSnippet(
|
|
349
349
|
[str(x.description), str(x.publisher), image].filter(Boolean).join(" \u2014 ")
|
|
@@ -400,7 +400,7 @@ async function places(query, maxResults, config, context, key, options) {
|
|
|
400
400
|
const description = id ? descriptionsById.get(id) : void 0;
|
|
401
401
|
const u = str(x.url) ?? str(x.provider_url) ?? "";
|
|
402
402
|
return {
|
|
403
|
-
title: str(x.title)
|
|
403
|
+
title: str(x.title),
|
|
404
404
|
url: u,
|
|
405
405
|
snippet: trimSnippet(
|
|
406
406
|
[
|
|
@@ -537,19 +537,11 @@ async function completion(input, config, context, request) {
|
|
|
537
537
|
if (!r.ok) throw await httpError2(r);
|
|
538
538
|
const text = await r.text();
|
|
539
539
|
const parsed = body.stream === false ? parseAnswerJson(text) : parseAnswerStream(text);
|
|
540
|
-
const lines = [parsed.answer.trim() || text.trim()];
|
|
541
|
-
if (parsed.citations.length) {
|
|
542
|
-
lines.push("", "Sources:");
|
|
543
|
-
parsed.citations.forEach((c, i) => {
|
|
544
|
-
lines.push(`${i + 1}. ${c.title ?? c.url ?? "Source"}`);
|
|
545
|
-
if (c.url) lines.push(` ${c.url}`);
|
|
546
|
-
});
|
|
547
|
-
}
|
|
548
540
|
const metadata = buildAnswerMetadata(parsed);
|
|
549
541
|
return {
|
|
550
542
|
provider: "brave",
|
|
551
|
-
text:
|
|
552
|
-
|
|
543
|
+
text: parsed.answer,
|
|
544
|
+
sources: parsed.citations,
|
|
553
545
|
...metadata ? { metadata } : {}
|
|
554
546
|
};
|
|
555
547
|
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// src/render.ts
|
|
2
|
+
function emptyResultText(capability) {
|
|
3
|
+
switch (capability) {
|
|
4
|
+
case "search":
|
|
5
|
+
return "No results found.";
|
|
6
|
+
case "contents":
|
|
7
|
+
return "No content returned.";
|
|
8
|
+
case "answer":
|
|
9
|
+
return "No answer returned.";
|
|
10
|
+
case "research":
|
|
11
|
+
return "No report returned.";
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
function resultLabel(result) {
|
|
15
|
+
return result.title ?? ("url" in result ? result.url : "");
|
|
16
|
+
}
|
|
17
|
+
function renderTextDocument(document, { includeErrors = true } = {}) {
|
|
18
|
+
return document.results.map((entry, index) => {
|
|
19
|
+
const heading = document.results.length > 1 ? `## ${index + 1}. ${entry.input}` : "";
|
|
20
|
+
if (!entry.ok)
|
|
21
|
+
return includeErrors ? [heading, `Error: ${entry.error.message}`].filter(Boolean).join("\n\n") : void 0;
|
|
22
|
+
let body;
|
|
23
|
+
if ("results" in entry.value)
|
|
24
|
+
body = renderSearch(entry.value.results, document.capability);
|
|
25
|
+
else if ("text" in entry.value)
|
|
26
|
+
body = renderText(entry.value, document.capability);
|
|
27
|
+
else body = renderContents(entry.value, document.capability);
|
|
28
|
+
return [heading, body].filter(Boolean).join("\n\n");
|
|
29
|
+
}).filter((part) => part !== void 0).join("\n\n");
|
|
30
|
+
}
|
|
31
|
+
function renderSearch(results, capability) {
|
|
32
|
+
if (!results.length) return emptyResultText(capability);
|
|
33
|
+
return results.map(
|
|
34
|
+
(result, i) => [
|
|
35
|
+
`${i + 1}. ${resultLabel(result)}`,
|
|
36
|
+
result.title === void 0 ? void 0 : ` ${result.url}`,
|
|
37
|
+
result.snippet.trim() ? ` ${result.snippet.replaceAll("\n", "\n ")}` : void 0
|
|
38
|
+
].filter((line) => line !== void 0).join("\n")
|
|
39
|
+
).join("\n\n");
|
|
40
|
+
}
|
|
41
|
+
function renderText(answer, capability) {
|
|
42
|
+
const lines = [
|
|
43
|
+
answer.text.trim() ? answer.text : emptyResultText(capability)
|
|
44
|
+
];
|
|
45
|
+
if (answer.sources?.length) {
|
|
46
|
+
lines.push("", "Sources:");
|
|
47
|
+
for (const [index, source] of answer.sources.entries()) {
|
|
48
|
+
lines.push(`${index + 1}. ${resultLabel(source)}`);
|
|
49
|
+
if ("url" in source && source.title && source.title !== source.url)
|
|
50
|
+
lines.push(` ${source.url}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return lines.join("\n");
|
|
54
|
+
}
|
|
55
|
+
function renderContents(answer, capability) {
|
|
56
|
+
const content = answer.content?.trim() ? answer.content : void 0;
|
|
57
|
+
const summary = typeof answer.summary === "string" ? answer.summary.trim() ? answer.summary : void 0 : answer.summary == null ? void 0 : JSON.stringify(answer.summary, null, 2);
|
|
58
|
+
return [
|
|
59
|
+
`## ${answer.url}`,
|
|
60
|
+
content,
|
|
61
|
+
summary === void 0 ? void 0 : `### Summary
|
|
62
|
+
|
|
63
|
+
${summary}`,
|
|
64
|
+
content === void 0 && summary === void 0 ? emptyResultText(capability) : void 0
|
|
65
|
+
].filter((part) => part !== void 0).join("\n\n");
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export {
|
|
69
|
+
emptyResultText,
|
|
70
|
+
renderTextDocument
|
|
71
|
+
};
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
optionSchema,
|
|
3
3
|
providers
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-PVNWACMT.js";
|
|
5
5
|
import {
|
|
6
6
|
CAPABILITIES
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-NENL6L6N.js";
|
|
8
8
|
|
|
9
9
|
// package.json
|
|
10
10
|
var package_default = {
|
|
11
11
|
name: "webfox",
|
|
12
|
-
version: "4.
|
|
12
|
+
version: "4.11.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: [
|
|
@@ -56,10 +56,7 @@ async function executeAsyncResearch({
|
|
|
56
56
|
continue;
|
|
57
57
|
}
|
|
58
58
|
if (result.status === "completed")
|
|
59
|
-
return result.output ?? {
|
|
60
|
-
provider: providerId,
|
|
61
|
-
text: `${providerLabel} research completed without textual output.`
|
|
62
|
-
};
|
|
59
|
+
return result.output ?? { provider: providerId, text: "" };
|
|
63
60
|
if (result.status === "failed" || result.status === "cancelled")
|
|
64
61
|
throw new WebfoxError(
|
|
65
62
|
result.status === "cancelled" ? "CANCELLED" : "PROVIDER_FAILURE",
|