



















@@ -1,4 +1,5 @@
11import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
2+import type { Page } from "playwright-core";
23import type { SsrFPolicy } from "../infra/net/ssrf.js";
34import { type AriaSnapshotNode, formatAriaSnapshot, type RawAXNode } from "./cdp.js";
45import { assertBrowserNavigationAllowed, withBrowserNavigationPolicy } from "./navigation-guard.js";
@@ -19,6 +20,46 @@ import {
1920} from "./pw-session.js";
2021import { withPageScopedCdpClient } from "./pw-session.page-cdp.js";
212223+type SnapshotUrlEntry = {
24+text: string;
25+url: string;
26+};
27+28+async function collectSnapshotUrls(page: Page): Promise<SnapshotUrlEntry[]> {
29+const urls = await page
30+.evaluate(() => {
31+const seen = new Set<string>();
32+const out: SnapshotUrlEntry[] = [];
33+for (const anchor of Array.from(document.querySelectorAll("a[href]"))) {
34+const href = anchor instanceof HTMLAnchorElement ? anchor.href : "";
35+if (!href || seen.has(href)) {
36+continue;
37+}
38+const text =
39+(anchor.textContent || anchor.getAttribute("aria-label") || "")
40+.replace(/\s+/g, " ")
41+.trim()
42+.slice(0, 120) || href;
43+seen.add(href);
44+out.push({ text, url: href });
45+if (out.length >= 100) {
46+break;
47+}
48+}
49+return out;
50+})
51+.catch(() => []);
52+return Array.isArray(urls) ? urls : [];
53+}
54+55+function appendSnapshotUrls(snapshot: string, urls: SnapshotUrlEntry[]): string {
56+if (urls.length === 0) {
57+return snapshot;
58+}
59+const lines = urls.map((entry, index) => `${index + 1}. ${entry.text} -> ${entry.url}`);
60+return `${snapshot}\n\nLinks:\n${lines.join("\n")}`;
61+}
62+2263export async function snapshotAriaViaPlaywright(opts: {
2364cdpUrl: string;
2465targetId?: string;
@@ -62,6 +103,7 @@ export async function snapshotAiViaPlaywright(opts: {
62103targetId?: string;
63104timeoutMs?: number;
64105maxChars?: number;
106+urls?: boolean;
65107ssrfPolicy?: SsrFPolicy;
66108}): Promise<{ snapshot: string; truncated?: boolean; refs: RoleRefMap }> {
67109const page = await getPageForTargetId({
@@ -83,6 +125,9 @@ export async function snapshotAiViaPlaywright(opts: {
83125mode: "ai",
84126timeout: Math.max(500, Math.min(60_000, Math.floor(opts.timeoutMs ?? 5000))),
85127});
128+if (opts.urls) {
129+snapshot = appendSnapshotUrls(snapshot, await collectSnapshotUrls(page));
130+}
86131const maxChars = opts.maxChars;
87132const limit =
88133typeof maxChars === "number" && Number.isFinite(maxChars) && maxChars > 0
@@ -112,6 +157,7 @@ export async function snapshotRoleViaPlaywright(opts: {
112157frameSelector?: string;
113158refsMode?: "role" | "aria";
114159options?: RoleSnapshotOptions;
160+urls?: boolean;
115161ssrfPolicy?: SsrFPolicy;
116162}): Promise<{
117163snapshot: string;
@@ -142,6 +188,9 @@ export async function snapshotRoleViaPlaywright(opts: {
142188timeout: 5000,
143189});
144190const built = buildRoleSnapshotFromAiSnapshot(snapshot, opts.options);
191+const snapshotWithUrls = opts.urls
192+ ? appendSnapshotUrls(built.snapshot, await collectSnapshotUrls(page))
193+ : built.snapshot;
145194storeRoleRefsForTarget({
146195 page,
147196cdpUrl: opts.cdpUrl,
@@ -150,9 +199,9 @@ export async function snapshotRoleViaPlaywright(opts: {
150199mode: "aria",
151200});
152201return {
153-snapshot: built.snapshot,
202+snapshot: snapshotWithUrls,
154203refs: built.refs,
155-stats: getRoleSnapshotStats(built.snapshot, built.refs),
204+stats: getRoleSnapshotStats(snapshotWithUrls, built.refs),
156205};
157206}
158207@@ -168,6 +217,9 @@ export async function snapshotRoleViaPlaywright(opts: {
168217169218const ariaSnapshot = await locator.ariaSnapshot();
170219const built = buildRoleSnapshotFromAriaSnapshot(ariaSnapshot ?? "", opts.options);
220+const snapshotWithUrls = opts.urls
221+ ? appendSnapshotUrls(built.snapshot, await collectSnapshotUrls(page))
222+ : built.snapshot;
171223storeRoleRefsForTarget({
172224 page,
173225cdpUrl: opts.cdpUrl,
@@ -177,9 +229,9 @@ export async function snapshotRoleViaPlaywright(opts: {
177229mode: "role",
178230});
179231return {
180-snapshot: built.snapshot,
232+snapshot: snapshotWithUrls,
181233refs: built.refs,
182-stats: getRoleSnapshotStats(built.snapshot, built.refs),
234+stats: getRoleSnapshotStats(snapshotWithUrls, built.refs),
183235};
184236}
185237此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。