@zeldrisho/pi-web-fetch 0.13.0 → 0.14.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/CHANGELOG.md +9 -1
- package/package.json +1 -1
- package/src/index.ts +48 -9
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.14.0] - 2026-10-25
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- Show cache progress, focus queries, offsets, and a compact fetch summary in Pi's tool preview without adding model-facing output.
|
|
15
|
+
- Declare read-only network access hints for permission integrations and validate existing input limits in the tool schema.
|
|
16
|
+
|
|
10
17
|
## [0.13.0] - 2026-10-24
|
|
11
18
|
|
|
12
19
|
### Added
|
|
@@ -256,7 +263,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
256
263
|
|
|
257
264
|
- Add bounded public page fetching ([b979496](https://github.com/zeldrisho/pi-packages/commit/b979496b32de1cead172ba570307e4a4a7b3421d))
|
|
258
265
|
|
|
259
|
-
[Unreleased]: https://github.com/zeldrisho/pi-packages/compare/pi-web-fetch-v0.
|
|
266
|
+
[Unreleased]: https://github.com/zeldrisho/pi-packages/compare/pi-web-fetch-v0.14.0...HEAD
|
|
267
|
+
[0.14.0]: https://github.com/zeldrisho/pi-packages/compare/pi-web-fetch-v0.13.0...pi-web-fetch-v0.14.0
|
|
260
268
|
[0.13.0]: https://github.com/zeldrisho/pi-packages/compare/pi-web-fetch-v0.12.0...pi-web-fetch-v0.13.0
|
|
261
269
|
[0.12.0]: https://github.com/zeldrisho/pi-packages/compare/pi-web-fetch-v0.11.1...pi-web-fetch-v0.12.0
|
|
262
270
|
[0.11.1]: https://github.com/zeldrisho/pi-packages/compare/pi-web-fetch-v0.11.0...pi-web-fetch-v0.11.1
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { Text } from "@earendil-works/pi-tui";
|
|
3
3
|
import { Type } from "typebox";
|
|
4
|
+
import {
|
|
5
|
+
FETCH_MAX_OFFSET_CHARACTERS,
|
|
6
|
+
FETCH_MAX_QUERY_CHARACTERS,
|
|
7
|
+
FETCH_MAX_URL_CHARACTERS,
|
|
8
|
+
} from "./limits";
|
|
4
9
|
import { redactUrlForDisplay } from "./redact";
|
|
5
10
|
import { formatCollapsibleOutput } from "./render";
|
|
6
|
-
import { executeWebFetch, webFetchOutputSchema } from "./service";
|
|
11
|
+
import { executeWebFetch, webFetchOutputSchema, type WebFetchDetails } from "./service";
|
|
7
12
|
|
|
8
13
|
export { ExpiringLruCache } from "./cache";
|
|
9
14
|
|
|
@@ -62,9 +67,21 @@ export {
|
|
|
62
67
|
} from "./network/network.ts";
|
|
63
68
|
|
|
64
69
|
export const webFetchParameters = Type.Object({
|
|
65
|
-
url: Type.String(),
|
|
66
|
-
query: Type.Optional(
|
|
67
|
-
|
|
70
|
+
url: Type.String({ minLength: 1, maxLength: FETCH_MAX_URL_CHARACTERS }),
|
|
71
|
+
query: Type.Optional(
|
|
72
|
+
Type.String({
|
|
73
|
+
minLength: 1,
|
|
74
|
+
maxLength: FETCH_MAX_QUERY_CHARACTERS,
|
|
75
|
+
description: "Find sections matching this text.",
|
|
76
|
+
}),
|
|
77
|
+
),
|
|
78
|
+
offset: Type.Optional(
|
|
79
|
+
Type.Integer({
|
|
80
|
+
minimum: 0,
|
|
81
|
+
maximum: FETCH_MAX_OFFSET_CHARACTERS,
|
|
82
|
+
description: "Start at this character offset.",
|
|
83
|
+
}),
|
|
84
|
+
),
|
|
68
85
|
});
|
|
69
86
|
|
|
70
87
|
/**
|
|
@@ -73,16 +90,18 @@ export const webFetchParameters = Type.Object({
|
|
|
73
90
|
* @param pi - The extension API instance
|
|
74
91
|
*/
|
|
75
92
|
export default function (pi: ExtensionAPI) {
|
|
76
|
-
pi.registerTool({
|
|
93
|
+
pi.registerTool<typeof webFetchParameters, Partial<WebFetchDetails>>({
|
|
77
94
|
name: "web_fetch",
|
|
78
95
|
label: "Web Fetch",
|
|
79
96
|
description: "Read a public webpage as Markdown.",
|
|
80
97
|
parameters: webFetchParameters,
|
|
81
98
|
outputSchema: webFetchOutputSchema,
|
|
99
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: true },
|
|
82
100
|
|
|
101
|
+
/** Renders the redacted URL, optional focus query, and character offset in the call preview. */
|
|
83
102
|
renderCall(args, theme) {
|
|
84
103
|
return new Text(
|
|
85
|
-
`${theme.fg("toolTitle", theme.bold("web_fetch"))} ${theme.fg("accent", redactUrlForDisplay(args.url))}`,
|
|
104
|
+
`${theme.fg("toolTitle", theme.bold("web_fetch"))} ${theme.fg("accent", redactUrlForDisplay(args.url))}${args.query === undefined ? "" : ` query=${JSON.stringify(args.query)}`}${args.offset === undefined ? "" : ` offset=${args.offset}`}`,
|
|
86
105
|
0,
|
|
87
106
|
0,
|
|
88
107
|
);
|
|
@@ -92,14 +111,34 @@ export default function (pi: ExtensionAPI) {
|
|
|
92
111
|
return executeWebFetch(params, signal, onUpdate);
|
|
93
112
|
},
|
|
94
113
|
|
|
114
|
+
/**
|
|
115
|
+
* Renders partial text or "Fetching…" while pending. Completed text gets a
|
|
116
|
+
* detail summary when available and a collapsible body; absent text shows "No content".
|
|
117
|
+
*/
|
|
95
118
|
renderResult(result, { expanded, isPartial }, theme) {
|
|
96
|
-
if (isPartial) return new Text(theme.fg("warning", "Fetching…"), 0, 0);
|
|
97
|
-
|
|
98
119
|
const content = result.content.find((item) => item.type === "text");
|
|
99
120
|
|
|
121
|
+
if (isPartial) return new Text(theme.fg("warning", content?.text || "Fetching…"), 0, 0);
|
|
122
|
+
|
|
123
|
+
const details = result.details;
|
|
124
|
+
|
|
125
|
+
const summary =
|
|
126
|
+
details?.characterCount !== undefined
|
|
127
|
+
? [
|
|
128
|
+
details.extractionDiagnostics?.botWall
|
|
129
|
+
? "Blocked"
|
|
130
|
+
: `${details.characterCount} characters`,
|
|
131
|
+
details.cacheStatus ?? (details.cached ? "cached" : "miss"),
|
|
132
|
+
...(details.focus
|
|
133
|
+
? [`${details.focus.matchedSections}/${details.focus.totalSections} sections`]
|
|
134
|
+
: []),
|
|
135
|
+
...(details.nextOffset === undefined ? [] : [`next offset=${details.nextOffset}`]),
|
|
136
|
+
].join(" · ")
|
|
137
|
+
: "";
|
|
138
|
+
|
|
100
139
|
return new Text(
|
|
101
140
|
content?.type === "text"
|
|
102
|
-
? formatCollapsibleOutput(content.text, expanded, theme)
|
|
141
|
+
? `${theme.fg("dim", summary)}${formatCollapsibleOutput(content.text, expanded, theme)}`
|
|
103
142
|
: theme.fg("dim", "No content"),
|
|
104
143
|
0,
|
|
105
144
|
0,
|