@agentium/browser 2.0.5 → 2.0.7

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/dist/index.cjs CHANGED
@@ -259,12 +259,21 @@ var BrowserProvider = class {
259
259
  // ── Screenshot ───────────────────────────────────────────────────────
260
260
  async screenshot() {
261
261
  this.ensurePage();
262
- return await this.page.screenshot({ type: "png", fullPage: false });
262
+ return await this.page.screenshot({
263
+ type: "png",
264
+ fullPage: false,
265
+ scale: "css"
266
+ });
267
+ }
268
+ /** Viewport size in CSS pixels (matches screenshot dimensions). */
269
+ get viewport() {
270
+ return this._viewport;
263
271
  }
264
272
  // ── Interaction (with optional humanize) ─────────────────────────────
265
273
  async click(x, y) {
266
274
  this.ensurePage();
267
- const [fx, fy] = this.jitter(x, y);
275
+ const [cx, cy] = this.clampToViewport(x, y);
276
+ const [fx, fy] = this.jitter(cx, cy);
268
277
  if (this._humanize?.mouseMovement) {
269
278
  await this.humanMouseMove(fx, fy);
270
279
  }
@@ -278,9 +287,10 @@ var BrowserProvider = class {
278
287
  await this.humanPause();
279
288
  }
280
289
  async clickAndType(x, y, text) {
281
- await this.click(x, y);
290
+ const [cx, cy] = this.clampToViewport(x, y);
291
+ await this.click(cx, cy);
282
292
  await this.sleep(this._humanize ? this.randInt(150, 350) : 200);
283
- const [fx, fy] = this.jitter(x, y);
293
+ const [fx, fy] = this.jitter(cx, cy);
284
294
  await this.page.mouse.click(fx, fy, { clickCount: 3 });
285
295
  await this.sleep(this._humanize ? this.randInt(80, 200) : 100);
286
296
  await this.type(text);
@@ -309,8 +319,10 @@ var BrowserProvider = class {
309
319
  // ── DOM Extraction ───────────────────────────────────────────────────
310
320
  async extractDOM(opts) {
311
321
  this.ensurePage();
312
- const max = opts?.maxElements ?? 80;
322
+ const max = opts?.maxElements ?? 120;
313
323
  const elements = await this.page.evaluate((limit) => {
324
+ const doc = globalThis.document;
325
+ const win = globalThis.window;
314
326
  const selectors = [
315
327
  "a[href]",
316
328
  "button",
@@ -321,37 +333,62 @@ var BrowserProvider = class {
321
333
  "[role='link']",
322
334
  "[role='tab']",
323
335
  "[role='menuitem']",
336
+ "[role='checkbox']",
337
+ "[role='radio']",
338
+ "[role='switch']",
339
+ "[role='combobox']",
340
+ "[role='option']",
324
341
  "[onclick]",
325
- "[contenteditable='true']"
342
+ "[contenteditable='true']",
343
+ "[tabindex]:not([tabindex='-1'])"
326
344
  ];
327
- const all = globalThis.document.querySelectorAll(selectors.join(","));
328
- const lines = [];
329
- let count = 0;
330
- const vh = globalThis.window.innerHeight;
331
- const vw = globalThis.window.innerWidth;
345
+ const all = Array.from(doc.querySelectorAll(selectors.join(",")));
346
+ const vh = win.innerHeight;
347
+ const vw = win.innerWidth;
348
+ const entries = [];
349
+ const seen = /* @__PURE__ */ new Set();
332
350
  for (const el of all) {
333
- if (count >= limit) break;
351
+ if (seen.has(el)) continue;
334
352
  const rect = el.getBoundingClientRect();
335
- if (rect.width === 0 || rect.height === 0) continue;
353
+ if (rect.width < 4 || rect.height < 4) continue;
336
354
  if (rect.bottom < 0 || rect.top > vh) continue;
337
355
  if (rect.right < 0 || rect.left > vw) continue;
356
+ const style = win.getComputedStyle(el);
357
+ if (style.visibility === "hidden" || style.display === "none" || style.pointerEvents === "none" || parseFloat(style.opacity || "1") < 0.1) {
358
+ continue;
359
+ }
360
+ const cx = Math.round(Math.max(0, Math.min(vw - 1, rect.left + rect.width / 2)));
361
+ const cy = Math.round(Math.max(0, Math.min(vh - 1, rect.top + rect.height / 2)));
362
+ try {
363
+ const hit = doc.elementFromPoint(cx, cy);
364
+ if (hit && hit !== el && !el.contains(hit) && !hit.contains(el)) {
365
+ continue;
366
+ }
367
+ } catch {
368
+ }
369
+ seen.add(el);
338
370
  const tag = el.tagName.toLowerCase();
339
371
  const role = el.getAttribute("role") || tag;
340
372
  const type = el.getAttribute("type") || "";
341
- const text = (el.textContent || "").trim().slice(0, 80);
373
+ const innerText = el.innerText || el.textContent || "";
374
+ const text = innerText.trim().replace(/\s+/g, " ").slice(0, 80);
342
375
  const placeholder = el.getAttribute("placeholder") || "";
343
376
  const ariaLabel = el.getAttribute("aria-label") || "";
377
+ const title = el.getAttribute("title") || "";
378
+ const name = el.getAttribute("name") || "";
344
379
  const href = el.getAttribute("href") || "";
345
380
  const value = el.value || "";
346
- const cx = Math.round(rect.left + rect.width / 2);
347
- const cy = Math.round(rect.top + rect.height / 2);
348
- let label = ariaLabel || text || placeholder || value;
381
+ let label = ariaLabel || text || placeholder || title || value || name;
349
382
  if (!label && href) label = href.slice(0, 60);
350
383
  if (!label) label = `(${tag}${type ? ` type=${type}` : ""})`;
351
- lines.push(`[${cx},${cy}] ${role}${type ? `(${type})` : ""}: "${label}"`);
352
- count++;
384
+ entries.push({
385
+ cx,
386
+ cy,
387
+ line: `[${cx},${cy}] ${role}${type ? `(${type})` : ""}: "${label}"`
388
+ });
353
389
  }
354
- return lines.join("\n");
390
+ entries.sort((a, b) => a.cy === b.cy ? a.cx - b.cx : a.cy - b.cy);
391
+ return entries.slice(0, limit).map((e) => e.line).join("\n");
355
392
  }, max);
356
393
  return elements;
357
394
  }
@@ -459,6 +496,18 @@ var BrowserProvider = class {
459
496
  const j = this._humanize.clickJitter;
460
497
  return [x + this.randInt(-j, j), y + this.randInt(-j, j)];
461
498
  }
499
+ /**
500
+ * Safety net: clamp coordinates returned by the vision model to the actual
501
+ * viewport. If a model occasionally returns image-space coordinates from a
502
+ * 2x screenshot (despite our `scale: "css"` fix), this prevents Playwright
503
+ * from clicking at e.g. (2200, 1300) and either erroring or landing on a
504
+ * random off-screen element.
505
+ */
506
+ clampToViewport(x, y) {
507
+ const cx = Math.max(0, Math.min(this._viewport.width - 1, Math.round(x)));
508
+ const cy = Math.max(0, Math.min(this._viewport.height - 1, Math.round(y)));
509
+ return [cx, cy];
510
+ }
462
511
  /**
463
512
  * Simulate human mouse movement using Bézier-like interpolation.
464
513
  * Moves from the current mouse position to the target in small steps.
@@ -502,8 +551,12 @@ function buildSystemPrompt(viewport, extraInstructions, credentialKeys) {
502
551
  const lines = [
503
552
  `You are a browser automation agent. You receive a screenshot of a web browser and decide what action to take next to complete the user's task.`,
504
553
  ``,
505
- `## Viewport`,
506
- `The browser viewport is ${viewport.width}\xD7${viewport.height} pixels. All coordinates you provide must be within this range.`,
554
+ `## Viewport & Coordinate System`,
555
+ `- The browser viewport is ${viewport.width}\xD7${viewport.height} CSS pixels.`,
556
+ `- The screenshot you are given has EXACTLY the same dimensions: ${viewport.width}\xD7${viewport.height} pixels (top-left = 0,0).`,
557
+ `- ALL coordinates you return MUST be within 0..${viewport.width - 1} for x and 0..${viewport.height - 1} for y.`,
558
+ `- Coordinates outside this range will be rejected \u2014 your click will go nowhere.`,
559
+ `- If a "Interactive elements on page" list is provided below, PREFER its coordinates over your own visual estimation. They are exact element centers in the same coordinate system.`,
507
560
  ``,
508
561
  `## Available Actions`,
509
562
  `Respond with a JSON object containing one of these actions:`,
@@ -544,14 +597,15 @@ function buildSystemPrompt(viewport, extraInstructions, credentialKeys) {
544
597
  `## Rules`,
545
598
  `1. ALWAYS look at the screenshot carefully before deciding your action.`,
546
599
  `2. Provide coordinates that target the CENTER of the element you want to interact with.`,
547
- `3. For text inputs: click the input field first (using "type" with x/y), then the text will be typed.`,
548
- `4. After typing in a search box, you often need to press Enter \u2014 use type with text "\\n" or click the search/submit button.`,
549
- `5. If your previous action didn't produce the expected result, try a different approach.`,
550
- `6. If a page is loading or blank, use "wait" with a short delay and try again.`,
551
- `7. If you see a cookie banner or popup, dismiss it first before proceeding with the task.`,
552
- `8. NEVER hallucinate content. Only report what you can actually see on the screen.`,
553
- `9. When the task is fully complete, use "done" immediately with a comprehensive result.`,
554
- `10. If after several attempts you cannot complete the task, use "fail" with a clear reason.`,
600
+ `3. When an "Interactive elements on page" list is provided, identify the target element in that list by its visible label (button text, aria-label, placeholder, link href) and use ITS coordinates \u2014 they are the ground truth. Only fall back to visual estimation when no matching element is listed.`,
601
+ `4. For text inputs: click the input field first (using "type" with x/y), then the text will be typed.`,
602
+ `5. After typing in a search box, you often need to press Enter \u2014 use type with text "\\n" or click the search/submit button.`,
603
+ `6. If your previous click landed on the wrong element (e.g. page didn't change or a different element became focused), the target was probably misaligned \u2014 re-read the elements list and pick a different coordinate; do NOT repeat the same click.`,
604
+ `7. If a page is loading or blank, use "wait" with a short delay and try again.`,
605
+ `8. If you see a cookie banner, consent dialog, or popup, dismiss it FIRST before proceeding with the task \u2014 these often intercept clicks on elements behind them.`,
606
+ `9. NEVER hallucinate content. Only report what you can actually see on the screen.`,
607
+ `10. When the task is fully complete, use "done" immediately with a comprehensive result.`,
608
+ `11. If after several attempts you cannot complete the task, use "fail" with a clear reason.`,
555
609
  ``,
556
610
  `## Response Format`,
557
611
  `Respond with ONLY a valid JSON object. No markdown, no explanation, just the JSON action.`
@@ -657,7 +711,7 @@ var BrowserAgent = class {
657
711
  this.defaultStartUrl = config.startUrl;
658
712
  this.waitAfterAction = config.waitAfterAction ?? 1500;
659
713
  this.maxRepeats = config.maxRepeats ?? 3;
660
- this.useDOM = config.useDOM ?? false;
714
+ this.useDOM = config.useDOM ?? true;
661
715
  this.storageState = config.storageState;
662
716
  this.recordVideo = config.recordVideo;
663
717
  this.credentials = config.credentials;
package/dist/index.d.cts CHANGED
@@ -91,8 +91,10 @@ interface BrowserAgentConfig {
91
91
  /** Max consecutive identical actions before the agent auto-fails. Default: 3 */
92
92
  maxRepeats?: number;
93
93
  /**
94
- * Include a simplified DOM/accessibility tree alongside the screenshot.
95
- * Helps the model target elements more accurately. Default: false
94
+ * Include a simplified DOM/accessibility tree (each interactive element
95
+ * tagged with its exact center coordinates) alongside the screenshot.
96
+ * Dramatically improves click accuracy — strongly recommended.
97
+ * Default: true
96
98
  */
97
99
  useDOM?: boolean;
98
100
  /**
@@ -290,6 +292,11 @@ declare class BrowserProvider {
290
292
  navigate(url: string): Promise<void>;
291
293
  back(): Promise<void>;
292
294
  screenshot(): Promise<Buffer>;
295
+ /** Viewport size in CSS pixels (matches screenshot dimensions). */
296
+ get viewport(): {
297
+ width: number;
298
+ height: number;
299
+ };
293
300
  click(x: number, y: number): Promise<void>;
294
301
  type(text: string): Promise<void>;
295
302
  clickAndType(x: number, y: number, text: string): Promise<void>;
@@ -314,6 +321,14 @@ declare class BrowserProvider {
314
321
  close(): Promise<void>;
315
322
  /** Add small random offset to coordinates to avoid pixel-perfect bot patterns. */
316
323
  private jitter;
324
+ /**
325
+ * Safety net: clamp coordinates returned by the vision model to the actual
326
+ * viewport. If a model occasionally returns image-space coordinates from a
327
+ * 2x screenshot (despite our `scale: "css"` fix), this prevents Playwright
328
+ * from clicking at e.g. (2200, 1300) and either erroring or landing on a
329
+ * random off-screen element.
330
+ */
331
+ private clampToViewport;
317
332
  /**
318
333
  * Simulate human mouse movement using Bézier-like interpolation.
319
334
  * Moves from the current mouse position to the target in small steps.
package/dist/index.d.ts CHANGED
@@ -91,8 +91,10 @@ interface BrowserAgentConfig {
91
91
  /** Max consecutive identical actions before the agent auto-fails. Default: 3 */
92
92
  maxRepeats?: number;
93
93
  /**
94
- * Include a simplified DOM/accessibility tree alongside the screenshot.
95
- * Helps the model target elements more accurately. Default: false
94
+ * Include a simplified DOM/accessibility tree (each interactive element
95
+ * tagged with its exact center coordinates) alongside the screenshot.
96
+ * Dramatically improves click accuracy — strongly recommended.
97
+ * Default: true
96
98
  */
97
99
  useDOM?: boolean;
98
100
  /**
@@ -290,6 +292,11 @@ declare class BrowserProvider {
290
292
  navigate(url: string): Promise<void>;
291
293
  back(): Promise<void>;
292
294
  screenshot(): Promise<Buffer>;
295
+ /** Viewport size in CSS pixels (matches screenshot dimensions). */
296
+ get viewport(): {
297
+ width: number;
298
+ height: number;
299
+ };
293
300
  click(x: number, y: number): Promise<void>;
294
301
  type(text: string): Promise<void>;
295
302
  clickAndType(x: number, y: number, text: string): Promise<void>;
@@ -314,6 +321,14 @@ declare class BrowserProvider {
314
321
  close(): Promise<void>;
315
322
  /** Add small random offset to coordinates to avoid pixel-perfect bot patterns. */
316
323
  private jitter;
324
+ /**
325
+ * Safety net: clamp coordinates returned by the vision model to the actual
326
+ * viewport. If a model occasionally returns image-space coordinates from a
327
+ * 2x screenshot (despite our `scale: "css"` fix), this prevents Playwright
328
+ * from clicking at e.g. (2200, 1300) and either erroring or landing on a
329
+ * random off-screen element.
330
+ */
331
+ private clampToViewport;
317
332
  /**
318
333
  * Simulate human mouse movement using Bézier-like interpolation.
319
334
  * Moves from the current mouse position to the target in small steps.
package/dist/index.js CHANGED
@@ -221,12 +221,21 @@ var BrowserProvider = class {
221
221
  // ── Screenshot ───────────────────────────────────────────────────────
222
222
  async screenshot() {
223
223
  this.ensurePage();
224
- return await this.page.screenshot({ type: "png", fullPage: false });
224
+ return await this.page.screenshot({
225
+ type: "png",
226
+ fullPage: false,
227
+ scale: "css"
228
+ });
229
+ }
230
+ /** Viewport size in CSS pixels (matches screenshot dimensions). */
231
+ get viewport() {
232
+ return this._viewport;
225
233
  }
226
234
  // ── Interaction (with optional humanize) ─────────────────────────────
227
235
  async click(x, y) {
228
236
  this.ensurePage();
229
- const [fx, fy] = this.jitter(x, y);
237
+ const [cx, cy] = this.clampToViewport(x, y);
238
+ const [fx, fy] = this.jitter(cx, cy);
230
239
  if (this._humanize?.mouseMovement) {
231
240
  await this.humanMouseMove(fx, fy);
232
241
  }
@@ -240,9 +249,10 @@ var BrowserProvider = class {
240
249
  await this.humanPause();
241
250
  }
242
251
  async clickAndType(x, y, text) {
243
- await this.click(x, y);
252
+ const [cx, cy] = this.clampToViewport(x, y);
253
+ await this.click(cx, cy);
244
254
  await this.sleep(this._humanize ? this.randInt(150, 350) : 200);
245
- const [fx, fy] = this.jitter(x, y);
255
+ const [fx, fy] = this.jitter(cx, cy);
246
256
  await this.page.mouse.click(fx, fy, { clickCount: 3 });
247
257
  await this.sleep(this._humanize ? this.randInt(80, 200) : 100);
248
258
  await this.type(text);
@@ -271,8 +281,10 @@ var BrowserProvider = class {
271
281
  // ── DOM Extraction ───────────────────────────────────────────────────
272
282
  async extractDOM(opts) {
273
283
  this.ensurePage();
274
- const max = opts?.maxElements ?? 80;
284
+ const max = opts?.maxElements ?? 120;
275
285
  const elements = await this.page.evaluate((limit) => {
286
+ const doc = globalThis.document;
287
+ const win = globalThis.window;
276
288
  const selectors = [
277
289
  "a[href]",
278
290
  "button",
@@ -283,37 +295,62 @@ var BrowserProvider = class {
283
295
  "[role='link']",
284
296
  "[role='tab']",
285
297
  "[role='menuitem']",
298
+ "[role='checkbox']",
299
+ "[role='radio']",
300
+ "[role='switch']",
301
+ "[role='combobox']",
302
+ "[role='option']",
286
303
  "[onclick]",
287
- "[contenteditable='true']"
304
+ "[contenteditable='true']",
305
+ "[tabindex]:not([tabindex='-1'])"
288
306
  ];
289
- const all = globalThis.document.querySelectorAll(selectors.join(","));
290
- const lines = [];
291
- let count = 0;
292
- const vh = globalThis.window.innerHeight;
293
- const vw = globalThis.window.innerWidth;
307
+ const all = Array.from(doc.querySelectorAll(selectors.join(",")));
308
+ const vh = win.innerHeight;
309
+ const vw = win.innerWidth;
310
+ const entries = [];
311
+ const seen = /* @__PURE__ */ new Set();
294
312
  for (const el of all) {
295
- if (count >= limit) break;
313
+ if (seen.has(el)) continue;
296
314
  const rect = el.getBoundingClientRect();
297
- if (rect.width === 0 || rect.height === 0) continue;
315
+ if (rect.width < 4 || rect.height < 4) continue;
298
316
  if (rect.bottom < 0 || rect.top > vh) continue;
299
317
  if (rect.right < 0 || rect.left > vw) continue;
318
+ const style = win.getComputedStyle(el);
319
+ if (style.visibility === "hidden" || style.display === "none" || style.pointerEvents === "none" || parseFloat(style.opacity || "1") < 0.1) {
320
+ continue;
321
+ }
322
+ const cx = Math.round(Math.max(0, Math.min(vw - 1, rect.left + rect.width / 2)));
323
+ const cy = Math.round(Math.max(0, Math.min(vh - 1, rect.top + rect.height / 2)));
324
+ try {
325
+ const hit = doc.elementFromPoint(cx, cy);
326
+ if (hit && hit !== el && !el.contains(hit) && !hit.contains(el)) {
327
+ continue;
328
+ }
329
+ } catch {
330
+ }
331
+ seen.add(el);
300
332
  const tag = el.tagName.toLowerCase();
301
333
  const role = el.getAttribute("role") || tag;
302
334
  const type = el.getAttribute("type") || "";
303
- const text = (el.textContent || "").trim().slice(0, 80);
335
+ const innerText = el.innerText || el.textContent || "";
336
+ const text = innerText.trim().replace(/\s+/g, " ").slice(0, 80);
304
337
  const placeholder = el.getAttribute("placeholder") || "";
305
338
  const ariaLabel = el.getAttribute("aria-label") || "";
339
+ const title = el.getAttribute("title") || "";
340
+ const name = el.getAttribute("name") || "";
306
341
  const href = el.getAttribute("href") || "";
307
342
  const value = el.value || "";
308
- const cx = Math.round(rect.left + rect.width / 2);
309
- const cy = Math.round(rect.top + rect.height / 2);
310
- let label = ariaLabel || text || placeholder || value;
343
+ let label = ariaLabel || text || placeholder || title || value || name;
311
344
  if (!label && href) label = href.slice(0, 60);
312
345
  if (!label) label = `(${tag}${type ? ` type=${type}` : ""})`;
313
- lines.push(`[${cx},${cy}] ${role}${type ? `(${type})` : ""}: "${label}"`);
314
- count++;
346
+ entries.push({
347
+ cx,
348
+ cy,
349
+ line: `[${cx},${cy}] ${role}${type ? `(${type})` : ""}: "${label}"`
350
+ });
315
351
  }
316
- return lines.join("\n");
352
+ entries.sort((a, b) => a.cy === b.cy ? a.cx - b.cx : a.cy - b.cy);
353
+ return entries.slice(0, limit).map((e) => e.line).join("\n");
317
354
  }, max);
318
355
  return elements;
319
356
  }
@@ -421,6 +458,18 @@ var BrowserProvider = class {
421
458
  const j = this._humanize.clickJitter;
422
459
  return [x + this.randInt(-j, j), y + this.randInt(-j, j)];
423
460
  }
461
+ /**
462
+ * Safety net: clamp coordinates returned by the vision model to the actual
463
+ * viewport. If a model occasionally returns image-space coordinates from a
464
+ * 2x screenshot (despite our `scale: "css"` fix), this prevents Playwright
465
+ * from clicking at e.g. (2200, 1300) and either erroring or landing on a
466
+ * random off-screen element.
467
+ */
468
+ clampToViewport(x, y) {
469
+ const cx = Math.max(0, Math.min(this._viewport.width - 1, Math.round(x)));
470
+ const cy = Math.max(0, Math.min(this._viewport.height - 1, Math.round(y)));
471
+ return [cx, cy];
472
+ }
424
473
  /**
425
474
  * Simulate human mouse movement using Bézier-like interpolation.
426
475
  * Moves from the current mouse position to the target in small steps.
@@ -464,8 +513,12 @@ function buildSystemPrompt(viewport, extraInstructions, credentialKeys) {
464
513
  const lines = [
465
514
  `You are a browser automation agent. You receive a screenshot of a web browser and decide what action to take next to complete the user's task.`,
466
515
  ``,
467
- `## Viewport`,
468
- `The browser viewport is ${viewport.width}\xD7${viewport.height} pixels. All coordinates you provide must be within this range.`,
516
+ `## Viewport & Coordinate System`,
517
+ `- The browser viewport is ${viewport.width}\xD7${viewport.height} CSS pixels.`,
518
+ `- The screenshot you are given has EXACTLY the same dimensions: ${viewport.width}\xD7${viewport.height} pixels (top-left = 0,0).`,
519
+ `- ALL coordinates you return MUST be within 0..${viewport.width - 1} for x and 0..${viewport.height - 1} for y.`,
520
+ `- Coordinates outside this range will be rejected \u2014 your click will go nowhere.`,
521
+ `- If a "Interactive elements on page" list is provided below, PREFER its coordinates over your own visual estimation. They are exact element centers in the same coordinate system.`,
469
522
  ``,
470
523
  `## Available Actions`,
471
524
  `Respond with a JSON object containing one of these actions:`,
@@ -506,14 +559,15 @@ function buildSystemPrompt(viewport, extraInstructions, credentialKeys) {
506
559
  `## Rules`,
507
560
  `1. ALWAYS look at the screenshot carefully before deciding your action.`,
508
561
  `2. Provide coordinates that target the CENTER of the element you want to interact with.`,
509
- `3. For text inputs: click the input field first (using "type" with x/y), then the text will be typed.`,
510
- `4. After typing in a search box, you often need to press Enter \u2014 use type with text "\\n" or click the search/submit button.`,
511
- `5. If your previous action didn't produce the expected result, try a different approach.`,
512
- `6. If a page is loading or blank, use "wait" with a short delay and try again.`,
513
- `7. If you see a cookie banner or popup, dismiss it first before proceeding with the task.`,
514
- `8. NEVER hallucinate content. Only report what you can actually see on the screen.`,
515
- `9. When the task is fully complete, use "done" immediately with a comprehensive result.`,
516
- `10. If after several attempts you cannot complete the task, use "fail" with a clear reason.`,
562
+ `3. When an "Interactive elements on page" list is provided, identify the target element in that list by its visible label (button text, aria-label, placeholder, link href) and use ITS coordinates \u2014 they are the ground truth. Only fall back to visual estimation when no matching element is listed.`,
563
+ `4. For text inputs: click the input field first (using "type" with x/y), then the text will be typed.`,
564
+ `5. After typing in a search box, you often need to press Enter \u2014 use type with text "\\n" or click the search/submit button.`,
565
+ `6. If your previous click landed on the wrong element (e.g. page didn't change or a different element became focused), the target was probably misaligned \u2014 re-read the elements list and pick a different coordinate; do NOT repeat the same click.`,
566
+ `7. If a page is loading or blank, use "wait" with a short delay and try again.`,
567
+ `8. If you see a cookie banner, consent dialog, or popup, dismiss it FIRST before proceeding with the task \u2014 these often intercept clicks on elements behind them.`,
568
+ `9. NEVER hallucinate content. Only report what you can actually see on the screen.`,
569
+ `10. When the task is fully complete, use "done" immediately with a comprehensive result.`,
570
+ `11. If after several attempts you cannot complete the task, use "fail" with a clear reason.`,
517
571
  ``,
518
572
  `## Response Format`,
519
573
  `Respond with ONLY a valid JSON object. No markdown, no explanation, just the JSON action.`
@@ -619,7 +673,7 @@ var BrowserAgent = class {
619
673
  this.defaultStartUrl = config.startUrl;
620
674
  this.waitAfterAction = config.waitAfterAction ?? 1500;
621
675
  this.maxRepeats = config.maxRepeats ?? 3;
622
- this.useDOM = config.useDOM ?? false;
676
+ this.useDOM = config.useDOM ?? true;
623
677
  this.storageState = config.storageState;
624
678
  this.recordVideo = config.recordVideo;
625
679
  this.credentials = config.credentials;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentium/browser",
3
- "version": "2.0.5",
3
+ "version": "2.0.7",
4
4
  "description": "Browser automation agent for Agentium using Playwright",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -46,7 +46,7 @@
46
46
  "typescript": "^5.6.0"
47
47
  },
48
48
  "peerDependencies": {
49
- "@agentium/core": "^2.0.5",
49
+ "@agentium/core": "^2.0.7",
50
50
  "playwright": ">=1.40.0"
51
51
  },
52
52
  "peerDependenciesMeta": {