@coolkiller007/my-page-agent 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/README.md +89 -0
- package/UPSTREAM.md +97 -0
- package/dist/index.d.ts +873 -0
- package/dist/index.js +4436 -0
- package/dist/index.js.map +1 -0
- package/package.json +84 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["#createCursor","#moveCursorToTarget","#cursor","#disposed","#currentCursorX","#targetCursorX","#currentCursorY","#targetCursorY","#handleStatusChange","#handleHistoryChange","#handleActivity","#askUser","#wrapper","#agent","#config","#i18n","#askUserCallback","#createWrapper","#indicator","#statusText","#historySection","#expandButton","#actionButton","#inputSection","#taskInput","#onStatusChange","#onHistoryChange","#onActivity","#onAgentDispose","#setupEventListeners","#startHeaderUpdateLoop","#showInputArea","#updateStatusIndicator","#hideInputArea","#isExpanded","#expand","#shouldShowInputArea","#renderHistory","#pendingHeaderText","#getToolExecutingText","#disposed","#createAbortError","#rejectPendingQuestion","#isWaitingForUserAnswer","#userAnswerResolver","#userAnswerRejecter","#scrollToBottom","#userAnswerSignal","#userAnswerAbortHandler","#removeTempCards","#clearQuestionState","#collapse","#stopHeaderUpdateLoop","#timers","#handleUserAnswer","#setTimer","#toggle","#handleActionButton","#submitTask","#headerUpdateTimer","#checkAndUpdateHeader","#isAnimating","#animateTextChange","#createTaskCard","#createHistoryCards","#createActionCards","#llm","#emitActivity","#emitHistoryChange","#status","#lastResult","#emitStatusChange","#observations","#abortController","#running","#states","#setStatus","#handleObservations","#getSystemPrompt","#assembleUserPrompt","#packMacroTool","#getInstructions"],"sources":["../src/browser/utils/index.ts","../src/browser/actions.ts","../src/browser/dom/dom_tree/index.js","../src/browser/dom/index.ts","../src/browser/dom/getPageInfo.ts","../src/browser/patches/react.ts","../src/browser/visual/checkDarkMode.ts","../src/browser/visual/SimulatorMask.module.css","../src/browser/visual/cursor.module.css","../src/browser/visual/SimulatorMask.ts","../src/browser/BrowserController.ts","../src/ui/i18n/locales.ts","../src/ui/i18n/index.ts","../src/ui/utils.ts","../src/ui/styles/UI.module.css","../src/ui/cards.ts","../src/ui/UI.ts","../src/llm/errors.ts","../src/llm/utils.ts","../src/llm/OpenAICompatibleClient.ts","../src/llm/LLM.ts","../src/agent/utils/autoFixer.ts","../src/agent/utils/index.ts","../src/agent/tools/index.ts","../src/agent/AgentRuntime.ts","../src/agent/MyPageAgent.ts","../src/index.ts"],"sourcesContent":["// ======= type guards =======\n// @note instanceof fails for elements inside iframes\n\nexport function isHTMLElement(el: unknown): el is HTMLElement {\n\t// @todo either specify to HTMLElement or allow Element here.\n\treturn !!el && (el as Node).nodeType === 1\n}\n\nexport function isInputElement(el: Element): el is HTMLInputElement {\n\treturn el?.nodeType === 1 && el.tagName === 'INPUT'\n}\n\nexport function isTextAreaElement(el: Element): el is HTMLTextAreaElement {\n\treturn el?.nodeType === 1 && el.tagName === 'TEXTAREA'\n}\n\nexport function isSelectElement(el: Element): el is HTMLSelectElement {\n\treturn el?.nodeType === 1 && el.tagName === 'SELECT'\n}\n\nexport function isAnchorElement(el: Element): el is HTMLAnchorElement {\n\treturn el?.nodeType === 1 && el.tagName === 'A'\n}\n\n// ======= iframe helpers =======\n\n/** Iframe offset for translating element coordinates to top-frame viewport. */\nexport function getIframeOffset(element: HTMLElement): { x: number; y: number } {\n\tconst frame = element.ownerDocument.defaultView?.frameElement as HTMLElement | null\n\tif (!frame) return { x: 0, y: 0 }\n\tconst rect = frame.getBoundingClientRect()\n\treturn { x: rect.left, y: rect.top }\n}\n\n/**\n * Get native value setter from the element's own prototype (iframe-safe).\n * @note for React\n */\nexport function getNativeValueSetter(element: HTMLInputElement | HTMLTextAreaElement) {\n\treturn Object.getOwnPropertyDescriptor(Object.getPrototypeOf(element) as object, 'value')!\n\t\t.set as (v: string) => void\n}\n\n// ======= general utils =======\n\nexport async function waitFor(seconds: number): Promise<void> {\n\tawait new Promise((resolve) => setTimeout(resolve, seconds * 1000))\n}\n\n// ======= mask events =======\n\n/**\n * Move the visual pointer to a position within an element.\n * @param x - x coordinate in the element's document viewport\n * @param y - y coordinate in the element's document viewport\n */\nexport async function movePointerToElement(element: HTMLElement, x: number, y: number) {\n\tconst offset = getIframeOffset(element)\n\n\twindow.dispatchEvent(\n\t\tnew CustomEvent('PageAgent::MovePointerTo', {\n\t\t\tdetail: { x: x + offset.x, y: y + offset.y },\n\t\t})\n\t)\n\n\tawait waitFor(0.3)\n}\n\nexport async function clickPointer() {\n\twindow.dispatchEvent(new CustomEvent('PageAgent::ClickPointer'))\n}\n\nexport async function enablePassThrough() {\n\twindow.dispatchEvent(new CustomEvent('PageAgent::EnablePassThrough'))\n}\n\nexport async function disablePassThrough() {\n\twindow.dispatchEvent(new CustomEvent('PageAgent::DisablePassThrough'))\n}\n","/**\n * Copyright (C) 2025 Alibaba Group Holding Limited\n * All rights reserved.\n */\nimport type { InteractiveElementDomNode } from './dom/dom_tree/type'\nimport {\n\tclickPointer,\n\tdisablePassThrough,\n\tenablePassThrough,\n\tgetNativeValueSetter,\n\tisHTMLElement,\n\tisInputElement,\n\tisSelectElement,\n\tisTextAreaElement,\n\tmovePointerToElement,\n\twaitFor,\n} from './utils'\n\n/**\n * Get the HTMLElement by index from a selectorMap.\n * @private Internal method, subject to change at any time.\n */\nexport function getElementByIndex(\n\tselectorMap: Map<number, InteractiveElementDomNode>,\n\tindex: number\n): HTMLElement {\n\tconst interactiveNode = selectorMap.get(index)\n\tif (!interactiveNode) {\n\t\tthrow new Error(`No interactive element found at index ${index}`)\n\t}\n\n\tconst element = interactiveNode.ref\n\tif (!element) {\n\t\tthrow new Error(`Element at index ${index} does not have a reference`)\n\t}\n\n\tif (!isHTMLElement(element)) {\n\t\tthrow new Error(`Element at index ${index} is not an HTMLElement`)\n\t}\n\n\treturn element\n}\n\nlet lastClickedElement: HTMLElement | null = null\n\nfunction blurLastClickedElement() {\n\tif (lastClickedElement) {\n\t\tlastClickedElement.dispatchEvent(new PointerEvent('pointerout', { bubbles: true }))\n\t\tlastClickedElement.dispatchEvent(new PointerEvent('pointerleave', { bubbles: false }))\n\t\tlastClickedElement.dispatchEvent(new MouseEvent('mouseout', { bubbles: true }))\n\t\tlastClickedElement.dispatchEvent(new MouseEvent('mouseleave', { bubbles: false }))\n\t\tlastClickedElement.blur()\n\t\tlastClickedElement = null\n\t}\n}\n\n/**\n * Simulate a full click following W3C Pointer Events + UI Events spec order:\n * pointerover/enter → mouseover/enter → pointerdown → mousedown → [focus] →\n * pointerup → mouseup → click\n *\n * @private Internal method, subject to change at any time.\n */\nexport async function clickElement(element: HTMLElement) {\n\tblurLastClickedElement()\n\n\tlastClickedElement = element\n\n\tawait scrollIntoViewIfNeeded(element)\n\tconst frame = element.ownerDocument.defaultView?.frameElement\n\tif (frame) await scrollIntoViewIfNeeded(frame)\n\n\tconst rect = element.getBoundingClientRect()\n\tconst x = rect.left + rect.width / 2\n\tconst y = rect.top + rect.height / 2\n\n\tawait movePointerToElement(element, x, y)\n\tawait clickPointer()\n\n\tawait waitFor(0.1)\n\n\t// Hit-test to find the deepest element at click coordinates, matching\n\t// real browser behavior where events target the innermost element.\n\t// @note This may hit a element in the blacklist\n\t// TODO: This is a temporary workaround. Should have been handled during dom extraction.\n\tconst doc = element.ownerDocument\n\tawait enablePassThrough()\n\tconst hitTarget = doc.elementFromPoint(x, y)\n\tawait disablePassThrough()\n\tconst target =\n\t\thitTarget instanceof HTMLElement && element.contains(hitTarget) ? hitTarget : element\n\n\tconst pointerOpts = {\n\t\tbubbles: true,\n\t\tcancelable: true,\n\t\tclientX: x,\n\t\tclientY: y,\n\t\tpointerType: 'mouse',\n\t}\n\tconst mouseOpts = { bubbles: true, cancelable: true, clientX: x, clientY: y, button: 0 }\n\n\t// Hover — pointer events first, then mouse events (spec order)\n\ttarget.dispatchEvent(new PointerEvent('pointerover', pointerOpts))\n\ttarget.dispatchEvent(new PointerEvent('pointerenter', { ...pointerOpts, bubbles: false }))\n\ttarget.dispatchEvent(new MouseEvent('mouseover', mouseOpts))\n\ttarget.dispatchEvent(new MouseEvent('mouseenter', { ...mouseOpts, bubbles: false }))\n\n\t// Press\n\ttarget.dispatchEvent(new PointerEvent('pointerdown', pointerOpts))\n\ttarget.dispatchEvent(new MouseEvent('mousedown', mouseOpts))\n\n\t// Focus is not part of the standard pointer/mouse event sequence\n\t// \"undefined and varies between user agents\".\n\t// We focus the original element (nearest focusable ancestor), not the hit-test target, matching browser behavior.\n\telement.focus({ preventScroll: true })\n\n\t// Release\n\ttarget.dispatchEvent(new PointerEvent('pointerup', pointerOpts))\n\ttarget.dispatchEvent(new MouseEvent('mouseup', mouseOpts))\n\n\t// Click — activation behavior (navigation, form submit, etc.) triggers\n\t// via bubbling from target up to the interactive ancestor.\n\ttarget.click()\n\n\tawait waitFor(0.2)\n}\n\n/**\n * @private Internal method, subject to change at any time.\n */\nexport async function inputTextElement(element: HTMLElement, text: string) {\n\tconst isContentEditable = element.isContentEditable\n\tif (!isInputElement(element) && !isTextAreaElement(element) && !isContentEditable) {\n\t\tthrow new Error('Element is not an input, textarea, or contenteditable')\n\t}\n\n\tawait clickElement(element)\n\n\tif (isContentEditable) {\n\t\t// Contenteditable support (partial)\n\t\t// Not supported:\n\t\t// - Monaco/CodeMirror: Require direct JS instance access. No universal way to obtain.\n\t\t// - Draft.js: Not responsive to synthetic/execCommand/Range/DataTransfer. Unmaintained.\n\t\t//\n\t\t// Strategy: Try Plan A (synthetic events) first, then verify and fall back\n\t\t// to Plan B (execCommand) if the text wasn't actually inserted.\n\t\t//\n\t\t// Plan A: Dispatch synthetic events\n\t\t// Works: React contenteditable, Quill.\n\t\t// Fails: Slate.js, some contenteditable editors that ignore synthetic events.\n\t\t// Sequence: beforeinput -> mutation -> input -> change -> blur\n\n\t\t// Dispatch beforeinput + mutation + input for clearing\n\t\tif (\n\t\t\telement.dispatchEvent(\n\t\t\t\tnew InputEvent('beforeinput', {\n\t\t\t\t\tbubbles: true,\n\t\t\t\t\tcancelable: true,\n\t\t\t\t\tinputType: 'deleteContent',\n\t\t\t\t})\n\t\t\t)\n\t\t) {\n\t\t\telement.innerText = ''\n\t\t\telement.dispatchEvent(\n\t\t\t\tnew InputEvent('input', {\n\t\t\t\t\tbubbles: true,\n\t\t\t\t\tinputType: 'deleteContent',\n\t\t\t\t})\n\t\t\t)\n\t\t}\n\n\t\t// Dispatch beforeinput + mutation + input for insertion (important for React apps)\n\t\tif (\n\t\t\telement.dispatchEvent(\n\t\t\t\tnew InputEvent('beforeinput', {\n\t\t\t\t\tbubbles: true,\n\t\t\t\t\tcancelable: true,\n\t\t\t\t\tinputType: 'insertText',\n\t\t\t\t\tdata: text,\n\t\t\t\t})\n\t\t\t)\n\t\t) {\n\t\t\telement.innerText = text\n\t\t\telement.dispatchEvent(\n\t\t\t\tnew InputEvent('input', {\n\t\t\t\t\tbubbles: true,\n\t\t\t\t\tinputType: 'insertText',\n\t\t\t\t\tdata: text,\n\t\t\t\t})\n\t\t\t)\n\t\t}\n\n\t\t// Verify Plan A worked by checking if the text was actually inserted\n\t\tconst planASucceeded = element.innerText.trim() === text.trim()\n\n\t\tif (!planASucceeded) {\n\t\t\t// Plan B: execCommand fallback (deprecated but widely supported)\n\t\t\t// Works: Quill, Slate.js, react contenteditable components.\n\t\t\t// This approach integrates with the browser's undo stack and is handled\n\t\t\t// natively by most rich-text editors.\n\t\t\telement.focus()\n\n\t\t\t// Select all existing content and delete it\n\t\t\tconst doc = element.ownerDocument\n\t\t\tconst selection = (doc.defaultView || window).getSelection()\n\t\t\tconst range = doc.createRange()\n\t\t\trange.selectNodeContents(element)\n\t\t\tselection?.removeAllRanges()\n\t\t\tselection?.addRange(range)\n\n\t\t\tdoc.execCommand('delete', false)\n\t\t\tdoc.execCommand('insertText', false, text)\n\t\t}\n\n\t\t// Dispatch change event (for good measure)\n\t\telement.dispatchEvent(new Event('change', { bubbles: true }))\n\n\t\t// Trigger blur for validation\n\t\telement.blur()\n\t} else {\n\t\tgetNativeValueSetter(element as HTMLInputElement | HTMLTextAreaElement).call(element, text)\n\t}\n\n\t// Only dispatch shared input event for non-contenteditable (contenteditable has its own)\n\tif (!isContentEditable) {\n\t\telement.dispatchEvent(new Event('input', { bubbles: true }))\n\t}\n\n\tawait waitFor(0.1)\n\n\tblurLastClickedElement()\n}\n\n/**\n * @todo browser-use version is very complex and supports menu tags, need to follow up\n * @private Internal method, subject to change at any time.\n */\nexport async function selectOptionElement(selectElement: HTMLSelectElement, optionText: string) {\n\tif (!isSelectElement(selectElement)) {\n\t\tthrow new Error('Element is not a select element')\n\t}\n\n\tconst options = Array.from(selectElement.options)\n\tconst option = options.find((opt) => opt.textContent?.trim() === optionText.trim())\n\n\tif (!option) {\n\t\tthrow new Error(`Option with text \"${optionText}\" not found in select element`)\n\t}\n\n\tselectElement.value = option.value\n\tselectElement.dispatchEvent(new Event('change', { bubbles: true }))\n\n\tawait waitFor(0.1) // Wait to ensure change event processing completes\n}\n\ninterface ScrollableElement extends Element {\n\tscrollIntoViewIfNeeded?: (centerIfNeeded?: boolean) => void\n}\n\n/**\n * @private Internal method, subject to change at any time.\n */\nexport async function scrollIntoViewIfNeeded(element: Element) {\n\tconst el = element as ScrollableElement\n\tif (typeof el.scrollIntoViewIfNeeded === 'function') {\n\t\tel.scrollIntoViewIfNeeded()\n\t\t// await waitFor(0.5) // Animation playback\n\t} else {\n\t\t// @todo visibility check\n\t\telement.scrollIntoView({ behavior: 'auto', block: 'center', inline: 'nearest' })\n\t\t// await waitFor(0.5) // Animation playback\n\t}\n}\n\nexport async function scrollVertically(scroll_amount: number, element?: HTMLElement | null) {\n\t// Element-specific scrolling if element is provided\n\tif (element) {\n\t\tconst targetElement = element\n\t\tlet currentElement = targetElement as HTMLElement | null\n\t\tlet scrollSuccess = false\n\t\tlet scrolledElement: HTMLElement | null = null\n\t\tlet scrollDelta = 0\n\t\tlet attempts = 0\n\t\tconst dy = scroll_amount\n\n\t\twhile (currentElement && attempts < 10) {\n\t\t\tconst computedStyle = window.getComputedStyle(currentElement)\n\t\t\tconst hasScrollableY =\n\t\t\t\t/(auto|scroll|overlay)/.test(computedStyle.overflowY) ||\n\t\t\t\t(computedStyle.scrollbarWidth && computedStyle.scrollbarWidth !== 'auto') ||\n\t\t\t\t(computedStyle.scrollbarGutter && computedStyle.scrollbarGutter !== 'auto')\n\t\t\tconst canScrollVertically = currentElement.scrollHeight > currentElement.clientHeight\n\n\t\t\tif (hasScrollableY && canScrollVertically) {\n\t\t\t\tconst beforeScroll = currentElement.scrollTop\n\t\t\t\tconst maxScroll = currentElement.scrollHeight - currentElement.clientHeight\n\n\t\t\t\tlet scrollAmount = dy / 3\n\n\t\t\t\tif (scrollAmount > 0) {\n\t\t\t\t\tscrollAmount = Math.min(scrollAmount, maxScroll - beforeScroll)\n\t\t\t\t} else {\n\t\t\t\t\tscrollAmount = Math.max(scrollAmount, -beforeScroll)\n\t\t\t\t}\n\n\t\t\t\tcurrentElement.scrollTop = beforeScroll + scrollAmount\n\n\t\t\t\tconst afterScroll = currentElement.scrollTop\n\t\t\t\tconst actualScrollDelta = afterScroll - beforeScroll\n\n\t\t\t\tif (Math.abs(actualScrollDelta) > 0.5) {\n\t\t\t\t\tscrollSuccess = true\n\t\t\t\t\tscrolledElement = currentElement\n\t\t\t\t\tscrollDelta = actualScrollDelta\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (currentElement === document.body || currentElement === document.documentElement) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcurrentElement = currentElement.parentElement\n\t\t\tattempts++\n\t\t}\n\n\t\tif (scrollSuccess) {\n\t\t\treturn `Scrolled container (${scrolledElement?.tagName}) by ${scrollDelta}px`\n\t\t} else {\n\t\t\treturn `No scrollable container found for element (${targetElement.tagName})`\n\t\t}\n\t}\n\n\t// Page-level scrolling (default or fallback)\n\n\tconst dy = scroll_amount\n\tconst bigEnough = (el: HTMLElement) => el.clientHeight >= window.innerHeight * 0.5\n\tconst canScroll = (el: HTMLElement | null): boolean =>\n\t\tBoolean(\n\t\t\tel &&\n\t\t\t/(auto|scroll|overlay)/.test(getComputedStyle(el).overflowY) &&\n\t\t\tel.scrollHeight > el.clientHeight &&\n\t\t\tbigEnough(el)\n\t\t)\n\n\t// @deprecated Heuristic container search.\n\t// Unreliable in multi-region layouts. Should guide LLMs to use indexed scroll for consistency.\n\t// TODO: remove this fallback\n\n\t// try to find the nearest scrollable container\n\t// document.activeElement is usually body.\n\t// After a successful element.focus(), activeElement become the nearest focusable parent\n\n\tlet el: HTMLElement | null = document.activeElement as HTMLElement | null\n\twhile (el && !canScroll(el) && el !== document.body) el = el.parentElement\n\n\t// Something is wrong if it falls back to global '*' search\n\t// TODO: Return error message instead of global '*' search\n\n\tel = canScroll(el)\n\t\t? el\n\t\t: Array.from(document.querySelectorAll<HTMLElement>('*')).find(canScroll) ||\n\t\t\t(document.scrollingElement as HTMLElement) ||\n\t\t\t(document.documentElement as HTMLElement)\n\n\tif (el === document.scrollingElement || el === document.documentElement || el === document.body) {\n\t\t// Page-level scroll\n\t\tconst scrollBefore = window.scrollY\n\t\tconst scrollMax = document.documentElement.scrollHeight - window.innerHeight\n\n\t\twindow.scrollBy(0, dy)\n\n\t\tconst scrollAfter = window.scrollY\n\t\tconst scrolled = scrollAfter - scrollBefore\n\n\t\tif (Math.abs(scrolled) < 1) {\n\t\t\treturn dy > 0\n\t\t\t\t? `⚠️ Already at the bottom of the page, cannot scroll down further.`\n\t\t\t\t: `⚠️ Already at the top of the page, cannot scroll up further.`\n\t\t}\n\n\t\tconst reachedBottom = dy > 0 && scrollAfter >= scrollMax - 1\n\t\tconst reachedTop = dy < 0 && scrollAfter <= 1\n\n\t\tif (reachedBottom) return `✅ Scrolled page by ${scrolled}px. Reached the bottom of the page.`\n\t\tif (reachedTop) return `✅ Scrolled page by ${scrolled}px. Reached the top of the page.`\n\t\treturn `✅ Scrolled page by ${scrolled}px.`\n\t} else {\n\t\t// Container scroll\n\n\t\tconst warningMsg = `The document is not scrollable. Falling back to container scroll.`\n\t\tconsole.log(`[BrowserController] ${warningMsg}`)\n\n\t\tconst scrollBefore = el!.scrollTop\n\t\tconst scrollMax = el!.scrollHeight - el!.clientHeight\n\n\t\tel!.scrollBy({ top: dy, behavior: 'smooth' })\n\t\tawait waitFor(0.1)\n\n\t\tconst scrollAfter = el!.scrollTop\n\t\tconst scrolled = scrollAfter - scrollBefore\n\n\t\tif (Math.abs(scrolled) < 1) {\n\t\t\treturn dy > 0\n\t\t\t\t? `⚠️ ${warningMsg} Already at the bottom of container (${el!.tagName}), cannot scroll down further.`\n\t\t\t\t: `⚠️ ${warningMsg} Already at the top of container (${el!.tagName}), cannot scroll up further.`\n\t\t}\n\n\t\tconst reachedBottom = dy > 0 && scrollAfter >= scrollMax - 1\n\t\tconst reachedTop = dy < 0 && scrollAfter <= 1\n\n\t\tif (reachedBottom)\n\t\t\treturn `✅ ${warningMsg} Scrolled container (${el!.tagName}) by ${scrolled}px. Reached the bottom.`\n\t\tif (reachedTop)\n\t\t\treturn `✅ ${warningMsg} Scrolled container (${el!.tagName}) by ${scrolled}px. Reached the top.`\n\t\treturn `✅ ${warningMsg} Scrolled container (${el!.tagName}) by ${scrolled}px.`\n\t}\n}\n\nexport async function scrollHorizontally(scroll_amount: number, element?: HTMLElement | null) {\n\t// Element-specific scrolling if element is provided\n\tif (element) {\n\t\tconst targetElement = element\n\t\tlet currentElement = targetElement as HTMLElement | null\n\t\tlet scrollSuccess = false\n\t\tlet scrolledElement: HTMLElement | null = null\n\t\tlet scrollDelta = 0\n\t\tlet attempts = 0\n\t\tconst dx = scroll_amount\n\n\t\twhile (currentElement && attempts < 10) {\n\t\t\tconst computedStyle = window.getComputedStyle(currentElement)\n\t\t\tconst hasScrollableX =\n\t\t\t\t/(auto|scroll|overlay)/.test(computedStyle.overflowX) ||\n\t\t\t\t(computedStyle.scrollbarWidth && computedStyle.scrollbarWidth !== 'auto') ||\n\t\t\t\t(computedStyle.scrollbarGutter && computedStyle.scrollbarGutter !== 'auto')\n\t\t\tconst canScrollHorizontally = currentElement.scrollWidth > currentElement.clientWidth\n\n\t\t\tif (hasScrollableX && canScrollHorizontally) {\n\t\t\t\tconst beforeScroll = currentElement.scrollLeft\n\t\t\t\tconst maxScroll = currentElement.scrollWidth - currentElement.clientWidth\n\n\t\t\t\tlet scrollAmount = dx / 3\n\n\t\t\t\tif (scrollAmount > 0) {\n\t\t\t\t\tscrollAmount = Math.min(scrollAmount, maxScroll - beforeScroll)\n\t\t\t\t} else {\n\t\t\t\t\tscrollAmount = Math.max(scrollAmount, -beforeScroll)\n\t\t\t\t}\n\n\t\t\t\tcurrentElement.scrollLeft = beforeScroll + scrollAmount\n\n\t\t\t\tconst afterScroll = currentElement.scrollLeft\n\t\t\t\tconst actualScrollDelta = afterScroll - beforeScroll\n\n\t\t\t\tif (Math.abs(actualScrollDelta) > 0.5) {\n\t\t\t\t\tscrollSuccess = true\n\t\t\t\t\tscrolledElement = currentElement\n\t\t\t\t\tscrollDelta = actualScrollDelta\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (currentElement === document.body || currentElement === document.documentElement) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcurrentElement = currentElement.parentElement\n\t\t\tattempts++\n\t\t}\n\n\t\tif (scrollSuccess) {\n\t\t\treturn `Scrolled container (${scrolledElement?.tagName}) horizontally by ${scrollDelta}px`\n\t\t} else {\n\t\t\treturn `No horizontally scrollable container found for element (${targetElement.tagName})`\n\t\t}\n\t}\n\n\t// Page-level scrolling (default or fallback)\n\n\tconst dx = scroll_amount\n\n\tconst bigEnough = (el: HTMLElement) => el.clientWidth >= window.innerWidth * 0.5\n\tconst canScroll = (el: HTMLElement | null): boolean =>\n\t\tBoolean(\n\t\t\tel &&\n\t\t\t/(auto|scroll|overlay)/.test(getComputedStyle(el).overflowX) &&\n\t\t\tel.scrollWidth > el.clientWidth &&\n\t\t\tbigEnough(el)\n\t\t)\n\n\t// @deprecated Same heuristic container search as scrollVertically.\n\t// TODO: Remove once LLMs reliably use indexed scrolling via data-scrollable.\n\n\tlet el: HTMLElement | null = document.activeElement as HTMLElement | null\n\twhile (el && !canScroll(el) && el !== document.body) el = el.parentElement\n\n\tel = canScroll(el)\n\t\t? el\n\t\t: Array.from(document.querySelectorAll<HTMLElement>('*')).find(canScroll) ||\n\t\t\t(document.scrollingElement as HTMLElement) ||\n\t\t\t(document.documentElement as HTMLElement)\n\n\tif (el === document.scrollingElement || el === document.documentElement || el === document.body) {\n\t\t// Page-level scroll\n\t\tconst scrollBefore = window.scrollX\n\t\tconst scrollMax = document.documentElement.scrollWidth - window.innerWidth\n\n\t\twindow.scrollBy(dx, 0)\n\n\t\tconst scrollAfter = window.scrollX\n\t\tconst scrolled = scrollAfter - scrollBefore\n\n\t\tif (Math.abs(scrolled) < 1) {\n\t\t\treturn dx > 0\n\t\t\t\t? `⚠️ Already at the right edge of the page, cannot scroll right further.`\n\t\t\t\t: `⚠️ Already at the left edge of the page, cannot scroll left further.`\n\t\t}\n\n\t\tconst reachedRight = dx > 0 && scrollAfter >= scrollMax - 1\n\t\tconst reachedLeft = dx < 0 && scrollAfter <= 1\n\n\t\tif (reachedRight)\n\t\t\treturn `✅ Scrolled page by ${scrolled}px. Reached the right edge of the page.`\n\t\tif (reachedLeft) return `✅ Scrolled page by ${scrolled}px. Reached the left edge of the page.`\n\t\treturn `✅ Scrolled page horizontally by ${scrolled}px.`\n\t} else {\n\t\t// Container scroll\n\t\tconst warningMsg = `The document is not scrollable. Falling back to container scroll.`\n\t\tconsole.log(`[BrowserController] ${warningMsg}`)\n\n\t\tconst scrollBefore = el!.scrollLeft\n\t\tconst scrollMax = el!.scrollWidth - el!.clientWidth\n\n\t\tel!.scrollBy({ left: dx, behavior: 'smooth' })\n\t\tawait waitFor(0.1)\n\n\t\tconst scrollAfter = el!.scrollLeft\n\t\tconst scrolled = scrollAfter - scrollBefore\n\n\t\tif (Math.abs(scrolled) < 1) {\n\t\t\treturn dx > 0\n\t\t\t\t? `⚠️ ${warningMsg} Already at the right edge of container (${el!.tagName}), cannot scroll right further.`\n\t\t\t\t: `⚠️ ${warningMsg} Already at the left edge of container (${el!.tagName}), cannot scroll left further.`\n\t\t}\n\n\t\tconst reachedRight = dx > 0 && scrollAfter >= scrollMax - 1\n\t\tconst reachedLeft = dx < 0 && scrollAfter <= 1\n\n\t\tif (reachedRight)\n\t\t\treturn `✅ ${warningMsg} Scrolled container (${el!.tagName}) by ${scrolled}px. Reached the right edge.`\n\t\tif (reachedLeft)\n\t\t\treturn `✅ ${warningMsg} Scrolled container (${el!.tagName}) by ${scrolled}px. Reached the left edge.`\n\t\treturn `✅ ${warningMsg} Scrolled container (${el!.tagName}) horizontally by ${scrolled}px.`\n\t}\n}\n","/**\n * @file port from browser-use\n * @see https://github.com/browser-use/browser-use/commits/main/browser_use/dom/dom_tree/index.js\n * @match 0.5.9 d51b6e73daff7165fdd3e44debd667e7f5f7fdc5\n *\n * search @edit for all the changed lines.\n *\n * @edit export\n * @edit add interactiveBlacklist interactiveWhitelist\n * @edit adjustable opacity\n * @edit direct dom ref\n * @edit @workaround input.checked\n * @edit smaller zIndex for highlight\n * @edit no need for xpath\n * @edit add `extra` field for extra data\n * @edit scrollable element detection\n * @edit add `data-browser-use-ignore` attribute\n * @edit improve `sampleRect`, filter out rects with 0 area\n * @edit exclude aria-hidden elements\n * @edit make sure attributes exist for interactive candidates.\n * @edit fix \"aria-*\" attributes check\n */\n\n/* eslint-disable @typescript-eslint/no-unused-vars, no-undef, no-useless-assignment */\n\nexport default (\n\targs = {\n\t\tdoHighlightElements: true,\n\t\tfocusHighlightIndex: -1,\n\t\tviewportExpansion: 0,\n\t\tdebugMode: false,\n\n\t\t/**\n\t\t * @edit\n\t\t */\n\t\t/** @type {Element[]} */\n\t\tinteractiveBlacklist: [],\n\t\t/** @type {Element[]} */\n\t\tinteractiveWhitelist: [],\n\t\thighlightOpacity: 0.1,\n\t\thighlightLabelOpacity: 0.5,\n\t}\n) => {\n\t/**\n\t * @edit\n\t */\n\tconst { interactiveBlacklist, interactiveWhitelist, highlightOpacity, highlightLabelOpacity } =\n\t\targs\n\n\tconst { doHighlightElements, focusHighlightIndex, viewportExpansion, debugMode } = args\n\tlet highlightIndex = 0 // Reset highlight index\n\n\t/**\n\t * @edit add `extra` field for extra data\n\t */\n\tconst extraData = new WeakMap()\n\tfunction addExtraData(element, data) {\n\t\tif (!element || element.nodeType !== Node.ELEMENT_NODE) return\n\t\textraData.set(element, { ...extraData.get(element), ...data })\n\t}\n\n\t// Add caching mechanisms at the top level\n\tconst DOM_CACHE = {\n\t\tboundingRects: new WeakMap(),\n\t\tclientRects: new WeakMap(),\n\t\tcomputedStyles: new WeakMap(),\n\t\tclearCache: () => {\n\t\t\tDOM_CACHE.boundingRects = new WeakMap()\n\t\t\tDOM_CACHE.clientRects = new WeakMap()\n\t\t\tDOM_CACHE.computedStyles = new WeakMap()\n\t\t},\n\t}\n\n\t/**\n\t * Gets the cached bounding rect for an element.\n\t *\n\t * @param {HTMLElement} element - The element to get the bounding rect for.\n\t * @returns {DOMRect | null} The cached bounding rect, or null if the element is not found.\n\t */\n\tfunction getCachedBoundingRect(element) {\n\t\tif (!element) return null\n\n\t\tif (DOM_CACHE.boundingRects.has(element)) {\n\t\t\treturn DOM_CACHE.boundingRects.get(element)\n\t\t}\n\n\t\tconst rect = element.getBoundingClientRect()\n\n\t\tif (rect) {\n\t\t\tDOM_CACHE.boundingRects.set(element, rect)\n\t\t}\n\t\treturn rect\n\t}\n\n\t/**\n\t * Gets the cached computed style for an element.\n\t *\n\t * @param {HTMLElement} element - The element to get the computed style for.\n\t * @returns {CSSStyleDeclaration | null} The cached computed style, or null if the element is not found.\n\t */\n\tfunction getCachedComputedStyle(element) {\n\t\tif (!element) return null\n\n\t\tif (DOM_CACHE.computedStyles.has(element)) {\n\t\t\treturn DOM_CACHE.computedStyles.get(element)\n\t\t}\n\n\t\tconst style = window.getComputedStyle(element)\n\n\t\tif (style) {\n\t\t\tDOM_CACHE.computedStyles.set(element, style)\n\t\t}\n\t\treturn style\n\t}\n\n\t/**\n\t * Gets the cached client rects for an element.\n\t *\n\t * @param {HTMLElement} element - The element to get the client rects for.\n\t * @returns {DOMRectList | null} The cached client rects, or null if the element is not found.\n\t */\n\tfunction getCachedClientRects(element) {\n\t\tif (!element) return null\n\n\t\tif (DOM_CACHE.clientRects.has(element)) {\n\t\t\treturn DOM_CACHE.clientRects.get(element)\n\t\t}\n\n\t\tconst rects = element.getClientRects()\n\n\t\tif (rects) {\n\t\t\tDOM_CACHE.clientRects.set(element, rects)\n\t\t}\n\t\treturn rects\n\t}\n\n\t/**\n\t * Hash map of DOM nodes indexed by their highlight index.\n\t *\n\t * @type {Object<string, any>}\n\t */\n\tconst DOM_HASH_MAP = {}\n\n\tconst ID = { current: 0 }\n\n\tconst HIGHLIGHT_CONTAINER_ID = 'playwright-highlight-container'\n\n\t// Add a WeakMap cache for XPath strings\n\tconst xpathCache = new WeakMap()\n\n\t// // Initialize once and reuse\n\t// const viewportObserver = new IntersectionObserver(\n\t// (entries) => {\n\t// entries.forEach(entry => {\n\t// elementVisibilityMap.set(entry.target, entry.isIntersecting);\n\t// });\n\t// },\n\t// { rootMargin: `${viewportExpansion}px` }\n\t// );\n\n\t/**\n\t * Highlights an element in the DOM and returns the index of the next element.\n\t *\n\t * @param {HTMLElement} element - The element to highlight.\n\t * @param {number} index - The index of the element.\n\t * @param {HTMLElement | null} parentIframe - The parent iframe node.\n\t * @returns {number} The index of the next element.\n\t */\n\tfunction highlightElement(element, index, parentIframe = null) {\n\t\tif (!element) return index\n\n\t\tconst overlays = []\n\t\t/**\n\t\t * @type {HTMLElement | null}\n\t\t */\n\t\tlet label = null\n\t\tlet labelWidth = 20\n\t\tlet labelHeight = 16\n\t\tlet cleanupFn = null\n\n\t\ttry {\n\t\t\t// Create or get highlight container\n\t\t\tlet container = document.getElementById(HIGHLIGHT_CONTAINER_ID)\n\t\t\tif (!container) {\n\t\t\t\tcontainer = document.createElement('div')\n\t\t\t\tcontainer.id = HIGHLIGHT_CONTAINER_ID\n\t\t\t\tcontainer.style.position = 'fixed'\n\t\t\t\tcontainer.style.pointerEvents = 'none'\n\t\t\t\tcontainer.style.top = '0'\n\t\t\t\tcontainer.style.left = '0'\n\t\t\t\tcontainer.style.width = '100%'\n\t\t\t\tcontainer.style.height = '100%'\n\n\t\t\t\t/**\n\t\t\t\t * @edit smaller zIndex for highlight\n\t\t\t\t */\n\t\t\t\t// Use the maximum valid value in zIndex to ensure the element is not blocked by overlapping elements.\n\t\t\t\t// container.style.zIndex = \"2147483647\";\n\t\t\t\tcontainer.style.zIndex = '2147483640'\n\n\t\t\t\tcontainer.style.backgroundColor = 'transparent'\n\t\t\t\tdocument.body.appendChild(container)\n\t\t\t}\n\n\t\t\t// Get element client rects\n\t\t\tconst rects = element.getClientRects() // Use getClientRects()\n\n\t\t\tif (!rects || rects.length === 0) return index // Exit if no rects\n\n\t\t\t// Generate a color based on the index\n\t\t\tconst colors = [\n\t\t\t\t'#FF0000',\n\t\t\t\t'#00FF00',\n\t\t\t\t'#0000FF',\n\t\t\t\t'#FFA500',\n\t\t\t\t'#800080',\n\t\t\t\t'#008080',\n\t\t\t\t'#FF69B4',\n\t\t\t\t'#4B0082',\n\t\t\t\t'#FF4500',\n\t\t\t\t'#2E8B57',\n\t\t\t\t'#DC143C',\n\t\t\t\t'#4682B4',\n\t\t\t]\n\t\t\tconst colorIndex = index % colors.length\n\t\t\tlet baseColor = colors[colorIndex]\n\n\t\t\t/**\n\t\t\t * @edit adjustable opacity\n\t\t\t */\n\t\t\t// const backgroundColor = baseColor + \"1A\"; // 10% opacity version of the color\n\t\t\tconst backgroundColor =\n\t\t\t\tbaseColor +\n\t\t\t\tMath.floor(highlightOpacity * 255)\n\t\t\t\t\t.toString(16)\n\t\t\t\t\t.padStart(2, '0')\n\t\t\tbaseColor =\n\t\t\t\tbaseColor +\n\t\t\t\tMath.floor(highlightLabelOpacity * 255)\n\t\t\t\t\t.toString(16)\n\t\t\t\t\t.padStart(2, '0')\n\n\t\t\t// Get iframe offset if necessary\n\t\t\tlet iframeOffset = { x: 0, y: 0 }\n\t\t\tif (parentIframe) {\n\t\t\t\tconst iframeRect = parentIframe.getBoundingClientRect() // Keep getBoundingClientRect for iframe offset\n\t\t\t\tiframeOffset.x = iframeRect.left\n\t\t\t\tiframeOffset.y = iframeRect.top\n\t\t\t}\n\n\t\t\t// Create fragment to hold overlay elements\n\t\t\tconst fragment = document.createDocumentFragment()\n\n\t\t\t// Create highlight overlays for each client rect\n\t\t\tfor (const rect of rects) {\n\t\t\t\tif (rect.width === 0 || rect.height === 0) continue // Skip empty rects\n\n\t\t\t\tconst overlay = document.createElement('div')\n\t\t\t\toverlay.style.position = 'fixed'\n\t\t\t\toverlay.style.border = `2px solid ${baseColor}`\n\t\t\t\toverlay.style.backgroundColor = backgroundColor\n\t\t\t\toverlay.style.pointerEvents = 'none'\n\t\t\t\toverlay.style.boxSizing = 'border-box'\n\n\t\t\t\tconst top = rect.top + iframeOffset.y\n\t\t\t\tconst left = rect.left + iframeOffset.x\n\n\t\t\t\toverlay.style.top = `${top}px`\n\t\t\t\toverlay.style.left = `${left}px`\n\t\t\t\toverlay.style.width = `${rect.width}px`\n\t\t\t\toverlay.style.height = `${rect.height}px`\n\n\t\t\t\tfragment.appendChild(overlay)\n\t\t\t\toverlays.push({ element: overlay, initialRect: rect }) // Store overlay and its rect\n\t\t\t}\n\n\t\t\t// Create and position a single label relative to the first rect\n\t\t\tconst firstRect = rects[0]\n\t\t\tlabel = document.createElement('div')\n\t\t\tlabel.className = 'playwright-highlight-label'\n\t\t\tlabel.style.position = 'fixed'\n\t\t\tlabel.style.background = baseColor\n\t\t\tlabel.style.color = 'white'\n\t\t\tlabel.style.padding = '1px 4px'\n\t\t\tlabel.style.borderRadius = '4px'\n\t\t\tlabel.style.fontSize = `${Math.min(12, Math.max(8, firstRect.height / 2))}px`\n\t\t\tlabel.textContent = index.toString()\n\n\t\t\tlabelWidth = label.offsetWidth > 0 ? label.offsetWidth : labelWidth // Update actual width if possible\n\t\t\tlabelHeight = label.offsetHeight > 0 ? label.offsetHeight : labelHeight // Update actual height if possible\n\n\t\t\tconst firstRectTop = firstRect.top + iframeOffset.y\n\t\t\tconst firstRectLeft = firstRect.left + iframeOffset.x\n\n\t\t\tlet labelTop = firstRectTop + 2\n\t\t\tlet labelLeft = firstRectLeft + firstRect.width - labelWidth - 2\n\n\t\t\t// Adjust label position if first rect is too small\n\t\t\tif (firstRect.width < labelWidth + 4 || firstRect.height < labelHeight + 4) {\n\t\t\t\tlabelTop = firstRectTop - labelHeight - 2\n\t\t\t\tlabelLeft = firstRectLeft + firstRect.width - labelWidth // Align with right edge\n\t\t\t\tif (labelLeft < iframeOffset.x) labelLeft = firstRectLeft // Prevent going off-left\n\t\t\t}\n\n\t\t\t// Ensure label stays within viewport bounds slightly better\n\t\t\tlabelTop = Math.max(0, Math.min(labelTop, window.innerHeight - labelHeight))\n\t\t\tlabelLeft = Math.max(0, Math.min(labelLeft, window.innerWidth - labelWidth))\n\n\t\t\tlabel.style.top = `${labelTop}px`\n\t\t\tlabel.style.left = `${labelLeft}px`\n\n\t\t\tfragment.appendChild(label)\n\n\t\t\t// Update positions on scroll/resize\n\t\t\tconst updatePositions = () => {\n\t\t\t\tconst newRects = element.getClientRects() // Get fresh rects\n\t\t\t\tlet newIframeOffset = { x: 0, y: 0 }\n\n\t\t\t\tif (parentIframe) {\n\t\t\t\t\tconst iframeRect = parentIframe.getBoundingClientRect() // Keep getBoundingClientRect for iframe\n\t\t\t\t\tnewIframeOffset.x = iframeRect.left\n\t\t\t\t\tnewIframeOffset.y = iframeRect.top\n\t\t\t\t}\n\n\t\t\t\t// Update each overlay\n\t\t\t\toverlays.forEach((overlayData, i) => {\n\t\t\t\t\tif (i < newRects.length) {\n\t\t\t\t\t\t// Check if rect still exists\n\t\t\t\t\t\tconst newRect = newRects[i]\n\t\t\t\t\t\tconst newTop = newRect.top + newIframeOffset.y\n\t\t\t\t\t\tconst newLeft = newRect.left + newIframeOffset.x\n\n\t\t\t\t\t\toverlayData.element.style.top = `${newTop}px`\n\t\t\t\t\t\toverlayData.element.style.left = `${newLeft}px`\n\t\t\t\t\t\toverlayData.element.style.width = `${newRect.width}px`\n\t\t\t\t\t\toverlayData.element.style.height = `${newRect.height}px`\n\t\t\t\t\t\toverlayData.element.style.display =\n\t\t\t\t\t\t\tnewRect.width === 0 || newRect.height === 0 ? 'none' : 'block'\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// If fewer rects now, hide extra overlays\n\t\t\t\t\t\toverlayData.element.style.display = 'none'\n\t\t\t\t\t}\n\t\t\t\t})\n\n\t\t\t\t// If there are fewer new rects than overlays, hide the extras\n\t\t\t\tif (newRects.length < overlays.length) {\n\t\t\t\t\tfor (let i = newRects.length; i < overlays.length; i++) {\n\t\t\t\t\t\toverlays[i].element.style.display = 'none'\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Update label position based on the first new rect\n\t\t\t\tif (label && newRects.length > 0) {\n\t\t\t\t\tconst firstNewRect = newRects[0]\n\t\t\t\t\tconst firstNewRectTop = firstNewRect.top + newIframeOffset.y\n\t\t\t\t\tconst firstNewRectLeft = firstNewRect.left + newIframeOffset.x\n\n\t\t\t\t\tlet newLabelTop = firstNewRectTop + 2\n\t\t\t\t\tlet newLabelLeft = firstNewRectLeft + firstNewRect.width - labelWidth - 2\n\n\t\t\t\t\tif (firstNewRect.width < labelWidth + 4 || firstNewRect.height < labelHeight + 4) {\n\t\t\t\t\t\tnewLabelTop = firstNewRectTop - labelHeight - 2\n\t\t\t\t\t\tnewLabelLeft = firstNewRectLeft + firstNewRect.width - labelWidth\n\t\t\t\t\t\tif (newLabelLeft < newIframeOffset.x) newLabelLeft = firstNewRectLeft\n\t\t\t\t\t}\n\n\t\t\t\t\t// Ensure label stays within viewport bounds\n\t\t\t\t\tnewLabelTop = Math.max(0, Math.min(newLabelTop, window.innerHeight - labelHeight))\n\t\t\t\t\tnewLabelLeft = Math.max(0, Math.min(newLabelLeft, window.innerWidth - labelWidth))\n\n\t\t\t\t\tlabel.style.top = `${newLabelTop}px`\n\t\t\t\t\tlabel.style.left = `${newLabelLeft}px`\n\t\t\t\t\tlabel.style.display = 'block'\n\t\t\t\t} else if (label) {\n\t\t\t\t\t// Hide label if element has no rects anymore\n\t\t\t\t\tlabel.style.display = 'none'\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst throttleFunction = (func, delay) => {\n\t\t\t\tlet lastCall = 0\n\t\t\t\treturn (...args) => {\n\t\t\t\t\tconst now = performance.now()\n\t\t\t\t\tif (now - lastCall < delay) return\n\t\t\t\t\tlastCall = now\n\t\t\t\t\treturn func(...args)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst throttledUpdatePositions = throttleFunction(updatePositions, 16) // ~60fps\n\t\t\twindow.addEventListener('scroll', throttledUpdatePositions, true)\n\t\t\twindow.addEventListener('resize', throttledUpdatePositions)\n\n\t\t\t// Add cleanup function\n\t\t\tcleanupFn = () => {\n\t\t\t\twindow.removeEventListener('scroll', throttledUpdatePositions, true)\n\t\t\t\twindow.removeEventListener('resize', throttledUpdatePositions)\n\t\t\t\t// Remove overlay elements if needed\n\t\t\t\toverlays.forEach((overlay) => overlay.element.remove())\n\t\t\t\tif (label) label.remove()\n\t\t\t}\n\n\t\t\t// Then add fragment to container in one operation\n\t\t\tcontainer.appendChild(fragment)\n\n\t\t\treturn index + 1\n\t\t} finally {\n\t\t\t// Store cleanup function for later use\n\t\t\tif (cleanupFn) {\n\t\t\t\t// Keep a reference to cleanup functions in a global array\n\t\t\t\t;(window._highlightCleanupFunctions = window._highlightCleanupFunctions || []).push(\n\t\t\t\t\tcleanupFn\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t}\n\n\t// // Add this function to perform cleanup when needed\n\t// function cleanupHighlights() {\n\t// if (window._highlightCleanupFunctions && window._highlightCleanupFunctions.length) {\n\t// window._highlightCleanupFunctions.forEach(fn => fn());\n\t// window._highlightCleanupFunctions = [];\n\t// }\n\n\t// // Also remove the container\n\t// const container = document.getElementById(HIGHLIGHT_CONTAINER_ID);\n\t// if (container) container.remove();\n\t// }\n\n\t/**\n\t * Gets the position of an element in its parent.\n\t *\n\t * @param {HTMLElement} currentElement - The element to get the position for.\n\t * @returns {number} The position of the element in its parent.\n\t */\n\tfunction getElementPosition(currentElement) {\n\t\tif (!currentElement.parentElement) {\n\t\t\treturn 0 // No parent means no siblings\n\t\t}\n\n\t\tconst tagName = currentElement.nodeName.toLowerCase()\n\n\t\tconst siblings = Array.from(currentElement.parentElement.children).filter(\n\t\t\t(sib) => sib.nodeName.toLowerCase() === tagName\n\t\t)\n\n\t\tif (siblings.length === 1) {\n\t\t\treturn 0 // Only element of its type\n\t\t}\n\n\t\tconst index = siblings.indexOf(currentElement) + 1 // 1-based index\n\t\treturn index\n\t}\n\n\tfunction getXPathTree(element, stopAtBoundary = true) {\n\t\tif (xpathCache.has(element)) return xpathCache.get(element)\n\n\t\tconst segments = []\n\t\tlet currentElement = element\n\n\t\twhile (currentElement && currentElement.nodeType === Node.ELEMENT_NODE) {\n\t\t\t// Stop if we hit a shadow root or iframe\n\t\t\tif (\n\t\t\t\tstopAtBoundary &&\n\t\t\t\t(currentElement.parentNode instanceof ShadowRoot ||\n\t\t\t\t\tcurrentElement.parentNode instanceof HTMLIFrameElement)\n\t\t\t) {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tconst position = getElementPosition(currentElement)\n\t\t\tconst tagName = currentElement.nodeName.toLowerCase()\n\t\t\tconst xpathIndex = position > 0 ? `[${position}]` : ''\n\t\t\tsegments.unshift(`${tagName}${xpathIndex}`)\n\n\t\t\tcurrentElement = currentElement.parentNode\n\t\t}\n\n\t\tconst result = segments.join('/')\n\t\txpathCache.set(element, result)\n\t\treturn result\n\t}\n\n\t/**\n\t * @edit scrollable element detection\n\t * Checks if an element is scrollable. if so, return the scrollable distance on each direction (left right top bottom). if not return null.\n\t * @note distance smaller than 4 will be considered as not scrollable.\n\t * @note only check block elements, not inline elements.\n\t */\n\tfunction isScrollableElement(element) {\n\t\tif (!element || element.nodeType !== Node.ELEMENT_NODE) {\n\t\t\treturn null // Not a valid element\n\t\t}\n\n\t\tconst style = getCachedComputedStyle(element)\n\t\tif (!style) return null\n\n\t\t// Check if the element is a block-level element\n\t\tconst display = style.display\n\t\tif (display === 'inline' || display === 'inline-block') {\n\t\t\treturn null // Not a block-level element\n\t\t}\n\n\t\t// Check overflow properties\n\t\tconst overflowX = style.overflowX\n\t\tconst overflowY = style.overflowY\n\n\t\t// scrollbar-width/scrollbar-gutter are only set on elements designed to scroll;\n\t\t// their presence signals scroll intent even when overflow is hidden (e.g. overflow: auto on :hover)\n\t\tconst hasScrollbarSignal =\n\t\t\t(style.scrollbarWidth && style.scrollbarWidth !== 'auto') ||\n\t\t\t(style.scrollbarGutter && style.scrollbarGutter !== 'auto')\n\n\t\tconst scrollableX = overflowX === 'auto' || overflowX === 'scroll'\n\t\tconst scrollableY = overflowY === 'auto' || overflowY === 'scroll'\n\n\t\tif (!scrollableX && !scrollableY && !hasScrollbarSignal) {\n\t\t\treturn null // Not scrollable in any direction\n\t\t}\n\n\t\tconst scrollWidth = element.scrollWidth - element.clientWidth\n\t\tconst scrollHeight = element.scrollHeight - element.clientHeight\n\n\t\t// Consider small distances as not scrollable\n\t\tconst threshold = 4\n\n\t\tif (scrollWidth < threshold && scrollHeight < threshold) {\n\t\t\treturn null // Not scrollable\n\t\t}\n\n\t\tif (!scrollableY && !hasScrollbarSignal && scrollWidth < threshold) {\n\t\t\treturn null // Not scrollable horizontally\n\t\t}\n\n\t\tif (!scrollableX && !hasScrollbarSignal && scrollHeight < threshold) {\n\t\t\treturn null // Not scrollable vertically\n\t\t}\n\n\t\tconst distanceToTop = element.scrollTop\n\t\tconst distanceToLeft = element.scrollLeft\n\t\tconst distanceToRight = element.scrollWidth - element.clientWidth - element.scrollLeft\n\t\tconst distanceToBottom = element.scrollHeight - element.clientHeight - element.scrollTop\n\n\t\tconst scrollData = {\n\t\t\ttop: distanceToTop,\n\t\t\tright: distanceToRight,\n\t\t\tbottom: distanceToBottom,\n\t\t\tleft: distanceToLeft,\n\t\t}\n\n\t\t// Store extra data for the element\n\t\taddExtraData(element, {\n\t\t\tscrollable: true,\n\t\t\tscrollData: scrollData,\n\t\t})\n\n\t\treturn scrollData\n\t}\n\n\t/**\n\t * Checks if a text node is visible.\n\t *\n\t * @param {Text} textNode - The text node to check.\n\t * @returns {boolean} Whether the text node is visible.\n\t */\n\tfunction isTextNodeVisible(textNode) {\n\t\ttry {\n\t\t\t// Special case: when viewportExpansion is -1, consider all text nodes as visible\n\t\t\tif (viewportExpansion === -1) {\n\t\t\t\t// Still check parent visibility for basic filtering\n\t\t\t\tconst parentElement = textNode.parentElement\n\t\t\t\tif (!parentElement) return false\n\n\t\t\t\ttry {\n\t\t\t\t\treturn parentElement.checkVisibility({\n\t\t\t\t\t\tcheckOpacity: true,\n\t\t\t\t\t\tcheckVisibilityCSS: true,\n\t\t\t\t\t})\n\t\t\t\t} catch (e) {\n\t\t\t\t\t// Fallback if checkVisibility is not supported\n\t\t\t\t\tconst style = window.getComputedStyle(parentElement)\n\t\t\t\t\treturn style.display !== 'none' && style.visibility !== 'hidden' && style.opacity !== '0'\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst range = document.createRange()\n\t\t\trange.selectNodeContents(textNode)\n\t\t\tconst rects = range.getClientRects() // Use getClientRects for Range\n\n\t\t\tif (!rects || rects.length === 0) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tlet isAnyRectVisible = false\n\t\t\tlet isAnyRectInViewport = false\n\n\t\t\tfor (const rect of rects) {\n\t\t\t\t// Check size\n\t\t\t\tif (rect.width > 0 && rect.height > 0) {\n\t\t\t\t\tisAnyRectVisible = true\n\n\t\t\t\t\t// Viewport check for this rect\n\t\t\t\t\tif (!(\n\t\t\t\t\t\trect.bottom < -viewportExpansion ||\n\t\t\t\t\t\trect.top > window.innerHeight + viewportExpansion ||\n\t\t\t\t\t\trect.right < -viewportExpansion ||\n\t\t\t\t\t\trect.left > window.innerWidth + viewportExpansion\n\t\t\t\t\t)) {\n\t\t\t\t\t\tisAnyRectInViewport = true\n\t\t\t\t\t\tbreak // Found a visible rect in viewport, no need to check others\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!isAnyRectVisible || !isAnyRectInViewport) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\t// Check parent visibility\n\t\t\tconst parentElement = textNode.parentElement\n\t\t\tif (!parentElement) return false\n\n\t\t\ttry {\n\t\t\t\treturn parentElement.checkVisibility({\n\t\t\t\t\tcheckOpacity: true,\n\t\t\t\t\tcheckVisibilityCSS: true,\n\t\t\t\t})\n\t\t\t} catch (e) {\n\t\t\t\t// Fallback if checkVisibility is not supported\n\t\t\t\tconst style = window.getComputedStyle(parentElement)\n\t\t\t\treturn style.display !== 'none' && style.visibility !== 'hidden' && style.opacity !== '0'\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tconsole.warn('Error checking text node visibility:', e)\n\t\t\treturn false\n\t\t}\n\t}\n\n\t/**\n\t * Checks if an element is accepted.\n\t *\n\t * @param {HTMLElement} element - The element to check.\n\t * @returns {boolean} Whether the element is accepted.\n\t */\n\tfunction isElementAccepted(element) {\n\t\tif (!element || !element.tagName) return false\n\n\t\t// Always accept body and common container elements\n\t\tconst alwaysAccept = new Set([\n\t\t\t'body',\n\t\t\t'div',\n\t\t\t'main',\n\t\t\t'article',\n\t\t\t'section',\n\t\t\t'nav',\n\t\t\t'header',\n\t\t\t'footer',\n\t\t])\n\t\tconst tagName = element.tagName.toLowerCase()\n\n\t\tif (alwaysAccept.has(tagName)) return true\n\n\t\tconst leafElementDenyList = new Set([\n\t\t\t'svg',\n\t\t\t'script',\n\t\t\t'style',\n\t\t\t'link',\n\t\t\t'meta',\n\t\t\t'noscript',\n\t\t\t'template',\n\t\t])\n\n\t\treturn !leafElementDenyList.has(tagName)\n\t}\n\n\t/**\n\t * Checks if an element is visible.\n\t *\n\t * @param {HTMLElement} element - The element to check.\n\t * @returns {boolean} Whether the element is visible.\n\t */\n\tfunction isElementVisible(element) {\n\t\tconst style = getCachedComputedStyle(element)\n\t\treturn (\n\t\t\telement.offsetWidth > 0 &&\n\t\t\telement.offsetHeight > 0 &&\n\t\t\tstyle?.visibility !== 'hidden' &&\n\t\t\tstyle?.display !== 'none'\n\t\t)\n\t}\n\n\t/**\n\t * Checks if an element is interactive.\n\t *\n\t * lots of comments, and uncommented code - to show the logic of what we already tried\n\t *\n\t * One of the things we tried at the beginning was also to use event listeners, and other fancy class, style stuff -> what actually worked best was just combining most things with computed cursor style :)\n\t *\n\t * @param {HTMLElement} element - The element to check.\n\t */\n\tfunction isInteractiveElement(element) {\n\t\tif (!element || element.nodeType !== Node.ELEMENT_NODE) {\n\t\t\treturn false\n\t\t}\n\n\t\t/**\n\t\t * @edit add interactiveBlacklist interactiveWhitelist\n\t\t */\n\t\tif (interactiveBlacklist.includes(element)) {\n\t\t\treturn false // Skip blacklisted elements\n\t\t}\n\t\tif (interactiveWhitelist.includes(element)) {\n\t\t\treturn true // Skip whitelisted elements\n\t\t}\n\n\t\t// Cache the tagName and style lookups\n\t\tconst tagName = element.tagName.toLowerCase()\n\t\tconst style = getCachedComputedStyle(element)\n\n\t\t// Define interactive cursors\n\t\tconst interactiveCursors = new Set([\n\t\t\t'pointer', // Link/clickable elements\n\t\t\t'move', // Movable elements\n\t\t\t'text', // Text selection\n\t\t\t'grab', // Grabbable elements\n\t\t\t'grabbing', // Currently grabbing\n\t\t\t'cell', // Table cell selection\n\t\t\t'copy', // Copy operation\n\t\t\t'alias', // Alias creation\n\t\t\t'all-scroll', // Scrollable content\n\t\t\t'col-resize', // Column resize\n\t\t\t'context-menu', // Context menu available\n\t\t\t'crosshair', // Precise selection\n\t\t\t'e-resize', // East resize\n\t\t\t'ew-resize', // East-west resize\n\t\t\t'help', // Help available\n\t\t\t'n-resize', // North resize\n\t\t\t'ne-resize', // Northeast resize\n\t\t\t'nesw-resize', // Northeast-southwest resize\n\t\t\t'ns-resize', // North-south resize\n\t\t\t'nw-resize', // Northwest resize\n\t\t\t'nwse-resize', // Northwest-southeast resize\n\t\t\t'row-resize', // Row resize\n\t\t\t's-resize', // South resize\n\t\t\t'se-resize', // Southeast resize\n\t\t\t'sw-resize', // Southwest resize\n\t\t\t'vertical-text', // Vertical text selection\n\t\t\t'w-resize', // West resize\n\t\t\t'zoom-in', // Zoom in\n\t\t\t'zoom-out', // Zoom out\n\t\t])\n\n\t\t// Define non-interactive cursors\n\t\tconst nonInteractiveCursors = new Set([\n\t\t\t'not-allowed', // Action not allowed\n\t\t\t'no-drop', // Drop not allowed\n\t\t\t'wait', // Processing\n\t\t\t'progress', // In progress\n\t\t\t'initial', // Initial value\n\t\t\t'inherit', // Inherited value\n\t\t\t//? Let's just include all potentially clickable elements that are not specifically blocked\n\t\t\t// 'none', // No cursor\n\t\t\t// 'default', // Default cursor\n\t\t\t// 'auto', // Browser default\n\t\t])\n\n\t\t/**\n\t\t * Checks if an element has an interactive pointer.\n\t\t *\n\t\t * @param {HTMLElement} element - The element to check.\n\t\t * @returns {boolean} Whether the element has an interactive pointer.\n\t\t */\n\t\tfunction doesElementHaveInteractivePointer(element) {\n\t\t\tif (element.tagName.toLowerCase() === 'html') return false\n\n\t\t\tif (style?.cursor && interactiveCursors.has(style.cursor)) return true\n\n\t\t\treturn false\n\t\t}\n\n\t\tlet isInteractiveCursor = doesElementHaveInteractivePointer(element)\n\n\t\t// Genius fix for almost all interactive elements\n\t\tif (isInteractiveCursor) {\n\t\t\treturn true\n\t\t}\n\n\t\tconst interactiveElements = new Set([\n\t\t\t'a', // Links\n\t\t\t'button', // Buttons\n\t\t\t'input', // All input types (text, checkbox, radio, etc.)\n\t\t\t'select', // Dropdown menus\n\t\t\t'textarea', // Text areas\n\t\t\t'details', // Expandable details\n\t\t\t'summary', // Summary element (clickable part of details)\n\t\t\t'label', // Form labels (often clickable)\n\t\t\t'option', // Select options\n\t\t\t'optgroup', // Option groups\n\t\t\t'fieldset', // Form fieldsets (can be interactive with legend)\n\t\t\t'legend', // Fieldset legends\n\t\t])\n\n\t\t// Define explicit disable attributes and properties\n\t\tconst explicitDisableTags = new Set([\n\t\t\t'disabled', // Standard disabled attribute\n\t\t\t// 'aria-disabled', // ARIA disabled state\n\t\t\t'readonly', // Read-only state\n\t\t\t// 'aria-readonly', // ARIA read-only state\n\t\t\t// 'aria-hidden', // Hidden from accessibility\n\t\t\t// 'hidden', // Hidden attribute\n\t\t\t// 'inert', // Inert attribute\n\t\t\t// 'aria-inert', // ARIA inert state\n\t\t\t// 'tabindex=\"-1\"', // Removed from tab order\n\t\t\t// 'aria-hidden=\"true\"' // Hidden from screen readers\n\t\t])\n\n\t\t// handle inputs, select, checkbox, radio, textarea, button and make sure they are not cursor style disabled/not-allowed\n\t\tif (interactiveElements.has(tagName)) {\n\t\t\t// Check for non-interactive cursor\n\t\t\tif (style?.cursor && nonInteractiveCursors.has(style.cursor)) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\t// Check for explicit disable attributes\n\t\t\tfor (const disableTag of explicitDisableTags) {\n\t\t\t\tif (\n\t\t\t\t\telement.hasAttribute(disableTag) ||\n\t\t\t\t\telement.getAttribute(disableTag) === 'true' ||\n\t\t\t\t\telement.getAttribute(disableTag) === ''\n\t\t\t\t) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Check for disabled property on form elements\n\t\t\tif (element.disabled) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\t// Check for readonly property on form elements\n\t\t\tif (element.readOnly) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\t// Check for inert property\n\t\t\tif (element.inert) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\treturn true\n\t\t}\n\n\t\tconst role = element.getAttribute('role')\n\t\tconst ariaRole = element.getAttribute('aria-role')\n\n\t\t// Check for contenteditable attribute\n\t\tif (element.getAttribute('contenteditable') === 'true' || element.isContentEditable) {\n\t\t\treturn true\n\t\t}\n\n\t\t// Added enhancement to capture dropdown interactive elements\n\t\tif (\n\t\t\telement.classList &&\n\t\t\t(element.classList.contains('button') ||\n\t\t\t\telement.classList.contains('dropdown-toggle') ||\n\t\t\t\telement.getAttribute('data-index') ||\n\t\t\t\telement.getAttribute('data-toggle') === 'dropdown' ||\n\t\t\t\telement.getAttribute('aria-haspopup') === 'true')\n\t\t) {\n\t\t\treturn true\n\t\t}\n\n\t\tconst interactiveRoles = new Set([\n\t\t\t'button', // Directly clickable element\n\t\t\t// 'link', // Clickable link\n\t\t\t'menu', // Menu container (ARIA menus)\n\t\t\t'menubar', // Menu bar container\n\t\t\t'menuitem', // Clickable menu item\n\t\t\t'menuitemradio', // Radio-style menu item (selectable)\n\t\t\t'menuitemcheckbox', // Checkbox-style menu item (toggleable)\n\t\t\t'radio', // Radio button (selectable)\n\t\t\t'checkbox', // Checkbox (toggleable)\n\t\t\t'tab', // Tab (clickable to switch content)\n\t\t\t'switch', // Toggle switch (clickable to change state)\n\t\t\t'slider', // Slider control (draggable)\n\t\t\t'spinbutton', // Number input with up/down controls\n\t\t\t'combobox', // Dropdown with text input\n\t\t\t'searchbox', // Search input field\n\t\t\t'textbox', // Text input field\n\t\t\t'listbox', // Selectable list\n\t\t\t'option', // Selectable option in a list\n\t\t\t'scrollbar', // Scrollable control\n\t\t])\n\n\t\t// Basic role/attribute checks\n\t\tconst hasInteractiveRole =\n\t\t\tinteractiveElements.has(tagName) ||\n\t\t\t(role && interactiveRoles.has(role)) ||\n\t\t\t(ariaRole && interactiveRoles.has(ariaRole))\n\n\t\tif (hasInteractiveRole) return true\n\n\t\t// check whether element has event listeners by window.getEventListeners\n\t\ttry {\n\t\t\tif (typeof getEventListeners === 'function') {\n\t\t\t\tconst listeners = getEventListeners(element)\n\t\t\t\tconst mouseEvents = ['click', 'mousedown', 'mouseup', 'dblclick']\n\t\t\t\tfor (const eventType of mouseEvents) {\n\t\t\t\t\tif (listeners[eventType] && listeners[eventType].length > 0) {\n\t\t\t\t\t\treturn true // Found a mouse interaction listener\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst getEventListenersForNode =\n\t\t\t\telement?.ownerDocument?.defaultView?.getEventListenersForNode ||\n\t\t\t\twindow.getEventListenersForNode\n\t\t\tif (typeof getEventListenersForNode === 'function') {\n\t\t\t\tconst listeners = getEventListenersForNode(element)\n\t\t\t\tconst interactionEvents = [\n\t\t\t\t\t'click',\n\t\t\t\t\t'mousedown',\n\t\t\t\t\t'mouseup',\n\t\t\t\t\t'keydown',\n\t\t\t\t\t'keyup',\n\t\t\t\t\t'submit',\n\t\t\t\t\t'change',\n\t\t\t\t\t'input',\n\t\t\t\t\t'focus',\n\t\t\t\t\t'blur',\n\t\t\t\t]\n\t\t\t\tfor (const eventType of interactionEvents) {\n\t\t\t\t\tfor (const listener of listeners) {\n\t\t\t\t\t\tif (listener.type === eventType) {\n\t\t\t\t\t\t\treturn true // Found a common interaction listener\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Fallback: Check common event attributes if getEventListeners is not available (getEventListeners doesn't work in page.evaluate context)\n\t\t\tconst commonMouseAttrs = ['onclick', 'onmousedown', 'onmouseup', 'ondblclick']\n\t\t\tfor (const attr of commonMouseAttrs) {\n\t\t\t\tif (element.hasAttribute(attr) || typeof element[attr] === 'function') {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (e) {\n\t\t\t// console.warn(`Could not check event listeners for ${element.tagName}:`, e);\n\t\t\t// If checking listeners fails, rely on other checks\n\t\t}\n\n\t\t/**\n\t\t * @edit scrollable element detection\n\t\t */\n\t\tif (isScrollableElement(element)) {\n\t\t\treturn true\n\t\t}\n\n\t\treturn false\n\t}\n\n\t/**\n\t * Checks if an element is the topmost element at its position.\n\t *\n\t * @param {HTMLElement} element - The element to check.\n\t * @returns {boolean} Whether the element is the topmost element at its position.\n\t */\n\tfunction isTopElement(element) {\n\t\t// Special case: when viewportExpansion is -1, consider all elements as \"top\" elements\n\t\tif (viewportExpansion === -1) {\n\t\t\treturn true\n\t\t}\n\n\t\tconst rects = getCachedClientRects(element) // Replace element.getClientRects()\n\n\t\tif (!rects || rects.length === 0) {\n\t\t\treturn false // No geometry, cannot be top\n\t\t}\n\n\t\tlet isAnyRectInViewport = false\n\t\tfor (const rect of rects) {\n\t\t\t// Use the same logic as isInExpandedViewport check\n\t\t\tif (\n\t\t\t\trect.width > 0 &&\n\t\t\t\trect.height > 0 &&\n\t\t\t\t!(\n\t\t\t\t\t// Only check non-empty rects\n\t\t\t\t\trect.bottom < -viewportExpansion ||\n\t\t\t\t\trect.top > window.innerHeight + viewportExpansion ||\n\t\t\t\t\trect.right < -viewportExpansion ||\n\t\t\t\t\trect.left > window.innerWidth + viewportExpansion\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tisAnyRectInViewport = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif (!isAnyRectInViewport) {\n\t\t\treturn false // All rects are outside the viewport area\n\t\t}\n\n\t\t// Find the correct document context and root element\n\t\tlet doc = element.ownerDocument\n\n\t\t// If we're in an iframe, elements are considered top by default\n\t\tif (doc !== window.document) {\n\t\t\treturn true\n\t\t}\n\n\t\t/**\n\t\t * @edit improve `sampleRect`, filter out rects with 0 area\n\t\t */\n\t\t// find a rect that has width and height as sample\n\t\tlet rect = Array.from(rects).find((r) => r.width > 0 && r.height > 0)\n\t\tif (!rect) {\n\t\t\treturn false // No valid rect found\n\t\t}\n\n\t\t// For shadow DOM, we need to check within its own root context\n\t\tconst shadowRoot = element.getRootNode()\n\t\tif (shadowRoot instanceof ShadowRoot) {\n\t\t\tconst centerX = rect.left + rect.width / 2\n\t\t\tconst centerY = rect.top + rect.height / 2\n\n\t\t\ttry {\n\t\t\t\tconst topEl = shadowRoot.elementFromPoint(centerX, centerY)\n\t\t\t\tif (!topEl) return false\n\n\t\t\t\tlet current = topEl\n\t\t\t\twhile (current && current !== shadowRoot) {\n\t\t\t\t\tif (current === element) return true\n\t\t\t\t\tcurrent = current.parentElement\n\t\t\t\t}\n\t\t\t\treturn false\n\t\t\t} catch (e) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\n\t\tconst margin = 5\n\n\t\t// For elements in viewport, check if they're topmost. Do the check in the\n\t\t// center of the element and at the corners to ensure we catch more cases.\n\t\tconst checkPoints = [\n\t\t\t// Initially only this was used, but it was not enough\n\t\t\t{ x: rect.left + rect.width / 2, y: rect.top + rect.height / 2 },\n\t\t\t{ x: rect.left + margin, y: rect.top + margin }, // top left\n\t\t\t// { x: rect.right - margin, y: rect.top + margin }, // top right\n\t\t\t// { x: rect.left + margin, y: rect.bottom - margin }, // bottom left\n\t\t\t{ x: rect.right - margin, y: rect.bottom - margin }, // bottom right\n\t\t]\n\n\t\treturn checkPoints.some(({ x, y }) => {\n\t\t\ttry {\n\t\t\t\tconst topEl = document.elementFromPoint(x, y)\n\t\t\t\tif (!topEl) return false\n\n\t\t\t\tlet current = topEl\n\t\t\t\twhile (current && current !== document.documentElement) {\n\t\t\t\t\tif (current === element) return true\n\t\t\t\t\tcurrent = current.parentElement\n\t\t\t\t}\n\t\t\t\treturn false\n\t\t\t} catch (e) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t})\n\t}\n\n\t/**\n\t * Checks if an element is within the expanded viewport.\n\t *\n\t * @param {HTMLElement} element - The element to check.\n\t * @param {number} viewportExpansion - The viewport expansion.\n\t * @returns {boolean} Whether the element is within the expanded viewport.\n\t */\n\tfunction isInExpandedViewport(element, viewportExpansion) {\n\t\tif (viewportExpansion === -1) {\n\t\t\treturn true\n\t\t}\n\n\t\tconst rects = element.getClientRects() // Use getClientRects\n\n\t\tif (!rects || rects.length === 0) {\n\t\t\t// Fallback to getBoundingClientRect if getClientRects is empty,\n\t\t\t// useful for elements like <svg> that might not have client rects but have a bounding box.\n\t\t\tconst boundingRect = getCachedBoundingRect(element)\n\t\t\tif (!boundingRect || boundingRect.width === 0 || boundingRect.height === 0) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn !(\n\t\t\t\tboundingRect.bottom < -viewportExpansion ||\n\t\t\t\tboundingRect.top > window.innerHeight + viewportExpansion ||\n\t\t\t\tboundingRect.right < -viewportExpansion ||\n\t\t\t\tboundingRect.left > window.innerWidth + viewportExpansion\n\t\t\t)\n\t\t}\n\n\t\t// Check if *any* client rect is within the viewport\n\t\tfor (const rect of rects) {\n\t\t\tif (rect.width === 0 || rect.height === 0) continue // Skip empty rects\n\n\t\t\tif (!(\n\t\t\t\trect.bottom < -viewportExpansion ||\n\t\t\t\trect.top > window.innerHeight + viewportExpansion ||\n\t\t\t\trect.right < -viewportExpansion ||\n\t\t\t\trect.left > window.innerWidth + viewportExpansion\n\t\t\t)) {\n\t\t\t\treturn true // Found at least one rect in the viewport\n\t\t\t}\n\t\t}\n\n\t\treturn false // No rects were found in the viewport\n\t}\n\n\t// /**\n\t// * Gets the effective scroll of an element.\n\t// *\n\t// * @param {HTMLElement} element - The element to get the effective scroll for.\n\t// * @returns {Object} The effective scroll of the element.\n\t// */\n\t// function getEffectiveScroll(element) {\n\t// let currentEl = element;\n\t// let scrollX = 0;\n\t// let scrollY = 0;\n\n\t// while (currentEl && currentEl !== document.documentElement) {\n\t// if (currentEl.scrollLeft || currentEl.scrollTop) {\n\t// scrollX += currentEl.scrollLeft;\n\t// scrollY += currentEl.scrollTop;\n\t// }\n\t// currentEl = currentEl.parentElement;\n\t// }\n\n\t// scrollX += window.scrollX;\n\t// scrollY += window.scrollY;\n\n\t// return { scrollX, scrollY };\n\t// }\n\n\t/**\n\t * Checks if an element is an interactive candidate.\n\t *\n\t * @param {HTMLElement} element - The element to check.\n\t * @returns {boolean} Whether the element is an interactive candidate.\n\t */\n\n\t// @edit fix \"aria-*\" attributes check\n\tconst INTERACTIVE_ARIA_ATTRS = [\n\t\t'aria-expanded',\n\t\t'aria-checked',\n\t\t'aria-selected',\n\t\t'aria-pressed',\n\t\t'aria-haspopup',\n\t\t'aria-controls',\n\t\t'aria-owns',\n\t\t'aria-activedescendant',\n\t\t'aria-valuenow',\n\t\t'aria-valuetext',\n\t\t'aria-valuemax',\n\t\t'aria-valuemin',\n\t\t'aria-autocomplete',\n\t]\n\n\tfunction hasInteractiveAria(el) {\n\t\tfor (let i = 0; i < INTERACTIVE_ARIA_ATTRS.length; i++) {\n\t\t\tif (el.hasAttribute(INTERACTIVE_ARIA_ATTRS[i])) return true\n\t\t}\n\t\treturn false\n\t}\n\n\tfunction isInteractiveCandidate(element) {\n\t\tif (!element || element.nodeType !== Node.ELEMENT_NODE) return false\n\n\t\tconst tagName = element.tagName.toLowerCase()\n\n\t\t// Fast-path for common interactive elements\n\t\tconst interactiveElements = new Set([\n\t\t\t'a',\n\t\t\t'button',\n\t\t\t'input',\n\t\t\t'select',\n\t\t\t'textarea',\n\t\t\t'details',\n\t\t\t'summary',\n\t\t\t'label',\n\t\t])\n\n\t\tif (interactiveElements.has(tagName)) return true\n\n\t\t// Quick attribute checks without getting full lists\n\t\tconst hasQuickInteractiveAttr =\n\t\t\telement.hasAttribute('onclick') ||\n\t\t\telement.hasAttribute('role') ||\n\t\t\telement.hasAttribute('tabindex') ||\n\t\t\thasInteractiveAria(element) ||\n\t\t\telement.hasAttribute('data-action') ||\n\t\t\telement.getAttribute('contenteditable') === 'true'\n\n\t\treturn hasQuickInteractiveAttr\n\t}\n\n\t// --- Define constants for distinct interaction check ---\n\tconst DISTINCT_INTERACTIVE_TAGS = new Set([\n\t\t'a',\n\t\t'button',\n\t\t'input',\n\t\t'select',\n\t\t'textarea',\n\t\t'summary',\n\t\t'details',\n\t\t'label',\n\t\t'option',\n\t\t'li',\n\t])\n\tconst DISTINCT_INTERACTIVE_ROLES = new Set([\n\t\t'button',\n\t\t'link',\n\t\t'menuitem',\n\t\t'menuitemradio',\n\t\t'menuitemcheckbox',\n\t\t'radio',\n\t\t'checkbox',\n\t\t'tab',\n\t\t'switch',\n\t\t'slider',\n\t\t'spinbutton',\n\t\t'combobox',\n\t\t'searchbox',\n\t\t'textbox',\n\t\t'listbox',\n\t\t'listitem',\n\t\t'treeitem',\n\t\t'row',\n\t\t'option',\n\t\t'scrollbar',\n\t])\n\n\t/**\n\t * Heuristically determines if an element should be considered as independently interactive,\n\t * even if it's nested inside another interactive container.\n\t *\n\t * This function helps detect deeply nested actionable elements (e.g., menu items within a button)\n\t * that may not be picked up by strict interactivity checks.\n\t *\n\t * @param {HTMLElement} element - The element to check.\n\t * @returns {boolean} Whether the element is heuristically interactive.\n\t */\n\tfunction isHeuristicallyInteractive(element) {\n\t\tif (!element || element.nodeType !== Node.ELEMENT_NODE) return false\n\n\t\t// Skip non-visible elements early for performance\n\t\tif (!isElementVisible(element)) return false\n\n\t\t// Check for common attributes that often indicate interactivity\n\t\tconst hasInteractiveAttributes =\n\t\t\telement.hasAttribute('role') ||\n\t\t\telement.hasAttribute('tabindex') ||\n\t\t\telement.hasAttribute('onclick') ||\n\t\t\ttypeof element.onclick === 'function'\n\n\t\t// Check for semantic class names suggesting interactivity\n\t\tconst hasInteractiveClass = /\\b(btn|clickable|menu|item|entry|link)\\b/i.test(\n\t\t\telement.className || ''\n\t\t)\n\n\t\t// Determine whether the element is inside a known interactive container\n\t\tconst isInKnownContainer = Boolean(\n\t\t\telement.closest('button,a,[role=\"button\"],.menu,.dropdown,.list,.toolbar')\n\t\t)\n\n\t\t// Ensure the element has at least one visible child (to avoid marking empty wrappers)\n\t\tconst hasVisibleChildren = [...element.children].some(isElementVisible)\n\n\t\t// Avoid highlighting elements whose parent is <body> (top-level wrappers)\n\t\tconst isParentBody = element.parentElement && element.parentElement.isSameNode(document.body)\n\n\t\treturn (\n\t\t\t(isInteractiveElement(element) || hasInteractiveAttributes || hasInteractiveClass) &&\n\t\t\thasVisibleChildren &&\n\t\t\tisInKnownContainer &&\n\t\t\t!isParentBody\n\t\t)\n\t}\n\n\t/**\n\t * Checks if an element likely represents a distinct interaction\n\t * separate from its parent (if the parent is also interactive).\n\t *\n\t * @param {HTMLElement} element - The element to check.\n\t * @returns {boolean} Whether the element is a distinct interaction.\n\t */\n\tfunction isElementDistinctInteraction(element) {\n\t\tif (!element || element.nodeType !== Node.ELEMENT_NODE) {\n\t\t\treturn false\n\t\t}\n\n\t\tconst tagName = element.tagName.toLowerCase()\n\t\tconst role = element.getAttribute('role')\n\n\t\t// Check if it's an iframe - always distinct boundary\n\t\tif (tagName === 'iframe') {\n\t\t\treturn true\n\t\t}\n\n\t\t// Check tag name\n\t\tif (DISTINCT_INTERACTIVE_TAGS.has(tagName)) {\n\t\t\treturn true\n\t\t}\n\t\t// Check interactive roles\n\t\tif (role && DISTINCT_INTERACTIVE_ROLES.has(role)) {\n\t\t\treturn true\n\t\t}\n\t\t// Check contenteditable\n\t\tif (element.isContentEditable || element.getAttribute('contenteditable') === 'true') {\n\t\t\treturn true\n\t\t}\n\t\t// Check for common testing/automation attributes\n\t\tif (\n\t\t\telement.hasAttribute('data-testid') ||\n\t\t\telement.hasAttribute('data-cy') ||\n\t\t\telement.hasAttribute('data-test')\n\t\t) {\n\t\t\treturn true\n\t\t}\n\t\t// Check for explicit onclick handler (attribute or property)\n\t\tif (element.hasAttribute('onclick') || typeof element.onclick === 'function') {\n\t\t\treturn true\n\t\t}\n\t\t// ARIA state attributes imply the element manages its own interaction state\n\t\tif (hasInteractiveAria(element)) {\n\t\t\treturn true\n\t\t}\n\n\t\t// return false\n\n\t\t// Check for other common interaction event listeners\n\t\ttry {\n\t\t\tconst getEventListenersForNode =\n\t\t\t\telement?.ownerDocument?.defaultView?.getEventListenersForNode ||\n\t\t\t\twindow.getEventListenersForNode\n\t\t\tif (typeof getEventListenersForNode === 'function') {\n\t\t\t\tconst listeners = getEventListenersForNode(element)\n\t\t\t\tconst interactionEvents = [\n\t\t\t\t\t'click',\n\t\t\t\t\t'mousedown',\n\t\t\t\t\t'mouseup',\n\t\t\t\t\t'keydown',\n\t\t\t\t\t'keyup',\n\t\t\t\t\t'submit',\n\t\t\t\t\t'change',\n\t\t\t\t\t'input',\n\t\t\t\t\t'focus',\n\t\t\t\t\t'blur',\n\t\t\t\t]\n\t\t\t\tfor (const eventType of interactionEvents) {\n\t\t\t\t\tfor (const listener of listeners) {\n\t\t\t\t\t\tif (listener.type === eventType) {\n\t\t\t\t\t\t\treturn true // Found a common interaction listener\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Fallback: Check common event attributes if getEventListeners is not available (getEventListenersForNode doesn't work in page.evaluate context)\n\t\t\tconst commonEventAttrs = [\n\t\t\t\t'onmousedown',\n\t\t\t\t'onmouseup',\n\t\t\t\t'onkeydown',\n\t\t\t\t'onkeyup',\n\t\t\t\t'onsubmit',\n\t\t\t\t'onchange',\n\t\t\t\t'oninput',\n\t\t\t\t'onfocus',\n\t\t\t\t'onblur',\n\t\t\t]\n\t\t\tif (commonEventAttrs.some((attr) => element.hasAttribute(attr))) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t} catch (e) {\n\t\t\t// console.warn(`Could not check event listeners for ${element.tagName}:`, e);\n\t\t\t// If checking listeners fails, rely on other checks\n\t\t}\n\n\t\t// if the element is not strictly interactive but appears clickable based on heuristic signals\n\t\tif (isHeuristicallyInteractive(element)) {\n\t\t\treturn true\n\t\t}\n\n\t\t// Scrollable containers are always distinct — the LLM needs their index for targeted scrolling.\n\t\t// Check extraData (already set by isScrollableElement in isInteractiveElement) to avoid redundant layout reads.\n\t\tif (extraData.get(element)?.scrollable) {\n\t\t\treturn true\n\t\t}\n\n\t\t// Default to false: if it's interactive but doesn't match above,\n\t\t// assume it triggers the same action as the parent.\n\t\treturn false\n\t}\n\t// --- End distinct interaction check ---\n\n\t/**\n * Handles the logic for deciding whether to highlight an element and performing the highlight.\n * @param {\n {\n tagName: string;\n attributes: Record<string, string>;\n xpath: any;\n children: never[];\n isVisible?: boolean;\n isTopElement?: boolean;\n isInteractive?: boolean;\n isInViewport?: boolean;\n highlightIndex?: number;\n shadowRoot?: boolean;\n }} nodeData - The node data object.\n * @param {HTMLElement} node - The node to highlight.\n * @param {HTMLElement | null} parentIframe - The parent iframe node.\n * @param {boolean} isParentHighlighted - Whether the parent node is highlighted.\n * @returns {boolean} Whether the element was highlighted.\n */\n\tfunction handleHighlighting(nodeData, node, parentIframe, isParentHighlighted) {\n\t\tif (!nodeData.isInteractive) return false // Not interactive, definitely don't highlight\n\n\t\tlet shouldHighlight = false\n\t\tif (!isParentHighlighted) {\n\t\t\t// Parent wasn't highlighted, this interactive node can be highlighted.\n\t\t\tshouldHighlight = true\n\t\t} else {\n\t\t\t// Parent *was* highlighted. Only highlight this node if it represents a distinct interaction.\n\t\t\tif (isElementDistinctInteraction(node)) {\n\t\t\t\tshouldHighlight = true\n\t\t\t} else {\n\t\t\t\t// console.log(`Skipping highlight for ${nodeData.tagName} (parent highlighted)`);\n\t\t\t\tshouldHighlight = false\n\t\t\t}\n\t\t}\n\n\t\tif (shouldHighlight) {\n\t\t\t// Check viewport status before assigning index and highlighting\n\t\t\tnodeData.isInViewport = isInExpandedViewport(node, viewportExpansion)\n\n\t\t\t// When viewportExpansion is -1, all interactive elements should get a highlight index\n\t\t\t// regardless of viewport status\n\t\t\tif (nodeData.isInViewport || viewportExpansion === -1) {\n\t\t\t\tnodeData.highlightIndex = highlightIndex++\n\n\t\t\t\tif (doHighlightElements) {\n\t\t\t\t\tif (focusHighlightIndex >= 0) {\n\t\t\t\t\t\tif (focusHighlightIndex === nodeData.highlightIndex) {\n\t\t\t\t\t\t\thighlightElement(node, nodeData.highlightIndex, parentIframe)\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\thighlightElement(node, nodeData.highlightIndex, parentIframe)\n\t\t\t\t\t}\n\t\t\t\t\treturn true // Successfully highlighted\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// console.log(`Skipping highlight for ${nodeData.tagName} (outside viewport)`);\n\t\t\t}\n\t\t}\n\n\t\treturn false // Did not highlight\n\t}\n\n\t/**\n\t * Creates a node data object for a given node and its descendants.\n\t *\n\t * @param {HTMLElement} node - The node to process.\n\t * @param {HTMLElement | null} parentIframe - The parent iframe node.\n\t * @param {boolean} isParentHighlighted - Whether the parent node is highlighted.\n\t * @returns {string | null} The ID of the node data object, or null if the node is not processed.\n\t */\n\tfunction buildDomTree(node, parentIframe = null, isParentHighlighted = false) {\n\t\t// Fast rejection checks first\n\t\tif (\n\t\t\t!node ||\n\t\t\tnode.id === HIGHLIGHT_CONTAINER_ID ||\n\t\t\t(node.nodeType !== Node.ELEMENT_NODE && node.nodeType !== Node.TEXT_NODE)\n\t\t) {\n\t\t\treturn null\n\t\t}\n\n\t\tif (!node || node.id === HIGHLIGHT_CONTAINER_ID) {\n\t\t\treturn null\n\t\t}\n\n\t\t/**\n\t\t * @edit add `data-browser-use-ignore` attribute\n\t\t */\n\t\tif (node.dataset?.browserUseIgnore === 'true' || node.dataset?.pageAgentIgnore === 'true') {\n\t\t\treturn null // Skip this node and its children\n\t\t}\n\n\t\t/**\n\t\t * @edit exclude aria-hidden elements\n\t\t */\n\t\tif (node.getAttribute && node.getAttribute('aria-hidden') === 'true') {\n\t\t\treturn null // Skip this node and its children\n\t\t}\n\n\t\t// Special handling for root node (body)\n\t\tif (node === document.body) {\n\t\t\tconst nodeData = {\n\t\t\t\ttagName: 'body',\n\t\t\t\tattributes: {},\n\t\t\t\txpath: '/body',\n\t\t\t\tchildren: [],\n\t\t\t}\n\n\t\t\t// Process children of body\n\t\t\tfor (const child of node.childNodes) {\n\t\t\t\tconst domElement = buildDomTree(child, parentIframe, false) // Body's children have no highlighted parent initially\n\t\t\t\tif (domElement) nodeData.children.push(domElement)\n\t\t\t}\n\n\t\t\tconst id = `${ID.current++}`\n\t\t\tDOM_HASH_MAP[id] = nodeData\n\t\t\treturn id\n\t\t}\n\n\t\t// Early bailout for non-element nodes except text\n\t\tif (node.nodeType !== Node.ELEMENT_NODE && node.nodeType !== Node.TEXT_NODE) {\n\t\t\treturn null\n\t\t}\n\n\t\t// Process text nodes\n\t\tif (node.nodeType === Node.TEXT_NODE) {\n\t\t\tconst textContent = node.textContent?.trim()\n\t\t\tif (!textContent) {\n\t\t\t\treturn null\n\t\t\t}\n\n\t\t\t// Only check visibility for text nodes that might be visible\n\t\t\tconst parentElement = node.parentElement\n\t\t\tif (!parentElement || parentElement.tagName.toLowerCase() === 'script') {\n\t\t\t\treturn null\n\t\t\t}\n\n\t\t\tconst id = `${ID.current++}`\n\t\t\tDOM_HASH_MAP[id] = {\n\t\t\t\ttype: 'TEXT_NODE',\n\t\t\t\ttext: textContent,\n\t\t\t\tisVisible: isTextNodeVisible(node),\n\t\t\t}\n\t\t\treturn id\n\t\t}\n\n\t\t// Quick checks for element nodes\n\t\tif (node.nodeType === Node.ELEMENT_NODE && !isElementAccepted(node)) {\n\t\t\treturn null\n\t\t}\n\n\t\t// Early viewport check - only filter out elements clearly outside viewport\n\t\t// The getBoundingClientRect() of the Shadow DOM host element may return width/height = 0\n\t\tif (viewportExpansion !== -1 && !node.shadowRoot) {\n\t\t\tconst rect = getCachedBoundingRect(node) // Keep for initial quick check\n\t\t\tconst style = getCachedComputedStyle(node)\n\n\t\t\t// Skip viewport check for fixed/sticky elements as they may appear anywhere\n\t\t\tconst isFixedOrSticky = style && (style.position === 'fixed' || style.position === 'sticky')\n\n\t\t\t// Check if element has actual dimensions using offsetWidth/Height (quick check)\n\t\t\tconst hasSize = node.offsetWidth > 0 || node.offsetHeight > 0\n\n\t\t\t// Use getBoundingClientRect for the quick OUTSIDE check.\n\t\t\t// isInExpandedViewport will do the more accurate check later if needed.\n\t\t\tif (\n\t\t\t\t!rect ||\n\t\t\t\t(!isFixedOrSticky &&\n\t\t\t\t\t!hasSize &&\n\t\t\t\t\t(rect.bottom < -viewportExpansion ||\n\t\t\t\t\t\trect.top > window.innerHeight + viewportExpansion ||\n\t\t\t\t\t\trect.right < -viewportExpansion ||\n\t\t\t\t\t\trect.left > window.innerWidth + viewportExpansion))\n\t\t\t) {\n\t\t\t\t// console.log(\"Skipping node outside viewport (quick check):\", node.tagName, rect);\n\t\t\t\treturn null\n\t\t\t}\n\t\t}\n\n\t\t/**\n * @type {\n {\n tagName: string;\n attributes: Record<string, string | null>;\n xpath: any;\n children: never[];\n isVisible?: boolean;\n isTopElement?: boolean;\n isInteractive?: boolean;\n isInViewport?: boolean;\n highlightIndex?: number;\n shadowRoot?: boolean;\n }\n } nodeData - The node data object.\n */\n\t\tconst nodeData = {\n\t\t\ttagName: node.tagName.toLowerCase(),\n\t\t\tattributes: {},\n\n\t\t\t/**\n\t\t\t * @edit no need for xpath\n\t\t\t */\n\t\t\t// xpath: getXPathTree(node, true),\n\n\t\t\tchildren: [],\n\t\t}\n\n\t\t// Get attributes for interactive elements or potential text containers\n\t\tif (\n\t\t\tisInteractiveCandidate(node) ||\n\t\t\tnode.tagName.toLowerCase() === 'iframe' ||\n\t\t\tnode.tagName.toLowerCase() === 'body'\n\t\t) {\n\t\t\tconst attributeNames = node.getAttributeNames?.() || []\n\t\t\tfor (const name of attributeNames) {\n\t\t\t\tconst value = node.getAttribute(name)\n\t\t\t\tnodeData.attributes[name] = value\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * @edit @workaround input.checked\n\t\t\t */\n\t\t\tif (\n\t\t\t\tnode.tagName.toLowerCase() === 'input' &&\n\t\t\t\t(node.type === 'checkbox' || node.type === 'radio')\n\t\t\t) {\n\t\t\t\tnodeData.attributes.checked = node.checked ? 'true' : 'false' // Store as string for consistency\n\t\t\t}\n\t\t}\n\n\t\tlet nodeWasHighlighted = false\n\t\t// Perform visibility, interactivity, and highlighting checks\n\t\tif (node.nodeType === Node.ELEMENT_NODE) {\n\t\t\tnodeData.isVisible = isElementVisible(node) // isElementVisible uses offsetWidth/Height, which is fine\n\t\t\tif (nodeData.isVisible) {\n\t\t\t\tnodeData.isTopElement = isTopElement(node)\n\n\t\t\t\t// Special handling for ARIA menu containers - check interactivity even if not top element\n\t\t\t\tconst role = node.getAttribute('role')\n\t\t\t\tconst isMenuContainer = role === 'menu' || role === 'menubar' || role === 'listbox'\n\n\t\t\t\tif (nodeData.isTopElement || isMenuContainer) {\n\t\t\t\t\tnodeData.isInteractive = isInteractiveElement(node)\n\t\t\t\t\t// Call the dedicated highlighting function\n\t\t\t\t\tnodeWasHighlighted = handleHighlighting(nodeData, node, parentIframe, isParentHighlighted)\n\n\t\t\t\t\t/**\n\t\t\t\t\t * @edit direct dom ref\n\t\t\t\t\t */\n\t\t\t\t\tnodeData.ref = node\n\n\t\t\t\t\t/**\n\t\t\t\t\t * @edit make sure attributes exist for interactive candidates.\n\t\t\t\t\t * @note if the element failed the isInteractiveCandidate, attributes would be empty.\n\t\t\t\t\t */\n\t\t\t\t\tif (nodeData.isInteractive && Object.keys(nodeData.attributes).length === 0) {\n\t\t\t\t\t\tconst attributeNames = node.getAttributeNames?.() || []\n\t\t\t\t\t\tfor (const name of attributeNames) {\n\t\t\t\t\t\t\tconst value = node.getAttribute(name)\n\t\t\t\t\t\t\tnodeData.attributes[name] = value\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Process children, with special handling for iframes and rich text editors\n\t\tif (node.tagName) {\n\t\t\tconst tagName = node.tagName.toLowerCase()\n\n\t\t\t// Handle iframes\n\t\t\tif (tagName === 'iframe') {\n\t\t\t\ttry {\n\t\t\t\t\tconst iframeDoc = node.contentDocument || node.contentWindow?.document\n\t\t\t\t\tif (iframeDoc) {\n\t\t\t\t\t\tfor (const child of iframeDoc.childNodes) {\n\t\t\t\t\t\t\tconst domElement = buildDomTree(child, node, false)\n\t\t\t\t\t\t\tif (domElement) nodeData.children.push(domElement)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch (e) {\n\t\t\t\t\tconsole.warn('Unable to access iframe:', e)\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Handle rich text editors and contenteditable elements\n\t\t\telse if (\n\t\t\t\tnode.isContentEditable ||\n\t\t\t\tnode.getAttribute('contenteditable') === 'true' ||\n\t\t\t\tnode.id === 'tinymce' ||\n\t\t\t\tnode.classList.contains('mce-content-body') ||\n\t\t\t\t(tagName === 'body' && node.getAttribute('data-id')?.startsWith('mce_'))\n\t\t\t) {\n\t\t\t\t// Process all child nodes to capture formatted text\n\t\t\t\tfor (const child of node.childNodes) {\n\t\t\t\t\tconst domElement = buildDomTree(child, parentIframe, nodeWasHighlighted)\n\t\t\t\t\tif (domElement) nodeData.children.push(domElement)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Handle shadow DOM\n\t\t\t\tif (node.shadowRoot) {\n\t\t\t\t\tnodeData.shadowRoot = true\n\t\t\t\t\tfor (const child of node.shadowRoot.childNodes) {\n\t\t\t\t\t\tconst domElement = buildDomTree(child, parentIframe, nodeWasHighlighted)\n\t\t\t\t\t\tif (domElement) nodeData.children.push(domElement)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Handle regular elements\n\t\t\t\tfor (const child of node.childNodes) {\n\t\t\t\t\t// Pass the highlighted status of the *current* node to its children\n\t\t\t\t\tconst passHighlightStatusToChild = nodeWasHighlighted || isParentHighlighted\n\t\t\t\t\tconst domElement = buildDomTree(child, parentIframe, passHighlightStatusToChild)\n\t\t\t\t\tif (domElement) nodeData.children.push(domElement)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Skip empty anchor tags only if they have no dimensions and no children\n\t\tif (nodeData.tagName === 'a' && nodeData.children.length === 0 && !nodeData.attributes.href) {\n\t\t\t// Check if the anchor has actual dimensions\n\t\t\tconst rect = getCachedBoundingRect(node)\n\t\t\tconst hasSize =\n\t\t\t\t(rect && rect.width > 0 && rect.height > 0) || node.offsetWidth > 0 || node.offsetHeight > 0\n\n\t\t\tif (!hasSize) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * @edit add `extra` field for extra data\n\t\t */\n\t\tnodeData.extra = extraData.get(node) || null\n\n\t\tconst id = `${ID.current++}`\n\t\tDOM_HASH_MAP[id] = nodeData\n\t\treturn id\n\t}\n\n\tconst rootId = buildDomTree(document.body)\n\n\t// Clear the cache before starting\n\tDOM_CACHE.clearCache()\n\n\treturn { rootId, map: DOM_HASH_MAP }\n}\n","import domTree from './dom_tree/index.js'\nimport {\n\tElementDomNode,\n\tFlatDomTree,\n\tInteractiveElementDomNode,\n\tTextDomNode,\n} from './dom_tree/type'\n\n/**\n * Structured browser state for LLM consumption\n */\nexport interface BrowserState {\n\turl: string\n\ttitle: string\n\t/** Page info + scroll position hint (e.g. \"Page info: 1920x1080px...\\n[Start of page]\") */\n\theader: string\n\t/** Simplified HTML of interactive elements */\n\tcontent: string\n\t/** Page footer hint (e.g. \"... 300 pixels below ...\" or \"[End of page]\") */\n\tfooter: string\n}\n\n/**\n * Viewport expansion for DOM tree extraction.\n * -1 means full page (no viewport restriction)\n * 0 means viewport only\n * positive values expand the viewport by that many pixels\n *\n * @note Since isTopElement depends on elementFromPoint,\n * it returns null when out of viewport, this feature has no practical use, only differ between -1 and 0\n */\nconst DEFAULT_VIEWPORT_EXPANSION = -1\n\nexport function resolveViewportExpansion(viewportExpansion?: number): number {\n\treturn viewportExpansion ?? DEFAULT_VIEWPORT_EXPANSION\n}\n\nexport interface DomConfig {\n\tviewportExpansion?: number\n\tinteractiveBlacklist?: (Element | (() => Element))[]\n\tinteractiveWhitelist?: (Element | (() => Element))[]\n\tincludeAttributes?: string[]\n\thighlightOpacity?: number\n\thighlightLabelOpacity?: number\n\n\t/**\n\t * Preserve semantic landmark tags in dehydrated output even if not interactive\n\t * @note maybe confusing for LLM combining with page scrolling, use with caution\n\t **/\n\tkeepSemanticTags?: boolean\n}\n\n// TODO: corresponding roles\nconst SEMANTIC_TAGS = new Set([\n\t'nav',\n\t'menu',\n\t// 'main',\n\t'header',\n\t'footer',\n\t'aside',\n\t// 'article',\n\t// 'form',\n\t'dialog',\n])\n\n/**\n * 用于检测可交互元素是否是新出现的。\n */\nconst newElementsCache = new WeakMap<HTMLElement, string>()\n\nexport function getFlatTree(config: DomConfig): FlatDomTree {\n\tconst viewportExpansion = resolveViewportExpansion(config.viewportExpansion)\n\n\tconst interactiveBlacklist = [] as Element[]\n\tfor (const item of config.interactiveBlacklist || []) {\n\t\tif (typeof item === 'function') {\n\t\t\tinteractiveBlacklist.push(item())\n\t\t} else {\n\t\t\tinteractiveBlacklist.push(item)\n\t\t}\n\t}\n\n\tconst interactiveWhitelist = [] as Element[]\n\tfor (const item of config.interactiveWhitelist || []) {\n\t\tif (typeof item === 'function') {\n\t\t\tinteractiveWhitelist.push(item())\n\t\t} else {\n\t\t\tinteractiveWhitelist.push(item)\n\t\t}\n\t}\n\n\tconst elements = domTree({\n\t\tdoHighlightElements: true,\n\t\tdebugMode: true,\n\t\tfocusHighlightIndex: -1,\n\t\tviewportExpansion,\n\t\tinteractiveBlacklist,\n\t\tinteractiveWhitelist,\n\t\thighlightOpacity: config.highlightOpacity ?? 0.0,\n\t\thighlightLabelOpacity: config.highlightLabelOpacity ?? 0.1,\n\t}) as FlatDomTree\n\n\tconst currentUrl = window.location.href\n\n\t/**\n\t * 标记新出现的元素\n\t * @todo browser-use 使用 hash(位置,属性等信息) 来判断是否同一个元素,\n\t * 能够解决 1. 元素被删除后重新添加 2. 页面卸载 等问题。\n\t * 这里先简单做.\n\t */\n\tfor (const nodeId in elements.map) {\n\t\tconst node = elements.map[nodeId]\n\t\tif (node.isInteractive && node.ref) {\n\t\t\tconst ref = node.ref as HTMLElement\n\t\t\t// @note 这样太严格,元素是可以跨页面存在的\n\t\t\t// if (newElementsCache.get(ref) !== currentUrl) {\n\t\t\tif (!newElementsCache.has(ref)) {\n\t\t\t\tnewElementsCache.set(ref, currentUrl)\n\t\t\t\tnode.isNew = true\n\t\t\t}\n\t\t}\n\t}\n\n\treturn elements\n}\n\nconst globRegexCache = new Map<string, RegExp>()\n\nfunction globToRegex(pattern: string): RegExp {\n\tlet regex = globRegexCache.get(pattern)\n\tif (!regex) {\n\t\tconst escaped = pattern.replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&')\n\t\tregex = new RegExp(`^${escaped.replace(/\\*/g, '.*')}$`)\n\t\tglobRegexCache.set(pattern, regex)\n\t}\n\treturn regex\n}\n\nfunction matchAttributes(\n\tattrs: Record<string, string>,\n\tpatterns: string[]\n): Record<string, string> {\n\tconst result: Record<string, string> = {}\n\n\tfor (const pattern of patterns) {\n\t\tif (pattern.includes('*')) {\n\t\t\tconst regex = globToRegex(pattern)\n\t\t\tfor (const key of Object.keys(attrs)) {\n\t\t\t\tif (regex.test(key) && attrs[key].trim()) {\n\t\t\t\t\tresult[key] = attrs[key].trim()\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tconst value = attrs[pattern]\n\t\t\tif (value && value.trim()) {\n\t\t\t\tresult[pattern] = value.trim()\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result\n}\n\n/**\n * elementsToString 内部使用的类型\n */\ninterface TreeNode {\n\ttype: 'text' | 'element'\n\tparent: TreeNode | null\n\tchildren: TreeNode[]\n\tisVisible: boolean\n\t// Text node properties\n\ttext?: string\n\t// Element node properties\n\ttagName?: string\n\tattributes?: Record<string, string>\n\tisInteractive?: boolean\n\tisTopElement?: boolean\n\tisNew?: boolean\n\thighlightIndex?: number\n\textra?: Record<string, any>\n}\n\n/**\n * 对应 python 中的 views::clickable_elements_to_string,\n * 将 dom 信息处理成适合 llm 阅读的文本格式\n * @形如\n * ``` text\n * [0]<a aria-label=page-agent.js 首页 />\n * [1]<div >P />\n * [2]<div >page-agent.js\n * UI Agent in your webpage />\n * [3]<a >文档 />\n * [4]<a aria-label=查看源码(在新窗口打开)>源码 />\n * UI Agent in your webpage\n * 用户输入需求,AI 理解页面并自动操作。\n * [5]<a role=button>快速开始 />\n * [6]<a role=button>查看文档 />\n * 无需后端\n * ```\n * 其中可交互元素用序号标出,提示llm可以用序号操作。\n * 缩进代表父子关系。\n * 普通文本则直接列出来。\n *\n * @todo 数据脱敏过滤器\n */\nexport function flatTreeToString(\n\tflatTree: FlatDomTree,\n\tincludeAttributes: string[] = [],\n\tkeepSemanticTags = false\n): string {\n\tconst DEFAULT_INCLUDE_ATTRIBUTES = [\n\t\t'title',\n\t\t'type',\n\t\t'checked',\n\t\t'name',\n\t\t'role',\n\t\t'value',\n\t\t'placeholder',\n\t\t'data-date-format',\n\t\t'alt',\n\t\t'aria-label',\n\t\t'aria-expanded',\n\t\t'data-state',\n\t\t'aria-checked',\n\n\t\t// @edit added for better form handling\n\t\t'id',\n\t\t'for',\n\n\t\t// for jump check\n\t\t'target',\n\n\t\t// absolute position dropdown menu\n\t\t'aria-haspopup',\n\t\t'aria-controls',\n\t\t'aria-owns',\n\n\t\t// content editable\n\t\t'contenteditable',\n\t]\n\n\tconst includeAttrs = [...includeAttributes, ...DEFAULT_INCLUDE_ATTRIBUTES]\n\n\t// Helper function to cap text length\n\tconst capTextLength = (text: string, maxLength: number): string => {\n\t\tif (text.length > maxLength) {\n\t\t\treturn text.substring(0, maxLength) + '...'\n\t\t}\n\t\treturn text\n\t}\n\n\t// Build tree structure from flat map\n\tconst buildTreeNode = (nodeId: string): TreeNode | null => {\n\t\tconst node = flatTree.map[nodeId]\n\t\tif (!node) return null\n\n\t\tif (node.type === 'TEXT_NODE') {\n\t\t\tconst textNode = node as TextDomNode\n\t\t\treturn {\n\t\t\t\ttype: 'text',\n\t\t\t\ttext: textNode.text,\n\t\t\t\tisVisible: textNode.isVisible,\n\t\t\t\tparent: null,\n\t\t\t\tchildren: [],\n\t\t\t}\n\t\t} else {\n\t\t\tconst elementNode = node as ElementDomNode\n\t\t\tconst children: TreeNode[] = []\n\n\t\t\tif (elementNode.children) {\n\t\t\t\tfor (const childId of elementNode.children) {\n\t\t\t\t\tconst child = buildTreeNode(childId)\n\t\t\t\t\tif (child) {\n\t\t\t\t\t\tchild.parent = null // Will be set later\n\t\t\t\t\t\tchildren.push(child)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\ttype: 'element',\n\t\t\t\ttagName: elementNode.tagName,\n\t\t\t\tattributes: elementNode.attributes ?? {},\n\t\t\t\tisVisible: elementNode.isVisible ?? false,\n\t\t\t\tisInteractive: elementNode.isInteractive ?? false,\n\t\t\t\tisTopElement: elementNode.isTopElement ?? false,\n\t\t\t\tisNew: elementNode.isNew ?? false,\n\t\t\t\thighlightIndex: elementNode.highlightIndex,\n\t\t\t\tparent: null,\n\t\t\t\tchildren,\n\t\t\t\textra: elementNode.extra ?? {},\n\t\t\t}\n\t\t}\n\t}\n\n\t// Set parent references\n\tconst setParentReferences = (node: TreeNode, parent: TreeNode | null = null) => {\n\t\tnode.parent = parent\n\t\tfor (const child of node.children) {\n\t\t\tsetParentReferences(child, node)\n\t\t}\n\t}\n\n\t// Build root node\n\tconst rootNode = buildTreeNode(flatTree.rootId)\n\tif (!rootNode) return ''\n\n\tsetParentReferences(rootNode)\n\n\t// Helper to check if text node has parent with highlight index\n\tconst hasParentWithHighlightIndex = (node: TreeNode): boolean => {\n\t\tlet current = node.parent\n\t\twhile (current) {\n\t\t\tif (current.type === 'element' && current.highlightIndex !== undefined) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tcurrent = current.parent\n\t\t}\n\t\treturn false\n\t}\n\n\t// Helper to check if parent is top element\n\t// const isParentTopElement = (node: TreeNode): boolean => {\n\t// \treturn node.parent?.type === 'element' && node.parent.isTopElement === true\n\t// }\n\n\t// Main processing function\n\tconst processNode = (node: TreeNode, depth: number, result: string[]): void => {\n\t\tlet nextDepth = depth\n\t\tconst depthStr = '\\t'.repeat(depth)\n\n\t\tif (node.type === 'element') {\n\t\t\tconst isSemantic = keepSemanticTags && node.tagName && SEMANTIC_TAGS.has(node.tagName)\n\n\t\t\t// Add element with highlight_index\n\t\t\tif (node.highlightIndex !== undefined) {\n\t\t\t\tnextDepth += 1\n\n\t\t\t\tconst text = getAllTextTillNextClickableElement(node)\n\t\t\t\tlet attributesHtmlStr = ''\n\n\t\t\t\tif (includeAttrs.length > 0 && node.attributes) {\n\t\t\t\t\tconst attributesToInclude = matchAttributes(node.attributes, includeAttrs)\n\n\t\t\t\t\t// Remove duplicate values (for attributes longer than 5 chars)\n\t\t\t\t\tconst keys = Object.keys(attributesToInclude)\n\t\t\t\t\tif (keys.length > 1) {\n\t\t\t\t\t\tconst keysToRemove = new Set<string>()\n\t\t\t\t\t\tconst seenValues: Record<string, string> = {}\n\n\t\t\t\t\t\tfor (const key of keys) {\n\t\t\t\t\t\t\tconst value = attributesToInclude[key]\n\t\t\t\t\t\t\tif (value.length > 5) {\n\t\t\t\t\t\t\t\tif (value in seenValues) {\n\t\t\t\t\t\t\t\t\tkeysToRemove.add(key)\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tseenValues[value] = key\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tfor (const key of keysToRemove) {\n\t\t\t\t\t\t\tdelete attributesToInclude[key]\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Remove role if it matches tagName\n\t\t\t\t\tif (attributesToInclude.role === node.tagName) {\n\t\t\t\t\t\tdelete attributesToInclude.role\n\t\t\t\t\t}\n\n\t\t\t\t\t// Remove attributes that duplicate text content\n\t\t\t\t\tconst attrsToRemoveIfTextMatches = ['aria-label', 'placeholder', 'title']\n\t\t\t\t\tfor (const attr of attrsToRemoveIfTextMatches) {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tattributesToInclude[attr] &&\n\t\t\t\t\t\t\tattributesToInclude[attr].toLowerCase().trim() === text.toLowerCase().trim()\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tdelete attributesToInclude[attr]\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (Object.keys(attributesToInclude).length > 0) {\n\t\t\t\t\t\tattributesHtmlStr = Object.entries(attributesToInclude)\n\t\t\t\t\t\t\t.map(([key, value]) => `${key}=${capTextLength(value, 20)}`)\n\t\t\t\t\t\t\t.join(' ')\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Build the line\n\t\t\t\tconst highlightIndicator = node.isNew\n\t\t\t\t\t? `*[${node.highlightIndex}]`\n\t\t\t\t\t: `[${node.highlightIndex}]`\n\t\t\t\tlet line = `${depthStr}${highlightIndicator}<${node.tagName ?? ''}`\n\n\t\t\t\tif (attributesHtmlStr) {\n\t\t\t\t\tline += ` ${attributesHtmlStr}`\n\t\t\t\t}\n\n\t\t\t\t/**\n\t\t\t\t * @edit scrollable 数据\n\t\t\t\t */\n\t\t\t\tif (node.extra) {\n\t\t\t\t\tif (node.extra.scrollable) {\n\t\t\t\t\t\tlet scrollDataText = ''\n\t\t\t\t\t\tif (node.extra.scrollData?.left)\n\t\t\t\t\t\t\tscrollDataText += `left=${node.extra.scrollData.left}, `\n\t\t\t\t\t\tif (node.extra.scrollData?.top) scrollDataText += `top=${node.extra.scrollData.top}, `\n\t\t\t\t\t\tif (node.extra.scrollData?.right)\n\t\t\t\t\t\t\tscrollDataText += `right=${node.extra.scrollData.right}, `\n\t\t\t\t\t\tif (node.extra.scrollData?.bottom)\n\t\t\t\t\t\t\tscrollDataText += `bottom=${node.extra.scrollData.bottom}`\n\n\t\t\t\t\t\tline += ` data-scrollable=\"${scrollDataText}\"`\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (text) {\n\t\t\t\t\tconst trimmedText = text.trim()\n\t\t\t\t\tif (!attributesHtmlStr) {\n\t\t\t\t\t\tline += ' '\n\t\t\t\t\t}\n\t\t\t\t\tline += `>${trimmedText}`\n\t\t\t\t} else if (!attributesHtmlStr) {\n\t\t\t\t\tline += ' '\n\t\t\t\t}\n\n\t\t\t\tline += ' />'\n\t\t\t\tresult.push(line)\n\t\t\t}\n\n\t\t\t// special treatment for semantic tags\n\t\t\t// even if they are not interactive, we can keep them for clear context\n\n\t\t\tconst emitSemantic = isSemantic && node.highlightIndex === undefined\n\t\t\t// to check if this tag is empty\n\t\t\tconst mark = emitSemantic ? result.length : -1\n\n\t\t\tif (emitSemantic) {\n\t\t\t\tresult.push(`${depthStr}<${node.tagName}>`)\n\t\t\t\tnextDepth += 1\n\t\t\t}\n\n\t\t\tfor (const child of node.children) {\n\t\t\t\tprocessNode(child, nextDepth, result)\n\t\t\t}\n\n\t\t\tif (emitSemantic) {\n\t\t\t\t// empty tag should be removed\n\t\t\t\tif (result.length === mark + 1) {\n\t\t\t\t\tresult.pop()\n\t\t\t\t} else {\n\t\t\t\t\tresult.push(`${depthStr}</${node.tagName}>`)\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (node.type === 'text') {\n\t\t\t// Add text only if it doesn't have a highlighted parent\n\t\t\tif (hasParentWithHighlightIndex(node)) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tnode.parent &&\n\t\t\t\tnode.parent.type === 'element' &&\n\t\t\t\tnode.parent.isVisible &&\n\t\t\t\tnode.parent.isTopElement\n\t\t\t) {\n\t\t\t\tresult.push(`${depthStr}${node.text ?? ''}`)\n\t\t\t}\n\t\t}\n\t}\n\n\tconst result: string[] = []\n\tprocessNode(rootNode, 0, result)\n\treturn result.join('\\n')\n}\n\n// Get all text until next clickable element\nexport const getAllTextTillNextClickableElement = (node: TreeNode, maxDepth = -1): string => {\n\tconst textParts: string[] = []\n\n\tconst collectText = (currentNode: TreeNode, currentDepth: number) => {\n\t\tif (maxDepth !== -1 && currentDepth > maxDepth) {\n\t\t\treturn\n\t\t}\n\n\t\t// Skip this branch if we hit a highlighted element (except for the current node)\n\t\tif (\n\t\t\tcurrentNode.type === 'element' &&\n\t\t\tcurrentNode !== node &&\n\t\t\tcurrentNode.highlightIndex !== undefined\n\t\t) {\n\t\t\treturn\n\t\t}\n\n\t\tif (currentNode.type === 'text' && currentNode.text) {\n\t\t\ttextParts.push(currentNode.text)\n\t\t} else if (currentNode.type === 'element') {\n\t\t\tfor (const child of currentNode.children) {\n\t\t\t\tcollectText(child, currentDepth + 1)\n\t\t\t}\n\t\t}\n\t}\n\n\tcollectText(node, 0)\n\treturn textParts.join('\\n').trim()\n}\n\nexport function getSelectorMap(flatTree: FlatDomTree): Map<number, InteractiveElementDomNode> {\n\tconst selectorMap = new Map<number, InteractiveElementDomNode>()\n\n\tconst keys = Object.keys(flatTree.map)\n\tfor (const key of keys) {\n\t\tconst node = flatTree.map[key]\n\t\tif (node.isInteractive && typeof node.highlightIndex === 'number') {\n\t\t\tselectorMap.set(node.highlightIndex, node as InteractiveElementDomNode)\n\t\t}\n\t}\n\n\treturn selectorMap\n}\n\nexport function getElementTextMap(simplifiedHTML: string) {\n\tconst lines = simplifiedHTML\n\t\t.split('\\n')\n\t\t.map((line) => line.trim())\n\t\t.filter((line) => line.length > 0)\n\tconst elementTextMap = new Map<number, string>()\n\tfor (const line of lines) {\n\t\tconst regex = /^\\[(\\d+)\\]<[^>]+>([^<]*)/\n\t\tconst match = regex.exec(line)\n\t\tif (match) {\n\t\t\tconst index = parseInt(match[1], 10)\n\t\t\telementTextMap.set(index, line)\n\t\t}\n\t}\n\n\treturn elementTextMap\n}\n\nexport function cleanUpHighlights() {\n\tconst cleanupFunctions = (window as any)._highlightCleanupFunctions || []\n\tfor (const cleanup of cleanupFunctions) {\n\t\tif (typeof cleanup === 'function') {\n\t\t\tcleanup()\n\t\t}\n\t}\n\n\t;(window as any)._highlightCleanupFunctions = []\n}\n\n// 监听 URL 的任何变化,立刻清空 highLights\nwindow.addEventListener('popstate', () => {\n\t// console.log('URL changed (popstate), highlights cleaned up.')\n\tcleanUpHighlights()\n})\nwindow.addEventListener('hashchange', () => {\n\t// console.log('URL changed (hashchange), highlights cleaned up.')\n\tcleanUpHighlights()\n})\nwindow.addEventListener('beforeunload', () => {\n\t// console.log('Page is unloading, highlights cleaned up.')\n\tcleanUpHighlights()\n})\n\nconst navigation = (window as any).navigation\nif (navigation && typeof navigation.addEventListener === 'function') {\n\tnavigation.addEventListener('navigate', () => {\n\t\t// console.log('Navigation event detected, highlights cleaned up.')\n\t\tcleanUpHighlights()\n\t})\n} else {\n\t// 定时器\n\tlet currentUrl = window.location.href\n\tsetInterval(() => {\n\t\tif (window.location.href !== currentUrl) {\n\t\t\tcurrentUrl = window.location.href\n\t\t\t// console.log('URL changed (interval), highlights cleaned up.')\n\t\t\tcleanUpHighlights()\n\t\t}\n\t}, 500)\n}\n","export function getPageInfo() {\n\tconst viewport_width = window.innerWidth\n\tconst viewport_height = window.innerHeight\n\n\tconst page_width = Math.max(document.documentElement.scrollWidth, document.body.scrollWidth || 0)\n\tconst page_height = Math.max(\n\t\tdocument.documentElement.scrollHeight,\n\t\tdocument.body.scrollHeight || 0\n\t)\n\n\tconst scroll_x = window.scrollX || window.pageXOffset || document.documentElement.scrollLeft || 0\n\tconst scroll_y = window.scrollY || window.pageYOffset || document.documentElement.scrollTop || 0\n\n\tconst pixels_below = Math.max(0, page_height - (window.innerHeight + scroll_y))\n\tconst pixels_right = Math.max(0, page_width - (window.innerWidth + scroll_x))\n\n\treturn {\n\t\t// Current viewport dimensions\n\t\tviewport_width,\n\t\tviewport_height,\n\n\t\t// Total page dimensions\n\t\tpage_width,\n\t\tpage_height,\n\n\t\t// Current scroll position\n\t\tscroll_x,\n\t\tscroll_y,\n\n\t\tpixels_above: scroll_y,\n\t\tpixels_below,\n\n\t\tpages_above: viewport_height > 0 ? scroll_y / viewport_height : 0,\n\t\tpages_below: viewport_height > 0 ? pixels_below / viewport_height : 0,\n\t\ttotal_pages: viewport_height > 0 ? page_height / viewport_height : 0,\n\n\t\tcurrent_page_position: scroll_y / Math.max(1, page_height - viewport_height),\n\n\t\tpixels_left: scroll_x,\n\t\tpixels_right,\n\t}\n}\n","import type { BrowserController } from '../BrowserController'\n\n// Find common React root elements and add data-page-agent-not-interactive attribute\nexport function patchReact(_browserController: BrowserController) {\n\tconst reactRootElements = document.querySelectorAll(\n\t\t'[data-reactroot], [data-reactid], [data-react-checksum], #root, #app, [id^=\"root-\"], [id^=\"app-\"], #adex-wrapper, #adex-root'\n\t)\n\n\tfor (const element of reactRootElements) {\n\t\telement.setAttribute('data-page-agent-not-interactive', 'true')\n\t}\n}\n\n/**\n * @todo (Heavy, might have false negatives) Interaction detection, if element width/height equals body offsetWidth/Height, consider it root element and non-interactive (React often attaches many events to root elements, causing false positives)\n */\n","/**\n * A comprehensive function to determine if the page is currently in a dark theme.\n * Heuristic check. Only work for common patterns. Return false by default.\n */\nexport function isPageDark() {\n\ttry {\n\t\tif (hasDarkModeClass()) return true\n\t\tif (hasDarkModeDataAttribute()) return true\n\t\tif (isColorSchemeDark()) return true\n\t\tif (isBackgroundDark()) return true\n\t\tif (isMainContentBackgroundDark()) return true\n\t\tif (isTextColorLight()) return true\n\n\t\treturn false\n\t} catch (error) {\n\t\tconsole.warn('Error determining if page is dark:', error)\n\t\treturn false\n\t}\n}\n\n/**\n * Checks for common dark mode CSS classes on the html or body elements.\n */\nfunction hasDarkModeClass() {\n\tconst DEFAULT_DARK_MODE_CLASSES = ['dark', 'dark-mode', 'theme-dark', 'night', 'night-mode']\n\n\tconst htmlElement = document.documentElement\n\tconst bodyElement = document.body || document.documentElement // can be null in some cases\n\n\t// Check class names on <html> and <body>\n\tfor (const className of DEFAULT_DARK_MODE_CLASSES) {\n\t\tif (htmlElement.classList.contains(className) || bodyElement?.classList.contains(className)) {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\n/**\n * Some UI frameworks use data attributes to indicate theme\n */\nfunction hasDarkModeDataAttribute() {\n\tconst htmlElement = document.documentElement\n\tconst bodyElement = document.body || document.documentElement // can be null in some cases\n\n\tconst dataAttrs = ['data-theme', 'data-color-mode', 'data-bs-theme', 'data-mui-color-scheme']\n\tfor (const attr of dataAttrs) {\n\t\tconst bodyValue = bodyElement?.getAttribute(attr)\n\t\tconst htmlValue = htmlElement.getAttribute(attr)\n\n\t\tif (bodyValue?.toLowerCase() === 'dark' || htmlValue?.toLowerCase() === 'dark') {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\n/**\n * Checks the CSS `color-scheme` property and `<meta name=\"color-scheme\">` tag.\n * Only \"dark\"/\"only dark\" counts as dark; \"light dark\" is ambiguous and ignored.\n */\nfunction isColorSchemeDark() {\n\t// Check <meta name=\"color-scheme\" content=\"dark\">\n\tconst meta = document.querySelector<HTMLMetaElement>('meta[name=\"color-scheme\"]')\n\tconst metaContent = meta?.content.toLowerCase()\n\tif (metaContent === 'dark' || metaContent === 'only dark') return true\n\n\t// Check the computed color-scheme CSS property on :root\n\tconst rootStyle = window.getComputedStyle(document.documentElement)\n\tconst colorScheme = rootStyle.getPropertyValue('color-scheme').trim().toLowerCase()\n\treturn colorScheme === 'dark' || colorScheme === 'only dark'\n}\n\n/**\n * Checks the background color of the body element to determine if the page is dark.\n */\nfunction isBackgroundDark() {\n\t// We check both <html> and <body> because some pages set the color on <html>\n\tconst htmlStyle = window.getComputedStyle(document.documentElement)\n\tconst bodyStyle = window.getComputedStyle(document.body || document.documentElement)\n\n\t// Get background colors\n\tconst htmlBgColor = htmlStyle.backgroundColor\n\tconst bodyBgColor = bodyStyle.backgroundColor\n\n\t// The body's background might be transparent, in which case we should\n\t// fall back to the html element's background.\n\tif (isColorDark(bodyBgColor)) {\n\t\treturn true\n\t} else if (bodyBgColor === 'transparent' || bodyBgColor.startsWith('rgba(0, 0, 0, 0)')) {\n\t\treturn isColorDark(htmlBgColor)\n\t}\n\n\treturn false\n}\n\n/**\n * Checks if the text color on the body is light, which implies a dark background.\n */\nfunction isTextColorLight() {\n\t/** Luminance (0-255) above which body text is considered light */\n\tconst LIGHT_TEXT_LUMINANCE = 200\n\n\tconst bodyStyle = window.getComputedStyle(document.body || document.documentElement)\n\tconst luminance = getLuminance(bodyStyle.color)\n\n\t// Light text has high luminance (e.g. white text on dark bg)\n\treturn luminance !== null && luminance > LIGHT_TEXT_LUMINANCE\n}\n\n/**\n * Checks the background color of major layout elements (#app, #root, etc.).\n * Many SPAs render into a container that may have its own dark background while\n * <body> remains transparent.\n */\nfunction isMainContentBackgroundDark() {\n\tconst { innerWidth: vw, innerHeight: vh } = window\n\tconst minArea = vw * vh * 0.5\n\n\tconst selectors = ['#app', '#root', '#__next']\n\tfor (const selector of selectors) {\n\t\tconst el = document.querySelector(selector)\n\t\tif (!el) continue\n\n\t\tconst rect = el.getBoundingClientRect()\n\t\tif (rect.width * rect.height < minArea) continue\n\n\t\tif (isColorDark(window.getComputedStyle(el).backgroundColor)) return true\n\t}\n\treturn false\n}\n\n// --- utils ---\n\n/**\n * Parses an RGB or RGBA color string and returns an object with r, g, b properties.\n * @param {string} colorString - e.g., \"rgb(34, 34, 34)\" or \"rgba(0, 0, 0, 0.5)\"\n * @returns {{r: number, g: number, b: number}|null}\n */\nfunction parseRgbColor(colorString: string) {\n\tconst rgbMatch = /rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)/.exec(colorString)\n\tif (!rgbMatch) {\n\t\treturn null // Not a valid rgb/rgba string\n\t}\n\treturn {\n\t\tr: parseInt(rgbMatch[1]),\n\t\tg: parseInt(rgbMatch[2]),\n\t\tb: parseInt(rgbMatch[3]),\n\t}\n}\n\n/**\n * Calculates the perceived luminance (0-255) of a CSS color string.\n * @param {string} colorString - e.g., \"rgb(50, 50, 50)\" or \"rgba(0, 0, 0, 0.5)\"\n * @returns {number|null} - The luminance, or null if the color is transparent or unparseable.\n */\nfunction getLuminance(colorString: string): number | null {\n\tif (!colorString || colorString === 'transparent' || colorString.startsWith('rgba(0, 0, 0, 0)')) {\n\t\treturn null // Transparent has no meaningful luminance\n\t}\n\n\tconst rgb = parseRgbColor(colorString)\n\tif (!rgb) {\n\t\treturn null // Could not parse color\n\t}\n\n\t// Standard perceived luminance formula\n\treturn 0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b\n}\n\n/**\n * Determines if a color is \"dark\" based on its calculated luminance.\n * @param {string} colorString - The CSS color string (e.g., \"rgb(50, 50, 50)\").\n * @param {number} threshold - A value between 0 and 255. Colors with luminance below this will be considered dark. Default is 128.\n */\nfunction isColorDark(colorString: string, threshold = 128) {\n\tconst luminance = getLuminance(colorString)\n\treturn luminance !== null && luminance < threshold\n}\n",".wrapper {\n\tposition: fixed;\n\tinset: 0;\n\tz-index: 2147483641; /* 确保在所有元素之上,除了 Agent UI */\n\tcursor: wait;\n\toverflow: hidden;\n\n\tdisplay: none;\n}\n\n.wrapper.visible {\n\tdisplay: block;\n}\n","/* AI 光标样式 */\n.cursor {\n\tposition: absolute;\n\twidth: var(--cursor-size, 75px);\n\theight: var(--cursor-size, 75px);\n\tpointer-events: none;\n\tz-index: 10000;\n}\n\n.cursorBorder {\n\tposition: absolute;\n\twidth: 100%;\n\theight: 100%;\n\tbackground: linear-gradient(45deg, rgb(57, 182, 255), rgb(189, 69, 251));\n\tmask-image: url(./cursor-border.svg);\n\tmask-size: 100% 100%;\n\tmask-repeat: no-repeat;\n\n\ttransform-origin: center;\n\ttransform: rotate(-135deg) scale(1.2);\n\tmargin-left: -10px;\n\tmargin-top: -18px;\n}\n\n.cursorFilling {\n\tposition: absolute;\n\twidth: 100%;\n\theight: 100%;\n\tbackground: url(./cursor-fill.svg);\n\tbackground-size: 100% 100%;\n\tbackground-repeat: no-repeat;\n\n\ttransform-origin: center;\n\ttransform: rotate(-135deg) scale(1.2);\n\tmargin-left: -10px;\n\tmargin-top: -18px;\n}\n\n.cursorRipple {\n\tposition: absolute;\n\twidth: 100%;\n\theight: 100%;\n\tpointer-events: none;\n\tmargin-left: -50%;\n\tmargin-top: -50%;\n\n\t&::after {\n\t\tcontent: '';\n\t\topacity: 0;\n\t\tposition: absolute;\n\t\tinset: 0;\n\t\tborder: 4px solid rgba(57, 182, 255, 1);\n\t\tborder-radius: 50%;\n\t}\n}\n\n.cursor.clicking .cursorRipple::after {\n\tanimation: cursor-ripple 300ms ease-out forwards;\n}\n\n@keyframes cursor-ripple {\n\t0% {\n\t\ttransform: scale(0);\n\t\topacity: 1;\n\t}\n\t100% {\n\t\ttransform: scale(2);\n\t\topacity: 0;\n\t}\n}\n","import { Motion } from 'ai-motion'\n\nimport { isPageDark } from './checkDarkMode'\n\nimport styles from './SimulatorMask.module.css'\nimport cursorStyles from './cursor.module.css'\n\nexport class SimulatorMask extends EventTarget {\n\tshown: boolean = false\n\twrapper = document.createElement('div')\n\tmotion: Motion | null = null\n\n\t#disposed = false\n\n\t#cursor = document.createElement('div')\n\n\t#currentCursorX = 0\n\t#currentCursorY = 0\n\n\t#targetCursorX = 0\n\t#targetCursorY = 0\n\n\tconstructor() {\n\t\tsuper()\n\n\t\tthis.wrapper.id = 'page-agent-runtime_simulator-mask'\n\t\tthis.wrapper.className = styles.wrapper\n\t\tthis.wrapper.setAttribute('data-browser-use-ignore', 'true')\n\t\tthis.wrapper.setAttribute('data-page-agent-ignore', 'true')\n\n\t\ttry {\n\t\t\tconst motion = new Motion({\n\t\t\t\tmode: isPageDark() ? 'dark' : 'light',\n\t\t\t\tstyles: { position: 'absolute', inset: '0' },\n\t\t\t})\n\t\t\tthis.motion = motion\n\t\t\tthis.wrapper.appendChild(motion.element)\n\t\t\tmotion.autoResize(this.wrapper)\n\t\t} catch (e) {\n\t\t\tconsole.warn('[SimulatorMask] Motion overlay unavailable:', e)\n\t\t}\n\n\t\t// Capture all mouse, keyboard, and wheel events\n\t\tthis.wrapper.addEventListener('click', (e) => {\n\t\t\te.stopPropagation()\n\t\t\te.preventDefault()\n\t\t})\n\t\tthis.wrapper.addEventListener('mousedown', (e) => {\n\t\t\te.stopPropagation()\n\t\t\te.preventDefault()\n\t\t})\n\t\tthis.wrapper.addEventListener('mouseup', (e) => {\n\t\t\te.stopPropagation()\n\t\t\te.preventDefault()\n\t\t})\n\t\tthis.wrapper.addEventListener('mousemove', (e) => {\n\t\t\te.stopPropagation()\n\t\t\te.preventDefault()\n\t\t})\n\t\tthis.wrapper.addEventListener('wheel', (e) => {\n\t\t\te.stopPropagation()\n\t\t\te.preventDefault()\n\t\t})\n\t\tthis.wrapper.addEventListener('keydown', (e) => {\n\t\t\te.stopPropagation()\n\t\t\te.preventDefault()\n\t\t})\n\t\tthis.wrapper.addEventListener('keyup', (e) => {\n\t\t\te.stopPropagation()\n\t\t\te.preventDefault()\n\t\t})\n\n\t\t// Create AI cursor\n\t\tthis.#createCursor()\n\t\t// this.show()\n\n\t\tdocument.body.appendChild(this.wrapper)\n\n\t\tthis.#moveCursorToTarget()\n\n\t\t// global events\n\t\t// @note Mask should be isolated from the rest of the code.\n\t\t// Global events are easier to manage and cleanup.\n\n\t\tconst movePointerToListener = (event: Event) => {\n\t\t\tconst { x, y } = (event as CustomEvent).detail\n\t\t\tthis.setCursorPosition(x, y)\n\t\t}\n\t\tconst clickPointerListener = () => {\n\t\t\tthis.triggerClickAnimation()\n\t\t}\n\t\tconst enablePassThroughListener = () => {\n\t\t\tthis.wrapper.style.pointerEvents = 'none'\n\t\t}\n\t\tconst disablePassThroughListener = () => {\n\t\t\tthis.wrapper.style.pointerEvents = 'auto'\n\t\t}\n\n\t\twindow.addEventListener('PageAgent::MovePointerTo', movePointerToListener)\n\t\twindow.addEventListener('PageAgent::ClickPointer', clickPointerListener)\n\t\twindow.addEventListener('PageAgent::EnablePassThrough', enablePassThroughListener)\n\t\twindow.addEventListener('PageAgent::DisablePassThrough', disablePassThroughListener)\n\n\t\tthis.addEventListener('dispose', () => {\n\t\t\twindow.removeEventListener('PageAgent::MovePointerTo', movePointerToListener)\n\t\t\twindow.removeEventListener('PageAgent::ClickPointer', clickPointerListener)\n\t\t\twindow.removeEventListener('PageAgent::EnablePassThrough', enablePassThroughListener)\n\t\t\twindow.removeEventListener('PageAgent::DisablePassThrough', disablePassThroughListener)\n\t\t})\n\t}\n\n\t#createCursor() {\n\t\tthis.#cursor.className = cursorStyles.cursor\n\n\t\t// Create ripple effect container\n\t\tconst rippleContainer = document.createElement('div')\n\t\trippleContainer.className = cursorStyles.cursorRipple\n\t\tthis.#cursor.appendChild(rippleContainer)\n\n\t\t// Create filling layer\n\t\tconst fillingLayer = document.createElement('div')\n\t\tfillingLayer.className = cursorStyles.cursorFilling\n\t\tthis.#cursor.appendChild(fillingLayer)\n\n\t\t// Create border layer\n\t\tconst borderLayer = document.createElement('div')\n\t\tborderLayer.className = cursorStyles.cursorBorder\n\t\tthis.#cursor.appendChild(borderLayer)\n\n\t\tthis.wrapper.appendChild(this.#cursor)\n\t}\n\n\t#moveCursorToTarget() {\n\t\tif (this.#disposed) return\n\n\t\tconst newX = this.#currentCursorX + (this.#targetCursorX - this.#currentCursorX) * 0.2\n\t\tconst newY = this.#currentCursorY + (this.#targetCursorY - this.#currentCursorY) * 0.2\n\n\t\tconst xDistance = Math.abs(newX - this.#targetCursorX)\n\t\tif (xDistance > 0) {\n\t\t\tif (xDistance < 2) {\n\t\t\t\tthis.#currentCursorX = this.#targetCursorX\n\t\t\t} else {\n\t\t\t\tthis.#currentCursorX = newX\n\t\t\t}\n\t\t\tthis.#cursor.style.left = `${this.#currentCursorX}px`\n\t\t}\n\n\t\tconst yDistance = Math.abs(newY - this.#targetCursorY)\n\t\tif (yDistance > 0) {\n\t\t\tif (yDistance < 2) {\n\t\t\t\tthis.#currentCursorY = this.#targetCursorY\n\t\t\t} else {\n\t\t\t\tthis.#currentCursorY = newY\n\t\t\t}\n\t\t\tthis.#cursor.style.top = `${this.#currentCursorY}px`\n\t\t}\n\n\t\trequestAnimationFrame(() => this.#moveCursorToTarget())\n\t}\n\n\tsetCursorPosition(x: number, y: number) {\n\t\tif (this.#disposed) return\n\n\t\tthis.#targetCursorX = x\n\t\tthis.#targetCursorY = y\n\t}\n\n\ttriggerClickAnimation() {\n\t\tif (this.#disposed) return\n\n\t\tthis.#cursor.classList.remove(cursorStyles.clicking)\n\t\t// Force reflow to restart animation\n\t\tvoid this.#cursor.offsetHeight\n\t\tthis.#cursor.classList.add(cursorStyles.clicking)\n\t}\n\n\tshow() {\n\t\tif (this.shown || this.#disposed) return\n\n\t\tthis.shown = true\n\t\tthis.motion?.start()\n\t\tthis.motion?.fadeIn()\n\n\t\tthis.wrapper.classList.add(styles.visible)\n\n\t\t// Initialize cursor position\n\t\tthis.#currentCursorX = window.innerWidth / 2\n\t\tthis.#currentCursorY = window.innerHeight / 2\n\t\tthis.#targetCursorX = this.#currentCursorX\n\t\tthis.#targetCursorY = this.#currentCursorY\n\t\tthis.#cursor.style.left = `${this.#currentCursorX}px`\n\t\tthis.#cursor.style.top = `${this.#currentCursorY}px`\n\t}\n\n\thide() {\n\t\tif (!this.shown || this.#disposed) return\n\n\t\tthis.shown = false\n\t\tthis.motion?.fadeOut()\n\t\tthis.motion?.pause()\n\n\t\tthis.#cursor.classList.remove(cursorStyles.clicking)\n\n\t\tsetTimeout(() => {\n\t\t\tthis.wrapper.classList.remove(styles.visible)\n\t\t}, 800) // Match the animation duration\n\t}\n\n\tdispose() {\n\t\tthis.#disposed = true\n\t\tthis.motion?.dispose()\n\t\tthis.wrapper.remove()\n\t\tthis.dispatchEvent(new Event('dispose'))\n\t}\n}\n","/**\n * Copyright (C) 2025 Alibaba Group Holding Limited\n * All rights reserved.\n *\n * BrowserController - Manages DOM operations and element interactions.\n * Designed to be independent of LLM and can be tested in unit tests.\n * All public methods are async for potential remote calling support.\n */\nimport {\n\tclickElement,\n\tgetElementByIndex,\n\tinputTextElement,\n\tscrollHorizontally,\n\tscrollVertically,\n\tselectOptionElement,\n} from './actions'\nimport * as dom from './dom'\nimport type { BrowserState } from './dom'\nimport type { FlatDomTree, InteractiveElementDomNode } from './dom/dom_tree/type'\nimport { getPageInfo } from './dom/getPageInfo'\nimport { patchReact } from './patches/react'\nimport { isAnchorElement } from './utils'\n\nexport type { BrowserState } from './dom'\n\n/**\n * Configuration for BrowserController\n */\nexport interface BrowserControllerConfig extends dom.DomConfig {\n\t/** Enable visual mask overlay during operations (default: false) */\n\tenableMask?: boolean\n}\n\ninterface ActionResult {\n\tsuccess: boolean\n\tmessage: string\n}\n\n/**\n * BrowserController manages DOM state and element interactions.\n * It provides async methods for all DOM operations, keeping state isolated.\n *\n * @lifecycle\n * - beforeUpdate: Emitted before the DOM tree is updated.\n * - afterUpdate: Emitted after the DOM tree is updated.\n */\nexport class BrowserController extends EventTarget {\n\tprivate config: BrowserControllerConfig\n\n\t/** Corresponds to eval_page in browser-use */\n\tprivate flatTree: FlatDomTree | null = null\n\n\t/**\n\t * All highlighted index-mapped interactive elements\n\t * Corresponds to DOMState.selector_map in browser-use\n\t */\n\tprivate selectorMap = new Map<number, InteractiveElementDomNode>()\n\n\t/** Index -> element text description mapping */\n\tprivate elementTextMap = new Map<number, string>()\n\n\t/**\n\t * Simplified HTML for LLM consumption.\n\t * Corresponds to clickable_elements_to_string in browser-use\n\t */\n\tprivate simplifiedHTML = '<EMPTY>'\n\n\t/** last time the tree was updated */\n\tprivate lastTimeUpdate = 0\n\n\t/** Whether the tree has been indexed at least once */\n\tprivate isIndexed = false\n\n\t/** Visual mask overlay for blocking user interaction during automation */\n\tprivate mask: InstanceType<typeof import('./visual/SimulatorMask').SimulatorMask> | null = null\n\tprivate maskReady: Promise<void> | null = null\n\tprivate disposed = false\n\n\tconstructor(config: BrowserControllerConfig = {}) {\n\t\tsuper()\n\n\t\tthis.config = config\n\n\t\tpatchReact(this)\n\n\t\tif (config.enableMask) this.initMask()\n\t}\n\n\t/**\n\t * Initialize mask asynchronously (dynamic import to avoid CSS loading in Node)\n\t */\n\tinitMask() {\n\t\tif (this.disposed || this.maskReady !== null) return\n\t\tthis.maskReady = (async () => {\n\t\t\tconst { SimulatorMask } = await import('./visual/SimulatorMask')\n\t\t\tif (this.disposed) return\n\n\t\t\tconst mask = new SimulatorMask()\n\t\t\tif (this.disposed) {\n\t\t\t\tmask.dispose()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.mask = mask\n\t\t})()\n\t}\n\t// ======= State Queries =======\n\n\t/**\n\t * Get current page URL\n\t */\n\tasync getCurrentUrl(): Promise<string> {\n\t\treturn window.location.href\n\t}\n\n\t/**\n\t * Get last tree update timestamp\n\t */\n\tasync getLastUpdateTime(): Promise<number> {\n\t\treturn this.lastTimeUpdate\n\t}\n\n\t/**\n\t * Get structured browser state for LLM consumption.\n\t * Automatically calls updateTree() to refresh the DOM state.\n\t */\n\tasync getBrowserState(): Promise<BrowserState> {\n\t\tconst url = window.location.href\n\t\tconst title = document.title\n\t\tconst pi = getPageInfo()\n\t\tconst viewportExpansion = dom.resolveViewportExpansion(this.config.viewportExpansion)\n\n\t\tawait this.updateTree()\n\n\t\tconst content = this.simplifiedHTML\n\n\t\t// Build header: page info + scroll position hint\n\t\tconst titleLine = `Current Page: [${title}](${url})`\n\n\t\tconst pageInfoLine = `Page info: ${pi.viewport_width}x${pi.viewport_height}px viewport, ${pi.page_width}x${pi.page_height}px total page size, ${pi.pages_above.toFixed(1)} pages above, ${pi.pages_below.toFixed(1)} pages below, ${pi.total_pages.toFixed(1)} total pages, at ${(pi.current_page_position * 100).toFixed(0)}% of page`\n\n\t\tconst elementsLabel =\n\t\t\tviewportExpansion === -1\n\t\t\t\t? 'Interactive elements from top layer of the current page (full page):'\n\t\t\t\t: 'Interactive elements from top layer of the current page inside the viewport:'\n\n\t\tconst hasContentAbove = pi.pixels_above > 4\n\t\tconst scrollHintAbove =\n\t\t\thasContentAbove && viewportExpansion !== -1\n\t\t\t\t? `... ${pi.pixels_above} pixels above (${pi.pages_above.toFixed(1)} pages) - scroll to see more ...`\n\t\t\t\t: '[Start of page]'\n\n\t\tconst header = `${titleLine}\\n${pageInfoLine}\\n\\n${elementsLabel}\\n\\n${scrollHintAbove}`\n\n\t\t// Build footer: scroll position hint\n\t\tconst hasContentBelow = pi.pixels_below > 4\n\t\tconst footer =\n\t\t\thasContentBelow && viewportExpansion !== -1\n\t\t\t\t? `... ${pi.pixels_below} pixels below (${pi.pages_below.toFixed(1)} pages) - scroll to see more ...`\n\t\t\t\t: '[End of page]'\n\n\t\treturn { url, title, header, content, footer }\n\t}\n\n\t// ======= DOM Tree Operations =======\n\n\t/**\n\t * Update DOM tree, returns simplified HTML for LLM.\n\t * This is the main method to refresh the page state.\n\t * Automatically bypasses mask during DOM extraction if enabled.\n\t */\n\tasync updateTree(): Promise<string> {\n\t\tthis.dispatchEvent(new Event('beforeUpdate'))\n\n\t\tthis.lastTimeUpdate = Date.now()\n\n\t\t// Temporarily bypass mask to allow DOM extraction\n\t\tif (this.mask) {\n\t\t\tthis.mask.wrapper.style.pointerEvents = 'none'\n\t\t}\n\n\t\tdom.cleanUpHighlights()\n\n\t\tconst blacklist = [\n\t\t\t...(this.config.interactiveBlacklist || []),\n\t\t\t...Array.from(document.querySelectorAll('[data-page-agent-not-interactive]')),\n\t\t]\n\n\t\tthis.flatTree = dom.getFlatTree({\n\t\t\t...this.config,\n\t\t\tinteractiveBlacklist: blacklist,\n\t\t})\n\n\t\tthis.simplifiedHTML = dom.flatTreeToString(\n\t\t\tthis.flatTree,\n\t\t\tthis.config.includeAttributes,\n\t\t\tthis.config.keepSemanticTags\n\t\t)\n\n\t\tthis.selectorMap.clear()\n\t\tthis.selectorMap = dom.getSelectorMap(this.flatTree)\n\n\t\tthis.elementTextMap.clear()\n\t\tthis.elementTextMap = dom.getElementTextMap(this.simplifiedHTML)\n\n\t\t// Mark as indexed - now element actions are allowed\n\t\tthis.isIndexed = true\n\n\t\t// Restore mask blocking\n\t\tif (this.mask) {\n\t\t\tthis.mask.wrapper.style.pointerEvents = 'auto'\n\t\t}\n\n\t\tthis.dispatchEvent(new Event('afterUpdate'))\n\n\t\treturn this.simplifiedHTML\n\t}\n\n\t/**\n\t * Clean up all element highlights\n\t */\n\tasync cleanUpHighlights(): Promise<void> {\n\t\tconsole.log('[BrowserController] cleanUpHighlights')\n\t\tdom.cleanUpHighlights()\n\t}\n\n\t// ======= Element Actions =======\n\n\t/**\n\t * Ensure the tree has been indexed before any index-based operation.\n\t * Throws if updateTree() hasn't been called yet.\n\t */\n\tprivate assertIndexed(): void {\n\t\tif (!this.isIndexed) {\n\t\t\tthrow new Error('DOM tree not indexed yet. Can not perform actions on elements.')\n\t\t}\n\t}\n\n\t/**\n\t * Click element by index\n\t */\n\tasync clickElement(index: number): Promise<ActionResult> {\n\t\ttry {\n\t\t\tthis.assertIndexed()\n\t\t\tconst element = getElementByIndex(this.selectorMap, index)\n\t\t\tconst elemText = this.elementTextMap.get(index)\n\t\t\tawait clickElement(element)\n\n\t\t\t// Handle links that open in new tabs\n\t\t\tif (isAnchorElement(element) && element.target === '_blank') {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: true,\n\t\t\t\t\tmessage: `✅ Clicked element (${elemText ?? index}). ⚠️ Link opened in a new tab.`,\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tsuccess: true,\n\t\t\t\tmessage: `✅ Clicked element (${elemText ?? index}).`,\n\t\t\t}\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\tmessage: `❌ Failed to click element: ${error}`,\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Input text into element by index\n\t */\n\tasync inputText(index: number, text: string): Promise<ActionResult> {\n\t\ttry {\n\t\t\tthis.assertIndexed()\n\t\t\tconst element = getElementByIndex(this.selectorMap, index)\n\t\t\tconst elemText = this.elementTextMap.get(index)\n\t\t\tawait inputTextElement(element, text)\n\n\t\t\treturn {\n\t\t\t\tsuccess: true,\n\t\t\t\tmessage: `✅ Input text (${text}) into element (${elemText ?? index}).`,\n\t\t\t}\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\tmessage: `❌ Failed to input text: ${error}`,\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Select dropdown option by index and option text\n\t */\n\tasync selectOption(index: number, optionText: string): Promise<ActionResult> {\n\t\ttry {\n\t\t\tthis.assertIndexed()\n\t\t\tconst element = getElementByIndex(this.selectorMap, index)\n\t\t\tconst elemText = this.elementTextMap.get(index)\n\t\t\tawait selectOptionElement(element as HTMLSelectElement, optionText)\n\n\t\t\treturn {\n\t\t\t\tsuccess: true,\n\t\t\t\tmessage: `✅ Selected option (${optionText}) in element (${elemText ?? index}).`,\n\t\t\t}\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\tmessage: `❌ Failed to select option: ${error}`,\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Scroll vertically\n\t */\n\tasync scroll(options: {\n\t\tdown: boolean\n\t\tnumPages: number\n\t\tpixels?: number\n\t\tindex?: number\n\t}): Promise<ActionResult> {\n\t\ttry {\n\t\t\tconst { down, numPages, pixels, index } = options\n\n\t\t\tthis.assertIndexed()\n\n\t\t\tconst scrollAmount = (pixels ?? numPages * window.innerHeight) * (down ? 1 : -1)\n\n\t\t\tconst element = index !== undefined ? getElementByIndex(this.selectorMap, index) : null\n\n\t\t\tconst message = await scrollVertically(scrollAmount, element)\n\n\t\t\treturn {\n\t\t\t\tsuccess: true,\n\t\t\t\tmessage,\n\t\t\t}\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\tmessage: `❌ Failed to scroll: ${error}`,\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Scroll horizontally\n\t */\n\tasync scrollHorizontally(options: {\n\t\tright: boolean\n\t\tpixels: number\n\t\tindex?: number\n\t}): Promise<ActionResult> {\n\t\ttry {\n\t\t\tconst { right, pixels, index } = options\n\n\t\t\tthis.assertIndexed()\n\n\t\t\tconst scrollAmount = pixels * (right ? 1 : -1)\n\n\t\t\tconst element = index !== undefined ? getElementByIndex(this.selectorMap, index) : null\n\n\t\t\tconst message = await scrollHorizontally(scrollAmount, element)\n\n\t\t\treturn {\n\t\t\t\tsuccess: true,\n\t\t\t\tmessage,\n\t\t\t}\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\tmessage: `❌ Failed to scroll horizontally: ${error}`,\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Execute arbitrary JavaScript on the page.\n\t * The optional `signal` is exposed to the script scope so cooperative code\n\t * can abort promptly when the task is stopped.\n\t */\n\tasync executeJavascript(script: string, signal?: AbortSignal): Promise<ActionResult> {\n\t\ttry {\n\t\t\t// Wrap script in async function to support await, exposing `signal`.\n\t\t\tconst asyncFunction = (0, eval)(`(async (signal) => { ${script} })`)\n\t\t\tconst result = await asyncFunction(signal)\n\t\t\treturn {\n\t\t\t\tsuccess: true,\n\t\t\t\tmessage: `✅ Executed JavaScript. Result: ${result}`,\n\t\t\t}\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\tmessage: `❌ Error executing JavaScript: ${error}`,\n\t\t\t}\n\t\t}\n\t}\n\n\t// ======= Mask Operations =======\n\n\t/**\n\t * Show the visual mask overlay.\n\t * Only works after mask is setup.\n\t */\n\tasync showMask(): Promise<void> {\n\t\tif (this.disposed) return\n\t\tawait this.maskReady\n\t\tif (this.disposed) return\n\t\tthis.mask?.show()\n\t}\n\n\t/**\n\t * Hide the visual mask overlay.\n\t * Only works after mask is setup.\n\t */\n\tasync hideMask(): Promise<void> {\n\t\tif (this.disposed) return\n\t\tawait this.maskReady\n\t\tif (this.disposed) return\n\t\tthis.mask?.hide()\n\t}\n\n\t/**\n\t * Dispose and clean up resources\n\t */\n\tdispose(): void {\n\t\tif (this.disposed) return\n\t\tthis.disposed = true\n\n\t\tconst errors: unknown[] = []\n\t\tconst cleanUp = (callback: () => void) => {\n\t\t\ttry {\n\t\t\t\tcallback()\n\t\t\t} catch (error: unknown) {\n\t\t\t\terrors.push(error)\n\t\t\t}\n\t\t}\n\n\t\tcleanUp(() => dom.cleanUpHighlights())\n\t\tcleanUp(() => {\n\t\t\tthis.flatTree = null\n\t\t\tthis.selectorMap.clear()\n\t\t\tthis.elementTextMap.clear()\n\t\t\tthis.simplifiedHTML = '<EMPTY>'\n\t\t\tthis.isIndexed = false\n\t\t})\n\t\tcleanUp(() => this.mask?.dispose())\n\t\tthis.mask = null\n\n\t\tif (errors.length === 1) throw errors[0]\n\t\tif (errors.length > 1) throw new AggregateError(errors, 'BrowserController disposal failed')\n\t}\n}\n\nexport * from './actions'\n","// English translations (base/reference language)\nconst enUS = {\n\tui: {\n\t\tready: 'Ready',\n\t\tthinking: 'Thinking...',\n\t\ttaskInput: 'Enter new task, describe steps in detail, press Enter to submit',\n\t\tuserAnswerPrompt: 'Please answer the question above, press Enter to submit',\n\t\ttaskTerminated: 'Task terminated',\n\t\ttaskCompleted: 'Task completed',\n\t\tuserAnswer: 'User answer: {{input}}',\n\t\tquestion: 'Question: {{question}}',\n\t\twaitingPlaceholder: 'Waiting for task to start...',\n\t\tstop: 'Stop',\n\t\tclose: 'Close',\n\t\texpand: 'Expand history',\n\t\tcollapse: 'Collapse history',\n\t\tstep: 'Step {{number}}',\n\t\ttools: {\n\t\t\tclicking: 'Clicking element [{{index}}]...',\n\t\t\tinputting: 'Inputting text to element [{{index}}]...',\n\t\t\tselecting: 'Selecting option \"{{text}}\"...',\n\t\t\tscrolling: 'Scrolling page...',\n\t\t\twaiting: 'Waiting {{seconds}} seconds...',\n\t\t\taskingUser: 'Asking user...',\n\t\t\tdone: 'Task done',\n\t\t\tclicked: '🖱️ Clicked element [{{index}}]',\n\t\t\tinputted: '⌨️ Inputted text \"{{text}}\"',\n\t\t\tselected: '☑️ Selected option \"{{text}}\"',\n\t\t\tscrolled: '🛞 Page scrolled',\n\t\t\twaited: '⌛️ Wait completed',\n\t\t\texecuting: 'Executing {{toolName}}...',\n\t\t\tresultSuccess: 'success',\n\t\t\tresultFailure: 'failed',\n\t\t\tresultError: 'error',\n\t\t},\n\t\terrors: {\n\t\t\telementNotFound: 'No interactive element found at index {{index}}',\n\t\t\ttaskRequired: 'Task description is required',\n\t\t\texecutionFailed: 'Task execution failed',\n\t\t\tnotInputElement: 'Element is not an input or textarea',\n\t\t\tnotSelectElement: 'Element is not a select element',\n\t\t\toptionNotFound: 'Option \"{{text}}\" not found',\n\t\t},\n\t},\n} as const\n\n// Chinese translations (must match the structure of enUS)\nconst zhCN = {\n\tui: {\n\t\tready: '准备就绪',\n\t\tthinking: '正在思考...',\n\t\ttaskInput: '输入新任务,详细描述步骤,回车提交',\n\t\tuserAnswerPrompt: '请回答上面问题,回车提交',\n\t\ttaskTerminated: '任务已终止',\n\t\ttaskCompleted: '任务结束',\n\t\tuserAnswer: '用户回答: {{input}}',\n\t\tquestion: '询问: {{question}}',\n\t\twaitingPlaceholder: '等待任务开始...',\n\t\tstop: '终止',\n\t\tclose: '关闭',\n\t\texpand: '展开历史',\n\t\tcollapse: '收起历史',\n\t\tstep: '步骤 {{number}}',\n\t\ttools: {\n\t\t\tclicking: '正在点击元素 [{{index}}]...',\n\t\t\tinputting: '正在输入文本到元素 [{{index}}]...',\n\t\t\tselecting: '正在选择选项 \"{{text}}\"...',\n\t\t\tscrolling: '正在滚动页面...',\n\t\t\twaiting: '等待 {{seconds}} 秒...',\n\t\t\taskingUser: '正在询问用户...',\n\t\t\tdone: '结束任务',\n\t\t\tclicked: '🖱️ 已点击元素 [{{index}}]',\n\t\t\tinputted: '⌨️ 已输入文本 \"{{text}}\"',\n\t\t\tselected: '☑️ 已选择选项 \"{{text}}\"',\n\t\t\tscrolled: '🛞 页面滚动完成',\n\t\t\twaited: '⌛️ 等待完成',\n\t\t\texecuting: '正在执行 {{toolName}}...',\n\t\t\tresultSuccess: '成功',\n\t\t\tresultFailure: '失败',\n\t\t\tresultError: '错误',\n\t\t},\n\t\terrors: {\n\t\t\telementNotFound: '未找到索引为 {{index}} 的交互元素',\n\t\t\ttaskRequired: '任务描述不能为空',\n\t\t\texecutionFailed: '任务执行失败',\n\t\t\tnotInputElement: '元素不是输入框或文本域',\n\t\t\tnotSelectElement: '元素不是选择框',\n\t\t\toptionNotFound: '未找到选项 \"{{text}}\"',\n\t\t},\n\t},\n} as const\n\n// Type definitions generated from English base structure (but with string values)\ntype DeepStringify<T> = {\n\t[K in keyof T]: T[K] extends string ? string : T[K] extends object ? DeepStringify<T[K]> : T[K]\n}\n\nexport type TranslationSchema = DeepStringify<typeof enUS>\n\n// Utility type: Extract all nested paths from translation object\ntype NestedKeyOf<ObjectType extends object> = {\n\t[Key in keyof ObjectType & (string | number)]: ObjectType[Key] extends object\n\t\t? `${Key}` | `${Key}.${NestedKeyOf<ObjectType[Key]>}`\n\t\t: `${Key}`\n}[keyof ObjectType & (string | number)]\n\n// Extract all possible key paths from translation structure\nexport type TranslationKey = NestedKeyOf<TranslationSchema>\n\n// Parameterized translation types\nexport type TranslationParams = Record<string, string | number>\n\nexport const locales = {\n\t'en-US': enUS,\n\t'zh-CN': zhCN,\n} as const\n\nexport type SupportedLanguage = keyof typeof locales\n","import {\n\ttype SupportedLanguage,\n\ttype TranslationKey,\n\ttype TranslationParams,\n\ttype TranslationSchema,\n\tlocales,\n} from './locales'\n\nexport class I18n {\n\tprivate language: SupportedLanguage\n\tprivate translations: TranslationSchema\n\n\tconstructor(language: SupportedLanguage = 'en-US') {\n\t\tthis.language = language in locales ? language : 'en-US'\n\t\tthis.translations = locales[this.language]\n\t}\n\n\t// 类型安全的翻译方法\n\tt(key: TranslationKey, params?: TranslationParams): string {\n\t\tconst value = this.getNestedValue(this.translations, key)\n\t\tif (!value) {\n\t\t\tconsole.warn(`Translation key \"${key}\" not found for language \"${this.language}\"`)\n\t\t\treturn key\n\t\t}\n\n\t\tif (params) {\n\t\t\treturn this.interpolate(value, params)\n\t\t}\n\t\treturn value\n\t}\n\n\tprivate getNestedValue(obj: any, path: string): string | undefined {\n\t\treturn path.split('.').reduce((current, key) => current?.[key], obj)\n\t}\n\n\tprivate interpolate(template: string, params: TranslationParams): string {\n\t\treturn template.replace(/\\{\\{(\\w+)\\}\\}/g, (match, key) => {\n\t\t\t// Use != null to check for both null and undefined, allow empty strings\n\t\t\treturn params[key] != null ? params[key].toString() : match\n\t\t})\n\t}\n\n\tgetLanguage(): SupportedLanguage {\n\t\treturn this.language\n\t}\n}\n\n// 导出类型和实例创建函数\nexport type { TranslationKey, SupportedLanguage, TranslationParams }\nexport { locales }\n","export function truncate(text: string, maxLength: number): string {\n\tif (text.length > maxLength) {\n\t\treturn text.substring(0, maxLength) + '...'\n\t}\n\treturn text\n}\n\n/**\n * Escape HTML special characters to prevent XSS and rendering issues\n */\nexport function escapeHtml(text: string): string {\n\treturn text\n\t\t.replace(/&/g, '&')\n\t\t.replace(/</g, '<')\n\t\t.replace(/>/g, '>')\n\t\t.replace(/\"/g, '"')\n\t\t.replace(/'/g, ''')\n}\n",".wrapper {\n\tposition: fixed;\n\tbottom: 100px;\n\tleft: 50%;\n\ttransform: translateX(-50%) translateY(20px);\n\topacity: 0;\n\tz-index: 2147483642; /* 比 SimulatorMask 高一层 */\n\tbox-sizing: border-box;\n\n\toverflow: visible;\n\n\t* {\n\t\tbox-sizing: border-box;\n\t}\n\n\t--width: 360px;\n\t--height: 40px;\n\t--border-radius: 12px;\n\n\t--side-space: 12px; /* 控制栏两侧的间距 */\n\t--history-width: calc(var(--width) - var(--side-space) * 2);\n\n\t--color-1: rgb(57, 182, 255);\n\t--color-2: rgb(189, 69, 251);\n\t--color-3: rgb(255, 87, 51);\n\t--color-4: rgb(255, 214, 0);\n\n\twidth: var(--width);\n\theight: var(--height);\n\n\ttransition: all 0.3s ease-in-out;\n\n\t/* 响应式设计 */\n\t@media (max-width: 480px) {\n\t\twidth: calc(100vw - 40px);\n\t\t--width: calc(100vw - 40px);\n\t}\n\n\t.background {\n\t\tposition: absolute;\n\t\tinset: -2px -8px;\n\t\tborder-radius: calc(var(--border-radius) + 4px);\n\t\tfilter: blur(16px);\n\t\toverflow: hidden;\n\t\t/* mix-blend-mode: lighten; */\n\t\t/* display: none; */\n\n\t\t&::before {\n\t\t\tcontent: '';\n\t\t\tz-index: -1;\n\t\t\tpointer-events: none;\n\t\t\tposition: absolute;\n\t\t\twidth: 100%;\n\t\t\theight: 100%;\n\t\t\t/* left: -100%; */\n\t\t\tleft: 0;\n\t\t\ttop: 0;\n\n\t\t\tbackground-image: linear-gradient(\n\t\t\t\tto bottom left,\n\t\t\t\tvar(--color-1),\n\t\t\t\tvar(--color-2),\n\t\t\t\tvar(--color-1)\n\t\t\t);\n\t\t\tanimation: mask-running 2s linear infinite;\n\t\t}\n\t\t&::after {\n\t\t\tcontent: '';\n\t\t\tz-index: -1;\n\t\t\tpointer-events: none;\n\t\t\tposition: absolute;\n\t\t\twidth: 100%;\n\t\t\theight: 100%;\n\t\t\tleft: 0;\n\t\t\ttop: 0;\n\n\t\t\tbackground-image: linear-gradient(\n\t\t\t\tto bottom left,\n\t\t\t\tvar(--color-2),\n\t\t\t\tvar(--color-1),\n\t\t\t\tvar(--color-2)\n\t\t\t);\n\t\t\tanimation: mask-running 2s linear infinite;\n\t\t\tanimation-delay: 1s;\n\t\t}\n\t}\n}\n\n@keyframes mask-running {\n\tfrom {\n\t\ttransform: translateX(-100%);\n\t}\n\tto {\n\t\ttransform: translateX(100%);\n\t}\n}\n\n/* 控制栏 */\n.header {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tpadding: 8px 12px;\n\tuser-select: none;\n\n\tposition: absolute;\n\tinset: 0;\n\n\tcursor: pointer;\n\tflex-shrink: 0; /* 防止 header 被压缩 */\n\n\tbackground: rgba(0, 0, 0, 0.5);\n\tbackdrop-filter: blur(10px);\n\tborder-radius: var(--border-radius);\n\tbackground-clip: padding-box;\n\n\tbox-shadow:\n\t\t0 0 0px 2px rgba(255, 255, 255, 0.4),\n\t\t0 0 5px 1px rgba(255, 255, 255, 0.3);\n\n\t.statusSection {\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tgap: 8px;\n\t\tflex: 1;\n\t\tmin-height: 24px; /* 确保垂直居中 */\n\n\t\t.indicator {\n\t\t\twidth: 6px;\n\t\t\theight: 6px;\n\t\t\tborder-radius: 50%;\n\t\t\tbackground: rgba(255, 255, 255, 0.5);\n\t\t\tflex-shrink: 0;\n\t\t\tanimation: none; /* 默认无动画 */\n\n\t\t\t/* 运行状态 - 有动画 */\n\t\t\t&.thinking {\n\t\t\t\tbackground: rgb(57, 182, 255);\n\t\t\t\tanimation: pulse 0.8s ease-in-out infinite;\n\t\t\t}\n\n\t\t\t&.tool_executing {\n\t\t\t\tbackground: rgb(189, 69, 251);\n\t\t\t\tanimation: pulse 0.6s ease-in-out infinite;\n\t\t\t}\n\n\t\t\t&.retry {\n\t\t\t\tbackground: rgb(255, 214, 0);\n\t\t\t\tanimation: retryPulse 1s ease-in-out infinite;\n\t\t\t}\n\n\t\t\t/* 静止状态 - 无动画 */\n\t\t\t&.completed,\n\t\t\t&.input,\n\t\t\t&.output {\n\t\t\t\tbackground: rgb(34, 197, 94);\n\t\t\t\tanimation: none;\n\t\t\t}\n\n\t\t\t&.error {\n\t\t\t\tbackground: rgb(239, 68, 68);\n\t\t\t\tanimation: none;\n\t\t\t}\n\t\t}\n\n\t\t.statusText {\n\t\t\tcolor: white;\n\t\t\tfont-size: 12px;\n\t\t\tline-height: 1;\n\t\t\tfont-weight: 500;\n\t\t\ttransition: all 0.3s ease-in-out;\n\t\t\tposition: relative;\n\t\t\toverflow: hidden;\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tmin-height: 24px; /* 确保垂直居中 */\n\n\t\t\t&.fadeOut {\n\t\t\t\tanimation: statusTextFadeOut 0.3s ease forwards;\n\t\t\t}\n\n\t\t\t&.fadeIn {\n\t\t\t\tanimation: statusTextFadeIn 0.3s ease forwards;\n\t\t\t}\n\t\t}\n\t}\n\n\t.controls {\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tgap: 4px;\n\n\t\t.controlButton {\n\t\t\twidth: 24px;\n\t\t\theight: 24px;\n\t\t\tborder: none;\n\t\t\tborder-radius: 4px;\n\t\t\tbackground: rgba(255, 255, 255, 0.1);\n\t\t\tcolor: white;\n\t\t\tcursor: pointer;\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tjustify-content: center;\n\t\t\tfont-size: 12px;\n\t\t\tline-height: 1;\n\n\t\t\t&:hover {\n\t\t\t\tbackground: rgba(255, 255, 255, 0.2);\n\t\t\t}\n\t\t}\n\n\t\t.stopButton {\n\t\t\tbackground: rgba(239, 68, 68, 0.2);\n\t\t\tcolor: rgb(255, 41, 41);\n\t\t\tfont-weight: 600;\n\n\t\t\t&:hover {\n\t\t\t\tbackground: rgba(239, 68, 68, 0.3);\n\t\t\t}\n\t\t}\n\t}\n}\n\n@keyframes statusTextFadeIn {\n\t0% {\n\t\topacity: 0;\n\t\ttransform: translateY(5px);\n\t}\n\t100% {\n\t\topacity: 1;\n\t\ttransform: translateY(0);\n\t}\n}\n\n@keyframes statusTextFadeOut {\n\t0% {\n\t\topacity: 1;\n\t\ttransform: translateY(0);\n\t}\n\t100% {\n\t\topacity: 0;\n\t\ttransform: translateY(-5px);\n\t}\n}\n\n.historySectionWrapper {\n\tposition: absolute;\n\twidth: var(--history-width);\n\tbottom: var(--height);\n\tleft: var(--side-space);\n\tz-index: -2;\n\n\tpadding-top: 0px;\n\tvisibility: collapse;\n\toverflow: hidden;\n\n\ttransition: all 0.2s;\n\n\tbackground: rgba(2, 0, 20, 0.5);\n\t/* background: rgba(186, 186, 186, 0.2); */\n\tbackdrop-filter: blur(10px);\n\n\ttext-shadow: 0 0 1px rgba(0, 0, 0, 0.2);\n\n\tborder-top-left-radius: calc(var(--border-radius) + 4px);\n\tborder-top-right-radius: calc(var(--border-radius) + 4px);\n\n\t/* border: 2px solid rgba(255, 255, 255, 0.8); */\n\tborder: 2px solid rgba(255, 255, 255, 0.4);\n\tbox-shadow: 0 4px 16px rgba(0, 0, 0, 0.6);\n\n\t/* @media (prefers-color-scheme: dark) {\n\t\tbox-shadow:\n\t\t\t0 8px 32px 0 rgba(0, 0, 0, 0.85),\n\t\t\t0 2px 12px 0 rgba(57, 182, 255, 0.1);\n\t} */\n\n\t.expanded & {\n\t\tpadding-top: 8px;\n\t\tvisibility: visible;\n\t}\n\n\t.historySection {\n\t\tposition: relative;\n\t\toverflow-y: auto;\n\t\toverscroll-behavior: contain;\n\t\tscrollbar-width: none;\n\t\tmax-height: 0;\n\t\tpadding-inline: 8px;\n\n\t\ttransition: max-height 0.2s;\n\n\t\t.expanded & {\n\t\t\tmax-height: min(500px, calc(100vh - 200px - var(--height)));\n\t\t}\n\n\t\t.historyItem {\n\t\t\t/* backdrop-filter: blur(10px); */\n\t\t\tpadding: 8px 10px;\n\t\t\tmargin-bottom: 6px;\n\t\t\tbackground: linear-gradient(135deg, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0.03));\n\t\t\tborder-radius: 8px;\n\t\t\tborder-left: 2px solid rgba(57, 182, 255, 0.5);\n\t\t\tfont-size: 12px;\n\t\t\tcolor: white;\n\t\t\t/* color: black; */\n\t\t\tline-height: 1.3;\n\t\t\tposition: relative;\n\t\t\toverflow: hidden;\n\n\t\t\t/* 微妙的内阴影 */\n\t\t\tbox-shadow:\n\t\t\t\tinset 0 1px 0 rgba(255, 255, 255, 0.1),\n\t\t\t\t0 1px 3px rgba(0, 0, 0, 0.1);\n\n\t\t\t&::before {\n\t\t\t\tcontent: '';\n\t\t\t\tposition: absolute;\n\t\t\t\ttop: 0;\n\t\t\t\tleft: 0;\n\t\t\t\tright: 0;\n\t\t\t\theight: 1px;\n\t\t\t\tbackground: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);\n\t\t\t}\n\n\t\t\t&:hover {\n\t\t\t\tbackground: linear-gradient(135deg, rgba(255, 255, 255, 0.12), rgba(255, 255, 255, 0.06));\n\t\t\t\t/* transform: translateY(-1px); */\n\t\t\t\tbox-shadow:\n\t\t\t\t\tinset 0 1px 0 rgba(255, 255, 255, 0.15),\n\t\t\t\t\t0 2px 4px rgba(0, 0, 0, 0.15);\n\t\t\t}\n\n\t\t\t&:last-child {\n\t\t\t\tmargin-bottom: 10px;\n\t\t\t}\n\n\t\t\t&.completed,\n\t\t\t&.input,\n\t\t\t&.output {\n\t\t\t\tborder-left-color: rgb(34, 197, 94);\n\t\t\t\tbackground: linear-gradient(135deg, rgba(34, 197, 94, 0.1), rgba(34, 197, 94, 0.05));\n\t\t\t}\n\n\t\t\t&.error {\n\t\t\t\tborder-left-color: rgb(239, 68, 68);\n\t\t\t\tbackground: linear-gradient(135deg, rgba(239, 68, 68, 0.1), rgba(239, 68, 68, 0.05));\n\t\t\t}\n\n\t\t\t&.retry {\n\t\t\t\tborder-left-color: rgb(255, 214, 0);\n\t\t\t\tbackground: linear-gradient(135deg, rgba(255, 214, 0, 0.1), rgba(255, 214, 0, 0.05));\n\t\t\t}\n\n\t\t\t&.observation {\n\t\t\t\tborder-left-color: rgb(147, 51, 234);\n\t\t\t\tbackground: linear-gradient(135deg, rgba(147, 51, 234, 0.1), rgba(147, 51, 234, 0.05));\n\t\t\t}\n\n\t\t\t&.question {\n\t\t\t\tborder-left-color: rgb(255, 159, 67);\n\t\t\t\tbackground: linear-gradient(135deg, rgba(255, 159, 67, 0.15), rgba(255, 159, 67, 0.08));\n\t\t\t}\n\n\t\t\t/* 突出显示 done 成功结果 */\n\t\t\t&.doneSuccess {\n\t\t\t\tbackground: linear-gradient(\n\t\t\t\t\t135deg,\n\t\t\t\t\trgba(34, 197, 94, 0.25),\n\t\t\t\t\trgba(34, 197, 94, 0.15),\n\t\t\t\t\trgba(34, 197, 94, 0.08)\n\t\t\t\t);\n\t\t\t\tborder: none;\n\t\t\t\tborder-left: 4px solid rgb(34, 197, 94);\n\t\t\t\tbox-shadow:\n\t\t\t\t\t0 4px 12px rgba(34, 197, 94, 0.3),\n\t\t\t\t\tinset 0 1px 0 rgba(255, 255, 255, 0.2),\n\t\t\t\t\t0 0 20px rgba(34, 197, 94, 0.1);\n\t\t\t\tfont-weight: 600;\n\t\t\t\tcolor: rgb(220, 252, 231);\n\t\t\t\tpadding: 10px 12px;\n\t\t\t\tmargin-bottom: 8px;\n\t\t\t\tborder-radius: 8px;\n\t\t\t\tposition: relative;\n\t\t\t\toverflow: hidden;\n\n\t\t\t\t&::before {\n\t\t\t\t\tbackground: linear-gradient(90deg, transparent, rgba(34, 197, 94, 0.4), transparent);\n\t\t\t\t}\n\n\t\t\t\t&::after {\n\t\t\t\t\tcontent: '';\n\t\t\t\t\tposition: absolute;\n\t\t\t\t\ttop: 0;\n\t\t\t\t\tleft: -100%;\n\t\t\t\t\twidth: 100%;\n\t\t\t\t\theight: 100%;\n\t\t\t\t\tbackground: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.1), transparent);\n\t\t\t\t\tanimation: shimmer 2s ease-in-out infinite;\n\t\t\t\t}\n\n\t\t\t\t.historyContent {\n\t\t\t\t\t.statusIcon {\n\t\t\t\t\t\tfont-size: 16px;\n\t\t\t\t\t\tanimation: celebrate 0.8s ease-in-out;\n\t\t\t\t\t\tfilter: drop-shadow(0 2px 4px rgba(34, 197, 94, 0.5));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/* 突出显示 done 失败结果 */\n\t\t\t&.doneError {\n\t\t\t\tbackground: linear-gradient(\n\t\t\t\t\t135deg,\n\t\t\t\t\trgba(239, 68, 68, 0.25),\n\t\t\t\t\trgba(239, 68, 68, 0.15),\n\t\t\t\t\trgba(239, 68, 68, 0.08)\n\t\t\t\t);\n\t\t\t\tborder: none;\n\t\t\t\tborder-left: 4px solid rgb(239, 68, 68);\n\t\t\t\tbox-shadow:\n\t\t\t\t\t0 4px 12px rgba(239, 68, 68, 0.3),\n\t\t\t\t\tinset 0 1px 0 rgba(255, 255, 255, 0.2),\n\t\t\t\t\t0 0 20px rgba(239, 68, 68, 0.1);\n\t\t\t\tfont-weight: 600;\n\t\t\t\tcolor: rgb(254, 226, 226);\n\t\t\t\tpadding: 10px 12px;\n\t\t\t\tmargin-bottom: 8px;\n\t\t\t\tborder-radius: 8px;\n\t\t\t\tposition: relative;\n\t\t\t\toverflow: hidden;\n\n\t\t\t\t&::before {\n\t\t\t\t\tbackground: linear-gradient(90deg, transparent, rgba(239, 68, 68, 0.4), transparent);\n\t\t\t\t}\n\n\t\t\t\t.historyContent {\n\t\t\t\t\t.statusIcon {\n\t\t\t\t\t\tfont-size: 16px;\n\t\t\t\t\t\tfilter: drop-shadow(0 2px 4px rgba(239, 68, 68, 0.5));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t.historyContent {\n\t\t\t\tdisplay: flex;\n\t\t\t\talign-items: flex-start;\n\t\t\t\tgap: 8px;\n\n\t\t\t\tword-break: break-all;\n\t\t\t\twhite-space: pre-wrap;\n\n\t\t\t\t/* overflow-x: auto; */\n\n\t\t\t\t.statusIcon {\n\t\t\t\t\tfont-size: 12px;\n\t\t\t\t\tflex-shrink: 0;\n\t\t\t\t\tline-height: 1;\n\t\t\t\t\ttransition: all 0.3s ease;\n\t\t\t\t}\n\n\t\t\t\t.reflectionLines {\n\t\t\t\t\tdisplay: flex;\n\t\t\t\t\tflex-direction: column;\n\t\t\t\t\tgap: 4px;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t.historyMeta {\n\t\t\t\tfont-size: 10px;\n\t\t\t\tcolor: rgba(255, 255, 255, 0.6);\n\t\t\t\t/* color: rgb(61, 61, 61); */\n\t\t\t\tmargin-top: 8px;\n\t\t\t\tline-height: 1;\n\t\t\t}\n\t\t}\n\t}\n}\n\n/* 动画关键帧 - 更快的闪烁 */\n@keyframes pulse {\n\t0%,\n\t100% {\n\t\topacity: 1;\n\t\ttransform: scale(1);\n\t}\n\t50% {\n\t\topacity: 0.4;\n\t\ttransform: scale(1.3);\n\t}\n}\n\n/* 重试动画 - 旋转脉冲 */\n@keyframes retryPulse {\n\t0%,\n\t100% {\n\t\topacity: 1;\n\t\ttransform: scale(1) rotate(0deg);\n\t}\n\t25% {\n\t\topacity: 0.6;\n\t\ttransform: scale(1.2) rotate(90deg);\n\t}\n\t50% {\n\t\topacity: 0.8;\n\t\ttransform: scale(1.1) rotate(180deg);\n\t}\n\t75% {\n\t\topacity: 0.6;\n\t\ttransform: scale(1.2) rotate(270deg);\n\t}\n}\n\n/* 庆祝动画 */\n@keyframes celebrate {\n\t0%,\n\t100% {\n\t\ttransform: scale(1);\n\t}\n\t25% {\n\t\ttransform: scale(1.2) rotate(-5deg);\n\t}\n\t75% {\n\t\ttransform: scale(1.2) rotate(5deg);\n\t}\n}\n\n/* done 卡片的光泽效果 */\n@keyframes shimmer {\n\t0% {\n\t\tleft: -100%;\n\t}\n\t100% {\n\t\tleft: 100%;\n\t}\n}\n\n/* 输入区域样式 */\n.inputSectionWrapper {\n\tposition: absolute;\n\twidth: var(--history-width);\n\ttop: var(--height);\n\tleft: var(--side-space);\n\tz-index: -1;\n\n\tvisibility: visible;\n\toverflow: hidden;\n\n\theight: 48px;\n\n\ttransition: all 0.2s;\n\n\tbackground: rgba(186, 186, 186, 0.2);\n\tbackdrop-filter: blur(10px);\n\n\tborder-bottom-left-radius: calc(var(--border-radius) + 4px);\n\tborder-bottom-right-radius: calc(var(--border-radius) + 4px);\n\n\tborder: 2px solid rgba(255, 255, 255, 0.3);\n\tbox-shadow: 0 1px 16px rgba(0, 0, 0, 0.4);\n\n\t&.hidden {\n\t\tvisibility: collapse;\n\t\theight: 0;\n\t}\n\n\t.inputSection {\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tgap: 4px;\n\t\tpadding: 8px 8px;\n\n\t\t.taskInput {\n\t\t\tflex: 1;\n\t\t\tbackground: rgba(255, 255, 255, 0.4);\n\t\t\tborder: 1px solid rgba(255, 255, 255, 0.3);\n\t\t\tborder-radius: 10px;\n\t\t\tpadding-inline: 10px;\n\t\t\tcolor: rgb(20, 20, 20);\n\t\t\tfont-size: 12px;\n\t\t\theight: 28px;\n\t\t\tline-height: 1;\n\t\t\toutline: none;\n\t\t\ttransition: all 0.2s ease;\n\n\t\t\t/* text-shadow: 0 0 2px rgba(255, 255, 255, 0.8); */\n\n\t\t\t/* border-color: rgba(57, 182, 255, 0.3); */\n\n\t\t\t&::placeholder {\n\t\t\t\tcolor: rgb(53, 53, 53);\n\t\t\t}\n\n\t\t\t&:focus {\n\t\t\t\tbackground: rgba(255, 255, 255, 0.8);\n\t\t\t\tborder-color: rgba(57, 182, 255, 0.6);\n\t\t\t\tbox-shadow: 0 0 0 2px rgba(57, 182, 255, 0.2);\n\t\t\t}\n\t\t}\n\t}\n}\n","/**\n * Card HTML generation utilities for UI\n */\nimport { escapeHtml } from './utils'\n\nimport styles from './styles/UI.module.css'\n\ntype CardType =\n\t'default' | 'input' | 'output' | 'question' | 'observation' | 'doneSuccess' | 'doneError'\n\ninterface CardOptions {\n\ticon: string\n\tcontent: string | string[]\n\tmeta?: string\n\ttype?: CardType\n}\n\n/** Create a single history card */\nexport function createCard({ icon, content, meta, type }: CardOptions): string {\n\tconst typeClass = type ? styles[type] : ''\n\tconst contentHtml = Array.isArray(content)\n\t\t? `<div class=\"${styles.reflectionLines}\">${content.map((line) => `<span>${escapeHtml(line)}</span>`).join('')}</div>`\n\t\t: `<span>${escapeHtml(content)}</span>`\n\n\treturn `\n\t\t<div class=\"${styles.historyItem} ${typeClass}\">\n\t\t\t<div class=\"${styles.historyContent}\">\n\t\t\t\t<span class=\"${styles.statusIcon}\">${icon}</span>\n\t\t\t\t${contentHtml}\n\t\t\t</div>\n\t\t\t${meta ? `<div class=\"${styles.historyMeta}\">${meta}</div>` : ''}\n\t\t</div>\n\t`\n}\n\n/** Create reflection lines from reflection object */\nexport function createReflectionLines(reflection: {\n\tevaluation_previous_goal?: string\n\tmemory?: string\n\tnext_goal?: string\n}): string[] {\n\tconst lines: string[] = []\n\tif (reflection.evaluation_previous_goal) {\n\t\tlines.push(`🔍 ${reflection.evaluation_previous_goal}`)\n\t}\n\tif (reflection.memory) {\n\t\tlines.push(`💾 ${reflection.memory}`)\n\t}\n\tif (reflection.next_goal) {\n\t\tlines.push(`🎯 ${reflection.next_goal}`)\n\t}\n\treturn lines\n}\n","import { I18n, type SupportedLanguage } from './i18n'\nimport { truncate } from './utils'\nimport { createCard, createReflectionLines } from './cards'\nimport type { AgentActivity, UIAdapter } from './types'\n\nimport styles from './styles/UI.module.css'\n\nexport type { UIAdapter } from './types'\n\n/**\n * UI configuration\n */\nexport interface UIConfig {\n\tlanguage?: SupportedLanguage\n\t/**\n\t * Whether to prompt for next task after task completion\n\t * @default true\n\t */\n\tpromptForNextTask?: boolean\n}\n\n/**\n * Agent control UI\n *\n * Architecture:\n * - History list: renders directly from agent.history (historical events)\n * - Header bar: shows activity events (transient state) and agent status\n *\n * This separation ensures data consistency - history is the single source of truth\n * for what has been done, while activity shows what is happening now.\n */\nexport class UI {\n\t#wrapper: HTMLElement\n\t#indicator: HTMLElement\n\t#statusText: HTMLElement\n\t#historySection: HTMLElement\n\t#expandButton: HTMLElement\n\t#actionButton: HTMLElement\n\t#inputSection: HTMLElement\n\t#taskInput: HTMLInputElement\n\n\t#agent: UIAdapter\n\t#config: UIConfig\n\t#isExpanded = false\n\t#i18n: I18n\n\t#userAnswerResolver: ((input: string) => void) | null = null\n\t#userAnswerRejecter: ((reason: DOMException) => void) | null = null\n\t#userAnswerSignal: AbortSignal | null = null\n\t#userAnswerAbortHandler: (() => void) | null = null\n\t#isWaitingForUserAnswer: boolean = false\n\t#headerUpdateTimer: ReturnType<typeof setInterval> | null = null\n\t#timers = new Set<ReturnType<typeof setTimeout>>()\n\t#pendingHeaderText: string | null = null\n\t#isAnimating = false\n\t#disposed = false\n\n\t// Event handlers (bound for removal)\n\t#onStatusChange = () => this.#handleStatusChange()\n\t#onHistoryChange = () => this.#handleHistoryChange()\n\t#onActivity = (e: Event) => this.#handleActivity((e as CustomEvent<AgentActivity>).detail)\n\t#onAgentDispose = () => this.dispose()\n\t#askUserCallback = (question: string, options?: { signal: AbortSignal }) =>\n\t\tthis.#askUser(question, options?.signal)\n\n\tget wrapper(): HTMLElement {\n\t\treturn this.#wrapper\n\t}\n\n\t/**\n\t * Create a UI bound to an agent\n\t * @param agent - Agent instance that implements UIAdapter\n\t * @param config - Optional UI configuration\n\t */\n\tconstructor(agent: UIAdapter, config: UIConfig = {}) {\n\t\tthis.#agent = agent\n\t\tthis.#config = config\n\t\tthis.#i18n = new I18n(config.language ?? 'en-US')\n\n\t\t// Set up askUser callback on agent\n\t\tthis.#agent.onAskUser = this.#askUserCallback\n\n\t\t// Create UI elements\n\t\tthis.#wrapper = this.#createWrapper()\n\t\tthis.#indicator = this.#wrapper.querySelector(`.${styles.indicator}`)!\n\t\tthis.#statusText = this.#wrapper.querySelector(`.${styles.statusText}`)!\n\t\tthis.#historySection = this.#wrapper.querySelector(`.${styles.historySection}`)!\n\t\tthis.#expandButton = this.#wrapper.querySelector(`.${styles.expandButton}`)!\n\t\tthis.#actionButton = this.#wrapper.querySelector(`.${styles.stopButton}`)!\n\t\tthis.#inputSection = this.#wrapper.querySelector(`.${styles.inputSectionWrapper}`)!\n\t\tthis.#taskInput = this.#wrapper.querySelector(`.${styles.taskInput}`)!\n\n\t\t// Listen to agent events\n\t\tthis.#agent.addEventListener('statuschange', this.#onStatusChange)\n\t\tthis.#agent.addEventListener('historychange', this.#onHistoryChange)\n\t\tthis.#agent.addEventListener('activity', this.#onActivity)\n\t\tthis.#agent.addEventListener('dispose', this.#onAgentDispose)\n\n\t\tthis.#setupEventListeners()\n\t\tthis.#startHeaderUpdateLoop()\n\n\t\tthis.#showInputArea()\n\n\t\tthis.hide() // Start hidden\n\t}\n\n\t// ========== Agent event handlers ==========\n\n\t/** Handle agent status change */\n\t#handleStatusChange(): void {\n\t\tconst status = this.#agent.status\n\n\t\t// Map agent status to UI indicator. A `completed` run whose result reports\n\t\t// failure shows as error; other statuses map to their own indicator.\n\t\tconst failed = status === 'completed' && this.#agent.lastResult?.success === false\n\t\tthis.#updateStatusIndicator(failed ? 'error' : status)\n\n\t\t// Morph action button: running = stop (■), not running = close (X)\n\t\tif (status === 'running') {\n\t\t\tthis.#actionButton.textContent = '■'\n\t\t\tthis.#actionButton.title = this.#i18n.t('ui.stop')\n\t\t} else {\n\t\t\tthis.#actionButton.textContent = 'X'\n\t\t\tthis.#actionButton.title = this.#i18n.t('ui.close')\n\t\t}\n\n\t\t// Show/hide based on status\n\t\tif (status === 'running') {\n\t\t\tthis.show()\n\t\t\tthis.#hideInputArea() // Hide input while running\n\t\t}\n\n\t\t// Handle completion\n\t\tif (status === 'completed' || status === 'error' || status === 'stopped') {\n\t\t\tif (!this.#isExpanded) {\n\t\t\t\tthis.#expand()\n\t\t\t}\n\t\t\tif (this.#shouldShowInputArea()) {\n\t\t\t\tthis.#showInputArea()\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Handle agent history change - re-render history list from agent.history */\n\t#handleHistoryChange(): void {\n\t\tthis.#renderHistory()\n\t}\n\n\t/**\n\t * Handle agent activity - transient state for immediate UI feedback\n\t * Activity events are NOT persisted in history, only used for header bar updates\n\t */\n\t#handleActivity(activity: AgentActivity): void {\n\t\tswitch (activity.type) {\n\t\t\tcase 'thinking':\n\t\t\t\tthis.#pendingHeaderText = this.#i18n.t('ui.thinking')\n\t\t\t\tthis.#updateStatusIndicator('thinking')\n\t\t\t\tbreak\n\n\t\t\tcase 'executing':\n\t\t\t\tthis.#pendingHeaderText = this.#getToolExecutingText(activity.tool, activity.input)\n\t\t\t\tthis.#updateStatusIndicator('executing')\n\t\t\t\tbreak\n\n\t\t\tcase 'executed':\n\t\t\t\tthis.#pendingHeaderText = truncate(activity.output, 50)\n\t\t\t\tbreak\n\n\t\t\tcase 'retrying':\n\t\t\t\tthis.#pendingHeaderText = `Retrying (${activity.attempt}/${activity.maxAttempts})`\n\t\t\t\tthis.#updateStatusIndicator('retrying')\n\t\t\t\tbreak\n\n\t\t\tcase 'error':\n\t\t\t\tthis.#pendingHeaderText = truncate(activity.message, 50)\n\t\t\t\tthis.#updateStatusIndicator('error')\n\t\t\t\tbreak\n\t\t}\n\t}\n\n\t/**\n\t * Ask for user input (internal, called by agent via onAskUser).\n\t * Rejects when `signal` aborts (task stopped or disposed), cleaning up the\n\t * question card and pending state so the agent loop can settle.\n\t */\n\t#askUser(question: string, signal?: AbortSignal): Promise<string> {\n\t\tif (this.#disposed) return Promise.reject(this.#createAbortError())\n\t\tthis.#rejectPendingQuestion()\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\t// Set `waiting for user answer` state\n\t\t\tthis.#isWaitingForUserAnswer = true\n\t\t\tthis.#userAnswerResolver = resolve\n\t\t\tthis.#userAnswerRejecter = reject\n\n\t\t\t// Expand history UI\n\t\t\tif (!this.#isExpanded) {\n\t\t\t\tthis.#expand()\n\t\t\t}\n\n\t\t\t// Add temporary question card so user can see the full question\n\t\t\tconst tempCard = document.createElement('div')\n\t\t\ttempCard.innerHTML = createCard({\n\t\t\t\ticon: '❓',\n\t\t\t\tcontent: `Question: ${question}`,\n\t\t\t\ttype: 'question',\n\t\t\t})\n\t\t\tconst cardElement = tempCard.firstElementChild as HTMLElement\n\t\t\tcardElement.setAttribute('data-temp-card', 'true')\n\t\t\tthis.#historySection.appendChild(cardElement)\n\t\t\tthis.#scrollToBottom()\n\n\t\t\tthis.#showInputArea(this.#i18n.t('ui.userAnswerPrompt'))\n\n\t\t\tif (signal) {\n\t\t\t\tthis.#userAnswerSignal = signal\n\t\t\t\tthis.#userAnswerAbortHandler = () => this.#rejectPendingQuestion()\n\t\t\t\tif (signal.aborted) {\n\t\t\t\t\tthis.#rejectPendingQuestion()\n\t\t\t\t} else {\n\t\t\t\t\tsignal.addEventListener('abort', this.#userAnswerAbortHandler, { once: true })\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n\n\t#createAbortError(): DOMException {\n\t\treturn new DOMException('The operation was aborted.', 'AbortError')\n\t}\n\n\t#clearQuestionState(): void {\n\t\tif (this.#userAnswerSignal && this.#userAnswerAbortHandler) {\n\t\t\tthis.#userAnswerSignal.removeEventListener('abort', this.#userAnswerAbortHandler)\n\t\t}\n\t\tthis.#userAnswerSignal = null\n\t\tthis.#userAnswerAbortHandler = null\n\t\tthis.#userAnswerResolver = null\n\t\tthis.#userAnswerRejecter = null\n\t\tthis.#isWaitingForUserAnswer = false\n\t\tthis.#removeTempCards()\n\t}\n\n\t#rejectPendingQuestion(): void {\n\t\tconst reject = this.#userAnswerRejecter\n\t\tif (!reject) return\n\t\tthis.#clearQuestionState()\n\t\treject(this.#createAbortError())\n\t}\n\n\t/** Remove temporary question cards (only direct children for safety) */\n\t#removeTempCards(): void {\n\t\tArray.from(this.#historySection.children).forEach((child) => {\n\t\t\tif (child.getAttribute('data-temp-card') === 'true') {\n\t\t\t\tchild.remove()\n\t\t\t}\n\t\t})\n\t}\n\n\t// ========== Public control methods ==========\n\n\tshow(): void {\n\t\tthis.wrapper.style.display = 'block'\n\t\tvoid this.wrapper.offsetHeight\n\t\tthis.wrapper.style.opacity = '1'\n\t\tthis.wrapper.style.transform = 'translateX(-50%) translateY(0)'\n\t}\n\n\thide(): void {\n\t\tthis.wrapper.style.opacity = '0'\n\t\tthis.wrapper.style.transform = 'translateX(-50%) translateY(20px)'\n\t\tthis.wrapper.style.display = 'none'\n\t}\n\n\treset(): void {\n\t\tthis.#rejectPendingQuestion()\n\t\tthis.#statusText.textContent = this.#i18n.t('ui.ready')\n\t\tthis.#updateStatusIndicator('thinking')\n\t\tthis.#renderHistory()\n\t\tthis.#collapse()\n\t\t// Show input area\n\t\tthis.#showInputArea()\n\t}\n\n\texpand(): void {\n\t\tthis.#expand()\n\t}\n\n\tcollapse(): void {\n\t\tthis.#collapse()\n\t}\n\n\t/**\n\t * Dispose UI and clean up event listeners\n\t */\n\tdispose(): void {\n\t\tif (this.#disposed) return\n\t\tthis.#disposed = true\n\n\t\t// Remove agent event listeners\n\t\tthis.#agent.removeEventListener('statuschange', this.#onStatusChange)\n\t\tthis.#agent.removeEventListener('historychange', this.#onHistoryChange)\n\t\tthis.#agent.removeEventListener('activity', this.#onActivity)\n\t\tthis.#agent.removeEventListener('dispose', this.#onAgentDispose)\n\t\tif (this.#agent.onAskUser === this.#askUserCallback) {\n\t\t\tthis.#agent.onAskUser = undefined\n\t\t}\n\n\t\t// Clean up UI\n\t\tthis.#rejectPendingQuestion()\n\t\tthis.#clearQuestionState()\n\t\tthis.#stopHeaderUpdateLoop()\n\t\tfor (const timer of this.#timers) clearTimeout(timer)\n\t\tthis.#timers.clear()\n\t\tthis.wrapper.remove()\n\t}\n\n\t// ========== Private methods ==========\n\n\t#getToolExecutingText(toolName: string, args: unknown): string {\n\t\tconst a = args as Record<string, string | number>\n\t\tswitch (toolName) {\n\t\t\tcase 'click_element_by_index':\n\t\t\t\treturn this.#i18n.t('ui.tools.clicking', { index: a.index })\n\t\t\tcase 'input_text':\n\t\t\t\treturn this.#i18n.t('ui.tools.inputting', { index: a.index })\n\t\t\tcase 'select_dropdown_option':\n\t\t\t\treturn this.#i18n.t('ui.tools.selecting', { text: a.text })\n\t\t\tcase 'scroll':\n\t\t\t\treturn this.#i18n.t('ui.tools.scrolling')\n\t\t\tcase 'wait':\n\t\t\t\treturn this.#i18n.t('ui.tools.waiting', { seconds: a.seconds })\n\t\t\tcase 'ask_user':\n\t\t\t\treturn this.#i18n.t('ui.tools.askingUser')\n\t\t\tcase 'done':\n\t\t\t\treturn this.#i18n.t('ui.tools.done')\n\t\t\tdefault:\n\t\t\t\treturn this.#i18n.t('ui.tools.executing', { toolName })\n\t\t}\n\t}\n\n\t/**\n\t * Action button handler: stop when running, close (dispose) when idle\n\t */\n\t#handleActionButton(): void {\n\t\tif (this.#agent.status === 'running') {\n\t\t\tthis.#agent.stop()\n\t\t} else {\n\t\t\tthis.#agent.dispose()\n\t\t}\n\t}\n\n\t/**\n\t * Submit task\n\t */\n\t#submitTask() {\n\t\tconst input = this.#taskInput.value.trim()\n\t\tif (!input) return\n\n\t\t// Hide input area\n\t\tthis.#hideInputArea()\n\n\t\tif (this.#isWaitingForUserAnswer) {\n\t\t\t// Handle user input mode\n\t\t\tthis.#handleUserAnswer(input)\n\t\t} else {\n\t\t\t// Execute task via agent\n\t\t\tvoid this.#agent.execute(input).catch((error: unknown) => {\n\t\t\t\tif ((error as { name?: string })?.name === 'AbortError') return\n\t\t\t\tconsole.error('[UI] Failed to execute task:', error)\n\t\t\t\tif (!this.#disposed) this.#showInputArea()\n\t\t\t})\n\t\t}\n\t}\n\n\t/**\n\t * Handle user answer\n\t */\n\t#handleUserAnswer(input: string): void {\n\t\tthis.#removeTempCards()\n\n\t\t// Call resolver to return user input\n\t\tconst resolve = this.#userAnswerResolver\n\t\tthis.#clearQuestionState()\n\t\tresolve?.(input)\n\t}\n\n\t/**\n\t * Show input area\n\t */\n\t#showInputArea(placeholder?: string): void {\n\t\t// Clear input field\n\t\tthis.#taskInput.value = ''\n\t\tthis.#taskInput.placeholder = placeholder || this.#i18n.t('ui.taskInput')\n\t\tthis.#inputSection.classList.remove(styles.hidden)\n\t\t// Focus on input field\n\t\tthis.#setTimer(() => {\n\t\t\tthis.#taskInput.focus()\n\t\t}, 100)\n\t}\n\n\t/**\n\t * Hide input area\n\t */\n\t#hideInputArea(): void {\n\t\tthis.#inputSection.classList.add(styles.hidden)\n\t}\n\n\t/**\n\t * Check if input area should be shown\n\t */\n\t#shouldShowInputArea(): boolean {\n\t\t// Always show input area if waiting for user input\n\t\tif (this.#isWaitingForUserAnswer) return true\n\n\t\tconst history = this.#agent.history\n\t\tif (history.length === 0) {\n\t\t\treturn true // Initial state\n\t\t}\n\n\t\tconst status = this.#agent.status\n\t\tconst isTaskEnded = status === 'completed' || status === 'error' || status === 'stopped'\n\n\t\t// Only show input area after task completion if configured to do so\n\t\tif (isTaskEnded) {\n\t\t\treturn this.#config.promptForNextTask ?? true\n\t\t}\n\n\t\treturn false\n\t}\n\n\t#createWrapper(): HTMLElement {\n\t\tconst taskInputMaxLength = 1000\n\t\tconst wrapper = document.createElement('div')\n\t\twrapper.id = 'my-page-agent-runtime_agent-ui'\n\t\twrapper.className = styles.wrapper\n\t\twrapper.setAttribute('data-browser-use-ignore', 'true')\n\t\twrapper.setAttribute('data-page-agent-ignore', 'true')\n\n\t\twrapper.innerHTML = `\n\t\t\t<div class=\"${styles.background}\"></div>\n\t\t\t<div class=\"${styles.historySectionWrapper}\">\n\t\t\t\t<div class=\"${styles.historySection}\">\n\t\t\t\t\t<div class=\"${styles.historyItem}\">\n\t\t\t\t\t\t<div class=\"${styles.historyContent}\">\n\t\t\t\t\t\t\t<span class=\"${styles.statusIcon}\">🧠</span>\n\t\t\t\t\t\t\t<span>${this.#i18n.t('ui.waitingPlaceholder')}</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div class=\"${styles.header}\">\n\t\t\t\t<div class=\"${styles.statusSection}\">\n\t\t\t\t\t<div class=\"${styles.indicator} ${styles.thinking}\"></div>\n\t\t\t\t\t<div class=\"${styles.statusText}\">${this.#i18n.t('ui.ready')}</div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"${styles.controls}\">\n\t\t\t\t\t<button class=\"${styles.controlButton} ${styles.expandButton}\" title=\"${this.#i18n.t('ui.expand')}\">\n\t\t\t\t\t\t▼\n\t\t\t\t\t</button>\n\t\t\t\t\t<button class=\"${styles.controlButton} ${styles.stopButton}\" title=\"${this.#i18n.t('ui.close')}\">\n\t\t\t\t\t\tX\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div class=\"${styles.inputSectionWrapper} ${styles.hidden}\">\n\t\t\t\t<div class=\"${styles.inputSection}\">\n\t\t\t\t\t<input \n\t\t\t\t\t\ttype=\"text\" \n\t\t\t\t\t\tclass=\"${styles.taskInput}\" \n\t\t\t\t\t\tmaxlength=\"${taskInputMaxLength}\"\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t`\n\n\t\tdocument.body.appendChild(wrapper)\n\t\treturn wrapper\n\t}\n\n\t#setupEventListeners(): void {\n\t\t// Click header area to expand/collapse\n\t\tconst header = this.wrapper.querySelector(`.${styles.header}`)!\n\t\theader.addEventListener('click', (e) => {\n\t\t\t// Don't trigger expand/collapse if clicking on buttons\n\t\t\tif ((e.target as HTMLElement).closest(`.${styles.controlButton}`)) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.#toggle()\n\t\t})\n\n\t\t// Expand button\n\t\tthis.#expandButton.addEventListener('click', (e) => {\n\t\t\te.stopPropagation()\n\t\t\tthis.#toggle()\n\t\t})\n\n\t\t// Action button (stop / close)\n\t\tthis.#actionButton.addEventListener('click', (e) => {\n\t\t\te.stopPropagation()\n\t\t\tthis.#handleActionButton()\n\t\t})\n\n\t\t// Submit on Enter key in input field\n\t\tthis.#taskInput.addEventListener('keydown', (e) => {\n\t\t\tif (e.isComposing) return // Ignore IME composition keys\n\t\t\tif (e.key === 'Enter') {\n\t\t\t\te.preventDefault()\n\t\t\t\tthis.#submitTask()\n\t\t\t}\n\t\t})\n\n\t\t// Prevent input area click event bubbling\n\t\tthis.#inputSection.addEventListener('click', (e) => {\n\t\t\te.stopPropagation()\n\t\t})\n\t}\n\n\t#toggle(): void {\n\t\tif (this.#isExpanded) {\n\t\t\tthis.#collapse()\n\t\t} else {\n\t\t\tthis.#expand()\n\t\t}\n\t}\n\n\t#expand(): void {\n\t\tthis.#isExpanded = true\n\t\tthis.wrapper.classList.add(styles.expanded)\n\t\tthis.#expandButton.textContent = '▲'\n\t}\n\n\t#collapse(): void {\n\t\tthis.#isExpanded = false\n\t\tthis.wrapper.classList.remove(styles.expanded)\n\t\tthis.#expandButton.textContent = '▼'\n\t}\n\n\t/**\n\t * Start periodic header update loop\n\t */\n\t#startHeaderUpdateLoop(): void {\n\t\t// Check every 450ms (same as total animation duration)\n\t\tthis.#headerUpdateTimer = setInterval(() => {\n\t\t\tthis.#checkAndUpdateHeader()\n\t\t}, 450)\n\t}\n\n\t/**\n\t * Stop periodic header update loop\n\t */\n\t#stopHeaderUpdateLoop(): void {\n\t\tif (this.#headerUpdateTimer) {\n\t\t\tclearInterval(this.#headerUpdateTimer)\n\t\t\tthis.#headerUpdateTimer = null\n\t\t}\n\t}\n\n\t#setTimer(callback: () => void, delay: number): void {\n\t\tconst timer = setTimeout(() => {\n\t\t\tthis.#timers.delete(timer)\n\t\t\tif (!this.#disposed) callback()\n\t\t}, delay)\n\t\tthis.#timers.add(timer)\n\t}\n\n\t/**\n\t * Check if header needs update and trigger animation if not currently animating\n\t */\n\t#checkAndUpdateHeader(): void {\n\t\t// If no pending text or currently animating, skip\n\t\tif (!this.#pendingHeaderText || this.#isAnimating) {\n\t\t\treturn\n\t\t}\n\n\t\t// If text is already displayed, clear pending and skip\n\t\tif (this.#statusText.textContent === this.#pendingHeaderText) {\n\t\t\tthis.#pendingHeaderText = null\n\t\t\treturn\n\t\t}\n\n\t\t// Start animation\n\t\tconst textToShow = this.#pendingHeaderText\n\t\tthis.#pendingHeaderText = null\n\t\tthis.#animateTextChange(textToShow)\n\t}\n\n\t/**\n\t * Animate text change with fade out/in effect\n\t */\n\t#animateTextChange(newText: string): void {\n\t\tthis.#isAnimating = true\n\n\t\t// Fade out current text\n\t\tthis.#statusText.classList.add(styles.fadeOut)\n\n\t\tthis.#setTimer(() => {\n\t\t\t// Update text content\n\t\t\tthis.#statusText.textContent = newText\n\n\t\t\t// Fade in new text\n\t\t\tthis.#statusText.classList.remove(styles.fadeOut)\n\t\t\tthis.#statusText.classList.add(styles.fadeIn)\n\n\t\t\tthis.#setTimer(() => {\n\t\t\t\tthis.#statusText.classList.remove(styles.fadeIn)\n\t\t\t\tthis.#isAnimating = false\n\t\t\t}, 300)\n\t\t}, 150) // Half the duration of fade out animation\n\t}\n\n\t#updateStatusIndicator(\n\t\ttype:\n\t\t\t| 'idle'\n\t\t\t| 'running'\n\t\t\t| 'thinking'\n\t\t\t| 'executing'\n\t\t\t| 'executed'\n\t\t\t| 'retrying'\n\t\t\t| 'completed'\n\t\t\t| 'error'\n\t\t\t| 'stopped'\n\t): void {\n\t\t// `running` animates like thinking; `idle`/`stopped` use the neutral base.\n\t\tconst variant =\n\t\t\ttype === 'running'\n\t\t\t\t? 'thinking'\n\t\t\t\t: type === 'executing'\n\t\t\t\t\t? 'tool_executing'\n\t\t\t\t\t: type === 'retrying'\n\t\t\t\t\t\t? 'retry'\n\t\t\t\t\t\t: type\n\t\tthis.#indicator.className = styles.indicator\n\t\tif (variant !== 'idle' && variant !== 'stopped') {\n\t\t\tthis.#indicator.classList.add(styles[variant])\n\t\t}\n\t}\n\n\t#scrollToBottom(): void {\n\t\t// Execute in next event loop to ensure DOM update completion\n\t\tthis.#setTimer(() => {\n\t\t\tthis.#historySection.scrollTop = this.#historySection.scrollHeight\n\t\t}, 0)\n\t}\n\n\t/**\n\t * Render history directly from agent.history\n\t *\n\t * Renders:\n\t * 1. Task (first item, from agent.task)\n\t * 2. Reflection cards (evaluation, memory, next_goal)\n\t * 3. Tool execution with output\n\t * 4. Observations\n\t */\n\t#renderHistory(): void {\n\t\tconst items: string[] = []\n\n\t\t// 1. Task card (always first)\n\t\tconst task = this.#agent.task\n\t\tif (task) {\n\t\t\titems.push(this.#createTaskCard(task))\n\t\t}\n\n\t\t// 2. Render each history event\n\t\tconst history = this.#agent.history\n\t\tfor (const event of history) {\n\t\t\titems.push(...this.#createHistoryCards(event))\n\t\t}\n\n\t\tthis.#historySection.innerHTML = items.join('')\n\t\tthis.#scrollToBottom()\n\t}\n\n\t#createTaskCard(task: string): string {\n\t\treturn createCard({ icon: '🎯', content: task, type: 'input' })\n\t}\n\n\t/** Create cards for a history event */\n\t#createHistoryCards(event: UIAdapter['history'][number]): string[] {\n\t\tconst cards: string[] = []\n\t\tconst meta =\n\t\t\tevent.type === 'step' && event.stepIndex !== undefined\n\t\t\t\t? this.#i18n.t('ui.step', {\n\t\t\t\t\t\tnumber: (event.stepIndex + 1).toString(),\n\t\t\t\t\t})\n\t\t\t\t: undefined\n\n\t\tif (event.type === 'step') {\n\t\t\t// Reflection card\n\t\t\tif (event.reflection) {\n\t\t\t\tconst lines = createReflectionLines(event.reflection)\n\t\t\t\tif (lines.length > 0) {\n\t\t\t\t\tcards.push(createCard({ icon: '🧠', content: lines, meta }))\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Action card\n\t\t\tconst action = event.action\n\t\t\tif (action) {\n\t\t\t\tcards.push(...this.#createActionCards(action, meta))\n\t\t\t}\n\t\t} else if (event.type === 'observation') {\n\t\t\tcards.push(\n\t\t\t\tcreateCard({ icon: '👁️', content: event.content || '', meta, type: 'observation' })\n\t\t\t)\n\t\t} else if (event.type === 'user_takeover') {\n\t\t\tcards.push(createCard({ icon: '👤', content: 'User takeover', meta, type: 'input' }))\n\t\t} else if (event.type === 'retry') {\n\t\t\tconst retryInfo = `${event.message || 'Retrying'} (${event.attempt}/${event.maxAttempts})`\n\t\t\tcards.push(createCard({ icon: '🔄', content: retryInfo, meta, type: 'observation' }))\n\t\t} else if (event.type === 'error') {\n\t\t\tcards.push(\n\t\t\t\tcreateCard({ icon: '❌', content: event.message || 'Error', meta, type: 'observation' })\n\t\t\t)\n\t\t}\n\n\t\treturn cards\n\t}\n\n\t/** Create cards for an action */\n\t#createActionCards(\n\t\taction: { name: string; input: unknown; output: string },\n\t\tmeta?: string\n\t): string[] {\n\t\tconst cards: string[] = []\n\n\t\tif (action.name === 'done') {\n\t\t\tconst input = action.input as { text?: string; success?: boolean }\n\t\t\tconst text = input.text || action.output || ''\n\t\t\tif (text) {\n\t\t\t\tcards.push(\n\t\t\t\t\tcreateCard({\n\t\t\t\t\t\ticon: '🤖',\n\t\t\t\t\t\tcontent: text,\n\t\t\t\t\t\tmeta,\n\t\t\t\t\t\ttype: input.success === true ? 'doneSuccess' : 'doneError',\n\t\t\t\t\t})\n\t\t\t\t)\n\t\t\t}\n\t\t} else if (action.name === 'ask_user') {\n\t\t\tconst input = action.input as { question?: string }\n\t\t\tconst answer = action.output.replace(/^User answered:\\s*/i, '')\n\t\t\tcards.push(\n\t\t\t\tcreateCard({\n\t\t\t\t\ticon: '❓',\n\t\t\t\t\tcontent: `Question: ${input.question || ''}`,\n\t\t\t\t\tmeta,\n\t\t\t\t\ttype: 'question',\n\t\t\t\t})\n\t\t\t)\n\t\t\tcards.push(createCard({ icon: '💬', content: `Answer: ${answer}`, meta, type: 'input' }))\n\t\t} else {\n\t\t\tconst toolText = this.#getToolExecutingText(action.name, action.input)\n\t\t\tcards.push(createCard({ icon: '🔨', content: toolText, meta }))\n\t\t\tif (action.output?.length > 0) {\n\t\t\t\tcards.push(createCard({ icon: '🔨', content: action.output, meta, type: 'output' }))\n\t\t\t}\n\t\t}\n\n\t\treturn cards\n\t}\n}\n","/**\n * Error types and error handling for LLM invocations.\n */\n\nexport const InvokeErrorTypes = {\n\t// Retryable\n\tNETWORK_ERROR: 'network_error', // Network error, retry\n\tRATE_LIMIT: 'rate_limit', // Rate limit, retry\n\tSERVER_ERROR: 'server_error', // 5xx, retry\n\tNO_TOOL_CALL: 'no_tool_call', // Model did not call tool\n\tINVALID_TOOL_ARGS: 'invalid_tool_args', // Tool args don't match schema\n\tTOOL_EXECUTION_ERROR: 'tool_execution_error', // Tool execution error\n\tINVALID_RESPONSE: 'invalid_response', // Response body is not valid JSON\n\tINVALID_SCHEMA: 'invalid_schema', // Response is valid JSON but doesn't match expected shape\n\n\tUNKNOWN: 'unknown',\n\n\t// Non-retryable\n\tCONFIG_ERROR: 'config_error', // Invalid local configuration or hook\n\tAUTH_ERROR: 'auth_error', // Authentication failed\n\tCONTEXT_LENGTH: 'context_length', // Prompt too long\n\tCONTENT_FILTER: 'content_filter', // Content filtered\n} as const\n\ntype InvokeErrorType = (typeof InvokeErrorTypes)[keyof typeof InvokeErrorTypes]\n\nconst RETRYABLE_TYPES: readonly InvokeErrorType[] = [\n\tInvokeErrorTypes.NETWORK_ERROR,\n\tInvokeErrorTypes.RATE_LIMIT,\n\tInvokeErrorTypes.SERVER_ERROR,\n\tInvokeErrorTypes.NO_TOOL_CALL,\n\tInvokeErrorTypes.INVALID_TOOL_ARGS,\n\tInvokeErrorTypes.TOOL_EXECUTION_ERROR,\n\tInvokeErrorTypes.INVALID_RESPONSE,\n\tInvokeErrorTypes.INVALID_SCHEMA,\n\tInvokeErrorTypes.UNKNOWN,\n]\n\nexport class InvokeError extends Error {\n\ttype: InvokeErrorType\n\tretryable: boolean\n\tstatusCode?: number\n\t/* raw error (provided if this error is caused by another error) */\n\trawError?: unknown\n\t/* raw response from the API (provided if this error is caused by an API calling) */\n\trawResponse?: unknown\n\n\tconstructor(type: InvokeErrorType, message: string, rawError?: unknown, rawResponse?: unknown) {\n\t\tsuper(message)\n\t\tthis.name = 'InvokeError'\n\t\tthis.type = type\n\t\tthis.retryable = RETRYABLE_TYPES.includes(type)\n\t\tthis.rawError = rawError\n\t\tthis.rawResponse = rawResponse\n\t}\n}\n","/**\n * Utility functions for LLM integration\n */\nimport chalk from 'chalk'\nimport * as z from 'zod/v4'\n\nimport type { Tool } from './types'\n\nconst debug = console.debug.bind(console, chalk.gray('[LLM]'))\n\n/**\n * Convert Zod schema to OpenAI tool format\n * Uses Zod 4 native z.toJSONSchema()\n */\nexport function zodToOpenAITool(name: string, tool: Tool) {\n\treturn {\n\t\ttype: 'function' as const,\n\t\tfunction: {\n\t\t\tname,\n\t\t\tdescription: tool.description,\n\t\t\tparameters: z.toJSONSchema(tool.inputSchema, { target: 'openapi-3.0' }),\n\t\t},\n\t}\n}\n\n/**\n * Patch model specific parameters. Only patches known models.\n *\n * @purpose\n * - Reconcile the differences in the parameter schema each model accepts.\n * - Disable thinking/reasoning, or lower it to the minimum where a full disable is impossible.\n * - Minimize returned tokens.\n * - Raise temperature for known smaller models to improve auto-recovery odds.\n * @note Honor temperature if explicitly set by the user\n *\n * @todo Need vendor-specific patches.\n * Local and 3rd-party hosted models may have different schema.\n */\nexport function modelPatch(body: Record<string, any>, baseURL?: string) {\n\tconst model: string = body.model || ''\n\tif (!model) return body\n\n\tconst provider = getProvider(baseURL)\n\n\tconst modelName = normalizeModelName(model)\n\n\tif (modelName.startsWith('qwen')) {\n\t\tdebug('Patch Qwen: disable thinking')\n\t\tbody.enable_thinking = false\n\t\tif (body.temperature === undefined && !/max|plus/.test(modelName)) {\n\t\t\tdebug('Patch Qwen: raise temperature to 1.0')\n\t\t\tbody.temperature = 1.0\n\t\t}\n\t}\n\n\tif (modelName.startsWith('deepseek')) {\n\t\tdebug('Patch DeepSeek: disable thinking, remove tool_choice')\n\t\tbody.thinking = { type: 'disabled' }\n\t\tdelete body.tool_choice\n\t}\n\n\tif (modelName.startsWith('gpt')) {\n\t\tif (modelName.startsWith('gpt-5')) {\n\t\t\tbody.verbosity = 'low'\n\t\t}\n\n\t\t// Since gpt-5.4, /chat/completions rejects any explicit reasoning_effort\n\t\t// when function tools are present. Newer models are expected to follow.\n\t\t// - gpt-5.1 / gpt-5.2 can fully disable reasoning\n\t\t// - gpt-5 / -mini / -nano bottom out at \"minimal\"\n\t\t// - everything else (gpt-4.x, chat-latest, gpt-5.4+) must not receive it\n\t\tif (modelName.includes('chat-latest')) {\n\t\t\tdebug('Patch chat-latest: omit reasoning_effort and temperature')\n\t\t\tdelete body.reasoning_effort\n\t\t\tdelete body.temperature\n\t\t} else if (/^gpt-5[12](-|$)/.test(modelName)) {\n\t\t\tdebug('Patch GPT-5.1/5.2: reasoning_effort=none')\n\t\t\tbody.reasoning_effort = 'none'\n\t\t} else if (/^gpt-5(-|$)/.test(modelName)) {\n\t\t\tdebug('Patch GPT-5: reasoning_effort=minimal')\n\t\t\tbody.reasoning_effort = 'minimal'\n\t\t} else {\n\t\t\tdebug('Patch GPT: omit reasoning_effort')\n\t\t\tdelete body.reasoning_effort\n\t\t}\n\t}\n\n\tif (modelName.startsWith('claude')) {\n\t\tif (/opus|sonnet|haiku/.test(modelName)) {\n\t\t\tdebug('Patch Claude: disable thinking')\n\t\t\tbody.thinking = { type: 'disabled' }\n\n\t\t\tif (provider !== 'openrouter') {\n\t\t\t\t// Convert tool_choice to Claude format\n\t\t\t\tif (body.tool_choice === 'required') {\n\t\t\t\t\t// 'required' -> { type: 'any' } (must call some tool)\n\t\t\t\t\tdebug('Applying Claude patch: convert tool_choice \"required\" to { type: \"any\" }')\n\t\t\t\t\tbody.tool_choice = { type: 'any' }\n\t\t\t\t} else if (body.tool_choice?.function?.name) {\n\t\t\t\t\t// { type: 'function', function: { name: '...' } } -> { type: 'tool', name: '...' }\n\t\t\t\t\tdebug('Applying Claude patch: convert tool_choice format')\n\t\t\t\t\tbody.tool_choice = { type: 'tool', name: body.tool_choice.function.name }\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tdebug('Patch Claude: reasoning_effort=low')\n\t\t\tbody.reasoning_effort = 'low'\n\n\t\t\t// Fable and mythos can not disable adaptive thinking.\n\t\t\t// Claude does not support tool_choice with extended thinking.\n\t\t\t// These 2 concepts are blurred. Basically no tool_choice with thinking.\n\t\t\tdelete body.tool_choice\n\t\t}\n\t}\n\n\tif (modelName.startsWith('gemini')) {\n\t\tdebug('Patch Gemini: reasoning_effort=low')\n\t\tbody.reasoning_effort = 'low'\n\t\tif (/^gemini-25(?!.*pro)/.test(modelName)) {\n\t\t\tdebug('Patch Gemini 2.5 non-Pro: reasoning_effort=none')\n\t\t\tbody.reasoning_effort = 'none'\n\t\t} else if (\n\t\t\tmodelName.startsWith('gemini-35-flash') ||\n\t\t\tmodelName.startsWith('gemini-31-flash-lite') ||\n\t\t\tmodelName.startsWith('gemini-3-flash')\n\t\t) {\n\t\t\tdebug('Patch Gemini 3.x Flash/Lite: reasoning_effort=minimal')\n\t\t\tbody.reasoning_effort = 'minimal'\n\t\t}\n\t}\n\n\tif (modelName.startsWith('glm')) {\n\t\tdebug('Patch GLM: disable thinking')\n\t\tbody.thinking = { type: 'disabled' }\n\t}\n\n\tif (modelName.startsWith('hy')) {\n\t\tdebug('Patch Hunyuan: disable thinking, reasoning_effort=low')\n\t\tbody.thinking = { type: 'disabled' }\n\t\tbody.reasoning_effort = 'low'\n\t}\n\n\tif (modelName.startsWith('grok')) {\n\t\tif (/^grok-4-?3/.test(modelName)) {\n\t\t\tdebug('Patch Grok 4.3: reasoning_effort=none')\n\t\t\tbody.reasoning_effort = 'none'\n\t\t} else if (modelName.startsWith('grok-3-mini') || modelName.startsWith('grok-code-fast')) {\n\t\t\tdebug('Patch Grok mini/code: reasoning_effort=low')\n\t\t\tbody.reasoning_effort = 'low'\n\t\t}\n\t}\n\n\tif (modelName.startsWith('kimi')) {\n\t\tif (modelName.startsWith('kimi-k3')) {\n\t\t\t// Kimi K3 always thinks and rejects named tool choice while thinking.\n\t\t\tdebug('Patch Kimi K3: use required tool choice, remove parallel tool calls')\n\t\t\tdelete body.parallel_tool_calls\n\t\t\tif (body.tool_choice?.function?.name) body.tool_choice = 'required'\n\t\t} else if (!modelName.includes('code')) {\n\t\t\t// kimi-k2.7-code cannot disable thinking\n\t\t\tdebug('Patch Kimi: disable thinking')\n\t\t\tbody.thinking = { type: 'disabled' }\n\t\t}\n\t}\n\n\tif (modelName.startsWith('minimax')) {\n\t\tdebug('Patch MiniMax: remove parallel_tool_calls')\n\t\tdelete body.parallel_tool_calls\n\n\t\tif (modelName.includes('m3')) {\n\t\t\t// Only M3 can disable thinking\n\t\t\tdebug('Patch MiniMax: disable thinking')\n\t\t\tbody.thinking = { type: 'disabled' }\n\t\t}\n\t}\n\n\t// provider patches\n\n\tif (provider === 'openrouter') {\n\t\t// openrouter use reasoning object instead of reasoning_effort\n\n\t\tconst reasoningEffort = body.reasoning_effort\n\t\tconst reasoningDisabled =\n\t\t\tbody.thinking?.type === 'disabled' ||\n\t\t\tbody.enable_thinking === false ||\n\t\t\treasoningEffort === 'none'\n\n\t\tif (reasoningDisabled) {\n\t\t\tbody.reasoning = { enabled: false }\n\t\t} else if (reasoningEffort) {\n\t\t\tbody.reasoning = { enabled: true, effort: reasoningEffort }\n\t\t}\n\t}\n\n\treturn body\n}\n\n/**\n * check if a given model ID fits a specific model name\n *\n * @note\n * Different model providers may use different model IDs for the same model.\n * For example, openai's `gpt-5.2` may called:\n *\n * - `gpt-5.2-version`\n * - `gpt-5_2-date`\n * - `GPT-52-version-date`\n * - `openai/gpt-5.2-chat`\n *\n * They should be treated as the same model.\n * Normalize them to `gpt-52`\n */\nexport function normalizeModelName(modelName: string): string {\n\tlet normalizedName = modelName.toLowerCase()\n\n\t// remove prefix before '/'\n\tif (normalizedName.includes('/')) {\n\t\tnormalizedName = normalizedName.split('/')[1]\n\t}\n\n\t// remove '_'\n\tnormalizedName = normalizedName.replace(/_/g, '')\n\n\t// remove '.'\n\tnormalizedName = normalizedName.replace(/\\./g, '')\n\n\treturn normalizedName\n}\n\nexport function getProvider(baseURL?: string): 'openrouter' | undefined {\n\tif (!baseURL) return undefined\n\ttry {\n\t\tconst url = new URL(baseURL)\n\t\tconst hostname = url.hostname\n\t\tif (hostname === 'openrouter.ai') return 'openrouter'\n\t\treturn undefined\n\t} catch {\n\t\treturn undefined\n\t}\n}\n","/**\n * OpenAI Client implementation\n */\nimport * as z from 'zod/v4'\n\nimport { InvokeError, InvokeErrorTypes } from './errors'\nimport type {\n\tInvokeOptions,\n\tInvokeResult,\n\tLLMClient,\n\tMessage,\n\tResolvedLLMConfig,\n\tTool,\n} from './types'\nimport { modelPatch, zodToOpenAITool } from './utils'\n\n/**\n * Client for OpenAI compatible APIs\n */\nexport class OpenAICompatibleClient implements LLMClient {\n\tconfig: ResolvedLLMConfig\n\tprivate fetch: typeof globalThis.fetch\n\n\tconstructor(config: ResolvedLLMConfig) {\n\t\tthis.config = config\n\t\tthis.fetch = config.customFetch\n\t}\n\n\tasync invoke(\n\t\tmessages: Message[],\n\t\ttools: Record<string, Tool>,\n\t\tabortSignal?: AbortSignal,\n\t\toptions?: InvokeOptions\n\t): Promise<InvokeResult> {\n\t\tabortSignal?.throwIfAborted()\n\n\t\t// 1. Convert tools to OpenAI format\n\t\tconst openaiTools = Object.entries(tools).map(([name, t]) => zodToOpenAITool(name, t))\n\n\t\t// Build request body\n\n\t\tlet toolChoice: unknown = 'required'\n\t\tif (options?.toolChoiceName && !this.config.disableNamedToolChoice) {\n\t\t\ttoolChoice = { type: 'function', function: { name: options.toolChoiceName } }\n\t\t}\n\n\t\tconst requestBody: Record<string, unknown> = {\n\t\t\tmodel: this.config.model,\n\t\t\tmessages,\n\t\t\ttools: openaiTools,\n\t\t\tparallel_tool_calls: false,\n\t\t\ttool_choice: toolChoice,\n\t\t}\n\t\t// Only sent if the caller explicitly set it. Most new models throw if this is set.\n\t\tif (this.config.temperature !== undefined) {\n\t\t\trequestBody.temperature = this.config.temperature\n\t\t}\n\n\t\tmodelPatch(requestBody, this.config.baseURL)\n\n\t\tlet transformedBody: Record<string, unknown> | undefined\n\t\ttry {\n\t\t\ttransformedBody = this.config.transformRequestBody(requestBody)\n\t\t} catch (error) {\n\t\t\tthrow new InvokeError(\n\t\t\t\tInvokeErrorTypes.CONFIG_ERROR,\n\t\t\t\t`transformRequestBody failed: ${(error as Error).message}`,\n\t\t\t\terror\n\t\t\t)\n\t\t}\n\t\tconst finalRequestBody = transformedBody ?? requestBody\n\n\t\t// 2. Call API\n\t\tlet response: Response\n\t\ttry {\n\t\t\tresponse = await this.fetch(`${this.config.baseURL}/chat/completions`, {\n\t\t\t\tmethod: 'POST',\n\t\t\t\theaders: {\n\t\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t\t...(this.config.apiKey && { Authorization: `Bearer ${this.config.apiKey}` }),\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify(finalRequestBody),\n\t\t\t\tsignal: abortSignal,\n\t\t\t})\n\t\t} catch (error: unknown) {\n\t\t\tif ((error as any)?.name === 'AbortError') throw error\n\t\t\tconsole.error(error)\n\t\t\tthrow new InvokeError(InvokeErrorTypes.NETWORK_ERROR, 'Network request failed', error)\n\t\t}\n\n\t\t// 3. Handle HTTP errors\n\t\tif (!response.ok) {\n\t\t\tlet errorData: any\n\t\t\ttry {\n\t\t\t\terrorData = await response.json()\n\t\t\t} catch (error) {\n\t\t\t\tif ((error as any)?.name === 'AbortError') throw error\n\t\t\t}\n\t\t\tconst errorMessage = errorData?.error?.message || response.statusText\n\n\t\t\tif (response.status === 401 || response.status === 403) {\n\t\t\t\tthrow new InvokeError(\n\t\t\t\t\tInvokeErrorTypes.AUTH_ERROR,\n\t\t\t\t\t`Authentication failed: ${errorMessage}`,\n\t\t\t\t\terrorData\n\t\t\t\t)\n\t\t\t}\n\t\t\tif (response.status === 429) {\n\t\t\t\tthrow new InvokeError(\n\t\t\t\t\tInvokeErrorTypes.RATE_LIMIT,\n\t\t\t\t\t`Rate limit exceeded: ${errorMessage}`,\n\t\t\t\t\terrorData\n\t\t\t\t)\n\t\t\t}\n\t\t\tif (response.status >= 500) {\n\t\t\t\tthrow new InvokeError(\n\t\t\t\t\tInvokeErrorTypes.SERVER_ERROR,\n\t\t\t\t\t`Server error: ${errorMessage}`,\n\t\t\t\t\terrorData\n\t\t\t\t)\n\t\t\t}\n\t\t\tthrow new InvokeError(\n\t\t\t\tInvokeErrorTypes.UNKNOWN,\n\t\t\t\t`HTTP ${response.status}: ${errorMessage}`,\n\t\t\t\terrorData\n\t\t\t)\n\t\t}\n\n\t\t// 4. Parse and validate response\n\t\tlet data: any\n\t\ttry {\n\t\t\tdata = await response.json()\n\t\t} catch (error) {\n\t\t\tif ((error as any)?.name === 'AbortError') throw error\n\t\t\tthrow new InvokeError(\n\t\t\t\tInvokeErrorTypes.INVALID_RESPONSE,\n\t\t\t\t'Response body is not valid JSON',\n\t\t\t\terror\n\t\t\t)\n\t\t}\n\n\t\tconst choice = data.choices?.[0]\n\t\tif (!choice) {\n\t\t\tthrow new InvokeError(InvokeErrorTypes.INVALID_SCHEMA, 'No choices in response', data)\n\t\t}\n\n\t\t// Check finish_reason\n\t\tswitch (choice.finish_reason) {\n\t\t\tcase 'tool_calls':\n\t\t\tcase 'function_call': // gemini\n\t\t\tcase 'stop': // some models use this even with tool calls\n\t\t\t\tbreak\n\t\t\tcase 'length':\n\t\t\t\tthrow new InvokeError(\n\t\t\t\t\tInvokeErrorTypes.CONTEXT_LENGTH,\n\t\t\t\t\t'Response truncated: max tokens reached',\n\t\t\t\t\tundefined,\n\t\t\t\t\tdata\n\t\t\t\t)\n\t\t\tcase 'content_filter':\n\t\t\t\tthrow new InvokeError(\n\t\t\t\t\tInvokeErrorTypes.CONTENT_FILTER,\n\t\t\t\t\t'Content filtered by safety system',\n\t\t\t\t\tundefined,\n\t\t\t\t\tdata\n\t\t\t\t)\n\t\t\tdefault:\n\t\t\t\tthrow new InvokeError(\n\t\t\t\t\tInvokeErrorTypes.INVALID_SCHEMA,\n\t\t\t\t\t`Unexpected finish_reason: ${choice.finish_reason}`,\n\t\t\t\t\tundefined,\n\t\t\t\t\tdata\n\t\t\t\t)\n\t\t}\n\n\t\t// Apply normalizeResponse if provided (for fixing format issues automatically)\n\t\tconst normalizedData = options?.normalizeResponse ? options.normalizeResponse(data) : data\n\t\tconst normalizedChoice = (normalizedData as any).choices?.[0]\n\n\t\t// Get tool name from response\n\t\tconst toolCallName = normalizedChoice?.message?.tool_calls?.[0]?.function?.name\n\t\tif (!toolCallName) {\n\t\t\tthrow new InvokeError(\n\t\t\t\tInvokeErrorTypes.NO_TOOL_CALL,\n\t\t\t\t'No tool call found in response',\n\t\t\t\tundefined,\n\t\t\t\tdata\n\t\t\t)\n\t\t}\n\n\t\tconst tool = tools[toolCallName]\n\t\tif (!tool) {\n\t\t\tthrow new InvokeError(\n\t\t\t\tInvokeErrorTypes.UNKNOWN,\n\t\t\t\t`Tool \"${toolCallName}\" not found in tools`,\n\t\t\t\tundefined,\n\t\t\t\tdata\n\t\t\t)\n\t\t}\n\n\t\t// Extract and parse tool arguments\n\t\tconst argString = normalizedChoice.message?.tool_calls?.[0]?.function?.arguments\n\t\tif (!argString) {\n\t\t\tthrow new InvokeError(\n\t\t\t\tInvokeErrorTypes.INVALID_TOOL_ARGS,\n\t\t\t\t'No tool call arguments found',\n\t\t\t\tundefined,\n\t\t\t\tdata\n\t\t\t)\n\t\t}\n\n\t\tlet parsedArgs: unknown\n\t\ttry {\n\t\t\tparsedArgs = JSON.parse(argString)\n\t\t} catch (error) {\n\t\t\tthrow new InvokeError(\n\t\t\t\tInvokeErrorTypes.INVALID_TOOL_ARGS,\n\t\t\t\t'Failed to parse tool arguments as JSON',\n\t\t\t\terror,\n\t\t\t\tdata\n\t\t\t)\n\t\t}\n\n\t\t// Validate with schema\n\t\tconst validation = tool.inputSchema.safeParse(parsedArgs)\n\t\tif (!validation.success) {\n\t\t\tconsole.error(z.prettifyError(validation.error))\n\t\t\tthrow new InvokeError(\n\t\t\t\tInvokeErrorTypes.INVALID_TOOL_ARGS,\n\t\t\t\t'Tool arguments validation failed',\n\t\t\t\tvalidation.error,\n\t\t\t\tdata\n\t\t\t)\n\t\t}\n\t\tconst toolInput = validation.data\n\n\t\t// 5. Execute tool\n\t\tlet toolResult: unknown\n\t\ttry {\n\t\t\ttoolResult = await tool.execute(toolInput)\n\t\t} catch (error: unknown) {\n\t\t\tif ((error as any)?.name === 'AbortError') throw error\n\t\t\tthrow new InvokeError(\n\t\t\t\tInvokeErrorTypes.TOOL_EXECUTION_ERROR,\n\t\t\t\t`Tool execution failed: ${(error as Error)?.message}`,\n\t\t\t\terror,\n\t\t\t\tdata\n\t\t\t)\n\t\t}\n\n\t\t// Return result\n\t\treturn {\n\t\t\ttoolCall: {\n\t\t\t\tname: toolCallName,\n\t\t\t\targs: toolInput,\n\t\t\t},\n\t\t\ttoolResult,\n\t\t\tusage: {\n\t\t\t\tpromptTokens: data.usage?.prompt_tokens ?? 0,\n\t\t\t\tcompletionTokens: data.usage?.completion_tokens ?? 0,\n\t\t\t\ttotalTokens: data.usage?.total_tokens ?? 0,\n\t\t\t\tcachedTokens: data.usage?.prompt_tokens_details?.cached_tokens,\n\t\t\t\treasoningTokens: data.usage?.completion_tokens_details?.reasoning_tokens,\n\t\t\t},\n\t\t\trawResponse: data,\n\t\t\trawRequest: finalRequestBody,\n\t\t}\n\t}\n}\n","import { OpenAICompatibleClient } from './OpenAICompatibleClient'\nimport { InvokeError, InvokeErrorTypes } from './errors'\nimport type {\n\tInvokeOptions,\n\tInvokeResult,\n\tLLMClient,\n\tLLMConfig,\n\tMessage,\n\tResolvedLLMConfig,\n\tTool,\n} from './types'\n\nexport { InvokeError, InvokeErrorTypes }\nexport type { InvokeOptions, InvokeResult, LLMClient, LLMConfig, Message, Tool }\n\n/**\n * LLM module\n */\nexport class LLM extends EventTarget {\n\tconfig: ResolvedLLMConfig\n\tclient: LLMClient\n\n\tconstructor(config: LLMConfig) {\n\t\tsuper()\n\t\tthis.config = parseLLMConfig(config)\n\n\t\t// Default to OpenAI client\n\t\tthis.client = new OpenAICompatibleClient(this.config)\n\t}\n\n\t/**\n\t * - call llm api *once*\n\t * - invoke tool call *once*\n\t * - return the result of the tool\n\t */\n\tasync invoke(\n\t\tmessages: Message[],\n\t\ttools: Record<string, Tool>,\n\t\tabortSignal: AbortSignal,\n\t\toptions?: InvokeOptions\n\t): Promise<InvokeResult> {\n\t\treturn await withRetry(async () => this.client.invoke(messages, tools, abortSignal, options), {\n\t\t\tmaxRetries: this.config.maxRetries,\n\t\t\tonRetry: (attempt, lastError) => {\n\t\t\t\tthis.dispatchEvent(\n\t\t\t\t\tnew CustomEvent('retry', {\n\t\t\t\t\t\tdetail: { attempt, maxAttempts: this.config.maxRetries, lastError },\n\t\t\t\t\t})\n\t\t\t\t)\n\t\t\t},\n\t\t})\n\t}\n}\n\n/**\n * Retry a function until it succeeds or reaches the maximum number of retries.\n */\nasync function withRetry<T>(\n\tfn: () => Promise<T>,\n\tsettings: {\n\t\tmaxRetries: number\n\t\tonRetry: (attempt: number, lastError: Error) => void\n\t}\n): Promise<T> {\n\tlet attempt = 0\n\twhile (true) {\n\t\ttry {\n\t\t\treturn await fn()\n\t\t} catch (error: unknown) {\n\t\t\tif ((error as any)?.name === 'AbortError') throw error\n\t\t\tif (error instanceof InvokeError && !error.retryable) throw error\n\t\t\tattempt++\n\t\t\tif (attempt > settings.maxRetries) throw error\n\n\t\t\tconsole.debug('[LLM] retryable failure, will retry:', error)\n\t\t\tsettings.onRetry(attempt, error as Error)\n\n\t\t\tawait new Promise((resolve) => setTimeout(resolve, 100))\n\t\t}\n\t}\n}\n\nexport function parseLLMConfig(config: LLMConfig): ResolvedLLMConfig {\n\t// Runtime validation as defensive programming (types already guarantee these)\n\tif (!config.baseURL || !config.model) {\n\t\tthrow new Error(\n\t\t\t'[PageAgent] LLM configuration required. Please provide: baseURL, model. ' +\n\t\t\t\t'See: https://alibaba.github.io/page-agent/docs/features/models'\n\t\t)\n\t}\n\n\tif (config.temperature !== undefined) {\n\t\tconsole.warn(\n\t\t\t'[PageAgent] LLMConfig.temperature is deprecated and will be removed in a future version. ' +\n\t\t\t\t'Use transformRequestBody to set it only for models you have verified accept it.'\n\t\t)\n\t}\n\n\treturn {\n\t\tbaseURL: config.baseURL,\n\t\tmodel: config.model,\n\t\tapiKey: config.apiKey || '',\n\t\ttemperature: config.temperature,\n\t\tmaxRetries: config.maxRetries ?? 2,\n\t\ttransformRequestBody: config.transformRequestBody ?? ((requestBody) => requestBody),\n\t\tdisableNamedToolChoice: config.disableNamedToolChoice ?? false,\n\t\tcustomFetch: (config.customFetch ?? fetch).bind(globalThis), // fetch will be illegal unless bound\n\t}\n}\n","import { InvokeError, InvokeErrorTypes } from '../../llm/errors'\nimport chalk from 'chalk'\nimport * as z from 'zod/v4'\n\nimport type { AgentTool } from '../tools'\n\nconst log = console.log.bind(console, chalk.yellow('[autoFixer]'))\n\n/**\n * Normalize LLM response and fix common format issues.\n *\n * Handles:\n * - No tool_calls but JSON in message.content (fallback)\n * - Model returns action name as tool call instead of AgentOutput\n * - Arguments wrapped as double JSON string\n * - Nested function call format\n * - Missing action field (fallback to wait)\n * - Primitive action input for single-field tools (e.g. `{\"click_element_by_index\": 2}`)\n * - etc.\n */\nexport function normalizeResponse(response: any, tools?: Map<string, AgentTool>): any {\n\tlet resolvedArguments: any\n\n\tconst choice = (response as { choices?: Choice[] }).choices?.[0]\n\tif (!choice) throw new Error('No choices in response')\n\n\tconst message = choice.message\n\tif (!message) throw new Error('No message in choice')\n\n\tconst toolCall = message.tool_calls?.[0]\n\n\t// fix level and location of arguments\n\n\tif (toolCall?.function?.arguments) {\n\t\tresolvedArguments = safeJsonParse(toolCall.function.arguments)\n\n\t\t// case: sometimes the model only returns the action level\n\t\tif (toolCall.function.name && toolCall.function.name !== 'AgentOutput') {\n\t\t\tlog(`#1: fixing tool_call`)\n\t\t\tresolvedArguments = { action: safeJsonParse(resolvedArguments) }\n\t\t}\n\t} else {\n\t\t// case: sometimes the model returns json in content instead of tool_calls\n\t\tif (message.content) {\n\t\t\tconst content = message.content.trim()\n\t\t\tconst jsonInContent = retrieveJsonFromString(content)\n\t\t\tif (jsonInContent) {\n\t\t\t\tresolvedArguments = safeJsonParse(jsonInContent)\n\n\t\t\t\t// case: sometimes the content json includes upper level wrapper\n\t\t\t\tif (resolvedArguments?.name === 'AgentOutput') {\n\t\t\t\t\tlog(`#2: fixing tool_call`)\n\t\t\t\t\tresolvedArguments = safeJsonParse(resolvedArguments.arguments)\n\t\t\t\t}\n\n\t\t\t\t// case: sometimes even 2-levels of wrapping\n\t\t\t\tif (resolvedArguments?.type === 'function') {\n\t\t\t\t\tlog(`#3: fixing tool_call`)\n\t\t\t\t\tresolvedArguments = safeJsonParse(resolvedArguments.function.arguments)\n\t\t\t\t}\n\n\t\t\t\t// case: and sometimes action level only\n\t\t\t\t// todo: needs better detection logic\n\t\t\t\tif (\n\t\t\t\t\t!resolvedArguments?.action &&\n\t\t\t\t\t!resolvedArguments?.evaluation_previous_goal &&\n\t\t\t\t\t!resolvedArguments?.memory &&\n\t\t\t\t\t!resolvedArguments?.next_goal &&\n\t\t\t\t\t!resolvedArguments?.thinking\n\t\t\t\t) {\n\t\t\t\t\tlog(`#4: fixing tool_call`)\n\t\t\t\t\tresolvedArguments = { action: safeJsonParse(resolvedArguments) }\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthrow new Error('No tool_call and the message content does not contain valid JSON')\n\t\t\t}\n\t\t} else {\n\t\t\tthrow new Error('No tool_call nor message content is present')\n\t\t}\n\t}\n\n\t// fix double stringified arguments\n\tresolvedArguments = safeJsonParse(resolvedArguments)\n\tif (resolvedArguments.action) {\n\t\tresolvedArguments.action = safeJsonParse(resolvedArguments.action)\n\t}\n\n\t// validate and fix action input using tool schemas\n\tif (resolvedArguments.action && tools) {\n\t\tresolvedArguments.action = validateAction(resolvedArguments.action, tools)\n\t}\n\n\t// fix incomplete formats\n\tif (!resolvedArguments.action) {\n\t\tlog(`#5: fixing tool_call`)\n\t\tresolvedArguments.action = { wait: { seconds: 1 } }\n\t}\n\n\t// pack back to standard format\n\treturn {\n\t\t...response,\n\t\tchoices: [\n\t\t\t{\n\t\t\t\t...choice,\n\t\t\t\tmessage: {\n\t\t\t\t\t...message,\n\t\t\t\t\ttool_calls: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t...(toolCall || {}),\n\t\t\t\t\t\t\tfunction: {\n\t\t\t\t\t\t\t\t...(toolCall?.function || {}),\n\t\t\t\t\t\t\t\tname: 'AgentOutput',\n\t\t\t\t\t\t\t\targuments: JSON.stringify(resolvedArguments),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t}\n}\n\n/**\n * Validate action against tool schemas. Provides clear error messages\n * instead of letting the union schema produce unreadable errors.\n *\n * Also coerces primitive inputs for single-field tools:\n * e.g. `{\"click_element_by_index\": 2}` → `{\"click_element_by_index\": {\"index\": 2}}`\n */\nfunction validateAction(action: any, tools: Map<string, AgentTool>): any {\n\tif (typeof action !== 'object' || action === null) return action\n\n\tconst toolName = Object.keys(action)[0]\n\tif (!toolName) return action\n\n\tconst tool = tools.get(toolName)\n\tif (!tool) {\n\t\tconst available = Array.from(tools.keys()).join(', ')\n\t\tthrow new InvokeError(\n\t\t\tInvokeErrorTypes.INVALID_TOOL_ARGS,\n\t\t\t`Unknown action \"${toolName}\". Available: ${available}`\n\t\t)\n\t}\n\n\tlet value = action[toolName]\n\tconst schema = tool.inputSchema\n\n\t// coerce primitive input for single-field tools\n\tif (schema instanceof z.ZodObject && value !== null && typeof value !== 'object') {\n\t\tconst requiredKey = Object.keys(schema.shape).find(\n\t\t\t(k) => !(schema.shape as Record<string, z.ZodType>)[k].safeParse(undefined).success\n\t\t)\n\t\tif (requiredKey) {\n\t\t\tlog(`coercing primitive action input for \"${toolName}\"`)\n\t\t\tvalue = { [requiredKey]: value }\n\t\t}\n\t}\n\n\tconst result = schema.safeParse(value)\n\tif (!result.success) {\n\t\tthrow new InvokeError(\n\t\t\tInvokeErrorTypes.INVALID_TOOL_ARGS,\n\t\t\t`Invalid input for action \"${toolName}\": ${z.prettifyError(result.error)}`\n\t\t)\n\t}\n\n\treturn { [toolName]: result.data }\n}\n\n/**\n * Safely parse JSON, return original input if not json.\n */\nfunction safeJsonParse(input: any): any {\n\tif (typeof input === 'string') {\n\t\ttry {\n\t\t\treturn JSON.parse(input.trim())\n\t\t} catch {\n\t\t\treturn input\n\t\t}\n\t}\n\treturn input\n}\n\n/**\n * Extract and parse JSON from a string.\n * - Treat content between the first `{` and the last `}` as JSON.\n * - Try to parse that content as JSON and return the parsed value (object/array/primitive) if successful, otherwise return null.\n */\nfunction retrieveJsonFromString(str: string): any {\n\ttry {\n\t\tconst json = /({[\\s\\S]*})/.exec(str) ?? []\n\t\tif (json.length === 0) {\n\t\t\treturn null\n\t\t}\n\t\treturn JSON.parse(json[0]!)\n\t} catch {\n\t\treturn null\n\t}\n}\n\ninterface Choice {\n\tmessage?: {\n\t\trole?: 'assistant'\n\t\tcontent?: string\n\t\ttool_calls?: {\n\t\t\tid?: string\n\t\t\ttype?: 'function'\n\t\t\tfunction?: {\n\t\t\t\tname?: string\n\t\t\t\targuments?: string\n\t\t\t}\n\t\t}[]\n\t}\n\tindex?: 0\n\tfinish_reason?: 'tool_calls'\n}\n","import chalk from 'chalk'\n\nexport * from './autoFixer'\n\n/**\n * Wait for `seconds`. If a `signal` is provided, the wait is cancellable:\n * aborting rejects with the signal's reason (an `AbortError`).\n */\nexport async function waitFor(seconds: number, signal?: AbortSignal): Promise<void> {\n\tif (!signal) {\n\t\tawait new Promise((resolve) => setTimeout(resolve, seconds * 1000))\n\t\treturn\n\t}\n\tsignal.throwIfAborted()\n\tawait new Promise<void>((resolve, reject) => {\n\t\tconst timer = setTimeout(() => {\n\t\t\tsignal.removeEventListener('abort', onAbort)\n\t\t\tresolve()\n\t\t}, seconds * 1000)\n\t\tconst onAbort = () => {\n\t\t\tclearTimeout(timer)\n\t\t\t// reason is a DOMException AbortError.\n\t\t\treject(signal.reason as DOMException)\n\t\t}\n\t\tsignal.addEventListener('abort', onAbort, { once: true })\n\t})\n}\n\n//\n\nexport function truncate(text: string, maxLength: number): string {\n\tif (text.length > maxLength) {\n\t\treturn text.substring(0, maxLength) + '...'\n\t}\n\treturn text\n}\n\n//\n\nexport function randomID(existingIDs?: string[]): string {\n\tlet id = Math.random().toString(36).substring(2, 11)\n\n\tif (!existingIDs) {\n\t\treturn id\n\t}\n\n\tconst MAX_TRY = 1000\n\tlet tryCount = 0\n\n\twhile (existingIDs.includes(id)) {\n\t\tid = Math.random().toString(36).substring(2, 11)\n\t\ttryCount++\n\t\tif (tryCount > MAX_TRY) {\n\t\t\tthrow new Error('randomID: too many tries')\n\t\t}\n\t}\n\n\treturn id\n}\n\n//\nconst _global = globalThis as any\n\nif (!_global.__PAGE_AGENT_IDS__) {\n\t_global.__PAGE_AGENT_IDS__ = []\n}\n\nconst ids = _global.__PAGE_AGENT_IDS__\n\n/**\n * Generate a random ID.\n * @note Unique within this window.\n */\nexport function uid() {\n\tconst id = randomID(ids)\n\tids.push(id)\n\treturn id\n}\n\nconst llmsTxtCache = new Map<string, string | null>()\n\n/** Fetch /llms.txt for a URL's origin. Cached per origin, `null` = tried and not found. */\nexport async function fetchLlmsTxt(url: string): Promise<string | null> {\n\tlet origin: string\n\ttry {\n\t\torigin = new URL(url).origin\n\t} catch {\n\t\treturn null // Invalid URL\n\t}\n\t// about:blank, data:, file:\n\tif (origin === 'null') return null\n\n\tif (llmsTxtCache.has(origin)) return llmsTxtCache.get(origin)!\n\n\tconst endpoint = `${origin}/llms.txt`\n\tlet result: string | null = null\n\ttry {\n\t\tconsole.log(chalk.gray(`[llms.txt] Fetching ${endpoint}`))\n\t\tconst res = await fetch(endpoint, { signal: AbortSignal.timeout(3000) })\n\t\tif (res.ok) {\n\t\t\tresult = await res.text()\n\t\t\tconsole.log(chalk.green(`[llms.txt] Found (${result.length} chars)`))\n\t\t\tif (result.length > 1000) {\n\t\t\t\tconsole.log(chalk.yellow(`[llms.txt] Truncating to 1000 chars`))\n\t\t\t\tresult = truncate(result, 1000)\n\t\t\t}\n\t\t} else {\n\t\t\tconsole.debug(chalk.gray(`[llms.txt] ${res.status} for ${endpoint}`))\n\t\t}\n\t} catch (e) {\n\t\tconsole.debug(chalk.gray(`[llms.txt] not found for ${endpoint}`), e)\n\t}\n\tllmsTxtCache.set(origin, result)\n\treturn result\n}\n\n/**\n * Simple assertion function that throws an error if the condition is falsy\n * @param condition - The condition to assert\n * @param message - Optional error message\n * @throws Error if condition is falsy\n */\nexport function assert(condition: unknown, message?: string, silent?: boolean): asserts condition {\n\tif (!condition) {\n\t\tconst errorMessage = message ?? 'Assertion failed'\n\n\t\tif (!silent) console.error(chalk.red(`❌ assert: ${errorMessage}`))\n\n\t\tthrow new Error(errorMessage)\n\t}\n}\n\n/**\n * Suppress errors from a function.\n */\nexport async function suppress<T>(fn: () => T | Promise<T>): Promise<Awaited<T> | undefined> {\n\ttry {\n\t\treturn await fn()\n\t} catch (error) {\n\t\tconsole.error(error)\n\t\treturn undefined\n\t}\n}\n","/**\n * Internal tools for PageAgent.\n * @note Adapted from browser-use\n */\nimport * as z from 'zod/v4'\n\nimport type { AgentRuntime } from '../AgentRuntime'\nimport { waitFor } from '../utils'\n\n/**\n * Per-invocation context passed to every tool execution.\n * Tools MUST honor `signal` to support cooperative cancellation.\n */\nexport interface ToolContext {\n\tsignal: AbortSignal\n}\n\n/**\n * Internal tool definition that has access to PageAgent `this` context\n */\nexport interface AgentTool<TParams = any> {\n\t// name: string\n\tdescription: string\n\tinputSchema: z.ZodType<TParams>\n\texecute: (this: AgentRuntime, args: TParams, ctx: ToolContext) => Promise<string>\n}\n\nexport function tool<TParams>(options: AgentTool<TParams>): AgentTool<TParams> {\n\treturn options\n}\n\n/**\n * Internal tools for PageAgent.\n * Note: Using any to allow different parameter types for each tool\n */\nexport const tools = new Map<string, AgentTool>()\n\ntools.set(\n\t'done',\n\ttool({\n\t\tdescription:\n\t\t\t'Complete task. Text is your final response to the user — keep it concise unless the user explicitly asks for detail.',\n\t\tinputSchema: z.object({\n\t\t\ttext: z.string(),\n\t\t\tsuccess: z.boolean().default(true),\n\t\t}),\n\t\texecute: async function (this: AgentRuntime, _input) {\n\t\t\t// @note main loop will handle this one\n\t\t\treturn Promise.resolve('Task completed')\n\t\t},\n\t})\n)\n\ntools.set(\n\t'wait',\n\ttool({\n\t\tdescription: 'Wait for x seconds. Can be used to wait until the page or data is fully loaded.',\n\t\tinputSchema: z.object({\n\t\t\tseconds: z.number().min(1).max(10).default(1),\n\t\t}),\n\t\texecute: async function (this: AgentRuntime, input, { signal }) {\n\t\t\t// try to subtract LLM calling time from the actual wait time\n\t\t\tconst lastTimeUpdate = await this.browserController.getLastUpdateTime()\n\t\t\tconst secondsSinceLastUpdate = (Date.now() - lastTimeUpdate) / 1000\n\t\t\tconst actualWaitTime = Math.max(0, input.seconds - secondsSinceLastUpdate)\n\t\t\tconsole.log(`actualWaitTime: ${actualWaitTime} seconds`)\n\t\t\tawait waitFor(actualWaitTime, signal)\n\n\t\t\tconst waitedSeconds = (secondsSinceLastUpdate + actualWaitTime).toFixed(2)\n\t\t\treturn `✅ Waited for ${waitedSeconds} seconds.`\n\t\t},\n\t})\n)\n\ntools.set(\n\t'ask_user',\n\ttool({\n\t\tdescription:\n\t\t\t'Ask the user a question and wait for their answer. Use this if you need more information or clarification.',\n\t\tinputSchema: z.object({\n\t\t\tquestion: z.string(),\n\t\t}),\n\t\texecute: async function (this: AgentRuntime, input, { signal }) {\n\t\t\tif (!this.onAskUser) {\n\t\t\t\tthrow new Error('ask_user tool requires onAskUser callback to be set')\n\t\t\t}\n\t\t\tconst answer = await this.onAskUser(input.question, { signal })\n\t\t\treturn `User answered: ${answer}`\n\t\t},\n\t})\n)\n\ntools.set(\n\t'click_element_by_index',\n\ttool({\n\t\tdescription: 'Click element by index',\n\t\tinputSchema: z.object({\n\t\t\tindex: z.int().min(0),\n\t\t}),\n\t\texecute: async function (this: AgentRuntime, input) {\n\t\t\tconst result = await this.browserController.clickElement(input.index)\n\t\t\treturn result.message\n\t\t},\n\t})\n)\n\ntools.set(\n\t'input_text',\n\ttool({\n\t\tdescription: 'Click and type text into an interactive input element',\n\t\tinputSchema: z.object({\n\t\t\tindex: z.int().min(0),\n\t\t\ttext: z.string(),\n\t\t}),\n\t\texecute: async function (this: AgentRuntime, input) {\n\t\t\tconst result = await this.browserController.inputText(input.index, input.text)\n\t\t\treturn result.message\n\t\t},\n\t})\n)\n\ntools.set(\n\t'select_dropdown_option',\n\ttool({\n\t\tdescription:\n\t\t\t'Select dropdown option for interactive element index by the text of the option you want to select',\n\t\tinputSchema: z.object({\n\t\t\tindex: z.int().min(0),\n\t\t\ttext: z.string(),\n\t\t}),\n\t\texecute: async function (this: AgentRuntime, input) {\n\t\t\tconst result = await this.browserController.selectOption(input.index, input.text)\n\t\t\treturn result.message\n\t\t},\n\t})\n)\n\n/**\n * @note Reference from browser-use\n */\ntools.set(\n\t'scroll',\n\ttool({\n\t\tdescription:\n\t\t\t'Scroll vertically. Without index: scrolls the document. With index: scrolls the container at that index (or its nearest scrollable ancestor). Use index of a data-scrollable element to scroll a specific area.',\n\t\tinputSchema: z.object({\n\t\t\tdown: z.boolean().default(true),\n\t\t\tnum_pages: z.number().min(0).max(10).optional().default(0.1),\n\t\t\tpixels: z.number().int().min(0).optional(),\n\t\t\tindex: z.number().int().min(0).optional(),\n\t\t}),\n\t\texecute: async function (this: AgentRuntime, input) {\n\t\t\tconst result = await this.browserController.scroll({\n\t\t\t\t...input,\n\t\t\t\tnumPages: input.num_pages,\n\t\t\t})\n\t\t\treturn result.message\n\t\t},\n\t})\n)\n\n/**\n * @todo Tables need a dedicated parser to extract structured data. This tool is useless.\n */\ntools.set(\n\t'scroll_horizontally',\n\ttool({\n\t\tdescription:\n\t\t\t'Scroll horizontally. Without index: scrolls the document. With index: scrolls the container at that index (or its nearest scrollable ancestor). Use index of a data-scrollable element to scroll a specific area.',\n\t\tinputSchema: z.object({\n\t\t\tright: z.boolean().default(true),\n\t\t\tpixels: z.number().int().min(0),\n\t\t\tindex: z.number().int().min(0).optional(),\n\t\t}),\n\t\texecute: async function (this: AgentRuntime, input) {\n\t\t\tconst result = await this.browserController.scrollHorizontally(input)\n\t\t\treturn result.message\n\t\t},\n\t})\n)\n\ntools.set(\n\t'execute_javascript',\n\ttool({\n\t\tdescription:\n\t\t\t'Execute JavaScript code on the current page. Supports async/await syntax. Use with caution! ' +\n\t\t\t'An `AbortSignal` named `signal` is available in scope: long-running async code MUST honor it ' +\n\t\t\t'(e.g. `await fetch(url, { signal })`, or `signal.throwIfAborted()` in loops)',\n\t\tinputSchema: z.object({\n\t\t\tscript: z.string(),\n\t\t}),\n\t\texecute: async function (this: AgentRuntime, input, { signal }) {\n\t\t\tconst result = await this.browserController.executeJavascript(input.script, signal)\n\t\t\tsignal.throwIfAborted()\n\t\t\treturn result.message\n\t\t},\n\t})\n)\n\n// @todo send_keys\n// @todo upload_file\n// @todo extract_structured_data\n","/**\n * Copyright (C) 2025 Alibaba Group Holding Limited\n * Copyright (C) 2026 SimonLuvRamen\n * All rights reserved.\n */\nimport type { BrowserState } from '../browser/dom'\nimport type { BrowserController } from '../browser/BrowserController'\nimport { InvokeError } from '../llm/errors'\nimport { LLM } from '../llm/LLM'\nimport type { Tool } from '../llm/types'\nimport chalk from 'chalk'\nimport * as z from 'zod/v4'\n\nimport SYSTEM_PROMPT from './prompts/system_prompt.md?raw'\nimport { tools } from './tools'\nimport type {\n\tAgentActivity,\n\tAgentConfig,\n\tAgentReflection,\n\tAgentStatus,\n\tAgentStepEvent,\n\tExecutionResult,\n\tHistoricalEvent,\n\tMacroToolInput,\n\tMacroToolResult,\n} from './types'\nimport { assert, fetchLlmsTxt, normalizeResponse, suppress, uid, waitFor } from './utils'\n\nexport { tool, type AgentTool, type ToolContext } from './tools'\nexport type * from './types'\n\nexport type AgentRuntimeConfig = AgentConfig & { browserController: BrowserController }\n\n/**\n * AI agent for browser automation.\n *\n * @remarks\n * ## Re-act Agent Loop\n * - step\n * - observe (gather information about current environment and context)\n * - think (LLM calling)\n * - reflection (evaluate history, generate memory, short-term planning)\n * - action (give the action to approach the next goal)\n * - act (execute the action)\n * - loop\n *\n * ## Event System\n * - `statuschange` - Agent status transitions (idle → running → completed/error/stopped)\n * - `historychange` - History events updated (persistent, part of agent memory)\n * - `activity` - Real-time activity feedback (transient, for UI only)\n * - `dispose` - Agent cleanup triggered\n *\n * ## Information Streams\n * 1. **History Events** (`history` array)\n * - Persistent event stream that forms agent's memory\n * - Included in LLM context across steps\n * - Types: steps, observations, user takeovers, llm errors\n *\n * 2. **Activity Events** (via `activity` event)\n * - Transient UI feedback during task execution\n * - NOT included in LLM context\n * - Types: thinking, executing, executed, retrying, error\n */\nexport class AgentRuntime extends EventTarget {\n\treadonly id = uid()\n\treadonly config: AgentRuntimeConfig & { maxSteps: number }\n\treadonly tools: typeof tools\n\t/** BrowserController for DOM operations */\n\treadonly browserController: BrowserController\n\n\ttask = ''\n\ttaskId = ''\n\t/** History events */\n\thistory: HistoricalEvent[] = []\n\t/** Whether this agent has been disposed */\n\tdisposed = false\n\n\t/**\n\t * Called when the agent needs to ask the user questions.\n\t * If unset, the `ask_user` tool will be disabled.\n\t * Implementations should reject the promise when `signal` aborts.\n\t * @example onAskUser: (q) => window.prompt(q) || ''\n\t */\n\tonAskUser?: (question: string, options?: { signal: AbortSignal }) => Promise<string>\n\n\t#status: AgentStatus = 'idle'\n\t#llm: LLM\n\t/**\n\t * Task cancellation primitive: its signal reaches the LLM fetch, tools\n\t * (via `ctx.signal`) and async callbacks. Aborted only by `stop`/`dispose`\n\t * (during a task) or task setup, always WITHOUT a reason so `signal.reason`\n\t * stays a standard `AbortError`.\n\t */\n\t#abortController = new AbortController()\n\t#observations: string[] = []\n\n\t/** Resolves when the current run has fully settled. Awaited by `stop()`. */\n\t#running: Promise<void> = Promise.resolve()\n\t#lastResult: ExecutionResult | null = null\n\n\t/** internal states during a single task execution */\n\t#states = {\n\t\t/** Accumulated wait time in seconds */\n\t\ttotalWaitTime: 0,\n\t\t/** For detecting navigation */\n\t\tlastURL: '',\n\t\t/** Browser state */\n\t\tbrowserState: null as BrowserState | null,\n\t}\n\n\tconstructor(config: AgentRuntimeConfig) {\n\t\tsuper()\n\n\t\tthis.config = { ...config, maxSteps: config.maxSteps ?? 40 }\n\n\t\tthis.#llm = new LLM(this.config)\n\t\tthis.tools = new Map(tools)\n\t\tthis.browserController = config.browserController\n\n\t\tthis.#llm.addEventListener('retry', (e) => {\n\t\t\tconst { attempt, maxAttempts, lastError } = (e as CustomEvent).detail\n\t\t\tthis.#emitActivity({ type: 'retrying', attempt, maxAttempts })\n\t\t\tthis.history.push({\n\t\t\t\ttype: 'error',\n\t\t\t\tmessage: String(lastError),\n\t\t\t\trawResponse: (lastError as InvokeError).rawResponse,\n\t\t\t})\n\t\t\tthis.history.push({\n\t\t\t\ttype: 'retry',\n\t\t\t\tmessage: `LLM retry attempt ${attempt} of ${maxAttempts}`,\n\t\t\t\tattempt,\n\t\t\t\tmaxAttempts,\n\t\t\t})\n\t\t\tthis.#emitHistoryChange()\n\t\t})\n\n\t\tif (this.config.customTools) {\n\t\t\tfor (const [name, tool] of Object.entries(this.config.customTools)) {\n\t\t\t\tif (tool === null) {\n\t\t\t\t\tthis.tools.delete(name)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tthis.tools.set(name, tool)\n\t\t\t}\n\t\t}\n\n\t\tif (!this.config.experimentalScriptExecutionTool) {\n\t\t\tthis.tools.delete('execute_javascript')\n\t\t}\n\t}\n\n\t/** Get current agent status */\n\tget status(): AgentStatus {\n\t\treturn this.#status\n\t}\n\n\t/** Result of the most recent run, or `null` before the first run completes. */\n\tget lastResult(): ExecutionResult | null {\n\t\treturn this.#lastResult\n\t}\n\n\t/** Emit statuschange event */\n\t#emitStatusChange(): void {\n\t\tthis.dispatchEvent(new Event('statuschange'))\n\t}\n\n\t/** Emit historychange event */\n\t#emitHistoryChange(pushHistoricalEvent?: HistoricalEvent): void {\n\t\tif (pushHistoricalEvent) this.history.push(pushHistoricalEvent)\n\t\tthis.dispatchEvent(new Event('historychange'))\n\t}\n\n\t/**\n\t * Emit activity event - for transient UI feedback\n\t * @param activity - Current agent activity\n\t */\n\t#emitActivity(activity: AgentActivity): void {\n\t\tthis.dispatchEvent(new CustomEvent('activity', { detail: activity }))\n\t}\n\n\t/** Update status and emit event */\n\t#setStatus(status: AgentStatus): void {\n\t\tif (this.#status !== status) {\n\t\t\tthis.#status = status\n\t\t\tthis.#emitStatusChange()\n\t\t}\n\t}\n\n\t/**\n\t * Push an observation message to the history event stream.\n\t * This will be visible in <agent_history> and remain persistent in memory across steps.\n\t * @experimental @internal\n\t * @note history change will be emitted before next step starts\n\t */\n\tpushObservation(content: string): void {\n\t\tthis.#observations.push(content)\n\t}\n\n\t/**\n\t * Stop the current task and wait until the run has fully settled (including lifecycle hooks).\n\t * @note never await .stop() in a lifecycle hook.\n\t */\n\tasync stop(): Promise<void> {\n\t\tif (this.#status !== 'running') return\n\t\tthis.#abortController.abort()\n\t\tawait this.#running\n\t}\n\n\t/**\n\t * external errors (pre-checks/config/hooks) will threw;\n\t * agent errors will be caught and added to history, and return a failed result\n\t */\n\tasync execute(task: string): Promise<ExecutionResult> {\n\t\t// pre-checks\n\t\tif (this.disposed) throw new Error('PageAgent has been disposed. Create a new instance.')\n\t\tif (this.#status === 'running') throw new Error('A task is already running.')\n\t\tif (!task) throw new Error('Task is required')\n\n\t\tthis.task = task\n\t\tthis.taskId = uid()\n\n\t\tthis.history = []\n\t\tthis.#observations = []\n\t\tthis.#states = { totalWaitTime: 0, lastURL: '', browserState: null }\n\t\tthis.#abortController = new AbortController()\n\t\tconst signal = this.#abortController.signal\n\n\t\tlet resolveRunning!: () => void\n\t\tthis.#running = new Promise<void>((r) => (resolveRunning = r))\n\n\t\tthis.#setStatus('running')\n\t\tthis.#emitHistoryChange()\n\n\t\t// Disable ask_user tool if onAskUser is not set\n\t\tif (!this.onAskUser) this.tools.delete('ask_user')\n\n\t\tconst onBeforeStep = this.config.onBeforeStep\n\t\tconst onAfterStep = this.config.onAfterStep\n\t\tconst onBeforeTask = this.config.onBeforeTask\n\t\tconst onAfterTask = this.config.onAfterTask\n\t\tconst stepDelay = this.config.stepDelay ?? 0.4\n\t\tconst maxSteps = this.config.maxSteps\n\n\t\tlet step = 0\n\t\tlet taskResult: ExecutionResult\n\t\tlet finalStatus: AgentStatus = 'error'\n\n\t\tawait suppress(() => this.browserController.showMask())\n\n\t\t// graceful exit\n\t\ttry {\n\t\t\tawait onBeforeTask?.(this)\n\n\t\t\twhile (true) {\n\t\t\t\tif (step >= maxSteps) {\n\t\t\t\t\tconst message = 'Step count exceeded maximum limit'\n\t\t\t\t\tconsole.error(message)\n\t\t\t\t\tthis.#emitActivity({ type: 'error', message: message })\n\t\t\t\t\tthis.#emitHistoryChange({ type: 'error', message: message })\n\t\t\t\t\ttaskResult = { success: false, data: message, history: this.history }\n\t\t\t\t\tthis.#lastResult = taskResult\n\t\t\t\t\tfinalStatus = 'error'\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\tawait onBeforeStep?.(this, step)\n\n\t\t\t\t// handle internal agent errors\n\t\t\t\ttry {\n\t\t\t\t\tconsole.group(`step: ${step}`)\n\n\t\t\t\t\t// @note It's convenient to treat stepDelay as part of the next step.\n\t\t\t\t\t// Maybe move it to a dedicated try block for better semantics?\n\t\t\t\t\tif (step > 0) await waitFor(stepDelay, signal)\n\n\t\t\t\t\tsignal.throwIfAborted()\n\n\t\t\t\t\t// observe\n\n\t\t\t\t\tconsole.log(chalk.blue.bold('👀 Observing...'))\n\n\t\t\t\t\tthis.#states.browserState = await this.browserController.getBrowserState()\n\t\t\t\t\tawait this.#handleObservations(step)\n\n\t\t\t\t\t// assemble prompts\n\n\t\t\t\t\tconst messages = [\n\t\t\t\t\t\t{ role: 'system' as const, content: this.#getSystemPrompt() },\n\t\t\t\t\t\t{ role: 'user' as const, content: await this.#assembleUserPrompt() },\n\t\t\t\t\t]\n\n\t\t\t\t\tconst macroTool = { AgentOutput: this.#packMacroTool() }\n\n\t\t\t\t\t// invoke LLM\n\n\t\t\t\t\tconsole.log(chalk.blue.bold('🧠 Thinking...'))\n\t\t\t\t\tthis.#emitActivity({ type: 'thinking' })\n\n\t\t\t\t\tconst result = await this.#llm.invoke(messages, macroTool, signal, {\n\t\t\t\t\t\ttoolChoiceName: 'AgentOutput',\n\t\t\t\t\t\tnormalizeResponse: (res) => normalizeResponse(res, this.tools),\n\t\t\t\t\t})\n\n\t\t\t\t\t// assemble history\n\n\t\t\t\t\tconst macroResult = result.toolResult as MacroToolResult\n\t\t\t\t\tconst input = macroResult.input\n\t\t\t\t\tconst output = macroResult.output\n\t\t\t\t\tconst reflection: Partial<AgentReflection> = {\n\t\t\t\t\t\tevaluation_previous_goal: input.evaluation_previous_goal,\n\t\t\t\t\t\tmemory: input.memory,\n\t\t\t\t\t\tnext_goal: input.next_goal,\n\t\t\t\t\t}\n\t\t\t\t\tconst actionName = Object.keys(input.action)[0]\n\t\t\t\t\tconst action: AgentStepEvent['action'] = {\n\t\t\t\t\t\tname: actionName,\n\t\t\t\t\t\tinput: input.action[actionName],\n\t\t\t\t\t\toutput: output,\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.#emitHistoryChange({\n\t\t\t\t\t\ttype: 'step',\n\t\t\t\t\t\tstepIndex: step,\n\t\t\t\t\t\treflection,\n\t\t\t\t\t\taction,\n\t\t\t\t\t\tusage: result.usage,\n\t\t\t\t\t\trawResponse: result.rawResponse,\n\t\t\t\t\t\trawRequest: result.rawRequest,\n\t\t\t\t\t})\n\n\t\t\t\t\tif (actionName === 'done') {\n\t\t\t\t\t\tconst success = action.input?.success ?? false\n\t\t\t\t\t\tconst data = action.input?.text || 'no text provided'\n\t\t\t\t\t\tconsole.log(chalk.green.bold('Task completed'), success, data)\n\t\t\t\t\t\ttaskResult = { success, data, history: this.history }\n\t\t\t\t\t\tthis.#lastResult = taskResult\n\t\t\t\t\t\tfinalStatus = 'completed'\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t} catch (error: unknown) {\n\t\t\t\t\t// catch block must not throw error. otherwise the error may be overridden if finally block also throws error.\n\n\t\t\t\t\tconst isAbortError = (error as any)?.name === 'AbortError'\n\t\t\t\t\tif (!isAbortError) console.error('Task failed', error)\n\t\t\t\t\tconst message = isAbortError ? 'Task aborted' : String(error)\n\t\t\t\t\tthis.#emitActivity({ type: 'error', message: message })\n\t\t\t\t\tthis.#emitHistoryChange({ type: 'error', message: message, rawResponse: error })\n\t\t\t\t\ttaskResult = { success: false, data: message, history: this.history }\n\t\t\t\t\tthis.#lastResult = taskResult\n\t\t\t\t\tfinalStatus = isAbortError ? 'stopped' : 'error'\n\t\t\t\t\tbreak\n\t\t\t\t} finally {\n\t\t\t\t\t// finally block runs before the break above.\n\n\t\t\t\t\tconsole.groupEnd()\n\t\t\t\t\t// @note hook may throw error.\n\t\t\t\t\t// which will override the `break` above and be handled as an external error.\n\t\t\t\t\t// as expected.\n\t\t\t\t\tawait onAfterStep?.(this, this.history)\n\t\t\t\t}\n\n\t\t\t\tstep++\n\t\t\t} // while\n\n\t\t\tawait onAfterTask?.(this, taskResult)\n\n\t\t\treturn taskResult\n\t\t} catch (error) {\n\t\t\tthis.#emitActivity({ type: 'error', message: String(error) })\n\t\t\tfinalStatus = 'error'\n\t\t\tthrow error\n\t\t} finally {\n\t\t\tawait suppress(() => this.browserController.cleanUpHighlights())\n\t\t\tawait suppress(() => this.browserController.hideMask())\n\t\t\tthis.#abortController.abort()\n\t\t\tresolveRunning()\n\t\t\tthis.#setStatus(finalStatus)\n\t\t}\n\t}\n\n\t/**\n\t * Merge all tools into a single MacroTool with the following input:\n\t * - thinking: string\n\t * - evaluation_previous_goal: string\n\t * - memory: string\n\t * - next_goal: string\n\t * - action: { toolName: toolInput }\n\t * where action must be selected from tools defined in this.tools\n\t */\n\t#packMacroTool(): Tool<MacroToolInput, MacroToolResult> {\n\t\tconst tools = this.tools\n\n\t\tconst actionSchemas = Array.from(tools.entries()).map(([toolName, tool]) => {\n\t\t\treturn z.object({ [toolName]: tool.inputSchema }).describe(tool.description)\n\t\t})\n\n\t\tconst actionSchema = z.union(actionSchemas as unknown as [z.ZodType, z.ZodType, ...z.ZodType[]])\n\n\t\tconst macroToolSchema = z.object({\n\t\t\t// thinking: z.string().optional(),\n\t\t\tevaluation_previous_goal: z.string().optional(),\n\t\t\tmemory: z.string().optional(),\n\t\t\tnext_goal: z.string().optional(),\n\t\t\taction: actionSchema,\n\t\t})\n\n\t\treturn {\n\t\t\tdescription: 'You MUST call this tool every step!',\n\t\t\tinputSchema: macroToolSchema as z.ZodType<MacroToolInput>,\n\t\t\texecute: async (input: MacroToolInput): Promise<MacroToolResult> => {\n\t\t\t\tconst signal = this.#abortController.signal\n\t\t\t\tsignal.throwIfAborted()\n\n\t\t\t\tconsole.log(chalk.blue.bold('MacroTool input'), input)\n\t\t\t\tconst action = input.action\n\n\t\t\t\tconst toolName = Object.keys(action)[0]\n\t\t\t\tconst toolInput = action[toolName]\n\n\t\t\t\t// Build reflection text, only include non-empty fields\n\t\t\t\tconst reflectionLines: string[] = []\n\t\t\t\tif (input.evaluation_previous_goal)\n\t\t\t\t\treflectionLines.push(`✅: ${input.evaluation_previous_goal}`)\n\t\t\t\tif (input.memory) reflectionLines.push(`💾: ${input.memory}`)\n\t\t\t\tif (input.next_goal) reflectionLines.push(`🎯: ${input.next_goal}`)\n\n\t\t\t\tconst reflectionText = reflectionLines.length > 0 ? reflectionLines.join('\\n') : ''\n\n\t\t\t\tif (reflectionText) {\n\t\t\t\t\tconsole.log(reflectionText)\n\t\t\t\t}\n\n\t\t\t\t// Find the corresponding tool\n\t\t\t\tconst tool = tools.get(toolName)\n\t\t\t\tassert(tool, `Tool ${toolName} not found`)\n\n\t\t\t\tconsole.log(chalk.blue.bold(`Executing tool: ${toolName}`), toolInput)\n\n\t\t\t\t// Emit executing activity\n\t\t\t\tthis.#emitActivity({ type: 'executing', tool: toolName, input: toolInput })\n\n\t\t\t\tconst startTime = Date.now()\n\n\t\t\t\tconst result = await tool.execute.bind(this)(toolInput, { signal })\n\t\t\t\t// Enforce abort even if the tool ignored the signal and resolved normally.\n\t\t\t\tsignal.throwIfAborted()\n\n\t\t\t\tconst duration = Date.now() - startTime\n\t\t\t\tconsole.log(chalk.green.bold(`Tool (${toolName}) executed for ${duration}ms`), result)\n\n\t\t\t\t// Emit executed activity\n\t\t\t\tthis.#emitActivity({\n\t\t\t\t\ttype: 'executed',\n\t\t\t\t\ttool: toolName,\n\t\t\t\t\tinput: toolInput,\n\t\t\t\t\toutput: result,\n\t\t\t\t\tduration,\n\t\t\t\t})\n\n\t\t\t\t// counting wait time\n\t\t\t\tif (toolName === 'wait') {\n\t\t\t\t\tthis.#states.totalWaitTime += toolInput?.seconds || 0\n\t\t\t\t} else {\n\t\t\t\t\tthis.#states.totalWaitTime = 0\n\t\t\t\t}\n\n\t\t\t\t// Return structured result\n\t\t\t\treturn {\n\t\t\t\t\tinput,\n\t\t\t\t\toutput: result,\n\t\t\t\t}\n\t\t\t},\n\t\t}\n\t}\n\n\t/**\n\t * Get system prompt, dynamically replace language settings based on configured language\n\t */\n\t#getSystemPrompt(): string {\n\t\tif (this.config.customSystemPrompt) {\n\t\t\treturn this.config.customSystemPrompt\n\t\t}\n\n\t\tconst targetLanguage = this.config.language === 'zh-CN' ? '中文' : 'English'\n\t\tconst systemPrompt = SYSTEM_PROMPT.replace(\n\t\t\t/Default working language: \\*\\*.*?\\*\\*/,\n\t\t\t`Default working language: **${targetLanguage}**`\n\t\t)\n\n\t\treturn systemPrompt\n\t}\n\n\t/**\n\t * Get instructions from config\n\t */\n\tasync #getInstructions(): Promise<string> {\n\t\tconst { instructions, experimentalLlmsTxt } = this.config\n\n\t\tconst systemInstructions = instructions?.system?.trim()\n\t\tlet pageInstructions: string | undefined\n\n\t\tconst url = this.#states.browserState?.url || ''\n\t\tif (instructions?.getPageInstructions && url) {\n\t\t\ttry {\n\t\t\t\tpageInstructions = instructions.getPageInstructions(url)?.trim()\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(\n\t\t\t\t\tchalk.red('[PageAgent] Failed to execute getPageInstructions callback:'),\n\t\t\t\t\terror\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\tconst llmsTxt = experimentalLlmsTxt && url ? await fetchLlmsTxt(url) : undefined\n\n\t\tif (!systemInstructions && !pageInstructions && !llmsTxt) return ''\n\n\t\tlet result = '<instructions>\\n'\n\n\t\tif (systemInstructions) {\n\t\t\tresult += `<system_instructions>\\n${systemInstructions}\\n</system_instructions>\\n`\n\t\t}\n\n\t\tif (pageInstructions) {\n\t\t\tresult += `<page_instructions>\\n${pageInstructions}\\n</page_instructions>\\n`\n\t\t}\n\n\t\tif (llmsTxt) {\n\t\t\tresult += `<llms_txt>\\n${llmsTxt}\\n</llms_txt>\\n`\n\t\t}\n\n\t\tresult += '</instructions>\\n\\n'\n\n\t\treturn result\n\t}\n\n\t/**\n\t * Generate system observations before each step\n\t * @todo loop detection\n\t * @todo console error\n\t */\n\tasync #handleObservations(step: number): Promise<void> {\n\t\t// Accumulated wait time warning\n\t\tif (this.#states.totalWaitTime >= 3) {\n\t\t\tthis.pushObservation(\n\t\t\t\t`You have waited ${this.#states.totalWaitTime} seconds accumulatively. ` +\n\t\t\t\t\t`DO NOT wait any longer unless you have a good reason.`\n\t\t\t)\n\t\t}\n\n\t\t// Detect URL change\n\t\tconst currentURL = this.#states.browserState?.url || ''\n\t\tif (currentURL !== this.#states.lastURL) {\n\t\t\tthis.pushObservation(`Page navigated to → ${currentURL}`)\n\t\t\tthis.#states.lastURL = currentURL\n\t\t\tawait waitFor(0.5) // wait for page to stabilize\n\t\t}\n\n\t\t// Remaining steps warning\n\t\tconst remaining = this.config.maxSteps - step\n\t\tif (remaining === 5) {\n\t\t\tthis.pushObservation(\n\t\t\t\t`⚠️ Only ${remaining} steps remaining. ` +\n\t\t\t\t\t`Consider wrapping up or calling done with partial results.`\n\t\t\t)\n\t\t} else if (remaining === 2) {\n\t\t\tthis.pushObservation(\n\t\t\t\t`⚠️ Critical: Only ${remaining} steps left! You must finish the task or call done immediately.`\n\t\t\t)\n\t\t}\n\n\t\t// Push observations to history and emit\n\t\tif (this.#observations.length > 0) {\n\t\t\tfor (const content of this.#observations) {\n\t\t\t\tthis.history.push({ type: 'observation', content })\n\t\t\t\tconsole.log(chalk.cyan('Observation:'), content)\n\t\t\t}\n\t\t\tthis.#observations = []\n\t\t\tthis.#emitHistoryChange()\n\t\t}\n\t}\n\n\tasync #assembleUserPrompt(): Promise<string> {\n\t\tconst browserState = this.#states.browserState!\n\n\t\tlet prompt = ''\n\n\t\t// <instructions> (optional)\n\n\t\tprompt += await this.#getInstructions()\n\n\t\t// <agent_state>\n\t\t// - <user_request>\n\t\t// - <step_info>\n\t\t// <agent_state>\n\n\t\tconst stepCount = this.history.filter((e) => e.type === 'step').length\n\n\t\tprompt += '<agent_state>\\n'\n\t\tprompt += '<user_request>\\n'\n\t\tprompt += `${this.task}\\n`\n\t\tprompt += '</user_request>\\n'\n\t\tprompt += '<step_info>\\n'\n\t\tprompt += `Step ${stepCount + 1} of ${this.config.maxSteps} max possible steps\\n`\n\t\tprompt += `Current time: ${new Date().toLocaleString()}\\n`\n\t\tprompt += '</step_info>\\n'\n\t\tprompt += '</agent_state>\\n\\n'\n\n\t\t// <agent_history>\n\t\t// - <step_N> for steps\n\t\t// - <sys> for observations and system messages\n\n\t\tprompt += '<agent_history>\\n'\n\n\t\tlet stepIndex = 0\n\t\tfor (const event of this.history) {\n\t\t\tif (event.type === 'step') {\n\t\t\t\tstepIndex++\n\t\t\t\tprompt += `<step_${stepIndex}>\\n`\n\t\t\t\tprompt += `Evaluation of Previous Step: ${event.reflection.evaluation_previous_goal}\\n`\n\t\t\t\tprompt += `Memory: ${event.reflection.memory}\\n`\n\t\t\t\tprompt += `Next Goal: ${event.reflection.next_goal}\\n`\n\t\t\t\tprompt += `Action Results: ${event.action.output}\\n`\n\t\t\t\tprompt += `</step_${stepIndex}>\\n`\n\t\t\t} else if (event.type === 'observation') {\n\t\t\t\tprompt += `<sys>${event.content}</sys>\\n`\n\t\t\t} else if (event.type === 'user_takeover') {\n\t\t\t\tprompt += `<sys>User took over control and made changes to the page</sys>\\n`\n\t\t\t} else if (event.type === 'error') {\n\t\t\t\t// Error events are mainly for UI rendering, not included in LLM context\n\t\t\t\t// to avoid polluting the agent's reasoning with transient errors\n\t\t\t}\n\t\t}\n\n\t\tprompt += '</agent_history>\\n\\n'\n\n\t\t// <browser_state>\n\n\t\tlet pageContent = browserState.content\n\t\tif (this.config.transformPageContent) {\n\t\t\tpageContent = await this.config.transformPageContent(pageContent)\n\t\t}\n\n\t\tprompt += '<browser_state>\\n'\n\t\tprompt += browserState.header + '\\n'\n\t\tprompt += pageContent + '\\n'\n\t\tprompt += browserState.footer + '\\n\\n'\n\t\tprompt += '</browser_state>\\n\\n'\n\n\t\treturn prompt\n\t}\n\n\tdispose() {\n\t\tif (this.disposed) return\n\t\tthis.disposed = true\n\n\t\tconsole.log('Disposing PageAgent...')\n\t\tconst errors: unknown[] = []\n\t\tconst cleanUp = (callback: () => void) => {\n\t\t\ttry {\n\t\t\t\tcallback()\n\t\t\t} catch (error: unknown) {\n\t\t\t\terrors.push(error)\n\t\t\t}\n\t\t}\n\n\t\tcleanUp(() => this.#abortController.abort())\n\t\tcleanUp(() => this.browserController.dispose())\n\t\t// this.history = []\n\n\t\t// Emit dispose event for UI cleanup\n\t\tcleanUp(() => this.dispatchEvent(new Event('dispose')))\n\n\t\tcleanUp(() => this.config.onDispose?.(this))\n\n\t\tif (errors.length === 1) throw errors[0]\n\t\tif (errors.length > 1) throw new AggregateError(errors, 'PageAgent disposal failed')\n\t}\n}\n","import { BrowserController, type BrowserControllerConfig } from '../browser/BrowserController'\nimport { UI, type UIConfig } from '../ui/UI'\nimport { AgentRuntime } from './AgentRuntime'\nimport type { AgentConfig } from './types'\n\nexport type MyPageAgentConfig = Omit<AgentConfig, 'experimentalScriptExecutionTool'> &\n\tBrowserControllerConfig &\n\tOmit<UIConfig, 'language'>\n\nexport class MyPageAgent extends AgentRuntime {\n\treadonly ui: UI\n\n\tconstructor(config: MyPageAgentConfig) {\n\t\tconst browserController = new BrowserController({\n\t\t\t...config,\n\t\t\tenableMask: config.enableMask ?? true,\n\t\t})\n\n\t\tsuper({ ...config, experimentalScriptExecutionTool: false, browserController })\n\n\t\tthis.ui = new UI(this, {\n\t\t\tlanguage: config.language,\n\t\t\tpromptForNextTask: config.promptForNextTask,\n\t\t})\n\t}\n}\n","import { MyPageAgent, type MyPageAgentConfig } from './agent/MyPageAgent'\n\nexport { MyPageAgent }\nexport type { MyPageAgentConfig }\nexport { tool } from './agent/tools'\nexport type { AgentActivity, AgentStatus, ExecutionResult, HistoricalEvent } from './agent/types'\n\nexport function createAgent(config: MyPageAgentConfig): MyPageAgent {\n\treturn new MyPageAgent(config)\n}\n"],"mappings":"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"}
|