@nuanu-ai/agentbrowse 0.2.36 → 0.2.37

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.
@@ -1 +1 @@
1
- {"version":3,"file":"observe-accessibility.d.ts","sourceRoot":"","sources":["../../src/commands/observe-accessibility.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAS5C,OAAO,KAAK,EAEV,iBAAiB,EAElB,MAAM,wBAAwB,CAAC;AAEhC,KAAK,6BAA6B,GAAG;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC,CAAC;CACpD,CAAC;AAOF,MAAM,MAAM,yBAAyB,GAAG;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,KAAK,2BAA2B,GAAG;IACjC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,yBAAyB,KAAK,IAAI,CAAC;CACtD,CAAC;AAyDF,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAClC,6BAA6B,GAAG,IAAI,CAoDtC;AA+nBD,wBAAsB,iCAAiC,CACrD,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,aAAa,CAAC,iBAAiB,CAAC,EACzC,OAAO,CAAC,EAAE,2BAA2B,GACpC,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAY9B;AAED,eAAO,MAAM,0BAA0B;;CAEtC,CAAC"}
1
+ {"version":3,"file":"observe-accessibility.d.ts","sourceRoot":"","sources":["../../src/commands/observe-accessibility.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAa5C,OAAO,KAAK,EAEV,iBAAiB,EAElB,MAAM,wBAAwB,CAAC;AAEhC,KAAK,6BAA6B,GAAG;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC,CAAC;CACpD,CAAC;AAOF,MAAM,MAAM,yBAAyB,GAAG;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,KAAK,2BAA2B,GAAG;IACjC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,yBAAyB,KAAK,IAAI,CAAC;CACtD,CAAC;AAyDF,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAClC,6BAA6B,GAAG,IAAI,CAoDtC;AAiqBD,wBAAsB,iCAAiC,CACrD,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,aAAa,CAAC,iBAAiB,CAAC,EACzC,OAAO,CAAC,EAAE,2BAA2B,GACpC,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAY9B;AAED,eAAO,MAAM,0BAA0B;;CAEtC,CAAC"}
@@ -1,5 +1,6 @@
1
1
  import { resolveLocatorRoot } from './action-fallbacks.js';
2
2
  import { buildObserveDisplayLabel } from './observe-display-label.js';
3
+ import { isButtonLikeObservedInput, shouldAllowLooseFieldLabelFallbackForObservedControl, } from './observe-label-policy.js';
3
4
  import { fallbackContextNodeLabelOf, fallbackHintTextOf, fallbackSurfaceLabelOf, fallbackTargetLabelOf, } from './observe-fallback-semantics.js';
4
5
  const AX_ENRICHMENT_CONCURRENCY = 12;
5
6
  const AX_SNAPSHOT_TIMEOUT_MS = 250;
@@ -105,12 +106,39 @@ function shouldPreferAccessibilityName(target, accessibilityName) {
105
106
  const currentKey = normalizeLabelKey(currentLabel);
106
107
  const nextLabel = normalizeText(accessibilityName);
107
108
  const visibleText = normalizeText(target.text);
109
+ const kind = normalizeText(target.kind)?.toLowerCase();
110
+ const role = normalizeText(target.role)?.toLowerCase();
111
+ const looseFieldFallbackAllowed = shouldAllowLooseFieldLabelFallbackForObservedControl({
112
+ tag: kind,
113
+ role,
114
+ inputType: target.inputType,
115
+ });
116
+ const primaryAxControl = !looseFieldFallbackAllowed &&
117
+ (kind === 'button' ||
118
+ kind === 'link' ||
119
+ kind === 'checkbox' ||
120
+ kind === 'radio' ||
121
+ role === 'button' ||
122
+ role === 'link' ||
123
+ role === 'checkbox' ||
124
+ role === 'radio' ||
125
+ role === 'menuitem' ||
126
+ role === 'option' ||
127
+ role === 'switch' ||
128
+ role === 'tab' ||
129
+ isButtonLikeObservedInput({
130
+ tag: kind,
131
+ inputType: target.inputType,
132
+ }));
108
133
  if (!isMeaningfulName(nextLabel)) {
109
134
  return false;
110
135
  }
111
136
  if (!isMeaningfulName(currentLabel)) {
112
137
  return true;
113
138
  }
139
+ if (primaryAxControl && currentLabel !== nextLabel) {
140
+ return true;
141
+ }
114
142
  if (GENERIC_FALLBACK_LABELS.has(currentKey)) {
115
143
  return true;
116
144
  }
@@ -426,7 +454,13 @@ async function enrichTargetWithAccessibility(page, target, rootCache, snapshotCa
426
454
  const landmarkDomFallback = await readDomFallbackSemantics(page, { selector: target.context?.landmark?.selector, framePath: target.framePath }, rootCache, fallbackCache);
427
455
  const targetDomFallback = await readDomFallbackSemantics(page, target, rootCache, fallbackCache);
428
456
  const nextLabel = isMeaningfulName(semantics?.name) &&
429
- shouldPreferAccessibilityName({ label: fallbackTargetLabelOf(target), text: target.text }, semantics.name)
457
+ shouldPreferAccessibilityName({
458
+ kind: target.kind,
459
+ role: target.role,
460
+ inputType: target.inputType,
461
+ label: fallbackTargetLabelOf(target),
462
+ text: target.text,
463
+ }, semantics.name)
430
464
  ? semantics.name
431
465
  : chooseSemanticName(fallbackTargetLabelOf(target), semantics, stats);
432
466
  const nextContext = target.context
@@ -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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"}
@@ -2025,6 +2025,14 @@ async function collectDomTargetsFromDocument(context, options) {
2025
2025
  }
2026
2026
  }
2027
2027
 
2028
+ return undefined;
2029
+ };
2030
+
2031
+ const contextTextOf = (element) => {
2032
+ if (!isHTMLElementNode(element)) {
2033
+ return undefined;
2034
+ }
2035
+
2028
2036
  const text = textOf(element, { container: true });
2029
2037
  if (!text) {
2030
2038
  return undefined;
@@ -2036,14 +2044,19 @@ async function collectDomTargetsFromDocument(context, options) {
2036
2044
  if (!element) return undefined;
2037
2045
 
2038
2046
  const kind = element.getAttribute?.('role')?.trim() || element.tagName?.toLowerCase?.();
2039
- const label = contextLabelOf(element);
2047
+ const fallbackLabel = contextLabelOf(element);
2048
+ const text = contextTextOf(element);
2040
2049
  const selector = buildSelector(element);
2041
- if (!kind && !label && !selector) return undefined;
2050
+ if (!kind && !fallbackLabel && !text && !selector) return undefined;
2042
2051
  return {
2043
2052
  kind: kind || undefined,
2044
- label,
2045
- text: undefined,
2053
+ label: undefined,
2054
+ text:
2055
+ text && (!fallbackLabel || text.toLowerCase() !== fallbackLabel.toLowerCase())
2056
+ ? text
2057
+ : undefined,
2046
2058
  selector,
2059
+ fallbackLabel,
2047
2060
  };
2048
2061
  };
2049
2062
 
@@ -0,0 +1,31 @@
1
+ export type SemanticObserveAnalyzerKey = 'en' | 'ru' | 'neutral';
2
+ export type SemanticObserveLexicalField = {
3
+ value?: string;
4
+ weight: number;
5
+ };
6
+ export type SemanticObserveAnalyzedText = {
7
+ analyzerKey: SemanticObserveAnalyzerKey;
8
+ normalizedText?: string;
9
+ terms: string[];
10
+ };
11
+ export type SemanticObserveLexicalDocument = {
12
+ analyzerKey: SemanticObserveAnalyzerKey;
13
+ weightedLength: number;
14
+ weightedTermFrequencies: Map<string, number>;
15
+ };
16
+ export type SemanticObserveBm25CorpusStats = {
17
+ averageDocumentLength: number;
18
+ documentCount: number;
19
+ documentFrequencyByTerm: Map<string, number>;
20
+ };
21
+ export declare function assertSemanticObserveRuntimeSupport(): void;
22
+ export declare function normalizeSemanticObserveText(value: string | undefined): string | undefined;
23
+ export declare function dominantSemanticObserveAnalyzerKey(value: string | undefined): SemanticObserveAnalyzerKey;
24
+ export declare function analyzeSemanticObserveText(value: string | undefined): SemanticObserveAnalyzedText;
25
+ export declare function buildSemanticObserveLexicalDocument(fields: ReadonlyArray<SemanticObserveLexicalField>): SemanticObserveLexicalDocument;
26
+ export declare function buildSemanticObserveBm25CorpusStats(documents: ReadonlyArray<SemanticObserveLexicalDocument>): SemanticObserveBm25CorpusStats;
27
+ export declare function scoreSemanticObserveBm25(query: SemanticObserveAnalyzedText, document: SemanticObserveLexicalDocument, corpus: SemanticObserveBm25CorpusStats, options?: {
28
+ k1?: number;
29
+ b?: number;
30
+ }): number;
31
+ //# sourceMappingURL=semantic-observe-lexical.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"semantic-observe-lexical.d.ts","sourceRoot":"","sources":["../../src/commands/semantic-observe-lexical.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,0BAA0B,GAAG,IAAI,GAAG,IAAI,GAAG,SAAS,CAAC;AAEjE,MAAM,MAAM,2BAA2B,GAAG;IACxC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,WAAW,EAAE,0BAA0B,CAAC;IACxC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,8BAA8B,GAAG;IAC3C,WAAW,EAAE,0BAA0B,CAAC;IACxC,cAAc,EAAE,MAAM,CAAC;IACvB,uBAAuB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9C,CAAC;AAEF,MAAM,MAAM,8BAA8B,GAAG;IAC3C,qBAAqB,EAAE,MAAM,CAAC;IAC9B,aAAa,EAAE,MAAM,CAAC;IACtB,uBAAuB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9C,CAAC;AAMF,wBAAgB,mCAAmC,IAAI,IAAI,CAM1D;AAgDD,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAO1F;AAED,wBAAgB,kCAAkC,CAChD,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,0BAA0B,CAwB5B;AAmCD,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,2BAA2B,CAqBjG;AAED,wBAAgB,mCAAmC,CACjD,MAAM,EAAE,aAAa,CAAC,2BAA2B,CAAC,GACjD,8BAA8B,CAoChC;AAED,wBAAgB,mCAAmC,CACjD,SAAS,EAAE,aAAa,CAAC,8BAA8B,CAAC,GACvD,8BAA8B,CAiBhC;AAED,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,2BAA2B,EAClC,QAAQ,EAAE,8BAA8B,EACxC,MAAM,EAAE,8BAA8B,EACtC,OAAO,GAAE;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,CAAC,EAAE,MAAM,CAAA;CAAO,GACxC,MAAM,CA0BR"}
@@ -0,0 +1,188 @@
1
+ import { newStemmer } from 'snowball-stemmers';
2
+ const TOKENIZER_FALLBACK_RE = /[\p{L}\p{N}]+/gu;
3
+ const segmenterCache = new Map();
4
+ const stemmerCache = new Map();
5
+ export function assertSemanticObserveRuntimeSupport() {
6
+ if (typeof Intl === 'undefined' || typeof Intl.Segmenter !== 'function') {
7
+ throw new Error('AgentBrowse requires Intl.Segmenter. Use a modern Node runtime with standard Intl support.');
8
+ }
9
+ }
10
+ function segmenterFor(locale) {
11
+ const cached = segmenterCache.get(locale);
12
+ if (cached !== undefined) {
13
+ return cached;
14
+ }
15
+ assertSemanticObserveRuntimeSupport();
16
+ const segmenter = new Intl.Segmenter(locale === 'neutral' ? undefined : locale, {
17
+ granularity: 'word',
18
+ });
19
+ segmenterCache.set(locale, segmenter);
20
+ return segmenter;
21
+ }
22
+ function stemmerFor(locale) {
23
+ const cached = stemmerCache.get(locale);
24
+ if (cached !== undefined) {
25
+ return cached;
26
+ }
27
+ const algorithm = locale === 'en' ? 'english' : locale === 'ru' ? 'russian' : undefined;
28
+ if (!algorithm) {
29
+ stemmerCache.set(locale, null);
30
+ return null;
31
+ }
32
+ const stemmer = newStemmer(algorithm);
33
+ stemmerCache.set(locale, stemmer);
34
+ return stemmer;
35
+ }
36
+ function isNumericToken(token) {
37
+ return /^[\p{N}]+$/u.test(token);
38
+ }
39
+ function detectAnalyzerKeyForToken(token) {
40
+ if (/[\p{Script=Cyrillic}]/u.test(token)) {
41
+ return 'ru';
42
+ }
43
+ if (/[\p{Script=Latin}]/u.test(token)) {
44
+ return 'en';
45
+ }
46
+ return 'neutral';
47
+ }
48
+ export function normalizeSemanticObserveText(value) {
49
+ const normalized = value
50
+ ?.normalize('NFKC')
51
+ .replace(/\s+/g, ' ')
52
+ .trim()
53
+ .toLowerCase();
54
+ return normalized ? normalized : undefined;
55
+ }
56
+ export function dominantSemanticObserveAnalyzerKey(value) {
57
+ const normalized = normalizeSemanticObserveText(value);
58
+ if (!normalized) {
59
+ return 'neutral';
60
+ }
61
+ let latinCount = 0;
62
+ let cyrillicCount = 0;
63
+ for (const token of normalized.match(TOKENIZER_FALLBACK_RE) ?? []) {
64
+ const key = detectAnalyzerKeyForToken(token);
65
+ if (key === 'en') {
66
+ latinCount += 1;
67
+ }
68
+ else if (key === 'ru') {
69
+ cyrillicCount += 1;
70
+ }
71
+ }
72
+ if (cyrillicCount > latinCount) {
73
+ return 'ru';
74
+ }
75
+ if (latinCount > 0) {
76
+ return 'en';
77
+ }
78
+ return 'neutral';
79
+ }
80
+ function segmentSemanticObserveText(normalizedText, locale) {
81
+ const segmenter = segmenterFor(locale);
82
+ const tokens = [];
83
+ for (const segment of segmenter.segment(normalizedText)) {
84
+ if (segment.isWordLike === false) {
85
+ continue;
86
+ }
87
+ const token = normalizeSemanticObserveText(segment.segment);
88
+ if (!token) {
89
+ continue;
90
+ }
91
+ if (!/[\p{L}\p{N}]/u.test(token)) {
92
+ continue;
93
+ }
94
+ tokens.push(token);
95
+ }
96
+ return tokens;
97
+ }
98
+ function stemSemanticObserveToken(token) {
99
+ const analyzerKey = detectAnalyzerKeyForToken(token);
100
+ const stemmer = stemmerFor(analyzerKey);
101
+ if (!stemmer) {
102
+ return token;
103
+ }
104
+ const stemmed = normalizeSemanticObserveText(stemmer.stem(token));
105
+ return stemmed && (stemmed.length >= 2 || isNumericToken(stemmed)) ? stemmed : token;
106
+ }
107
+ export function analyzeSemanticObserveText(value) {
108
+ const normalizedText = normalizeSemanticObserveText(value);
109
+ if (!normalizedText) {
110
+ return {
111
+ analyzerKey: 'neutral',
112
+ normalizedText: undefined,
113
+ terms: [],
114
+ };
115
+ }
116
+ const analyzerKey = dominantSemanticObserveAnalyzerKey(normalizedText);
117
+ const segmented = segmentSemanticObserveText(normalizedText, analyzerKey);
118
+ const terms = segmented
119
+ .map((token) => stemSemanticObserveToken(token))
120
+ .filter((token) => token.length >= 2 || isNumericToken(token));
121
+ return {
122
+ analyzerKey,
123
+ normalizedText,
124
+ terms,
125
+ };
126
+ }
127
+ export function buildSemanticObserveLexicalDocument(fields) {
128
+ const weightedTermFrequencies = new Map();
129
+ const analyzerVotes = new Map();
130
+ let weightedLength = 0;
131
+ for (const field of fields) {
132
+ if (field.weight <= 0) {
133
+ continue;
134
+ }
135
+ const analyzed = analyzeSemanticObserveText(field.value);
136
+ if (analyzed.terms.length === 0) {
137
+ continue;
138
+ }
139
+ analyzerVotes.set(analyzed.analyzerKey, (analyzerVotes.get(analyzed.analyzerKey) ?? 0) + analyzed.terms.length);
140
+ weightedLength += analyzed.terms.length * field.weight;
141
+ for (const term of analyzed.terms) {
142
+ weightedTermFrequencies.set(term, (weightedTermFrequencies.get(term) ?? 0) + field.weight);
143
+ }
144
+ }
145
+ const analyzerKey = [...analyzerVotes.entries()].sort((left, right) => right[1] - left[1])[0]?.[0] ?? 'neutral';
146
+ return {
147
+ analyzerKey,
148
+ weightedLength,
149
+ weightedTermFrequencies,
150
+ };
151
+ }
152
+ export function buildSemanticObserveBm25CorpusStats(documents) {
153
+ const documentFrequencyByTerm = new Map();
154
+ let totalLength = 0;
155
+ for (const document of documents) {
156
+ totalLength += document.weightedLength;
157
+ for (const term of document.weightedTermFrequencies.keys()) {
158
+ documentFrequencyByTerm.set(term, (documentFrequencyByTerm.get(term) ?? 0) + 1);
159
+ }
160
+ }
161
+ return {
162
+ averageDocumentLength: documents.length > 0 ? totalLength / documents.length : 0,
163
+ documentCount: documents.length,
164
+ documentFrequencyByTerm,
165
+ };
166
+ }
167
+ export function scoreSemanticObserveBm25(query, document, corpus, options = {}) {
168
+ if (query.terms.length === 0 || document.weightedTermFrequencies.size === 0 || corpus.documentCount === 0) {
169
+ return 0;
170
+ }
171
+ const k1 = options.k1 ?? 1.2;
172
+ const b = options.b ?? 0.75;
173
+ const averageDocumentLength = Math.max(corpus.averageDocumentLength, 1);
174
+ const documentLength = Math.max(document.weightedLength, 1);
175
+ const uniqueTerms = [...new Set(query.terms)];
176
+ let score = 0;
177
+ for (const term of uniqueTerms) {
178
+ const termFrequency = document.weightedTermFrequencies.get(term) ?? 0;
179
+ if (termFrequency <= 0) {
180
+ continue;
181
+ }
182
+ const documentFrequency = corpus.documentFrequencyByTerm.get(term) ?? 0;
183
+ const idf = Math.log(1 + (corpus.documentCount - documentFrequency + 0.5) / (documentFrequency + 0.5));
184
+ const denominator = termFrequency + k1 * (1 - b + b * (documentLength / averageDocumentLength));
185
+ score += idf * ((termFrequency * (k1 + 1)) / denominator);
186
+ }
187
+ return score;
188
+ }
@@ -24,6 +24,7 @@ type ObserveInventoryTarget = {
24
24
  pageSignature?: string;
25
25
  goalInventoryType?: 'target' | 'scope';
26
26
  goalSurfaceId?: string;
27
+ controlsSurfaceSelector?: string;
27
28
  };
28
29
  export declare function rerankDomTargetsForGoal<T extends ObserveInventoryTarget>(instruction: string, targets: ReadonlyArray<T>, options?: {
29
30
  session?: BrowseSession;
@@ -1 +1 @@
1
- {"version":3,"file":"semantic-observe.d.ts","sourceRoot":"","sources":["../../src/commands/semantic-observe.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD,OAAO,KAAK,EACV,sBAAsB,EACtB,mBAAmB,EACnB,gBAAgB,EAChB,aAAa,EACb,mBAAmB,EACnB,eAAe,EAChB,MAAM,qBAAqB,CAAC;AAE7B,KAAK,sBAAsB,GAAG;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC,CAAC;IACnD,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,cAAc,CAAC,EAAE,mBAAmB,EAAE,CAAC;IACvC,gBAAgB,CAAC,EAAE,sBAAsB,CAAC;IAC1C,aAAa,CAAC,EAAE,mBAAmB,CAAC;IACpC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;IACvC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAwhCF,wBAAsB,uBAAuB,CAAC,CAAC,SAAS,sBAAsB,EAC5E,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,EACzB,OAAO,GAAE;IAAE,OAAO,CAAC,EAAE,aAAa,CAAA;CAAO,GACxC,OAAO,CAAC,CAAC,EAAE,CAAC,CA0Ed"}
1
+ {"version":3,"file":"semantic-observe.d.ts","sourceRoot":"","sources":["../../src/commands/semantic-observe.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD,OAAO,KAAK,EACV,sBAAsB,EACtB,mBAAmB,EACnB,gBAAgB,EAChB,aAAa,EACb,mBAAmB,EACnB,eAAe,EAChB,MAAM,qBAAqB,CAAC;AAY7B,KAAK,sBAAsB,GAAG;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC,CAAC;IACnD,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,cAAc,CAAC,EAAE,mBAAmB,EAAE,CAAC;IACvC,gBAAgB,CAAC,EAAE,sBAAsB,CAAC;IAC1C,aAAa,CAAC,EAAE,mBAAmB,CAAC;IACpC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;IACvC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,uBAAuB,CAAC,EAAE,MAAM,CAAC;CAClC,CAAC;AAwoCF,wBAAsB,uBAAuB,CAAC,CAAC,SAAS,sBAAsB,EAC5E,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,EACzB,OAAO,GAAE;IAAE,OAAO,CAAC,EAAE,aAAa,CAAA;CAAO,GACxC,OAAO,CAAC,CAAC,EAAE,CAAC,CA2Ed"}
@@ -2,6 +2,7 @@ import { z } from 'zod';
2
2
  import { AgentpayStagehandLlmClient } from '../agentpay-stagehand-llm.js';
3
3
  import { resolveAgentpayGatewayConfig } from '../agentpay-gateway.js';
4
4
  import { recordLlmUsage, recordPayloadBudget } from '../runtime-state.js';
5
+ import { analyzeSemanticObserveText, buildSemanticObserveBm25CorpusStats, buildSemanticObserveLexicalDocument, normalizeSemanticObserveText, scoreSemanticObserveBm25, } from './semantic-observe-lexical.js';
5
6
  const rerankSchema = z.object({
6
7
  matches: z
7
8
  .array(z.object({
@@ -17,6 +18,31 @@ const SCOPE_BUCKET_RESERVE_LIMIT = 24;
17
18
  const SCOPE_BUCKET_RESERVE_PER_BUCKET = 2;
18
19
  const IFRAME_BUCKET_RESERVE_LIMIT = 24;
19
20
  const IFRAME_BUCKET_RESERVE_PER_BUCKET = 2;
21
+ const RETRIEVAL_FIELD_WEIGHTS = {
22
+ entityLabel: 5.5,
23
+ representativeLabel: 5,
24
+ representativeLabels: 4,
25
+ surfaceLabel: 2.25,
26
+ placeholder: 2.5,
27
+ title: 1.25,
28
+ itemLabel: 2.5,
29
+ itemText: 1.5,
30
+ groupLabel: 1.75,
31
+ groupText: 1,
32
+ containerLabel: 1.5,
33
+ containerText: 0.9,
34
+ landmarkLabel: 1.25,
35
+ landmarkText: 0.75,
36
+ hintText: 1.5,
37
+ kind: 0.6,
38
+ role: 0.6,
39
+ surfaceKind: 0.75,
40
+ controlFamily: 0.9,
41
+ acceptancePolicy: 1,
42
+ allowedActions: 0.9,
43
+ structure: 1.25,
44
+ latentIntent: 1.2,
45
+ };
20
46
  const HIGH_SIGNAL_SCOPE_KINDS = new Set([
21
47
  'dialog',
22
48
  'listbox',
@@ -29,27 +55,6 @@ const HIGH_SIGNAL_SCOPE_KINDS = new Set([
29
55
  'card',
30
56
  'form',
31
57
  ]);
32
- const GOAL_TEXT_STOPWORDS = new Set([
33
- 'a',
34
- 'an',
35
- 'and',
36
- 'at',
37
- 'for',
38
- 'from',
39
- 'in',
40
- 'of',
41
- 'on',
42
- 'or',
43
- 'the',
44
- 'to',
45
- 'with',
46
- 'в',
47
- 'для',
48
- 'и',
49
- 'или',
50
- 'на',
51
- 'найти',
52
- ]);
53
58
  function isFieldLikeTarget(target) {
54
59
  const kind = (target.kind ?? '').trim().toLowerCase();
55
60
  const role = (target.role ?? '').trim().toLowerCase();
@@ -73,16 +78,6 @@ function isActionLikeTargetCandidate(target) {
73
78
  kind === 'link' ||
74
79
  role === 'link');
75
80
  }
76
- function normalizeRetrievalText(value) {
77
- const normalized = value?.replace(/\s+/g, ' ').trim().toLowerCase();
78
- return normalized ? normalized : undefined;
79
- }
80
- function tokenizeRetrievalText(value) {
81
- if (!value) {
82
- return [];
83
- }
84
- return (value.match(/[\p{L}\p{N}]+/gu) ?? []).map((token) => token.toLowerCase());
85
- }
86
81
  function semanticFormContextKey(context) {
87
82
  for (const node of [context?.landmark, context?.container, context?.group, context?.item]) {
88
83
  const kind = (node?.kind ?? '').trim().toLowerCase();
@@ -140,6 +135,13 @@ function isPrimaryFormControlTarget(target) {
140
135
  acceptancePolicy === 'disclosure' &&
141
136
  (kind === 'button' || role === 'button'));
142
137
  }
138
+ function shouldPreserveStandaloneFormActionEntity(target) {
139
+ return (Boolean(formBucketKey(target)) &&
140
+ !isScopeLikeCandidate(target) &&
141
+ !isFieldLikeTarget(target) &&
142
+ isActionLikeTargetCandidate(target) &&
143
+ isPrimaryFormControlTarget(target));
144
+ }
143
145
  function primaryFormTargetPriority(target) {
144
146
  const acceptancePolicy = (target.acceptancePolicy ?? '').trim().toLowerCase();
145
147
  if (isFieldLikeTarget(target)) {
@@ -178,11 +180,11 @@ function contentItemBucketKey(target) {
178
180
  if (surfaceIdentity) {
179
181
  return `surface:${surfaceIdentity}`;
180
182
  }
181
- const itemKey = normalizeRetrievalText(target.context?.item?.label ?? target.context?.item?.text);
183
+ const itemKey = normalizeSemanticObserveText(target.context?.item?.label ?? target.context?.item?.text);
182
184
  if (itemKey) {
183
185
  return `item:${itemKey}`;
184
186
  }
185
- const containerKey = normalizeRetrievalText(target.context?.container?.label ?? target.context?.container?.text);
187
+ const containerKey = normalizeSemanticObserveText(target.context?.container?.label ?? target.context?.container?.text);
186
188
  if (containerKey) {
187
189
  return `container:${containerKey}`;
188
190
  }
@@ -205,7 +207,7 @@ function scopeCandidatePriority(target) {
205
207
  return 4;
206
208
  }
207
209
  function representativeCandidateScore(target) {
208
- const normalizedLabel = normalizeRetrievalText(target.label);
210
+ const normalizedLabel = normalizeSemanticObserveText(target.label);
209
211
  const kind = (target.kind ?? '').trim().toLowerCase();
210
212
  const role = (target.role ?? '').trim().toLowerCase();
211
213
  let score = (target.surfacePriority ?? 0) * 10;
@@ -295,26 +297,131 @@ function collectRepresentativeLabels(targets) {
295
297
  }
296
298
  return labels;
297
299
  }
298
- function buildEntitySearchText(entityLabel, representative, representativeLabels) {
300
+ function structureLexicalValue(structure) {
301
+ if (!structure) {
302
+ return undefined;
303
+ }
299
304
  return [
300
- entityLabel,
301
- representative.label,
302
- ...representativeLabels,
303
- representative.surfaceLabel,
304
- representative.context?.item?.label,
305
- representative.context?.item?.text,
306
- representative.context?.group?.label,
307
- representative.context?.group?.text,
308
- representative.context?.container?.label,
309
- representative.context?.container?.text,
310
- representative.context?.landmark?.label,
311
- representative.context?.landmark?.text,
312
- representative.context?.hintText,
305
+ structure.family,
306
+ structure.variant,
307
+ structure.row,
308
+ structure.column,
309
+ structure.zone,
310
+ structure.cellLabel,
313
311
  ]
314
- .map((value) => normalizeRetrievalText(value))
315
- .filter((value) => Boolean(value))
312
+ .filter(Boolean)
316
313
  .join(' ');
317
314
  }
315
+ function latentActionHintText(target) {
316
+ const acceptancePolicy = (target.acceptancePolicy ?? '').trim().toLowerCase();
317
+ const controlFamily = (target.controlFamily ?? '').trim().toLowerCase();
318
+ const surfaceKind = (target.surfaceKind ?? '').trim().toLowerCase();
319
+ const kind = (target.kind ?? '').trim().toLowerCase();
320
+ const role = (target.role ?? '').trim().toLowerCase();
321
+ const popupBacked = acceptancePolicy === 'disclosure' ||
322
+ Boolean(target.controlsSurfaceSelector) ||
323
+ target.states?.expanded !== undefined;
324
+ if (!popupBacked) {
325
+ return undefined;
326
+ }
327
+ const hints = new Set();
328
+ hints.add('open menu options choices');
329
+ if (!isFieldLikeTarget(target)) {
330
+ hints.add('sort sorting filter filters view switch picker');
331
+ }
332
+ if (controlFamily === 'select' ||
333
+ ['menu', 'listbox', 'dropdown', 'popover'].includes(surfaceKind)) {
334
+ hints.add('select choose option options menu dropdown listbox');
335
+ }
336
+ if (controlFamily === 'datepicker' || surfaceKind === 'datepicker') {
337
+ hints.add('open calendar datepicker date picker choose date calendar');
338
+ }
339
+ const evidenceText = [
340
+ target.label,
341
+ target.placeholder,
342
+ target.title,
343
+ target.surfaceLabel,
344
+ target.context?.group?.label,
345
+ target.context?.container?.label,
346
+ target.context?.landmark?.label,
347
+ target.context?.hintText,
348
+ ]
349
+ .filter((value) => Boolean(value))
350
+ .join(' ')
351
+ .toLowerCase();
352
+ if (/(?:sort|sorting|show first|ordered by|order by|popular|relevance|recommended|price|cheap|cheapest|expensive|сорт|сначала|популяр|релевант|рекоменд|цене|дешев|дорог)/i.test(evidenceText)) {
353
+ hints.add('sort sorting order order by relevance popular recommended price cheapest cheapest first');
354
+ }
355
+ if (/(?:filter|filters|refine|brand|airline|amenit|фильтр|фильтры|бренд|авиакомпан|удобств)/i.test(evidenceText)) {
356
+ hints.add('filter filters refine refine results brand airline amenities');
357
+ }
358
+ if (/(?:view|layout|grid|list|map|calendar view|вид|список|сетка|карта|раскладк)/i.test(evidenceText)) {
359
+ hints.add('view layout grid list map switch');
360
+ }
361
+ if (kind === 'button' &&
362
+ role === 'button' &&
363
+ (acceptancePolicy === 'disclosure' || controlFamily === 'select' || controlFamily === 'datepicker')) {
364
+ hints.add('open selector choose mode');
365
+ }
366
+ return hints.size > 0 ? [...hints].join(' ') : undefined;
367
+ }
368
+ function buildEntityLexicalFields(entityLabel, representative, representativeLabels) {
369
+ return [
370
+ { value: entityLabel, weight: RETRIEVAL_FIELD_WEIGHTS.entityLabel },
371
+ { value: representative.label, weight: RETRIEVAL_FIELD_WEIGHTS.representativeLabel },
372
+ ...representativeLabels.map((value) => ({
373
+ value,
374
+ weight: RETRIEVAL_FIELD_WEIGHTS.representativeLabels,
375
+ })),
376
+ { value: representative.surfaceLabel, weight: RETRIEVAL_FIELD_WEIGHTS.surfaceLabel },
377
+ { value: representative.placeholder, weight: RETRIEVAL_FIELD_WEIGHTS.placeholder },
378
+ { value: representative.title, weight: RETRIEVAL_FIELD_WEIGHTS.title },
379
+ { value: representative.context?.item?.label, weight: RETRIEVAL_FIELD_WEIGHTS.itemLabel },
380
+ { value: representative.context?.item?.text, weight: RETRIEVAL_FIELD_WEIGHTS.itemText },
381
+ { value: representative.context?.group?.label, weight: RETRIEVAL_FIELD_WEIGHTS.groupLabel },
382
+ { value: representative.context?.group?.text, weight: RETRIEVAL_FIELD_WEIGHTS.groupText },
383
+ {
384
+ value: representative.context?.container?.label,
385
+ weight: RETRIEVAL_FIELD_WEIGHTS.containerLabel,
386
+ },
387
+ {
388
+ value: representative.context?.container?.text,
389
+ weight: RETRIEVAL_FIELD_WEIGHTS.containerText,
390
+ },
391
+ {
392
+ value: representative.context?.landmark?.label,
393
+ weight: RETRIEVAL_FIELD_WEIGHTS.landmarkLabel,
394
+ },
395
+ {
396
+ value: representative.context?.landmark?.text,
397
+ weight: RETRIEVAL_FIELD_WEIGHTS.landmarkText,
398
+ },
399
+ { value: representative.context?.hintText, weight: RETRIEVAL_FIELD_WEIGHTS.hintText },
400
+ { value: representative.kind, weight: RETRIEVAL_FIELD_WEIGHTS.kind },
401
+ { value: representative.role, weight: RETRIEVAL_FIELD_WEIGHTS.role },
402
+ { value: representative.surfaceKind, weight: RETRIEVAL_FIELD_WEIGHTS.surfaceKind },
403
+ {
404
+ value: representative.controlFamily,
405
+ weight: RETRIEVAL_FIELD_WEIGHTS.controlFamily,
406
+ },
407
+ {
408
+ value: representative.acceptancePolicy,
409
+ weight: RETRIEVAL_FIELD_WEIGHTS.acceptancePolicy,
410
+ },
411
+ {
412
+ value: representative.allowedActions?.join(' '),
413
+ weight: RETRIEVAL_FIELD_WEIGHTS.allowedActions,
414
+ },
415
+ {
416
+ value: structureLexicalValue(representative.structure),
417
+ weight: RETRIEVAL_FIELD_WEIGHTS.structure,
418
+ },
419
+ {
420
+ value: latentActionHintText(representative),
421
+ weight: RETRIEVAL_FIELD_WEIGHTS.latentIntent,
422
+ },
423
+ ];
424
+ }
318
425
  function buildGoalRetrievalEntity(entityKind, entityKey, memberIndexes, targets) {
319
426
  const orderedMembers = [...memberIndexes]
320
427
  .map((index) => ({ index, target: targets[index] }))
@@ -322,6 +429,8 @@ function buildGoalRetrievalEntity(entityKind, entityKey, memberIndexes, targets)
322
429
  const representative = orderedMembers[0].target;
323
430
  const representativeLabels = collectRepresentativeLabels(orderedMembers.map((entry) => entry.target));
324
431
  const label = pickEntityLabel(entityKind, representative);
432
+ const lexicalFields = buildEntityLexicalFields(label, representative, representativeLabels);
433
+ const lexicalDocument = buildSemanticObserveLexicalDocument(lexicalFields);
325
434
  return {
326
435
  entityKind,
327
436
  entityKey,
@@ -342,7 +451,8 @@ function buildGoalRetrievalEntity(entityKind, entityKey, memberIndexes, targets)
342
451
  context: representative.context,
343
452
  structure: representative.structure,
344
453
  representativeLabels,
345
- searchText: buildEntitySearchText(label, representative, representativeLabels),
454
+ analyzerKey: lexicalDocument.analyzerKey,
455
+ lexicalDocument,
346
456
  };
347
457
  }
348
458
  function buildGoalRetrievalEntities(targets) {
@@ -376,7 +486,12 @@ function buildGoalRetrievalEntities(targets) {
376
486
  }
377
487
  for (const [key, memberIndexes] of formGroups.entries()) {
378
488
  entities.push(buildGoalRetrievalEntity('form', `form:${key}`, memberIndexes, targets));
379
- memberIndexes.forEach((index) => groupedTargetIndexes.add(index));
489
+ memberIndexes.forEach((index) => {
490
+ if (shouldPreserveStandaloneFormActionEntity(targets[index])) {
491
+ return;
492
+ }
493
+ groupedTargetIndexes.add(index);
494
+ });
380
495
  }
381
496
  const itemGroups = new Map();
382
497
  for (const [index, target] of targets.entries()) {
@@ -445,58 +560,28 @@ function retrievalEntityPriority(entity) {
445
560
  score += representativeCandidateScore(entity.representative);
446
561
  return score;
447
562
  }
448
- function scoreRetrievalEntityAgainstGoal(goal, entity) {
449
- const normalizedGoal = normalizeRetrievalText(goal);
450
- if (!normalizedGoal) {
563
+ function scoreRetrievalEntityAgainstGoal(analyzedGoal, entity, corpusStats) {
564
+ if (!analyzedGoal.normalizedText) {
451
565
  return 0;
452
566
  }
453
- const entityText = entity.searchText;
454
- if (!entityText) {
567
+ if (entity.lexicalDocument.weightedLength <= 0) {
455
568
  return 0;
456
569
  }
457
- let score = 0;
458
- const goalTokens = tokenizeRetrievalText(normalizedGoal).filter((token) => token.length >= 2 && !GOAL_TEXT_STOPWORDS.has(token));
459
- const entityTokens = new Set(tokenizeRetrievalText(entityText));
460
- if (entityText.includes(normalizedGoal)) {
461
- score += 220;
462
- }
463
- const entityLabel = normalizeRetrievalText(entity.label);
464
- if (entityLabel) {
465
- if (normalizedGoal.includes(entityLabel)) {
466
- score += 180;
467
- }
468
- if (entityLabel.includes(normalizedGoal)) {
469
- score += 140;
470
- }
471
- }
472
- let matchedTokenCount = 0;
473
- for (const token of goalTokens) {
474
- if (entityTokens.has(token)) {
475
- matchedTokenCount += 1;
476
- score += 8 + Math.min(token.length, 12);
477
- }
478
- }
479
- if (goalTokens.length > 0) {
480
- const coverage = matchedTokenCount / goalTokens.length;
481
- if (coverage === 1) {
482
- score += 120;
483
- }
484
- else if (coverage >= 0.75) {
485
- score += 70;
486
- }
487
- else if (coverage >= 0.5) {
488
- score += 35;
489
- }
490
- }
491
- return score;
570
+ const bm25Score = scoreSemanticObserveBm25(analyzedGoal, entity.lexicalDocument, corpusStats);
571
+ const analyzerAlignmentScore = analyzedGoal.analyzerKey !== 'neutral' && analyzedGoal.analyzerKey === entity.analyzerKey
572
+ ? 15
573
+ : 0;
574
+ return bm25Score * 100 + analyzerAlignmentScore;
492
575
  }
493
576
  function preselectRetrievalEntities(goal, entities) {
494
577
  if (entities.length <= GOAL_RETRIEVAL_ENTITY_LIMIT) {
495
578
  return [...entities];
496
579
  }
580
+ const analyzedGoal = analyzeSemanticObserveText(goal);
581
+ const corpusStats = buildSemanticObserveBm25CorpusStats(entities.map((entity) => entity.lexicalDocument));
497
582
  const scored = entities.map((entity) => ({
498
583
  entity,
499
- lexicalScore: scoreRetrievalEntityAgainstGoal(goal, entity),
584
+ lexicalScore: scoreRetrievalEntityAgainstGoal(analyzedGoal, entity, corpusStats),
500
585
  priority: retrievalEntityPriority(entity),
501
586
  }));
502
587
  const selected = [];
@@ -634,9 +719,6 @@ function diversifyCandidates(targets) {
634
719
  }
635
720
  return orderedIndexes.map((index) => targets[index]).slice(0, RERANK_CANDIDATE_LIMIT);
636
721
  }
637
- function buildCandidateSummary(target, index, surfaceSummaryIdBySurfaceKey) {
638
- return buildCompactCandidateSummary(target, index, surfaceSummaryIdBySurfaceKey);
639
- }
640
722
  function compactContextValue(value, maxLength = 80) {
641
723
  const normalized = value?.replace(/\s+/g, ' ').trim();
642
724
  if (!normalized) {
@@ -791,6 +873,9 @@ function buildCompactCandidateSummary(target, index, surfaceSummaryIdBySurfaceKe
791
873
  if (target.controlFamily) {
792
874
  parts.push(`family=${JSON.stringify(target.controlFamily)}`);
793
875
  }
876
+ if (target.controlsSurfaceSelector) {
877
+ parts.push('controlsPopup=true');
878
+ }
794
879
  if (target.capability && target.capability !== 'actionable') {
795
880
  parts.push(`capability=${JSON.stringify(target.capability)}`);
796
881
  }
@@ -836,6 +921,7 @@ export async function rerankDomTargetsForGoal(instruction, targets, options = {}
836
921
  const prompt = [
837
922
  'You are choosing from already discovered visible webpage candidates.',
838
923
  'Select only candidate IDs that directly satisfy the goal.',
924
+ 'A disclosure trigger with a current-state label can still directly satisfy sort, filter, view-switch, or picker goals when opening it is the immediate next step.',
839
925
  'Prefer direct actionable controls over surrounding regions unless the goal explicitly asks for a form, region, widget, or set of controls.',
840
926
  'Use owning surface, compact context, explicit state, and structure metadata to disambiguate similar labels.',
841
927
  'For input/value goals, prefer the directly editable field or primary picker trigger over wrappers or mirrored summary content.',
@@ -847,7 +933,7 @@ export async function rerankDomTargetsForGoal(instruction, targets, options = {}
847
933
  '',
848
934
  ...(surfaceSummaries.length > 0 ? ['Surfaces:', ...surfaceSummaries.map((entry) => entry.line), ''] : []),
849
935
  'Candidates:',
850
- ...candidates.map((target, index) => buildCandidateSummary(target, index, summaryIdBySurfaceKey)),
936
+ ...candidates.map((target, index) => buildCompactCandidateSummary(target, index, summaryIdBySurfaceKey)),
851
937
  ].join('\n');
852
938
  const result = await client.createChatCompletion({
853
939
  logger: () => { },
@@ -1 +1 @@
1
- {"version":3,"file":"control-semantics.d.ts","sourceRoot":"","sources":["../src/control-semantics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,sBAAsB,EACtB,mBAAmB,EACnB,uBAAuB,EACvB,mBAAmB,EACnB,eAAe,EAChB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC,CAAC;AAEzE,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,OAAO,GAAG,aAAa,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;AAyCtF,wBAAgB,iCAAiC,CAC/C,KAAK,EAAE,oBAAoB,GAC1B,mBAAmB,GAAG,SAAS,CAuCjC;AAsCD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAYxE;AAED,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,oBAAoB,GAAG,mBAAmB,EAAE,CAoG/F;AAED,wBAAgB,0BAA0B,CACxC,MAAM,CAAC,EAAE,gBAAgB,EACzB,WAAW,CAAC,EAAE,MAAM,EACpB,OAAO,GAAE;IACP,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC1B,GACL,uBAAuB,CAyBzB;AAED,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,oBAAoB,EAC3B,cAAc,EAAE,aAAa,CAAC,mBAAmB,CAAC,GACjD,mBAAmB,GAAG,SAAS,CA0EjC;AAED,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE,oBAAoB,EAC3B,cAAc,EAAE,aAAa,CAAC,mBAAmB,CAAC,GACjD,sBAAsB,GAAG,SAAS,CAiDpC"}
1
+ {"version":3,"file":"control-semantics.d.ts","sourceRoot":"","sources":["../src/control-semantics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,sBAAsB,EACtB,mBAAmB,EACnB,uBAAuB,EACvB,mBAAmB,EACnB,eAAe,EAChB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC,CAAC;AAEzE,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,OAAO,GAAG,aAAa,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;AAiDtF,wBAAgB,iCAAiC,CAC/C,KAAK,EAAE,oBAAoB,GAC1B,mBAAmB,GAAG,SAAS,CAuCjC;AA2ID,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAYxE;AAED,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,oBAAoB,GAAG,mBAAmB,EAAE,CAoG/F;AAED,wBAAgB,0BAA0B,CACxC,MAAM,CAAC,EAAE,gBAAgB,EACzB,WAAW,CAAC,EAAE,MAAM,EACpB,OAAO,GAAE;IACP,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC1B,GACL,uBAAuB,CAyBzB;AAED,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,oBAAoB,EAC3B,cAAc,EAAE,aAAa,CAAC,mBAAmB,CAAC,GACjD,mBAAmB,GAAG,SAAS,CA0EjC;AAED,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE,oBAAoB,EAC3B,cAAc,EAAE,aAAa,CAAC,mBAAmB,CAAC,GACjD,sBAAsB,GAAG,SAAS,CA6CpC"}
@@ -7,6 +7,14 @@ const CARD_EXPIRY_FIELD_RE = /\b(exp(?:iry|iration)(?: date)?|cc-exp|valid\s+thr
7
7
  const CARD_CVC_FIELD_RE = /\b(cvc|cvv|cc-csc|security code|card cvc)\b/i;
8
8
  const DATE_VALUE_MASK_RE = /(?:^|\b)(?:dd|d|дд|д)\s*[./-]\s*(?:mm|m|мм|м)\s*[./-]\s*(?:yyyy|yyy|yy|y|гггг|гг|г)(?:\b|$)/i;
9
9
  const NON_CARD_DATE_FIELD_RE = /\b(?:birth|dob|date|issued|expires|expiry|expiration|expir)\b|(?:дата|рожд|срок)/i;
10
+ const POPUP_DISCLOSURE_SURFACE_KINDS = new Set([
11
+ 'dialog',
12
+ 'dropdown',
13
+ 'listbox',
14
+ 'menu',
15
+ 'popover',
16
+ 'datepicker',
17
+ ]);
10
18
  function normalizeText(value) {
11
19
  return (value ?? '').trim().toLowerCase();
12
20
  }
@@ -83,6 +91,78 @@ function isButtonLikeInputFacts(facts) {
83
91
  return (normalizeText(facts.kind) === 'input' &&
84
92
  ['button', 'submit', 'reset'].includes(normalizeText(facts.inputType)));
85
93
  }
94
+ function isSelectionItemLikeFacts(facts) {
95
+ const kind = normalizeText(facts.kind);
96
+ const role = normalizeText(facts.role);
97
+ return (kind === 'option' ||
98
+ role === 'option' ||
99
+ role === 'menuitem' ||
100
+ facts.structure?.family === 'structured-grid');
101
+ }
102
+ function isBinaryToggleControlFacts(facts) {
103
+ const kind = normalizeText(facts.kind);
104
+ const role = normalizeText(facts.role);
105
+ const inputType = normalizeText(facts.inputType);
106
+ return (kind === 'checkbox' ||
107
+ kind === 'radio' ||
108
+ role === 'checkbox' ||
109
+ role === 'radio' ||
110
+ role === 'switch' ||
111
+ kind === 'tab' ||
112
+ role === 'tab' ||
113
+ inputType === 'checkbox' ||
114
+ inputType === 'radio');
115
+ }
116
+ function isDisclosureLikeTriggerFacts(facts, controlFamily) {
117
+ const kind = normalizeText(facts.kind);
118
+ const role = normalizeText(facts.role);
119
+ const surfaceKind = normalizeText(facts.surfaceKind);
120
+ const inputType = normalizeText(facts.inputType);
121
+ const popupBacked = Boolean(facts.controlsSurfaceSelector) ||
122
+ facts.states?.expanded !== undefined ||
123
+ POPUP_DISCLOSURE_SURFACE_KINDS.has(surfaceKind);
124
+ if (!popupBacked) {
125
+ return false;
126
+ }
127
+ if (isSelectionItemLikeFacts(facts) || controlFamily === 'text-input') {
128
+ return false;
129
+ }
130
+ if (controlFamily === 'select' || controlFamily === 'datepicker') {
131
+ return true;
132
+ }
133
+ return (kind === 'button' ||
134
+ role === 'button' ||
135
+ kind === 'link' ||
136
+ role === 'link' ||
137
+ kind === 'combobox' ||
138
+ role === 'combobox' ||
139
+ kind === 'select' ||
140
+ isButtonLikeInputFacts(facts) ||
141
+ inputType === 'button' ||
142
+ isPopupBackedTextEntry(facts));
143
+ }
144
+ function isToggleLikeControlFacts(facts, controlFamily) {
145
+ const states = facts.states;
146
+ if (!states) {
147
+ return false;
148
+ }
149
+ if (states.checked !== undefined || isBinaryToggleControlFacts(facts)) {
150
+ return true;
151
+ }
152
+ if (states.selected !== undefined) {
153
+ if (isSelectionItemLikeFacts(facts) ||
154
+ controlFamily === 'select' ||
155
+ controlFamily === 'datepicker' ||
156
+ isDisclosureLikeTriggerFacts(facts, controlFamily)) {
157
+ return false;
158
+ }
159
+ return true;
160
+ }
161
+ if (states.pressed !== undefined) {
162
+ return !isDisclosureLikeTriggerFacts(facts, controlFamily);
163
+ }
164
+ return false;
165
+ }
86
166
  export function isLikelyDateLikeLabel(value) {
87
167
  const trimmed = (value ?? '').trim();
88
168
  if (!trimmed) {
@@ -280,17 +360,15 @@ export function inferAcceptancePolicyFromFacts(facts, allowedActions) {
280
360
  if (facts.structure?.family === 'structured-grid') {
281
361
  return facts.structure.variant === 'date-cell' ? 'date-selection' : 'selection';
282
362
  }
283
- if (states?.checked !== undefined ||
284
- states?.selected !== undefined ||
285
- states?.pressed !== undefined) {
286
- return 'toggle';
287
- }
288
363
  if (controlFamily === 'text-input') {
289
364
  return 'value-change';
290
365
  }
291
- if (states?.expanded !== undefined) {
366
+ if (isDisclosureLikeTriggerFacts(facts, controlFamily)) {
292
367
  return 'disclosure';
293
368
  }
369
+ if (isToggleLikeControlFacts(facts, controlFamily)) {
370
+ return 'toggle';
371
+ }
294
372
  if (controlFamily === 'datepicker') {
295
373
  return 'date-selection';
296
374
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AA2QA,iBAAe,IAAI,CAAC,IAAI,GAAE,MAAM,EAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAsKhE;AAED,OAAO,EAAE,IAAI,EAAE,CAAC;AAEhB,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,EAAiB,GAAG,OAAO,CAWzF"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AA4QA,iBAAe,IAAI,CAAC,IAAI,GAAE,MAAM,EAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CA4KhE;AAED,OAAO,EAAE,IAAI,EAAE,CAAC;AAEhB,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,EAAiB,GAAG,OAAO,CAWzF"}
package/dist/index.js CHANGED
@@ -5,6 +5,7 @@ import { fileURLToPath } from 'node:url';
5
5
  loadEnv();
6
6
  import { preflightAgentpayGateway } from './agentpay-gateway.js';
7
7
  import { browseCommand, browseCommandName } from './command-name.js';
8
+ import { assertSemanticObserveRuntimeSupport } from './commands/semantic-observe-lexical.js';
8
9
  import { loadSession } from './session.js';
9
10
  import { outputError, outputJSON, fatal, info } from './output.js';
10
11
  import { applyDemoProxyBootstrap } from './solver/config.js';
@@ -223,6 +224,12 @@ async function main(argv = process.argv) {
223
224
  if (!KNOWN_COMMANDS.has(command)) {
224
225
  outputError(`Unknown command: ${command}\n\n${usageText()}`);
225
226
  }
227
+ try {
228
+ assertSemanticObserveRuntimeSupport();
229
+ }
230
+ catch (err) {
231
+ outputError(err instanceof Error ? err.message : String(err));
232
+ }
226
233
  if (command !== 'init') {
227
234
  try {
228
235
  await preflightAgentpayGateway();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nuanu-ai/agentbrowse",
3
- "version": "0.2.36",
3
+ "version": "0.2.37",
4
4
  "type": "module",
5
5
  "description": "Browser automation CLI for AI agents: control a CDP browser, observe UI surfaces, act on refs, extract data, capture screenshots, complete protected fills, and solve captchas",
6
6
  "keywords": [
@@ -57,6 +57,7 @@
57
57
  "puppeteer": "^23.11.1",
58
58
  "puppeteer-extra": "^3.3.6",
59
59
  "puppeteer-extra-plugin-stealth": "^2.11.2",
60
+ "snowball-stemmers": "^0.6.0",
60
61
  "zod": "^3.24.0"
61
62
  },
62
63
  "devDependencies": {