feat: custom PageController; remove beforeunload; node-safe PageController
This commit is contained in:
@@ -68,7 +68,6 @@ export class PageAgent extends EventTarget {
|
|||||||
|
|
||||||
#llm: LLM
|
#llm: LLM
|
||||||
#abortController = new AbortController()
|
#abortController = new AbortController()
|
||||||
#beforeUnloadListener: ((e: Event) => void) | null = null
|
|
||||||
|
|
||||||
/** PageController for DOM operations */
|
/** PageController for DOM operations */
|
||||||
pageController: PageController
|
pageController: PageController
|
||||||
@@ -92,7 +91,9 @@ export class PageAgent extends EventTarget {
|
|||||||
this.tools = new Map(tools)
|
this.tools = new Map(tools)
|
||||||
|
|
||||||
// Initialize PageController with config (mask enabled by default)
|
// Initialize PageController with config (mask enabled by default)
|
||||||
this.pageController = new PageController({
|
this.pageController =
|
||||||
|
this.config.pageController ??
|
||||||
|
new PageController({
|
||||||
...this.config,
|
...this.config,
|
||||||
enableMask: this.config.enableMask ?? true,
|
enableMask: this.config.enableMask ?? true,
|
||||||
})
|
})
|
||||||
@@ -137,11 +138,6 @@ export class PageAgent extends EventTarget {
|
|||||||
if (!this.config.experimentalScriptExecutionTool) {
|
if (!this.config.experimentalScriptExecutionTool) {
|
||||||
this.tools.delete('execute_javascript')
|
this.tools.delete('execute_javascript')
|
||||||
}
|
}
|
||||||
|
|
||||||
this.#beforeUnloadListener = (e) => {
|
|
||||||
if (!this.disposed) this.dispose('PAGE_UNLOADING')
|
|
||||||
}
|
|
||||||
window.addEventListener('beforeunload', this.#beforeUnloadListener)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get current agent status */
|
/** Get current agent status */
|
||||||
@@ -591,12 +587,6 @@ export class PageAgent extends EventTarget {
|
|||||||
this.history = []
|
this.history = []
|
||||||
this.#abortController.abort(reason ?? 'PageAgent disposed')
|
this.#abortController.abort(reason ?? 'PageAgent disposed')
|
||||||
|
|
||||||
// Clean up window event listeners
|
|
||||||
if (this.#beforeUnloadListener) {
|
|
||||||
window.removeEventListener('beforeunload', this.#beforeUnloadListener)
|
|
||||||
this.#beforeUnloadListener = null
|
|
||||||
}
|
|
||||||
|
|
||||||
// Emit dispose event for UI cleanup
|
// Emit dispose event for UI cleanup
|
||||||
this.dispatchEvent(new Event('dispose'))
|
this.dispatchEvent(new Event('dispose'))
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { LLMConfig } from '@page-agent/llms'
|
import type { LLMConfig } from '@page-agent/llms'
|
||||||
import type { PageControllerConfig } from '@page-agent/page-controller'
|
import type { PageController, PageControllerConfig } from '@page-agent/page-controller'
|
||||||
|
|
||||||
import type { PageAgent } from '../PageAgent'
|
import type { PageAgent } from '../PageAgent'
|
||||||
import type { PageAgentTool } from '../tools'
|
import type { PageAgentTool } from '../tools'
|
||||||
@@ -74,7 +74,6 @@ export interface AgentConfig {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @note this hook can block the disposal process
|
* @note this hook can block the disposal process
|
||||||
* @note when dispose caused by page unload, reason will be 'PAGE_UNLOADING'. this method CANNOT block unloading. async operations may be cut.
|
|
||||||
* @todo remove `this` binding, pass agent as explicit parameter instead
|
* @todo remove `this` binding, pass agent as explicit parameter instead
|
||||||
*/
|
*/
|
||||||
onDispose?: (this: PageAgent, reason?: string) => void
|
onDispose?: (this: PageAgent, reason?: string) => void
|
||||||
@@ -105,6 +104,13 @@ export interface AgentConfig {
|
|||||||
*/
|
*/
|
||||||
transformPageContent?: (content: string) => Promise<string> | string
|
transformPageContent?: (content: string) => Promise<string> | string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @experimental
|
||||||
|
* Custom PageController instance to control page navigation and actions
|
||||||
|
* @note If not provided, a default PageController will be created
|
||||||
|
*/
|
||||||
|
pageController?: PageController
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: @unimplemented
|
* TODO: @unimplemented
|
||||||
* hook when action causes a new page to be opened
|
* hook when action causes a new page to be opened
|
||||||
|
|||||||
@@ -18,11 +18,8 @@ import { VIEWPORT_EXPANSION } from './constants'
|
|||||||
import * as dom from './dom'
|
import * as dom from './dom'
|
||||||
import type { FlatDomTree, InteractiveElementDomNode } from './dom/dom_tree/type'
|
import type { FlatDomTree, InteractiveElementDomNode } from './dom/dom_tree/type'
|
||||||
import { getPageInfo } from './dom/getPageInfo'
|
import { getPageInfo } from './dom/getPageInfo'
|
||||||
import { SimulatorMask } from './mask/SimulatorMask'
|
|
||||||
import { patchReact } from './patches/react'
|
import { patchReact } from './patches/react'
|
||||||
|
|
||||||
export { SimulatorMask }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configuration for PageController
|
* Configuration for PageController
|
||||||
*/
|
*/
|
||||||
@@ -84,7 +81,7 @@ export class PageController extends EventTarget {
|
|||||||
private lastTimeUpdate = 0
|
private lastTimeUpdate = 0
|
||||||
|
|
||||||
/** Visual mask overlay for blocking user interaction during automation */
|
/** Visual mask overlay for blocking user interaction during automation */
|
||||||
private mask: SimulatorMask | null = null
|
private mask: InstanceType<typeof import('./mask/SimulatorMask').SimulatorMask> | null = null
|
||||||
|
|
||||||
constructor(config: PageControllerConfig = {}) {
|
constructor(config: PageControllerConfig = {}) {
|
||||||
super()
|
super()
|
||||||
@@ -94,10 +91,16 @@ export class PageController extends EventTarget {
|
|||||||
patchReact(this)
|
patchReact(this)
|
||||||
|
|
||||||
if (config.enableMask) {
|
if (config.enableMask) {
|
||||||
|
this.initMask()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Initialize mask asynchronously (dynamic import to avoid CSS loading in Node)
|
||||||
|
*/
|
||||||
|
private async initMask(): Promise<void> {
|
||||||
|
const { SimulatorMask } = await import('./mask/SimulatorMask')
|
||||||
this.mask = new SimulatorMask()
|
this.mask = new SimulatorMask()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// ======= State Queries =======
|
// ======= State Queries =======
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user