page-agent 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,7 +1,5 @@
1
1
  # PageAgent 🤖🪄
2
2
 
3
- > ⚠️ See [**Roadmap**](./ROADMAP.md)
4
-
5
3
  ![banner](https://img.alicdn.com/imgextra/i1/O1CN01RY0Wvh26ATVeDIX7v_!!6000000007621-0-tps-1672-512.jpg)
6
4
 
7
5
  [![npm version](https://badge.fury.io/js/page-agent.svg)](https://badge.fury.io/js/page-agent) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-%230074c1.svg)](http://www.typescriptlang.org/) [![Downloads](https://img.shields.io/npm/dt/page-agent.svg)](https://www.npmjs.com/package/page-agent) [![Bundle Size](https://img.shields.io/bundlephobia/minzip/page-agent)](https://bundlephobia.com/package/page-agent) [![GitHub stars](https://img.shields.io/github/stars/alibaba/page-agent.svg)](https://github.com/alibaba/page-agent)
@@ -34,7 +32,11 @@ An in-page UI agent in javascript. Control web interfaces with natural language.
34
32
 
35
33
  ```html
36
34
  <!-- temporary CDN URL. May change in the future -->
37
- <script src="https://hwcxiuzfylggtcktqgij.supabase.co/storage/v1/object/public/demo-public/v0.0.2/page-agent.js" crossorigin="true" type="text/javascript"></script>
35
+ <script
36
+ src="https://hwcxiuzfylggtcktqgij.supabase.co/storage/v1/object/public/demo-public/v0.0.2/page-agent.js"
37
+ crossorigin="true"
38
+ type="text/javascript"
39
+ ></script>
38
40
  ```
39
41
 
40
42
  ### NPM Installation
@@ -54,13 +56,13 @@ const DEMO_BASE_URL = 'https://hwcxiuzfylggtcktqgij.supabase.co/functions/v1/llm
54
56
  const DEMO_API_KEY = 'PAGE-AGENT-FREE-TESTING-RANDOM'
55
57
 
56
58
  const agent = new PageAgent({
57
- modelName: DEMO_MODEL,
58
- baseURL: DEMO_BASE_URL,
59
- apiKey: DEMO_API_KEY,
60
- language: 'en-US'
59
+ modelName: DEMO_MODEL,
60
+ baseURL: DEMO_BASE_URL,
61
+ apiKey: DEMO_API_KEY,
62
+ language: 'en-US',
61
63
  })
62
64
 
63
- await agent.execute("Click the login button")
65
+ await agent.execute('Click the login button')
64
66
  ```
65
67
 
66
68
  ## 🏗️ Structure
@@ -104,9 +106,8 @@ PageAgent is designed for **client-side web enhancement**, not server-side autom
104
106
 
105
107
  MIT License - see the [LICENSE](LICENSE) file for details.
106
108
 
107
-
108
109
  ```
109
- DOM processing components and prompt are derived from browser-use:
110
+ DOM processing components and prompt are derived from browser-use:
110
111
 
111
112
  Browser Use
112
113
  Copyright (c) 2024 Gregor Zunic
@@ -7,6 +7,61 @@ export declare interface AgentBrain {
7
7
  next_goal: string;
8
8
  }
9
9
 
10
+ declare interface AgentConfig {
11
+ language?: SupportedLanguage;
12
+ /**
13
+ * Custom tools to extend PageAgent capabilities
14
+ * @experimental
15
+ * @note You can also override or remove internal tools by using the same name.
16
+ * @see [tools](../tools/index.ts)
17
+ *
18
+ * @example
19
+ * // override internal tool
20
+ * import { tool } from 'page-agent'
21
+ * const customTools = {
22
+ * ask_user: tool({
23
+ * description:
24
+ * 'Ask the user or parent model a question and wait for their answer. Use this if you need more information or clarification.',
25
+ * inputSchema: zod.object({
26
+ * question: zod.string(),
27
+ * }),
28
+ * execute: async function (this: PageAgent, input) {
29
+ * const answer = await do_some_thing(input.question)
30
+ * return "✅ Received user answer: " + answer
31
+ * },
32
+ * })
33
+ * }
34
+ *
35
+ * @example
36
+ * // remove internal tool
37
+ * const customTools = {
38
+ * ask_user: null // never ask user questions
39
+ * }
40
+ */
41
+ customTools?: Record<string, PageAgentTool | null>;
42
+ onBeforeStep?: (this: PageAgent, stepCnt: number) => Promise<void> | void;
43
+ onAfterStep?: (this: PageAgent, stepCnt: number, history: AgentHistory[]) => Promise<void> | void;
44
+ onBeforeTask?: (this: PageAgent) => Promise<void> | void;
45
+ onAfterTask?: (this: PageAgent, result: ExecutionResult) => Promise<void> | void;
46
+ /**
47
+ * @note this hook can block the disposal process
48
+ * @note when dispose caused by page unload, reason will be 'PAGE_UNLOADING'. this method CANNOT block unloading. async operations may be cut.
49
+ */
50
+ onDispose?: (this: PageAgent, reason?: string) => void;
51
+ /**
52
+ * TODO: @unimplemented
53
+ * hook when action causes a new page to be opened
54
+ * @note PageAgent will try to detect new pages and decide if it's caused by an action. But not very reliable.
55
+ */
56
+ onNewPageOpen?: (this: PageAgent, url: string) => Promise<void> | void;
57
+ /**
58
+ * TODO: @unimplemented
59
+ * try to navigate to a new page instead of opening a new tab/window.
60
+ * @note will unload the current page when a action tries to open a new page. so that things keep in the same tab/window.
61
+ */
62
+ experimentalPreventNewPage?: boolean;
63
+ }
64
+
10
65
  export declare interface AgentHistory {
11
66
  brain: AgentBrain;
12
67
  action: {
@@ -303,9 +358,11 @@ export declare class PageAgent extends EventTarget {
303
358
  bus: EventBus;
304
359
  i18n: I18n;
305
360
  panel: Panel;
361
+ tools: typeof tools;
306
362
  paused: boolean;
307
363
  disposed: boolean;
308
364
  task: string;
365
+ taskId: string;
309
366
  /** Corresponds to eval_page in browser-use */
310
367
  flatTree: FlatDomTree | null;
311
368
  /**
@@ -319,8 +376,6 @@ export declare class PageAgent extends EventTarget {
319
376
  simplifiedHTML: string;
320
377
  /** last time the tree was updated */
321
378
  lastTimeUpdate: number;
322
- /** Corresponds to actions in browser-use */
323
- tools: Map<string, PageAgentTool<any>>;
324
379
  /** Fullscreen mask */
325
380
  mask: SimulatorMask;
326
381
  /** History records */
@@ -330,10 +385,10 @@ export declare class PageAgent extends EventTarget {
330
385
  * @todo maybe return something?
331
386
  */
332
387
  execute(task: string): Promise<ExecutionResult>;
333
- dispose(): void;
388
+ dispose(reason?: string): void;
334
389
  }
335
390
 
336
- export declare type PageAgentConfig = LLMConfig & DomConfig & UIConfig;
391
+ export declare type PageAgentConfig = LLMConfig & AgentConfig & DomConfig;
337
392
 
338
393
  /**
339
394
  * Event mapping definitions
@@ -363,7 +418,7 @@ declare interface PageAgentEventMap {
363
418
  /**
364
419
  * Internal tool definition that has access to PageAgent `this` context
365
420
  */
366
- declare interface PageAgentTool<TParams = any> {
421
+ export declare interface PageAgentTool<TParams = any> {
367
422
  description: string;
368
423
  inputSchema: z.ZodType<TParams>;
369
424
  execute: (this: PageAgent, args: TParams) => Promise<string>;
@@ -422,14 +477,30 @@ declare interface TextDomNode {
422
477
  [key: string]: unknown;
423
478
  }
424
479
 
480
+ export declare function tool<TParams>(options: PageAgentTool<TParams>): PageAgentTool<TParams>;
481
+
482
+ /**
483
+ * Internal tools for PageAgent.
484
+ * Note: Using any to allow different parameter types for each tool
485
+ */
486
+ declare const tools: Map<string, PageAgentTool<any>>;
487
+
425
488
  declare type TranslationKey = NestedKeyOf<TranslationSchema>;
426
489
 
427
490
  declare type TranslationParams = Record<string, string | number>;
428
491
 
429
492
  declare type TranslationSchema = DeepStringify<typeof enUS>;
430
493
 
431
- declare interface UIConfig {
432
- language?: SupportedLanguage;
433
- }
434
-
435
494
  export { }
495
+
496
+
497
+ declare module 'react-i18next' {
498
+ interface CustomTypeOptions {
499
+ defaultNS: 'common';
500
+ resources: {
501
+ common: typeof commonZh;
502
+ home: typeof homeZh;
503
+ docs: typeof docsZh;
504
+ };
505
+ }
506
+ }
@@ -3,7 +3,7 @@
3
3
  try {
4
4
  if (typeof document != "undefined") {
5
5
  var elementStyle = document.createElement("style");
6
- elementStyle.appendChild(document.createTextNode("._wrapper_d1n0a_1 {\n position: fixed;\n bottom: 100px;\n left: 50%;\n transform: translateX(-50%) translateY(20px);\n opacity: 0;\n z-index: 2147483642; /* 比 SimulatorMask 高一层 */\n box-sizing: border-box;\n\n overflow: visible;\n\n * {\n box-sizing: border-box;\n }\n\n --width: 360px;\n --height: 40px;\n --border-radius: 12px;\n\n --side-space: 12px; /* 控制栏两侧的间距 */\n --history-width: calc(var(--width) - var(--side-space) * 2);\n\n --color-1: rgb(57, 182, 255);\n --color-2: rgb(189, 69, 251);\n --color-3: rgb(255, 87, 51);\n --color-4: rgb(255, 214, 0);\n\n width: var(--width);\n height: var(--height);\n\n transition: all 0.3s ease-in-out;\n\n /* 响应式设计 */\n @media (max-width: 480px) {\n width: calc(100vw - 40px);\n left: 20px;\n transform: none;\n }\n\n ._background_d1n0a_40 {\n position: absolute;\n inset: -2px -8px;\n border-radius: calc(var(--border-radius) + 4px);\n filter: blur(16px);\n overflow: hidden;\n /* mix-blend-mode: lighten; */\n /* display: none; */\n\n &::before {\n content: '';\n z-index: -1;\n pointer-events: none;\n position: absolute;\n width: 100%;\n height: 100%;\n /* left: -100%; */\n left: 0;\n top: 0;\n\n background-image: linear-gradient(\n to bottom left,\n var(--color-1),\n var(--color-2),\n var(--color-1)\n );\n animation: _mask-running_d1n0a_1 2s linear infinite;\n }\n &::after {\n content: '';\n z-index: -1;\n pointer-events: none;\n position: absolute;\n width: 100%;\n height: 100%;\n left: 0;\n top: 0;\n\n background-image: linear-gradient(\n to bottom left,\n var(--color-2),\n var(--color-1),\n var(--color-2)\n );\n animation: _mask-running_d1n0a_1 2s linear infinite;\n animation-delay: 1s;\n }\n }\n}\n\n@keyframes _mask-running_d1n0a_1 {\n from {\n transform: translateX(-100%);\n }\n to {\n transform: translateX(100%);\n }\n}\n\n/* 控制栏 */\n._header_d1n0a_100 {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 12px;\n user-select: none;\n\n position: absolute;\n inset: 0;\n\n cursor: pointer;\n flex-shrink: 0; /* 防止 header 被压缩 */\n\n background: rgba(0, 0, 0, 0.5);\n backdrop-filter: blur(10px);\n border-radius: var(--border-radius);\n background-clip: padding-box;\n\n box-shadow:\n 0 0 0px 2px rgba(255, 255, 255, 0.4),\n 0 0 5px 1px rgba(255, 255, 255, 0.3);\n\n ._statusSection_d1n0a_122 {\n display: flex;\n align-items: center;\n gap: 8px;\n flex: 1;\n min-height: 24px; /* 确保垂直居中 */\n\n ._indicator_d1n0a_129 {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: rgba(255, 255, 255, 0.5);\n flex-shrink: 0;\n animation: none; /* 默认无动画 */\n\n /* 运行状态 - 有动画 */\n &._thinking_d1n0a_138 {\n background: rgb(57, 182, 255);\n animation: _pulse_d1n0a_1 0.8s ease-in-out infinite;\n }\n\n &._tool_executing_d1n0a_143 {\n background: rgb(189, 69, 251);\n animation: _pulse_d1n0a_1 0.6s ease-in-out infinite;\n }\n\n &._retry_d1n0a_148 {\n background: rgb(255, 214, 0);\n animation: _retryPulse_d1n0a_1 1s ease-in-out infinite;\n }\n\n /* 静止状态 - 无动画 */\n &._completed_d1n0a_154,\n &._input_d1n0a_155,\n &._output_d1n0a_156 {\n background: rgb(34, 197, 94);\n animation: none;\n }\n\n &._error_d1n0a_161 {\n background: rgb(239, 68, 68);\n animation: none;\n }\n }\n\n ._statusText_d1n0a_167 {\n color: white;\n font-size: 12px;\n line-height: 1;\n font-weight: 500;\n transition: all 0.3s ease-in-out;\n position: relative;\n overflow: hidden;\n display: flex;\n align-items: center;\n min-height: 24px; /* 确保垂直居中 */\n\n &._fadeOut_d1n0a_179 {\n animation: _statusTextFadeOut_d1n0a_1 0.3s ease forwards;\n }\n\n &._fadeIn_d1n0a_183 {\n animation: _statusTextFadeIn_d1n0a_1 0.3s ease forwards;\n }\n }\n }\n\n ._controls_d1n0a_189 {\n display: flex;\n align-items: center;\n gap: 4px;\n\n ._controlButton_d1n0a_194 {\n width: 24px;\n height: 24px;\n border: none;\n border-radius: 4px;\n background: rgba(255, 255, 255, 0.1);\n color: white;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n line-height: 1;\n\n &:hover {\n background: rgba(255, 255, 255, 0.2);\n }\n }\n\n ._pauseButton_d1n0a_213 {\n font-weight: 600;\n &._paused_d1n0a_215 {\n background: rgba(34, 197, 94, 0.2); /* 绿色背景表示可以继续 */\n color: rgb(34, 197, 94);\n\n &:hover {\n background: rgba(34, 197, 94, 0.3);\n }\n }\n }\n\n ._stopButton_d1n0a_225 {\n background: rgba(239, 68, 68, 0.2);\n color: rgb(255, 41, 41);\n font-weight: 600;\n\n &:hover {\n background: rgba(239, 68, 68, 0.3);\n }\n }\n }\n}\n\n@keyframes _statusTextFadeIn_d1n0a_1 {\n 0% {\n opacity: 0;\n transform: translateY(5px);\n }\n 100% {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes _statusTextFadeOut_d1n0a_1 {\n 0% {\n opacity: 1;\n transform: translateY(0);\n }\n 100% {\n opacity: 0;\n transform: translateY(-5px);\n }\n}\n\n._historySectionWrapper_d1n0a_259 {\n position: absolute;\n width: var(--history-width);\n bottom: var(--height);\n left: var(--side-space);\n z-index: -2;\n\n padding-top: 0px;\n visibility: collapse;\n overflow: hidden;\n\n transition: all 0.2s;\n\n background: rgba(2, 0, 20, 0.5);\n /* background: rgba(186, 186, 186, 0.2); */\n backdrop-filter: blur(10px);\n\n text-shadow: 0 0 1px rgba(0, 0, 0, 0.2);\n\n border-top-left-radius: calc(var(--border-radius) + 4px);\n border-top-right-radius: calc(var(--border-radius) + 4px);\n\n /* border: 2px solid rgba(255, 255, 255, 0.8); */\n border: 2px solid rgba(255, 255, 255, 0.4);\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.6);\n\n /* @media (prefers-color-scheme: dark) {\n box-shadow:\n 0 8px 32px 0 rgba(0, 0, 0, 0.85),\n 0 2px 12px 0 rgba(57, 182, 255, 0.1);\n } */\n\n ._expanded_d1n0a_291 & {\n padding-top: 8px;\n visibility: visible;\n }\n\n ._historySection_d1n0a_259 {\n position: relative;\n overflow-y: auto;\n overscroll-behavior: contain;\n scrollbar-width: none;\n max-height: 0;\n padding-inline: 8px;\n\n transition: max-height 0.2s;\n\n ._expanded_d1n0a_291 & {\n max-height: 400px;\n }\n\n ._historyItem_d1n0a_310 {\n /* backdrop-filter: blur(10px); */\n padding: 8px 10px;\n margin-bottom: 6px;\n background: linear-gradient(135deg, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0.03));\n border-radius: 8px;\n border-left: 2px solid rgba(57, 182, 255, 0.5);\n font-size: 12px;\n color: white;\n /* color: black; */\n line-height: 1.3;\n position: relative;\n overflow: hidden;\n\n /* 微妙的内阴影 */\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.1),\n 0 1px 3px rgba(0, 0, 0, 0.1);\n\n &::before {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n height: 1px;\n background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);\n }\n\n &:hover {\n background: linear-gradient(135deg, rgba(255, 255, 255, 0.12), rgba(255, 255, 255, 0.06));\n /* transform: translateY(-1px); */\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.15),\n 0 2px 4px rgba(0, 0, 0, 0.15);\n }\n\n &:last-child {\n margin-bottom: 10px;\n }\n\n &._completed_d1n0a_154,\n &._input_d1n0a_155,\n &._output_d1n0a_156 {\n border-left-color: rgb(34, 197, 94);\n background: linear-gradient(135deg, rgba(34, 197, 94, 0.1), rgba(34, 197, 94, 0.05));\n }\n\n &._error_d1n0a_161 {\n border-left-color: rgb(239, 68, 68);\n background: linear-gradient(135deg, rgba(239, 68, 68, 0.1), rgba(239, 68, 68, 0.05));\n }\n\n &._retry_d1n0a_148 {\n border-left-color: rgb(255, 214, 0);\n background: linear-gradient(135deg, rgba(255, 214, 0, 0.1), rgba(255, 214, 0, 0.05));\n }\n\n /* 突出显示 done 成功结果 */\n &._doneSuccess_d1n0a_369 {\n background: linear-gradient(\n 135deg,\n rgba(34, 197, 94, 0.25),\n rgba(34, 197, 94, 0.15),\n rgba(34, 197, 94, 0.08)\n );\n border: none;\n border-left: 4px solid rgb(34, 197, 94);\n box-shadow:\n 0 4px 12px rgba(34, 197, 94, 0.3),\n inset 0 1px 0 rgba(255, 255, 255, 0.2),\n 0 0 20px rgba(34, 197, 94, 0.1);\n font-weight: 600;\n color: rgb(220, 252, 231);\n padding: 10px 12px;\n margin-bottom: 8px;\n border-radius: 8px;\n position: relative;\n overflow: hidden;\n\n &::before {\n background: linear-gradient(90deg, transparent, rgba(34, 197, 94, 0.4), transparent);\n }\n\n &::after {\n content: '';\n position: absolute;\n top: 0;\n left: -100%;\n width: 100%;\n height: 100%;\n background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.1), transparent);\n animation: _shimmer_d1n0a_1 2s ease-in-out infinite;\n }\n\n ._historyContent_d1n0a_405 {\n ._statusIcon_d1n0a_406 {\n font-size: 16px;\n animation: _celebrate_d1n0a_1 0.8s ease-in-out;\n filter: drop-shadow(0 2px 4px rgba(34, 197, 94, 0.5));\n }\n }\n }\n\n /* 突出显示 done 失败结果 */\n &._doneError_d1n0a_415 {\n background: linear-gradient(\n 135deg,\n rgba(239, 68, 68, 0.25),\n rgba(239, 68, 68, 0.15),\n rgba(239, 68, 68, 0.08)\n );\n border: none;\n border-left: 4px solid rgb(239, 68, 68);\n box-shadow:\n 0 4px 12px rgba(239, 68, 68, 0.3),\n inset 0 1px 0 rgba(255, 255, 255, 0.2),\n 0 0 20px rgba(239, 68, 68, 0.1);\n font-weight: 600;\n color: rgb(254, 226, 226);\n padding: 10px 12px;\n margin-bottom: 8px;\n border-radius: 8px;\n position: relative;\n overflow: hidden;\n\n &::before {\n background: linear-gradient(90deg, transparent, rgba(239, 68, 68, 0.4), transparent);\n }\n\n ._historyContent_d1n0a_405 {\n ._statusIcon_d1n0a_406 {\n font-size: 16px;\n filter: drop-shadow(0 2px 4px rgba(239, 68, 68, 0.5));\n }\n }\n }\n\n ._historyContent_d1n0a_405 {\n display: flex;\n align-items: center;\n gap: 8px;\n\n word-break: break-all;\n white-space: pre-wrap;\n\n /* overflow-x: auto; */\n\n ._statusIcon_d1n0a_406 {\n font-size: 12px;\n flex-shrink: 0;\n line-height: 1;\n transition: all 0.3s ease;\n }\n }\n\n ._historyMeta_d1n0a_466 {\n font-size: 10px;\n color: rgba(255, 255, 255, 0.6);\n /* color: rgb(61, 61, 61); */\n margin-top: 8px;\n line-height: 1;\n }\n }\n }\n}\n\n/* 动画关键帧 - 更快的闪烁 */\n@keyframes _pulse_d1n0a_1 {\n 0%,\n 100% {\n opacity: 1;\n transform: scale(1);\n }\n 50% {\n opacity: 0.4;\n transform: scale(1.3);\n }\n}\n\n/* 重试动画 - 旋转脉冲 */\n@keyframes _retryPulse_d1n0a_1 {\n 0%,\n 100% {\n opacity: 1;\n transform: scale(1) rotate(0deg);\n }\n 25% {\n opacity: 0.6;\n transform: scale(1.2) rotate(90deg);\n }\n 50% {\n opacity: 0.8;\n transform: scale(1.1) rotate(180deg);\n }\n 75% {\n opacity: 0.6;\n transform: scale(1.2) rotate(270deg);\n }\n}\n\n/* 庆祝动画 */\n@keyframes _celebrate_d1n0a_1 {\n 0%,\n 100% {\n transform: scale(1);\n }\n 25% {\n transform: scale(1.2) rotate(-5deg);\n }\n 75% {\n transform: scale(1.2) rotate(5deg);\n }\n}\n\n/* done 卡片的光泽效果 */\n@keyframes _shimmer_d1n0a_1 {\n 0% {\n left: -100%;\n }\n 100% {\n left: 100%;\n }\n}\n\n/* 输入区域样式 */\n._inputSectionWrapper_d1n0a_536 {\n position: absolute;\n width: var(--history-width);\n top: var(--height);\n left: var(--side-space);\n z-index: -1;\n\n visibility: visible;\n overflow: hidden;\n\n height: 48px;\n\n transition: all 0.2s;\n\n background: rgba(186, 186, 186, 0.2);\n backdrop-filter: blur(10px);\n\n border-bottom-left-radius: calc(var(--border-radius) + 4px);\n border-bottom-right-radius: calc(var(--border-radius) + 4px);\n\n border: 2px solid rgba(255, 255, 255, 0.3);\n box-shadow: 0 1px 16px rgba(0, 0, 0, 0.4);\n\n &._hidden_d1n0a_559 {\n visibility: collapse;\n height: 0;\n }\n\n ._inputSection_d1n0a_536 {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 8px 8px;\n\n ._taskInput_d1n0a_570 {\n flex: 1;\n background: rgba(255, 255, 255, 0.4);\n border: 1px solid rgba(255, 255, 255, 0.3);\n border-radius: 10px;\n padding-inline: 10px;\n color: rgb(20, 20, 20);\n font-size: 12px;\n height: 28px;\n line-height: 1;\n outline: none;\n transition: all 0.2s ease;\n\n /* text-shadow: 0 0 2px rgba(255, 255, 255, 0.8); */\n\n /* border-color: rgba(57, 182, 255, 0.3); */\n\n &::placeholder {\n color: rgb(53, 53, 53);\n }\n\n &:focus {\n background: rgba(255, 255, 255, 0.8);\n border-color: rgba(57, 182, 255, 0.6);\n box-shadow: 0 0 0 2px rgba(57, 182, 255, 0.2);\n }\n }\n }\n}\n._wrapper_1oy2s_1 {\n position: fixed;\n inset: 0;\n z-index: 2147483641; /* 确保在所有元素之上,除了 panel */\n /* pointer-events: none; */\n cursor: not-allowed;\n overflow: hidden;\n\n display: none;\n}\n/* AI 光标样式 */\n._cursor_1vrf3_2 {\n position: absolute;\n width: var(--cursor-size, 75px);\n height: var(--cursor-size, 75px);\n pointer-events: none;\n z-index: 10000;\n transform: translate(-30%, -30%);\n\n animation: _cursor-enter_1vrf3_1 300ms ease-out forwards;\n}\n\n._cursorBorder_1vrf3_13 {\n position: absolute;\n inset: 0;\n background: linear-gradient(45deg, rgb(57, 182, 255), rgb(189, 69, 251));\n mask-image: url(https://img.alicdn.com/imgextra/i1/O1CN01YHLVYR1LvqWIyo5kH_!!6000000001362-2-tps-202-202.png);\n mask-size: 100% 100%;\n mask-repeat: no-repeat;\n animation: _cursor-breathe_1vrf3_1 2s ease-in-out infinite;\n}\n\n._cursorFilling_1vrf3_23 {\n position: absolute;\n inset: 0;\n background: url(https://img.alicdn.com/imgextra/i3/O1CN01JZOqOS1Tu1sIKbPLW_!!6000000002441-2-tps-202-202.png);\n background-size: 100% 100%;\n background-repeat: no-repeat;\n}\n\n._cursorRipple_1vrf3_31 {\n position: absolute;\n inset: 0;\n pointer-events: none;\n}\n\n._cursor_1vrf3_2._clicking_1vrf3_37 ._cursorRipple_1vrf3_31::after {\n content: '';\n position: absolute;\n width: 100%;\n height: 100%;\n left: -30%;\n top: -30%;\n border: 4px solid rgba(57, 182, 255, 1);\n border-radius: 50%;\n animation: _cursor-ripple_1vrf3_1 300ms ease-out forwards;\n}\n\n/* 光标动画关键帧 */\n@keyframes _cursor-breathe_1vrf3_1 {\n 0%,\n 100% {\n transform: scale(1);\n opacity: 0.9;\n }\n 50% {\n transform: scale(1.05);\n opacity: 1;\n }\n}\n\n@keyframes _cursor-rotate_1vrf3_1 {\n 0% {\n transform: rotate(0deg);\n }\n 100% {\n transform: rotate(360deg);\n }\n}\n\n@keyframes _cursor-enter_1vrf3_1 {\n 0% {\n transform: translate(-30%, -30%) scale(0.5);\n opacity: 0;\n }\n 100% {\n transform: translate(-30%, -30%) scale(1);\n opacity: 1;\n }\n}\n\n@keyframes _cursor-ripple_1vrf3_1 {\n 0% {\n transform: scale(0);\n opacity: 1;\n }\n 100% {\n transform: scale(2);\n opacity: 0;\n }\n}"));
6
+ elementStyle.appendChild(document.createTextNode("._wrapper_1j0ct_1 {\n position: fixed;\n bottom: 100px;\n left: 50%;\n transform: translateX(-50%) translateY(20px);\n opacity: 0;\n z-index: 2147483642; /* 比 SimulatorMask 高一层 */\n box-sizing: border-box;\n\n overflow: visible;\n\n * {\n box-sizing: border-box;\n }\n\n --width: 360px;\n --height: 40px;\n --border-radius: 12px;\n\n --side-space: 12px; /* 控制栏两侧的间距 */\n --history-width: calc(var(--width) - var(--side-space) * 2);\n\n --color-1: rgb(57, 182, 255);\n --color-2: rgb(189, 69, 251);\n --color-3: rgb(255, 87, 51);\n --color-4: rgb(255, 214, 0);\n\n width: var(--width);\n height: var(--height);\n\n transition: all 0.3s ease-in-out;\n\n /* 响应式设计 */\n @media (max-width: 480px) {\n width: calc(100vw - 40px);\n --width: calc(100vw - 40px);\n }\n\n ._background_1j0ct_39 {\n position: absolute;\n inset: -2px -8px;\n border-radius: calc(var(--border-radius) + 4px);\n filter: blur(16px);\n overflow: hidden;\n /* mix-blend-mode: lighten; */\n /* display: none; */\n\n &::before {\n content: '';\n z-index: -1;\n pointer-events: none;\n position: absolute;\n width: 100%;\n height: 100%;\n /* left: -100%; */\n left: 0;\n top: 0;\n\n background-image: linear-gradient(\n to bottom left,\n var(--color-1),\n var(--color-2),\n var(--color-1)\n );\n animation: _mask-running_1j0ct_1 2s linear infinite;\n }\n &::after {\n content: '';\n z-index: -1;\n pointer-events: none;\n position: absolute;\n width: 100%;\n height: 100%;\n left: 0;\n top: 0;\n\n background-image: linear-gradient(\n to bottom left,\n var(--color-2),\n var(--color-1),\n var(--color-2)\n );\n animation: _mask-running_1j0ct_1 2s linear infinite;\n animation-delay: 1s;\n }\n }\n}\n\n@keyframes _mask-running_1j0ct_1 {\n from {\n transform: translateX(-100%);\n }\n to {\n transform: translateX(100%);\n }\n}\n\n/* 控制栏 */\n._header_1j0ct_99 {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 12px;\n user-select: none;\n\n position: absolute;\n inset: 0;\n\n cursor: pointer;\n flex-shrink: 0; /* 防止 header 被压缩 */\n\n background: rgba(0, 0, 0, 0.5);\n backdrop-filter: blur(10px);\n border-radius: var(--border-radius);\n background-clip: padding-box;\n\n box-shadow:\n 0 0 0px 2px rgba(255, 255, 255, 0.4),\n 0 0 5px 1px rgba(255, 255, 255, 0.3);\n\n ._statusSection_1j0ct_121 {\n display: flex;\n align-items: center;\n gap: 8px;\n flex: 1;\n min-height: 24px; /* 确保垂直居中 */\n\n ._indicator_1j0ct_128 {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: rgba(255, 255, 255, 0.5);\n flex-shrink: 0;\n animation: none; /* 默认无动画 */\n\n /* 运行状态 - 有动画 */\n &._thinking_1j0ct_137 {\n background: rgb(57, 182, 255);\n animation: _pulse_1j0ct_1 0.8s ease-in-out infinite;\n }\n\n &._tool_executing_1j0ct_142 {\n background: rgb(189, 69, 251);\n animation: _pulse_1j0ct_1 0.6s ease-in-out infinite;\n }\n\n &._retry_1j0ct_147 {\n background: rgb(255, 214, 0);\n animation: _retryPulse_1j0ct_1 1s ease-in-out infinite;\n }\n\n /* 静止状态 - 无动画 */\n &._completed_1j0ct_153,\n &._input_1j0ct_154,\n &._output_1j0ct_155 {\n background: rgb(34, 197, 94);\n animation: none;\n }\n\n &._error_1j0ct_160 {\n background: rgb(239, 68, 68);\n animation: none;\n }\n }\n\n ._statusText_1j0ct_166 {\n color: white;\n font-size: 12px;\n line-height: 1;\n font-weight: 500;\n transition: all 0.3s ease-in-out;\n position: relative;\n overflow: hidden;\n display: flex;\n align-items: center;\n min-height: 24px; /* 确保垂直居中 */\n\n &._fadeOut_1j0ct_178 {\n animation: _statusTextFadeOut_1j0ct_1 0.3s ease forwards;\n }\n\n &._fadeIn_1j0ct_182 {\n animation: _statusTextFadeIn_1j0ct_1 0.3s ease forwards;\n }\n }\n }\n\n ._controls_1j0ct_188 {\n display: flex;\n align-items: center;\n gap: 4px;\n\n ._controlButton_1j0ct_193 {\n width: 24px;\n height: 24px;\n border: none;\n border-radius: 4px;\n background: rgba(255, 255, 255, 0.1);\n color: white;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n line-height: 1;\n\n &:hover {\n background: rgba(255, 255, 255, 0.2);\n }\n }\n\n ._pauseButton_1j0ct_212 {\n font-weight: 600;\n &._paused_1j0ct_214 {\n background: rgba(34, 197, 94, 0.2); /* 绿色背景表示可以继续 */\n color: rgb(34, 197, 94);\n\n &:hover {\n background: rgba(34, 197, 94, 0.3);\n }\n }\n }\n\n ._stopButton_1j0ct_224 {\n background: rgba(239, 68, 68, 0.2);\n color: rgb(255, 41, 41);\n font-weight: 600;\n\n &:hover {\n background: rgba(239, 68, 68, 0.3);\n }\n }\n }\n}\n\n@keyframes _statusTextFadeIn_1j0ct_1 {\n 0% {\n opacity: 0;\n transform: translateY(5px);\n }\n 100% {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes _statusTextFadeOut_1j0ct_1 {\n 0% {\n opacity: 1;\n transform: translateY(0);\n }\n 100% {\n opacity: 0;\n transform: translateY(-5px);\n }\n}\n\n._historySectionWrapper_1j0ct_258 {\n position: absolute;\n width: var(--history-width);\n bottom: var(--height);\n left: var(--side-space);\n z-index: -2;\n\n padding-top: 0px;\n visibility: collapse;\n overflow: hidden;\n\n transition: all 0.2s;\n\n background: rgba(2, 0, 20, 0.5);\n /* background: rgba(186, 186, 186, 0.2); */\n backdrop-filter: blur(10px);\n\n text-shadow: 0 0 1px rgba(0, 0, 0, 0.2);\n\n border-top-left-radius: calc(var(--border-radius) + 4px);\n border-top-right-radius: calc(var(--border-radius) + 4px);\n\n /* border: 2px solid rgba(255, 255, 255, 0.8); */\n border: 2px solid rgba(255, 255, 255, 0.4);\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.6);\n\n /* @media (prefers-color-scheme: dark) {\n box-shadow:\n 0 8px 32px 0 rgba(0, 0, 0, 0.85),\n 0 2px 12px 0 rgba(57, 182, 255, 0.1);\n } */\n\n ._expanded_1j0ct_290 & {\n padding-top: 8px;\n visibility: visible;\n }\n\n ._historySection_1j0ct_258 {\n position: relative;\n overflow-y: auto;\n overscroll-behavior: contain;\n scrollbar-width: none;\n max-height: 0;\n padding-inline: 8px;\n\n transition: max-height 0.2s;\n\n ._expanded_1j0ct_290 & {\n max-height: 400px;\n }\n\n ._historyItem_1j0ct_309 {\n /* backdrop-filter: blur(10px); */\n padding: 8px 10px;\n margin-bottom: 6px;\n background: linear-gradient(135deg, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0.03));\n border-radius: 8px;\n border-left: 2px solid rgba(57, 182, 255, 0.5);\n font-size: 12px;\n color: white;\n /* color: black; */\n line-height: 1.3;\n position: relative;\n overflow: hidden;\n\n /* 微妙的内阴影 */\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.1),\n 0 1px 3px rgba(0, 0, 0, 0.1);\n\n &::before {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n height: 1px;\n background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);\n }\n\n &:hover {\n background: linear-gradient(135deg, rgba(255, 255, 255, 0.12), rgba(255, 255, 255, 0.06));\n /* transform: translateY(-1px); */\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.15),\n 0 2px 4px rgba(0, 0, 0, 0.15);\n }\n\n &:last-child {\n margin-bottom: 10px;\n }\n\n &._completed_1j0ct_153,\n &._input_1j0ct_154,\n &._output_1j0ct_155 {\n border-left-color: rgb(34, 197, 94);\n background: linear-gradient(135deg, rgba(34, 197, 94, 0.1), rgba(34, 197, 94, 0.05));\n }\n\n &._error_1j0ct_160 {\n border-left-color: rgb(239, 68, 68);\n background: linear-gradient(135deg, rgba(239, 68, 68, 0.1), rgba(239, 68, 68, 0.05));\n }\n\n &._retry_1j0ct_147 {\n border-left-color: rgb(255, 214, 0);\n background: linear-gradient(135deg, rgba(255, 214, 0, 0.1), rgba(255, 214, 0, 0.05));\n }\n\n /* 突出显示 done 成功结果 */\n &._doneSuccess_1j0ct_368 {\n background: linear-gradient(\n 135deg,\n rgba(34, 197, 94, 0.25),\n rgba(34, 197, 94, 0.15),\n rgba(34, 197, 94, 0.08)\n );\n border: none;\n border-left: 4px solid rgb(34, 197, 94);\n box-shadow:\n 0 4px 12px rgba(34, 197, 94, 0.3),\n inset 0 1px 0 rgba(255, 255, 255, 0.2),\n 0 0 20px rgba(34, 197, 94, 0.1);\n font-weight: 600;\n color: rgb(220, 252, 231);\n padding: 10px 12px;\n margin-bottom: 8px;\n border-radius: 8px;\n position: relative;\n overflow: hidden;\n\n &::before {\n background: linear-gradient(90deg, transparent, rgba(34, 197, 94, 0.4), transparent);\n }\n\n &::after {\n content: '';\n position: absolute;\n top: 0;\n left: -100%;\n width: 100%;\n height: 100%;\n background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.1), transparent);\n animation: _shimmer_1j0ct_1 2s ease-in-out infinite;\n }\n\n ._historyContent_1j0ct_404 {\n ._statusIcon_1j0ct_405 {\n font-size: 16px;\n animation: _celebrate_1j0ct_1 0.8s ease-in-out;\n filter: drop-shadow(0 2px 4px rgba(34, 197, 94, 0.5));\n }\n }\n }\n\n /* 突出显示 done 失败结果 */\n &._doneError_1j0ct_414 {\n background: linear-gradient(\n 135deg,\n rgba(239, 68, 68, 0.25),\n rgba(239, 68, 68, 0.15),\n rgba(239, 68, 68, 0.08)\n );\n border: none;\n border-left: 4px solid rgb(239, 68, 68);\n box-shadow:\n 0 4px 12px rgba(239, 68, 68, 0.3),\n inset 0 1px 0 rgba(255, 255, 255, 0.2),\n 0 0 20px rgba(239, 68, 68, 0.1);\n font-weight: 600;\n color: rgb(254, 226, 226);\n padding: 10px 12px;\n margin-bottom: 8px;\n border-radius: 8px;\n position: relative;\n overflow: hidden;\n\n &::before {\n background: linear-gradient(90deg, transparent, rgba(239, 68, 68, 0.4), transparent);\n }\n\n ._historyContent_1j0ct_404 {\n ._statusIcon_1j0ct_405 {\n font-size: 16px;\n filter: drop-shadow(0 2px 4px rgba(239, 68, 68, 0.5));\n }\n }\n }\n\n ._historyContent_1j0ct_404 {\n display: flex;\n align-items: center;\n gap: 8px;\n\n word-break: break-all;\n white-space: pre-wrap;\n\n /* overflow-x: auto; */\n\n ._statusIcon_1j0ct_405 {\n font-size: 12px;\n flex-shrink: 0;\n line-height: 1;\n transition: all 0.3s ease;\n }\n }\n\n ._historyMeta_1j0ct_465 {\n font-size: 10px;\n color: rgba(255, 255, 255, 0.6);\n /* color: rgb(61, 61, 61); */\n margin-top: 8px;\n line-height: 1;\n }\n }\n }\n}\n\n/* 动画关键帧 - 更快的闪烁 */\n@keyframes _pulse_1j0ct_1 {\n 0%,\n 100% {\n opacity: 1;\n transform: scale(1);\n }\n 50% {\n opacity: 0.4;\n transform: scale(1.3);\n }\n}\n\n/* 重试动画 - 旋转脉冲 */\n@keyframes _retryPulse_1j0ct_1 {\n 0%,\n 100% {\n opacity: 1;\n transform: scale(1) rotate(0deg);\n }\n 25% {\n opacity: 0.6;\n transform: scale(1.2) rotate(90deg);\n }\n 50% {\n opacity: 0.8;\n transform: scale(1.1) rotate(180deg);\n }\n 75% {\n opacity: 0.6;\n transform: scale(1.2) rotate(270deg);\n }\n}\n\n/* 庆祝动画 */\n@keyframes _celebrate_1j0ct_1 {\n 0%,\n 100% {\n transform: scale(1);\n }\n 25% {\n transform: scale(1.2) rotate(-5deg);\n }\n 75% {\n transform: scale(1.2) rotate(5deg);\n }\n}\n\n/* done 卡片的光泽效果 */\n@keyframes _shimmer_1j0ct_1 {\n 0% {\n left: -100%;\n }\n 100% {\n left: 100%;\n }\n}\n\n/* 输入区域样式 */\n._inputSectionWrapper_1j0ct_535 {\n position: absolute;\n width: var(--history-width);\n top: var(--height);\n left: var(--side-space);\n z-index: -1;\n\n visibility: visible;\n overflow: hidden;\n\n height: 48px;\n\n transition: all 0.2s;\n\n background: rgba(186, 186, 186, 0.2);\n backdrop-filter: blur(10px);\n\n border-bottom-left-radius: calc(var(--border-radius) + 4px);\n border-bottom-right-radius: calc(var(--border-radius) + 4px);\n\n border: 2px solid rgba(255, 255, 255, 0.3);\n box-shadow: 0 1px 16px rgba(0, 0, 0, 0.4);\n\n &._hidden_1j0ct_558 {\n visibility: collapse;\n height: 0;\n }\n\n ._inputSection_1j0ct_535 {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 8px 8px;\n\n ._taskInput_1j0ct_569 {\n flex: 1;\n background: rgba(255, 255, 255, 0.4);\n border: 1px solid rgba(255, 255, 255, 0.3);\n border-radius: 10px;\n padding-inline: 10px;\n color: rgb(20, 20, 20);\n font-size: 12px;\n height: 28px;\n line-height: 1;\n outline: none;\n transition: all 0.2s ease;\n\n /* text-shadow: 0 0 2px rgba(255, 255, 255, 0.8); */\n\n /* border-color: rgba(57, 182, 255, 0.3); */\n\n &::placeholder {\n color: rgb(53, 53, 53);\n }\n\n &:focus {\n background: rgba(255, 255, 255, 0.8);\n border-color: rgba(57, 182, 255, 0.6);\n box-shadow: 0 0 0 2px rgba(57, 182, 255, 0.2);\n }\n }\n }\n}\n._wrapper_1oy2s_1 {\n position: fixed;\n inset: 0;\n z-index: 2147483641; /* 确保在所有元素之上,除了 panel */\n /* pointer-events: none; */\n cursor: not-allowed;\n overflow: hidden;\n\n display: none;\n}\n/* AI 光标样式 */\n._cursor_1vrf3_2 {\n position: absolute;\n width: var(--cursor-size, 75px);\n height: var(--cursor-size, 75px);\n pointer-events: none;\n z-index: 10000;\n transform: translate(-30%, -30%);\n\n animation: _cursor-enter_1vrf3_1 300ms ease-out forwards;\n}\n\n._cursorBorder_1vrf3_13 {\n position: absolute;\n inset: 0;\n background: linear-gradient(45deg, rgb(57, 182, 255), rgb(189, 69, 251));\n mask-image: url(https://img.alicdn.com/imgextra/i1/O1CN01YHLVYR1LvqWIyo5kH_!!6000000001362-2-tps-202-202.png);\n mask-size: 100% 100%;\n mask-repeat: no-repeat;\n animation: _cursor-breathe_1vrf3_1 2s ease-in-out infinite;\n}\n\n._cursorFilling_1vrf3_23 {\n position: absolute;\n inset: 0;\n background: url(https://img.alicdn.com/imgextra/i3/O1CN01JZOqOS1Tu1sIKbPLW_!!6000000002441-2-tps-202-202.png);\n background-size: 100% 100%;\n background-repeat: no-repeat;\n}\n\n._cursorRipple_1vrf3_31 {\n position: absolute;\n inset: 0;\n pointer-events: none;\n}\n\n._cursor_1vrf3_2._clicking_1vrf3_37 ._cursorRipple_1vrf3_31::after {\n content: '';\n position: absolute;\n width: 100%;\n height: 100%;\n left: -30%;\n top: -30%;\n border: 4px solid rgba(57, 182, 255, 1);\n border-radius: 50%;\n animation: _cursor-ripple_1vrf3_1 300ms ease-out forwards;\n}\n\n/* 光标动画关键帧 */\n@keyframes _cursor-breathe_1vrf3_1 {\n 0%,\n 100% {\n transform: scale(1);\n opacity: 0.9;\n }\n 50% {\n transform: scale(1.05);\n opacity: 1;\n }\n}\n\n@keyframes _cursor-rotate_1vrf3_1 {\n 0% {\n transform: rotate(0deg);\n }\n 100% {\n transform: rotate(360deg);\n }\n}\n\n@keyframes _cursor-enter_1vrf3_1 {\n 0% {\n transform: translate(-30%, -30%) scale(0.5);\n opacity: 0;\n }\n 100% {\n transform: translate(-30%, -30%) scale(1);\n opacity: 1;\n }\n}\n\n@keyframes _cursor-ripple_1vrf3_1 {\n 0% {\n transform: scale(0);\n opacity: 1;\n }\n 100% {\n transform: scale(2);\n opacity: 0;\n }\n}"));
7
7
  document.head.appendChild(elementStyle);
8
8
  }
9
9
  } catch (e) {
@@ -27,9 +27,9 @@ import chalk from "chalk";
27
27
  import zod, { z } from "zod";
28
28
  import { Motion } from "ai-motion";
29
29
  const VIEWPORT_EXPANSION = -1;
30
- const DEFAULT_MODEL_NAME = "gpt-41-mini-0414-global";
31
- const DEFAULT_API_KEY = "not-needed";
32
- const DEFAULT_BASE_URL = "http://localhost:3000/api/agent";
30
+ const DEFAULT_MODEL_NAME = "PAGE-AGENT-FREE-TESTING-RANDOM";
31
+ const DEFAULT_API_KEY = "PAGE-AGENT-FREE-TESTING-RANDOM";
32
+ const DEFAULT_BASE_URL = "https://hwcxiuzfylggtcktqgij.supabase.co/functions/v1/llm-testing-proxy";
33
33
  const LLM_MAX_RETRIES = 2;
34
34
  const MAX_STEPS = 20;
35
35
  const DEFAULT_TEMPERATURE = 0.7;
@@ -2527,48 +2527,48 @@ const _UIState = class _UIState {
2527
2527
  };
2528
2528
  __name(_UIState, "UIState");
2529
2529
  let UIState = _UIState;
2530
- const wrapper$1 = "_wrapper_d1n0a_1";
2531
- const background = "_background_d1n0a_40";
2532
- const header = "_header_d1n0a_100";
2533
- const pulse = "_pulse_d1n0a_1";
2534
- const retryPulse = "_retryPulse_d1n0a_1";
2535
- const statusTextFadeOut = "_statusTextFadeOut_d1n0a_1";
2536
- const statusTextFadeIn = "_statusTextFadeIn_d1n0a_1";
2537
- const statusSection = "_statusSection_d1n0a_122";
2538
- const indicator = "_indicator_d1n0a_129";
2539
- const thinking = "_thinking_d1n0a_138";
2540
- const tool_executing = "_tool_executing_d1n0a_143";
2541
- const retry = "_retry_d1n0a_148";
2542
- const completed = "_completed_d1n0a_154";
2543
- const input = "_input_d1n0a_155";
2544
- const output = "_output_d1n0a_156";
2545
- const error = "_error_d1n0a_161";
2546
- const statusText = "_statusText_d1n0a_167";
2547
- const fadeOut = "_fadeOut_d1n0a_179";
2548
- const fadeIn = "_fadeIn_d1n0a_183";
2549
- const controls = "_controls_d1n0a_189";
2550
- const controlButton = "_controlButton_d1n0a_194";
2551
- const pauseButton = "_pauseButton_d1n0a_213";
2552
- const paused = "_paused_d1n0a_215";
2553
- const stopButton = "_stopButton_d1n0a_225";
2554
- const historySectionWrapper = "_historySectionWrapper_d1n0a_259";
2555
- const shimmer = "_shimmer_d1n0a_1";
2556
- const celebrate = "_celebrate_d1n0a_1";
2557
- const expanded = "_expanded_d1n0a_291";
2558
- const historySection = "_historySection_d1n0a_259";
2559
- const historyItem = "_historyItem_d1n0a_310";
2560
- const doneSuccess = "_doneSuccess_d1n0a_369";
2561
- const historyContent = "_historyContent_d1n0a_405";
2562
- const statusIcon = "_statusIcon_d1n0a_406";
2563
- const doneError = "_doneError_d1n0a_415";
2564
- const historyMeta = "_historyMeta_d1n0a_466";
2565
- const inputSectionWrapper = "_inputSectionWrapper_d1n0a_536";
2566
- const hidden = "_hidden_d1n0a_559";
2567
- const inputSection = "_inputSection_d1n0a_536";
2568
- const taskInput = "_taskInput_d1n0a_570";
2530
+ const wrapper$1 = "_wrapper_1j0ct_1";
2531
+ const background = "_background_1j0ct_39";
2532
+ const header = "_header_1j0ct_99";
2533
+ const pulse = "_pulse_1j0ct_1";
2534
+ const retryPulse = "_retryPulse_1j0ct_1";
2535
+ const statusTextFadeOut = "_statusTextFadeOut_1j0ct_1";
2536
+ const statusTextFadeIn = "_statusTextFadeIn_1j0ct_1";
2537
+ const statusSection = "_statusSection_1j0ct_121";
2538
+ const indicator = "_indicator_1j0ct_128";
2539
+ const thinking = "_thinking_1j0ct_137";
2540
+ const tool_executing = "_tool_executing_1j0ct_142";
2541
+ const retry = "_retry_1j0ct_147";
2542
+ const completed = "_completed_1j0ct_153";
2543
+ const input = "_input_1j0ct_154";
2544
+ const output = "_output_1j0ct_155";
2545
+ const error = "_error_1j0ct_160";
2546
+ const statusText = "_statusText_1j0ct_166";
2547
+ const fadeOut = "_fadeOut_1j0ct_178";
2548
+ const fadeIn = "_fadeIn_1j0ct_182";
2549
+ const controls = "_controls_1j0ct_188";
2550
+ const controlButton = "_controlButton_1j0ct_193";
2551
+ const pauseButton = "_pauseButton_1j0ct_212";
2552
+ const paused = "_paused_1j0ct_214";
2553
+ const stopButton = "_stopButton_1j0ct_224";
2554
+ const historySectionWrapper = "_historySectionWrapper_1j0ct_258";
2555
+ const shimmer = "_shimmer_1j0ct_1";
2556
+ const celebrate = "_celebrate_1j0ct_1";
2557
+ const expanded = "_expanded_1j0ct_290";
2558
+ const historySection = "_historySection_1j0ct_258";
2559
+ const historyItem = "_historyItem_1j0ct_309";
2560
+ const doneSuccess = "_doneSuccess_1j0ct_368";
2561
+ const historyContent = "_historyContent_1j0ct_404";
2562
+ const statusIcon = "_statusIcon_1j0ct_405";
2563
+ const doneError = "_doneError_1j0ct_414";
2564
+ const historyMeta = "_historyMeta_1j0ct_465";
2565
+ const inputSectionWrapper = "_inputSectionWrapper_1j0ct_535";
2566
+ const hidden = "_hidden_1j0ct_558";
2567
+ const inputSection = "_inputSection_1j0ct_535";
2568
+ const taskInput = "_taskInput_1j0ct_569";
2569
2569
  const styles$1 = {
2570
2570
  wrapper: wrapper$1,
2571
- "mask-running": "_mask-running_d1n0a_1",
2571
+ "mask-running": "_mask-running_1j0ct_1",
2572
2572
  background,
2573
2573
  header,
2574
2574
  pulse,
@@ -3333,9 +3333,11 @@ const _PageAgent = class _PageAgent extends EventTarget {
3333
3333
  __publicField(this, "bus", getEventBus(this.id));
3334
3334
  __publicField(this, "i18n");
3335
3335
  __publicField(this, "panel");
3336
+ __publicField(this, "tools");
3336
3337
  __publicField(this, "paused", false);
3337
3338
  __publicField(this, "disposed", false);
3338
3339
  __publicField(this, "task", "");
3340
+ __publicField(this, "taskId", "");
3339
3341
  __privateAdd(this, _llm);
3340
3342
  __privateAdd(this, _totalWaitTime, 0);
3341
3343
  __privateAdd(this, _abortController, new AbortController());
@@ -3352,8 +3354,6 @@ const _PageAgent = class _PageAgent extends EventTarget {
3352
3354
  __publicField(this, "simplifiedHTML", "<EMPTY>");
3353
3355
  /** last time the tree was updated */
3354
3356
  __publicField(this, "lastTimeUpdate", 0);
3355
- /** Corresponds to actions in browser-use */
3356
- __publicField(this, "tools", new Map(tools));
3357
3357
  /** Fullscreen mask */
3358
3358
  __publicField(this, "mask", new SimulatorMask());
3359
3359
  /** History records */
@@ -3362,7 +3362,20 @@ const _PageAgent = class _PageAgent extends EventTarget {
3362
3362
  __privateSet(this, _llm, new LLM(this.config, this.id));
3363
3363
  this.i18n = new I18n(this.config.language);
3364
3364
  this.panel = new Panel(this);
3365
+ this.tools = new Map(tools);
3366
+ if (this.config.customTools) {
3367
+ for (const [name, tool2] of Object.entries(this.config.customTools)) {
3368
+ if (tool2 === null) {
3369
+ this.tools.delete(name);
3370
+ continue;
3371
+ }
3372
+ this.tools.set(name, tool2);
3373
+ }
3374
+ }
3365
3375
  patchReact();
3376
+ window.addEventListener("beforeunload", (e) => {
3377
+ if (!this.disposed) this.dispose("PAGE_UNLOADING");
3378
+ });
3366
3379
  }
3367
3380
  /**
3368
3381
  * @todo maybe return something?
@@ -3370,12 +3383,18 @@ const _PageAgent = class _PageAgent extends EventTarget {
3370
3383
  async execute(task) {
3371
3384
  if (!task) throw new Error("Task is required");
3372
3385
  this.task = task;
3386
+ this.taskId = uid();
3387
+ const onBeforeStep = this.config.onBeforeStep || (() => void 0);
3388
+ const onAfterStep = this.config.onAfterStep || (() => void 0);
3389
+ const onBeforeTask = this.config.onBeforeTask || (() => void 0);
3390
+ const onAfterTask = this.config.onAfterTask || (() => void 0);
3391
+ await onBeforeTask.call(this);
3373
3392
  this.mask.show();
3374
3393
  this.bus.emit("panel:show");
3375
3394
  this.bus.emit("panel:reset");
3376
3395
  this.bus.emit("panel:update", {
3377
3396
  type: "input",
3378
- displayText: task
3397
+ displayText: this.task
3379
3398
  });
3380
3399
  if (__privateGet(this, _abortController)) {
3381
3400
  __privateGet(this, _abortController).abort();
@@ -3385,6 +3404,7 @@ const _PageAgent = class _PageAgent extends EventTarget {
3385
3404
  try {
3386
3405
  let step = 0;
3387
3406
  while (true) {
3407
+ await onBeforeStep.call(this, step);
3388
3408
  console.group(`step: ${step + 1}`);
3389
3409
  if (__privateGet(this, _abortController).signal.aborted) throw new Error("AbortError");
3390
3410
  await waitUntil(() => !this.paused);
@@ -3428,38 +3448,45 @@ const _PageAgent = class _PageAgent extends EventTarget {
3428
3448
  });
3429
3449
  console.log(chalk.green("Step finished:"), actionName);
3430
3450
  console.groupEnd();
3451
+ await onAfterStep.call(this, step, this.history);
3431
3452
  step++;
3432
3453
  if (step > MAX_STEPS) {
3433
3454
  __privateMethod(this, _PageAgent_instances, onDone_fn).call(this, "Step count exceeded maximum limit", false);
3434
- return {
3455
+ const result2 = {
3435
3456
  success: false,
3436
3457
  data: "Step count exceeded maximum limit",
3437
3458
  history: this.history
3438
3459
  };
3460
+ await onAfterTask.call(this, result2);
3461
+ return result2;
3439
3462
  }
3440
3463
  if (actionName === "done") {
3441
3464
  const success = action.input?.success ?? false;
3442
3465
  const text = action.input?.text || "no text provided";
3443
3466
  console.log(chalk.green.bold("Task completed"), success, text);
3444
3467
  __privateMethod(this, _PageAgent_instances, onDone_fn).call(this, text, success);
3445
- return {
3468
+ const result2 = {
3446
3469
  success,
3447
3470
  data: text,
3448
3471
  history: this.history
3449
3472
  };
3473
+ await onAfterTask.call(this, result2);
3474
+ return result2;
3450
3475
  }
3451
3476
  }
3452
3477
  } catch (error2) {
3453
3478
  console.error("Task failed", error2);
3454
3479
  __privateMethod(this, _PageAgent_instances, onDone_fn).call(this, String(error2), false);
3455
- return {
3480
+ const result = {
3456
3481
  success: false,
3457
3482
  data: String(error2),
3458
3483
  history: this.history
3459
3484
  };
3485
+ await onAfterTask.call(this, result);
3486
+ return result;
3460
3487
  }
3461
3488
  }
3462
- dispose() {
3489
+ dispose(reason) {
3463
3490
  console.log("Disposing PageAgent...");
3464
3491
  this.disposed = true;
3465
3492
  cleanUpHighlights();
@@ -3469,7 +3496,8 @@ const _PageAgent = class _PageAgent extends EventTarget {
3469
3496
  this.panel.dispose();
3470
3497
  this.mask.dispose();
3471
3498
  this.history = [];
3472
- __privateGet(this, _abortController).abort("PageAgent disposed");
3499
+ __privateGet(this, _abortController).abort(reason ?? "PageAgent disposed");
3500
+ this.config.onDispose?.call(this, reason);
3473
3501
  }
3474
3502
  };
3475
3503
  _llm = new WeakMap();
@@ -3503,8 +3531,6 @@ packMacroTool_fn = /* @__PURE__ */ __name(function() {
3503
3531
  action: actionSchema
3504
3532
  });
3505
3533
  return {
3506
- // name: MACRO_TOOL_NAME,
3507
- // description: 'Execute agent action', // @todo remote
3508
3534
  inputSchema: macroToolSchema,
3509
3535
  execute: /* @__PURE__ */ __name(async (input2) => {
3510
3536
  if (__privateGet(this, _abortController).signal.aborted) throw new Error("AbortError");
@@ -3668,6 +3694,7 @@ updateTree_fn = /* @__PURE__ */ __name(function() {
3668
3694
  __name(_PageAgent, "PageAgent");
3669
3695
  let PageAgent = _PageAgent;
3670
3696
  export {
3671
- PageAgent
3697
+ PageAgent,
3698
+ tool
3672
3699
  };
3673
3700
  //# sourceMappingURL=page-agent.js.map