webfox 4.5.0 → 4.6.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/dist/{chunk-VI3473TU.js → chunk-5TNPVBAZ.js} +6 -6
- package/dist/{chunk-D4HCJRBE.js → chunk-QXTTUDLI.js} +1 -1
- package/dist/cli.js +2 -2
- package/dist/document-schema.d.ts +114 -0
- package/dist/index.js +2 -2
- package/dist/pi.js +108 -21
- package/docs/reference.md +7 -0
- package/package.json +6 -6
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
// package.json
|
|
10
10
|
var package_default = {
|
|
11
11
|
name: "webfox",
|
|
12
|
-
version: "4.
|
|
12
|
+
version: "4.6.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: [
|
|
@@ -107,15 +107,14 @@ var package_default = {
|
|
|
107
107
|
openai: "^7.10.0",
|
|
108
108
|
"parallel-web": "^1.3.3",
|
|
109
109
|
picocolors: "^1.1.1",
|
|
110
|
-
typebox: "^1.3.6",
|
|
111
110
|
"valyu-js": "^2.10.1",
|
|
112
111
|
yaml: "^2.9.0"
|
|
113
112
|
},
|
|
114
113
|
devDependencies: {
|
|
115
114
|
"@biomejs/biome": "^2.5.4",
|
|
116
|
-
"@earendil-works/pi-ai": "^0.
|
|
117
|
-
"@earendil-works/pi-coding-agent": "^0.
|
|
118
|
-
"@earendil-works/pi-tui": "^0.
|
|
115
|
+
"@earendil-works/pi-ai": "^0.99.0",
|
|
116
|
+
"@earendil-works/pi-coding-agent": "^0.99.0",
|
|
117
|
+
"@earendil-works/pi-tui": "^0.99.0",
|
|
119
118
|
"@types/node": "^26.1.1",
|
|
120
119
|
esbuild: "^0.28.1",
|
|
121
120
|
typescript: "^7.0.2",
|
|
@@ -123,7 +122,8 @@ var package_default = {
|
|
|
123
122
|
},
|
|
124
123
|
peerDependencies: {
|
|
125
124
|
"@earendil-works/pi-coding-agent": "*",
|
|
126
|
-
"@earendil-works/pi-tui": "*"
|
|
125
|
+
"@earendil-works/pi-tui": "*",
|
|
126
|
+
typebox: "*"
|
|
127
127
|
},
|
|
128
128
|
peerDependenciesMeta: {
|
|
129
129
|
"@earendil-works/pi-coding-agent": {
|
package/dist/cli.js
CHANGED
|
@@ -11,11 +11,11 @@ import {
|
|
|
11
11
|
redactConfig,
|
|
12
12
|
resolveConfigPath,
|
|
13
13
|
setCapabilityDefault
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-QXTTUDLI.js";
|
|
15
15
|
import "./chunk-WCTOYZVB.js";
|
|
16
16
|
import {
|
|
17
17
|
PACKAGE_VERSION
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-5TNPVBAZ.js";
|
|
19
19
|
import {
|
|
20
20
|
validateConfiguredOptions
|
|
21
21
|
} from "./chunk-KH54YH7D.js";
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { Type, type Static } from "typebox";
|
|
2
|
+
import { type AnswerDocument, type ContentsDocument, type ResearchDocument, type SearchDocument } from "./domain.js";
|
|
3
|
+
/**
|
|
4
|
+
* JSON Schema of each capability's result document. This is the document the
|
|
5
|
+
* CLI prints with `--format json` and the library returns.
|
|
6
|
+
*/
|
|
7
|
+
export declare const DOCUMENT_SCHEMAS: {
|
|
8
|
+
readonly search: Type.TObject<{
|
|
9
|
+
schemaVersion: Type.TLiteral<1>;
|
|
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"]>;
|
|
12
|
+
status: Type.TEnum<["ok", "partial"]>;
|
|
13
|
+
results: Type.TArray<Type.TUnion<[Type.TObject<{
|
|
14
|
+
input: Type.TString;
|
|
15
|
+
ok: Type.TLiteral<true>;
|
|
16
|
+
value: Type.TObject<{
|
|
17
|
+
results: Type.TArray<Type.TObject<{
|
|
18
|
+
title: Type.TString;
|
|
19
|
+
url: Type.TString;
|
|
20
|
+
snippet: Type.TString;
|
|
21
|
+
score: Type.TOptional<Type.TNumber>;
|
|
22
|
+
metadata: Type.TOptional<Type.TRecord<"^.*$", Type.TUnknown>>;
|
|
23
|
+
}>>;
|
|
24
|
+
}>;
|
|
25
|
+
}>, Type.TObject<{
|
|
26
|
+
input: Type.TString;
|
|
27
|
+
ok: Type.TLiteral<false>;
|
|
28
|
+
error: Type.TObject<{
|
|
29
|
+
code: Type.TEnum<["INVALID_CONFIG", "INVALID_INPUT", "PROVIDER_UNAVAILABLE", "PROVIDER_FAILURE", "PARTIAL_BATCH", "TIMEOUT", "CANCELLED"]>;
|
|
30
|
+
message: Type.TString;
|
|
31
|
+
retryable: Type.TOptional<Type.TBoolean>;
|
|
32
|
+
}>;
|
|
33
|
+
}>]>>;
|
|
34
|
+
}>;
|
|
35
|
+
readonly contents: Type.TObject<{
|
|
36
|
+
schemaVersion: Type.TLiteral<1>;
|
|
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"]>;
|
|
39
|
+
status: Type.TEnum<["ok", "partial"]>;
|
|
40
|
+
results: Type.TArray<Type.TUnion<[Type.TObject<{
|
|
41
|
+
input: Type.TString;
|
|
42
|
+
ok: Type.TLiteral<true>;
|
|
43
|
+
value: Type.TObject<{
|
|
44
|
+
url: Type.TString;
|
|
45
|
+
content: Type.TOptional<Type.TString>;
|
|
46
|
+
summary: Type.TOptional<Type.TUnknown>;
|
|
47
|
+
metadata: Type.TOptional<Type.TRecord<"^.*$", Type.TUnknown>>;
|
|
48
|
+
}>;
|
|
49
|
+
}>, Type.TObject<{
|
|
50
|
+
input: Type.TString;
|
|
51
|
+
ok: Type.TLiteral<false>;
|
|
52
|
+
error: Type.TObject<{
|
|
53
|
+
code: Type.TEnum<["INVALID_CONFIG", "INVALID_INPUT", "PROVIDER_UNAVAILABLE", "PROVIDER_FAILURE", "PARTIAL_BATCH", "TIMEOUT", "CANCELLED"]>;
|
|
54
|
+
message: Type.TString;
|
|
55
|
+
retryable: Type.TOptional<Type.TBoolean>;
|
|
56
|
+
}>;
|
|
57
|
+
}>]>>;
|
|
58
|
+
}>;
|
|
59
|
+
readonly answer: Type.TObject<{
|
|
60
|
+
schemaVersion: Type.TLiteral<1>;
|
|
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"]>;
|
|
63
|
+
status: Type.TEnum<["ok", "partial"]>;
|
|
64
|
+
results: Type.TArray<Type.TUnion<[Type.TObject<{
|
|
65
|
+
input: Type.TString;
|
|
66
|
+
ok: Type.TLiteral<true>;
|
|
67
|
+
value: Type.TObject<{
|
|
68
|
+
text: Type.TString;
|
|
69
|
+
itemCount: Type.TOptional<Type.TInteger>;
|
|
70
|
+
metadata: Type.TOptional<Type.TRecord<"^.*$", Type.TUnknown>>;
|
|
71
|
+
}>;
|
|
72
|
+
}>, Type.TObject<{
|
|
73
|
+
input: Type.TString;
|
|
74
|
+
ok: Type.TLiteral<false>;
|
|
75
|
+
error: Type.TObject<{
|
|
76
|
+
code: Type.TEnum<["INVALID_CONFIG", "INVALID_INPUT", "PROVIDER_UNAVAILABLE", "PROVIDER_FAILURE", "PARTIAL_BATCH", "TIMEOUT", "CANCELLED"]>;
|
|
77
|
+
message: Type.TString;
|
|
78
|
+
retryable: Type.TOptional<Type.TBoolean>;
|
|
79
|
+
}>;
|
|
80
|
+
}>]>>;
|
|
81
|
+
}>;
|
|
82
|
+
readonly research: Type.TObject<{
|
|
83
|
+
schemaVersion: Type.TLiteral<1>;
|
|
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"]>;
|
|
86
|
+
status: Type.TEnum<["ok", "partial"]>;
|
|
87
|
+
results: Type.TArray<Type.TUnion<[Type.TObject<{
|
|
88
|
+
input: Type.TString;
|
|
89
|
+
ok: Type.TLiteral<true>;
|
|
90
|
+
value: Type.TObject<{
|
|
91
|
+
text: Type.TString;
|
|
92
|
+
itemCount: Type.TOptional<Type.TInteger>;
|
|
93
|
+
metadata: Type.TOptional<Type.TRecord<"^.*$", Type.TUnknown>>;
|
|
94
|
+
}>;
|
|
95
|
+
}>, Type.TObject<{
|
|
96
|
+
input: Type.TString;
|
|
97
|
+
ok: Type.TLiteral<false>;
|
|
98
|
+
error: Type.TObject<{
|
|
99
|
+
code: Type.TEnum<["INVALID_CONFIG", "INVALID_INPUT", "PROVIDER_UNAVAILABLE", "PROVIDER_FAILURE", "PARTIAL_BATCH", "TIMEOUT", "CANCELLED"]>;
|
|
100
|
+
message: Type.TString;
|
|
101
|
+
retryable: Type.TOptional<Type.TBoolean>;
|
|
102
|
+
}>;
|
|
103
|
+
}>]>>;
|
|
104
|
+
}>;
|
|
105
|
+
};
|
|
106
|
+
type Same<A, B> = [A] extends [B] ? ([B] extends [A] ? true : false) : false;
|
|
107
|
+
type Assert<T extends true> = T;
|
|
108
|
+
export type DocumentSchemaMatchesDomain = [
|
|
109
|
+
Assert<Same<Static<typeof DOCUMENT_SCHEMAS.search>, SearchDocument>>,
|
|
110
|
+
Assert<Same<Static<typeof DOCUMENT_SCHEMAS.contents>, ContentsDocument>>,
|
|
111
|
+
Assert<Same<Static<typeof DOCUMENT_SCHEMAS.answer>, AnswerDocument>>,
|
|
112
|
+
Assert<Same<Static<typeof DOCUMENT_SCHEMAS.research>, ResearchDocument>>
|
|
113
|
+
];
|
|
114
|
+
export {};
|
package/dist/index.js
CHANGED
|
@@ -6,11 +6,11 @@ import {
|
|
|
6
6
|
resolveConfigPath,
|
|
7
7
|
setCapabilityDefault,
|
|
8
8
|
validateConfig
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-QXTTUDLI.js";
|
|
10
10
|
import "./chunk-WCTOYZVB.js";
|
|
11
11
|
import {
|
|
12
12
|
CONFIG_SCHEMA_URL
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-5TNPVBAZ.js";
|
|
14
14
|
import {
|
|
15
15
|
validateConfiguredOptions
|
|
16
16
|
} from "./chunk-KH54YH7D.js";
|
package/dist/pi.js
CHANGED
|
@@ -4,13 +4,15 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
createWebfox,
|
|
6
6
|
resolveConfigPath
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-QXTTUDLI.js";
|
|
8
8
|
import "./chunk-WCTOYZVB.js";
|
|
9
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-5TNPVBAZ.js";
|
|
10
10
|
import "./chunk-KH54YH7D.js";
|
|
11
11
|
import "./chunk-ZVTVERW5.js";
|
|
12
12
|
import {
|
|
13
|
-
CAPABILITIES
|
|
13
|
+
CAPABILITIES,
|
|
14
|
+
PROVIDER_IDS,
|
|
15
|
+
WEBFOX_ERROR_CODES
|
|
14
16
|
} from "./chunk-GPACLYNT.js";
|
|
15
17
|
import {
|
|
16
18
|
WebfoxError
|
|
@@ -24,7 +26,7 @@ import {
|
|
|
24
26
|
truncateHead,
|
|
25
27
|
withFileMutationQueue
|
|
26
28
|
} from "@earendil-works/pi-coding-agent";
|
|
27
|
-
import { Type } from "typebox";
|
|
29
|
+
import { Type as Type2 } from "typebox";
|
|
28
30
|
|
|
29
31
|
// src/pi-render.ts
|
|
30
32
|
import { stripVTControlCharacters as stripVTControlCharacters3 } from "node:util";
|
|
@@ -186,11 +188,11 @@ function link(url, theme) {
|
|
|
186
188
|
return label;
|
|
187
189
|
}
|
|
188
190
|
function renderSearchResult(details, fallback, theme) {
|
|
189
|
-
const
|
|
191
|
+
const document2 = isRecord2(details) && searchDocument(details.result) ? details.result : void 0;
|
|
190
192
|
return {
|
|
191
193
|
render(width) {
|
|
192
194
|
if (width <= 0) return [];
|
|
193
|
-
if (!
|
|
195
|
+
if (!document2) {
|
|
194
196
|
const text = plainText(fallback).split("\n").map((line) => {
|
|
195
197
|
const urlLine = /^(\s*)(https?:\/\/\S+)(\s*)$/.exec(line);
|
|
196
198
|
return urlLine ? urlLine[1] + link(urlLine[2], theme) + urlLine[3] : theme.fg("toolOutput", line);
|
|
@@ -209,9 +211,9 @@ function renderSearchResult(details, fallback, theme) {
|
|
|
209
211
|
)
|
|
210
212
|
);
|
|
211
213
|
};
|
|
212
|
-
|
|
214
|
+
document2.results.forEach((entry, index) => {
|
|
213
215
|
if (index) lines.push("");
|
|
214
|
-
if (
|
|
216
|
+
if (document2.results.length > 1) {
|
|
215
217
|
append(
|
|
216
218
|
theme.fg(
|
|
217
219
|
"mdHeading",
|
|
@@ -304,8 +306,8 @@ var WebCall = class {
|
|
|
304
306
|
};
|
|
305
307
|
function renderWebResult(result, options, theme, isError, capability) {
|
|
306
308
|
const text = result.content.filter((part) => part.type === "text").map((part) => part.text ?? "").join("\n");
|
|
307
|
-
const
|
|
308
|
-
const isSearch = (capability ??
|
|
309
|
+
const metadata2 = result.details;
|
|
310
|
+
const isSearch = (capability ?? metadata2?.capability ?? metadata2?.result?.capability) === "search";
|
|
309
311
|
const body = () => isSearch ? renderSearchResult(result.details, text, theme) : new Markdown(text, 0, 0, getMarkdownTheme());
|
|
310
312
|
const rows = statusRows(result.details);
|
|
311
313
|
if (rows?.length) {
|
|
@@ -435,6 +437,85 @@ function configurationDiagnostic(error) {
|
|
|
435
437
|
].join("\n");
|
|
436
438
|
}
|
|
437
439
|
|
|
440
|
+
// src/document-schema.ts
|
|
441
|
+
import { Type } from "typebox";
|
|
442
|
+
var closed = { additionalProperties: false };
|
|
443
|
+
var metadata = Type.Record(Type.String(), Type.Unknown(), {
|
|
444
|
+
description: "Provider-specific fields."
|
|
445
|
+
});
|
|
446
|
+
var searchResult = Type.Object(
|
|
447
|
+
{
|
|
448
|
+
title: Type.String(),
|
|
449
|
+
url: Type.String(),
|
|
450
|
+
snippet: Type.String(),
|
|
451
|
+
score: Type.Optional(Type.Number()),
|
|
452
|
+
metadata: Type.Optional(metadata)
|
|
453
|
+
},
|
|
454
|
+
closed
|
|
455
|
+
);
|
|
456
|
+
var contentsAnswer = Type.Object(
|
|
457
|
+
{
|
|
458
|
+
url: Type.String({ description: "Final URL after redirects." }),
|
|
459
|
+
content: Type.Optional(Type.String()),
|
|
460
|
+
summary: Type.Optional(Type.Unknown()),
|
|
461
|
+
metadata: Type.Optional(metadata)
|
|
462
|
+
},
|
|
463
|
+
closed
|
|
464
|
+
);
|
|
465
|
+
var textAnswer = Type.Object(
|
|
466
|
+
{
|
|
467
|
+
text: Type.String(),
|
|
468
|
+
itemCount: Type.Optional(Type.Integer()),
|
|
469
|
+
metadata: Type.Optional(metadata)
|
|
470
|
+
},
|
|
471
|
+
closed
|
|
472
|
+
);
|
|
473
|
+
var serializedError = Type.Object(
|
|
474
|
+
{
|
|
475
|
+
code: Type.Enum(WEBFOX_ERROR_CODES),
|
|
476
|
+
message: Type.String(),
|
|
477
|
+
retryable: Type.Optional(Type.Boolean())
|
|
478
|
+
},
|
|
479
|
+
closed
|
|
480
|
+
);
|
|
481
|
+
function inputResult(value) {
|
|
482
|
+
const input = Type.String({
|
|
483
|
+
description: "The query, URL, or brief this entry answers."
|
|
484
|
+
});
|
|
485
|
+
return Type.Union([
|
|
486
|
+
Type.Object({ input, ok: Type.Literal(true), value }, closed),
|
|
487
|
+
Type.Object(
|
|
488
|
+
{ input, ok: Type.Literal(false), error: serializedError },
|
|
489
|
+
closed
|
|
490
|
+
)
|
|
491
|
+
]);
|
|
492
|
+
}
|
|
493
|
+
function document(capability, value) {
|
|
494
|
+
return Type.Object(
|
|
495
|
+
{
|
|
496
|
+
schemaVersion: Type.Literal(1),
|
|
497
|
+
capability: Type.Literal(capability),
|
|
498
|
+
provider: Type.Enum(PROVIDER_IDS),
|
|
499
|
+
status: Type.Enum(["ok", "partial"], {
|
|
500
|
+
description: "`partial` when at least one input failed."
|
|
501
|
+
}),
|
|
502
|
+
results: Type.Array(inputResult(value), {
|
|
503
|
+
description: "One entry per input, in input order."
|
|
504
|
+
})
|
|
505
|
+
},
|
|
506
|
+
closed
|
|
507
|
+
);
|
|
508
|
+
}
|
|
509
|
+
var DOCUMENT_SCHEMAS = {
|
|
510
|
+
search: document(
|
|
511
|
+
"search",
|
|
512
|
+
Type.Object({ results: Type.Array(searchResult) }, closed)
|
|
513
|
+
),
|
|
514
|
+
contents: document("contents", contentsAnswer),
|
|
515
|
+
answer: document("answer", textAnswer),
|
|
516
|
+
research: document("research", textAnswer)
|
|
517
|
+
};
|
|
518
|
+
|
|
438
519
|
// src/pi.ts
|
|
439
520
|
function webExtension(pi) {
|
|
440
521
|
const clients = /* @__PURE__ */ new Map();
|
|
@@ -475,18 +556,18 @@ function webExtension(pi) {
|
|
|
475
556
|
for (const inspection of selected) {
|
|
476
557
|
const capability = inspection.capability;
|
|
477
558
|
const provider = inspection.provider;
|
|
478
|
-
const fields = capability === "contents" ? { urls:
|
|
479
|
-
queries:
|
|
559
|
+
const fields = capability === "contents" ? { urls: Type2.Array(Type2.String({ minLength: 1 }), { minItems: 1 }) } : capability === "research" ? { input: Type2.String({ minLength: 1 }) } : {
|
|
560
|
+
queries: Type2.Array(Type2.String({ minLength: 1 }), {
|
|
480
561
|
minItems: 1,
|
|
481
562
|
maxItems: 10
|
|
482
563
|
}),
|
|
483
|
-
...capability === "search" ? { maxResults:
|
|
564
|
+
...capability === "search" ? { maxResults: Type2.Optional(Type2.Integer({ minimum: 1 })) } : {}
|
|
484
565
|
};
|
|
485
|
-
const parameters =
|
|
566
|
+
const parameters = Type2.Object(
|
|
486
567
|
{
|
|
487
568
|
...fields,
|
|
488
569
|
...inspection.optionSchema ? {
|
|
489
|
-
options:
|
|
570
|
+
options: Type2.Optional(
|
|
490
571
|
inspection.optionSchema
|
|
491
572
|
)
|
|
492
573
|
} : {}
|
|
@@ -503,6 +584,12 @@ function webExtension(pi) {
|
|
|
503
584
|
"Output is truncated to 2000 lines or 50 KiB; full results are saved to a file when truncated."
|
|
504
585
|
].join("\n"),
|
|
505
586
|
parameters,
|
|
587
|
+
// Let permission extensions and tool loadouts treat web access as a
|
|
588
|
+
// read-only call that reaches the open web.
|
|
589
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
590
|
+
// Programmatic callers such as codemode scripts receive the result
|
|
591
|
+
// document itself instead of parsing the rendered text.
|
|
592
|
+
outputSchema: DOCUMENT_SCHEMAS[capability],
|
|
506
593
|
prepareArguments(args) {
|
|
507
594
|
return prepareToolArguments(parameters, args);
|
|
508
595
|
},
|
|
@@ -550,6 +637,7 @@ function webExtension(pi) {
|
|
|
550
637
|
queries: params.queries,
|
|
551
638
|
maxResults: params.maxResults
|
|
552
639
|
}) : capability === "answer" ? await client.answer({ ...request, queries: params.queries }) : capability === "contents" ? await client.contents({ ...request, urls: params.urls }) : await client.research({ ...request, input: params.input });
|
|
640
|
+
const json = JSON.stringify(result);
|
|
553
641
|
const text = renderTextDocument(result);
|
|
554
642
|
const truncated = truncateHead(text);
|
|
555
643
|
let body = truncated.content;
|
|
@@ -561,7 +649,7 @@ function webExtension(pi) {
|
|
|
561
649
|
);
|
|
562
650
|
await withFileMutationQueue(
|
|
563
651
|
fullOutputPath,
|
|
564
|
-
() => writeFile(fullOutputPath,
|
|
652
|
+
() => writeFile(fullOutputPath, json, { mode: 384 })
|
|
565
653
|
);
|
|
566
654
|
body += `
|
|
567
655
|
|
|
@@ -569,8 +657,11 @@ Full results: ${fullOutputPath}`;
|
|
|
569
657
|
}
|
|
570
658
|
return {
|
|
571
659
|
content: [{ type: "text", text: body }],
|
|
660
|
+
// Pi keeps this out of the model's context and the session, so the
|
|
661
|
+
// text truncation above does not apply. Scripts get every result.
|
|
662
|
+
structuredContent: JSON.parse(json),
|
|
663
|
+
isError: result.status === "partial",
|
|
572
664
|
details: {
|
|
573
|
-
webProviderResult: true,
|
|
574
665
|
status: result.status,
|
|
575
666
|
webInputStatus: true,
|
|
576
667
|
capability,
|
|
@@ -584,10 +675,6 @@ Full results: ${fullOutputPath}`;
|
|
|
584
675
|
}
|
|
585
676
|
});
|
|
586
677
|
}
|
|
587
|
-
pi.on("tool_result", (event) => {
|
|
588
|
-
if (event.details && typeof event.details === "object" && "webProviderResult" in event.details && event.details.webProviderResult === true && "status" in event.details && event.details.status === "partial")
|
|
589
|
-
return { isError: true };
|
|
590
|
-
});
|
|
591
678
|
}
|
|
592
679
|
var descriptions = {
|
|
593
680
|
search: "Search up to ten queries and return titles, URLs, and snippets in input order.",
|
package/docs/reference.md
CHANGED
|
@@ -179,3 +179,10 @@ extension forwards cancellation and progress, marks partial results as errors,
|
|
|
179
179
|
and truncates tool output at 2,000 lines or 50 KiB, with full results saved to a
|
|
180
180
|
temporary file. It needs no globally installed `web` command and starts no
|
|
181
181
|
background research jobs.
|
|
182
|
+
|
|
183
|
+
Each tool declares the [JSON result document](./cli-experience.md#json-results)
|
|
184
|
+
as its output schema and returns that document as structured content. Scripts
|
|
185
|
+
that call the tools through Pi's codemode receive it as an object instead of
|
|
186
|
+
parsing text, including the completed inputs of a partial result. Structured
|
|
187
|
+
content is never truncated, and Pi neither sends it to the model nor stores it
|
|
188
|
+
in the session.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "webfox",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.6.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": [
|
|
@@ -98,15 +98,14 @@
|
|
|
98
98
|
"openai": "^7.10.0",
|
|
99
99
|
"parallel-web": "^1.3.3",
|
|
100
100
|
"picocolors": "^1.1.1",
|
|
101
|
-
"typebox": "^1.3.6",
|
|
102
101
|
"valyu-js": "^2.10.1",
|
|
103
102
|
"yaml": "^2.9.0"
|
|
104
103
|
},
|
|
105
104
|
"devDependencies": {
|
|
106
105
|
"@biomejs/biome": "^2.5.4",
|
|
107
|
-
"@earendil-works/pi-ai": "^0.
|
|
108
|
-
"@earendil-works/pi-coding-agent": "^0.
|
|
109
|
-
"@earendil-works/pi-tui": "^0.
|
|
106
|
+
"@earendil-works/pi-ai": "^0.99.0",
|
|
107
|
+
"@earendil-works/pi-coding-agent": "^0.99.0",
|
|
108
|
+
"@earendil-works/pi-tui": "^0.99.0",
|
|
110
109
|
"@types/node": "^26.1.1",
|
|
111
110
|
"esbuild": "^0.28.1",
|
|
112
111
|
"typescript": "^7.0.2",
|
|
@@ -114,7 +113,8 @@
|
|
|
114
113
|
},
|
|
115
114
|
"peerDependencies": {
|
|
116
115
|
"@earendil-works/pi-coding-agent": "*",
|
|
117
|
-
"@earendil-works/pi-tui": "*"
|
|
116
|
+
"@earendil-works/pi-tui": "*",
|
|
117
|
+
"typebox": "*"
|
|
118
118
|
},
|
|
119
119
|
"peerDependenciesMeta": {
|
|
120
120
|
"@earendil-works/pi-coding-agent": {
|