@nuanu-ai/agentbrowse 0.2.9 → 0.2.11

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 CHANGED
@@ -118,8 +118,9 @@ Default verification for this package is no longer unit-only:
118
118
  - `pnpm --filter @nuanu-ai/agentbrowse test` includes local fixture browser integration coverage for runtime and extract flows
119
119
  - the default suite also covers one explicit Stagehand-assisted observe fallback plus launch/session smoke at the command boundary
120
120
 
121
- See the neutral external-agent guide:
121
+ See package docs:
122
122
 
123
- - [docs/agentbrowse/testing/agent-usage-guide.md](/Users/dmitry/Dev/mercuryo-agent-pay/docs/agentbrowse/testing/agent-usage-guide.md)
123
+ - [packages/browse-cli/docs/README.md](/Users/dmitry/Dev/mercuryo-agent-pay/packages/browse-cli/docs/README.md)
124
+ - [packages/browse-cli/docs/testing/cli-usage-guide.md](/Users/dmitry/Dev/mercuryo-agent-pay/packages/browse-cli/docs/testing/cli-usage-guide.md)
124
125
 
125
126
  Releases are published automatically from `main` after checks pass. `@nuanu-ai/agentbrowse` is the only CLI package published by the current npm release workflow.
@@ -1 +1 @@
1
- {"version":3,"file":"click-action-executor.d.ts","sourceRoot":"","sources":["../../src/commands/click-action-executor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAMrD,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,8BAA8B,CAAC;AAEtC,KAAK,iBAAiB,GAAG;IACvB,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,CAAC,EAAE,qBAAqB,CAAC;CAChC,CAAC;AAwEF,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,MAAM,EAAE,EAClB,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,OAAO,CAAC,CAElB;AAED,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,MAAM,EAAE,EAClB,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,OAAO,CAAC,CAElB"}
1
+ {"version":3,"file":"click-action-executor.d.ts","sourceRoot":"","sources":["../../src/commands/click-action-executor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAMrD,OAAO,EAA2B,KAAK,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAEnG,KAAK,iBAAiB,GAAG;IACvB,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,CAAC,EAAE,qBAAqB,CAAC;CAChC,CAAC;AA+FF,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,MAAM,EAAE,EAClB,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,OAAO,CAAC,CAElB;AAED,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,MAAM,EAAE,EAClB,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,OAAO,CAAC,CAElB"}
@@ -1,5 +1,23 @@
1
1
  import { LOCATOR_CLICK_TIMEOUT_MS, dismissBlockingOverlay, looksLikeOverlayInterference, } from './action-executor-helpers.js';
2
- import { runActionExecutionGuard, } from './action-execution-guards.js';
2
+ import { runActionExecutionGuard } from './action-execution-guards.js';
3
+ async function handoffFocusFromActiveIframe(locator, attempts) {
4
+ const focused = await locator
5
+ .evaluate((element) => {
6
+ if (!(element instanceof HTMLElement)) {
7
+ return false;
8
+ }
9
+ const active = element.ownerDocument.activeElement;
10
+ if (!(active instanceof HTMLIFrameElement)) {
11
+ return false;
12
+ }
13
+ element.focus();
14
+ return element.ownerDocument.activeElement === element;
15
+ })
16
+ .catch(() => false);
17
+ if (focused) {
18
+ attempts.push('locator.focus.handoff-from-iframe');
19
+ }
20
+ }
3
21
  async function ensureLocatorRetryReady(locator, error, options) {
4
22
  await runActionExecutionGuard(options?.guards, 'click.before-retry');
5
23
  await options?.beforeRetry?.();
@@ -9,6 +27,7 @@ async function ensureLocatorRetryReady(locator, error, options) {
9
27
  }
10
28
  }
11
29
  async function applyClickSequence(page, locator, attempts, options) {
30
+ await handoffFocusFromActiveIframe(locator, attempts);
12
31
  attempts.push('locator.click');
13
32
  try {
14
33
  await locator.click({ timeout: LOCATOR_CLICK_TIMEOUT_MS });
@@ -1 +1 @@
1
- {"version":3,"file":"observe-projection.d.ts","sourceRoot":"","sources":["../../src/commands/observe-projection.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"observe-projection.d.ts","sourceRoot":"","sources":["../../src/commands/observe-projection.ts"],"names":[],"mappings":"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"}
@@ -97,25 +97,51 @@ function isGoalObserveScopeCandidate(candidate) {
97
97
  return candidate.goalInventoryType === 'scope';
98
98
  }
99
99
  export function selectTargetsForGoalMatches(allTargets, rerankedCandidates) {
100
- const directTargetOrdinals = new Set(rerankedCandidates
101
- .filter(isGoalObserveTargetCandidate)
102
- .map((candidate) => candidate.ordinal)
103
- .filter((value) => typeof value === 'number'));
104
- const directTargetKeys = new Set(rerankedCandidates
105
- .filter(isGoalObserveTargetCandidate)
106
- .map((candidate) => candidate.goalTargetKey)
107
- .filter((value) => typeof value === 'string' && value.length > 0));
100
+ const directTargetOrdinals = new Set();
101
+ const directTargetKeys = new Set();
108
102
  const selectedSurfaceIds = new Set(rerankedCandidates
109
103
  .filter(isGoalObserveScopeCandidate)
110
104
  .map((candidate) => candidate.goalSurfaceId));
111
- const mergedTargets = allTargets.filter((target) => {
105
+ const matchedTargets = [];
106
+ const seenTargetKeys = new Set();
107
+ for (const candidate of rerankedCandidates) {
108
+ if (!isGoalObserveTargetCandidate(candidate)) {
109
+ continue;
110
+ }
111
+ if (typeof candidate.ordinal === 'number') {
112
+ directTargetOrdinals.add(candidate.ordinal);
113
+ }
114
+ if (typeof candidate.goalTargetKey === 'string' && candidate.goalTargetKey.length > 0) {
115
+ directTargetKeys.add(candidate.goalTargetKey);
116
+ }
117
+ const matchedTarget = allTargets.find((target) => {
118
+ const directMatch = typeof candidate.ordinal === 'number' &&
119
+ typeof target.ordinal === 'number' &&
120
+ target.ordinal === candidate.ordinal;
121
+ const directKeyMatch = observedTargetKey(target) === candidate.goalTargetKey;
122
+ return directMatch || directKeyMatch;
123
+ });
124
+ if (!matchedTarget) {
125
+ continue;
126
+ }
127
+ const observedKey = observedTargetKey(matchedTarget);
128
+ if (seenTargetKeys.has(observedKey)) {
129
+ continue;
130
+ }
131
+ seenTargetKeys.add(observedKey);
132
+ matchedTargets.push(matchedTarget);
133
+ }
134
+ const scopeTargets = allTargets.filter((target) => {
112
135
  const directMatch = typeof target.ordinal === 'number' && directTargetOrdinals.has(target.ordinal);
113
136
  const directKeyMatch = directTargetKeys.has(observedTargetKey(target));
114
137
  const scopeMatch = target.surfaceRef ? selectedSurfaceIds.has(target.surfaceRef) : false;
115
- return directMatch || directKeyMatch || scopeMatch;
138
+ if (directMatch || directKeyMatch) {
139
+ return false;
140
+ }
141
+ return scopeMatch;
116
142
  });
117
143
  return {
118
- targets: mergedTargets,
144
+ targets: [...matchedTargets, ...scopeTargets],
119
145
  selectedSurfaceIds,
120
146
  };
121
147
  }
@@ -125,17 +151,31 @@ export function buildExplicitScopeRefs(selectedSurfaceIds, surfaceRefMap) {
125
151
  .filter((value) => typeof value === 'string' && value.length > 0));
126
152
  }
127
153
  export function projectPersistedTargetsForGoal(domTargets, persistedTargets, selectedTargets) {
128
- const selectedOrdinals = new Set(selectedTargets
129
- .map((target) => target.ordinal)
130
- .filter((value) => typeof value === 'number'));
131
- const selectedKeys = new Set(selectedTargets.map((target) => observedTargetKey(target)));
132
- return persistedTargets.filter((target, index) => {
154
+ const persistedByKey = new Map();
155
+ const persistedByOrdinal = new Map();
156
+ persistedTargets.forEach((target, index) => {
133
157
  const domTarget = domTargets[index];
134
158
  if (!domTarget) {
135
- return false;
159
+ return;
160
+ }
161
+ persistedByKey.set(observedTargetKey(domTarget), target);
162
+ if (typeof domTarget.ordinal === 'number') {
163
+ persistedByOrdinal.set(domTarget.ordinal, target);
136
164
  }
137
- const ordinalMatch = typeof domTarget.ordinal === 'number' && selectedOrdinals.has(domTarget.ordinal);
138
- const keyMatch = selectedKeys.has(observedTargetKey(domTarget));
139
- return ordinalMatch || keyMatch;
140
165
  });
166
+ const projected = [];
167
+ const seenRefs = new Set();
168
+ for (const selectedTarget of selectedTargets) {
169
+ const byKey = persistedByKey.get(observedTargetKey(selectedTarget));
170
+ const byOrdinal = typeof selectedTarget.ordinal === 'number'
171
+ ? persistedByOrdinal.get(selectedTarget.ordinal)
172
+ : undefined;
173
+ const persistedTarget = byKey ?? byOrdinal;
174
+ if (!persistedTarget || seenRefs.has(persistedTarget.ref)) {
175
+ continue;
176
+ }
177
+ seenRefs.add(persistedTarget.ref);
178
+ projected.push(persistedTarget);
179
+ }
180
+ return projected;
141
181
  }
@@ -4,6 +4,7 @@ export declare function isPrimaryFormControlTarget(target: DomObservedTarget): b
4
4
  export declare function formGroupingKeyOf(target: DomObservedTarget): string | undefined;
5
5
  export declare function observedTargetKey(target: DomObservedTarget): string;
6
6
  export declare function expandRerankedFormTargets(targets: ReadonlyArray<DomObservedTarget>, selectedTargets: ReadonlyArray<DomObservedTarget>): DomObservedTarget[];
7
+ export declare function prioritizeGoalActionTargets(instruction: string, selectedTargets: ReadonlyArray<DomObservedTarget>): DomObservedTarget[];
7
8
  export declare function compressSemanticallyDuplicateTargets(targets: ReadonlyArray<DomObservedTarget>): DomObservedTarget[];
8
9
  export declare function annotateDomTargets(targets: ReadonlyArray<DomObservedTarget>): DomObservedTarget[];
9
10
  export declare function orderBySurfaceCompetition(targets: ReadonlyArray<DomObservedTarget>): DomObservedTarget[];
@@ -1 +1 @@
1
- {"version":3,"file":"observe-semantics.d.ts","sourceRoot":"","sources":["../../src/commands/observe-semantics.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAGhE,wBAAgB,+BAA+B,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,CAYjF;AAED,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CA6B7E;AAgBD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,GAAG,SAAS,CAQ/E;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,CAMnE;AAED,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,aAAa,CAAC,iBAAiB,CAAC,EACzC,eAAe,EAAE,aAAa,CAAC,iBAAiB,CAAC,GAChD,iBAAiB,EAAE,CAyCrB;AAqBD,wBAAgB,oCAAoC,CAClD,OAAO,EAAE,aAAa,CAAC,iBAAiB,CAAC,GACxC,iBAAiB,EAAE,CAuBrB;AAkGD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,aAAa,CAAC,iBAAiB,CAAC,GAAG,iBAAiB,EAAE,CAmDjG;AAED,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,aAAa,CAAC,iBAAiB,CAAC,GACxC,iBAAiB,EAAE,CAsFrB"}
1
+ {"version":3,"file":"observe-semantics.d.ts","sourceRoot":"","sources":["../../src/commands/observe-semantics.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAGhE,wBAAgB,+BAA+B,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,CAYjF;AAED,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CA6B7E;AAgBD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,GAAG,SAAS,CAQ/E;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,CAMnE;AAED,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,aAAa,CAAC,iBAAiB,CAAC,EACzC,eAAe,EAAE,aAAa,CAAC,iBAAiB,CAAC,GAChD,iBAAiB,EAAE,CAyCrB;AAkFD,wBAAgB,2BAA2B,CACzC,WAAW,EAAE,MAAM,EACnB,eAAe,EAAE,aAAa,CAAC,iBAAiB,CAAC,GAChD,iBAAiB,EAAE,CA6BrB;AAqBD,wBAAgB,oCAAoC,CAClD,OAAO,EAAE,aAAa,CAAC,iBAAiB,CAAC,GACxC,iBAAiB,EAAE,CAuBrB;AAkGD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,aAAa,CAAC,iBAAiB,CAAC,GAAG,iBAAiB,EAAE,CAmDjG;AAED,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,aAAa,CAAC,iBAAiB,CAAC,GACxC,iBAAiB,EAAE,CAsFrB"}
@@ -94,6 +94,93 @@ export function expandRerankedFormTargets(targets, selectedTargets) {
94
94
  return (left.label ?? '').localeCompare(right.label ?? '');
95
95
  });
96
96
  }
97
+ function parseNumericAmount(value) {
98
+ const normalized = value.replace(/,/g, '.').trim();
99
+ if (!/^\d+(?:\.\d+)?$/.test(normalized)) {
100
+ return null;
101
+ }
102
+ const parsed = Number(normalized);
103
+ return Number.isFinite(parsed) ? parsed : null;
104
+ }
105
+ function parseGoalAmount(instruction) {
106
+ const normalized = instruction.trim().toLowerCase();
107
+ if (!normalized) {
108
+ return null;
109
+ }
110
+ const currencyPattern = /\b(\d+(?:[.,]\d+)?)\s*(?:usd|us dollars?|united states dollars?|dollars?)\b|\$(\d+(?:[.,]\d+)?)/i;
111
+ const match = normalized.match(currencyPattern);
112
+ if (!match) {
113
+ return null;
114
+ }
115
+ return parseNumericAmount(match[1] ?? match[2] ?? '');
116
+ }
117
+ function goalLooksLikePurchaseStart(instruction) {
118
+ return /\b(start|buy|support|purchase|pay|checkout|donat(?:e|ion))\b/i.test(instruction);
119
+ }
120
+ function targetLabelAmount(target) {
121
+ const candidates = [
122
+ target.label,
123
+ target.displayLabel,
124
+ target.text,
125
+ target.placeholder,
126
+ target.title,
127
+ ].filter((value) => typeof value === 'string' && value.trim().length > 0);
128
+ for (const candidate of candidates) {
129
+ const currencyMatch = candidate.match(/\b(\d+(?:[.,]\d+)?)\s*(?:usd|us dollars?|united states dollars?|dollars?)\b|\$(\d+(?:[.,]\d+)?)/i);
130
+ if (currencyMatch) {
131
+ return parseNumericAmount(currencyMatch[1] ?? currencyMatch[2] ?? '');
132
+ }
133
+ const exactNumeric = parseNumericAmount(candidate);
134
+ if (exactNumeric !== null) {
135
+ return exactNumeric;
136
+ }
137
+ }
138
+ return null;
139
+ }
140
+ function isExactAmountSubmitTarget(target, amount) {
141
+ const acceptancePolicy = (target.acceptancePolicy ?? '').trim().toLowerCase();
142
+ const labelAmount = targetLabelAmount(target);
143
+ if (labelAmount !== amount) {
144
+ return false;
145
+ }
146
+ if (acceptancePolicy === 'submit') {
147
+ return true;
148
+ }
149
+ const label = `${target.label ?? ''} ${target.displayLabel ?? ''}`.toLowerCase();
150
+ return /\b(support|pay|buy|checkout|donate)\b/.test(label);
151
+ }
152
+ function isExactAmountSelectionTarget(target, amount) {
153
+ const acceptancePolicy = (target.acceptancePolicy ?? '').trim().toLowerCase();
154
+ const inputType = (target.inputType ?? '').trim().toLowerCase();
155
+ return (targetLabelAmount(target) === amount &&
156
+ (acceptancePolicy === 'selection' || inputType === 'radio'));
157
+ }
158
+ export function prioritizeGoalActionTargets(instruction, selectedTargets) {
159
+ const goalAmount = parseGoalAmount(instruction);
160
+ if (goalAmount === null || !goalLooksLikePurchaseStart(instruction)) {
161
+ return [...selectedTargets];
162
+ }
163
+ const hasExactSubmit = selectedTargets.some((target) => isExactAmountSubmitTarget(target, goalAmount));
164
+ if (!hasExactSubmit) {
165
+ return [...selectedTargets];
166
+ }
167
+ return [...selectedTargets]
168
+ .map((target, index) => ({ target, index }))
169
+ .sort((left, right) => {
170
+ const leftIsSubmit = isExactAmountSubmitTarget(left.target, goalAmount);
171
+ const rightIsSubmit = isExactAmountSubmitTarget(right.target, goalAmount);
172
+ if (leftIsSubmit !== rightIsSubmit) {
173
+ return leftIsSubmit ? -1 : 1;
174
+ }
175
+ const leftIsSelection = isExactAmountSelectionTarget(left.target, goalAmount);
176
+ const rightIsSelection = isExactAmountSelectionTarget(right.target, goalAmount);
177
+ if (leftIsSelection !== rightIsSelection) {
178
+ return leftIsSelection ? 1 : -1;
179
+ }
180
+ return left.index - right.index;
181
+ })
182
+ .map(({ target }) => target);
183
+ }
97
184
  function semanticCompressionKey(target) {
98
185
  const band = target.context?.layout?.band;
99
186
  if (band !== 'bottom') {
@@ -1 +1 @@
1
- {"version":3,"file":"observe.d.ts","sourceRoot":"","sources":["../../src/commands/observe.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AA+CnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAU/D,eAAO,MAAM,yBAAyB;;;;iBA0Ou0F,CAAC;gBAAwB,CAAC;;;;;iBAAq7vE,CAAC;gBAAwB,CAAC;;;CA1Ojx1E,CAAC;AACtE,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAGrC,CAAC;AAEF,wBAAsB,OAAO,CAAC,OAAO,EAAE,aAAa,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAmOzF"}
1
+ {"version":3,"file":"observe.d.ts","sourceRoot":"","sources":["../../src/commands/observe.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAgDnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAU/D,eAAO,MAAM,yBAAyB;;;;iBA6OguF,CAAC;gBAAwB,CAAC;;;;;iBAAq7vE,CAAC;gBAAwB,CAAC;;;CA7O1q1E,CAAC;AACtE,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAGrC,CAAC;AAEF,wBAAsB,OAAO,CAAC,OAAO,EAAE,aAAa,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAsOzF"}
@@ -11,7 +11,7 @@ import { normalizePageSignature } from './descriptor-validation.js';
11
11
  import { collectDomTargets, collectPageSignals, __testDomTargetCollection as inventoryDomTargetCollection, __testStagehandDescriptor as inventoryStagehandDescriptor, } from './observe-inventory.js';
12
12
  import { attachObservedTargetOwners, reconcileObservedTargetsForPage, persistObservedSurfacesForPage, toDomDescriptor, } from './observe-persistence.js';
13
13
  import { clearProtectedFillableFormsForPage, persistProtectedFillableFormsForPage, } from './observe-protected.js';
14
- import { annotateDomTargets, compressSemanticallyDuplicateTargets, expandRerankedFormTargets, orderBySurfaceCompetition, } from './observe-semantics.js';
14
+ import { annotateDomTargets, compressSemanticallyDuplicateTargets, expandRerankedFormTargets, orderBySurfaceCompetition, prioritizeGoalActionTargets, } from './observe-semantics.js';
15
15
  import { buildExplicitScopeRefs, buildGoalObserveInventoryCandidates, compactFillableForms, compactScopes, compactSignals, compactTargets, projectPersistedTargetsForGoal, selectTargetsForGoalMatches, } from './observe-projection.js';
16
16
  import { collectSurfaceDescriptors, selectScopesForOutput } from './observe-surfaces.js';
17
17
  import { toStagehandDescriptor } from './observe-stagehand.js';
@@ -82,7 +82,7 @@ export async function observe(session, instruction) {
82
82
  if (domTargets.length > 0) {
83
83
  const rerankedCandidates = await rerankDomTargetsForGoal(instruction, buildGoalObserveInventoryCandidates(domTargets, surfaceInputs));
84
84
  const { targets: goalMatchedTargets, selectedSurfaceIds } = selectTargetsForGoalMatches(domTargets, rerankedCandidates);
85
- const selectedTargets = expandRerankedFormTargets(domTargets, goalMatchedTargets);
85
+ const selectedTargets = prioritizeGoalActionTargets(instruction, expandRerankedFormTargets(domTargets, goalMatchedTargets));
86
86
  if (selectedTargets.length > 0 || selectedSurfaceIds.size > 0) {
87
87
  const persisted = persistObservedSurfacesForPage(session, pageRef, domTargets, {
88
88
  allSurfaceInputs: surfaceInputs,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nuanu-ai/agentbrowse",
3
- "version": "0.2.9",
3
+ "version": "0.2.11",
4
4
  "type": "module",
5
5
  "description": "Standalone browser automation CLI for AI agents: launch, observe, act, extract, and solve captcha",
6
6
  "keywords": [