pi-agent-browser-native 0.2.48 → 0.2.49
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 +17 -0
- package/README.md +16 -6
- package/dist/extensions/agent-browser/index.js +785 -0
- package/dist/extensions/agent-browser/lib/argv-descriptor.js +71 -0
- package/dist/extensions/agent-browser/lib/argv-grammar.js +121 -0
- package/dist/extensions/agent-browser/lib/bash-guard.js +190 -0
- package/dist/extensions/agent-browser/lib/command-policy.js +85 -0
- package/dist/extensions/agent-browser/lib/command-taxonomy.js +302 -0
- package/dist/extensions/agent-browser/lib/config-policy.js +686 -0
- package/dist/extensions/agent-browser/lib/config.js +122 -0
- package/dist/extensions/agent-browser/lib/electron/cdp.js +51 -0
- package/dist/extensions/agent-browser/lib/electron/cleanup.js +212 -0
- package/dist/extensions/agent-browser/lib/electron/discovery.js +633 -0
- package/dist/extensions/agent-browser/lib/electron/launch.js +351 -0
- package/{extensions/agent-browser/lib/electron/text.ts → dist/extensions/agent-browser/lib/electron/text.js} +5 -5
- package/dist/extensions/agent-browser/lib/executable-path.js +20 -0
- package/dist/extensions/agent-browser/lib/fs-utils.js +18 -0
- package/dist/extensions/agent-browser/lib/input-modes/electron.js +165 -0
- package/dist/extensions/agent-browser/lib/input-modes/job.js +519 -0
- package/dist/extensions/agent-browser/lib/input-modes/lookups.js +440 -0
- package/dist/extensions/agent-browser/lib/input-modes/params.js +164 -0
- package/dist/extensions/agent-browser/lib/input-modes/semantic-action.js +119 -0
- package/dist/extensions/agent-browser/lib/input-modes/shared.js +42 -0
- package/dist/extensions/agent-browser/lib/input-modes/types.js +21 -0
- package/dist/extensions/agent-browser/lib/input-modes.js +10 -0
- package/dist/extensions/agent-browser/lib/json-schema.js +58 -0
- package/dist/extensions/agent-browser/lib/launch-scoped-flags.js +59 -0
- package/dist/extensions/agent-browser/lib/navigation-policy.js +83 -0
- package/dist/extensions/agent-browser/lib/orchestration/batch-stdin.js +62 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/artifact-paths.js +39 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/click-dispatch.js +276 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/diagnostics.js +909 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result.js +443 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/index.js +47 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/direct-anchor-download.js +141 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/network-page-filter.js +108 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/scroll-shims.js +112 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/snapshot-filter.js +158 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/wait-timeouts.js +54 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare.js +762 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output.js +491 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prompt-guards.js +40 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-artifacts.js +5 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state.js +731 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/types.js +1 -0
- package/dist/extensions/agent-browser/lib/orchestration/electron-host/index.js +718 -0
- package/dist/extensions/agent-browser/lib/orchestration/input-plan.js +247 -0
- package/dist/extensions/agent-browser/lib/orchestration/output-file.js +68 -0
- package/{extensions/agent-browser/lib/parsing.ts → dist/extensions/agent-browser/lib/parsing.js} +12 -11
- package/dist/extensions/agent-browser/lib/pi-tool-rendering.js +241 -0
- package/dist/extensions/agent-browser/lib/playbook.js +121 -0
- package/dist/extensions/agent-browser/lib/process.js +448 -0
- package/dist/extensions/agent-browser/lib/prompt-policy.js +91 -0
- package/dist/extensions/agent-browser/lib/results/action-recommendations.js +220 -0
- package/dist/extensions/agent-browser/lib/results/artifact-manifest.js +111 -0
- package/{extensions/agent-browser/lib/results/artifact-state.ts → dist/extensions/agent-browser/lib/results/artifact-state.js} +4 -8
- package/dist/extensions/agent-browser/lib/results/categories.js +76 -0
- package/dist/extensions/agent-browser/lib/results/confirmation.js +63 -0
- package/dist/extensions/agent-browser/lib/results/contracts.js +8 -0
- package/dist/extensions/agent-browser/lib/results/editable-ref-evidence.js +74 -0
- package/dist/extensions/agent-browser/lib/results/envelope.js +166 -0
- package/dist/extensions/agent-browser/lib/results/network-routes.js +92 -0
- package/dist/extensions/agent-browser/lib/results/network.js +73 -0
- package/dist/extensions/agent-browser/lib/results/next-actions.js +72 -0
- package/dist/extensions/agent-browser/lib/results/presentation/artifacts.js +515 -0
- package/dist/extensions/agent-browser/lib/results/presentation/batch.js +397 -0
- package/dist/extensions/agent-browser/lib/results/presentation/browser-profile-recovery.js +55 -0
- package/dist/extensions/agent-browser/lib/results/presentation/common.js +46 -0
- package/dist/extensions/agent-browser/lib/results/presentation/content.js +24 -0
- package/dist/extensions/agent-browser/lib/results/presentation/diagnostics.js +960 -0
- package/dist/extensions/agent-browser/lib/results/presentation/errors.js +205 -0
- package/dist/extensions/agent-browser/lib/results/presentation/large-output.js +134 -0
- package/dist/extensions/agent-browser/lib/results/presentation/navigation.js +159 -0
- package/dist/extensions/agent-browser/lib/results/presentation/registry.js +216 -0
- package/dist/extensions/agent-browser/lib/results/presentation/semantic-action.js +104 -0
- package/dist/extensions/agent-browser/lib/results/presentation/skills.js +152 -0
- package/dist/extensions/agent-browser/lib/results/presentation.js +177 -0
- package/dist/extensions/agent-browser/lib/results/recovery-actions.js +107 -0
- package/dist/extensions/agent-browser/lib/results/recovery-next-actions.js +50 -0
- package/dist/extensions/agent-browser/lib/results/selector-recovery.js +225 -0
- package/{extensions/agent-browser/lib/results/shared.ts → dist/extensions/agent-browser/lib/results/shared.js} +0 -1
- package/dist/extensions/agent-browser/lib/results/snapshot-high-value-controls.js +208 -0
- package/dist/extensions/agent-browser/lib/results/snapshot-refs.js +78 -0
- package/dist/extensions/agent-browser/lib/results/snapshot-segments.js +331 -0
- package/dist/extensions/agent-browser/lib/results/snapshot-spill.js +40 -0
- package/dist/extensions/agent-browser/lib/results/snapshot.js +264 -0
- package/dist/extensions/agent-browser/lib/results/text.js +40 -0
- package/{extensions/agent-browser/lib/results.ts → dist/extensions/agent-browser/lib/results.js} +2 -32
- package/dist/extensions/agent-browser/lib/runtime.js +816 -0
- package/dist/extensions/agent-browser/lib/session-page-state.js +411 -0
- package/dist/extensions/agent-browser/lib/string-enum-schema.js +13 -0
- package/dist/extensions/agent-browser/lib/temp.js +498 -0
- package/dist/extensions/agent-browser/lib/web-search.js +562 -0
- package/docs/RELEASE.md +22 -11
- package/docs/SUPPORT_MATRIX.md +4 -3
- package/package.json +9 -5
- package/scripts/config.mjs +8 -2
- package/scripts/doctor.mjs +8 -7
- package/extensions/agent-browser/index.ts +0 -961
- package/extensions/agent-browser/lib/argv-descriptor.ts +0 -90
- package/extensions/agent-browser/lib/argv-grammar.ts +0 -128
- package/extensions/agent-browser/lib/bash-guard.ts +0 -205
- package/extensions/agent-browser/lib/command-policy.ts +0 -71
- package/extensions/agent-browser/lib/command-taxonomy.ts +0 -336
- package/extensions/agent-browser/lib/config-policy.js +0 -690
- package/extensions/agent-browser/lib/config.ts +0 -211
- package/extensions/agent-browser/lib/electron/cdp.ts +0 -69
- package/extensions/agent-browser/lib/electron/cleanup.ts +0 -235
- package/extensions/agent-browser/lib/electron/discovery.ts +0 -710
- package/extensions/agent-browser/lib/electron/launch.ts +0 -499
- package/extensions/agent-browser/lib/executable-path.ts +0 -19
- package/extensions/agent-browser/lib/fs-utils.ts +0 -18
- package/extensions/agent-browser/lib/input-modes/electron.ts +0 -170
- package/extensions/agent-browser/lib/input-modes/job.ts +0 -527
- package/extensions/agent-browser/lib/input-modes/lookups.ts +0 -447
- package/extensions/agent-browser/lib/input-modes/params.ts +0 -205
- package/extensions/agent-browser/lib/input-modes/semantic-action.ts +0 -127
- package/extensions/agent-browser/lib/input-modes/shared.ts +0 -46
- package/extensions/agent-browser/lib/input-modes/types.ts +0 -225
- package/extensions/agent-browser/lib/input-modes.ts +0 -45
- package/extensions/agent-browser/lib/json-schema.ts +0 -73
- package/extensions/agent-browser/lib/launch-scoped-flags.ts +0 -67
- package/extensions/agent-browser/lib/navigation-policy.ts +0 -95
- package/extensions/agent-browser/lib/orchestration/batch-stdin.ts +0 -65
- package/extensions/agent-browser/lib/orchestration/browser-run/artifact-paths.ts +0 -44
- package/extensions/agent-browser/lib/orchestration/browser-run/click-dispatch.ts +0 -280
- package/extensions/agent-browser/lib/orchestration/browser-run/diagnostics.ts +0 -914
- package/extensions/agent-browser/lib/orchestration/browser-run/final-result.ts +0 -521
- package/extensions/agent-browser/lib/orchestration/browser-run/index.ts +0 -53
- package/extensions/agent-browser/lib/orchestration/browser-run/prepare/direct-anchor-download.ts +0 -158
- package/extensions/agent-browser/lib/orchestration/browser-run/prepare/network-page-filter.ts +0 -116
- package/extensions/agent-browser/lib/orchestration/browser-run/prepare/scroll-shims.ts +0 -147
- package/extensions/agent-browser/lib/orchestration/browser-run/prepare/snapshot-filter.ts +0 -183
- package/extensions/agent-browser/lib/orchestration/browser-run/prepare/wait-timeouts.ts +0 -58
- package/extensions/agent-browser/lib/orchestration/browser-run/prepare.ts +0 -847
- package/extensions/agent-browser/lib/orchestration/browser-run/process-output.ts +0 -559
- package/extensions/agent-browser/lib/orchestration/browser-run/prompt-guards.ts +0 -47
- package/extensions/agent-browser/lib/orchestration/browser-run/session-artifacts.ts +0 -8
- package/extensions/agent-browser/lib/orchestration/browser-run/session-state.ts +0 -868
- package/extensions/agent-browser/lib/orchestration/browser-run/types.ts +0 -565
- package/extensions/agent-browser/lib/orchestration/electron-host/index.ts +0 -855
- package/extensions/agent-browser/lib/orchestration/input-plan.ts +0 -375
- package/extensions/agent-browser/lib/orchestration/output-file.ts +0 -86
- package/extensions/agent-browser/lib/pi-tool-rendering.ts +0 -267
- package/extensions/agent-browser/lib/playbook.ts +0 -142
- package/extensions/agent-browser/lib/process.ts +0 -516
- package/extensions/agent-browser/lib/prompt-policy.ts +0 -105
- package/extensions/agent-browser/lib/results/action-recommendations.ts +0 -264
- package/extensions/agent-browser/lib/results/artifact-manifest.ts +0 -111
- package/extensions/agent-browser/lib/results/categories.ts +0 -106
- package/extensions/agent-browser/lib/results/confirmation.ts +0 -76
- package/extensions/agent-browser/lib/results/contracts.ts +0 -241
- package/extensions/agent-browser/lib/results/editable-ref-evidence.ts +0 -72
- package/extensions/agent-browser/lib/results/envelope.ts +0 -195
- package/extensions/agent-browser/lib/results/network-routes.ts +0 -83
- package/extensions/agent-browser/lib/results/network.ts +0 -78
- package/extensions/agent-browser/lib/results/next-actions.ts +0 -117
- package/extensions/agent-browser/lib/results/presentation/artifacts.ts +0 -588
- package/extensions/agent-browser/lib/results/presentation/batch.ts +0 -450
- package/extensions/agent-browser/lib/results/presentation/browser-profile-recovery.ts +0 -67
- package/extensions/agent-browser/lib/results/presentation/common.ts +0 -53
- package/extensions/agent-browser/lib/results/presentation/content.ts +0 -36
- package/extensions/agent-browser/lib/results/presentation/diagnostics.ts +0 -923
- package/extensions/agent-browser/lib/results/presentation/errors.ts +0 -227
- package/extensions/agent-browser/lib/results/presentation/large-output.ts +0 -182
- package/extensions/agent-browser/lib/results/presentation/navigation.ts +0 -184
- package/extensions/agent-browser/lib/results/presentation/registry.ts +0 -242
- package/extensions/agent-browser/lib/results/presentation/semantic-action.ts +0 -131
- package/extensions/agent-browser/lib/results/presentation/skills.ts +0 -143
- package/extensions/agent-browser/lib/results/presentation.ts +0 -257
- package/extensions/agent-browser/lib/results/recovery-actions.ts +0 -139
- package/extensions/agent-browser/lib/results/recovery-next-actions.ts +0 -71
- package/extensions/agent-browser/lib/results/selector-recovery.ts +0 -320
- package/extensions/agent-browser/lib/results/snapshot-high-value-controls.ts +0 -273
- package/extensions/agent-browser/lib/results/snapshot-refs.ts +0 -100
- package/extensions/agent-browser/lib/results/snapshot-segments.ts +0 -366
- package/extensions/agent-browser/lib/results/snapshot-spill.ts +0 -63
- package/extensions/agent-browser/lib/results/snapshot.ts +0 -329
- package/extensions/agent-browser/lib/results/text.ts +0 -40
- package/extensions/agent-browser/lib/runtime.ts +0 -988
- package/extensions/agent-browser/lib/session-page-state.ts +0 -512
- package/extensions/agent-browser/lib/string-enum-schema.ts +0 -20
- package/extensions/agent-browser/lib/temp.ts +0 -577
- package/extensions/agent-browser/lib/web-search.ts +0 -728
- /package/{extensions/agent-browser/lib/orchestration/browser-run.ts → dist/extensions/agent-browser/lib/orchestration/browser-run.js} +0 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Purpose: Own canonical parsing and enrichment of refs from agent-browser snapshot payloads.
|
|
3
|
+
* Responsibilities: Read structured refs, correlate them with raw snapshot lines, and infer editable/ref role evidence once for consumers.
|
|
4
|
+
* Scope: Snapshot ref metadata only; section preview, high-value ranking, and presentation assembly live in neighboring modules.
|
|
5
|
+
* Usage: Imported by snapshot presentation and recovery diagnostics that need consistent ref/name/role/editable evidence.
|
|
6
|
+
* Invariants/Assumptions: Snapshot text parsing is best-effort and must tolerate upstream formatting changes by preserving structured ref data when line parsing fails.
|
|
7
|
+
*/
|
|
8
|
+
import { isRecord } from "../parsing.js";
|
|
9
|
+
import { getEditableRefEvidence } from "./editable-ref-evidence.js";
|
|
10
|
+
import { compareRefIds, normalizeWhitespace } from "./text.js";
|
|
11
|
+
export function getSnapshotRefRecord(data) {
|
|
12
|
+
return isRecord(data) && isRecord(data.refs) ? data.refs : undefined;
|
|
13
|
+
}
|
|
14
|
+
export function getSnapshotLineTextByRef(data) {
|
|
15
|
+
const snapshot = isRecord(data) && typeof data.snapshot === "string" ? data.snapshot : "";
|
|
16
|
+
const lineByRef = new Map();
|
|
17
|
+
for (const line of snapshot.split("\n")) {
|
|
18
|
+
const ref = line.match(/\bref=([^,\]\s]+)/)?.[1];
|
|
19
|
+
if (!ref || lineByRef.has(ref))
|
|
20
|
+
continue;
|
|
21
|
+
lineByRef.set(ref, line);
|
|
22
|
+
}
|
|
23
|
+
return lineByRef;
|
|
24
|
+
}
|
|
25
|
+
export function getSnapshotRefEntries(data) {
|
|
26
|
+
const refs = getSnapshotRefRecord(data);
|
|
27
|
+
if (!refs)
|
|
28
|
+
return [];
|
|
29
|
+
return Object.entries(refs)
|
|
30
|
+
.map(([id, value]) => {
|
|
31
|
+
if (!isRecord(value)) {
|
|
32
|
+
return { id, name: "", role: "unknown" };
|
|
33
|
+
}
|
|
34
|
+
const name = typeof value.name === "string" ? normalizeWhitespace(value.name) : "";
|
|
35
|
+
const role = typeof value.role === "string" && value.role.length > 0 ? value.role : "unknown";
|
|
36
|
+
const isEditable = getEditableRefEvidence({ ref: value });
|
|
37
|
+
return { id, isEditable, name, refData: value, role };
|
|
38
|
+
})
|
|
39
|
+
.sort((a, b) => compareRefIds(a.id, b.id));
|
|
40
|
+
}
|
|
41
|
+
function isEditableSnapshotLine(line) {
|
|
42
|
+
const editableEvidence = getEditableRefEvidence({ text: line.raw });
|
|
43
|
+
if (editableEvidence !== undefined)
|
|
44
|
+
return editableEvidence;
|
|
45
|
+
return line.role === "searchbox" || line.role === "textbox" || line.role === "combobox" ? true : undefined;
|
|
46
|
+
}
|
|
47
|
+
export function getSnapshotRefRole(entry, editableEvidence) {
|
|
48
|
+
const rawRole = typeof entry.role === "string" && entry.role.length > 0 ? entry.role : "unknown";
|
|
49
|
+
const normalizedRole = rawRole.toLowerCase();
|
|
50
|
+
if ((normalizedRole === "generic" || normalizedRole === "unknown") && editableEvidence === true) {
|
|
51
|
+
return "textbox";
|
|
52
|
+
}
|
|
53
|
+
return rawRole;
|
|
54
|
+
}
|
|
55
|
+
export function enrichSnapshotRefEntries(refEntries, snapshotLines) {
|
|
56
|
+
const lineByRef = new Map();
|
|
57
|
+
for (const line of snapshotLines) {
|
|
58
|
+
if (!line.ref || lineByRef.has(line.ref))
|
|
59
|
+
continue;
|
|
60
|
+
lineByRef.set(line.ref, line);
|
|
61
|
+
}
|
|
62
|
+
return refEntries.map((entry) => {
|
|
63
|
+
const line = lineByRef.get(entry.id);
|
|
64
|
+
const lineRole = line && line.role !== "unknown" ? line.role : undefined;
|
|
65
|
+
const editableEvidence = getEditableRefEvidence({ ref: entry.refData, text: line?.raw });
|
|
66
|
+
const hasEditableRole = line ? isEditableSnapshotLine(line) === true && !["unknown", "generic"].includes(line.role) : false;
|
|
67
|
+
const isEditable = editableEvidence === true || (editableEvidence !== false && hasEditableRole);
|
|
68
|
+
const roleFromRefOrLine = entry.role !== "unknown" && entry.role !== "generic" ? entry.role : lineRole ?? entry.role;
|
|
69
|
+
const role = getSnapshotRefRole({ role: roleFromRefOrLine }, isEditable);
|
|
70
|
+
return {
|
|
71
|
+
...entry,
|
|
72
|
+
isEditable,
|
|
73
|
+
lineIndex: line?.index,
|
|
74
|
+
name: entry.name.length > 0 ? entry.name : (line?.name ?? ""),
|
|
75
|
+
role,
|
|
76
|
+
};
|
|
77
|
+
});
|
|
78
|
+
}
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Purpose: Parse raw agent-browser snapshot text into previewable sections.
|
|
3
|
+
* Responsibilities: Identify signal lines, rank content segments, build structured previews, and provide raw-outline fallback previews.
|
|
4
|
+
* Scope: Snapshot text/section planning only; ref enrichment, high-value control ranking, spill files, and final presentation live elsewhere.
|
|
5
|
+
* Usage: Snapshot presentation uses this module before selecting displayed refs.
|
|
6
|
+
* Invariants/Assumptions: Parsing is best-effort and must stay resilient to upstream snapshot text format changes.
|
|
7
|
+
*/
|
|
8
|
+
import { normalizeWhitespace, truncateText } from "./text.js";
|
|
9
|
+
const SNAPSHOT_MAX_ADDITIONAL_SECTIONS = 2;
|
|
10
|
+
const SNAPSHOT_FALLBACK_PREVIEW_MAX_LINES = 12;
|
|
11
|
+
const SNAPSHOT_LINE_MAX_CHARS = 140;
|
|
12
|
+
const SNAPSHOT_SIGNAL_ROLES = new Set([
|
|
13
|
+
"article",
|
|
14
|
+
"banner",
|
|
15
|
+
"button",
|
|
16
|
+
"checkbox",
|
|
17
|
+
"combobox",
|
|
18
|
+
"dialog",
|
|
19
|
+
"gridcell",
|
|
20
|
+
"heading",
|
|
21
|
+
"link",
|
|
22
|
+
"listitem",
|
|
23
|
+
"main",
|
|
24
|
+
"menu",
|
|
25
|
+
"menuitem",
|
|
26
|
+
"navigation",
|
|
27
|
+
"option",
|
|
28
|
+
"radio",
|
|
29
|
+
"region",
|
|
30
|
+
"row",
|
|
31
|
+
"searchbox",
|
|
32
|
+
"tab",
|
|
33
|
+
"textbox",
|
|
34
|
+
]);
|
|
35
|
+
const SNAPSHOT_SEGMENT_ROOT_ROLES = new Set(["article", "dialog", "heading", "main", "menu", "region"]);
|
|
36
|
+
const SNAPSHOT_ROLE_PRIORITY = {
|
|
37
|
+
article: 0,
|
|
38
|
+
main: 1,
|
|
39
|
+
dialog: 2,
|
|
40
|
+
menu: 3,
|
|
41
|
+
region: 4,
|
|
42
|
+
heading: 5,
|
|
43
|
+
searchbox: 6,
|
|
44
|
+
textbox: 7,
|
|
45
|
+
combobox: 8,
|
|
46
|
+
button: 9,
|
|
47
|
+
checkbox: 10,
|
|
48
|
+
radio: 11,
|
|
49
|
+
tab: 12,
|
|
50
|
+
option: 13,
|
|
51
|
+
link: 14,
|
|
52
|
+
listitem: 14,
|
|
53
|
+
row: 15,
|
|
54
|
+
gridcell: 16,
|
|
55
|
+
navigation: 17,
|
|
56
|
+
generic: 99,
|
|
57
|
+
unknown: 100,
|
|
58
|
+
};
|
|
59
|
+
const SNAPSHOT_NOISE_NAME_PATTERNS = [
|
|
60
|
+
/^skip to /i,
|
|
61
|
+
/^ad$/i,
|
|
62
|
+
/^don't want to see ads\??$/i,
|
|
63
|
+
/keyboard shortcuts/i,
|
|
64
|
+
/\bpromoted\b/i,
|
|
65
|
+
/\bsponsored\b/i,
|
|
66
|
+
];
|
|
67
|
+
const SNAPSHOT_CHROME_SECTION_PATTERNS = [
|
|
68
|
+
/^primary$/i,
|
|
69
|
+
/^footer$/i,
|
|
70
|
+
/^navigation$/i,
|
|
71
|
+
/\bwhat['’]?s happening\b/i,
|
|
72
|
+
/\brelevant people\b/i,
|
|
73
|
+
/\btrending\b/i,
|
|
74
|
+
/\brelated\b/i,
|
|
75
|
+
/\brecommended\b/i,
|
|
76
|
+
/\bsuggested\b/i,
|
|
77
|
+
];
|
|
78
|
+
export function getSnapshotRolePriority(role) {
|
|
79
|
+
return SNAPSHOT_ROLE_PRIORITY[role] ?? 50;
|
|
80
|
+
}
|
|
81
|
+
export function parseSnapshotLines(snapshot) {
|
|
82
|
+
return snapshot
|
|
83
|
+
.split("\n")
|
|
84
|
+
.filter((line) => line.length > 0)
|
|
85
|
+
.map((raw, index) => {
|
|
86
|
+
const trimmed = raw.trimStart();
|
|
87
|
+
const depth = Math.floor(((raw.match(/^\s*/) ?? [""])[0].length ?? 0) / 2);
|
|
88
|
+
const role = trimmed.match(/^[-*]\s+([^\s"]+)/)?.[1] ?? "unknown";
|
|
89
|
+
const name = normalizeWhitespace(trimmed.match(/"([^"]*)"/)?.[1] ?? "");
|
|
90
|
+
const ref = trimmed.match(/\bref=([^,\]\s]+)/)?.[1];
|
|
91
|
+
const headingLevel = trimmed.match(/\blevel=(\d+)/)?.[1];
|
|
92
|
+
return {
|
|
93
|
+
depth,
|
|
94
|
+
headingLevel: headingLevel ? Number(headingLevel) : undefined,
|
|
95
|
+
index,
|
|
96
|
+
name,
|
|
97
|
+
raw,
|
|
98
|
+
ref,
|
|
99
|
+
role,
|
|
100
|
+
};
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
export function isNoiseName(name) {
|
|
104
|
+
return SNAPSHOT_NOISE_NAME_PATTERNS.some((pattern) => pattern.test(name));
|
|
105
|
+
}
|
|
106
|
+
export function isChromeSectionName(name) {
|
|
107
|
+
return SNAPSHOT_CHROME_SECTION_PATTERNS.some((pattern) => pattern.test(name));
|
|
108
|
+
}
|
|
109
|
+
function isNoiseSnapshotLine(line) {
|
|
110
|
+
if (line.name.length > 0 && isNoiseName(line.name))
|
|
111
|
+
return true;
|
|
112
|
+
const loweredRaw = line.raw.toLowerCase();
|
|
113
|
+
return loweredRaw.includes("promoted") || loweredRaw.includes("sponsored");
|
|
114
|
+
}
|
|
115
|
+
function isPotentialSegmentRootLine(line) {
|
|
116
|
+
if (!SNAPSHOT_SEGMENT_ROOT_ROLES.has(line.role))
|
|
117
|
+
return false;
|
|
118
|
+
if (isNoiseSnapshotLine(line))
|
|
119
|
+
return false;
|
|
120
|
+
if (line.role === "heading") {
|
|
121
|
+
return line.name.length > 0 && (line.headingLevel ?? 99) <= 3;
|
|
122
|
+
}
|
|
123
|
+
if (line.role === "region") {
|
|
124
|
+
return line.name.length > 0;
|
|
125
|
+
}
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
function scoreSegment(segment) {
|
|
129
|
+
const { root } = segment;
|
|
130
|
+
const distinctRefs = new Set(segment.lines.flatMap((line) => (line.ref ? [line.ref] : []))).size;
|
|
131
|
+
let score = 0;
|
|
132
|
+
score += 120 - getSnapshotRolePriority(root.role) * 8;
|
|
133
|
+
score += Math.min(distinctRefs, 16);
|
|
134
|
+
score += Math.min(segment.lines.length, 12);
|
|
135
|
+
score -= Math.min(root.index, 60) / 3;
|
|
136
|
+
score -= root.depth * 6;
|
|
137
|
+
if (root.role === "heading") {
|
|
138
|
+
if (root.headingLevel === 1)
|
|
139
|
+
score += 40;
|
|
140
|
+
else if (root.headingLevel === 2)
|
|
141
|
+
score += 22;
|
|
142
|
+
else if (root.headingLevel === 3)
|
|
143
|
+
score += 12;
|
|
144
|
+
}
|
|
145
|
+
if (root.name.length > 0)
|
|
146
|
+
score += 10;
|
|
147
|
+
if (root.name.length <= 2)
|
|
148
|
+
score -= 18;
|
|
149
|
+
if (isChromeSectionName(root.name))
|
|
150
|
+
score -= 45;
|
|
151
|
+
if (isNoiseName(root.name))
|
|
152
|
+
score -= 1000;
|
|
153
|
+
return score;
|
|
154
|
+
}
|
|
155
|
+
export function buildSnapshotSegments(snapshotLines) {
|
|
156
|
+
const roots = [];
|
|
157
|
+
const stack = [];
|
|
158
|
+
for (const line of snapshotLines) {
|
|
159
|
+
stack.length = line.depth;
|
|
160
|
+
if (isPotentialSegmentRootLine(line)) {
|
|
161
|
+
const normalizedName = normalizeWhitespace(line.name.toLowerCase());
|
|
162
|
+
let duplicateAncestor;
|
|
163
|
+
for (let index = stack.length - 1; index >= 0; index -= 1) {
|
|
164
|
+
const ancestor = stack[index];
|
|
165
|
+
if (normalizedName.length > 0 &&
|
|
166
|
+
normalizeWhitespace(ancestor.name.toLowerCase()) === normalizedName &&
|
|
167
|
+
SNAPSHOT_SEGMENT_ROOT_ROLES.has(ancestor.role)) {
|
|
168
|
+
duplicateAncestor = ancestor;
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
if (!duplicateAncestor) {
|
|
173
|
+
roots.push(line);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
stack[line.depth] = line;
|
|
177
|
+
}
|
|
178
|
+
return roots.map((root, index) => {
|
|
179
|
+
let endIndexExclusive = snapshotLines.length;
|
|
180
|
+
for (let nextIndex = index + 1; nextIndex < roots.length; nextIndex += 1) {
|
|
181
|
+
const candidate = roots[nextIndex];
|
|
182
|
+
if (candidate.depth <= root.depth) {
|
|
183
|
+
endIndexExclusive = candidate.index;
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
const lines = snapshotLines.slice(root.index, endIndexExclusive);
|
|
188
|
+
const segment = {
|
|
189
|
+
endIndexExclusive,
|
|
190
|
+
lines,
|
|
191
|
+
root,
|
|
192
|
+
score: 0,
|
|
193
|
+
startIndex: root.index,
|
|
194
|
+
};
|
|
195
|
+
segment.score = scoreSegment(segment);
|
|
196
|
+
return segment;
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
export function choosePrimarySegment(segments) {
|
|
200
|
+
if (segments.length === 0)
|
|
201
|
+
return undefined;
|
|
202
|
+
return (segments.find((segment) => segment.root.role === "main" || segment.root.role === "article") ??
|
|
203
|
+
segments.find((segment) => segment.root.role === "heading" && segment.root.headingLevel === 1) ??
|
|
204
|
+
segments.find((segment) => segment.score >= 90) ??
|
|
205
|
+
[...segments].sort((left, right) => right.score - left.score || left.startIndex - right.startIndex)[0]);
|
|
206
|
+
}
|
|
207
|
+
export function chooseAdditionalSegments(segments, primary) {
|
|
208
|
+
if (!primary)
|
|
209
|
+
return [];
|
|
210
|
+
const seenNames = new Set([normalizeWhitespace(primary.root.name.toLowerCase())]);
|
|
211
|
+
const rankedCandidates = segments
|
|
212
|
+
.filter((segment) => segment !== primary && segment.score >= 45)
|
|
213
|
+
.sort((left, right) => {
|
|
214
|
+
const leftDistance = Math.abs(left.startIndex - primary.startIndex);
|
|
215
|
+
const rightDistance = Math.abs(right.startIndex - primary.startIndex);
|
|
216
|
+
if (leftDistance !== rightDistance)
|
|
217
|
+
return leftDistance - rightDistance;
|
|
218
|
+
if (right.score !== left.score)
|
|
219
|
+
return right.score - left.score;
|
|
220
|
+
return left.startIndex - right.startIndex;
|
|
221
|
+
});
|
|
222
|
+
const chosen = [];
|
|
223
|
+
for (const segment of rankedCandidates) {
|
|
224
|
+
if (chosen.length >= SNAPSHOT_MAX_ADDITIONAL_SECTIONS)
|
|
225
|
+
break;
|
|
226
|
+
if (isChromeSectionName(segment.root.name))
|
|
227
|
+
continue;
|
|
228
|
+
if (segment.root.role === "heading" && segment.root.name.length <= 2)
|
|
229
|
+
continue;
|
|
230
|
+
const nameKey = normalizeWhitespace(segment.root.name.toLowerCase());
|
|
231
|
+
if (nameKey && seenNames.has(nameKey))
|
|
232
|
+
continue;
|
|
233
|
+
chosen.push(segment);
|
|
234
|
+
if (nameKey)
|
|
235
|
+
seenNames.add(nameKey);
|
|
236
|
+
}
|
|
237
|
+
return chosen.sort((left, right) => left.startIndex - right.startIndex);
|
|
238
|
+
}
|
|
239
|
+
export function getMeaningfulSegmentLines(segment) {
|
|
240
|
+
return segment.lines.filter((line) => {
|
|
241
|
+
if (isNoiseSnapshotLine(line))
|
|
242
|
+
return false;
|
|
243
|
+
if (line.role === "generic" && !line.ref && line.name.length === 0)
|
|
244
|
+
return false;
|
|
245
|
+
if (line.role === "link" && line.name.length === 0)
|
|
246
|
+
return false;
|
|
247
|
+
return true;
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
function formatPreviewLine(line, baseDepth) {
|
|
251
|
+
const leadingWhitespace = (line.raw.match(/^\s*/) ?? [""])[0].length;
|
|
252
|
+
const stripChars = Math.min(leadingWhitespace, Math.max(0, baseDepth) * 2);
|
|
253
|
+
return truncateText(line.raw.slice(stripChars), SNAPSHOT_LINE_MAX_CHARS);
|
|
254
|
+
}
|
|
255
|
+
export function buildSegmentPreview(segment, maxLines) {
|
|
256
|
+
const meaningfulLines = getMeaningfulSegmentLines(segment);
|
|
257
|
+
if (meaningfulLines.length === 0) {
|
|
258
|
+
return { omittedCount: 0, refIds: [], lines: [] };
|
|
259
|
+
}
|
|
260
|
+
const previewLines = [];
|
|
261
|
+
const previewRefIds = new Set();
|
|
262
|
+
const seenPreviewKeys = new Set();
|
|
263
|
+
const rootDepth = segment.root.depth;
|
|
264
|
+
for (const line of meaningfulLines) {
|
|
265
|
+
if (previewLines.length >= maxLines)
|
|
266
|
+
break;
|
|
267
|
+
if (line !== segment.root) {
|
|
268
|
+
const relativeDepth = line.depth - rootDepth;
|
|
269
|
+
if (segment.root.role !== "heading" && relativeDepth > 2)
|
|
270
|
+
continue;
|
|
271
|
+
if (segment.root.name.length > 0 && line.name === segment.root.name && (line.role === "heading" || line.role === "link")) {
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
const key = `${line.role}:${line.name}:${line.ref ?? ""}:${line.depth}`;
|
|
276
|
+
if (seenPreviewKeys.has(key))
|
|
277
|
+
continue;
|
|
278
|
+
seenPreviewKeys.add(key);
|
|
279
|
+
previewLines.push(line);
|
|
280
|
+
if (line.ref)
|
|
281
|
+
previewRefIds.add(line.ref);
|
|
282
|
+
}
|
|
283
|
+
return {
|
|
284
|
+
omittedCount: Math.max(0, meaningfulLines.length - previewLines.length),
|
|
285
|
+
refIds: [...previewRefIds],
|
|
286
|
+
lines: previewLines.map((line) => formatPreviewLine(line, rootDepth)),
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
export function buildFallbackSnapshotOutline(snapshotLines) {
|
|
290
|
+
const selected = new Set();
|
|
291
|
+
for (let index = 0; index < snapshotLines.length && selected.size < 4; index += 1) {
|
|
292
|
+
if (!isNoiseSnapshotLine(snapshotLines[index]))
|
|
293
|
+
selected.add(index);
|
|
294
|
+
}
|
|
295
|
+
for (let index = 0; index < snapshotLines.length && selected.size < SNAPSHOT_FALLBACK_PREVIEW_MAX_LINES; index += 1) {
|
|
296
|
+
const line = snapshotLines[index];
|
|
297
|
+
if (isNoiseSnapshotLine(line))
|
|
298
|
+
continue;
|
|
299
|
+
if (SNAPSHOT_SIGNAL_ROLES.has(line.role) || line.ref || line.name.length > 0) {
|
|
300
|
+
selected.add(index);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
const chosenLines = [...selected]
|
|
304
|
+
.sort((left, right) => left - right)
|
|
305
|
+
.slice(0, SNAPSHOT_FALLBACK_PREVIEW_MAX_LINES)
|
|
306
|
+
.map((index) => snapshotLines[index]);
|
|
307
|
+
return {
|
|
308
|
+
omittedCount: Math.max(0, snapshotLines.length - chosenLines.length),
|
|
309
|
+
refIds: chosenLines.flatMap((line) => (line.ref ? [line.ref] : [])),
|
|
310
|
+
lines: chosenLines.map((line) => truncateText(line.raw, SNAPSHOT_LINE_MAX_CHARS)),
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
export function buildRefLineOrderMap(snapshotLines) {
|
|
314
|
+
const map = new Map();
|
|
315
|
+
for (const line of snapshotLines) {
|
|
316
|
+
if (!line.ref || map.has(line.ref))
|
|
317
|
+
continue;
|
|
318
|
+
map.set(line.ref, line.index);
|
|
319
|
+
}
|
|
320
|
+
return map;
|
|
321
|
+
}
|
|
322
|
+
export function canUseStructuredSnapshotPreview(snapshotLines, refEntries) {
|
|
323
|
+
if (snapshotLines.length === 0)
|
|
324
|
+
return false;
|
|
325
|
+
const linesWithRecognizedRoles = snapshotLines.filter((line) => line.role !== "unknown").length;
|
|
326
|
+
const linesWithNames = snapshotLines.filter((line) => line.name.length > 0).length;
|
|
327
|
+
const parsedRefIds = new Set(snapshotLines.flatMap((line) => (line.ref ? [line.ref] : [])));
|
|
328
|
+
return (linesWithRecognizedRoles >= Math.min(snapshotLines.length, 3) ||
|
|
329
|
+
linesWithNames >= Math.min(snapshotLines.length, 3) ||
|
|
330
|
+
parsedRefIds.size >= Math.min(refEntries.length, 3));
|
|
331
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Purpose: Persist full compacted snapshot payloads when model-facing output is shortened.
|
|
3
|
+
* Responsibilities: Write persistent or secure-temp snapshot spill files and merge spill retention metadata into the session artifact manifest.
|
|
4
|
+
* Scope: Snapshot spill artifact lifecycle only; preview planning and presentation text live in snapshot.ts and sibling modules.
|
|
5
|
+
* Usage: Snapshot presentation calls these helpers after deciding a snapshot is too large for inline output.
|
|
6
|
+
* Invariants/Assumptions: Explicit full-output paths are reported but not deleted here; retention state mirrors the backing storage scope.
|
|
7
|
+
*/
|
|
8
|
+
import { writePersistentSessionArtifactFile, writeSecureTempFile } from "../temp.js";
|
|
9
|
+
import { buildEvictedSessionArtifactEntries, formatSessionArtifactRetentionSummary, mergeSessionArtifactManifest, } from "./artifact-manifest.js";
|
|
10
|
+
const SNAPSHOT_SPILL_FILE_PREFIX = "pi-agent-browser-snapshot";
|
|
11
|
+
export async function writeSnapshotSpillFile(data, persistentArtifactStore) {
|
|
12
|
+
const options = {
|
|
13
|
+
content: JSON.stringify(data, null, 2),
|
|
14
|
+
prefix: SNAPSHOT_SPILL_FILE_PREFIX,
|
|
15
|
+
suffix: ".json",
|
|
16
|
+
};
|
|
17
|
+
if (persistentArtifactStore) {
|
|
18
|
+
const result = await writePersistentSessionArtifactFile({ ...options, store: persistentArtifactStore });
|
|
19
|
+
return { ...result, storageScope: "persistent-session" };
|
|
20
|
+
}
|
|
21
|
+
return { evictedArtifacts: [], path: await writeSecureTempFile(options), storageScope: "process-temp" };
|
|
22
|
+
}
|
|
23
|
+
export function applySnapshotArtifactManifest(options) {
|
|
24
|
+
if (!options.fullOutputPath || !options.spill)
|
|
25
|
+
return {};
|
|
26
|
+
const nowMs = Date.now();
|
|
27
|
+
const entries = [
|
|
28
|
+
{
|
|
29
|
+
command: options.command,
|
|
30
|
+
createdAtMs: nowMs,
|
|
31
|
+
kind: "spill",
|
|
32
|
+
path: options.fullOutputPath,
|
|
33
|
+
retentionState: options.spill.storageScope === "persistent-session" ? "live" : "ephemeral",
|
|
34
|
+
storageScope: options.spill.storageScope,
|
|
35
|
+
},
|
|
36
|
+
...buildEvictedSessionArtifactEntries(options.spill.evictedArtifacts, nowMs),
|
|
37
|
+
];
|
|
38
|
+
const artifactManifest = mergeSessionArtifactManifest({ base: options.baseManifest, entries, nowMs });
|
|
39
|
+
return artifactManifest ? { artifactManifest, artifactRetentionSummary: formatSessionArtifactRetentionSummary(artifactManifest) } : {};
|
|
40
|
+
}
|