momentic 0.0.2 → 0.0.4

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.
Files changed (2) hide show
  1. package/dist/index.js +1144 -992
  2. package/package.json +2 -3
package/dist/index.js CHANGED
@@ -1,8 +1,6 @@
1
- import * as __WEBPACK_EXTERNAL_MODULE_playwright__ from "playwright";
2
- import * as __WEBPACK_EXTERNAL_MODULE_zod__ from "zod";
3
- import * as __WEBPACK_EXTERNAL_MODULE_dedent__ from "dedent";
4
- import * as __WEBPACK_EXTERNAL_MODULE_diff_lines_24b6f423__ from "diff-lines";
5
- /******/ var __webpack_modules__ = ({
1
+ /******/ (() => { // webpackBootstrap
2
+ /******/ "use strict";
3
+ /******/ var __webpack_modules__ = ({
6
4
 
7
5
  /***/ 909:
8
6
  /***/ (function(__unused_webpack_module, exports) {
@@ -333,90 +331,16 @@ function ArgumentError(message) {
333
331
  }
334
332
 
335
333
 
336
- /***/ })
334
+ /***/ }),
337
335
 
338
- /******/ });
339
- /************************************************************************/
340
- /******/ // The module cache
341
- /******/ var __webpack_module_cache__ = {};
342
- /******/
343
- /******/ // The require function
344
- /******/ function __nccwpck_require__(moduleId) {
345
- /******/ // Check if module is in cache
346
- /******/ var cachedModule = __webpack_module_cache__[moduleId];
347
- /******/ if (cachedModule !== undefined) {
348
- /******/ return cachedModule.exports;
349
- /******/ }
350
- /******/ // Create a new module (and put it into the cache)
351
- /******/ var module = __webpack_module_cache__[moduleId] = {
352
- /******/ // no module.id needed
353
- /******/ // no module.loaded needed
354
- /******/ exports: {}
355
- /******/ };
356
- /******/
357
- /******/ // Execute the module function
358
- /******/ var threw = true;
359
- /******/ try {
360
- /******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __nccwpck_require__);
361
- /******/ threw = false;
362
- /******/ } finally {
363
- /******/ if(threw) delete __webpack_module_cache__[moduleId];
364
- /******/ }
365
- /******/
366
- /******/ // Return the exports of the module
367
- /******/ return module.exports;
368
- /******/ }
369
- /******/
370
- /************************************************************************/
371
- /******/ /* webpack/runtime/compat get default export */
372
- /******/ (() => {
373
- /******/ // getDefaultExport function for compatibility with non-harmony modules
374
- /******/ __nccwpck_require__.n = (module) => {
375
- /******/ var getter = module && module.__esModule ?
376
- /******/ () => (module['default']) :
377
- /******/ () => (module);
378
- /******/ __nccwpck_require__.d(getter, { a: getter });
379
- /******/ return getter;
380
- /******/ };
381
- /******/ })();
382
- /******/
383
- /******/ /* webpack/runtime/define property getters */
384
- /******/ (() => {
385
- /******/ // define getter functions for harmony exports
386
- /******/ __nccwpck_require__.d = (exports, definition) => {
387
- /******/ for(var key in definition) {
388
- /******/ if(__nccwpck_require__.o(definition, key) && !__nccwpck_require__.o(exports, key)) {
389
- /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
390
- /******/ }
391
- /******/ }
392
- /******/ };
393
- /******/ })();
394
- /******/
395
- /******/ /* webpack/runtime/hasOwnProperty shorthand */
396
- /******/ (() => {
397
- /******/ __nccwpck_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
398
- /******/ })();
399
- /******/
400
- /******/ /* webpack/runtime/compat */
401
- /******/
402
- /******/ if (typeof __nccwpck_require__ !== 'undefined') __nccwpck_require__.ab = new URL('.', import.meta.url).pathname.slice(import.meta.url.match(/^file:\/\/\/\w:/) ? 1 : 0, -1) + "/";
403
- /******/
404
- /************************************************************************/
405
- var __webpack_exports__ = {};
406
- // This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
407
- (() => {
408
-
409
- // EXPORTS
410
- __nccwpck_require__.d(__webpack_exports__, {
411
- "_w": () => (/* reexport */ APIGenerator),
412
- "Yt": () => (/* reexport */ AgentController),
413
- "DE": () => (/* reexport */ ChromeBrowser)
414
- });
336
+ /***/ 811:
337
+ /***/ ((module, __webpack_exports__, __nccwpck_require__) => {
338
+
339
+ // ESM COMPAT FLAG
340
+ __nccwpck_require__.r(__webpack_exports__);
415
341
 
416
342
  ;// CONCATENATED MODULE: external "playwright"
417
- var x = y => { var x = {}; __nccwpck_require__.d(x, y); return x; }
418
- var y = x => () => x
419
- const external_playwright_namespaceObject = x({ ["chromium"]: () => __WEBPACK_EXTERNAL_MODULE_playwright__.chromium, ["devices"]: () => __WEBPACK_EXTERNAL_MODULE_playwright__.devices });
343
+ const external_playwright_namespaceObject = require("playwright");
420
344
  ;// CONCATENATED MODULE: ../../packages/web-agent/src/utils/url.ts
421
345
  // Returns true if 2 urls are different, ignoring differences in query params.
422
346
  const urlChanged = (url1, url2) => {
@@ -433,9 +357,7 @@ var AgentType;
433
357
  })(AgentType || (AgentType = {}));
434
358
 
435
359
  ;// CONCATENATED MODULE: external "zod"
436
- var external_zod_x = y => { var x = {}; __nccwpck_require__.d(x, y); return x; }
437
- var external_zod_y = x => () => x
438
- const external_zod_namespaceObject = external_zod_x({ ["array"]: () => __WEBPACK_EXTERNAL_MODULE_zod__.array, ["boolean"]: () => __WEBPACK_EXTERNAL_MODULE_zod__.boolean, ["coerce"]: () => __WEBPACK_EXTERNAL_MODULE_zod__.coerce, ["discriminatedUnion"]: () => __WEBPACK_EXTERNAL_MODULE_zod__.discriminatedUnion, ["literal"]: () => __WEBPACK_EXTERNAL_MODULE_zod__.literal, ["nativeEnum"]: () => __WEBPACK_EXTERNAL_MODULE_zod__.nativeEnum, ["null"]: () => __WEBPACK_EXTERNAL_MODULE_zod__["null"], ["number"]: () => __WEBPACK_EXTERNAL_MODULE_zod__.number, ["object"]: () => __WEBPACK_EXTERNAL_MODULE_zod__.object, ["string"]: () => __WEBPACK_EXTERNAL_MODULE_zod__.string, ["union"]: () => __WEBPACK_EXTERNAL_MODULE_zod__.union, ["z"]: () => __WEBPACK_EXTERNAL_MODULE_zod__.z });
360
+ const external_zod_namespaceObject = require("zod");
439
361
  ;// CONCATENATED MODULE: ../../packages/types/src/a11y-targets.ts
440
362
 
441
363
  const A11yTargetWithCacheSchema = external_zod_namespaceObject.object({
@@ -481,9 +403,8 @@ class EmptyA11yTreeError extends Error {
481
403
  }
482
404
 
483
405
  ;// CONCATENATED MODULE: external "dedent"
484
- var external_dedent_x = y => { var x = {}; __nccwpck_require__.d(x, y); return x; }
485
- var external_dedent_y = x => () => x
486
- const external_dedent_namespaceObject = external_dedent_x({ ["default"]: () => __WEBPACK_EXTERNAL_MODULE_dedent__["default"] });
406
+ const external_dedent_namespaceObject = require("dedent");
407
+ var external_dedent_default = /*#__PURE__*/__nccwpck_require__.n(external_dedent_namespaceObject);
487
408
  ;// CONCATENATED MODULE: ../../packages/types/src/preset.ts
488
409
 
489
410
 
@@ -541,7 +462,7 @@ const ClickCommandSchema = CommonCommandSchema.merge(external_zod_namespaceObjec
541
462
  target: ElementDescriptorSchema,
542
463
  doubleClick: external_zod_namespaceObject.boolean().default(false),
543
464
  rightClick: external_zod_namespaceObject.boolean().default(false),
544
- })).describe(external_dedent_namespaceObject["default"] `CLICK <id> - click on the element that has the specified id.
465
+ })).describe((external_dedent_default()) `CLICK <id> - click on the element that has the specified id.
545
466
  You are NOT allowed to click on disabled, hidden or StaticText elements.
546
467
  Only click on elements on the Current Page.
547
468
  Only click on elements with the following tag names: button, input, link, image, generic.
@@ -1073,6 +994,7 @@ function serializeAICommand(cmd) {
1073
994
  return humanSummary;
1074
995
  }
1075
996
  function serializePresetCommand(command) {
997
+ var _a;
1076
998
  switch (command.type) {
1077
999
  case preset_PresetCommandType.NAVIGATE:
1078
1000
  return `Go to URL: ${clampText(command.url, 30)}`;
@@ -1092,7 +1014,7 @@ function serializePresetCommand(command) {
1092
1014
  return `Click on '${command.target.elementDescriptor}'`;
1093
1015
  case preset_PresetCommandType.TYPE:
1094
1016
  let serializedTarget = "";
1095
- if (command.target.a11yData?.serializedForm) {
1017
+ if ((_a = command.target.a11yData) === null || _a === void 0 ? void 0 : _a.serializedForm) {
1096
1018
  serializedTarget = ` in element ${command.target.a11yData.serializedForm}`;
1097
1019
  }
1098
1020
  else if (command.target.elementDescriptor.length > 0) {
@@ -1277,10 +1199,11 @@ class ProcessedA11yNode {
1277
1199
  this.backendNodeID = params.backendNodeID;
1278
1200
  }
1279
1201
  getLogForm() {
1202
+ var _a, _b;
1280
1203
  return JSON.stringify({
1281
1204
  id: this.id,
1282
- name: this.name ?? "",
1283
- role: this.role ?? "",
1205
+ name: (_a = this.name) !== null && _a !== void 0 ? _a : "",
1206
+ role: (_b = this.role) !== null && _b !== void 0 ? _b : "",
1284
1207
  backendNodeId: this.backendNodeID,
1285
1208
  });
1286
1209
  }
@@ -1372,10 +1295,11 @@ class ProcessedA11yTree {
1372
1295
  * May not be unique in a graph.
1373
1296
  */
1374
1297
  function getNodePathIdentifier(node) {
1375
- if (node.name?.value) {
1298
+ var _a, _b;
1299
+ if ((_a = node.name) === null || _a === void 0 ? void 0 : _a.value) {
1376
1300
  return `"${node.name.value}"`;
1377
1301
  }
1378
- if (node.role?.value &&
1302
+ if (((_b = node.role) === null || _b === void 0 ? void 0 : _b.value) &&
1379
1303
  node.role.value !== "none" &&
1380
1304
  node.role.value !== "generic") {
1381
1305
  return `"${node.role.value}"`;
@@ -1383,22 +1307,23 @@ function getNodePathIdentifier(node) {
1383
1307
  return `"${node.nodeId}"`;
1384
1308
  }
1385
1309
  function processA11yTreeDFS(node, parent, inputNodeMap, outputNodeMap) {
1310
+ var _a, _b, _c, _d, _e, _f, _g;
1386
1311
  if (!parent && node.parentId) {
1387
1312
  throw new Error(`Got no parent for accessibility node ${node.nodeId}: ${JSON.stringify(node)}`);
1388
1313
  }
1389
1314
  const processedNode = new ProcessedA11yNode({
1390
1315
  id: node.nodeId,
1391
- role: node.role?.value || "",
1392
- name: node.name?.value || "",
1393
- content: node.value?.value || "",
1316
+ role: ((_a = node.role) === null || _a === void 0 ? void 0 : _a.value) || "",
1317
+ name: ((_b = node.name) === null || _b === void 0 ? void 0 : _b.value) || "",
1318
+ content: ((_c = node.value) === null || _c === void 0 ? void 0 : _c.value) || "",
1394
1319
  properties: {},
1395
1320
  children: [],
1396
1321
  pathFromRoot: (parent ? `${parent.pathFromRoot} ` : "") + getNodePathIdentifier(node),
1397
1322
  backendNodeID: node.backendDOMNodeId,
1398
1323
  // md5Sum: "",
1399
1324
  });
1400
- if (node.value?.value) {
1401
- processedNode.content = `${node.value?.value}`;
1325
+ if ((_d = node.value) === null || _d === void 0 ? void 0 : _d.value) {
1326
+ processedNode.content = `${(_e = node.value) === null || _e === void 0 ? void 0 : _e.value}`;
1402
1327
  }
1403
1328
  if (node.properties) {
1404
1329
  node.properties.forEach((prop) => {
@@ -1406,7 +1331,7 @@ function processA11yTreeDFS(node, parent, inputNodeMap, outputNodeMap) {
1406
1331
  });
1407
1332
  }
1408
1333
  outputNodeMap.set(processedNode.id, processedNode);
1409
- const children = node.childIds ?? [];
1334
+ const children = (_f = node.childIds) !== null && _f !== void 0 ? _f : [];
1410
1335
  for (const childId of children) {
1411
1336
  if (!childId) {
1412
1337
  continue;
@@ -1430,7 +1355,7 @@ function processA11yTreeDFS(node, parent, inputNodeMap, outputNodeMap) {
1430
1355
  if (processedNode.children.length === 1 &&
1431
1356
  processedNode.children[0].role === "StaticText") {
1432
1357
  const currentName = processedNode.name;
1433
- const childName = processedNode.children[0]?.name;
1358
+ const childName = (_g = processedNode.children[0]) === null || _g === void 0 ? void 0 : _g.name;
1434
1359
  if (currentName === childName || !childName) {
1435
1360
  processedNode.children = [];
1436
1361
  }
@@ -1496,12 +1421,16 @@ function processA11yTree(graph) {
1496
1421
  }
1497
1422
  // filter out nodes that are no longer rendered on the page
1498
1423
  graph.allNodes = graph.allNodes.filter((node) => {
1424
+ var _a;
1499
1425
  if (!node.ignored) {
1500
1426
  return true;
1501
1427
  }
1502
1428
  // CDP types are wrong; notRendered is a possible ignored reason
1503
- return !node.ignoredReasons?.find((reason) => reason.name === "notRendered" &&
1504
- reason.value?.value);
1429
+ return !((_a = node.ignoredReasons) === null || _a === void 0 ? void 0 : _a.find((reason) => {
1430
+ var _a;
1431
+ return reason.name === "notRendered" &&
1432
+ ((_a = reason.value) === null || _a === void 0 ? void 0 : _a.value);
1433
+ }));
1505
1434
  });
1506
1435
  const nodeMap = new Map();
1507
1436
  for (const node of graph.allNodes) {
@@ -1609,7 +1538,7 @@ function addIDsScript() {
1609
1538
  // Loop through all elements and add the property
1610
1539
  for (let i = 0; i < allElements.length; i++) {
1611
1540
  const element = allElements[i];
1612
- element?.setAttribute("data-momentic-id", currentID);
1541
+ element === null || element === void 0 ? void 0 : element.setAttribute("data-momentic-id", currentID);
1613
1542
  currentID++;
1614
1543
  }
1615
1544
  }
@@ -1678,6 +1607,15 @@ function isRequestRelevantForPageLoad(request, currentURL) {
1678
1607
 
1679
1608
 
1680
1609
  ;// CONCATENATED MODULE: ../../packages/web-agent/src/browsers/chrome.ts
1610
+ var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
1611
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
1612
+ return new (P || (P = Promise))(function (resolve, reject) {
1613
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
1614
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
1615
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
1616
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
1617
+ });
1618
+ };
1681
1619
 
1682
1620
 
1683
1621
 
@@ -1705,108 +1643,120 @@ class ChromeBrowser {
1705
1643
  /**
1706
1644
  * Creates a new browser and waits for navigation to the given test URL.
1707
1645
  */
1708
- static async init(baseURL, logger, onScreenshot, timeout = MAX_LOAD_TIMEOUT_MS) {
1709
- const browser = await external_playwright_namespaceObject.chromium.launch({ headless: true });
1710
- const context = await browser.newContext({
1711
- viewport: {
1712
- width: 1920,
1713
- height: 1080,
1714
- },
1715
- // comment out the below if you are on Mac OS but you're using a monitor
1716
- deviceScaleFactor: process.platform === "darwin"
1717
- ? RETINA_WINDOW_SCALE_FACTOR
1718
- : 1,
1719
- userAgent: external_playwright_namespaceObject.devices["Desktop Chrome"].userAgent,
1720
- geolocation: { latitude: 37.7749, longitude: -122.4194 },
1721
- locale: "en-US",
1722
- timezoneId: "America/Los_Angeles",
1723
- });
1724
- const page = await context.newPage();
1725
- const cdpClient = await context.newCDPSession(page);
1726
- const chrome = new ChromeBrowser({
1727
- browser,
1728
- context,
1729
- page,
1730
- baseURL,
1731
- cdpClient,
1732
- logger,
1733
- });
1734
- let completed = false;
1735
- const navigateAndInitCDP = async () => {
1736
- try {
1737
- await chrome.navigate(baseURL, false);
1738
- await cdpClient.send("Accessibility.enable");
1739
- await cdpClient.send("DOM.enable");
1740
- await cdpClient.send("Overlay.enable");
1741
- }
1742
- catch (err) {
1743
- logger.error({ err }, "Failed to initialize chrome browser");
1744
- }
1745
- finally {
1746
- completed = true;
1747
- }
1748
- };
1749
- void navigateAndInitCDP();
1750
- const sendScreenshot = async () => {
1751
- if (!onScreenshot) {
1752
- return;
1753
- }
1754
- try {
1755
- onScreenshot({
1756
- viewport: chrome.viewport,
1757
- buffer: await chrome.screenshot(),
1758
- });
1646
+ static init(baseURL, logger, onScreenshot, timeout = MAX_LOAD_TIMEOUT_MS) {
1647
+ return __awaiter(this, void 0, void 0, function* () {
1648
+ const browser = yield external_playwright_namespaceObject.chromium.launch({ headless: true });
1649
+ const context = yield browser.newContext({
1650
+ viewport: {
1651
+ width: 1920,
1652
+ height: 1080,
1653
+ },
1654
+ // comment out the below if you are on Mac OS but you're using a monitor
1655
+ deviceScaleFactor: process.platform === "darwin"
1656
+ ? RETINA_WINDOW_SCALE_FACTOR
1657
+ : 1,
1658
+ userAgent: external_playwright_namespaceObject.devices["Desktop Chrome"].userAgent,
1659
+ geolocation: { latitude: 37.7749, longitude: -122.4194 },
1660
+ locale: "en-US",
1661
+ timezoneId: "America/Los_Angeles",
1662
+ });
1663
+ const page = yield context.newPage();
1664
+ const cdpClient = yield context.newCDPSession(page);
1665
+ const chrome = new ChromeBrowser({
1666
+ browser,
1667
+ context,
1668
+ page,
1669
+ baseURL,
1670
+ cdpClient,
1671
+ logger,
1672
+ });
1673
+ let completed = false;
1674
+ const navigateAndInitCDP = () => __awaiter(this, void 0, void 0, function* () {
1675
+ try {
1676
+ yield chrome.navigate(baseURL, false);
1677
+ yield cdpClient.send("Accessibility.enable");
1678
+ yield cdpClient.send("DOM.enable");
1679
+ yield cdpClient.send("Overlay.enable");
1680
+ }
1681
+ catch (err) {
1682
+ logger.error({ err }, "Failed to initialize chrome browser");
1683
+ }
1684
+ finally {
1685
+ completed = true;
1686
+ }
1687
+ });
1688
+ void navigateAndInitCDP();
1689
+ const sendScreenshot = () => __awaiter(this, void 0, void 0, function* () {
1690
+ if (!onScreenshot) {
1691
+ return;
1692
+ }
1693
+ try {
1694
+ onScreenshot({
1695
+ viewport: chrome.viewport,
1696
+ buffer: yield chrome.screenshot(),
1697
+ });
1698
+ }
1699
+ catch (err) {
1700
+ logger.error({ err }, "Failed to take screenshot");
1701
+ }
1702
+ });
1703
+ void sendScreenshot();
1704
+ // NOTE: this is a very quick interval because while chome is navigating
1705
+ // we want to show updates to the user ASAP
1706
+ const screenshotInterval = setInterval(() => {
1707
+ void sendScreenshot();
1708
+ }, 250);
1709
+ const startTime = Date.now();
1710
+ while (!completed && Date.now() - startTime < timeout) {
1711
+ yield sleep(CHECK_INTERVAL_MS);
1759
1712
  }
1760
- catch (err) {
1761
- logger.error({ err }, "Failed to take screenshot");
1713
+ clearInterval(screenshotInterval);
1714
+ if (!completed) {
1715
+ logger.warn("Timeout elapsed waiting for browser to initialize - are you sure this page is accessible?");
1762
1716
  }
1763
- };
1764
- void sendScreenshot();
1765
- // NOTE: this is a very quick interval because while chome is navigating
1766
- // we want to show updates to the user ASAP
1767
- const screenshotInterval = setInterval(() => {
1768
- void sendScreenshot();
1769
- }, 250);
1770
- const startTime = Date.now();
1771
- while (!completed && Date.now() - startTime < timeout) {
1772
- await sleep(CHECK_INTERVAL_MS);
1773
- }
1774
- clearInterval(screenshotInterval);
1775
- if (!completed) {
1776
- logger.warn("Timeout elapsed waiting for browser to initialize - are you sure this page is accessible?");
1777
- }
1778
- return chrome;
1717
+ return chrome;
1718
+ });
1779
1719
  }
1780
1720
  // Things to do on every page load
1781
- async pageSetup() {
1782
- await this.page.evaluate(addCursorScript);
1783
- await this.page.evaluate(addIDsScript);
1721
+ pageSetup() {
1722
+ return __awaiter(this, void 0, void 0, function* () {
1723
+ yield this.page.evaluate(addCursorScript);
1724
+ yield this.page.evaluate(addIDsScript);
1725
+ });
1784
1726
  }
1785
- async wait(timeoutMs) {
1786
- await this.page.waitForTimeout(timeoutMs);
1727
+ wait(timeoutMs) {
1728
+ return __awaiter(this, void 0, void 0, function* () {
1729
+ yield this.page.waitForTimeout(timeoutMs);
1730
+ });
1787
1731
  }
1788
- async cleanup() {
1789
- await this.page.close();
1790
- await this.context.close();
1791
- await this.browser.close();
1732
+ cleanup() {
1733
+ return __awaiter(this, void 0, void 0, function* () {
1734
+ yield this.page.close();
1735
+ yield this.context.close();
1736
+ yield this.browser.close();
1737
+ });
1792
1738
  }
1793
1739
  get closed() {
1794
1740
  return this.page.isClosed() || !this.browser.isConnected();
1795
1741
  }
1796
- async html() {
1797
- return await this.page.content();
1742
+ html() {
1743
+ return __awaiter(this, void 0, void 0, function* () {
1744
+ return yield this.page.content();
1745
+ });
1798
1746
  }
1799
1747
  get url() {
1800
1748
  return this.page.url();
1801
1749
  }
1802
- async screenshot(quality = 100, scale = "device") {
1803
- return await this.page.screenshot({
1804
- fullPage: false,
1805
- quality,
1806
- scale,
1807
- type: "jpeg",
1808
- // allow the blinking text cursor thing to remain there
1809
- caret: "initial",
1750
+ screenshot(quality = 100, scale = "device") {
1751
+ return __awaiter(this, void 0, void 0, function* () {
1752
+ return yield this.page.screenshot({
1753
+ fullPage: false,
1754
+ quality,
1755
+ scale,
1756
+ type: "jpeg",
1757
+ // allow the blinking text cursor thing to remain there
1758
+ caret: "initial",
1759
+ });
1810
1760
  });
1811
1761
  }
1812
1762
  get viewport() {
@@ -1816,502 +1766,560 @@ class ChromeBrowser {
1816
1766
  }
1817
1767
  return viewport;
1818
1768
  }
1819
- async navigate(url,
1769
+ navigate(url,
1820
1770
  // FIXME: this is an escape hatch to make sure some pages load (assembledhq.com)
1821
1771
  wrapPossibleNavigation = true) {
1822
- this.logger.debug(`Navigating to ${url}`);
1823
- const startTime = Date.now();
1824
- const doNav = async () => {
1825
- try {
1826
- await this.page.goto(url, {
1827
- timeout: MAX_LOAD_TIMEOUT_MS,
1828
- });
1829
- this.logger.debug({ url }, `Got load event in ${Math.floor(Date.now() - startTime)}ms`);
1772
+ return __awaiter(this, void 0, void 0, function* () {
1773
+ this.logger.debug(`Navigating to ${url}`);
1774
+ const startTime = Date.now();
1775
+ const doNav = () => __awaiter(this, void 0, void 0, function* () {
1776
+ try {
1777
+ yield this.page.goto(url, {
1778
+ timeout: MAX_LOAD_TIMEOUT_MS,
1779
+ });
1780
+ this.logger.debug({ url }, `Got load event in ${Math.floor(Date.now() - startTime)}ms`);
1781
+ }
1782
+ catch (e) {
1783
+ this.logger.warn({ url, type: "navigate", err: e }, "Timeout elapsed waiting for page to load, continuing anyways...");
1784
+ }
1785
+ });
1786
+ if (wrapPossibleNavigation) {
1787
+ yield this.wrapPossibleNavigation(doNav);
1830
1788
  }
1831
- catch (e) {
1832
- this.logger.warn({ url, type: "navigate", err: e }, "Timeout elapsed waiting for page to load, continuing anyways...");
1789
+ else {
1790
+ yield doNav();
1833
1791
  }
1834
- };
1835
- if (wrapPossibleNavigation) {
1836
- await this.wrapPossibleNavigation(doNav);
1837
- }
1838
- else {
1839
- await doNav();
1840
- }
1841
- if (CHROME_INTERNAL_URLS.has(this.url) &&
1842
- process.env.NODE_ENV === "production") {
1843
- // in dev, this is a little annoying
1844
- throw new Error(`${url} took too long to load 😞. Please ensure the site and your internet are working.`);
1845
- }
1846
- await this.pageSetup();
1847
- this.logger.debug({ url }, "Navigation complete");
1848
- }
1849
- async fill(target, text, options = {}) {
1850
- const element = await this.click(target, {
1851
- doubleClick: false,
1852
- rightClick: false,
1792
+ if (CHROME_INTERNAL_URLS.has(this.url) &&
1793
+ process.env.NODE_ENV === "production") {
1794
+ // in dev, this is a little annoying
1795
+ throw new Error(`${url} took too long to load 😞. Please ensure the site and your internet are working.`);
1796
+ }
1797
+ yield this.pageSetup();
1798
+ this.logger.debug({ url }, "Navigation complete");
1853
1799
  });
1854
- await this.type(text, options);
1855
- return element;
1856
- }
1857
- async type(text, options = {}) {
1858
- const { clearContent = true, pressKeysSequentially = false } = options;
1859
- if (clearContent) {
1860
- await this.page.keyboard.press("Meta+A");
1861
- await this.page.keyboard.press("Backspace");
1862
- }
1863
- if (pressKeysSequentially) {
1864
- await this.page.keyboard.type(text);
1865
- }
1866
- else {
1867
- await this.page.keyboard.insertText(text);
1868
- }
1869
1800
  }
1870
- async clickByA11yID(index, options = {}) {
1871
- const node = this.nodeMap.get(`${index}`);
1872
- if (!node) {
1873
- throw new Error(`Could not find node in DOM with index: ${index}`);
1874
- }
1875
- const nodeClicked = await this.clickUsingCDP(node, options);
1876
- await this.highlightNode(nodeClicked);
1877
- return node.serialize({ noChildren: true, noProperties: true, noID: true });
1878
- }
1879
- async selectOptionByA11yID(index, option) {
1880
- const node = this.nodeMap.get(`${index}`);
1881
- if (!node) {
1882
- throw new Error(`Could not find node in DOM with index: ${index}`);
1883
- }
1884
- if (!node.backendNodeID) {
1885
- throw new Error(`Select target missing backend node id: ${node.getLogForm()}`);
1886
- }
1887
- const locator = await this.getLocatorFromBackendID(node.backendNodeID);
1888
- await locator.selectOption(option, {
1889
- timeout: COMPLICATED_BROWSER_ACTION_TIMEOUT_MS,
1801
+ fill(target, text, options = {}) {
1802
+ return __awaiter(this, void 0, void 0, function* () {
1803
+ const element = yield this.click(target, {
1804
+ doubleClick: false,
1805
+ rightClick: false,
1806
+ });
1807
+ yield this.type(text, options);
1808
+ return element;
1890
1809
  });
1891
- await this.highlightNode(node);
1892
- return node.serialize({ noChildren: true, noProperties: true, noID: true });
1893
1810
  }
1894
- async highlight(target) {
1895
- try {
1896
- await this.highlightByA11yID(target.id);
1897
- }
1898
- catch (err) {
1899
- // should never be fatal
1900
- this.logger.warn({ err, target }, "Failed to highlight target");
1901
- }
1811
+ type(text, options = {}) {
1812
+ return __awaiter(this, void 0, void 0, function* () {
1813
+ const { clearContent = true, pressKeysSequentially = false } = options;
1814
+ if (clearContent) {
1815
+ yield this.page.keyboard.press("Meta+A");
1816
+ yield this.page.keyboard.press("Backspace");
1817
+ }
1818
+ if (pressKeysSequentially) {
1819
+ yield this.page.keyboard.type(text);
1820
+ }
1821
+ else {
1822
+ yield this.page.keyboard.insertText(text);
1823
+ }
1824
+ });
1902
1825
  }
1903
- async highlightByA11yID(index) {
1904
- const node = this.nodeMap.get(`${index}`);
1905
- if (!node) {
1906
- throw new Error(`Could not find node in DOM with index: ${index}`);
1907
- }
1908
- if (!node.backendNodeID) {
1909
- throw new Error(`Select target missing backend node id: ${node.getLogForm()}`);
1910
- }
1911
- await this.highlightNode(node);
1826
+ clickByA11yID(index, options = {}) {
1827
+ return __awaiter(this, void 0, void 0, function* () {
1828
+ const node = this.nodeMap.get(`${index}`);
1829
+ if (!node) {
1830
+ throw new Error(`Could not find node in DOM with index: ${index}`);
1831
+ }
1832
+ const nodeClicked = yield this.clickUsingCDP(node, options);
1833
+ yield this.highlightNode(nodeClicked);
1834
+ return node.serialize({ noChildren: true, noProperties: true, noID: true });
1835
+ });
1912
1836
  }
1913
- async highlightNode(node) {
1914
- try {
1915
- await this.cdpClient.send("Overlay.highlightNode", {
1916
- highlightConfig: NODE_HIGHLIGHT_CONFIG,
1917
- backendNodeId: node.backendNodeID,
1837
+ selectOptionByA11yID(index, option) {
1838
+ return __awaiter(this, void 0, void 0, function* () {
1839
+ const node = this.nodeMap.get(`${index}`);
1840
+ if (!node) {
1841
+ throw new Error(`Could not find node in DOM with index: ${index}`);
1842
+ }
1843
+ if (!node.backendNodeID) {
1844
+ throw new Error(`Select target missing backend node id: ${node.getLogForm()}`);
1845
+ }
1846
+ const locator = yield this.getLocatorFromBackendID(node.backendNodeID);
1847
+ yield locator.selectOption(option, {
1848
+ timeout: COMPLICATED_BROWSER_ACTION_TIMEOUT_MS,
1918
1849
  });
1919
- }
1920
- catch (err) {
1921
- this.logger.warn({ err }, "Failed to add node highlight");
1922
- }
1923
- const hideHighlight = async () => {
1850
+ yield this.highlightNode(node);
1851
+ return node.serialize({ noChildren: true, noProperties: true, noID: true });
1852
+ });
1853
+ }
1854
+ highlight(target) {
1855
+ return __awaiter(this, void 0, void 0, function* () {
1924
1856
  try {
1925
- await this.cdpClient.send("Overlay.hideHighlight", {
1926
- backendNodeId: node.backendNodeID,
1927
- });
1857
+ yield this.highlightByA11yID(target.id);
1928
1858
  }
1929
1859
  catch (err) {
1930
- // this is okay, purely visual and often occurs due to navigation
1931
- this.logger.debug({ err }, "Failed to remove node highlight");
1860
+ // should never be fatal
1861
+ this.logger.warn({ err, target }, "Failed to highlight target");
1932
1862
  }
1933
- };
1934
- setTimeout(() => {
1935
- void hideHighlight();
1936
- }, HIGHLIGHT_DURATION_MS);
1937
- }
1938
- async wrapPossibleNavigation(fn, timeoutMS = MAX_LOAD_TIMEOUT_MS) {
1939
- const startTime = Date.now();
1940
- const startURL = this.url;
1941
- let lastRequestReceived = Date.now();
1942
- const firedRequests = new Map();
1943
- const finishedRequests = new Map();
1944
- const requestFinishedListener = (request) => {
1945
- const key = serializeRequest(request);
1946
- finishedRequests.set(key, (finishedRequests.get(key) ?? 0) + 1);
1947
- };
1948
- const requestFiredListener = (request) => {
1949
- if (!isRequestRelevantForPageLoad(request, this.url)) {
1950
- this.logger.debug({
1951
- uri: serializeRequest(request),
1952
- }, "Ignoring request for page load network stability");
1953
- return;
1863
+ });
1864
+ }
1865
+ highlightByA11yID(index) {
1866
+ return __awaiter(this, void 0, void 0, function* () {
1867
+ const node = this.nodeMap.get(`${index}`);
1868
+ if (!node) {
1869
+ throw new Error(`Could not find node in DOM with index: ${index}`);
1954
1870
  }
1955
- const key = serializeRequest(request);
1956
- this.logger.debug({
1957
- uri: key,
1958
- }, "Request fired on page load, delaying network stability");
1959
- firedRequests.set(key, (firedRequests.get(key) ?? 0) + 1);
1960
- lastRequestReceived = Date.now();
1961
- };
1962
- this.page.on("requestfinished", requestFinishedListener);
1963
- this.page.on("request", requestFiredListener);
1964
- // fire actual function asynchronously
1965
- // instead of throwing the error, we return it so we can handle it later
1966
- let rejected = false;
1967
- const retPromise = fn().catch((e) => {
1968
- rejected = true;
1969
- if (e instanceof Error)
1970
- return e;
1971
- // we are returning NOT throwing on purpose
1972
- return new Error(`${e}`);
1871
+ if (!node.backendNodeID) {
1872
+ throw new Error(`Select target missing backend node id: ${node.getLogForm()}`);
1873
+ }
1874
+ yield this.highlightNode(node);
1973
1875
  });
1974
- await sleep(CHECK_INTERVAL_MS);
1975
- const unwrapAndThrowError = async (p) => {
1976
- const v = await p;
1977
- if (v instanceof Error) {
1978
- throw v;
1876
+ }
1877
+ highlightNode(node) {
1878
+ return __awaiter(this, void 0, void 0, function* () {
1879
+ try {
1880
+ yield this.cdpClient.send("Overlay.highlightNode", {
1881
+ highlightConfig: NODE_HIGHLIGHT_CONFIG,
1882
+ backendNodeId: node.backendNodeID,
1883
+ });
1979
1884
  }
1980
- return v;
1981
- };
1982
- // wait for network idle
1983
- let unfinishedRequests = new Set();
1984
- const waitForNetworkIdle = async () => {
1985
- while (!rejected && Date.now() - startTime < timeoutMS) {
1986
- unfinishedRequests = new Set();
1987
- await sleep(CHECK_INTERVAL_MS);
1988
- if (Date.now() - lastRequestReceived <=
1989
- NETWORK_STABLE_DURATION_MS) {
1990
- continue;
1885
+ catch (err) {
1886
+ this.logger.warn({ err }, "Failed to add node highlight");
1887
+ }
1888
+ const hideHighlight = () => __awaiter(this, void 0, void 0, function* () {
1889
+ try {
1890
+ yield this.cdpClient.send("Overlay.hideHighlight", {
1891
+ backendNodeId: node.backendNodeID,
1892
+ });
1991
1893
  }
1992
- let anyDifference = false;
1993
- for (const key of firedRequests.keys()) {
1994
- if (firedRequests.get(key) !== finishedRequests.get(key)) {
1995
- this.logger.debug({ uri: key }, "Waiting on request to finish");
1996
- anyDifference = true;
1997
- unfinishedRequests.add(key);
1998
- }
1894
+ catch (err) {
1895
+ // this is okay, purely visual and often occurs due to navigation
1896
+ this.logger.debug({ err }, "Failed to remove node highlight");
1999
1897
  }
2000
- if (!anyDifference) {
1898
+ });
1899
+ setTimeout(() => {
1900
+ void hideHighlight();
1901
+ }, HIGHLIGHT_DURATION_MS);
1902
+ });
1903
+ }
1904
+ wrapPossibleNavigation(fn, timeoutMS = MAX_LOAD_TIMEOUT_MS) {
1905
+ return __awaiter(this, void 0, void 0, function* () {
1906
+ const startTime = Date.now();
1907
+ const startURL = this.url;
1908
+ let lastRequestReceived = Date.now();
1909
+ const firedRequests = new Map();
1910
+ const finishedRequests = new Map();
1911
+ const requestFinishedListener = (request) => {
1912
+ var _a;
1913
+ const key = serializeRequest(request);
1914
+ finishedRequests.set(key, ((_a = finishedRequests.get(key)) !== null && _a !== void 0 ? _a : 0) + 1);
1915
+ };
1916
+ const requestFiredListener = (request) => {
1917
+ var _a;
1918
+ if (!isRequestRelevantForPageLoad(request, this.url)) {
2001
1919
  this.logger.debug({
1920
+ uri: serializeRequest(request),
1921
+ }, "Ignoring request for page load network stability");
1922
+ return;
1923
+ }
1924
+ const key = serializeRequest(request);
1925
+ this.logger.debug({
1926
+ uri: key,
1927
+ }, "Request fired on page load, delaying network stability");
1928
+ firedRequests.set(key, ((_a = firedRequests.get(key)) !== null && _a !== void 0 ? _a : 0) + 1);
1929
+ lastRequestReceived = Date.now();
1930
+ };
1931
+ this.page.on("requestfinished", requestFinishedListener);
1932
+ this.page.on("request", requestFiredListener);
1933
+ // fire actual function asynchronously
1934
+ // instead of throwing the error, we return it so we can handle it later
1935
+ let rejected = false;
1936
+ const retPromise = fn().catch((e) => {
1937
+ rejected = true;
1938
+ if (e instanceof Error)
1939
+ return e;
1940
+ // we are returning NOT throwing on purpose
1941
+ return new Error(`${e}`);
1942
+ });
1943
+ yield sleep(CHECK_INTERVAL_MS);
1944
+ const unwrapAndThrowError = (p) => __awaiter(this, void 0, void 0, function* () {
1945
+ const v = yield p;
1946
+ if (v instanceof Error) {
1947
+ throw v;
1948
+ }
1949
+ return v;
1950
+ });
1951
+ // wait for network idle
1952
+ let unfinishedRequests = new Set();
1953
+ const waitForNetworkIdle = () => __awaiter(this, void 0, void 0, function* () {
1954
+ while (!rejected && Date.now() - startTime < timeoutMS) {
1955
+ unfinishedRequests = new Set();
1956
+ yield sleep(CHECK_INTERVAL_MS);
1957
+ if (Date.now() - lastRequestReceived <=
1958
+ NETWORK_STABLE_DURATION_MS) {
1959
+ continue;
1960
+ }
1961
+ let anyDifference = false;
1962
+ for (const key of firedRequests.keys()) {
1963
+ if (firedRequests.get(key) !== finishedRequests.get(key)) {
1964
+ this.logger.debug({ uri: key }, "Waiting on request to finish");
1965
+ anyDifference = true;
1966
+ unfinishedRequests.add(key);
1967
+ }
1968
+ }
1969
+ if (!anyDifference) {
1970
+ this.logger.debug({
1971
+ url: this.url,
1972
+ requests: JSON.stringify(Array.from(firedRequests.entries())),
1973
+ }, `Network idle in ${Math.floor(Date.now() - startTime)}ms`);
1974
+ return true;
1975
+ }
1976
+ }
1977
+ if (!rejected) {
1978
+ this.logger.warn({
2002
1979
  url: this.url,
2003
- requests: JSON.stringify(Array.from(firedRequests.entries())),
2004
- }, `Network idle in ${Math.floor(Date.now() - startTime)}ms`);
2005
- return true;
1980
+ requests: JSON.stringify(Array.from(unfinishedRequests.entries())),
1981
+ }, "Timeout elapsed waiting for network idle, continuing anyways...");
2006
1982
  }
1983
+ return false;
1984
+ });
1985
+ const waitResult = yield waitForNetworkIdle();
1986
+ this.page.off("requestfinished", requestFinishedListener);
1987
+ this.page.off("request", requestFiredListener);
1988
+ if (!waitResult) {
1989
+ return unwrapAndThrowError(retPromise);
2007
1990
  }
2008
- if (!rejected) {
2009
- this.logger.warn({
2010
- url: this.url,
2011
- requests: JSON.stringify(Array.from(unfinishedRequests.entries())),
2012
- }, "Timeout elapsed waiting for network idle, continuing anyways...");
1991
+ if (!rejected && urlChanged(this.url, startURL)) {
1992
+ this.logger.debug(`Detected url change in wrapPossibleNavigation, waiting for load state`);
1993
+ try {
1994
+ yield this.page.waitForLoadState("load", {
1995
+ timeout: timeoutMS - (Date.now() - startTime),
1996
+ });
1997
+ }
1998
+ catch (e) {
1999
+ this.logger.warn({ url: this.url }, "Timeout elapsed waiting for load state to fire, continuing anyways...");
2000
+ }
2013
2001
  }
2014
- return false;
2015
- };
2016
- const waitResult = await waitForNetworkIdle();
2017
- this.page.off("requestfinished", requestFinishedListener);
2018
- this.page.off("request", requestFiredListener);
2019
- if (!waitResult) {
2020
2002
  return unwrapAndThrowError(retPromise);
2021
- }
2022
- if (!rejected && urlChanged(this.url, startURL)) {
2023
- this.logger.debug(`Detected url change in wrapPossibleNavigation, waiting for load state`);
2024
- try {
2025
- await this.page.waitForLoadState("load", {
2026
- timeout: timeoutMS - (Date.now() - startTime),
2027
- });
2028
- }
2029
- catch (e) {
2030
- this.logger.warn({ url: this.url }, "Timeout elapsed waiting for load state to fire, continuing anyways...");
2031
- }
2032
- }
2033
- return unwrapAndThrowError(retPromise);
2003
+ });
2034
2004
  }
2035
- async click(target, options = {}) {
2036
- const elementInteracted = await this.wrapPossibleNavigation(() => this.clickByA11yID(target.id, options));
2037
- return elementInteracted;
2005
+ click(target, options = {}) {
2006
+ return __awaiter(this, void 0, void 0, function* () {
2007
+ const elementInteracted = yield this.wrapPossibleNavigation(() => this.clickByA11yID(target.id, options));
2008
+ return elementInteracted;
2009
+ });
2038
2010
  }
2039
- async selectOption(target, option) {
2040
- return this.selectOptionByA11yID(target.id, option);
2011
+ selectOption(target, option) {
2012
+ return __awaiter(this, void 0, void 0, function* () {
2013
+ return this.selectOptionByA11yID(target.id, option);
2014
+ });
2041
2015
  }
2042
- async press(key) {
2043
- await this.wrapPossibleNavigation(() => this.page.keyboard.press(key));
2016
+ press(key) {
2017
+ return __awaiter(this, void 0, void 0, function* () {
2018
+ yield this.wrapPossibleNavigation(() => this.page.keyboard.press(key));
2019
+ });
2044
2020
  }
2045
- async refresh() {
2046
- await this.page.reload();
2047
- await this.pageSetup();
2021
+ refresh() {
2022
+ return __awaiter(this, void 0, void 0, function* () {
2023
+ yield this.page.reload();
2024
+ yield this.pageSetup();
2025
+ });
2048
2026
  }
2049
- async getA11yTree() {
2050
- let processedTree = null;
2051
- let attempt = 0;
2052
- const url = this.url;
2053
- while (!processedTree) {
2054
- try {
2055
- this.logger.debug(`Getting a11y tree at ${url}`);
2056
- const graph = await this.getRawA11yTree();
2057
- if (!graph.root || graph.allNodes.length === 0) {
2058
- // throw specific error class
2059
- throw new Error("No a11y tree found on page");
2060
- }
2061
- processedTree = processA11yTree(graph);
2062
- }
2063
- catch (e) {
2064
- this.logger.error({ err: e, url }, "Error fetching a11y tree");
2065
- if (attempt === 0) {
2066
- await sleep(1000);
2067
- attempt++;
2027
+ getA11yTree() {
2028
+ return __awaiter(this, void 0, void 0, function* () {
2029
+ let processedTree = null;
2030
+ let attempt = 0;
2031
+ const url = this.url;
2032
+ while (!processedTree) {
2033
+ try {
2034
+ this.logger.debug(`Getting a11y tree at ${url}`);
2035
+ const graph = yield this.getRawA11yTree();
2036
+ if (!graph.root || graph.allNodes.length === 0) {
2037
+ // throw specific error class
2038
+ throw new Error("No a11y tree found on page");
2039
+ }
2040
+ processedTree = processA11yTree(graph);
2068
2041
  }
2069
- else {
2070
- throw new Error(`Max retries exceeded fetching a11y tree: ${e}`);
2042
+ catch (e) {
2043
+ this.logger.error({ err: e, url }, "Error fetching a11y tree");
2044
+ if (attempt === 0) {
2045
+ yield sleep(1000);
2046
+ attempt++;
2047
+ }
2048
+ else {
2049
+ throw new Error(`Max retries exceeded fetching a11y tree: ${e}`);
2050
+ }
2071
2051
  }
2072
2052
  }
2073
- }
2074
- if (!processedTree.root) {
2075
- // could be valid!
2076
- this.logger.warn("A11y tree was pruned entirely");
2077
- }
2078
- this.nodeMap = processedTree.nodeMap;
2079
- return processedTree;
2080
- }
2081
- async getRawA11yTree() {
2082
- const url = this.page.url();
2083
- let lastTreeUpdateTimestamp = Date.now();
2084
- const treeUpdateListener = () => {
2085
- lastTreeUpdateTimestamp = Date.now();
2086
- };
2087
- this.cdpClient.addListener("Accessibility.nodesUpdated", treeUpdateListener);
2088
- let accessibilityTreeLoadFired = false;
2089
- const accessibilityLoadListener = () => {
2090
- this.logger.info({ url }, `A11y tree load event fired`);
2091
- accessibilityTreeLoadFired = true;
2092
- };
2093
- this.cdpClient.addListener("Accessibility.loadComplete", accessibilityLoadListener);
2094
- // make sure the a11y tree hasn't updated in the last 1 second
2095
- // and the a11y event has fired
2096
- const a11yLoadStart = Date.now();
2097
- let timeoutTriggered = true;
2098
- while (Date.now() - a11yLoadStart < A11Y_STABLE_TIMEOUT_MS) {
2099
- await sleep(CHECK_INTERVAL_MS);
2100
- if (!accessibilityTreeLoadFired &&
2101
- Date.now() - a11yLoadStart < A11Y_LOAD_TIMEOUT_MS) {
2102
- // some websites never fire the a11y load event
2103
- // thus, we only allocate 1 second for catching this event
2104
- this.logger.debug({ url }, `A11y tree not loaded yet, waiting...`);
2105
- continue;
2106
- }
2107
- if (Date.now() - lastTreeUpdateTimestamp >=
2108
- A11Y_STABLE_DURATION_MS) {
2109
- this.logger.debug({ url }, `A11y tree not stable yet, waiting...`);
2110
- continue;
2053
+ if (!processedTree.root) {
2054
+ // could be valid!
2055
+ this.logger.warn("A11y tree was pruned entirely");
2111
2056
  }
2112
- timeoutTriggered = false;
2113
- break;
2114
- }
2115
- this.logger.debug({
2116
- duration: Date.now() - a11yLoadStart,
2117
- eventReceived: accessibilityTreeLoadFired,
2118
- timeoutTriggered,
2119
- }, "A11y wait phase completed");
2120
- const { node: root } = await this.cdpClient.send("Accessibility.getRootAXNode");
2121
- const { nodes } = await this.cdpClient.send("Accessibility.queryAXTree", {
2122
- backendNodeId: root.backendDOMNodeId,
2057
+ this.nodeMap = processedTree.nodeMap;
2058
+ return processedTree;
2123
2059
  });
2124
- this.cdpClient.removeListener("Accessibility.loadComplete", accessibilityLoadListener);
2125
- this.cdpClient.removeListener("Accessibility.nodesUpdated", treeUpdateListener);
2126
- return {
2127
- root,
2128
- allNodes: nodes,
2129
- };
2130
- }
2131
- async clickUsingVisualCoordinates(backendNodeId) {
2132
- const location = await this.getElementLocation(backendNodeId);
2133
- if (!location) {
2134
- throw new Error(`Could not find element location with backend node id: ${backendNodeId}`);
2135
- }
2136
- this.logger.debug({ location }, "Executing mouse click");
2137
- await this.page.mouse.click(location.centerX, location.centerY);
2138
2060
  }
2139
- // Get the "id" attribute value from an HTML element.
2140
- async getIDAttributeUsingCDP(objectId) {
2141
- // https://bugs.chromium.org/p/chromium/issues/detail?id=1374241
2142
- await this.cdpClient.send("DOM.getDocument", { depth: 0 });
2143
- const cdpNodeResult = await this.cdpClient.send("DOM.requestNode", {
2144
- objectId,
2145
- });
2146
- const attrResult = await this.cdpClient.send("DOM.getAttributes", {
2147
- nodeId: cdpNodeResult.nodeId,
2061
+ getRawA11yTree() {
2062
+ return __awaiter(this, void 0, void 0, function* () {
2063
+ const url = this.page.url();
2064
+ let lastTreeUpdateTimestamp = Date.now();
2065
+ const treeUpdateListener = () => {
2066
+ lastTreeUpdateTimestamp = Date.now();
2067
+ };
2068
+ this.cdpClient.addListener("Accessibility.nodesUpdated", treeUpdateListener);
2069
+ let accessibilityTreeLoadFired = false;
2070
+ const accessibilityLoadListener = () => {
2071
+ this.logger.info({ url }, `A11y tree load event fired`);
2072
+ accessibilityTreeLoadFired = true;
2073
+ };
2074
+ this.cdpClient.addListener("Accessibility.loadComplete", accessibilityLoadListener);
2075
+ // make sure the a11y tree hasn't updated in the last 1 second
2076
+ // and the a11y event has fired
2077
+ const a11yLoadStart = Date.now();
2078
+ let timeoutTriggered = true;
2079
+ while (Date.now() - a11yLoadStart < A11Y_STABLE_TIMEOUT_MS) {
2080
+ yield sleep(CHECK_INTERVAL_MS);
2081
+ if (!accessibilityTreeLoadFired &&
2082
+ Date.now() - a11yLoadStart < A11Y_LOAD_TIMEOUT_MS) {
2083
+ // some websites never fire the a11y load event
2084
+ // thus, we only allocate 1 second for catching this event
2085
+ this.logger.debug({ url }, `A11y tree not loaded yet, waiting...`);
2086
+ continue;
2087
+ }
2088
+ if (Date.now() - lastTreeUpdateTimestamp >=
2089
+ A11Y_STABLE_DURATION_MS) {
2090
+ this.logger.debug({ url }, `A11y tree not stable yet, waiting...`);
2091
+ continue;
2092
+ }
2093
+ timeoutTriggered = false;
2094
+ break;
2095
+ }
2096
+ this.logger.debug({
2097
+ duration: Date.now() - a11yLoadStart,
2098
+ eventReceived: accessibilityTreeLoadFired,
2099
+ timeoutTriggered,
2100
+ }, "A11y wait phase completed");
2101
+ const { node: root } = yield this.cdpClient.send("Accessibility.getRootAXNode");
2102
+ const { nodes } = yield this.cdpClient.send("Accessibility.queryAXTree", {
2103
+ backendNodeId: root.backendDOMNodeId,
2104
+ });
2105
+ this.cdpClient.removeListener("Accessibility.loadComplete", accessibilityLoadListener);
2106
+ this.cdpClient.removeListener("Accessibility.nodesUpdated", treeUpdateListener);
2107
+ return {
2108
+ root,
2109
+ allNodes: nodes,
2110
+ };
2148
2111
  });
2149
- const attributes = attrResult.attributes;
2150
- const indexAttr = attributes.findIndex((s) => s === "data-momentic-id");
2151
- if (indexAttr === -1) {
2152
- return "";
2153
- }
2154
- return attributes[indexAttr + 1] || "";
2155
2112
  }
2156
- async getLocatorFromBackendID(backendNodeId) {
2157
- await this.page.evaluate(addIDsScript);
2158
- // get a remote javascript object from the a11y backend node ID
2159
- const cdpResolveResult = await this.cdpClient.send("DOM.resolveNode", {
2160
- backendNodeId,
2113
+ clickUsingVisualCoordinates(backendNodeId) {
2114
+ return __awaiter(this, void 0, void 0, function* () {
2115
+ const location = yield this.getElementLocation(backendNodeId);
2116
+ if (!location) {
2117
+ throw new Error(`Could not find element location with backend node id: ${backendNodeId}`);
2118
+ }
2119
+ this.logger.debug({ location }, "Executing mouse click");
2120
+ yield this.page.mouse.click(location.centerX, location.centerY);
2161
2121
  });
2162
- if (!cdpResolveResult || !cdpResolveResult.object.objectId) {
2163
- throw new Error(`Could not resolve backend node ${backendNodeId}`);
2164
- }
2165
- try {
2166
- const id = await this.getIDAttributeUsingCDP(cdpResolveResult.object.objectId);
2167
- if (!id) {
2168
- throw new Error("Failed getting data-momentic-id attribute using CDP");
2122
+ }
2123
+ // Get the "id" attribute value from an HTML element.
2124
+ getIDAttributeUsingCDP(objectId) {
2125
+ return __awaiter(this, void 0, void 0, function* () {
2126
+ // https://bugs.chromium.org/p/chromium/issues/detail?id=1374241
2127
+ yield this.cdpClient.send("DOM.getDocument", { depth: 0 });
2128
+ const cdpNodeResult = yield this.cdpClient.send("DOM.requestNode", {
2129
+ objectId,
2130
+ });
2131
+ const attrResult = yield this.cdpClient.send("DOM.getAttributes", {
2132
+ nodeId: cdpNodeResult.nodeId,
2133
+ });
2134
+ const attributes = attrResult.attributes;
2135
+ const indexAttr = attributes.findIndex((s) => s === "data-momentic-id");
2136
+ if (indexAttr === -1) {
2137
+ return "";
2169
2138
  }
2170
- return this.page.locator(`[data-momentic-id="${id}"]`);
2171
- }
2172
- catch (err) {
2173
- this.logger.error({
2174
- err,
2175
- }, "Failed to get ID attribute");
2176
- throw err;
2177
- }
2139
+ return attributes[indexAttr + 1] || "";
2140
+ });
2178
2141
  }
2179
- async clickUsingCDP(originalNode, options = {}) {
2180
- let clickAttempts = 0;
2181
- let candidateNode = originalNode;
2182
- while (clickAttempts < MAX_BROWSER_ACTION_ATTEMPTS) {
2183
- // Did we reach the root?
2184
- if (!candidateNode || candidateNode.role === "RootWebArea") {
2185
- throw new Error(`Attempted to click node with no clickable surrounding elements: ${originalNode.getLogForm()}`);
2142
+ getLocatorFromBackendID(backendNodeId) {
2143
+ return __awaiter(this, void 0, void 0, function* () {
2144
+ yield this.page.evaluate(addIDsScript);
2145
+ // get a remote javascript object from the a11y backend node ID
2146
+ const cdpResolveResult = yield this.cdpClient.send("DOM.resolveNode", {
2147
+ backendNodeId,
2148
+ });
2149
+ if (!cdpResolveResult || !cdpResolveResult.object.objectId) {
2150
+ throw new Error(`Could not resolve backend node ${backendNodeId}`);
2186
2151
  }
2187
- // Check disqualifying conditions for clicks - these don't count as "attempts"
2188
- if (candidateNode.role === "StaticText") {
2189
- // static text corresponds to html text nodes that are not clickable
2190
- candidateNode = candidateNode.parent;
2191
- continue;
2152
+ try {
2153
+ const id = yield this.getIDAttributeUsingCDP(cdpResolveResult.object.objectId);
2154
+ if (!id) {
2155
+ throw new Error("Failed getting data-momentic-id attribute using CDP");
2156
+ }
2157
+ return this.page.locator(`[data-momentic-id="${id}"]`);
2192
2158
  }
2193
- const candidateNodeID = candidateNode.backendNodeID;
2194
- if (!candidateNodeID) {
2195
- this.logger.warn({ node: candidateNode.getLogForm() }, "Click candidate had no backend node ID");
2196
- candidateNode = candidateNode.parent;
2197
- continue;
2159
+ catch (err) {
2160
+ this.logger.error({
2161
+ err,
2162
+ }, "Failed to get ID attribute");
2163
+ throw err;
2198
2164
  }
2199
- // Attempt to click
2200
- try {
2201
- const locator = await this.getLocatorFromBackendID(candidateNodeID);
2202
- // this timeout is important because playwright checks for clickability/visibility
2203
- // before clicking, and a timeout indicates obstruction, or disabled state
2204
- // see: https://playwright.dev/docs/actionability#introduction
2205
- if (options.doubleClick) {
2206
- await locator.dblclick({
2207
- timeout: BROWSER_ACTION_TIMEOUT_MS,
2208
- });
2165
+ });
2166
+ }
2167
+ clickUsingCDP(originalNode, options = {}) {
2168
+ return __awaiter(this, void 0, void 0, function* () {
2169
+ let clickAttempts = 0;
2170
+ let candidateNode = originalNode;
2171
+ while (clickAttempts < MAX_BROWSER_ACTION_ATTEMPTS) {
2172
+ // Did we reach the root?
2173
+ if (!candidateNode || candidateNode.role === "RootWebArea") {
2174
+ throw new Error(`Attempted to click node with no clickable surrounding elements: ${originalNode.getLogForm()}`);
2209
2175
  }
2210
- else {
2211
- await locator.click({
2212
- timeout: BROWSER_ACTION_TIMEOUT_MS,
2213
- button: options.rightClick ? "right" : "left",
2214
- });
2176
+ // Check disqualifying conditions for clicks - these don't count as "attempts"
2177
+ if (candidateNode.role === "StaticText") {
2178
+ // static text corresponds to html text nodes that are not clickable
2179
+ candidateNode = candidateNode.parent;
2180
+ continue;
2215
2181
  }
2216
- if (candidateNode.id !== originalNode.id) {
2217
- this.logger.info({
2218
- oldNode: originalNode.getLogForm(),
2219
- newNode: candidateNode.getLogForm(),
2220
- }, `Redirected click successfully to new element`);
2182
+ const candidateNodeID = candidateNode.backendNodeID;
2183
+ if (!candidateNodeID) {
2184
+ this.logger.warn({ node: candidateNode.getLogForm() }, "Click candidate had no backend node ID");
2185
+ candidateNode = candidateNode.parent;
2186
+ continue;
2187
+ }
2188
+ // Attempt to click
2189
+ try {
2190
+ const locator = yield this.getLocatorFromBackendID(candidateNodeID);
2191
+ // this timeout is important because playwright checks for clickability/visibility
2192
+ // before clicking, and a timeout indicates obstruction, or disabled state
2193
+ // see: https://playwright.dev/docs/actionability#introduction
2194
+ if (options.doubleClick) {
2195
+ yield locator.dblclick({
2196
+ timeout: BROWSER_ACTION_TIMEOUT_MS,
2197
+ });
2198
+ }
2199
+ else {
2200
+ yield locator.click({
2201
+ timeout: BROWSER_ACTION_TIMEOUT_MS,
2202
+ button: options.rightClick ? "right" : "left",
2203
+ });
2204
+ }
2205
+ if (candidateNode.id !== originalNode.id) {
2206
+ this.logger.info({
2207
+ oldNode: originalNode.getLogForm(),
2208
+ newNode: candidateNode.getLogForm(),
2209
+ }, `Redirected click successfully to new element`);
2210
+ }
2211
+ return candidateNode;
2212
+ }
2213
+ catch (err) {
2214
+ this.logger.error({ err, node: candidateNode.getLogForm() }, "Failed click or click timed out");
2215
+ clickAttempts++;
2216
+ // try to click the parent instead
2217
+ // we could re-prompt the LLM in the future
2218
+ candidateNode = candidateNode.parent;
2221
2219
  }
2222
- return candidateNode;
2223
- }
2224
- catch (err) {
2225
- this.logger.error({ err, node: candidateNode.getLogForm() }, "Failed click or click timed out");
2226
- clickAttempts++;
2227
- // try to click the parent instead
2228
- // we could re-prompt the LLM in the future
2229
- candidateNode = candidateNode.parent;
2230
2220
  }
2231
- }
2232
- throw new Error(`Max click redirection attempts exhausted on original element: ${originalNode.getLogForm()}`);
2221
+ throw new Error(`Max click redirection attempts exhausted on original element: ${originalNode.getLogForm()}`);
2222
+ });
2233
2223
  }
2234
2224
  /**
2235
2225
  * Currently unused, but could be useful for vision model integration.
2236
2226
  * Gets x/y position of an a11y node.
2237
2227
  */
2238
- async getElementLocation(backendNodeId) {
2239
- const tree = await this.cdpClient.send("DOMSnapshot.captureSnapshot", {
2240
- computedStyles: [],
2241
- includeDOMRects: true,
2242
- includePaintOrder: true,
2243
- });
2244
- let devicePixelRatio = await this.page.evaluate(() => window.devicePixelRatio);
2245
- // it lies on macos lolol
2246
- // this apparently isn't working when the browser is dragged onto a monitor either
2247
- if (process.platform === "darwin" && devicePixelRatio === 1) {
2248
- // UNCOMMENT THE BELOW IF YOU ARE ON MAC OS AND NOT USING A MONITOR
2249
- // COMMENT THE BELOW OUT IF YOU ARE USING A MONITOR OR NOT ON MAC OS
2250
- devicePixelRatio = RETINA_WINDOW_SCALE_FACTOR;
2251
- }
2252
- const document = tree["documents"][0];
2253
- const layout = document["layout"];
2254
- const nodes = document["nodes"];
2255
- const nodeNames = nodes["nodeName"] || [];
2256
- const backendNodeIds = nodes["backendNodeId"] || [];
2257
- const layoutNodeIndex = layout["nodeIndex"];
2258
- const bounds = layout["bounds"];
2259
- let cursor = -1;
2260
- for (let i = 0; i < nodeNames.length; i++) {
2261
- if (backendNodeIds[i] === backendNodeId) {
2262
- cursor = layoutNodeIndex.indexOf(i);
2263
- break;
2228
+ getElementLocation(backendNodeId) {
2229
+ return __awaiter(this, void 0, void 0, function* () {
2230
+ const tree = yield this.cdpClient.send("DOMSnapshot.captureSnapshot", {
2231
+ computedStyles: [],
2232
+ includeDOMRects: true,
2233
+ includePaintOrder: true,
2234
+ });
2235
+ let devicePixelRatio = yield this.page.evaluate(() => window.devicePixelRatio);
2236
+ // it lies on macos lolol
2237
+ // this apparently isn't working when the browser is dragged onto a monitor either
2238
+ if (process.platform === "darwin" && devicePixelRatio === 1) {
2239
+ // UNCOMMENT THE BELOW IF YOU ARE ON MAC OS AND NOT USING A MONITOR
2240
+ // COMMENT THE BELOW OUT IF YOU ARE USING A MONITOR OR NOT ON MAC OS
2241
+ devicePixelRatio = RETINA_WINDOW_SCALE_FACTOR;
2264
2242
  }
2265
- }
2266
- if (cursor === -1) {
2267
- throw new Error(`Could not find any backend node with ID ${backendNodeId}`);
2268
- }
2269
- let [x = 0, y = 0, width = 0, height = 0] = bounds[cursor];
2270
- x /= devicePixelRatio;
2271
- y /= devicePixelRatio;
2272
- width /= devicePixelRatio;
2273
- height /= devicePixelRatio;
2274
- const centerX = x + width / 2;
2275
- const centerY = y + height / 2;
2276
- return { centerX, centerY };
2277
- }
2278
- async scrollUp() {
2279
- // TODO: this works pretty well for full page scroll, in the future we'd need to figure out how to scroll nested containers
2280
- await this.page.evaluate(() => {
2281
- (document.scrollingElement || document.body).scrollTop =
2282
- (document.scrollingElement || document.body).scrollTop -
2283
- window.innerHeight;
2243
+ const document = tree["documents"][0];
2244
+ const layout = document["layout"];
2245
+ const nodes = document["nodes"];
2246
+ const nodeNames = nodes["nodeName"] || [];
2247
+ const backendNodeIds = nodes["backendNodeId"] || [];
2248
+ const layoutNodeIndex = layout["nodeIndex"];
2249
+ const bounds = layout["bounds"];
2250
+ let cursor = -1;
2251
+ for (let i = 0; i < nodeNames.length; i++) {
2252
+ if (backendNodeIds[i] === backendNodeId) {
2253
+ cursor = layoutNodeIndex.indexOf(i);
2254
+ break;
2255
+ }
2256
+ }
2257
+ if (cursor === -1) {
2258
+ throw new Error(`Could not find any backend node with ID ${backendNodeId}`);
2259
+ }
2260
+ let [x = 0, y = 0, width = 0, height = 0] = bounds[cursor];
2261
+ x /= devicePixelRatio;
2262
+ y /= devicePixelRatio;
2263
+ width /= devicePixelRatio;
2264
+ height /= devicePixelRatio;
2265
+ const centerX = x + width / 2;
2266
+ const centerY = y + height / 2;
2267
+ return { centerX, centerY };
2284
2268
  });
2285
- await this.page.evaluate(() => {
2286
- (document.scrollingElement || document.body).scrollTop =
2287
- (document.scrollingElement || document.body).scrollTop +
2288
- window.innerHeight;
2269
+ }
2270
+ scrollUp() {
2271
+ return __awaiter(this, void 0, void 0, function* () {
2272
+ // TODO: this works pretty well for full page scroll, in the future we'd need to figure out how to scroll nested containers
2273
+ yield this.page.evaluate(() => {
2274
+ (document.scrollingElement || document.body).scrollTop =
2275
+ (document.scrollingElement || document.body).scrollTop -
2276
+ window.innerHeight;
2277
+ });
2278
+ yield this.page.evaluate(() => {
2279
+ (document.scrollingElement || document.body).scrollTop =
2280
+ (document.scrollingElement || document.body).scrollTop +
2281
+ window.innerHeight;
2282
+ });
2289
2283
  });
2290
2284
  }
2291
- async scrollDown() {
2292
- await this.page.evaluate(() => {
2293
- (document.scrollingElement || document.body).scrollTop =
2294
- (document.scrollingElement || document.body).scrollTop +
2295
- window.innerHeight;
2285
+ scrollDown() {
2286
+ return __awaiter(this, void 0, void 0, function* () {
2287
+ yield this.page.evaluate(() => {
2288
+ (document.scrollingElement || document.body).scrollTop =
2289
+ (document.scrollingElement || document.body).scrollTop +
2290
+ window.innerHeight;
2291
+ });
2296
2292
  });
2297
2293
  }
2298
- async goForward() {
2299
- await this.wrapPossibleNavigation(() => this.page.goForward({ timeout: MAX_LOAD_TIMEOUT_MS }));
2300
- await this.pageSetup();
2294
+ goForward() {
2295
+ return __awaiter(this, void 0, void 0, function* () {
2296
+ yield this.wrapPossibleNavigation(() => this.page.goForward({ timeout: MAX_LOAD_TIMEOUT_MS }));
2297
+ yield this.pageSetup();
2298
+ });
2301
2299
  }
2302
- async goBack() {
2303
- await this.wrapPossibleNavigation(() => this.page.goBack({ timeout: MAX_LOAD_TIMEOUT_MS }));
2304
- await this.pageSetup();
2300
+ goBack() {
2301
+ return __awaiter(this, void 0, void 0, function* () {
2302
+ yield this.wrapPossibleNavigation(() => this.page.goBack({ timeout: MAX_LOAD_TIMEOUT_MS }));
2303
+ yield this.pageSetup();
2304
+ });
2305
2305
  }
2306
2306
  }
2307
2307
  ChromeBrowser.USER_AGENT = external_playwright_namespaceObject.devices["Desktop Chrome"].userAgent;
2308
2308
 
2309
2309
 
2310
2310
  ;// CONCATENATED MODULE: external "diff-lines"
2311
- var external_diff_lines_x = y => { var x = {}; __nccwpck_require__.d(x, y); return x; }
2312
- var external_diff_lines_y = x => () => x
2313
- const external_diff_lines_namespaceObject = external_diff_lines_x({ ["default"]: () => __WEBPACK_EXTERNAL_MODULE_diff_lines_24b6f423__["default"] });
2311
+ const external_diff_lines_namespaceObject = require("diff-lines");
2312
+ var external_diff_lines_default = /*#__PURE__*/__nccwpck_require__.n(external_diff_lines_namespaceObject);
2314
2313
  ;// CONCATENATED MODULE: ../../packages/web-agent/src/controller.ts
2314
+ var controller_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
2315
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
2316
+ return new (P || (P = Promise))(function (resolve, reject) {
2317
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
2318
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
2319
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
2320
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
2321
+ });
2322
+ };
2315
2323
 
2316
2324
  // @ts-expect-error: no types from this library
2317
2325
 
@@ -2353,16 +2361,20 @@ class AgentController {
2353
2361
  /**
2354
2362
  * Reset controller and browser state.
2355
2363
  */
2356
- async resetState() {
2357
- this.resetHistory();
2358
- await this.browser.navigate(this.browser.baseURL);
2364
+ resetState() {
2365
+ return controller_awaiter(this, void 0, void 0, function* () {
2366
+ this.resetHistory();
2367
+ yield this.browser.navigate(this.browser.baseURL);
2368
+ });
2359
2369
  }
2360
2370
  /**
2361
2371
  * Get the browser state as a string
2362
2372
  */
2363
- async getBrowserState() {
2364
- const a11yTree = await this.browser.getA11yTree();
2365
- return a11yTree.serialize();
2373
+ getBrowserState() {
2374
+ return controller_awaiter(this, void 0, void 0, function* () {
2375
+ const a11yTree = yield this.browser.getA11yTree();
2376
+ return a11yTree.serialize();
2377
+ });
2366
2378
  }
2367
2379
  getSerializedHistory(url, currentBrowserState) {
2368
2380
  let history;
@@ -2374,84 +2386,90 @@ class AgentController {
2374
2386
  }
2375
2387
  return history;
2376
2388
  }
2377
- async splitUserGoal(type, goal, disableCache) {
2378
- if (type === StepType.AI_ACTION &&
2379
- goal.match(/[,!;.]|(?:and)|(?:then)/) &&
2380
- this.config.useGoalSplitter) {
2381
- const granularInstructions = await this.generator.getGranularGoals({ goal, url: this.browser.url }, disableCache);
2382
- // convert into a stack (last element is first to be executed)
2383
- this.pendingInstructions = granularInstructions.reverse();
2384
- }
2385
- else {
2386
- this.pendingInstructions = [goal];
2387
- }
2389
+ splitUserGoal(type, goal, disableCache) {
2390
+ return controller_awaiter(this, void 0, void 0, function* () {
2391
+ if (type === StepType.AI_ACTION &&
2392
+ goal.match(/[,!;.]|(?:and)|(?:then)/) &&
2393
+ this.config.useGoalSplitter) {
2394
+ const granularInstructions = yield this.generator.getGranularGoals({ goal, url: this.browser.url }, disableCache);
2395
+ // convert into a stack (last element is first to be executed)
2396
+ this.pendingInstructions = granularInstructions.reverse();
2397
+ }
2398
+ else {
2399
+ this.pendingInstructions = [goal];
2400
+ }
2401
+ });
2388
2402
  }
2389
2403
  /**
2390
2404
  * Given previously executed commands, generate command for the current prompt.
2391
2405
  * Should only be used for AI action.
2392
2406
  */
2393
- async promptToCommand(type, goal, disableCache) {
2394
- // are we out of granular instructions to execute?
2395
- if (this.pendingInstructions.length === 0) {
2396
- // stores granular instructions in this.pendingInstructions, which functions like a stack
2397
- await this.splitUserGoal(type, goal, disableCache);
2398
- }
2399
- const currInstruction = this.pendingInstructions[this.pendingInstructions.length - 1];
2400
- this.logger.info({ goal: currInstruction }, "Starting prompt translation");
2401
- const getBrowserStateStart = Date.now();
2402
- const url = this.browser.url;
2403
- const browserState = await this.getBrowserState();
2404
- this.logger.info({
2405
- duration: Date.now() - getBrowserStateStart,
2406
- url,
2407
- }, "Got browser state");
2408
- const numPrevious = this.commandHistory.length;
2409
- this.commandHistory.push({
2410
- state: "PENDING",
2411
- browserStateBeforeCommand: browserState,
2412
- urlBeforeCommand: url,
2413
- type,
2414
- });
2415
- const history = this.getSerializedHistory(url, browserState);
2416
- const getCommandProposalStart = Date.now();
2417
- const proposedCommand = await this.generator.getProposedCommand({
2418
- url,
2419
- numPrevious,
2420
- browserState,
2421
- history,
2422
- goal: currInstruction,
2423
- lastCommand: this.lastExecutedCommand,
2424
- }, disableCache);
2425
- this.logger.info({ duration: Date.now() - getCommandProposalStart }, "Got proposed command");
2426
- if (proposedCommand.type === ControlFlowCommandType.SUCCESS) {
2427
- const finishedInstruction = this.pendingInstructions.pop();
2428
- this.logger.info({
2429
- finishedInstruction,
2430
- remainingInstructions: this.pendingInstructions,
2431
- }, "Removing pending instruction due to SUCCESS");
2432
- // promptToCommand will pick the next instruction to execute off the stack
2433
- if (this.pendingInstructions.length !== 0) {
2434
- // remove the last command from the history since it was an intermediate command from goalSplitter
2435
- this.commandHistory.pop();
2436
- return this.promptToCommand(type, "", disableCache);
2407
+ promptToCommand(type, goal, disableCache) {
2408
+ return controller_awaiter(this, void 0, void 0, function* () {
2409
+ // are we out of granular instructions to execute?
2410
+ if (this.pendingInstructions.length === 0) {
2411
+ // stores granular instructions in this.pendingInstructions, which functions like a stack
2412
+ yield this.splitUserGoal(type, goal, disableCache);
2437
2413
  }
2438
- }
2439
- else if (
2440
- // on failure, we don't continue to execute
2441
- proposedCommand.type === ControlFlowCommandType.FAILURE) {
2414
+ const currInstruction = this.pendingInstructions[this.pendingInstructions.length - 1];
2415
+ this.logger.info({ goal: currInstruction }, "Starting prompt translation");
2416
+ const getBrowserStateStart = Date.now();
2417
+ const url = this.browser.url;
2418
+ const browserState = yield this.getBrowserState();
2442
2419
  this.logger.info({
2443
- remainingInstructions: this.pendingInstructions,
2444
- }, "Removing pending instructions due to FAILURE");
2445
- this.pendingInstructions = [];
2446
- }
2447
- return proposedCommand;
2420
+ duration: Date.now() - getBrowserStateStart,
2421
+ url,
2422
+ }, "Got browser state");
2423
+ const numPrevious = this.commandHistory.length;
2424
+ this.commandHistory.push({
2425
+ state: "PENDING",
2426
+ browserStateBeforeCommand: browserState,
2427
+ urlBeforeCommand: url,
2428
+ type,
2429
+ });
2430
+ const history = this.getSerializedHistory(url, browserState);
2431
+ const getCommandProposalStart = Date.now();
2432
+ const proposedCommand = yield this.generator.getProposedCommand({
2433
+ url,
2434
+ numPrevious,
2435
+ browserState,
2436
+ history,
2437
+ goal: currInstruction,
2438
+ lastCommand: this.lastExecutedCommand,
2439
+ }, disableCache);
2440
+ this.logger.info({ duration: Date.now() - getCommandProposalStart }, "Got proposed command");
2441
+ if (proposedCommand.type === ControlFlowCommandType.SUCCESS) {
2442
+ const finishedInstruction = this.pendingInstructions.pop();
2443
+ this.logger.info({
2444
+ finishedInstruction,
2445
+ remainingInstructions: this.pendingInstructions,
2446
+ }, "Removing pending instruction due to SUCCESS");
2447
+ // promptToCommand will pick the next instruction to execute off the stack
2448
+ if (this.pendingInstructions.length !== 0) {
2449
+ // remove the last command from the history since it was an intermediate command from goalSplitter
2450
+ this.commandHistory.pop();
2451
+ return this.promptToCommand(type, "", disableCache);
2452
+ }
2453
+ }
2454
+ else if (
2455
+ // on failure, we don't continue to execute
2456
+ proposedCommand.type === ControlFlowCommandType.FAILURE) {
2457
+ this.logger.info({
2458
+ remainingInstructions: this.pendingInstructions,
2459
+ }, "Removing pending instructions due to FAILURE");
2460
+ this.pendingInstructions = [];
2461
+ }
2462
+ return proposedCommand;
2463
+ });
2448
2464
  }
2449
- async locateElement(description, disableCache) {
2450
- const locator = await this.generator.getElementLocation({ browserState: await this.getBrowserState(), goal: description }, disableCache);
2451
- if (locator.id < 0) {
2452
- throw new Error(`Unable to locate element with description: ${description}`);
2453
- }
2454
- return locator;
2465
+ locateElement(description, disableCache) {
2466
+ return controller_awaiter(this, void 0, void 0, function* () {
2467
+ const locator = yield this.generator.getElementLocation({ browserState: yield this.getBrowserState(), goal: description }, disableCache);
2468
+ if (locator.id < 0) {
2469
+ throw new Error(`Unable to locate element with description: ${description}`);
2470
+ }
2471
+ return locator;
2472
+ });
2455
2473
  }
2456
2474
  /**
2457
2475
  * Construct a detailed history that can be passed to the LLM.
@@ -2475,7 +2493,7 @@ class AgentController {
2475
2493
  historyLines.push(` URL CHANGE: '${log.urlBeforeCommand}' -> '${currentURL}'`);
2476
2494
  }
2477
2495
  else {
2478
- const browserStateDiff = (0,external_diff_lines_namespaceObject["default"])(log.browserStateBeforeCommand, currentPageState, {
2496
+ const browserStateDiff = external_diff_lines_default()(log.browserStateBeforeCommand, currentPageState, {
2479
2497
  n_surrounding: 1,
2480
2498
  });
2481
2499
  if (!browserStateDiff) {
@@ -2498,7 +2516,7 @@ class AgentController {
2498
2516
  return historyLines.join("\n");
2499
2517
  }
2500
2518
  getListHistory() {
2501
- return external_dedent_namespaceObject["default"] `Here are the commands that you have successfully executed:
2519
+ return (external_dedent_default()) `Here are the commands that you have successfully executed:
2502
2520
  ${this.commandHistory
2503
2521
  .filter((cmd) => cmd.type === StepType.AI_ACTION)
2504
2522
  .map((cmd) => `- ${cmd.serializedCommand}`)
@@ -2509,254 +2527,261 @@ class AgentController {
2509
2527
  * @param [stateless=false] Execute this command in a stateless fashion, without modifying any controller state such as
2510
2528
  * pending instructions. Useful when executing cached instructions.
2511
2529
  */
2512
- async executeCommand(command, disableCache, stateless = false) {
2513
- const pendingHistory = this.commandHistory[this.commandHistory.length - 1];
2514
- if (!stateless) {
2515
- // if we're not using cached commands, we must be executing a pending command
2516
- // generated by promptToCommand
2517
- if (!pendingHistory || pendingHistory.state !== "PENDING") {
2518
- throw new Error("Executing command but there is no pending entry in the history");
2530
+ executeCommand(command, disableCache, stateless = false) {
2531
+ return controller_awaiter(this, void 0, void 0, function* () {
2532
+ const pendingHistory = this.commandHistory[this.commandHistory.length - 1];
2533
+ if (!stateless) {
2534
+ // if we're not using cached commands, we must be executing a pending command
2535
+ // generated by promptToCommand
2536
+ if (!pendingHistory || pendingHistory.state !== "PENDING") {
2537
+ throw new Error("Executing command but there is no pending entry in the history");
2538
+ }
2519
2539
  }
2520
- }
2521
- else {
2522
- // cached commands can rely on things like a11y IDs - we need to populate this state in the chrome browser.
2523
- // currently, all necessary side effects are accomplished by getting the a11y tree
2524
- await this.browser.getA11yTree();
2525
- }
2526
- let result;
2527
- try {
2528
- const executionStart = Date.now();
2529
- result = await this.sendCommandToBrowser(command, disableCache);
2530
- this.logger.info({ result, duration: Date.now() - executionStart }, "Got execution result");
2531
- }
2532
- catch (e) {
2533
- if (e instanceof Error) {
2534
- throw new BrowserExecutionError(`Failed to execute command: ${e}`, {
2535
- cause: e,
2540
+ else {
2541
+ // cached commands can rely on things like a11y IDs - we need to populate this state in the chrome browser.
2542
+ // currently, all necessary side effects are accomplished by getting the a11y tree
2543
+ yield this.browser.getA11yTree();
2544
+ }
2545
+ let result;
2546
+ try {
2547
+ const executionStart = Date.now();
2548
+ result = yield this.sendCommandToBrowser(command, disableCache);
2549
+ this.logger.info({ result, duration: Date.now() - executionStart }, "Got execution result");
2550
+ }
2551
+ catch (e) {
2552
+ if (e instanceof Error) {
2553
+ throw new BrowserExecutionError(`Failed to execute command: ${e}`, {
2554
+ cause: e,
2555
+ });
2556
+ }
2557
+ throw new BrowserExecutionError(`Unexpected throw from executing command`, {
2558
+ cause: new Error(`${e}`),
2536
2559
  });
2537
2560
  }
2538
- throw new BrowserExecutionError(`Unexpected throw from executing command`, {
2539
- cause: new Error(`${e}`),
2540
- });
2541
- }
2542
- if (result.succeedImmediately && !stateless) {
2543
- // pop the last command off the stack since we won't get a real SUCCESS command within promptToCommand
2544
- this.pendingInstructions.pop();
2545
- if (this.pendingInstructions.length > 0) {
2546
- // we still have pending instructions queued up
2547
- // override the immediate success
2548
- result.succeedImmediately = false;
2561
+ if (result.succeedImmediately && !stateless) {
2562
+ // pop the last command off the stack since we won't get a real SUCCESS command within promptToCommand
2563
+ this.pendingInstructions.pop();
2564
+ if (this.pendingInstructions.length > 0) {
2565
+ // we still have pending instructions queued up
2566
+ // override the immediate success
2567
+ result.succeedImmediately = false;
2568
+ }
2549
2569
  }
2550
- }
2551
- // TODO(ENG-139): Save other a11y stuff as well.
2552
- // Update the command with the targeted element
2553
- // if this is the first time the command was generated
2554
- if (result.elementInteracted &&
2555
- "target" in command &&
2556
- !command.target.elementDescriptor) {
2557
- // Save the serialized element interacted as the "descriptor" for now
2558
- // In the future, we can ask the LLM for a more human-readable descriptor
2559
- command.target.elementDescriptor = result.elementInteracted;
2560
- }
2561
- if (!stateless) {
2562
- // the conditional at the beginning of this function validates that pendingHistory isn't undefined
2563
- // if stateless is false
2564
- pendingHistory.generatedStep = command;
2565
- pendingHistory.serializedCommand = serializeAICommand(command);
2566
- pendingHistory.state = "DONE";
2567
- }
2568
- return result;
2570
+ // TODO(ENG-139): Save other a11y stuff as well.
2571
+ // Update the command with the targeted element
2572
+ // if this is the first time the command was generated
2573
+ if (result.elementInteracted &&
2574
+ "target" in command &&
2575
+ !command.target.elementDescriptor) {
2576
+ // Save the serialized element interacted as the "descriptor" for now
2577
+ // In the future, we can ask the LLM for a more human-readable descriptor
2578
+ command.target.elementDescriptor = result.elementInteracted;
2579
+ }
2580
+ if (!stateless) {
2581
+ // the conditional at the beginning of this function validates that pendingHistory isn't undefined
2582
+ // if stateless is false
2583
+ pendingHistory.generatedStep = command;
2584
+ pendingHistory.serializedCommand = serializeAICommand(command);
2585
+ pendingHistory.state = "DONE";
2586
+ }
2587
+ return result;
2588
+ });
2569
2589
  }
2570
2590
  /**
2571
2591
  * Executes a preset command.
2572
2592
  * For most cases, the execution result contains metadata about the command executed.
2573
2593
  * For assertions, an AssertionResult with thoughts is returned.
2574
2594
  */
2575
- async executePresetStep(command, disableCache) {
2576
- const urlBeforeCommand = this.browser.url;
2577
- switch (command.type) {
2578
- case preset_PresetCommandType.AI_ASSERTION: {
2579
- let params;
2580
- if (command.useVision) {
2581
- params = {
2582
- goal: command.assertion,
2583
- url: urlBeforeCommand,
2584
- // used for vision only
2585
- screenshot: await this.browser.screenshot(),
2586
- // unused for visual assertion
2587
- browserState: "",
2588
- history: "",
2589
- numPrevious: -1,
2590
- lastCommand: null,
2591
- };
2595
+ executePresetStep(command, disableCache) {
2596
+ var _a, _b;
2597
+ return controller_awaiter(this, void 0, void 0, function* () {
2598
+ const urlBeforeCommand = this.browser.url;
2599
+ switch (command.type) {
2600
+ case preset_PresetCommandType.AI_ASSERTION: {
2601
+ let params;
2602
+ if (command.useVision) {
2603
+ params = {
2604
+ goal: command.assertion,
2605
+ url: urlBeforeCommand,
2606
+ // used for vision only
2607
+ screenshot: yield this.browser.screenshot(),
2608
+ // unused for visual assertion
2609
+ browserState: "",
2610
+ history: "",
2611
+ numPrevious: -1,
2612
+ lastCommand: null,
2613
+ };
2614
+ }
2615
+ else {
2616
+ const browserState = yield this.getBrowserState();
2617
+ const history = this.getSerializedHistory(urlBeforeCommand, browserState);
2618
+ params = {
2619
+ goal: command.assertion,
2620
+ url: urlBeforeCommand,
2621
+ // used for text only
2622
+ browserState,
2623
+ history,
2624
+ lastCommand: this.lastExecutedCommand,
2625
+ numPrevious: this.commandHistory.length,
2626
+ };
2627
+ }
2628
+ const result = yield this.generator.getAssertionResult(params, command.useVision, command.disableCache);
2629
+ if (result.relevantElements) {
2630
+ // highlight relevant elements
2631
+ void Promise.all(result.relevantElements.map((id) => this.browser.highlight({ id })));
2632
+ }
2633
+ return result;
2592
2634
  }
2593
- else {
2594
- const browserState = await this.getBrowserState();
2595
- const history = this.getSerializedHistory(urlBeforeCommand, browserState);
2596
- params = {
2597
- goal: command.assertion,
2598
- url: urlBeforeCommand,
2599
- // used for text only
2600
- browserState,
2601
- history,
2602
- lastCommand: this.lastExecutedCommand,
2603
- numPrevious: this.commandHistory.length,
2635
+ case preset_PresetCommandType.NAVIGATE:
2636
+ yield this.browser.navigate(command.url);
2637
+ break;
2638
+ case preset_PresetCommandType.GO_BACK:
2639
+ yield this.browser.goBack();
2640
+ break;
2641
+ case preset_PresetCommandType.GO_FORWARD:
2642
+ yield this.browser.goForward();
2643
+ break;
2644
+ case preset_PresetCommandType.SCROLL_DOWN:
2645
+ yield this.browser.scrollDown();
2646
+ break;
2647
+ case preset_PresetCommandType.SCROLL_UP:
2648
+ yield this.browser.scrollUp();
2649
+ break;
2650
+ case preset_PresetCommandType.WAIT:
2651
+ yield this.browser.wait(command.delay * 1000);
2652
+ break;
2653
+ case preset_PresetCommandType.REFRESH:
2654
+ yield this.browser.refresh();
2655
+ break;
2656
+ case preset_PresetCommandType.CLICK: {
2657
+ let id;
2658
+ if (command.target.a11yData) {
2659
+ id = (_a = command.target.a11yData) === null || _a === void 0 ? void 0 : _a.id;
2660
+ }
2661
+ else {
2662
+ const locator = yield this.locateElement(command.target.elementDescriptor, disableCache);
2663
+ id = locator.id;
2664
+ }
2665
+ const elementInteracted = yield this.browser.click({
2666
+ id,
2667
+ }, {
2668
+ doubleClick: command.doubleClick,
2669
+ rightClick: command.rightClick,
2670
+ });
2671
+ const result = {
2672
+ type: ExecuteResultType.COMMAND,
2673
+ urlAfterCommand: this.browser.url,
2674
+ succeedImmediately: false,
2675
+ elementInteracted,
2604
2676
  };
2677
+ if (urlChanged(urlBeforeCommand, result.urlAfterCommand)) {
2678
+ result.succeedImmediately = true;
2679
+ result.succeedImmediatelyReason = "URL changed";
2680
+ }
2681
+ return result;
2605
2682
  }
2606
- const result = await this.generator.getAssertionResult(params, command.useVision, command.disableCache);
2607
- if (result.relevantElements) {
2608
- // highlight relevant elements
2609
- void Promise.all(result.relevantElements.map((id) => this.browser.highlight({ id })));
2610
- }
2611
- return result;
2612
- }
2613
- case preset_PresetCommandType.NAVIGATE:
2614
- await this.browser.navigate(command.url);
2615
- break;
2616
- case preset_PresetCommandType.GO_BACK:
2617
- await this.browser.goBack();
2618
- break;
2619
- case preset_PresetCommandType.GO_FORWARD:
2620
- await this.browser.goForward();
2621
- break;
2622
- case preset_PresetCommandType.SCROLL_DOWN:
2623
- await this.browser.scrollDown();
2624
- break;
2625
- case preset_PresetCommandType.SCROLL_UP:
2626
- await this.browser.scrollUp();
2627
- break;
2628
- case preset_PresetCommandType.WAIT:
2629
- await this.browser.wait(command.delay * 1000);
2630
- break;
2631
- case preset_PresetCommandType.REFRESH:
2632
- await this.browser.refresh();
2633
- break;
2634
- case preset_PresetCommandType.CLICK: {
2635
- let id;
2636
- if (command.target.a11yData) {
2637
- id = command.target.a11yData?.id;
2638
- }
2639
- else {
2640
- const locator = await this.locateElement(command.target.elementDescriptor, disableCache);
2641
- id = locator.id;
2642
- }
2643
- const elementInteracted = await this.browser.click({
2644
- id,
2645
- }, {
2646
- doubleClick: command.doubleClick,
2647
- rightClick: command.rightClick,
2648
- });
2649
- const result = {
2650
- type: ExecuteResultType.COMMAND,
2651
- urlAfterCommand: this.browser.url,
2652
- succeedImmediately: false,
2653
- elementInteracted,
2654
- };
2655
- if (urlChanged(urlBeforeCommand, result.urlAfterCommand)) {
2656
- result.succeedImmediately = true;
2657
- result.succeedImmediatelyReason = "URL changed";
2658
- }
2659
- return result;
2660
- }
2661
- case preset_PresetCommandType.SELECT_OPTION: {
2662
- let id;
2663
- if (command.target.a11yData) {
2664
- id = command.target.a11yData?.id;
2665
- }
2666
- else {
2667
- const locator = await this.locateElement(command.target.elementDescriptor, disableCache);
2668
- id = locator.id;
2669
- }
2670
- const elementInteracted = await this.browser.selectOption({
2671
- id,
2672
- }, command.option);
2673
- return {
2674
- type: ExecuteResultType.COMMAND,
2675
- succeedImmediately: false,
2676
- urlAfterCommand: this.browser.url,
2677
- elementInteracted,
2678
- };
2679
- }
2680
- case preset_PresetCommandType.TYPE: {
2681
- let elementInteracted;
2682
- const target = command.target;
2683
- if (target.a11yData) {
2684
- elementInteracted = await this.browser.click({
2685
- id: target.a11yData.id,
2686
- });
2683
+ case preset_PresetCommandType.SELECT_OPTION: {
2684
+ let id;
2685
+ if (command.target.a11yData) {
2686
+ id = (_b = command.target.a11yData) === null || _b === void 0 ? void 0 : _b.id;
2687
+ }
2688
+ else {
2689
+ const locator = yield this.locateElement(command.target.elementDescriptor, disableCache);
2690
+ id = locator.id;
2691
+ }
2692
+ const elementInteracted = yield this.browser.selectOption({
2693
+ id,
2694
+ }, command.option);
2695
+ return {
2696
+ type: ExecuteResultType.COMMAND,
2697
+ succeedImmediately: false,
2698
+ urlAfterCommand: this.browser.url,
2699
+ elementInteracted,
2700
+ };
2687
2701
  }
2688
- else if (target.elementDescriptor.length > 0) {
2689
- const locator = await this.locateElement(command.target.elementDescriptor, disableCache);
2690
- elementInteracted = await this.browser.click({
2691
- id: locator.id,
2702
+ case preset_PresetCommandType.TYPE: {
2703
+ let elementInteracted;
2704
+ const target = command.target;
2705
+ if (target.a11yData) {
2706
+ elementInteracted = yield this.browser.click({
2707
+ id: target.a11yData.id,
2708
+ });
2709
+ }
2710
+ else if (target.elementDescriptor.length > 0) {
2711
+ const locator = yield this.locateElement(command.target.elementDescriptor, disableCache);
2712
+ elementInteracted = yield this.browser.click({
2713
+ id: locator.id,
2714
+ });
2715
+ }
2716
+ yield this.browser.type(command.value, {
2717
+ clearContent: command.clearContent,
2718
+ pressKeysSequentially: command.pressKeysSequentially,
2692
2719
  });
2720
+ if (command.pressEnter) {
2721
+ yield this.browser.press("Enter");
2722
+ }
2723
+ const result = {
2724
+ type: ExecuteResultType.COMMAND,
2725
+ urlAfterCommand: this.browser.url,
2726
+ succeedImmediately: false,
2727
+ elementInteracted,
2728
+ };
2729
+ if (urlChanged(urlBeforeCommand, result.urlAfterCommand)) {
2730
+ result.succeedImmediately = true;
2731
+ result.succeedImmediatelyReason = "URL changed";
2732
+ }
2733
+ return result;
2693
2734
  }
2694
- await this.browser.type(command.value, {
2695
- clearContent: command.clearContent,
2696
- pressKeysSequentially: command.pressKeysSequentially,
2697
- });
2698
- if (command.pressEnter) {
2699
- await this.browser.press("Enter");
2700
- }
2701
- const result = {
2702
- type: ExecuteResultType.COMMAND,
2703
- urlAfterCommand: this.browser.url,
2704
- succeedImmediately: false,
2705
- elementInteracted,
2706
- };
2707
- if (urlChanged(urlBeforeCommand, result.urlAfterCommand)) {
2708
- result.succeedImmediately = true;
2709
- result.succeedImmediatelyReason = "URL changed";
2710
- }
2711
- return result;
2735
+ case preset_PresetCommandType.PRESS:
2736
+ yield this.browser.press(command.value);
2737
+ const result = {
2738
+ type: ExecuteResultType.COMMAND,
2739
+ urlAfterCommand: this.browser.url,
2740
+ succeedImmediately: false,
2741
+ };
2742
+ if (urlChanged(urlBeforeCommand, result.urlAfterCommand)) {
2743
+ result.succeedImmediately = true;
2744
+ result.succeedImmediatelyReason = "URL changed";
2745
+ }
2746
+ return result;
2747
+ default:
2748
+ const assertUnreachable = (_x) => {
2749
+ throw "If Typescript complains about the line below, you missed a case or break in the switch above";
2750
+ };
2751
+ return assertUnreachable(command);
2712
2752
  }
2713
- case preset_PresetCommandType.PRESS:
2714
- await this.browser.press(command.value);
2715
- const result = {
2716
- type: ExecuteResultType.COMMAND,
2717
- urlAfterCommand: this.browser.url,
2718
- succeedImmediately: false,
2719
- };
2720
- if (urlChanged(urlBeforeCommand, result.urlAfterCommand)) {
2721
- result.succeedImmediately = true;
2722
- result.succeedImmediatelyReason = "URL changed";
2723
- }
2724
- return result;
2725
- default:
2726
- const assertUnreachable = (_x) => {
2727
- throw "If Typescript complains about the line below, you missed a case or break in the switch above";
2728
- };
2729
- return assertUnreachable(command);
2730
- }
2731
- return {
2732
- type: ExecuteResultType.COMMAND,
2733
- succeedImmediately: false,
2734
- urlAfterCommand: this.browser.url,
2735
- };
2736
- }
2737
- async sendCommandToBrowser(command, disableCache) {
2738
- switch (command.type) {
2739
- /**
2740
- * Control flow
2741
- */
2742
- case ControlFlowCommandType.SUCCESS:
2743
- case ControlFlowCommandType.FAILURE:
2744
- return {
2745
- type: ExecuteResultType.COMMAND,
2746
- succeedImmediately: false,
2747
- urlAfterCommand: this.browser.url,
2748
- };
2749
- /**
2750
- * Preset action
2751
- */
2752
- default:
2753
- const result = await this.executePresetStep(command, disableCache);
2754
- if (result.type !== "command") {
2755
- // AI should never generate 'assertion' results
2756
- throw new Error(`Unexpected preset result type ${result.type} from executing AI action`);
2757
- }
2758
- return result;
2759
- }
2753
+ return {
2754
+ type: ExecuteResultType.COMMAND,
2755
+ succeedImmediately: false,
2756
+ urlAfterCommand: this.browser.url,
2757
+ };
2758
+ });
2759
+ }
2760
+ sendCommandToBrowser(command, disableCache) {
2761
+ return controller_awaiter(this, void 0, void 0, function* () {
2762
+ switch (command.type) {
2763
+ /**
2764
+ * Control flow
2765
+ */
2766
+ case ControlFlowCommandType.SUCCESS:
2767
+ case ControlFlowCommandType.FAILURE:
2768
+ return {
2769
+ type: ExecuteResultType.COMMAND,
2770
+ succeedImmediately: false,
2771
+ urlAfterCommand: this.browser.url,
2772
+ };
2773
+ /**
2774
+ * Preset action
2775
+ */
2776
+ default:
2777
+ const result = yield this.executePresetStep(command, disableCache);
2778
+ if (result.type !== "command") {
2779
+ // AI should never generate 'assertion' results
2780
+ throw new Error(`Unexpected preset result type ${result.type} from executing AI action`);
2781
+ }
2782
+ return result;
2783
+ }
2784
+ });
2760
2785
  }
2761
2786
  }
2762
2787
 
@@ -2764,6 +2789,15 @@ class AgentController {
2764
2789
  var fetch_retry = __nccwpck_require__(62);
2765
2790
  var fetch_retry_default = /*#__PURE__*/__nccwpck_require__.n(fetch_retry);
2766
2791
  ;// CONCATENATED MODULE: ../../packages/web-agent/src/generators/api-generator.ts
2792
+ var api_generator_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
2793
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
2794
+ return new (P || (P = Promise))(function (resolve, reject) {
2795
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
2796
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
2797
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
2798
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
2799
+ });
2800
+ };
2767
2801
 
2768
2802
 
2769
2803
 
@@ -2774,85 +2808,203 @@ class APIGenerator {
2774
2808
  this.baseURL = params.baseURL;
2775
2809
  this.apiKey = params.apiKey;
2776
2810
  }
2777
- async getElementLocation(context, disableCache) {
2778
- const result = await this.sendRequest(`/${API_VERSION}/web-agent/locate-element`, {
2779
- browserState: context.browserState,
2780
- goal: context.goal,
2781
- disableCache,
2811
+ getElementLocation(context, disableCache) {
2812
+ return api_generator_awaiter(this, void 0, void 0, function* () {
2813
+ const result = yield this.sendRequest(`/${API_VERSION}/web-agent/locate-element`, {
2814
+ browserState: context.browserState,
2815
+ goal: context.goal,
2816
+ disableCache,
2817
+ });
2818
+ return locator_AILocatorSchema.parse(result);
2782
2819
  });
2783
- return locator_AILocatorSchema.parse(result);
2784
2820
  }
2785
- async getAssertionResult(context, useVision, disableCache) {
2786
- if (useVision) {
2787
- const result = await this.sendRequest(`/${API_VERSION}/web-agent/assertion`, {
2821
+ getAssertionResult(context, useVision, disableCache) {
2822
+ var _a;
2823
+ return api_generator_awaiter(this, void 0, void 0, function* () {
2824
+ if (useVision) {
2825
+ const result = yield this.sendRequest(`/${API_VERSION}/web-agent/assertion`, {
2826
+ url: context.url,
2827
+ goal: context.goal,
2828
+ screenshot: (_a = context.screenshot) === null || _a === void 0 ? void 0 : _a.toString("base64"),
2829
+ disableCache,
2830
+ vision: true,
2831
+ });
2832
+ return execute_results_ExecuteAssertionResultSchema.parse(result);
2833
+ }
2834
+ const result = yield this.sendRequest(`/${API_VERSION}/web-agent/assertion`, {
2788
2835
  url: context.url,
2836
+ browserState: context.browserState,
2789
2837
  goal: context.goal,
2790
- screenshot: context.screenshot?.toString("base64"),
2838
+ history: context.history,
2839
+ numPrevious: context.numPrevious,
2840
+ lastCommand: context.lastCommand,
2791
2841
  disableCache,
2792
- vision: true,
2842
+ vision: false,
2793
2843
  });
2794
2844
  return execute_results_ExecuteAssertionResultSchema.parse(result);
2795
- }
2796
- const result = await this.sendRequest(`/${API_VERSION}/web-agent/assertion`, {
2797
- url: context.url,
2798
- browserState: context.browserState,
2799
- goal: context.goal,
2800
- history: context.history,
2801
- numPrevious: context.numPrevious,
2802
- lastCommand: context.lastCommand,
2803
- disableCache,
2804
- vision: false,
2805
2845
  });
2806
- return execute_results_ExecuteAssertionResultSchema.parse(result);
2807
- }
2808
- async getProposedCommand(context, disableCache) {
2809
- const result = await this.sendRequest(`/${API_VERSION}/web-agent/next-command`, {
2810
- url: context.url,
2811
- browserState: context.browserState,
2812
- goal: context.goal,
2813
- history: context.history,
2814
- numPrevious: context.numPrevious,
2815
- lastCommand: context.lastCommand,
2816
- disableCache,
2846
+ }
2847
+ getProposedCommand(context, disableCache) {
2848
+ return api_generator_awaiter(this, void 0, void 0, function* () {
2849
+ const result = yield this.sendRequest(`/${API_VERSION}/web-agent/next-command`, {
2850
+ url: context.url,
2851
+ browserState: context.browserState,
2852
+ goal: context.goal,
2853
+ history: context.history,
2854
+ numPrevious: context.numPrevious,
2855
+ lastCommand: context.lastCommand,
2856
+ disableCache,
2857
+ });
2858
+ return ai_commands_AICommandSchema.parse(result);
2817
2859
  });
2818
- return ai_commands_AICommandSchema.parse(result);
2819
2860
  }
2820
- async getGranularGoals(context, disableCache) {
2821
- const result = await this.sendRequest(`/${API_VERSION}/web-agent/split-goal`, {
2822
- url: context.url,
2823
- goal: context.goal,
2824
- disableCache,
2861
+ getGranularGoals(context, disableCache) {
2862
+ return api_generator_awaiter(this, void 0, void 0, function* () {
2863
+ const result = yield this.sendRequest(`/${API_VERSION}/web-agent/split-goal`, {
2864
+ url: context.url,
2865
+ goal: context.goal,
2866
+ disableCache,
2867
+ });
2868
+ return external_zod_namespaceObject.string().array().parse(result);
2825
2869
  });
2826
- return external_zod_namespaceObject.string().array().parse(result);
2827
- }
2828
- async sendRequest(path, body) {
2829
- const response = await fetch(`${this.baseURL}${path}`, {
2830
- retries: 3,
2831
- retryDelay: 1000,
2832
- method: "POST",
2833
- body: JSON.stringify(body),
2834
- headers: {
2835
- "Content-Type": "application/json",
2836
- Authorization: `Bearer ${this.apiKey}`,
2837
- },
2870
+ }
2871
+ sendRequest(path, body) {
2872
+ return api_generator_awaiter(this, void 0, void 0, function* () {
2873
+ const response = yield fetch(`${this.baseURL}${path}`, {
2874
+ retries: 3,
2875
+ retryDelay: 1000,
2876
+ method: "POST",
2877
+ body: JSON.stringify(body),
2878
+ headers: {
2879
+ "Content-Type": "application/json",
2880
+ Authorization: `Bearer ${this.apiKey}`,
2881
+ },
2882
+ });
2883
+ if (!response.ok) {
2884
+ throw new Error(`Request to ${path} failed with status ${response.status}: ${yield response.text()}`);
2885
+ }
2886
+ return response.json();
2838
2887
  });
2839
- if (!response.ok) {
2840
- throw new Error(`Request to ${path} failed with status ${response.status}: ${await response.text()}`);
2841
- }
2842
- return response.json();
2843
2888
  }
2844
2889
  }
2845
2890
 
2846
2891
  ;// CONCATENATED MODULE: ./src/index.ts
2892
+ /* module decorator */ module = __nccwpck_require__.hmd(module);
2847
2893
  // NOTE: these paths are using the direct paths to these files to support treeshaking so we don't bundle unnecessary code
2848
2894
 
2849
2895
 
2850
2896
 
2897
+ module.exports = {
2898
+ APIGenerator: APIGenerator,
2899
+ AgentController: AgentController,
2900
+ ChromeBrowser: ChromeBrowser,
2901
+ };
2851
2902
 
2852
2903
 
2853
- })();
2904
+ /***/ })
2854
2905
 
2855
- var __webpack_exports__APIGenerator = __webpack_exports__._w;
2856
- var __webpack_exports__AgentController = __webpack_exports__.Yt;
2857
- var __webpack_exports__ChromeBrowser = __webpack_exports__.DE;
2858
- export { __webpack_exports__APIGenerator as APIGenerator, __webpack_exports__AgentController as AgentController, __webpack_exports__ChromeBrowser as ChromeBrowser };
2906
+ /******/ });
2907
+ /************************************************************************/
2908
+ /******/ // The module cache
2909
+ /******/ var __webpack_module_cache__ = {};
2910
+ /******/
2911
+ /******/ // The require function
2912
+ /******/ function __nccwpck_require__(moduleId) {
2913
+ /******/ // Check if module is in cache
2914
+ /******/ var cachedModule = __webpack_module_cache__[moduleId];
2915
+ /******/ if (cachedModule !== undefined) {
2916
+ /******/ return cachedModule.exports;
2917
+ /******/ }
2918
+ /******/ // Create a new module (and put it into the cache)
2919
+ /******/ var module = __webpack_module_cache__[moduleId] = {
2920
+ /******/ id: moduleId,
2921
+ /******/ loaded: false,
2922
+ /******/ exports: {}
2923
+ /******/ };
2924
+ /******/
2925
+ /******/ // Execute the module function
2926
+ /******/ var threw = true;
2927
+ /******/ try {
2928
+ /******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __nccwpck_require__);
2929
+ /******/ threw = false;
2930
+ /******/ } finally {
2931
+ /******/ if(threw) delete __webpack_module_cache__[moduleId];
2932
+ /******/ }
2933
+ /******/
2934
+ /******/ // Flag the module as loaded
2935
+ /******/ module.loaded = true;
2936
+ /******/
2937
+ /******/ // Return the exports of the module
2938
+ /******/ return module.exports;
2939
+ /******/ }
2940
+ /******/
2941
+ /************************************************************************/
2942
+ /******/ /* webpack/runtime/compat get default export */
2943
+ /******/ (() => {
2944
+ /******/ // getDefaultExport function for compatibility with non-harmony modules
2945
+ /******/ __nccwpck_require__.n = (module) => {
2946
+ /******/ var getter = module && module.__esModule ?
2947
+ /******/ () => (module['default']) :
2948
+ /******/ () => (module);
2949
+ /******/ __nccwpck_require__.d(getter, { a: getter });
2950
+ /******/ return getter;
2951
+ /******/ };
2952
+ /******/ })();
2953
+ /******/
2954
+ /******/ /* webpack/runtime/define property getters */
2955
+ /******/ (() => {
2956
+ /******/ // define getter functions for harmony exports
2957
+ /******/ __nccwpck_require__.d = (exports, definition) => {
2958
+ /******/ for(var key in definition) {
2959
+ /******/ if(__nccwpck_require__.o(definition, key) && !__nccwpck_require__.o(exports, key)) {
2960
+ /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
2961
+ /******/ }
2962
+ /******/ }
2963
+ /******/ };
2964
+ /******/ })();
2965
+ /******/
2966
+ /******/ /* webpack/runtime/harmony module decorator */
2967
+ /******/ (() => {
2968
+ /******/ __nccwpck_require__.hmd = (module) => {
2969
+ /******/ module = Object.create(module);
2970
+ /******/ if (!module.children) module.children = [];
2971
+ /******/ Object.defineProperty(module, 'exports', {
2972
+ /******/ enumerable: true,
2973
+ /******/ set: () => {
2974
+ /******/ throw new Error('ES Modules may not assign module.exports or exports.*, Use ESM export syntax, instead: ' + module.id);
2975
+ /******/ }
2976
+ /******/ });
2977
+ /******/ return module;
2978
+ /******/ };
2979
+ /******/ })();
2980
+ /******/
2981
+ /******/ /* webpack/runtime/hasOwnProperty shorthand */
2982
+ /******/ (() => {
2983
+ /******/ __nccwpck_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
2984
+ /******/ })();
2985
+ /******/
2986
+ /******/ /* webpack/runtime/make namespace object */
2987
+ /******/ (() => {
2988
+ /******/ // define __esModule on exports
2989
+ /******/ __nccwpck_require__.r = (exports) => {
2990
+ /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
2991
+ /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2992
+ /******/ }
2993
+ /******/ Object.defineProperty(exports, '__esModule', { value: true });
2994
+ /******/ };
2995
+ /******/ })();
2996
+ /******/
2997
+ /******/ /* webpack/runtime/compat */
2998
+ /******/
2999
+ /******/ if (typeof __nccwpck_require__ !== 'undefined') __nccwpck_require__.ab = __dirname + "/";
3000
+ /******/
3001
+ /************************************************************************/
3002
+ /******/
3003
+ /******/ // startup
3004
+ /******/ // Load entry module and return exports
3005
+ /******/ // This entry module is referenced by other modules so it can't be inlined
3006
+ /******/ var __webpack_exports__ = __nccwpck_require__(811);
3007
+ /******/ module.exports = __webpack_exports__;
3008
+ /******/
3009
+ /******/ })()
3010
+ ;