@nuanu-ai/agentbrowse 0.2.29 → 0.2.31
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/README.md +3 -0
- package/dist/commands/extract-snapshot-sanitizer.d.ts +3 -0
- package/dist/commands/extract-snapshot-sanitizer.d.ts.map +1 -1
- package/dist/commands/extract-snapshot-sanitizer.js +33 -0
- package/dist/commands/extract-stagehand-executor.d.ts.map +1 -1
- package/dist/commands/extract-stagehand-executor.js +84 -20
- package/dist/commands/observe-inventory.d.ts +10 -0
- package/dist/commands/observe-inventory.d.ts.map +1 -1
- package/dist/commands/observe-inventory.js +388 -1
- package/dist/commands/observe.d.ts +1 -0
- package/dist/commands/observe.d.ts.map +1 -1
- package/dist/commands/observe.js +1 -1
- package/dist/commands/observe.test-harness.d.ts +1 -0
- package/dist/commands/observe.test-harness.d.ts.map +1 -1
- package/dist/commands/semantic-observe.d.ts +7 -1
- package/dist/commands/semantic-observe.d.ts.map +1 -1
- package/dist/commands/semantic-observe.js +609 -83
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -2
- package/dist/runtime-state.d.ts +47 -1
- package/dist/runtime-state.d.ts.map +1 -1
- package/dist/runtime-state.js +88 -2
- package/dist/secrets/protected-field-values.d.ts +2 -0
- package/dist/secrets/protected-field-values.d.ts.map +1 -1
- package/dist/secrets/protected-field-values.js +50 -17
- package/dist/secrets/protected-fill.d.ts.map +1 -1
- package/dist/secrets/protected-fill.js +6 -0
- package/dist/secrets/protected-value-adapters.d.ts +3 -0
- package/dist/secrets/protected-value-adapters.d.ts.map +1 -0
- package/dist/secrets/protected-value-adapters.js +39 -0
- package/dist/update-check.d.ts +14 -0
- package/dist/update-check.d.ts.map +1 -0
- package/dist/update-check.js +182 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -165,6 +165,9 @@ overrides.
|
|
|
165
165
|
Human-readable progress is written to `stderr`. Command results are written to
|
|
166
166
|
`stdout`.
|
|
167
167
|
|
|
168
|
+
When `launch` detects a newer npm release, it prints the reminder to `stderr`
|
|
169
|
+
without changing the JSON result written to `stdout`.
|
|
170
|
+
|
|
168
171
|
`observe()` and `extract()` responses expose where runtime work came from:
|
|
169
172
|
|
|
170
173
|
- top-level `source` shows the winning execution source, for example `dom` or `stagehand`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extract-snapshot-sanitizer.d.ts","sourceRoot":"","sources":["../../src/commands/extract-snapshot-sanitizer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"extract-snapshot-sanitizer.d.ts","sourceRoot":"","sources":["../../src/commands/extract-snapshot-sanitizer.ts"],"names":[],"mappings":"AAyEA,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAQhE;AA4BD,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GACjC,MAAM,CAcR"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
const SUSPICIOUS_LINE_LENGTH = 220;
|
|
2
2
|
const SUSPICIOUS_TOKEN_LENGTH = 120;
|
|
3
3
|
const MIN_MACHINE_PUNCTUATION_RATIO = 0.18;
|
|
4
|
+
const MAX_SCOPED_EXTRACT_LINES = 160;
|
|
5
|
+
const MAX_SCOPED_EXTRACT_CHARS = 12_000;
|
|
4
6
|
const SCRIPT_MARKERS = [
|
|
5
7
|
/\bwindow\./i,
|
|
6
8
|
/\bdocument\./i,
|
|
@@ -63,3 +65,34 @@ export function sanitizeExtractSnapshot(snapshot) {
|
|
|
63
65
|
});
|
|
64
66
|
return sanitized.some((line) => line.trim()) ? sanitized.join('\n') : snapshot;
|
|
65
67
|
}
|
|
68
|
+
function trimSnapshotToBudget(snapshot, options) {
|
|
69
|
+
const lines = snapshot.split(/\r?\n/).filter((line) => line.trim().length > 0);
|
|
70
|
+
const kept = [];
|
|
71
|
+
let totalChars = 0;
|
|
72
|
+
for (const line of lines) {
|
|
73
|
+
const nextChars = totalChars + line.length + (kept.length > 0 ? 1 : 0);
|
|
74
|
+
if (kept.length >= options.maxLines || nextChars > options.maxChars) {
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
kept.push(line);
|
|
78
|
+
totalChars = nextChars;
|
|
79
|
+
}
|
|
80
|
+
if (kept.length === 0) {
|
|
81
|
+
return snapshot;
|
|
82
|
+
}
|
|
83
|
+
const trimmed = kept.join('\n');
|
|
84
|
+
return trimmed.length >= Math.floor(snapshot.length * 0.35) ? trimmed : snapshot;
|
|
85
|
+
}
|
|
86
|
+
export function budgetExtractSnapshot(snapshot, options = {}) {
|
|
87
|
+
if (!options.scoped) {
|
|
88
|
+
return snapshot;
|
|
89
|
+
}
|
|
90
|
+
const lines = snapshot.split(/\r?\n/);
|
|
91
|
+
if (lines.length <= MAX_SCOPED_EXTRACT_LINES && snapshot.length <= MAX_SCOPED_EXTRACT_CHARS) {
|
|
92
|
+
return snapshot;
|
|
93
|
+
}
|
|
94
|
+
return trimSnapshotToBudget(snapshot, {
|
|
95
|
+
maxLines: MAX_SCOPED_EXTRACT_LINES,
|
|
96
|
+
maxChars: MAX_SCOPED_EXTRACT_CHARS,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extract-stagehand-executor.d.ts","sourceRoot":"","sources":["../../src/commands/extract-stagehand-executor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAI5C,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD,OAAO,EAA8B,KAAK,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"extract-stagehand-executor.d.ts","sourceRoot":"","sources":["../../src/commands/extract-stagehand-executor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAI5C,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD,OAAO,EAA8B,KAAK,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAK9F,MAAM,MAAM,yBAAyB,GAAG,iBAAiB,GAAG;IAC1D,IAAI,EAAE,OAAO,CAAC;IACd,UAAU,EAAE,mBAAmB,CAAC;CACjC,CAAC;AAiEF,wBAAsB,uBAAuB,CAAC,IAAI,EAAE;IAClD,OAAO,EAAE,aAAa,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC;IAClB,IAAI,EAAE,IAAI,CAAC;IACX,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAwFrC"}
|
|
@@ -1,10 +1,41 @@
|
|
|
1
1
|
import { extract as runExtract } from '@browserbasehq/stagehand/lib/inference.js';
|
|
2
2
|
import { v3Logger } from '@browserbasehq/stagehand/lib/v3/logger.js';
|
|
3
3
|
import { captureHybridSnapshot } from '@browserbasehq/stagehand/lib/v3/understudy/a11y/snapshot/index.js';
|
|
4
|
-
import { incrementMetric } from '../runtime-state.js';
|
|
4
|
+
import { incrementMetric, recordLlmUsage, recordPayloadBudget } from '../runtime-state.js';
|
|
5
5
|
import { stagehandRuntimeResolution } from '../runtime-resolution.js';
|
|
6
6
|
import { withStagehand } from '../stagehand-runtime.js';
|
|
7
|
-
import {
|
|
7
|
+
import { readLocatorOuterHtml } from './descriptor-validation.js';
|
|
8
|
+
import { budgetExtractSnapshot, sanitizeExtractSnapshot } from './extract-snapshot-sanitizer.js';
|
|
9
|
+
const SCOPED_EXTRACT_MIRROR_SELECTOR = '#agentbrowse-scope';
|
|
10
|
+
async function mirrorScopedSnapshotPage(page, selector) {
|
|
11
|
+
if (!selector || selector === SCOPED_EXTRACT_MIRROR_SELECTOR) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
const locator = page.locator(selector);
|
|
15
|
+
const first = locator.first();
|
|
16
|
+
const count = typeof first.count === 'function' ? await first.count().catch(() => 0) : 1;
|
|
17
|
+
if (count === 0) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
let scopedHtml = await readLocatorOuterHtml(first).catch(() => null);
|
|
21
|
+
if (!scopedHtml) {
|
|
22
|
+
scopedHtml = await first
|
|
23
|
+
.evaluate((element) => (element instanceof Element ? element.outerHTML : null))
|
|
24
|
+
.catch(() => null);
|
|
25
|
+
}
|
|
26
|
+
if (!scopedHtml) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
const scratchPage = await page.context().newPage();
|
|
30
|
+
await scratchPage.setContent(`<!doctype html><html lang="en"><body><div id="agentbrowse-scope">${scopedHtml}</div></body></html>`);
|
|
31
|
+
return {
|
|
32
|
+
page: scratchPage,
|
|
33
|
+
focusSelector: SCOPED_EXTRACT_MIRROR_SELECTOR,
|
|
34
|
+
cleanup: async () => {
|
|
35
|
+
await scratchPage.close().catch(() => undefined);
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
}
|
|
8
39
|
export async function executeStagehandExtract(args) {
|
|
9
40
|
const { session, instruction, schema, page, selector, degradationReason } = args;
|
|
10
41
|
const data = await withStagehand(session, async (stagehand) => {
|
|
@@ -21,24 +52,57 @@ export async function executeStagehandExtract(args) {
|
|
|
21
52
|
});
|
|
22
53
|
}
|
|
23
54
|
const extractPage = await resolvePage.call(internalStagehand, page);
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
55
|
+
let snapshotPage = extractPage;
|
|
56
|
+
let focusSelector = selector?.replace(/^xpath=/i, '') ?? '';
|
|
57
|
+
let cleanupMirroredSnapshot = null;
|
|
58
|
+
try {
|
|
59
|
+
if (selector) {
|
|
60
|
+
const mirroredSnapshot = await mirrorScopedSnapshotPage(page, selector);
|
|
61
|
+
if (mirroredSnapshot) {
|
|
62
|
+
cleanupMirroredSnapshot = mirroredSnapshot.cleanup;
|
|
63
|
+
snapshotPage = await resolvePage.call(internalStagehand, mirroredSnapshot.page);
|
|
64
|
+
focusSelector = mirroredSnapshot.focusSelector;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const snapshot = await captureHybridSnapshot(snapshotPage, {
|
|
68
|
+
experimental: internalStagehand.experimental ?? false,
|
|
69
|
+
focusSelector,
|
|
70
|
+
});
|
|
71
|
+
recordPayloadBudget(session, {
|
|
72
|
+
extractSnapshotLinesSeen: snapshot.combinedTree.split(/\r?\n/).length,
|
|
73
|
+
});
|
|
74
|
+
const sanitizedTree = sanitizeExtractSnapshot(snapshot.combinedTree);
|
|
75
|
+
const budgetedTree = budgetExtractSnapshot(sanitizedTree, {
|
|
76
|
+
scoped: Boolean(selector),
|
|
77
|
+
});
|
|
78
|
+
recordPayloadBudget(session, {
|
|
79
|
+
extractSnapshotLinesSent: budgetedTree.split(/\r?\n/).length,
|
|
80
|
+
});
|
|
81
|
+
const extractionResponse = await runExtract({
|
|
82
|
+
instruction,
|
|
83
|
+
domElements: budgetedTree,
|
|
84
|
+
schema: schema,
|
|
85
|
+
llmClient: internalStagehand.llmClient,
|
|
86
|
+
userProvidedInstructions: internalStagehand.opts?.systemPrompt ?? '',
|
|
87
|
+
logger: v3Logger,
|
|
88
|
+
logInferenceToFile: internalStagehand.logInferenceToFile ?? false,
|
|
89
|
+
});
|
|
90
|
+
const { metadata: _metadata, prompt_tokens: promptTokens, completion_tokens: completionTokens, reasoning_tokens: reasoningTokens, cached_input_tokens: cachedInputTokens, inference_time_ms: _inferenceTimeMs, ...result } = extractionResponse;
|
|
91
|
+
recordLlmUsage(session, {
|
|
92
|
+
purpose: 'browse.extract',
|
|
93
|
+
inputChars: budgetedTree.length,
|
|
94
|
+
promptTokens: typeof promptTokens === 'number' ? promptTokens : undefined,
|
|
95
|
+
completionTokens: typeof completionTokens === 'number' ? completionTokens : undefined,
|
|
96
|
+
cachedInputTokens: typeof cachedInputTokens === 'number' ? cachedInputTokens : undefined,
|
|
97
|
+
reasoningTokens: typeof reasoningTokens === 'number' ? reasoningTokens : undefined,
|
|
98
|
+
});
|
|
99
|
+
return result;
|
|
100
|
+
}
|
|
101
|
+
finally {
|
|
102
|
+
if (cleanupMirroredSnapshot) {
|
|
103
|
+
await cleanupMirroredSnapshot().catch(() => undefined);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
42
106
|
});
|
|
43
107
|
return {
|
|
44
108
|
resolvedBy: 'stagehand-extract',
|
|
@@ -93,7 +93,16 @@ type StructuredCellVariantEvidence = {
|
|
|
93
93
|
hasSeatColumnAttribute?: boolean;
|
|
94
94
|
hasDateMetadata?: boolean;
|
|
95
95
|
};
|
|
96
|
+
export type DirectionalControlFallbackPosition = 'leading' | 'trailing' | 'upper' | 'lower';
|
|
97
|
+
export type DirectionalControlFallbackEvidence = {
|
|
98
|
+
kind?: string;
|
|
99
|
+
role?: string;
|
|
100
|
+
groupLabel?: string;
|
|
101
|
+
anchorText?: string;
|
|
102
|
+
position?: DirectionalControlFallbackPosition;
|
|
103
|
+
};
|
|
96
104
|
export declare function inferStructuredCellVariantFromEvidence(evidence: StructuredCellVariantEvidence): 'date-cell' | 'seat-cell' | 'grid-cell' | undefined;
|
|
105
|
+
export declare function inferDirectionalControlFallbackFromEvidence(evidence: DirectionalControlFallbackEvidence): string | undefined;
|
|
97
106
|
export declare function readStagehandLocatorSnapshot(locator: Locator): Promise<StagehandLocatorSnapshot>;
|
|
98
107
|
declare function readStagehandDomFactsInBrowser(element: Element): StagehandDomFacts | null;
|
|
99
108
|
declare function readStagehandDomFacts(locator: Locator): Promise<StagehandDomFacts | null>;
|
|
@@ -114,6 +123,7 @@ export declare function collectDomTargets(page: {
|
|
|
114
123
|
export declare const __testDomTargetCollection: {
|
|
115
124
|
collectDomTargetsFromDocument: typeof collectDomTargetsFromDocument;
|
|
116
125
|
inferStructuredCellVariantFromEvidence: typeof inferStructuredCellVariantFromEvidence;
|
|
126
|
+
inferDirectionalControlFallbackFromEvidence: typeof inferDirectionalControlFallbackFromEvidence;
|
|
117
127
|
locatorDomSignatureScript: string;
|
|
118
128
|
};
|
|
119
129
|
export declare const __testStagehandDescriptor: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"observe-inventory.d.ts","sourceRoot":"","sources":["../../src/commands/observe-inventory.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"observe-inventory.d.ts","sourceRoot":"","sources":["../../src/commands/observe-inventory.ts"],"names":[],"mappings":"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"}
|
|
@@ -31,7 +31,78 @@ export function inferStructuredCellVariantFromEvidence(evidence) {
|
|
|
31
31
|
}
|
|
32
32
|
return undefined;
|
|
33
33
|
}
|
|
34
|
+
export function inferDirectionalControlFallbackFromEvidence(evidence) {
|
|
35
|
+
const normalize = (value) => {
|
|
36
|
+
const normalized = (value ?? '').replace(/\s+/g, ' ').trim();
|
|
37
|
+
return normalized || undefined;
|
|
38
|
+
};
|
|
39
|
+
const normalizedKind = normalize(evidence.kind)?.toLowerCase();
|
|
40
|
+
const normalizedRole = normalize(evidence.role)?.toLowerCase();
|
|
41
|
+
const buttonLike = normalizedKind === 'button' ||
|
|
42
|
+
normalizedRole === 'button' ||
|
|
43
|
+
(normalizedKind === 'input' && normalizedRole === 'button');
|
|
44
|
+
if (!buttonLike) {
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
const position = normalize(evidence.position)?.toLowerCase();
|
|
48
|
+
const anchorText = normalize(evidence.anchorText);
|
|
49
|
+
const groupLabel = normalize(evidence.groupLabel);
|
|
50
|
+
if (!position || !anchorText) {
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
const monthYearLike = /\b(?:jan(?:uary)?|feb(?:ruary)?|mar(?:ch)?|apr(?:il)?|may|jun(?:e)?|jul(?:y)?|aug(?:ust)?|sep(?:t(?:ember)?)?|oct(?:ober)?|nov(?:ember)?|dec(?:ember)?|январ|феврал|март|апрел|ма[йя]|июн|июл|август|сентябр|октябр|ноябр|декабр)\b/i.test(anchorText);
|
|
54
|
+
if (monthYearLike && (position === 'leading' || position === 'trailing')) {
|
|
55
|
+
return position === 'leading' ? 'Previous month' : 'Next month';
|
|
56
|
+
}
|
|
57
|
+
const counterLike = /^\d{1,3}$/.test(anchorText);
|
|
58
|
+
if (counterLike && groupLabel && (position === 'leading' || position === 'trailing')) {
|
|
59
|
+
const subject = groupLabel.toLowerCase();
|
|
60
|
+
return position === 'leading' ? `Decrease ${subject}` : `Increase ${subject}`;
|
|
61
|
+
}
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
34
64
|
const INFER_STRUCTURED_CELL_VARIANT_HELPER_SCRIPT = `const inferStructuredCellVariantFromEvidence = ${inferStructuredCellVariantFromEvidence.toString()};`;
|
|
65
|
+
const INFER_DIRECTIONAL_CONTROL_FALLBACK_HELPER_SCRIPT = String.raw `
|
|
66
|
+
const inferDirectionalControlFallbackFromEvidence = (evidence) => {
|
|
67
|
+
const normalizeDirectionalControlFallbackValue = (value) => {
|
|
68
|
+
const normalized = (value || '').replace(/\s+/g, ' ').trim();
|
|
69
|
+
return normalized || undefined;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const normalizedKind = normalizeDirectionalControlFallbackValue(evidence?.kind)?.toLowerCase();
|
|
73
|
+
const normalizedRole = normalizeDirectionalControlFallbackValue(evidence?.role)?.toLowerCase();
|
|
74
|
+
const buttonLike =
|
|
75
|
+
normalizedKind === 'button' ||
|
|
76
|
+
normalizedRole === 'button' ||
|
|
77
|
+
(normalizedKind === 'input' && normalizedRole === 'button');
|
|
78
|
+
if (!buttonLike) {
|
|
79
|
+
return undefined;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const position = normalizeDirectionalControlFallbackValue(evidence?.position)?.toLowerCase();
|
|
83
|
+
const anchorText = normalizeDirectionalControlFallbackValue(evidence?.anchorText);
|
|
84
|
+
const groupLabel = normalizeDirectionalControlFallbackValue(evidence?.groupLabel);
|
|
85
|
+
if (!position || !anchorText) {
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const monthYearLike =
|
|
90
|
+
/\b(?:jan(?:uary)?|feb(?:ruary)?|mar(?:ch)?|apr(?:il)?|may|jun(?:e)?|jul(?:y)?|aug(?:ust)?|sep(?:t(?:ember)?)?|oct(?:ober)?|nov(?:ember)?|dec(?:ember)?|январ|феврал|март|апрел|ма[йя]|июн|июл|август|сентябр|октябр|ноябр|декабр)\b/i.test(
|
|
91
|
+
anchorText
|
|
92
|
+
);
|
|
93
|
+
if (monthYearLike && (position === 'leading' || position === 'trailing')) {
|
|
94
|
+
return position === 'leading' ? 'Previous month' : 'Next month';
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const counterLike = /^\d{1,3}$/.test(anchorText);
|
|
98
|
+
if (counterLike && groupLabel && (position === 'leading' || position === 'trailing')) {
|
|
99
|
+
const subject = groupLabel.toLowerCase();
|
|
100
|
+
return position === 'leading' ? 'Decrease ' + subject : 'Increase ' + subject;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return undefined;
|
|
104
|
+
};
|
|
105
|
+
`;
|
|
35
106
|
function sleep(ms) {
|
|
36
107
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
37
108
|
}
|
|
@@ -352,6 +423,7 @@ async function collectDomTargetsFromDocument(context, options) {
|
|
|
352
423
|
${TRANSPARENT_ACTIONABLE_CONTROL_HELPER_SCRIPT}
|
|
353
424
|
${OBSERVE_DOM_LABEL_CONTRACT_HELPER_SCRIPT}
|
|
354
425
|
${INFER_STRUCTURED_CELL_VARIANT_HELPER_SCRIPT}
|
|
426
|
+
${INFER_DIRECTIONAL_CONTROL_FALLBACK_HELPER_SCRIPT}
|
|
355
427
|
|
|
356
428
|
const normalizeDescriptorText = (value) => observedNormalizeDescriptorText(value);
|
|
357
429
|
|
|
@@ -1144,6 +1216,315 @@ async function collectDomTargetsFromDocument(context, options) {
|
|
|
1144
1216
|
return composedClosest(element, itemSelector) || undefined;
|
|
1145
1217
|
};
|
|
1146
1218
|
|
|
1219
|
+
const directionalControlSelector =
|
|
1220
|
+
'button, [role="button"], input[type="button"], input[type="submit"], input[type="reset"]';
|
|
1221
|
+
const weakDirectionalTextRe = /^[+\-<>‹›«»←→↑↓]+$/;
|
|
1222
|
+
|
|
1223
|
+
const isButtonLikeDirectionalElement = (element) => {
|
|
1224
|
+
if (!isHTMLElementNode(element)) {
|
|
1225
|
+
return false;
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
const tag = element.tagName.toLowerCase();
|
|
1229
|
+
const role = (element.getAttribute('role') || '').trim().toLowerCase();
|
|
1230
|
+
if (tag === 'button') {
|
|
1231
|
+
return true;
|
|
1232
|
+
}
|
|
1233
|
+
if (tag === 'input') {
|
|
1234
|
+
return isButtonLikeInput(element);
|
|
1235
|
+
}
|
|
1236
|
+
return role === 'button';
|
|
1237
|
+
};
|
|
1238
|
+
|
|
1239
|
+
const isWeakDirectionalText = (value) => {
|
|
1240
|
+
const normalized = normalizeDescriptorText(value || '');
|
|
1241
|
+
return Boolean(normalized) && weakDirectionalTextRe.test(normalized);
|
|
1242
|
+
};
|
|
1243
|
+
|
|
1244
|
+
const directionalButtonsOf = (scope) => {
|
|
1245
|
+
if (!isHTMLElementNode(scope)) {
|
|
1246
|
+
return [];
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1249
|
+
return Array.from(scope.querySelectorAll(directionalControlSelector))
|
|
1250
|
+
.filter((candidate) => isHTMLElementNode(candidate))
|
|
1251
|
+
.filter((candidate) => isVisible(candidate))
|
|
1252
|
+
.filter((candidate) => isButtonLikeDirectionalElement(candidate))
|
|
1253
|
+
.slice(0, 6);
|
|
1254
|
+
};
|
|
1255
|
+
|
|
1256
|
+
const directionalChildTextCandidatesOf = (scope, exclude = []) => {
|
|
1257
|
+
if (!isHTMLElementNode(scope)) {
|
|
1258
|
+
return [];
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
const excluded = exclude.filter((candidate) => isHTMLElementNode(candidate));
|
|
1262
|
+
const candidates = [];
|
|
1263
|
+
for (const child of Array.from(scope.children).slice(0, 12)) {
|
|
1264
|
+
if (!isHTMLElementNode(child) || !isVisible(child)) {
|
|
1265
|
+
continue;
|
|
1266
|
+
}
|
|
1267
|
+
if (
|
|
1268
|
+
excluded.some(
|
|
1269
|
+
(candidate) =>
|
|
1270
|
+
child === candidate || child.contains(candidate) || candidate.contains(child)
|
|
1271
|
+
)
|
|
1272
|
+
) {
|
|
1273
|
+
continue;
|
|
1274
|
+
}
|
|
1275
|
+
if (isButtonLikeDirectionalElement(child)) {
|
|
1276
|
+
continue;
|
|
1277
|
+
}
|
|
1278
|
+
if (directionalButtonsOf(child).length > 0) {
|
|
1279
|
+
continue;
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
const text = normalizeDescriptorText(textOf(child, { container: true }) || '');
|
|
1283
|
+
if (!text || text.length > 48) {
|
|
1284
|
+
continue;
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
candidates.push({
|
|
1288
|
+
element: child,
|
|
1289
|
+
text,
|
|
1290
|
+
rect: child.getBoundingClientRect(),
|
|
1291
|
+
});
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
return candidates;
|
|
1295
|
+
};
|
|
1296
|
+
|
|
1297
|
+
const directionalAxisOf = (buttons) => {
|
|
1298
|
+
if (buttons.length !== 2) {
|
|
1299
|
+
return undefined;
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
const firstRect = buttons[0].getBoundingClientRect();
|
|
1303
|
+
const secondRect = buttons[1].getBoundingClientRect();
|
|
1304
|
+
const deltaX = Math.abs(
|
|
1305
|
+
firstRect.left + firstRect.width / 2 - (secondRect.left + secondRect.width / 2)
|
|
1306
|
+
);
|
|
1307
|
+
const deltaY = Math.abs(
|
|
1308
|
+
firstRect.top + firstRect.height / 2 - (secondRect.top + secondRect.height / 2)
|
|
1309
|
+
);
|
|
1310
|
+
return deltaX >= deltaY ? 'horizontal' : 'vertical';
|
|
1311
|
+
};
|
|
1312
|
+
|
|
1313
|
+
const orderedDirectionalButtonsOf = (buttons, axis) => {
|
|
1314
|
+
return [...buttons].sort((left, right) => {
|
|
1315
|
+
const leftRect = left.getBoundingClientRect();
|
|
1316
|
+
const rightRect = right.getBoundingClientRect();
|
|
1317
|
+
return axis === 'vertical'
|
|
1318
|
+
? leftRect.top - rightRect.top
|
|
1319
|
+
: leftRect.left - rightRect.left;
|
|
1320
|
+
});
|
|
1321
|
+
};
|
|
1322
|
+
|
|
1323
|
+
const directionalPositionOf = (element, orderedButtons, axis) => {
|
|
1324
|
+
if (orderedButtons.length !== 2) {
|
|
1325
|
+
return undefined;
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
if (orderedButtons[0] === element) {
|
|
1329
|
+
return axis === 'vertical' ? 'upper' : 'leading';
|
|
1330
|
+
}
|
|
1331
|
+
if (orderedButtons[1] === element) {
|
|
1332
|
+
return axis === 'vertical' ? 'lower' : 'trailing';
|
|
1333
|
+
}
|
|
1334
|
+
return undefined;
|
|
1335
|
+
};
|
|
1336
|
+
|
|
1337
|
+
const directionalAnchorCandidateOf = (cluster, orderedButtons, axis) => {
|
|
1338
|
+
if (!isHTMLElementNode(cluster) || orderedButtons.length !== 2) {
|
|
1339
|
+
return undefined;
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
const firstRect = orderedButtons[0].getBoundingClientRect();
|
|
1343
|
+
const secondRect = orderedButtons[1].getBoundingClientRect();
|
|
1344
|
+
const midpointX =
|
|
1345
|
+
(firstRect.left + firstRect.width / 2 + (secondRect.left + secondRect.width / 2)) / 2;
|
|
1346
|
+
const midpointY =
|
|
1347
|
+
(firstRect.top + firstRect.height / 2 + (secondRect.top + secondRect.height / 2)) / 2;
|
|
1348
|
+
|
|
1349
|
+
const candidates = directionalChildTextCandidatesOf(cluster, orderedButtons)
|
|
1350
|
+
.filter((candidate) => {
|
|
1351
|
+
const centerX = candidate.rect.left + candidate.rect.width / 2;
|
|
1352
|
+
const centerY = candidate.rect.top + candidate.rect.height / 2;
|
|
1353
|
+
if (axis === 'vertical') {
|
|
1354
|
+
return (
|
|
1355
|
+
centerY >= Math.min(midpointY, secondRect.top + secondRect.height / 2) - 40 &&
|
|
1356
|
+
centerY <= Math.max(midpointY, firstRect.top + firstRect.height / 2) + 40 &&
|
|
1357
|
+
Math.abs(centerX - midpointX) <= Math.max(40, firstRect.width * 1.5)
|
|
1358
|
+
);
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
return (
|
|
1362
|
+
centerX >= Math.min(firstRect.left + firstRect.width / 2, midpointX) - 40 &&
|
|
1363
|
+
centerX <= Math.max(secondRect.left + secondRect.width / 2, midpointX) + 40 &&
|
|
1364
|
+
Math.abs(centerY - midpointY) <= Math.max(32, firstRect.height * 1.5)
|
|
1365
|
+
);
|
|
1366
|
+
})
|
|
1367
|
+
.sort((left, right) => {
|
|
1368
|
+
const leftCenterX = left.rect.left + left.rect.width / 2;
|
|
1369
|
+
const leftCenterY = left.rect.top + left.rect.height / 2;
|
|
1370
|
+
const rightCenterX = right.rect.left + right.rect.width / 2;
|
|
1371
|
+
const rightCenterY = right.rect.top + right.rect.height / 2;
|
|
1372
|
+
const leftDistance = Math.hypot(leftCenterX - midpointX, leftCenterY - midpointY);
|
|
1373
|
+
const rightDistance = Math.hypot(rightCenterX - midpointX, rightCenterY - midpointY);
|
|
1374
|
+
return leftDistance - rightDistance;
|
|
1375
|
+
});
|
|
1376
|
+
|
|
1377
|
+
return candidates[0];
|
|
1378
|
+
};
|
|
1379
|
+
|
|
1380
|
+
const stepperGroupLabelOf = (element, cluster, axis, anchorText) => {
|
|
1381
|
+
const scopes = [];
|
|
1382
|
+
const parent = composedParentElement(cluster);
|
|
1383
|
+
const grandParent = composedParentElement(parent);
|
|
1384
|
+
const item = itemOf(element);
|
|
1385
|
+
|
|
1386
|
+
for (const scope of [parent, item, grandParent]) {
|
|
1387
|
+
if (
|
|
1388
|
+
isHTMLElementNode(scope) &&
|
|
1389
|
+
scope !== cluster &&
|
|
1390
|
+
!scopes.includes(scope)
|
|
1391
|
+
) {
|
|
1392
|
+
scopes.push(scope);
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1396
|
+
const anchorMonthLike = Boolean(
|
|
1397
|
+
inferDirectionalControlFallbackFromEvidence({
|
|
1398
|
+
kind: 'button',
|
|
1399
|
+
anchorText,
|
|
1400
|
+
position: 'leading',
|
|
1401
|
+
})
|
|
1402
|
+
);
|
|
1403
|
+
|
|
1404
|
+
for (const scope of scopes) {
|
|
1405
|
+
const scopeRect = cluster.getBoundingClientRect();
|
|
1406
|
+
const clusterCenterX = scopeRect.left + scopeRect.width / 2;
|
|
1407
|
+
const clusterCenterY = scopeRect.top + scopeRect.height / 2;
|
|
1408
|
+
const ranked = directionalChildTextCandidatesOf(scope, [cluster])
|
|
1409
|
+
.filter((candidate) => candidate.text !== anchorText)
|
|
1410
|
+
.filter((candidate) => !/^\d{1,3}$/.test(candidate.text))
|
|
1411
|
+
.filter(
|
|
1412
|
+
(candidate) =>
|
|
1413
|
+
!Boolean(
|
|
1414
|
+
inferDirectionalControlFallbackFromEvidence({
|
|
1415
|
+
kind: 'button',
|
|
1416
|
+
anchorText: candidate.text,
|
|
1417
|
+
position: 'leading',
|
|
1418
|
+
})
|
|
1419
|
+
) || !anchorMonthLike
|
|
1420
|
+
)
|
|
1421
|
+
.sort((left, right) => {
|
|
1422
|
+
const leftRect = left.rect;
|
|
1423
|
+
const rightRect = right.rect;
|
|
1424
|
+
const leftCenterX = leftRect.left + leftRect.width / 2;
|
|
1425
|
+
const leftCenterY = leftRect.top + leftRect.height / 2;
|
|
1426
|
+
const rightCenterX = rightRect.left + rightRect.width / 2;
|
|
1427
|
+
const rightCenterY = rightRect.top + rightRect.height / 2;
|
|
1428
|
+
const leftBias =
|
|
1429
|
+
axis === 'vertical'
|
|
1430
|
+
? leftRect.bottom <= scopeRect.top + 16
|
|
1431
|
+
? 0
|
|
1432
|
+
: leftRect.right <= scopeRect.left + 16
|
|
1433
|
+
? 1
|
|
1434
|
+
: 2
|
|
1435
|
+
: leftRect.right <= scopeRect.left + 16
|
|
1436
|
+
? 0
|
|
1437
|
+
: leftRect.bottom <= scopeRect.top + 16
|
|
1438
|
+
? 1
|
|
1439
|
+
: 2;
|
|
1440
|
+
const rightBias =
|
|
1441
|
+
axis === 'vertical'
|
|
1442
|
+
? rightRect.bottom <= scopeRect.top + 16
|
|
1443
|
+
? 0
|
|
1444
|
+
: rightRect.right <= scopeRect.left + 16
|
|
1445
|
+
? 1
|
|
1446
|
+
: 2
|
|
1447
|
+
: rightRect.right <= scopeRect.left + 16
|
|
1448
|
+
? 0
|
|
1449
|
+
: rightRect.bottom <= scopeRect.top + 16
|
|
1450
|
+
? 1
|
|
1451
|
+
: 2;
|
|
1452
|
+
if (leftBias !== rightBias) {
|
|
1453
|
+
return leftBias - rightBias;
|
|
1454
|
+
}
|
|
1455
|
+
const leftDistance = Math.hypot(leftCenterX - clusterCenterX, leftCenterY - clusterCenterY);
|
|
1456
|
+
const rightDistance = Math.hypot(rightCenterX - clusterCenterX, rightCenterY - clusterCenterY);
|
|
1457
|
+
if (leftDistance !== rightDistance) {
|
|
1458
|
+
return leftDistance - rightDistance;
|
|
1459
|
+
}
|
|
1460
|
+
return left.text.length - right.text.length;
|
|
1461
|
+
});
|
|
1462
|
+
|
|
1463
|
+
const subject = ranked[0]?.text;
|
|
1464
|
+
if (subject) {
|
|
1465
|
+
return subject;
|
|
1466
|
+
}
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
return undefined;
|
|
1470
|
+
};
|
|
1471
|
+
|
|
1472
|
+
const directionalControlFallbackLabelOf = (element, directFallbackLabel) => {
|
|
1473
|
+
if (!isButtonLikeDirectionalElement(element)) {
|
|
1474
|
+
return undefined;
|
|
1475
|
+
}
|
|
1476
|
+
if (directFallbackLabel && !isWeakDirectionalText(directFallbackLabel)) {
|
|
1477
|
+
return undefined;
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
let current = composedParentElement(element);
|
|
1481
|
+
let depth = 0;
|
|
1482
|
+
while (current && depth < 4) {
|
|
1483
|
+
if (!isHTMLElementNode(current) || !isVisible(current)) {
|
|
1484
|
+
current = composedParentElement(current);
|
|
1485
|
+
depth += 1;
|
|
1486
|
+
continue;
|
|
1487
|
+
}
|
|
1488
|
+
|
|
1489
|
+
const buttons = directionalButtonsOf(current);
|
|
1490
|
+
if (buttons.length !== 2 || !buttons.includes(element)) {
|
|
1491
|
+
current = composedParentElement(current);
|
|
1492
|
+
depth += 1;
|
|
1493
|
+
continue;
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
const axis = directionalAxisOf(buttons);
|
|
1497
|
+
if (!axis) {
|
|
1498
|
+
return undefined;
|
|
1499
|
+
}
|
|
1500
|
+
const orderedButtons = orderedDirectionalButtonsOf(buttons, axis);
|
|
1501
|
+
const position = directionalPositionOf(element, orderedButtons, axis);
|
|
1502
|
+
const anchorCandidate = directionalAnchorCandidateOf(current, orderedButtons, axis);
|
|
1503
|
+
const anchorText = anchorCandidate?.text;
|
|
1504
|
+
if (!position || !anchorText) {
|
|
1505
|
+
return undefined;
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1508
|
+
const groupLabel = /^\d{1,3}$/.test(anchorText)
|
|
1509
|
+
? stepperGroupLabelOf(element, current, axis, anchorText)
|
|
1510
|
+
: undefined;
|
|
1511
|
+
const fallbackLabel = inferDirectionalControlFallbackFromEvidence({
|
|
1512
|
+
kind: element.tagName.toLowerCase(),
|
|
1513
|
+
role: element.getAttribute('role')?.trim() || undefined,
|
|
1514
|
+
groupLabel,
|
|
1515
|
+
anchorText,
|
|
1516
|
+
position,
|
|
1517
|
+
});
|
|
1518
|
+
if (fallbackLabel) {
|
|
1519
|
+
return fallbackLabel;
|
|
1520
|
+
}
|
|
1521
|
+
|
|
1522
|
+
return undefined;
|
|
1523
|
+
}
|
|
1524
|
+
|
|
1525
|
+
return undefined;
|
|
1526
|
+
};
|
|
1527
|
+
|
|
1147
1528
|
const normalizeText = (value) => (value || '').replace(/\s+/g, ' ').trim().toLowerCase();
|
|
1148
1529
|
|
|
1149
1530
|
const VALIDATION_CLASS_RE = /\b(?:error|invalid|warning|danger|alert|failed)\b/i;
|
|
@@ -2192,7 +2573,12 @@ async function collectDomTargetsFromDocument(context, options) {
|
|
|
2192
2573
|
(isHTMLElementNode(overlaySurface) ? overlaySurface : localSurface || selfSurface);
|
|
2193
2574
|
const surfaceSelectors = surfaceSelectorsOf(element, localSurface || selfSurface);
|
|
2194
2575
|
const structure = visualSeatGrid?.structure || inferStructuredCell(element, surface);
|
|
2195
|
-
const
|
|
2576
|
+
const directFallbackLabel = explicitLabelOf(element) || looseFieldLabelOf(element);
|
|
2577
|
+
const directionalFallbackLabel = directionalControlFallbackLabelOf(
|
|
2578
|
+
element,
|
|
2579
|
+
directFallbackLabel
|
|
2580
|
+
);
|
|
2581
|
+
const fallbackLabel = directionalFallbackLabel || directFallbackLabel;
|
|
2196
2582
|
const currentValue = popupCurrentValueOf(element);
|
|
2197
2583
|
const role = inferRole(element);
|
|
2198
2584
|
const surfaceKind = visualSeatGrid?.surfaceKind || surfaceKindOf(surface);
|
|
@@ -2681,6 +3067,7 @@ export async function collectDomTargets(page, options) {
|
|
|
2681
3067
|
export const __testDomTargetCollection = {
|
|
2682
3068
|
collectDomTargetsFromDocument,
|
|
2683
3069
|
inferStructuredCellVariantFromEvidence,
|
|
3070
|
+
inferDirectionalControlFallbackFromEvidence,
|
|
2684
3071
|
locatorDomSignatureScript: LOCATOR_DOM_SIGNATURE_SCRIPT,
|
|
2685
3072
|
};
|
|
2686
3073
|
export const __testStagehandDescriptor = {
|