@bacnh85/pi-web 0.6.1 → 0.6.2
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 +18 -4
- package/README.md +1 -1
- package/extensions/index.ts +11 -4
- package/extensions/lib/content.ts +10 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 0.6.2 (2026-
|
|
3
|
+
## 0.6.2 (2026-09-06)
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- `web_screenshot` now returns the PNG **inline as an image block**
|
|
8
|
+
(`ImageContent`) alongside the text summary, so multimodal models (GLM-5.3,
|
|
9
|
+
Claude, Gemini) actually see the screenshot instead of a base64 char
|
|
10
|
+
count. The "Data: base64 PNG (N chars)" line is gone; artifact/MIME/size
|
|
11
|
+
summary unchanged. Inspired by zcode-plugins video2code's vision-in-the-loop.
|
|
12
|
+
Regression-tested in `test/unit/screenshot.test.ts` (fetch stubbed — no
|
|
13
|
+
daemon needed): image block present + base64-text line absent; text-only
|
|
14
|
+
fallback when the daemon returns no screenshot.
|
|
15
|
+
|
|
16
|
+
Daemon `success:false` responses (HTTP 200) now surface `error_message` as
|
|
17
|
+
a tool error instead of returning a silently empty screenshot result.
|
|
18
|
+
|
|
19
|
+
## 0.6.1 (2026-08-30)
|
|
4
20
|
|
|
5
21
|
### Changed
|
|
6
22
|
|
|
@@ -11,9 +27,7 @@
|
|
|
11
27
|
hook.test.ts assertion updated to the compressed phrasing. No tool,
|
|
12
28
|
parameter, or default changed.
|
|
13
29
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
### Changed
|
|
30
|
+
### Changed (2026-08-19)
|
|
17
31
|
|
|
18
32
|
- `web_extract` agy backend default model updated to `gemini-3.7-flash-medium`
|
|
19
33
|
— the current Flash generation in agy 1.1.x (3.6 is still served, this just
|
package/README.md
CHANGED
|
@@ -142,7 +142,7 @@ web_crawl url="https://example.com" mode=light poll=true # Poll for completio
|
|
|
142
142
|
|
|
143
143
|
### `web_screenshot` — Page screenshot
|
|
144
144
|
|
|
145
|
-
Captures a full-page PNG screenshot using Crawl4AI. Returns
|
|
145
|
+
Captures a full-page PNG screenshot using Crawl4AI. Returns the PNG inline as an image block (multimodal models see it); text summary includes artifact/MIME/size.
|
|
146
146
|
|
|
147
147
|
```
|
|
148
148
|
web_screenshot url="https://example.com"
|
package/extensions/index.ts
CHANGED
|
@@ -286,9 +286,9 @@ export default function piWebExtension(pi: ExtensionAPI) {
|
|
|
286
286
|
name: "web_screenshot",
|
|
287
287
|
label: "Web Page Screenshot",
|
|
288
288
|
description:
|
|
289
|
-
"Full-page PNG screenshot via Crawl4AI.",
|
|
289
|
+
"Full-page PNG screenshot via Crawl4AI. The PNG is returned inline as an image block.",
|
|
290
290
|
promptSnippet: "Screenshot a webpage",
|
|
291
|
-
promptGuidelines: ["Full-page PNG; use when web_extract fails on JS-heavy pages."],
|
|
291
|
+
promptGuidelines: ["Full-page PNG returned inline (multimodal models see it); use when web_extract fails on JS-heavy pages, or to visually inspect a built UI."],
|
|
292
292
|
parameters: Type.Object({
|
|
293
293
|
url: Type.String(),
|
|
294
294
|
wait_for: Type.Optional(Type.Number({ default: 2, description: "Seconds to wait before capture." })),
|
|
@@ -305,16 +305,23 @@ export default function piWebExtension(pi: ExtensionAPI) {
|
|
|
305
305
|
params.wait_for_images as boolean | undefined,
|
|
306
306
|
signal,
|
|
307
307
|
);
|
|
308
|
+
if (result.success === false) {
|
|
309
|
+
throw new Error(String(result.error_message ?? "Crawl4AI screenshot failed"));
|
|
310
|
+
}
|
|
308
311
|
const screenshot = result.screenshot as string | undefined;
|
|
309
312
|
const artifactUrl = result.url as string | undefined;
|
|
310
313
|
const mime = result.mime as string | undefined;
|
|
311
314
|
const size = result.size as number | undefined;
|
|
312
315
|
let text = `Screenshot: ${params.url}\n`;
|
|
313
|
-
if (screenshot) text += `Data: base64 PNG (${screenshot.length} chars)\n`;
|
|
314
316
|
if (artifactUrl) text += `Artifact: ${artifactUrl}\n`;
|
|
315
317
|
if (mime) text += `MIME: ${mime}\n`;
|
|
316
318
|
if (size) text += `Size: ${size} bytes\n`;
|
|
317
|
-
|
|
319
|
+
// Return the PNG as a real image block so multimodal models see it.
|
|
320
|
+
const content: Array<{ type: "text"; text: string } | { type: "image"; data: string; mimeType: string }> = [
|
|
321
|
+
{ type: "text", text: truncateText(text) },
|
|
322
|
+
];
|
|
323
|
+
if (screenshot) content.push({ type: "image", data: screenshot, mimeType: mime || "image/png" });
|
|
324
|
+
return { content, details: { ...result, url: params.url } };
|
|
318
325
|
},
|
|
319
326
|
});
|
|
320
327
|
|
|
@@ -59,6 +59,16 @@ export async function fetchReadableContent(
|
|
|
59
59
|
signal: signalWithTimeout(timeoutMs, signal),
|
|
60
60
|
});
|
|
61
61
|
if (!response.ok) throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
62
|
+
// Raw text/JSON payloads (raw.githubusercontent.com, JSON APIs) — Readability
|
|
63
|
+
// shreds them to nothing. Pass through verbatim. text/html and text/xml keep
|
|
64
|
+
// the Readability path — they're ordinary web pages. Session mining: 9/40
|
|
65
|
+
// static extract failures were raw-text/JSON shapes.
|
|
66
|
+
const contentType = (response.headers.get("content-type") ?? "").split(";")[0].trim();
|
|
67
|
+
if ((contentType.startsWith("text/") && contentType !== "text/html" && contentType !== "text/xml") || contentType === "application/json") {
|
|
68
|
+
const body = await response.text();
|
|
69
|
+
const markdown = contentType === "application/json" ? "```json\n" + body + "\n```" : body;
|
|
70
|
+
return { title: "", markdown: markdown.slice(0, 20000) };
|
|
71
|
+
}
|
|
62
72
|
const html = await response.text();
|
|
63
73
|
const deps = loadReadableContentDependencies();
|
|
64
74
|
const dom = new deps.JSDOM(html, { url });
|
package/package.json
CHANGED