From 78d491928940e1ec9b79f4348e46b9e1006bfa33 Mon Sep 17 00:00:00 2001 From: Simon <10131203+gaomeng1900@users.noreply.github.com> Date: Sat, 17 Jan 2026 17:24:17 +0800 Subject: [PATCH 1/3] feat: make `panel` optional --- packages/page-agent/src/PageAgent.ts | 51 +++++++++++++++---------- packages/page-agent/src/config/index.ts | 21 ++++++++++ packages/page-agent/src/tools/index.ts | 3 ++ packages/ui/src/Panel.ts | 14 ++++++- packages/website/src/pages/Home.tsx | 4 ++ 5 files changed, 72 insertions(+), 21 deletions(-) diff --git a/packages/page-agent/src/PageAgent.ts b/packages/page-agent/src/PageAgent.ts index b4b830e..b93cb83 100644 --- a/packages/page-agent/src/PageAgent.ts +++ b/packages/page-agent/src/PageAgent.ts @@ -99,7 +99,7 @@ export interface ExecutionResult { export class PageAgent extends EventTarget { config: PageAgentConfig id = uid() - panel: Panel + panel: Panel | null = null tools: typeof tools disposed = false task = '' @@ -130,11 +130,17 @@ export class PageAgent extends EventTarget { this.config = config this.#llm = new LLM(this.config) - this.panel = new Panel({ - language: this.config.language, - onExecuteTask: (task) => this.execute(task), - onStop: () => this.dispose(), - }) + + // Conditionally initialize Panel + if (this.config.enablePanel !== false) { + this.panel = new Panel({ + language: this.config.language, + onExecuteTask: (task) => this.execute(task), + onStop: () => this.dispose(), + promptForNextTask: this.config.promptForNextTask, + }) + } + this.tools = new Map(tools) // Initialize PageController with config (mask enabled by default) @@ -146,11 +152,11 @@ export class PageAgent extends EventTarget { // Listen to LLM events this.#llmRetryListener = (e) => { const { current, max } = (e as CustomEvent).detail - this.panel.update({ type: 'retry', current, max }) + this.panel?.update({ type: 'retry', current, max }) } this.#llmErrorListener = (e) => { const { error } = (e as CustomEvent).detail - this.panel.update({ type: 'error', message: `step failed: ${error.message}` }) + this.panel?.update({ type: 'error', message: `step failed: ${error.message}` }) } this.#llm.addEventListener('retry', this.#llmRetryListener) this.#llm.addEventListener('error', this.#llmErrorListener) @@ -169,6 +175,11 @@ export class PageAgent extends EventTarget { this.tools.delete('execute_javascript') } + // Disable ask_user tool if enableAskUser is false or if panel is disabled + if (this.config.enableAskUser === false || this.config.enablePanel === false) { + this.tools.delete('ask_user') + } + this.#beforeUnloadListener = (e) => { if (!this.disposed) this.dispose('PAGE_UNLOADING') } @@ -181,7 +192,7 @@ export class PageAgent extends EventTarget { */ pushObservation(content: string): void { this.history.push({ type: 'observation', content }) - this.panel.update({ type: 'observation', content }) + this.panel?.update({ type: 'observation', content }) } async execute(task: string): Promise { @@ -199,10 +210,10 @@ export class PageAgent extends EventTarget { // Show mask and panel this.pageController.showMask() - this.panel.show() - this.panel.reset() + this.panel?.show() + this.panel?.reset() - this.panel.update({ type: 'input', task: this.task }) + this.panel?.update({ type: 'input', task: this.task }) if (this.#abortController) { this.#abortController.abort() @@ -232,7 +243,7 @@ export class PageAgent extends EventTarget { // Update status to thinking console.log(chalk.blue('Thinking...')) - this.panel.update({ type: 'thinking' }) + this.panel?.update({ type: 'thinking' }) const result = await this.#llm.invoke( [ @@ -370,7 +381,7 @@ export class PageAgent extends EventTarget { if (reflectionText) { console.log(reflectionText) - this.panel.update({ type: 'thinking', text: reflectionText }) + this.panel?.update({ type: 'thinking', text: reflectionText }) } // Find the corresponding tool @@ -378,7 +389,7 @@ export class PageAgent extends EventTarget { assert(tool, `Tool ${toolName} not found. (@note should have been caught before this!!!)`) console.log(chalk.blue.bold(`Executing tool: ${toolName}`), toolInput) - this.panel.update({ type: 'toolExecuting', toolName, args: toolInput }) + this.panel?.update({ type: 'toolExecuting', toolName, args: toolInput }) const startTime = Date.now() @@ -394,7 +405,7 @@ export class PageAgent extends EventTarget { } // Briefly display execution result - this.panel.update({ + this.panel?.update({ type: 'toolCompleted', toolName, args: toolInput, @@ -557,13 +568,13 @@ export class PageAgent extends EventTarget { // Update panel status if (success) { - this.panel.update({ type: 'output', text }) + this.panel?.update({ type: 'output', text }) } else { - this.panel.update({ type: 'error', message: text }) + this.panel?.update({ type: 'error', message: text }) } // Task completed - this.panel.update({ type: 'completed' }) + this.panel?.update({ type: 'completed' }) this.pageController.hideMask() @@ -593,7 +604,7 @@ export class PageAgent extends EventTarget { console.log('Disposing PageAgent...') this.disposed = true this.pageController.dispose() - this.panel.dispose() + this.panel?.dispose() this.history = [] this.#abortController.abort(reason ?? 'PageAgent disposed') diff --git a/packages/page-agent/src/config/index.ts b/packages/page-agent/src/config/index.ts index 538be09..af2647c 100644 --- a/packages/page-agent/src/config/index.ts +++ b/packages/page-agent/src/config/index.ts @@ -11,6 +11,27 @@ export interface AgentConfig { // theme?: 'light' | 'dark' language?: SupportedLanguage + /** + * Whether to prompt for next task after task completion + * @default true + */ + promptForNextTask?: boolean + + /** + * Enable the UI panel for visual feedback and user interaction + * When disabled, the panel will not be created and all UI operations will be skipped. + * Useful for automated testing or when integrating PageAgent as a library. + * @default true + */ + enablePanel?: boolean + + /** + * Enable the ask_user tool for agent to ask questions + * When disabled, the agent cannot ask user questions during execution. + * @default true + */ + enableAskUser?: boolean + /** * Custom tools to extend PageAgent capabilities * @experimental diff --git a/packages/page-agent/src/tools/index.ts b/packages/page-agent/src/tools/index.ts index 7415009..caf7200 100644 --- a/packages/page-agent/src/tools/index.ts +++ b/packages/page-agent/src/tools/index.ts @@ -80,6 +80,9 @@ tools.set( question: zod.string(), }), execute: async function (this: PageAgent, input) { + if (!this.panel) { + throw new Error('ask_user tool requires panel to be enabled') + } const answer = await this.panel.askUser(input.question) return `✅ Received user answer: ${answer}` }, diff --git a/packages/ui/src/Panel.ts b/packages/ui/src/Panel.ts index d7d0d5c..8a2b602 100644 --- a/packages/ui/src/Panel.ts +++ b/packages/ui/src/Panel.ts @@ -11,6 +11,11 @@ export interface PanelConfig { language?: SupportedLanguage onExecuteTask: (task: string) => void onStop: () => void + /** + * Whether to prompt for next task after task completion + * @default true + */ + promptForNextTask?: boolean } /** @@ -358,7 +363,14 @@ export class Panel { } const lastStep = steps[steps.length - 1] - return lastStep.type === 'completed' || lastStep.type === 'error' + const isTaskEnded = lastStep.type === 'completed' || lastStep.type === 'error' + + // Only show input area after task completion if configured to do so + if (isTaskEnded) { + return this.#config.promptForNextTask ?? true + } + + return false } #createWrapper(): HTMLElement { diff --git a/packages/website/src/pages/Home.tsx b/packages/website/src/pages/Home.tsx index be13cf7..ba2c37a 100644 --- a/packages/website/src/pages/Home.tsx +++ b/packages/website/src/pages/Home.tsx @@ -89,6 +89,10 @@ export default function HomePage() { import.meta.env.DEV && import.meta.env.LLM_API_KEY ? import.meta.env.LLM_API_KEY : DEMO_API_KEY, + + // enableAskUser: false, + // promptForNextTask: false, + // enablePanel: false, }) } From 64c36f67bb19dfbdab94d70f2dc9f3d103145bc3 Mon Sep 17 00:00:00 2001 From: Simon <10131203+gaomeng1900@users.noreply.github.com> Date: Sat, 17 Jan 2026 17:28:28 +0800 Subject: [PATCH 2/3] docs: update config; instructions for programmatic usage --- .../docs/integration/configuration/page.tsx | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/packages/website/src/pages/docs/integration/configuration/page.tsx b/packages/website/src/pages/docs/integration/configuration/page.tsx index 6ff1cc0..491c7f6 100644 --- a/packages/website/src/pages/docs/integration/configuration/page.tsx +++ b/packages/website/src/pages/docs/integration/configuration/page.tsx @@ -61,6 +61,27 @@ export default function Configuration() { code={`interface AgentConfig { language?: 'en-US' | 'zh-CN' + /** + * Whether to prompt for next task after task completion + * @default true + */ + promptForNextTask?: boolean + + /** + * Enable the UI panel for visual feedback and user interaction + * When disabled, the panel will not be created and all UI operations will be skipped. + * Useful for automated testing or when integrating PageAgent as a library. + * @default true + */ + enablePanel?: boolean + + /** + * Enable the ask_user tool for agent to ask questions + * When disabled, the agent cannot ask user questions during execution. + * @default true + */ + enableAskUser?: boolean + /** Custom tools to extend or override built-in tools */ customTools?: Record @@ -140,6 +161,39 @@ interface PageControllerConfig extends DomConfig { code={`type PageAgentConfig = LLMConfig & AgentConfig & PageControllerConfig`} /> + + {/* Programmatic Usage Example */} +
+

+ {isZh ? '程序化使用配置' : 'Programmatic Usage'} +

+

+ {isZh + ? '对于程序化集成场景,可以禁用 UI。' + : 'For programmatic integration, you can disable UI.'} +

+ +
) } From ce3a80bc53c63d90c4b70afc6e8846df936f2cab Mon Sep 17 00:00:00 2001 From: Simon <10131203+gaomeng1900@users.noreply.github.com> Date: Sat, 17 Jan 2026 17:30:16 +0800 Subject: [PATCH 3/3] docs: typo --- .../src/pages/docs/integration/third-party-agent/page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/website/src/pages/docs/integration/third-party-agent/page.tsx b/packages/website/src/pages/docs/integration/third-party-agent/page.tsx index 6958d48..9b9d594 100644 --- a/packages/website/src/pages/docs/integration/third-party-agent/page.tsx +++ b/packages/website/src/pages/docs/integration/third-party-agent/page.tsx @@ -36,7 +36,7 @@ const pageAgentTool = { }, execute: async (params) => { const result = await pageAgent.execute(params.instruction) - return { success: result.success, message: result.message } + return { success: result.success, message: result.data } } }